| File: | libraries/libdxfrw/src/drw_entities.cpp |
| Warning: | line 15117, 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 | // The two wire forms of an embedded MTEXT (AcDbMTextObjectEmbedded). | |||
| 38 | enum class EmbeddedMTextForm { | |||
| 39 | // What AutoCAD writes into a multi-line ATTRIB / ATTDEF: every MTEXT | |||
| 40 | // field from the entity mode on, the R2018 "not annotative" block | |||
| 41 | // included, then the annotative data. Checked against an AutoCAD drawing, | |||
| 42 | // the ODA specification (ATTRIB, R2018+) and ACadSharp. | |||
| 43 | Full, | |||
| 44 | // IsNotAnnotative, one more bit, then the annotative data. GEOPOSITIONMARKER | |||
| 45 | // keeps this form because there is no AutoCAD drawing to check it against; | |||
| 46 | // LibreCAD also wrote it into attributes before it matched AutoCAD, so | |||
| 47 | // the attribute reader still accepts it. | |||
| 48 | Short | |||
| 49 | }; | |||
| 50 | ||||
| 51 | struct EmbeddedMTextHandleInfo { | |||
| 52 | bool m_ownerHandle = false; | |||
| 53 | int m_numReactors = 0; | |||
| 54 | // AC1015 has no xdict bit; AC1018+ supplies it and uses 1 to suppress | |||
| 55 | // the embedded xdictionary handle. | |||
| 56 | std::uint8_t m_xDictFlag = 0; | |||
| 57 | bool m_hasAcDbColorHandle = false; | |||
| 58 | int m_ltFlags = 0; | |||
| 59 | int m_plotFlags = 0; | |||
| 60 | int m_materialFlag = 0; | |||
| 61 | int m_shadowFlag = 0; | |||
| 62 | bool m_hasFullVisualStyle = false; | |||
| 63 | bool m_hasFaceVisualStyle = false; | |||
| 64 | bool m_hasEdgeVisualStyle = false; | |||
| 65 | bool m_hasStyleHandle = true; | |||
| 66 | bool m_hasR2018AppIdHandle = false; | |||
| 67 | bool m_hasAnnotativeAppHandle = false; | |||
| 68 | }; | |||
| 69 | static bool parseEmbeddedMTextDwg(DRW::Version version, dwgBuffer *buf, | |||
| 70 | dwgBuffer *sBuf, DRW_MText& mtext, | |||
| 71 | EmbeddedMTextHandleInfo& info, | |||
| 72 | EmbeddedMTextForm form, | |||
| 73 | std::uint64_t bodyEndBit = | |||
| 74 | std::numeric_limits<std::uint64_t>::max(), | |||
| 75 | std::uint64_t stringEndBit = | |||
| 76 | std::numeric_limits<std::uint64_t>::max()); | |||
| 77 | static bool consumeEmbeddedMTextHandles( | |||
| 78 | DRW::Version version, dwgBuffer *buf, | |||
| 79 | const EmbeddedMTextHandleInfo& info, DRW_MText *mtext, | |||
| 80 | std::uint64_t handleEndBit = | |||
| 81 | std::numeric_limits<std::uint64_t>::max()); | |||
| 82 | ||||
| 83 | constexpr std::uint32_t kMaxTableRows = 10000; | |||
| 84 | constexpr std::uint32_t kMaxTableColumns = 1000; | |||
| 85 | constexpr std::uint32_t kMaxTableCells = 200000; | |||
| 86 | constexpr std::uint32_t kMaxTableItems = 100000; | |||
| 87 | constexpr std::uint32_t kMaxTableStringBytes = 16 * 1024 * 1024; | |||
| 88 | constexpr std::uint32_t kMaxTableCellAttributes = 10000; | |||
| 89 | constexpr std::int32_t kMaxLWPolylineVertices = 1000000; | |||
| 90 | constexpr std::int32_t kMaxSplineItems = 1000000; | |||
| 91 | constexpr std::int32_t kMaxSplineDegree = 1024; | |||
| 92 | constexpr std::int32_t kMaxHatchItems = DRW_Hatch::kMaxDxfItems; | |||
| 93 | constexpr std::int32_t kMaxMInsertCount = | |||
| 94 | std::numeric_limits<std::int16_t>::max(); | |||
| 95 | constexpr std::int32_t kMaxViewportFrozenLayers = 512; | |||
| 96 | constexpr std::int32_t kMaxMTextColumnHeights = 4096; | |||
| 97 | constexpr std::int32_t kMaxMLeaderItems = 5000; | |||
| 98 | constexpr std::int32_t kMaxLeaderVertices = 5000; | |||
| 99 | constexpr std::uint16_t kMaxLoftedSurfaceModelerFormatVersion = 3; | |||
| 100 | ||||
| 101 | constexpr std::int32_t kSplineFlagMethodFitPoints = 1; | |||
| 102 | constexpr std::int32_t kSplineFlagClosed = 4; | |||
| 103 | constexpr std::int32_t kSplineFlagUseKnotParameter = 8; | |||
| 104 | constexpr std::int32_t kSplineKnotParamCustom = 15; | |||
| 105 | ||||
| 106 | bool isValidCount(std::int32_t count, std::int32_t maxCount) { | |||
| 107 | return count >= 0 && count <= maxCount; | |||
| 108 | } | |||
| 109 | ||||
| 110 | bool readDxfIntInRange(const std::unique_ptr<dxfReader>& reader, | |||
| 111 | int minimum, int maximum, int& value) { | |||
| 112 | value = reader->getInt32(); | |||
| 113 | return value >= minimum && value <= maximum; | |||
| 114 | } | |||
| 115 | ||||
| 116 | int hexNibble(char c) { | |||
| 117 | if (c >= '0' && c <= '9') | |||
| 118 | return c - '0'; | |||
| 119 | if (c >= 'A' && c <= 'F') | |||
| 120 | return c - 'A' + 10; | |||
| 121 | if (c >= 'a' && c <= 'f') | |||
| 122 | return c - 'a' + 10; | |||
| 123 | return -1; | |||
| 124 | } | |||
| 125 | ||||
| 126 | bool decodeHexBytes(const std::string& hex, std::vector<std::uint8_t>& out) { | |||
| 127 | if ((hex.size() % 2) != 0) | |||
| 128 | return false; | |||
| 129 | ||||
| 130 | std::vector<std::uint8_t> decoded; | |||
| 131 | const std::size_t byteCount = hex.size() / 2; | |||
| 132 | if (byteCount > static_cast<std::size_t>(std::numeric_limits<int>::max()) | |||
| 133 | || !DRW::reserve(decoded, static_cast<int>(byteCount))) | |||
| 134 | return false; | |||
| 135 | for (std::size_t i = 0; i < hex.size(); i += 2) { | |||
| 136 | const int hi = hexNibble(hex[i]); | |||
| 137 | const int lo = hexNibble(hex[i + 1]); | |||
| 138 | if (hi < 0 || lo < 0) | |||
| 139 | return false; | |||
| 140 | decoded.push_back(static_cast<std::uint8_t>((hi << 4) | lo)); | |||
| 141 | } | |||
| 142 | ||||
| 143 | out = std::move(decoded); | |||
| 144 | return true; | |||
| 145 | } | |||
| 146 | ||||
| 147 | bool appendBytesChecked(std::vector<std::uint8_t>& destination, | |||
| 148 | const std::vector<std::uint8_t>& bytes, | |||
| 149 | std::size_t maxSize) { | |||
| 150 | if (destination.size() > maxSize | |||
| 151 | || bytes.size() > maxSize - destination.size()) | |||
| 152 | return false; | |||
| 153 | const std::size_t newSize = destination.size() + bytes.size(); | |||
| 154 | if (newSize > static_cast<std::size_t>(std::numeric_limits<int>::max()) | |||
| 155 | || !DRW::reserve(destination, static_cast<int>(newSize))) | |||
| 156 | return false; | |||
| 157 | try { | |||
| 158 | destination.insert(destination.end(), bytes.begin(), bytes.end()); | |||
| 159 | } catch (...) { | |||
| 160 | return false; | |||
| 161 | } | |||
| 162 | return true; | |||
| 163 | } | |||
| 164 | ||||
| 165 | bool appendTextBytesChecked(std::vector<std::uint8_t>& destination, | |||
| 166 | const std::string& text, | |||
| 167 | std::size_t maxSize) { | |||
| 168 | if (destination.size() > maxSize | |||
| 169 | || text.size() > maxSize - destination.size()) | |||
| 170 | return false; | |||
| 171 | const std::size_t newSize = destination.size() + text.size(); | |||
| 172 | if (newSize > static_cast<std::size_t>(std::numeric_limits<int>::max()) | |||
| 173 | || !DRW::reserve(destination, static_cast<int>(newSize))) | |||
| 174 | return false; | |||
| 175 | try { | |||
| 176 | destination.insert(destination.end(), text.begin(), text.end()); | |||
| 177 | } catch (...) { | |||
| 178 | return false; | |||
| 179 | } | |||
| 180 | return true; | |||
| 181 | } | |||
| 182 | ||||
| 183 | bool appendHexBytesChecked(std::string& destination, const std::string& hex, | |||
| 184 | std::size_t maxSize) { | |||
| 185 | if ((hex.size() & 1u) != 0u || destination.size() > maxSize) | |||
| 186 | return false; | |||
| 187 | const std::size_t byteCount = hex.size() / 2u; | |||
| 188 | if (byteCount > maxSize - destination.size() | |||
| 189 | || byteCount > static_cast<std::size_t>(std::numeric_limits<int>::max())) | |||
| 190 | return false; | |||
| 191 | ||||
| 192 | std::string decoded; | |||
| 193 | if (!DRW::reserve(decoded, static_cast<int>(byteCount))) | |||
| 194 | return false; | |||
| 195 | for (std::size_t i = 0; i < hex.size(); i += 2) { | |||
| 196 | const int hi = hexNibble(hex[i]); | |||
| 197 | const int lo = hexNibble(hex[i + 1]); | |||
| 198 | if (hi < 0 || lo < 0) | |||
| 199 | return false; | |||
| 200 | decoded.push_back(static_cast<char>((hi << 4) | lo)); | |||
| 201 | } | |||
| 202 | try { | |||
| 203 | destination.append(decoded); | |||
| 204 | } catch (...) { | |||
| 205 | return false; | |||
| 206 | } | |||
| 207 | return true; | |||
| 208 | } | |||
| 209 | ||||
| 210 | std::uint64_t currentDwgBit(const dwgBuffer *buf) { | |||
| 211 | return buf->getPosition() * 8 + buf->getBitPos(); | |||
| 212 | } | |||
| 213 | ||||
| 214 | bool leaderHasEndpointProjection(DRW::Version version) { | |||
| 215 | return version >= DRW::AC1014; | |||
| 216 | } | |||
| 217 | ||||
| 218 | bool leaderHasTextBox(DRW::Version version) { | |||
| 219 | // R2010+ files use the compact LEADER layout without these legacy fields. | |||
| 220 | return version <= DRW::AC1021; | |||
| 221 | } | |||
| 222 | ||||
| 223 | std::uint64_t tableBodyEndBit(DRW::Version version, | |||
| 224 | const dwgBuffer *stringBuf, | |||
| 225 | std::uint32_t objectSize) { | |||
| 226 | // AC1021 objects may legally omit the string footer when they have no | |||
| 227 | // detached text. Keep their complete object body available; AC1024+ | |||
| 228 | // frames have the unambiguous extended object-data boundary. | |||
| 229 | if (version > DRW::AC1021 && stringBuf != nullptr) | |||
| 230 | return currentDwgBit(stringBuf); | |||
| 231 | return objectSize; | |||
| 232 | } | |||
| 233 | ||||
| 234 | bool readTableBodyCount(DRW::Version version, dwgBuffer *buf, | |||
| 235 | std::uint64_t objectSize, std::uint32_t maximum, | |||
| 236 | std::uint32_t minimumBitsPerItem, | |||
| 237 | std::uint32_t& value) { | |||
| 238 | if (buf == nullptr || !buf->isGood()) | |||
| 239 | return false; | |||
| 240 | ||||
| 241 | dwgBuffer probe = buf->forkIndependent(); | |||
| 242 | const std::int32_t parsed = probe.getBitLong(); | |||
| 243 | if (!probe.isGood() || parsed < 0 | |||
| 244 | || static_cast<std::uint32_t>(parsed) > maximum) | |||
| 245 | return false; | |||
| 246 | ||||
| 247 | if (version >= DRW::AC1015 && objectSize != 0) { | |||
| 248 | const std::uint64_t current = currentDwgBit(&probe); | |||
| 249 | if (current > objectSize || (minimumBitsPerItem != 0 | |||
| 250 | && static_cast<std::uint64_t>(parsed) | |||
| 251 | > (objectSize - current) | |||
| 252 | / minimumBitsPerItem)) | |||
| 253 | return false; | |||
| 254 | } | |||
| 255 | ||||
| 256 | *buf = probe; | |||
| 257 | value = static_cast<std::uint32_t>(parsed); | |||
| 258 | return true; | |||
| 259 | } | |||
| 260 | ||||
| 261 | std::uint64_t proxyEntityEndBit(const dwgBuffer& buffer, | |||
| 262 | std::uint32_t objectSize) { | |||
| 263 | if (objectSize != 0) | |||
| 264 | return objectSize; | |||
| 265 | return buffer.size() > std::numeric_limits<std::uint64_t>::max() / 8u | |||
| 266 | ? std::numeric_limits<std::uint64_t>::max() | |||
| 267 | : static_cast<std::uint64_t>(buffer.size()) * 8u; | |||
| 268 | } | |||
| 269 | ||||
| 270 | bool entityBodyDataEndBit(const dwgBuffer& stringBuffer, | |||
| 271 | DRW::Version version, std::uint32_t objectSize, | |||
| 272 | std::uint64_t& endBit, | |||
| 273 | std::uint64_t* stringEndBit = nullptr) { | |||
| 274 | if (version <= DRW::AC1021 || objectSize == 0) { | |||
| 275 | endBit = proxyEntityEndBit(stringBuffer, objectSize); | |||
| 276 | if (stringEndBit != nullptr) | |||
| 277 | *stringEndBit = endBit; | |||
| 278 | return true; | |||
| 279 | } | |||
| 280 | ||||
| 281 | std::uint64_t stringStartBit = 0; | |||
| 282 | std::uint64_t parsedStringEndBit = 0; | |||
| 283 | if (!stringBuffer.getR2007StringStreamBounds( | |||
| 284 | objectSize, stringStartBit, parsedStringEndBit) | |||
| 285 | || stringStartBit > parsedStringEndBit | |||
| 286 | || parsedStringEndBit > objectSize | |||
| 287 | || currentDwgBit(&stringBuffer) != stringStartBit) { | |||
| 288 | return false; | |||
| 289 | } | |||
| 290 | endBit = stringStartBit; | |||
| 291 | if (stringEndBit != nullptr) | |||
| 292 | *stringEndBit = parsedStringEndBit; | |||
| 293 | return true; | |||
| 294 | } | |||
| 295 | ||||
| 296 | bool dwgHandleStreamEndBit(const dwgBuffer& buffer, DRW::Version version, | |||
| 297 | std::uint32_t objectSize, std::uint32_t handleBits, | |||
| 298 | std::uint64_t& endBit) { | |||
| 299 | if (version > DRW::AC1021) { | |||
| 300 | std::uint64_t totalBits = 0; | |||
| 301 | return dwgSafety::add(objectSize, handleBits, endBit) | |||
| 302 | && dwgSafety::multiply(buffer.size(), 8, totalBits) | |||
| 303 | && endBit <= totalBits; | |||
| 304 | } | |||
| 305 | return dwgSafety::multiply(buffer.size(), 8, endBit); | |||
| 306 | } | |||
| 307 | ||||
| 308 | bool proxyEntityHasBits(const dwgBuffer& buffer, std::uint64_t endBit, | |||
| 309 | std::uint64_t count) { | |||
| 310 | const std::uint64_t current = currentDwgBit(&buffer); | |||
| 311 | return current <= endBit && count <= endBit - current; | |||
| 312 | } | |||
| 313 | ||||
| 314 | bool readProxyEntityOptionalBitLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 315 | bool& present, std::int32_t& value) { | |||
| 316 | present = false; | |||
| 317 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 318 | return true; | |||
| 319 | ||||
| 320 | const std::uint8_t prefix = buffer.get2Bits(); | |||
| 321 | if (!buffer.isGood()) | |||
| 322 | return false; | |||
| 323 | if (prefix == 0) { | |||
| 324 | if (!proxyEntityHasBits(buffer, endBit, 32)) | |||
| 325 | return false; | |||
| 326 | value = static_cast<std::int32_t>(buffer.getRawLong32()); | |||
| 327 | } else if (prefix == 1) { | |||
| 328 | if (!proxyEntityHasBits(buffer, endBit, 8)) | |||
| 329 | return false; | |||
| 330 | value = static_cast<std::int32_t>(buffer.getRawChar8()); | |||
| 331 | } else { | |||
| 332 | value = 0; | |||
| 333 | } | |||
| 334 | present = buffer.isGood(); | |||
| 335 | return present; | |||
| 336 | } | |||
| 337 | ||||
| 338 | bool copyDwgBitRange(const dwgBuffer& source, std::uint64_t startBit, | |||
| 339 | std::uint64_t endBit, | |||
| 340 | std::vector<std::uint8_t>& data) { | |||
| 341 | data.clear(); | |||
| 342 | if (endBit <= startBit) | |||
| 343 | return true; | |||
| 344 | ||||
| 345 | const std::uint64_t sourceEnd = proxyEntityEndBit(source, 0); | |||
| 346 | if (endBit > sourceEnd) | |||
| 347 | return false; | |||
| 348 | const std::uint64_t startByte = startBit >> 3; | |||
| 349 | const std::uint64_t endByte = (endBit >> 3) + ((endBit & 7u) != 0); | |||
| 350 | const std::uint64_t byteCount = endByte - startByte; | |||
| 351 | if (endByte < startByte | |||
| 352 | || byteCount > std::numeric_limits<std::size_t>::max() | |||
| 353 | || byteCount > static_cast<std::uint64_t>(std::numeric_limits<int>::max()) | |||
| 354 | || !DRW::resize(data, static_cast<int>(byteCount))) | |||
| 355 | return false; | |||
| 356 | dwgBuffer copy = source; | |||
| 357 | if (!copy.setPosition(startByte)) | |||
| 358 | return false; | |||
| 359 | if ((startBit & 7u) != 0) { | |||
| 360 | copy.setBitPos(static_cast<std::uint8_t>(startBit & 7u)); | |||
| 361 | if (!copy.isGood()) | |||
| 362 | return false; | |||
| 363 | } | |||
| 364 | return data.empty() | |||
| 365 | || (copy.getBytes(data.data(), data.size()) && copy.isGood()); | |||
| 366 | } | |||
| 367 | ||||
| 368 | bool readBoundedBitShort(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 369 | std::uint16_t& value) { | |||
| 370 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 371 | return false; | |||
| 372 | ||||
| 373 | // BS has a two-bit selector followed by either no payload, one byte, or | |||
| 374 | // two bytes. Probe the selector on an independent cursor before touching | |||
| 375 | // the publishing cursor, so a frame boundary is checked exactly. | |||
| 376 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 377 | const std::uint8_t selector = probe.get2Bits(); | |||
| 378 | if (!probe.isGood()) | |||
| 379 | return false; | |||
| 380 | const std::uint64_t bits = selector == 0 ? 18 | |||
| 381 | : selector == 1 ? 10 : 2; | |||
| 382 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 383 | return false; | |||
| 384 | value = buffer.getBitShort(); | |||
| 385 | return buffer.isGood(); | |||
| 386 | } | |||
| 387 | ||||
| 388 | bool readBoundedRawChar8(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 389 | std::uint8_t& value) { | |||
| 390 | if (!proxyEntityHasBits(buffer, endBit, 8)) | |||
| 391 | return false; | |||
| 392 | value = buffer.getRawChar8(); | |||
| 393 | return buffer.isGood(); | |||
| 394 | } | |||
| 395 | ||||
| 396 | bool readBounded2Bits(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 397 | std::uint8_t& value) { | |||
| 398 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 399 | return false; | |||
| 400 | value = buffer.get2Bits(); | |||
| 401 | return buffer.isGood(); | |||
| 402 | } | |||
| 403 | ||||
| 404 | bool readBoundedRawLong32(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 405 | std::uint32_t& value) { | |||
| 406 | if (!proxyEntityHasBits(buffer, endBit, 32)) | |||
| 407 | return false; | |||
| 408 | value = buffer.getRawLong32(); | |||
| 409 | return buffer.isGood(); | |||
| 410 | } | |||
| 411 | ||||
| 412 | bool readBoundedBit(dwgBuffer& buffer, std::uint64_t endBit, bool& value) { | |||
| 413 | if (!proxyEntityHasBits(buffer, endBit, 1)) | |||
| 414 | return false; | |||
| 415 | value = buffer.getBit() != 0; | |||
| 416 | return buffer.isGood(); | |||
| 417 | } | |||
| 418 | ||||
| 419 | bool readBoundedBitLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 420 | std::int32_t& value) { | |||
| 421 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 422 | return false; | |||
| 423 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 424 | const std::uint8_t selector = probe.get2Bits(); | |||
| 425 | if (!probe.isGood()) | |||
| 426 | return false; | |||
| 427 | const std::uint64_t bits = selector == 0 ? 34 | |||
| 428 | : selector == 1 ? 10 : 2; | |||
| 429 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 430 | return false; | |||
| 431 | value = buffer.getBitLong(); | |||
| 432 | return buffer.isGood(); | |||
| 433 | } | |||
| 434 | ||||
| 435 | bool readBoundedBitLongLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 436 | std::uint64_t& value) { | |||
| 437 | if (!proxyEntityHasBits(buffer, endBit, 3)) | |||
| 438 | return false; | |||
| 439 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 440 | const std::uint8_t byteCount = probe.get3Bits(); | |||
| 441 | const std::uint64_t bits = 3u + static_cast<std::uint64_t>(byteCount) * 8u; | |||
| 442 | if (!probe.isGood() || !proxyEntityHasBits(buffer, endBit, bits)) | |||
| 443 | return false; | |||
| 444 | value = buffer.getBitLongLong(); | |||
| 445 | return buffer.isGood(); | |||
| 446 | } | |||
| 447 | ||||
| 448 | bool readBoundedBitDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 449 | double& value) { | |||
| 450 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 451 | return false; | |||
| 452 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 453 | const std::uint8_t selector = probe.get2Bits(); | |||
| 454 | if (!probe.isGood()) | |||
| 455 | return false; | |||
| 456 | const std::uint64_t bits = selector == 0 ? 66 : 2; | |||
| 457 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 458 | return false; | |||
| 459 | dwgBuffer candidate = buffer.forkIndependent(); | |||
| 460 | const double parsed = candidate.getBitDouble(); | |||
| 461 | if (!candidate.isGood() || currentDwgBit(&candidate) > endBit | |||
| 462 | || !std::isfinite(parsed)) | |||
| 463 | return false; | |||
| 464 | buffer = candidate; | |||
| 465 | value = parsed; | |||
| 466 | return true; | |||
| 467 | } | |||
| 468 | ||||
| 469 | bool readBoundedBitCoord(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 470 | DRW_Coord& value) { | |||
| 471 | return readBoundedBitDouble(buffer, endBit, value.x) | |||
| 472 | && readBoundedBitDouble(buffer, endBit, value.y) | |||
| 473 | && readBoundedBitDouble(buffer, endBit, value.z); | |||
| 474 | } | |||
| 475 | ||||
| 476 | bool readBoundedEnColor(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 477 | DRW::Version version, std::uint32_t& value) { | |||
| 478 | if (!buffer.isGood() || currentDwgBit(&buffer) > endBit) | |||
| 479 | return false; | |||
| 480 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 481 | const std::uint32_t parsed = probe.getEnColor(version); | |||
| 482 | if (!probe.isGood() || currentDwgBit(&probe) > endBit) | |||
| 483 | return false; | |||
| 484 | buffer = probe; | |||
| 485 | buffer.lastEnColorHadDbColorRef = probe.lastEnColorHadDbColorRef; | |||
| 486 | buffer.lastEnColorName = probe.lastEnColorName; | |||
| 487 | buffer.lastEnColorBookName = probe.lastEnColorBookName; | |||
| 488 | buffer.lastEnColorRgb = probe.lastEnColorRgb; | |||
| 489 | buffer.lastEnColorAlphaRaw = probe.lastEnColorAlphaRaw; | |||
| 490 | value = parsed; | |||
| 491 | return true; | |||
| 492 | } | |||
| 493 | ||||
| 494 | struct TableDwgBounds { | |||
| 495 | std::uint64_t bodyEndBit = std::numeric_limits<std::uint64_t>::max(); | |||
| 496 | std::uint64_t stringEndBit = std::numeric_limits<std::uint64_t>::max(); | |||
| 497 | std::uint64_t handleEndBit = std::numeric_limits<std::uint64_t>::max(); | |||
| 498 | }; | |||
| 499 | ||||
| 500 | std::uint64_t tableTextEndBit(const dwgBuffer *bodyBuf, | |||
| 501 | const dwgBuffer *textBuf, | |||
| 502 | const TableDwgBounds& bounds) { | |||
| 503 | return textBuf == bodyBuf ? bounds.bodyEndBit : bounds.stringEndBit; | |||
| 504 | } | |||
| 505 | ||||
| 506 | bool skipTableBit(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 507 | bool value = false; | |||
| 508 | return readBoundedBit(buffer, endBit, value); | |||
| 509 | } | |||
| 510 | ||||
| 511 | bool skipTableBitShort(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 512 | std::uint16_t value = 0; | |||
| 513 | return readBoundedBitShort(buffer, endBit, value); | |||
| 514 | } | |||
| 515 | ||||
| 516 | bool skipTableBitLong(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 517 | std::int32_t value = 0; | |||
| 518 | return readBoundedBitLong(buffer, endBit, value); | |||
| 519 | } | |||
| 520 | ||||
| 521 | bool skipTableBitDouble(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 522 | double value = 0.0; | |||
| 523 | return readBoundedBitDouble(buffer, endBit, value); | |||
| 524 | } | |||
| 525 | ||||
| 526 | bool readBounded3BitDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 527 | DRW_Coord& value) { | |||
| 528 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 529 | DRW_Coord parsed; | |||
| 530 | if (!readBoundedBitDouble(probe, endBit, parsed.x) | |||
| 531 | || !readBoundedBitDouble(probe, endBit, parsed.y) | |||
| 532 | || !readBoundedBitDouble(probe, endBit, parsed.z)) | |||
| 533 | return false; | |||
| 534 | buffer = probe; | |||
| 535 | value = parsed; | |||
| 536 | return true; | |||
| 537 | } | |||
| 538 | ||||
| 539 | bool readBoundedBytes(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 540 | std::uint8_t *data, std::size_t size) { | |||
| 541 | std::uint64_t bits = 0; | |||
| 542 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(size), 8, bits) | |||
| 543 | || !proxyEntityHasBits(buffer, endBit, bits)) | |||
| 544 | return false; | |||
| 545 | return size == 0 || (buffer.getBytes(data, size) && buffer.isGood()); | |||
| 546 | } | |||
| 547 | ||||
| 548 | bool readBoundedRawLong64(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 549 | std::uint64_t& value) { | |||
| 550 | if (!proxyEntityHasBits(buffer, endBit, 64)) | |||
| 551 | return false; | |||
| 552 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 553 | const std::uint64_t parsed = probe.getRawLong64(); | |||
| 554 | if (!probe.isGood()) | |||
| 555 | return false; | |||
| 556 | buffer = probe; | |||
| 557 | value = parsed; | |||
| 558 | return true; | |||
| 559 | } | |||
| 560 | ||||
| 561 | bool readBounded2RawDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 562 | DRW_Coord& value) { | |||
| 563 | if (!proxyEntityHasBits(buffer, endBit, 128)) | |||
| 564 | return false; | |||
| 565 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 566 | DRW_Coord parsed = probe.get2RawDouble(); | |||
| 567 | if (!probe.isGood() | |||
| 568 | || !std::isfinite(parsed.x) | |||
| 569 | || !std::isfinite(parsed.y) | |||
| 570 | || !std::isfinite(parsed.z)) | |||
| 571 | return false; | |||
| 572 | parsed.z = 0.0; // 2RD carries only X and Y; keep the unused component defined. | |||
| 573 | buffer = probe; | |||
| 574 | value = parsed; | |||
| 575 | return true; | |||
| 576 | } | |||
| 577 | ||||
| 578 | bool readBoundedRawDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 579 | double& value) { | |||
| 580 | if (!proxyEntityHasBits(buffer, endBit, 64)) | |||
| 581 | return false; | |||
| 582 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 583 | const double parsed = probe.getRawDouble(); | |||
| 584 | if (!probe.isGood() || currentDwgBit(&probe) > endBit | |||
| 585 | || !std::isfinite(parsed)) | |||
| 586 | return false; | |||
| 587 | buffer = probe; | |||
| 588 | value = parsed; | |||
| 589 | return true; | |||
| 590 | } | |||
| 591 | ||||
| 592 | bool readBoundedDwgHandle(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 593 | std::uint32_t baseHandle, bool offset, | |||
| 594 | dwgHandle& value) { | |||
| 595 | if (!buffer.isGood() || currentDwgBit(&buffer) > endBit) | |||
| 596 | return false; | |||
| 597 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 598 | dwgHandle parsed; | |||
| 599 | if (!readDwgHandleChecked(probe, baseHandle, offset, parsed) | |||
| 600 | || currentDwgBit(&probe) > endBit) | |||
| 601 | return false; | |||
| 602 | buffer = probe; | |||
| 603 | value = parsed; | |||
| 604 | return true; | |||
| 605 | } | |||
| 606 | ||||
| 607 | bool readBoundedDwgObjectId(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 608 | std::uint32_t baseHandle, dwgHandle& raw, | |||
| 609 | dwgHandle& resolved) { | |||
| 610 | if (!buffer.isGood() || currentDwgBit(&buffer) > endBit) | |||
| 611 | return false; | |||
| 612 | ||||
| 613 | dwgBuffer rawProbe = buffer.forkIndependent(); | |||
| 614 | raw = rawProbe.getHandle(); | |||
| 615 | if (!rawProbe.isGood() || currentDwgBit(&rawProbe) > endBit) | |||
| 616 | return false; | |||
| 617 | ||||
| 618 | dwgBuffer resolvedProbe = buffer.forkIndependent(); | |||
| 619 | resolved = resolvedProbe.getOffsetHandle(baseHandle); | |||
| 620 | if (!resolvedProbe.isGood() || currentDwgBit(&resolvedProbe) > endBit) | |||
| 621 | return false; | |||
| 622 | ||||
| 623 | buffer = resolvedProbe; | |||
| 624 | return true; | |||
| 625 | } | |||
| 626 | ||||
| 627 | bool readBoundedVariableText(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 628 | DRW::Version version, UTF8STRINGstd::string& value) { | |||
| 629 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 630 | return false; | |||
| 631 | ||||
| 632 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 633 | const std::uint16_t units = probe.getBitShort(); | |||
| 634 | if (!probe.isGood()) | |||
| 635 | return false; | |||
| 636 | ||||
| 637 | const std::uint64_t bitsPerUnit = version > DRW::AC1018 ? 16u : 8u; | |||
| 638 | std::uint64_t payloadBits = 0; | |||
| 639 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(units), bitsPerUnit, | |||
| 640 | payloadBits) | |||
| 641 | || !proxyEntityHasBits(probe, endBit, payloadBits)) | |||
| 642 | return false; | |||
| 643 | ||||
| 644 | value = buffer.getVariableText(version, false); | |||
| 645 | return buffer.isGood() && currentDwgBit(&buffer) <= endBit; | |||
| 646 | } | |||
| 647 | ||||
| 648 | bool readBoundedDefaultDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 649 | double defaultValue, double& value) { | |||
| 650 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 651 | return false; | |||
| 652 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 653 | const std::uint8_t selector = probe.get2Bits(); | |||
| 654 | if (!probe.isGood()) | |||
| 655 | return false; | |||
| 656 | const std::uint64_t bits = selector == 0 ? 2 | |||
| 657 | : selector == 1 ? 34 | |||
| 658 | : selector == 2 ? 50 : 66; | |||
| 659 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 660 | return false; | |||
| 661 | value = buffer.getDefaultDouble(defaultValue); | |||
| 662 | return buffer.isGood(); | |||
| 663 | } | |||
| 664 | ||||
| 665 | bool readBoundedThickness(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 666 | bool modern, double& value) { | |||
| 667 | if (!modern) | |||
| 668 | return readBoundedBitDouble(buffer, endBit, value); | |||
| 669 | if (!proxyEntityHasBits(buffer, endBit, 1)) | |||
| 670 | return false; | |||
| 671 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 672 | const bool isZero = probe.getBit() != 0; | |||
| 673 | if (!probe.isGood()) | |||
| 674 | return false; | |||
| 675 | buffer.getBit(); | |||
| 676 | if (!buffer.isGood()) | |||
| 677 | return false; | |||
| 678 | if (isZero) { | |||
| 679 | value = 0.0; | |||
| 680 | return true; | |||
| 681 | } | |||
| 682 | return readBoundedBitDouble(buffer, endBit, value); | |||
| 683 | } | |||
| 684 | ||||
| 685 | bool readBoundedExtrusion(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 686 | bool modern, DRW_Coord& value) { | |||
| 687 | if (modern) { | |||
| 688 | if (!proxyEntityHasBits(buffer, endBit, 1)) | |||
| 689 | return false; | |||
| 690 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 691 | const bool isDefault = probe.getBit() != 0; | |||
| 692 | if (!probe.isGood()) | |||
| 693 | return false; | |||
| 694 | buffer.getBit(); | |||
| 695 | if (!buffer.isGood()) | |||
| 696 | return false; | |||
| 697 | if (isDefault) { | |||
| 698 | value = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 699 | return true; | |||
| 700 | } | |||
| 701 | } | |||
| 702 | ||||
| 703 | return readBoundedBitDouble(buffer, endBit, value.x) | |||
| 704 | && readBoundedBitDouble(buffer, endBit, value.y) | |||
| 705 | && readBoundedBitDouble(buffer, endBit, value.z); | |||
| 706 | } | |||
| 707 | ||||
| 708 | bool readBoundedCmColor(dwgBuffer& buffer, dwgBuffer *stringBuffer, | |||
| 709 | std::uint64_t endBit, DRW::Version version, | |||
| 710 | std::uint32_t& value, std::int32_t *rgb24 = nullptr, | |||
| 711 | bool *hasRgbColor = nullptr, | |||
| 712 | UTF8STRINGstd::string *outName = nullptr, | |||
| 713 | UTF8STRINGstd::string *outBookName = nullptr, | |||
| 714 | std::uint64_t stringEndBit = | |||
| 715 | std::numeric_limits<std::uint64_t>::max()) { | |||
| 716 | const bool separateStringBuffer = stringBuffer != nullptr | |||
| 717 | && stringBuffer != &buffer; | |||
| 718 | dwgBuffer bodyProbe = buffer.forkIndependent(); | |||
| 719 | dwgBuffer stringProbe = separateStringBuffer | |||
| 720 | ? stringBuffer->forkIndependent() : bodyProbe.forkIndependent(); | |||
| 721 | dwgBuffer *colorStringBuffer = separateStringBuffer | |||
| 722 | ? &stringProbe : &bodyProbe; | |||
| 723 | UTF8STRINGstd::string parsedName; | |||
| 724 | UTF8STRINGstd::string parsedBookName; | |||
| 725 | std::int32_t parsedRgb = -1; | |||
| 726 | bool parsedHasRgb = false; | |||
| 727 | const std::uint32_t parsed = bodyProbe.getCmColor( | |||
| 728 | version, &parsedRgb, colorStringBuffer, &parsedName, &parsedBookName, | |||
| 729 | &parsedHasRgb); | |||
| 730 | if (!bodyProbe.isGood() || !colorStringBuffer->isGood() | |||
| 731 | || currentDwgBit(&bodyProbe) > endBit | |||
| 732 | || (separateStringBuffer | |||
| 733 | && currentDwgBit(&stringProbe) > stringEndBit)) | |||
| 734 | return false; | |||
| 735 | buffer = bodyProbe; | |||
| 736 | if (separateStringBuffer) | |||
| 737 | *stringBuffer = stringProbe; | |||
| 738 | value = parsed; | |||
| 739 | if (outName != nullptr) | |||
| 740 | *outName = std::move(parsedName); | |||
| 741 | if (outBookName != nullptr) | |||
| 742 | *outBookName = std::move(parsedBookName); | |||
| 743 | if (rgb24 != nullptr) | |||
| 744 | *rgb24 = parsedRgb; | |||
| 745 | if (hasRgbColor != nullptr) | |||
| 746 | *hasRgbColor = parsedHasRgb; | |||
| 747 | return true; | |||
| 748 | } | |||
| 749 | ||||
| 750 | struct DwgTextBodyData { | |||
| 751 | DRW_Coord basePoint{0.0, 0.0, 0.0}; | |||
| 752 | DRW_Coord secPoint{0.0, 0.0, 0.0}; | |||
| 753 | DRW_Coord extPoint{0.0, 0.0, 1.0}; | |||
| 754 | double thickness = 0.0; | |||
| 755 | double oblique = 0.0; | |||
| 756 | double angle = 0.0; | |||
| 757 | double height = 0.0; | |||
| 758 | double widthscale = 1.0; | |||
| 759 | UTF8STRINGstd::string text; | |||
| 760 | int textgen = 0; | |||
| 761 | DRW_Text::HAlign alignH = DRW_Text::HLeft; | |||
| 762 | DRW_Text::VAlign alignV = DRW_Text::VBaseLine; | |||
| 763 | }; | |||
| 764 | ||||
| 765 | bool readBoundedDwgTextBody( | |||
| 766 | DRW::Version version, dwgBuffer& body, dwgBuffer& stringBuffer, | |||
| 767 | std::uint64_t bodyEndBit, std::uint64_t stringStartBit, | |||
| 768 | std::uint64_t stringEndBit, DwgTextBodyData& data) { | |||
| 769 | std::uint8_t dataFlags = 0; | |||
| 770 | if (version > DRW::AC1014) { | |||
| 771 | if (!readBoundedRawChar8(body, bodyEndBit, dataFlags)) | |||
| 772 | return false; | |||
| 773 | if (!(dataFlags & 0x01) | |||
| 774 | && !readBoundedRawDouble(body, bodyEndBit, data.basePoint.z)) | |||
| 775 | return false; | |||
| 776 | } else if (!readBoundedBitDouble(body, bodyEndBit, data.basePoint.z)) { | |||
| 777 | return false; | |||
| 778 | } | |||
| 779 | ||||
| 780 | if (!readBoundedRawDouble(body, bodyEndBit, data.basePoint.x) | |||
| 781 | || !readBoundedRawDouble(body, bodyEndBit, data.basePoint.y)) | |||
| 782 | return false; | |||
| 783 | ||||
| 784 | if (version > DRW::AC1014) { | |||
| 785 | if (!(dataFlags & 0x02)) { | |||
| 786 | if (!readBoundedDefaultDouble(body, bodyEndBit, | |||
| 787 | data.basePoint.x, data.secPoint.x) | |||
| 788 | || !readBoundedDefaultDouble(body, bodyEndBit, | |||
| 789 | data.basePoint.y, | |||
| 790 | data.secPoint.y)) | |||
| 791 | return false; | |||
| 792 | } else { | |||
| 793 | data.secPoint = data.basePoint; | |||
| 794 | } | |||
| 795 | } else if (!readBoundedRawDouble(body, bodyEndBit, data.secPoint.x) | |||
| 796 | || !readBoundedRawDouble(body, bodyEndBit, data.secPoint.y)) { | |||
| 797 | return false; | |||
| 798 | } | |||
| 799 | data.secPoint.z = data.basePoint.z; | |||
| 800 | ||||
| 801 | if (!readBoundedExtrusion(body, bodyEndBit, version > DRW::AC1014, | |||
| 802 | data.extPoint) | |||
| 803 | || !readBoundedThickness(body, bodyEndBit, version > DRW::AC1014, | |||
| 804 | data.thickness)) | |||
| 805 | return false; | |||
| 806 | ||||
| 807 | if (version > DRW::AC1014) { | |||
| 808 | if (!(dataFlags & 0x04) | |||
| 809 | && !readBoundedRawDouble(body, bodyEndBit, data.oblique)) | |||
| 810 | return false; | |||
| 811 | if (!(dataFlags & 0x08) | |||
| 812 | && !readBoundedRawDouble(body, bodyEndBit, data.angle)) | |||
| 813 | return false; | |||
| 814 | if (!readBoundedRawDouble(body, bodyEndBit, data.height)) | |||
| 815 | return false; | |||
| 816 | if (!(dataFlags & 0x10) | |||
| 817 | && !readBoundedRawDouble(body, bodyEndBit, data.widthscale)) | |||
| 818 | return false; | |||
| 819 | } else if (!readBoundedBitDouble(body, bodyEndBit, data.oblique) | |||
| 820 | || !readBoundedBitDouble(body, bodyEndBit, data.angle) | |||
| 821 | || !readBoundedBitDouble(body, bodyEndBit, data.height) | |||
| 822 | || !readBoundedBitDouble(body, bodyEndBit, data.widthscale)) { | |||
| 823 | return false; | |||
| 824 | } | |||
| 825 | data.angle *= ARAD57.29577951308232; | |||
| 826 | ||||
| 827 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 828 | data.text.clear(); | |||
| 829 | } else if (!readBoundedVariableText(stringBuffer, stringEndBit, version, | |||
| 830 | data.text)) { | |||
| 831 | return false; | |||
| 832 | } | |||
| 833 | ||||
| 834 | std::uint16_t parsedTextgen = 0; | |||
| 835 | std::uint16_t parsedAlignH = 0; | |||
| 836 | std::uint16_t parsedAlignV = 0; | |||
| 837 | if (!(dataFlags & 0x20) | |||
| 838 | && !readBoundedBitShort(body, bodyEndBit, parsedTextgen)) | |||
| 839 | return false; | |||
| 840 | if (!(dataFlags & 0x40) | |||
| 841 | && !readBoundedBitShort(body, bodyEndBit, parsedAlignH)) | |||
| 842 | return false; | |||
| 843 | if (!(dataFlags & 0x80) | |||
| 844 | && !readBoundedBitShort(body, bodyEndBit, parsedAlignV)) | |||
| 845 | return false; | |||
| 846 | data.textgen = parsedTextgen; | |||
| 847 | data.alignH = static_cast<DRW_Text::HAlign>(parsedAlignH); | |||
| 848 | data.alignV = static_cast<DRW_Text::VAlign>(parsedAlignV); | |||
| 849 | ||||
| 850 | const auto finite = [](const DRW_Coord& point) { | |||
| 851 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 852 | && std::isfinite(point.z); | |||
| 853 | }; | |||
| 854 | return body.isGood() && stringBuffer.isGood() && finite(data.basePoint) | |||
| 855 | && finite(data.secPoint) && finite(data.extPoint) | |||
| 856 | && std::isfinite(data.thickness) && std::isfinite(data.oblique) | |||
| 857 | && std::isfinite(data.angle) && std::isfinite(data.height) | |||
| 858 | && std::isfinite(data.widthscale); | |||
| 859 | } | |||
| 860 | ||||
| 861 | // R2018 MTEXT: the fields that follow a set "is not annotative" bit. AutoCAD | |||
| 862 | // writes the same block for a stand-alone MTEXT and for the MTEXT embedded in | |||
| 863 | // a multi-line ATTRIB / ATTDEF, so both codecs go through these helpers. | |||
| 864 | struct DwgMTextR2018Block { | |||
| 865 | std::uint16_t m_version = 0; | |||
| 866 | bool m_defaultFlag = false; | |||
| 867 | std::int32_t m_attachment = 0; | |||
| 868 | DRW_Coord m_xAxisDir; | |||
| 869 | DRW_Coord m_insertionPoint; | |||
| 870 | double m_rectWidth = 0.0; | |||
| 871 | double m_rectHeight = 0.0; | |||
| 872 | double m_extentsWidth = 0.0; | |||
| 873 | double m_extentsHeight = 0.0; | |||
| 874 | std::uint16_t m_columnType = 0; | |||
| 875 | std::int32_t m_columnCount = 0; | |||
| 876 | double m_columnWidth = 0.0; | |||
| 877 | double m_columnGutter = 0.0; | |||
| 878 | bool m_columnAutoHeight = false; | |||
| 879 | bool m_columnFlowReversed = false; | |||
| 880 | std::vector<double> m_columnHeights; | |||
| 881 | }; | |||
| 882 | ||||
| 883 | bool readBoundedDwgMTextR2018Block(dwgBuffer& body, std::uint64_t bodyEndBit, | |||
| 884 | DwgMTextR2018Block& block) { | |||
| 885 | // The registered application handle of this block is in the handle | |||
| 886 | // stream. The extents come width first here, height first in the fields | |||
| 887 | // before the text. | |||
| 888 | if (!readBoundedBitShort(body, bodyEndBit, block.m_version) | |||
| 889 | || !readBoundedBit(body, bodyEndBit, block.m_defaultFlag) | |||
| 890 | || !readBoundedBitLong(body, bodyEndBit, block.m_attachment) | |||
| 891 | || !readBoundedBitCoord(body, bodyEndBit, block.m_xAxisDir) | |||
| 892 | || !readBoundedBitCoord(body, bodyEndBit, block.m_insertionPoint) | |||
| 893 | || !readBoundedBitDouble(body, bodyEndBit, block.m_rectWidth) | |||
| 894 | || !readBoundedBitDouble(body, bodyEndBit, block.m_rectHeight) | |||
| 895 | || !readBoundedBitDouble(body, bodyEndBit, block.m_extentsWidth) | |||
| 896 | || !readBoundedBitDouble(body, bodyEndBit, block.m_extentsHeight) | |||
| 897 | || !readBoundedBitShort(body, bodyEndBit, block.m_columnType) | |||
| 898 | || block.m_columnType > 2) | |||
| 899 | return false; | |||
| 900 | if (block.m_columnType != 0) { | |||
| 901 | if (!readBoundedBitLong(body, bodyEndBit, block.m_columnCount) | |||
| 902 | || !isValidCount(block.m_columnCount, kMaxMTextColumnHeights) | |||
| 903 | || !readBoundedBitDouble(body, bodyEndBit, block.m_columnWidth) | |||
| 904 | || !readBoundedBitDouble(body, bodyEndBit, block.m_columnGutter) | |||
| 905 | || !readBoundedBit(body, bodyEndBit, block.m_columnAutoHeight) | |||
| 906 | || !readBoundedBit(body, bodyEndBit, block.m_columnFlowReversed)) | |||
| 907 | return false; | |||
| 908 | if (!block.m_columnAutoHeight && block.m_columnType == 2 | |||
| 909 | && block.m_columnCount > 0) { | |||
| 910 | if (!DRW::reserve(block.m_columnHeights, block.m_columnCount)) | |||
| 911 | return false; | |||
| 912 | for (std::int32_t i = 0; i < block.m_columnCount; ++i) { | |||
| 913 | double columnHeight = 0.0; | |||
| 914 | if (!readBoundedBitDouble(body, bodyEndBit, columnHeight) | |||
| 915 | || !std::isfinite(columnHeight)) | |||
| 916 | return false; | |||
| 917 | block.m_columnHeights.push_back(columnHeight); | |||
| 918 | } | |||
| 919 | } | |||
| 920 | } | |||
| 921 | const auto finite = [](const DRW_Coord& point) { | |||
| 922 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 923 | && std::isfinite(point.z); | |||
| 924 | }; | |||
| 925 | return body.isGood() && finite(block.m_xAxisDir) | |||
| 926 | && finite(block.m_insertionPoint) && std::isfinite(block.m_rectWidth) | |||
| 927 | && std::isfinite(block.m_rectHeight) | |||
| 928 | && std::isfinite(block.m_extentsWidth) | |||
| 929 | && std::isfinite(block.m_extentsHeight); | |||
| 930 | } | |||
| 931 | ||||
| 932 | DwgMTextR2018Block dwgMTextR2018BlockOf(const DRW_MText& mtext) { | |||
| 933 | DwgMTextR2018Block block; | |||
| 934 | block.m_version = mtext.m_r2018Version; | |||
| 935 | block.m_defaultFlag = mtext.m_r2018DefaultFlag; | |||
| 936 | block.m_attachment = mtext.m_r2018Attachment; | |||
| 937 | block.m_xAxisDir = mtext.m_r2018XAxisDir; | |||
| 938 | block.m_insertionPoint = mtext.m_r2018InsertionPoint; | |||
| 939 | block.m_rectWidth = mtext.m_r2018RectWidth; | |||
| 940 | block.m_rectHeight = mtext.m_r2018RectHeight; | |||
| 941 | block.m_extentsWidth = mtext.m_r2018ExtentsWidth; | |||
| 942 | block.m_extentsHeight = mtext.m_r2018ExtentsHeight; | |||
| 943 | block.m_columnType = mtext.m_r2018ColumnType; | |||
| 944 | block.m_columnCount = mtext.m_r2018ColumnCount; | |||
| 945 | block.m_columnWidth = mtext.m_r2018ColumnWidth; | |||
| 946 | block.m_columnGutter = mtext.m_r2018ColumnGutter; | |||
| 947 | block.m_columnAutoHeight = mtext.m_r2018ColumnAutoHeight; | |||
| 948 | block.m_columnFlowReversed = mtext.m_r2018ColumnFlowReversed; | |||
| 949 | block.m_columnHeights = mtext.m_r2018ColumnHeights; | |||
| 950 | return block; | |||
| 951 | } | |||
| 952 | ||||
| 953 | void storeDwgMTextR2018Block(DwgMTextR2018Block&& block, DRW_MText& mtext) { | |||
| 954 | mtext.m_r2018Version = block.m_version; | |||
| 955 | mtext.m_r2018DefaultFlag = block.m_defaultFlag; | |||
| 956 | mtext.m_r2018Attachment = block.m_attachment; | |||
| 957 | mtext.m_r2018XAxisDir = block.m_xAxisDir; | |||
| 958 | mtext.m_r2018InsertionPoint = block.m_insertionPoint; | |||
| 959 | mtext.m_r2018RectWidth = block.m_rectWidth; | |||
| 960 | mtext.m_r2018RectHeight = block.m_rectHeight; | |||
| 961 | mtext.m_r2018ExtentsWidth = block.m_extentsWidth; | |||
| 962 | mtext.m_r2018ExtentsHeight = block.m_extentsHeight; | |||
| 963 | mtext.m_r2018ColumnType = block.m_columnType; | |||
| 964 | mtext.m_r2018ColumnCount = block.m_columnCount; | |||
| 965 | mtext.m_r2018ColumnWidth = block.m_columnWidth; | |||
| 966 | mtext.m_r2018ColumnGutter = block.m_columnGutter; | |||
| 967 | mtext.m_r2018ColumnAutoHeight = block.m_columnAutoHeight; | |||
| 968 | mtext.m_r2018ColumnFlowReversed = block.m_columnFlowReversed; | |||
| 969 | mtext.m_r2018ColumnHeights = std::move(block.m_columnHeights); | |||
| 970 | } | |||
| 971 | ||||
| 972 | bool putDwgMTextR2018Block(dwgBufferW *buf, const DwgMTextR2018Block& block) { | |||
| 973 | const bool listsHeights = !block.m_columnAutoHeight && block.m_columnType == 2; | |||
| 974 | std::int32_t columnCount = block.m_columnCount; | |||
| 975 | if (block.m_columnType > 2 || columnCount < 0 | |||
| 976 | || columnCount > kMaxMTextColumnHeights | |||
| 977 | || block.m_columnHeights.size() | |||
| 978 | > static_cast<std::size_t>(kMaxMTextColumnHeights)) | |||
| 979 | return false; | |||
| 980 | if (listsHeights && !block.m_columnHeights.empty()) | |||
| 981 | columnCount = static_cast<std::int32_t>(block.m_columnHeights.size()); | |||
| 982 | if (block.m_columnType != 0 && listsHeights | |||
| 983 | && static_cast<std::size_t>(columnCount) | |||
| 984 | != block.m_columnHeights.size()) | |||
| 985 | return false; | |||
| 986 | ||||
| 987 | buf->putBitShort(block.m_version); | |||
| 988 | buf->putBit(block.m_defaultFlag ? 1 : 0); | |||
| 989 | buf->putBitLong(block.m_attachment); | |||
| 990 | buf->put3BitDouble(block.m_xAxisDir); | |||
| 991 | buf->put3BitDouble(block.m_insertionPoint); | |||
| 992 | buf->putBitDouble(block.m_rectWidth); | |||
| 993 | buf->putBitDouble(block.m_rectHeight); | |||
| 994 | buf->putBitDouble(block.m_extentsWidth); | |||
| 995 | buf->putBitDouble(block.m_extentsHeight); | |||
| 996 | buf->putBitShort(block.m_columnType); | |||
| 997 | if (block.m_columnType != 0) { | |||
| 998 | buf->putBitLong(columnCount); | |||
| 999 | buf->putBitDouble(block.m_columnWidth); | |||
| 1000 | buf->putBitDouble(block.m_columnGutter); | |||
| 1001 | buf->putBit(block.m_columnAutoHeight ? 1 : 0); | |||
| 1002 | buf->putBit(block.m_columnFlowReversed ? 1 : 0); | |||
| 1003 | if (listsHeights) { | |||
| 1004 | for (const double columnHeight : block.m_columnHeights) | |||
| 1005 | buf->putBitDouble(columnHeight); | |||
| 1006 | } | |||
| 1007 | } | |||
| 1008 | return true; | |||
| 1009 | } | |||
| 1010 | ||||
| 1011 | bool readBoundedHatchGradient(dwgBuffer& body, dwgBuffer *stringBuffer, | |||
| 1012 | std::uint64_t endBit, DRW::Version version, | |||
| 1013 | int& isGradient, int& reserved, | |||
| 1014 | double& angle, double& shift, int& singleColor, | |||
| 1015 | double& tint, UTF8STRINGstd::string& name, | |||
| 1016 | std::vector<DRW_Hatch::GradientStop>& colors, | |||
| 1017 | std::uint64_t stringEndBit = | |||
| 1018 | std::numeric_limits<std::uint64_t>::max()) { | |||
| 1019 | std::int32_t parsedIsGradient = 0; | |||
| 1020 | std::int32_t parsedReserved = 0; | |||
| 1021 | std::int32_t parsedSingleColor = 0; | |||
| 1022 | double parsedAngle = 0.0; | |||
| 1023 | double parsedShift = 0.0; | |||
| 1024 | double parsedTint = 0.0; | |||
| 1025 | if (!readBoundedBitLong(body, endBit, parsedIsGradient) | |||
| 1026 | || !readBoundedBitLong(body, endBit, parsedReserved) | |||
| 1027 | || !readBoundedBitDouble(body, endBit, parsedAngle) | |||
| 1028 | || !readBoundedBitDouble(body, endBit, parsedShift) | |||
| 1029 | || !readBoundedBitLong(body, endBit, parsedSingleColor) | |||
| 1030 | || !readBoundedBitDouble(body, endBit, parsedTint)) | |||
| 1031 | return false; | |||
| 1032 | ||||
| 1033 | std::uint32_t colorCount = 0; | |||
| 1034 | if (!readTableBodyCount(version, &body, endBit, kMaxHatchItems, 14, | |||
| 1035 | colorCount)) | |||
| 1036 | return false; | |||
| 1037 | std::vector<DRW_Hatch::GradientStop> parsedColors; | |||
| 1038 | if (!DRW::reserve(parsedColors, colorCount)) | |||
| 1039 | return false; | |||
| 1040 | for (std::uint32_t i = 0; i < colorCount; ++i) { | |||
| 1041 | DRW_Hatch::GradientStop stop; | |||
| 1042 | std::uint16_t aciColor = 0; | |||
| 1043 | std::int32_t rgb = 0; | |||
| 1044 | std::uint8_t ignoredColor = 0; | |||
| 1045 | if (!readBoundedBitDouble(body, endBit, stop.value) | |||
| 1046 | || !readBoundedBitShort(body, endBit, aciColor) | |||
| 1047 | || !readBoundedBitLong(body, endBit, rgb) | |||
| 1048 | || !readBoundedRawChar8(body, endBit, ignoredColor) | |||
| 1049 | || !std::isfinite(stop.value)) | |||
| 1050 | return false; | |||
| 1051 | stop.aciColor = aciColor; | |||
| 1052 | stop.rgb = rgb; | |||
| 1053 | parsedColors.push_back(std::move(stop)); | |||
| 1054 | } | |||
| 1055 | ||||
| 1056 | UTF8STRINGstd::string parsedName; | |||
| 1057 | if (stringBuffer == nullptr | |||
| 1058 | || !readBoundedVariableText(*stringBuffer, stringEndBit, version, | |||
| 1059 | parsedName)) | |||
| 1060 | return false; | |||
| 1061 | ||||
| 1062 | if (!std::isfinite(parsedAngle) || !std::isfinite(parsedShift) | |||
| 1063 | || !std::isfinite(parsedTint)) | |||
| 1064 | return false; | |||
| 1065 | isGradient = parsedIsGradient; | |||
| 1066 | reserved = parsedReserved; | |||
| 1067 | angle = parsedAngle; | |||
| 1068 | shift = parsedShift; | |||
| 1069 | singleColor = parsedSingleColor; | |||
| 1070 | tint = parsedTint; | |||
| 1071 | name = std::move(parsedName); | |||
| 1072 | colors = std::move(parsedColors); | |||
| 1073 | return true; | |||
| 1074 | } | |||
| 1075 | ||||
| 1076 | struct SurfaceDwgPayloadInfo { | |||
| 1077 | bool acisEmpty = false; | |||
| 1078 | int acisVersion = 0; | |||
| 1079 | int modelerFormatVersion = 0; | |||
| 1080 | int uIsolines = 0; | |||
| 1081 | int vIsolines = 0; | |||
| 1082 | bool revolvedFieldsValid = false; | |||
| 1083 | std::uint32_t revolvedClassId = 0; | |||
| 1084 | std::uint32_t revolvedId = 0; | |||
| 1085 | DRW_Coord revolvedAxisPoint; | |||
| 1086 | DRW_Coord revolvedAxisVector; | |||
| 1087 | double revolvedAngle = 0.0; | |||
| 1088 | double revolvedStartAngle = 0.0; | |||
| 1089 | std::array<double, DRW_RevolvedSurface::kTransformSize> revolvedTransform{}; | |||
| 1090 | double revolvedDraftAngle = 0.0; | |||
| 1091 | double revolvedDraftStartDistance = 0.0; | |||
| 1092 | double revolvedDraftEndDistance = 0.0; | |||
| 1093 | double revolvedTwistAngle = 0.0; | |||
| 1094 | bool revolvedSolid = false; | |||
| 1095 | bool revolvedCloseToAxis = false; | |||
| 1096 | bool extrudedFieldsValid = false; | |||
| 1097 | DRW_Coord extrudedSweepVector; | |||
| 1098 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1099 | extrudedTransform{}; | |||
| 1100 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1101 | extrudedSweepEntityTransform{}; | |||
| 1102 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1103 | extrudedPathEntityTransform{}; | |||
| 1104 | double extrudedDraftAngle = 0.0; | |||
| 1105 | double extrudedDraftStartDistance = 0.0; | |||
| 1106 | double extrudedDraftEndDistance = 0.0; | |||
| 1107 | double extrudedTwistAngle = 0.0; | |||
| 1108 | double extrudedScaleFactor = 0.0; | |||
| 1109 | double extrudedAlignAngle = 0.0; | |||
| 1110 | bool extrudedSolid = false; | |||
| 1111 | std::int32_t extrudedSweepAlignmentFlags = 0; | |||
| 1112 | std::int32_t extrudedPathFlags = 0; | |||
| 1113 | bool extrudedAlignStart = false; | |||
| 1114 | bool extrudedBank = false; | |||
| 1115 | bool extrudedBasePointSet = false; | |||
| 1116 | bool extrudedSweepEntityTransformComputed = false; | |||
| 1117 | bool extrudedPathEntityTransformComputed = false; | |||
| 1118 | DRW_Coord extrudedReferenceVector; | |||
| 1119 | bool sweptFieldsValid = false; | |||
| 1120 | std::uint32_t sweptClassVersion = 0; | |||
| 1121 | std::uint32_t sweptEntityId = 0; | |||
| 1122 | std::vector<std::uint8_t> sweptData; | |||
| 1123 | std::uint32_t sweptPathEntityId = 0; | |||
| 1124 | std::vector<std::uint8_t> sweptPathData; | |||
| 1125 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1126 | sweptEntityTransform{}; | |||
| 1127 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1128 | sweptPathEntityTransform{}; | |||
| 1129 | double sweptDraftAngle = 0.0; | |||
| 1130 | double sweptDraftStartDistance = 0.0; | |||
| 1131 | double sweptDraftEndDistance = 0.0; | |||
| 1132 | double sweptTwistAngle = 0.0; | |||
| 1133 | double sweptScaleFactor = 1.0; | |||
| 1134 | double sweptAlignAngle = 0.0; | |||
| 1135 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1136 | sweptEntityTransformed{}; | |||
| 1137 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1138 | sweptPathEntityTransformed{}; | |||
| 1139 | bool sweptSolid = false; | |||
| 1140 | std::int32_t sweptAlignmentFlags = 0; | |||
| 1141 | std::int32_t sweptPathFlags = 0; | |||
| 1142 | bool sweptAlignStart = false; | |||
| 1143 | bool sweptBank = false; | |||
| 1144 | bool sweptBasePointSet = false; | |||
| 1145 | bool sweptEntityTransformComputed = false; | |||
| 1146 | bool sweptPathEntityTransformComputed = false; | |||
| 1147 | DRW_Coord sweptReferenceVector; | |||
| 1148 | bool loftedFieldsValid = false; | |||
| 1149 | std::array<double, DRW_LoftedSurface::kTransformSize> | |||
| 1150 | loftedEntityTransform{}; | |||
| 1151 | std::int32_t loftedPlaneNormalLoftingType = 0; | |||
| 1152 | double loftedStartDraftAngle = 0.0; | |||
| 1153 | double loftedEndDraftAngle = 0.0; | |||
| 1154 | double loftedStartDraftMagnitude = 0.0; | |||
| 1155 | double loftedEndDraftMagnitude = 0.0; | |||
| 1156 | bool loftedArcLengthParameterization = false; | |||
| 1157 | bool loftedNoTwist = true; | |||
| 1158 | bool loftedAlignDirection = true; | |||
| 1159 | bool loftedSimpleSurfaces = true; | |||
| 1160 | bool loftedClosedSurfaces = false; | |||
| 1161 | bool loftedSolid = false; | |||
| 1162 | bool loftedRuledSurface = false; | |||
| 1163 | bool loftedVirtualGuide = false; | |||
| 1164 | std::int32_t loftedNumCrossSections = 0; | |||
| 1165 | std::int32_t loftedNumGuideCurves = 0; | |||
| 1166 | bool nurbsFieldsValid = false; | |||
| 1167 | std::uint16_t nurbsShort170 = 0; | |||
| 1168 | bool nurbsCvHullDisplay = false; | |||
| 1169 | DRW_Coord nurbsUvec1; | |||
| 1170 | DRW_Coord nurbsVvec1; | |||
| 1171 | DRW_Coord nurbsUvec2; | |||
| 1172 | DRW_Coord nurbsVvec2; | |||
| 1173 | }; | |||
| 1174 | ||||
| 1175 | std::uint64_t surfaceDwgBit(const dwgBuffer& buffer) { | |||
| 1176 | return buffer.getPosition() * 8u + buffer.getBitPos(); | |||
| 1177 | } | |||
| 1178 | ||||
| 1179 | bool surfaceDwgHasBits(const dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1180 | std::uint64_t count) { | |||
| 1181 | const std::uint64_t current = surfaceDwgBit(buffer); | |||
| 1182 | return current <= endBit && count <= endBit - current; | |||
| 1183 | } | |||
| 1184 | ||||
| 1185 | bool surfaceDwgReadBit(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1186 | std::uint8_t& value) { | |||
| 1187 | if (!surfaceDwgHasBits(buffer, endBit, 1)) | |||
| 1188 | return false; | |||
| 1189 | // Probe variable-width fields on a fork so a short object frame cannot | |||
| 1190 | // invalidate the reader before the caller re-anchors at its boundary. | |||
| 1191 | dwgBuffer candidate(buffer); | |||
| 1192 | value = candidate.getBit(); | |||
| 1193 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1194 | return false; | |||
| 1195 | buffer = candidate; | |||
| 1196 | return true; | |||
| 1197 | } | |||
| 1198 | ||||
| 1199 | bool surfaceDwgReadRawChar(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1200 | std::uint8_t& value) { | |||
| 1201 | if (!surfaceDwgHasBits(buffer, endBit, 8)) | |||
| 1202 | return false; | |||
| 1203 | dwgBuffer candidate(buffer); | |||
| 1204 | value = candidate.getRawChar8(); | |||
| 1205 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1206 | return false; | |||
| 1207 | buffer = candidate; | |||
| 1208 | return true; | |||
| 1209 | } | |||
| 1210 | ||||
| 1211 | bool surfaceDwgReadRawChar(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 1212 | std::uint8_t value = 0; | |||
| 1213 | return surfaceDwgReadRawChar(buffer, endBit, value); | |||
| 1214 | } | |||
| 1215 | ||||
| 1216 | bool surfaceDwgReadBitShort(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1217 | std::uint16_t& value) { | |||
| 1218 | if (!surfaceDwgHasBits(buffer, endBit, 2)) | |||
| 1219 | return false; | |||
| 1220 | dwgBuffer candidate(buffer); | |||
| 1221 | value = candidate.getBitShort(); | |||
| 1222 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1223 | return false; | |||
| 1224 | buffer = candidate; | |||
| 1225 | return true; | |||
| 1226 | } | |||
| 1227 | ||||
| 1228 | bool surfaceDwgReadBitLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1229 | std::int32_t& value) { | |||
| 1230 | if (!surfaceDwgHasBits(buffer, endBit, 2)) | |||
| 1231 | return false; | |||
| 1232 | dwgBuffer candidate(buffer); | |||
| 1233 | value = candidate.getBitLong(); | |||
| 1234 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1235 | return false; | |||
| 1236 | buffer = candidate; | |||
| 1237 | return true; | |||
| 1238 | } | |||
| 1239 | ||||
| 1240 | bool surfaceDwgReadDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1241 | double& value) { | |||
| 1242 | if (!surfaceDwgHasBits(buffer, endBit, 2)) | |||
| 1243 | return false; | |||
| 1244 | dwgBuffer candidate(buffer); | |||
| 1245 | value = candidate.getBitDouble(); | |||
| 1246 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit | |||
| 1247 | || !std::isfinite(value)) | |||
| 1248 | return false; | |||
| 1249 | buffer = candidate; | |||
| 1250 | return true; | |||
| 1251 | } | |||
| 1252 | ||||
| 1253 | bool surfaceDwgReadDouble(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 1254 | double value = 0.0; | |||
| 1255 | return surfaceDwgReadDouble(buffer, endBit, value); | |||
| 1256 | } | |||
| 1257 | ||||
| 1258 | bool surfaceDwgRead3BitDouble(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 1259 | return surfaceDwgReadDouble(buffer, endBit) | |||
| 1260 | && surfaceDwgReadDouble(buffer, endBit) | |||
| 1261 | && surfaceDwgReadDouble(buffer, endBit); | |||
| 1262 | } | |||
| 1263 | ||||
| 1264 | bool surfaceDwgRead3BitDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1265 | DRW_Coord& value) { | |||
| 1266 | return surfaceDwgReadDouble(buffer, endBit, value.x) | |||
| 1267 | && surfaceDwgReadDouble(buffer, endBit, value.y) | |||
| 1268 | && surfaceDwgReadDouble(buffer, endBit, value.z); | |||
| 1269 | } | |||
| 1270 | ||||
| 1271 | bool surfaceDwgSkipBytes(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1272 | std::uint64_t count) { | |||
| 1273 | const std::uint64_t current = surfaceDwgBit(buffer); | |||
| 1274 | if (current > endBit | |||
| 1275 | || count > static_cast<std::uint64_t>(std::numeric_limits<std::int32_t>::max()) / 8u | |||
| 1276 | || count > (endBit - current) / 8u) | |||
| 1277 | return false; | |||
| 1278 | return buffer.moveBitPos(static_cast<std::int32_t>(count * 8u)) | |||
| 1279 | && buffer.isGood() && surfaceDwgBit(buffer) <= endBit; | |||
| 1280 | } | |||
| 1281 | ||||
| 1282 | bool surfaceDwgReadBytes(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1283 | std::int32_t count, std::size_t maxCount, | |||
| 1284 | std::vector<std::uint8_t>& data) { | |||
| 1285 | if (count < 0 || static_cast<std::size_t>(count) > maxCount | |||
| 1286 | || !surfaceDwgHasBits(buffer, endBit, | |||
| 1287 | static_cast<std::uint64_t>(count) * 8u)) | |||
| 1288 | return false; | |||
| 1289 | dwgBuffer candidate(buffer); | |||
| 1290 | std::vector<std::uint8_t> decoded; | |||
| 1291 | if (!DRW::resize(decoded, count)) | |||
| 1292 | return false; | |||
| 1293 | for (std::uint8_t& value : decoded) { | |||
| 1294 | if (!surfaceDwgReadRawChar(candidate, endBit, value)) | |||
| 1295 | return false; | |||
| 1296 | } | |||
| 1297 | data = std::move(decoded); | |||
| 1298 | buffer = candidate; | |||
| 1299 | return true; | |||
| 1300 | } | |||
| 1301 | ||||
| 1302 | std::uint8_t surfaceDwgPeekByte(const std::vector<std::uint8_t>& data, | |||
| 1303 | std::size_t index, std::uint8_t bit) { | |||
| 1304 | if (index >= data.size()) | |||
| 1305 | return 0; | |||
| 1306 | if (bit == 0) | |||
| 1307 | return data[index]; | |||
| 1308 | const std::uint8_t next = index + 1 < data.size() ? data[index + 1] : 0; | |||
| 1309 | return static_cast<std::uint8_t>((data[index] << bit) | (next >> (8 - bit))); | |||
| 1310 | } | |||
| 1311 | ||||
| 1312 | std::size_t surfaceDwgFindMarker(const std::vector<std::uint8_t>& data, | |||
| 1313 | std::size_t start, std::uint8_t bit, | |||
| 1314 | const std::uint8_t* marker, | |||
| 1315 | std::size_t markerSize) { | |||
| 1316 | if (marker == nullptr || markerSize == 0 || data.size() < markerSize | |||
| 1317 | || start > data.size() - markerSize) | |||
| 1318 | return std::numeric_limits<std::size_t>::max(); | |||
| 1319 | for (std::size_t index = start; index <= data.size() - markerSize; ++index) { | |||
| 1320 | bool matched = true; | |||
| 1321 | for (std::size_t offset = 0; offset < markerSize; ++offset) { | |||
| 1322 | if (surfaceDwgPeekByte(data, index + offset, bit) != marker[offset]) { | |||
| 1323 | matched = false; | |||
| 1324 | break; | |||
| 1325 | } | |||
| 1326 | } | |||
| 1327 | if (matched) | |||
| 1328 | return index; | |||
| 1329 | } | |||
| 1330 | return std::numeric_limits<std::size_t>::max(); | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | bool surfaceDwgSkipAcis(dwgBuffer& buffer, const std::vector<std::uint8_t>& data, | |||
| 1334 | std::uint64_t endBit, bool& acisEmpty, int& acisVersion) { | |||
| 1335 | std::uint8_t empty = 0; | |||
| 1336 | if (!surfaceDwgReadBit(buffer, endBit, empty)) | |||
| 1337 | return false; | |||
| 1338 | acisEmpty = empty != 0; | |||
| 1339 | if (acisEmpty) | |||
| 1340 | return true; | |||
| 1341 | ||||
| 1342 | std::uint8_t unused = 0; | |||
| 1343 | std::uint16_t version = 0; | |||
| 1344 | if (!surfaceDwgReadBit(buffer, endBit, unused) | |||
| 1345 | || !surfaceDwgReadBitShort(buffer, endBit, version)) | |||
| 1346 | return false; | |||
| 1347 | acisVersion = static_cast<int>(version); | |||
| 1348 | ||||
| 1349 | if (version == 2) { | |||
| 1350 | static constexpr std::uint8_t endAcis[] = { | |||
| 1351 | 0x0E, 0x03, 0x45, 0x6E, 0x64, 0x0E, 0x02, 0x6F, 0x66, 0x0E, | |||
| 1352 | 0x04, 0x41, 0x43, 0x49, 0x53, 0x0D, 0x04, 0x64, 0x61, 0x74, | |||
| 1353 | 0x61}; | |||
| 1354 | static constexpr std::uint8_t endAsm[] = { | |||
| 1355 | 0x0E, 0x03, 0x45, 0x6E, 0x64, 0x0E, 0x02, 0x6F, 0x66, 0x0E, | |||
| 1356 | 0x03, 0x41, 0x53, 0x4D, 0x0D, 0x04, 0x64, 0x61, 0x74, 0x61}; | |||
| 1357 | const std::size_t start = static_cast<std::size_t>(buffer.getPosition()); | |||
| 1358 | const std::uint8_t bit = buffer.getBitPos(); | |||
| 1359 | std::size_t marker = surfaceDwgFindMarker( | |||
| 1360 | data, start, bit, endAcis, sizeof(endAcis)); | |||
| 1361 | std::size_t markerSize = sizeof(endAcis); | |||
| 1362 | if (marker == std::numeric_limits<std::size_t>::max()) { | |||
| 1363 | marker = surfaceDwgFindMarker( | |||
| 1364 | data, start, bit, endAsm, sizeof(endAsm)); | |||
| 1365 | markerSize = sizeof(endAsm); | |||
| 1366 | } | |||
| 1367 | if (marker == std::numeric_limits<std::size_t>::max() | |||
| 1368 | || marker < start) | |||
| 1369 | return false; | |||
| 1370 | return surfaceDwgSkipBytes(buffer, endBit, | |||
| 1371 | marker - start + markerSize); | |||
| 1372 | } | |||
| 1373 | ||||
| 1374 | for (std::uint32_t block = 0; block < 65536u; ++block) { | |||
| 1375 | std::int32_t blockSize = 0; | |||
| 1376 | if (!surfaceDwgReadBitLong(buffer, endBit, blockSize)) | |||
| 1377 | return false; | |||
| 1378 | if (blockSize == 0) | |||
| 1379 | return true; | |||
| 1380 | if (blockSize < 0 | |||
| 1381 | || !surfaceDwgSkipBytes(buffer, endBit, | |||
| 1382 | static_cast<std::uint32_t>(blockSize))) | |||
| 1383 | return false; | |||
| 1384 | } | |||
| 1385 | return false; | |||
| 1386 | } | |||
| 1387 | ||||
| 1388 | bool surfaceDwgSkipWire(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1389 | DRW::Version version) { | |||
| 1390 | if (!surfaceDwgReadRawChar(buffer, endBit)) | |||
| 1391 | return false; | |||
| 1392 | std::int32_t ignored = 0; | |||
| 1393 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1394 | return false; | |||
| 1395 | std::uint16_t color = 0; | |||
| 1396 | if (version < DRW::AC1018) { | |||
| 1397 | if (!surfaceDwgReadBitShort(buffer, endBit, color)) | |||
| 1398 | return false; | |||
| 1399 | } else if (!surfaceDwgReadBitLong(buffer, endBit, ignored)) { | |||
| 1400 | return false; | |||
| 1401 | } | |||
| 1402 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1403 | return false; | |||
| 1404 | ||||
| 1405 | std::int32_t pointCount = 0; | |||
| 1406 | if (!surfaceDwgReadBitLong(buffer, endBit, pointCount) | |||
| 1407 | || pointCount < 0 || pointCount > 1000000) | |||
| 1408 | return false; | |||
| 1409 | for (std::int32_t point = 0; point < pointCount; ++point) { | |||
| 1410 | if (!surfaceDwgRead3BitDouble(buffer, endBit)) | |||
| 1411 | return false; | |||
| 1412 | } | |||
| 1413 | ||||
| 1414 | std::uint8_t transformPresent = 0; | |||
| 1415 | if (!surfaceDwgReadBit(buffer, endBit, transformPresent)) | |||
| 1416 | return false; | |||
| 1417 | if (transformPresent != 0) { | |||
| 1418 | for (int field = 0; field < 5; ++field) { | |||
| 1419 | if (!surfaceDwgRead3BitDouble(buffer, endBit)) | |||
| 1420 | return false; | |||
| 1421 | } | |||
| 1422 | for (int field = 0; field < 3; ++field) { | |||
| 1423 | if (!surfaceDwgReadBit(buffer, endBit, transformPresent)) | |||
| 1424 | return false; | |||
| 1425 | } | |||
| 1426 | } | |||
| 1427 | return true; | |||
| 1428 | } | |||
| 1429 | ||||
| 1430 | bool surfaceDwgSkipCommon3dSolid(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1431 | DRW::Version version, int acisVersion) { | |||
| 1432 | std::uint8_t present = 0; | |||
| 1433 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1434 | return false; | |||
| 1435 | if (present != 0) { | |||
| 1436 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1437 | return false; | |||
| 1438 | if (present != 0 && !surfaceDwgRead3BitDouble(buffer, endBit)) | |||
| 1439 | return false; | |||
| 1440 | ||||
| 1441 | std::int32_t ignored = 0; | |||
| 1442 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1443 | || !surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1444 | return false; | |||
| 1445 | if (present != 0) { | |||
| 1446 | std::int32_t count = 0; | |||
| 1447 | if (!surfaceDwgReadBitLong(buffer, endBit, count) | |||
| 1448 | || count < 0 || count > 1000000) | |||
| 1449 | return false; | |||
| 1450 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 1451 | if (!surfaceDwgSkipWire(buffer, endBit, version)) | |||
| 1452 | return false; | |||
| 1453 | } | |||
| 1454 | if (!surfaceDwgReadBitLong(buffer, endBit, count) | |||
| 1455 | || count < 0 || count > 1000000) | |||
| 1456 | return false; | |||
| 1457 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 1458 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1459 | || !surfaceDwgRead3BitDouble(buffer, endBit) | |||
| 1460 | || !surfaceDwgRead3BitDouble(buffer, endBit) | |||
| 1461 | || !surfaceDwgRead3BitDouble(buffer, endBit) | |||
| 1462 | || !surfaceDwgReadBit(buffer, endBit, present) | |||
| 1463 | || !surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1464 | return false; | |||
| 1465 | if (present != 0) { | |||
| 1466 | std::int32_t wireCount = 0; | |||
| 1467 | if (!surfaceDwgReadBitLong(buffer, endBit, wireCount) | |||
| 1468 | || wireCount < 0 || wireCount > 1000000) | |||
| 1469 | return false; | |||
| 1470 | for (std::int32_t wire = 0; wire < wireCount; ++wire) { | |||
| 1471 | if (!surfaceDwgSkipWire(buffer, endBit, version)) | |||
| 1472 | return false; | |||
| 1473 | } | |||
| 1474 | } | |||
| 1475 | } | |||
| 1476 | } | |||
| 1477 | } | |||
| 1478 | ||||
| 1479 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1480 | return false; | |||
| 1481 | if (acisVersion > 1 && version >= DRW::AC1021) { | |||
| 1482 | std::int32_t count = 0; | |||
| 1483 | if (!surfaceDwgReadBitLong(buffer, endBit, count) | |||
| 1484 | || count < 0 || count > 1000000) | |||
| 1485 | return false; | |||
| 1486 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 1487 | std::int32_t ignored = 0; | |||
| 1488 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1489 | || !surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1490 | return false; | |||
| 1491 | } | |||
| 1492 | } | |||
| 1493 | if (version >= DRW::AC1027) { | |||
| 1494 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1495 | return false; | |||
| 1496 | std::int32_t ignored = 0; | |||
| 1497 | std::uint16_t ignoredShort = 0; | |||
| 1498 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1499 | || !surfaceDwgReadBitShort(buffer, endBit, ignoredShort) | |||
| 1500 | || !surfaceDwgReadBitShort(buffer, endBit, ignoredShort) | |||
| 1501 | || !surfaceDwgSkipBytes(buffer, endBit, 8) | |||
| 1502 | || !surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1503 | return false; | |||
| 1504 | } | |||
| 1505 | return true; | |||
| 1506 | } | |||
| 1507 | ||||
| 1508 | bool surfaceHasModelerFormatVersion(DRW::ETYPE type) { | |||
| 1509 | switch (type) { | |||
| 1510 | case DRW::PLANESURFACE: | |||
| 1511 | case DRW::LOFTEDSURFACE: | |||
| 1512 | case DRW::REVOLVEDSURFACE: | |||
| 1513 | case DRW::SWEPTSURFACE: | |||
| 1514 | return true; | |||
| 1515 | case DRW::EXTRUDEDSURFACE: | |||
| 1516 | case DRW::NURBSURFACE: | |||
| 1517 | default: | |||
| 1518 | return false; | |||
| 1519 | } | |||
| 1520 | } | |||
| 1521 | ||||
| 1522 | std::uint16_t surfaceModelerFormatVersionLimit(DRW::ETYPE type) { | |||
| 1523 | return type == DRW::LOFTEDSURFACE ? kMaxLoftedSurfaceModelerFormatVersion | |||
| 1524 | : std::numeric_limits<std::uint16_t>::max(); | |||
| 1525 | } | |||
| 1526 | ||||
| 1527 | bool readSurfaceDwgPayload(const std::vector<std::uint8_t>& data, | |||
| 1528 | std::uint64_t bitSize, DRW::Version version, | |||
| 1529 | DRW::ETYPE type, | |||
| 1530 | bool hasModelerFormatVersion, | |||
| 1531 | std::uint16_t modelerFormatVersionLimit, | |||
| 1532 | SurfaceDwgPayloadInfo& info) { | |||
| 1533 | if (data.empty() || bitSize == 0 | |||
| 1534 | || bitSize > static_cast<std::uint64_t>(data.size()) * 8u) | |||
| 1535 | return false; | |||
| 1536 | ||||
| 1537 | std::vector<std::uint8_t> payload = data; | |||
| 1538 | dwgBuffer buffer(payload.data(), payload.size()); | |||
| 1539 | const std::uint64_t endBit = bitSize; | |||
| 1540 | bool acisEmpty = false; | |||
| 1541 | int acisVersion = 0; | |||
| 1542 | if (!surfaceDwgSkipAcis(buffer, payload, endBit, acisEmpty, acisVersion)) | |||
| 1543 | return false; | |||
| 1544 | if (!acisEmpty | |||
| 1545 | && !surfaceDwgSkipCommon3dSolid(buffer, endBit, version, acisVersion)) | |||
| 1546 | return false; | |||
| 1547 | ||||
| 1548 | std::uint16_t modelerFormatVersion = 0; | |||
| 1549 | std::uint16_t uIsolines = 0; | |||
| 1550 | std::uint16_t vIsolines = 0; | |||
| 1551 | if ((hasModelerFormatVersion | |||
| 1552 | && !surfaceDwgReadBitShort(buffer, endBit, modelerFormatVersion)) | |||
| 1553 | || !surfaceDwgReadBitShort(buffer, endBit, uIsolines) | |||
| 1554 | || !surfaceDwgReadBitShort(buffer, endBit, vIsolines)) { | |||
| 1555 | return false; | |||
| 1556 | } | |||
| 1557 | if (hasModelerFormatVersion | |||
| 1558 | && modelerFormatVersion > modelerFormatVersionLimit) | |||
| 1559 | return false; | |||
| 1560 | ||||
| 1561 | if (type == DRW::EXTRUDEDSURFACE) { | |||
| 1562 | // DWG stores SweepOptions before the sweep vector and its transform; | |||
| 1563 | // keep the candidate isolated because the same fields have a | |||
| 1564 | // different order in the DXF subclass. | |||
| 1565 | dwgBuffer candidate = buffer; | |||
| 1566 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1567 | sweepEntityTransform{}; | |||
| 1568 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1569 | pathEntityTransform{}; | |||
| 1570 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1571 | extrudedTransform{}; | |||
| 1572 | double draftAngle = 0.0; | |||
| 1573 | double draftStartDistance = 0.0; | |||
| 1574 | double draftEndDistance = 0.0; | |||
| 1575 | double twistAngle = 0.0; | |||
| 1576 | double scaleFactor = 0.0; | |||
| 1577 | double alignAngle = 0.0; | |||
| 1578 | std::uint8_t solid = 0; | |||
| 1579 | std::uint16_t sweepAlignmentFlags = 0; | |||
| 1580 | std::uint16_t pathFlags = 0; | |||
| 1581 | std::uint8_t alignStart = 0; | |||
| 1582 | std::uint8_t bank = 0; | |||
| 1583 | std::uint8_t basePointSet = 0; | |||
| 1584 | std::uint8_t sweepEntityTransformComputed = 0; | |||
| 1585 | std::uint8_t pathEntityTransformComputed = 0; | |||
| 1586 | DRW_Coord referenceVector; | |||
| 1587 | DRW_Coord sweepVector; | |||
| 1588 | auto readMatrix = [&](std::array<double, | |||
| 1589 | DRW_ExtrudedSurface::kTransformSize>& matrix) { | |||
| 1590 | for (double& value : matrix) { | |||
| 1591 | if (!surfaceDwgReadDouble(candidate, endBit, value)) | |||
| 1592 | return false; | |||
| 1593 | } | |||
| 1594 | return true; | |||
| 1595 | }; | |||
| 1596 | bool valid = surfaceDwgReadDouble(candidate, endBit, draftAngle) | |||
| 1597 | && surfaceDwgReadDouble(candidate, endBit, draftStartDistance) | |||
| 1598 | && surfaceDwgReadDouble(candidate, endBit, draftEndDistance) | |||
| 1599 | && surfaceDwgReadDouble(candidate, endBit, twistAngle) | |||
| 1600 | && surfaceDwgReadDouble(candidate, endBit, scaleFactor) | |||
| 1601 | && surfaceDwgReadDouble(candidate, endBit, alignAngle) | |||
| 1602 | && readMatrix(sweepEntityTransform) | |||
| 1603 | && readMatrix(pathEntityTransform) | |||
| 1604 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1605 | && surfaceDwgReadBitShort(candidate, endBit, sweepAlignmentFlags) | |||
| 1606 | && surfaceDwgReadBitShort(candidate, endBit, pathFlags) | |||
| 1607 | && surfaceDwgReadBit(candidate, endBit, alignStart) | |||
| 1608 | && surfaceDwgReadBit(candidate, endBit, bank) | |||
| 1609 | && surfaceDwgReadBit(candidate, endBit, basePointSet) | |||
| 1610 | && surfaceDwgReadBit(candidate, endBit, sweepEntityTransformComputed) | |||
| 1611 | && surfaceDwgReadBit(candidate, endBit, pathEntityTransformComputed) | |||
| 1612 | && surfaceDwgRead3BitDouble(candidate, endBit, referenceVector) | |||
| 1613 | && surfaceDwgRead3BitDouble(candidate, endBit, sweepVector) | |||
| 1614 | && readMatrix(extrudedTransform); | |||
| 1615 | if (valid) { | |||
| 1616 | info.extrudedFieldsValid = true; | |||
| 1617 | info.extrudedSweepVector = sweepVector; | |||
| 1618 | info.extrudedTransform = extrudedTransform; | |||
| 1619 | info.extrudedSweepEntityTransform = sweepEntityTransform; | |||
| 1620 | info.extrudedPathEntityTransform = pathEntityTransform; | |||
| 1621 | info.extrudedDraftAngle = draftAngle; | |||
| 1622 | info.extrudedDraftStartDistance = draftStartDistance; | |||
| 1623 | info.extrudedDraftEndDistance = draftEndDistance; | |||
| 1624 | info.extrudedTwistAngle = twistAngle; | |||
| 1625 | info.extrudedScaleFactor = scaleFactor; | |||
| 1626 | info.extrudedAlignAngle = alignAngle; | |||
| 1627 | info.extrudedSolid = solid != 0; | |||
| 1628 | info.extrudedSweepAlignmentFlags = sweepAlignmentFlags; | |||
| 1629 | info.extrudedPathFlags = pathFlags; | |||
| 1630 | info.extrudedAlignStart = alignStart != 0; | |||
| 1631 | info.extrudedBank = bank != 0; | |||
| 1632 | info.extrudedBasePointSet = basePointSet != 0; | |||
| 1633 | info.extrudedSweepEntityTransformComputed = | |||
| 1634 | sweepEntityTransformComputed != 0; | |||
| 1635 | info.extrudedPathEntityTransformComputed = | |||
| 1636 | pathEntityTransformComputed != 0; | |||
| 1637 | info.extrudedReferenceVector = referenceVector; | |||
| 1638 | } | |||
| 1639 | } else if (type == DRW::LOFTEDSURFACE) { | |||
| 1640 | dwgBuffer candidate = buffer; | |||
| 1641 | std::array<double, DRW_LoftedSurface::kTransformSize> | |||
| 1642 | loftEntityTransform{}; | |||
| 1643 | std::int32_t planeNormalLoftingType = 0; | |||
| 1644 | double startDraftAngle = 0.0; | |||
| 1645 | double endDraftAngle = 0.0; | |||
| 1646 | double startDraftMagnitude = 0.0; | |||
| 1647 | double endDraftMagnitude = 0.0; | |||
| 1648 | std::uint8_t arcLengthParameterization = 0; | |||
| 1649 | std::uint8_t noTwist = 0; | |||
| 1650 | std::uint8_t alignDirection = 0; | |||
| 1651 | std::uint8_t simpleSurfaces = 0; | |||
| 1652 | std::uint8_t closedSurfaces = 0; | |||
| 1653 | std::uint8_t solid = 0; | |||
| 1654 | std::uint8_t ruledSurface = 0; | |||
| 1655 | std::uint8_t virtualGuide = 0; | |||
| 1656 | std::uint16_t numCrossSections = 0; | |||
| 1657 | std::uint16_t numGuideCurves = 0; | |||
| 1658 | auto readMatrix = [&](std::array<double, | |||
| 1659 | DRW_LoftedSurface::kTransformSize>& matrix) { | |||
| 1660 | for (double& value : matrix) { | |||
| 1661 | if (!surfaceDwgReadDouble(candidate, endBit, value)) | |||
| 1662 | return false; | |||
| 1663 | } | |||
| 1664 | return true; | |||
| 1665 | }; | |||
| 1666 | const bool valid = readMatrix(loftEntityTransform) | |||
| 1667 | && surfaceDwgReadBitLong(candidate, endBit, | |||
| 1668 | planeNormalLoftingType) | |||
| 1669 | && surfaceDwgReadDouble(candidate, endBit, startDraftAngle) | |||
| 1670 | && surfaceDwgReadDouble(candidate, endBit, endDraftAngle) | |||
| 1671 | && surfaceDwgReadDouble(candidate, endBit, startDraftMagnitude) | |||
| 1672 | && surfaceDwgReadDouble(candidate, endBit, endDraftMagnitude) | |||
| 1673 | && surfaceDwgReadBit(candidate, endBit, arcLengthParameterization) | |||
| 1674 | && surfaceDwgReadBit(candidate, endBit, noTwist) | |||
| 1675 | && surfaceDwgReadBit(candidate, endBit, alignDirection) | |||
| 1676 | && surfaceDwgReadBit(candidate, endBit, simpleSurfaces) | |||
| 1677 | && surfaceDwgReadBit(candidate, endBit, closedSurfaces) | |||
| 1678 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1679 | && surfaceDwgReadBit(candidate, endBit, ruledSurface) | |||
| 1680 | && surfaceDwgReadBit(candidate, endBit, virtualGuide) | |||
| 1681 | && surfaceDwgReadBitShort(candidate, endBit, numCrossSections) | |||
| 1682 | && surfaceDwgReadBitShort(candidate, endBit, numGuideCurves) | |||
| 1683 | && numCrossSections <= DRW_LoftedSurface::kMaxReferenceTokenCount | |||
| 1684 | && numGuideCurves <= DRW_LoftedSurface::kMaxReferenceTokenCount; | |||
| 1685 | if (valid) { | |||
| 1686 | info.loftedFieldsValid = true; | |||
| 1687 | info.loftedEntityTransform = loftEntityTransform; | |||
| 1688 | info.loftedPlaneNormalLoftingType = planeNormalLoftingType; | |||
| 1689 | info.loftedStartDraftAngle = startDraftAngle; | |||
| 1690 | info.loftedEndDraftAngle = endDraftAngle; | |||
| 1691 | info.loftedStartDraftMagnitude = startDraftMagnitude; | |||
| 1692 | info.loftedEndDraftMagnitude = endDraftMagnitude; | |||
| 1693 | info.loftedArcLengthParameterization = arcLengthParameterization != 0; | |||
| 1694 | info.loftedNoTwist = noTwist != 0; | |||
| 1695 | info.loftedAlignDirection = alignDirection != 0; | |||
| 1696 | info.loftedSimpleSurfaces = simpleSurfaces != 0; | |||
| 1697 | info.loftedClosedSurfaces = closedSurfaces != 0; | |||
| 1698 | info.loftedSolid = solid != 0; | |||
| 1699 | info.loftedRuledSurface = ruledSurface != 0; | |||
| 1700 | info.loftedVirtualGuide = virtualGuide != 0; | |||
| 1701 | info.loftedNumCrossSections = numCrossSections; | |||
| 1702 | info.loftedNumGuideCurves = numGuideCurves; | |||
| 1703 | } | |||
| 1704 | } else if (type == DRW::SWEPTSURFACE) { | |||
| 1705 | dwgBuffer candidate = buffer; | |||
| 1706 | std::int32_t classVersion = 0; | |||
| 1707 | std::int32_t sweepEntityId = 0; | |||
| 1708 | std::int32_t sweepDataSize = 0; | |||
| 1709 | std::int32_t pathEntityId = 0; | |||
| 1710 | std::int32_t pathDataSize = 0; | |||
| 1711 | std::vector<std::uint8_t> sweepData; | |||
| 1712 | std::vector<std::uint8_t> pathData; | |||
| 1713 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1714 | sweepEntityTransform{}; | |||
| 1715 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1716 | pathEntityTransform{}; | |||
| 1717 | double draftAngle = 0.0; | |||
| 1718 | double draftStartDistance = 0.0; | |||
| 1719 | double draftEndDistance = 0.0; | |||
| 1720 | double twistAngle = 0.0; | |||
| 1721 | double scaleFactor = 1.0; | |||
| 1722 | double alignAngle = 0.0; | |||
| 1723 | std::uint8_t solid = 0; | |||
| 1724 | std::uint16_t sweepAlignmentFlags = 0; | |||
| 1725 | std::uint16_t pathFlags = 0; | |||
| 1726 | std::uint8_t alignStart = 0; | |||
| 1727 | std::uint8_t bank = 0; | |||
| 1728 | std::uint8_t basePointSet = 0; | |||
| 1729 | std::uint8_t sweepEntityTransformComputed = 0; | |||
| 1730 | std::uint8_t pathEntityTransformComputed = 0; | |||
| 1731 | DRW_Coord referenceVector; | |||
| 1732 | auto readMatrix = [&](std::array<double, | |||
| 1733 | DRW_SweptSurface::kTransformSize>& matrix) { | |||
| 1734 | for (double& value : matrix) { | |||
| 1735 | if (!surfaceDwgReadDouble(candidate, endBit, value)) | |||
| 1736 | return false; | |||
| 1737 | } | |||
| 1738 | return true; | |||
| 1739 | }; | |||
| 1740 | bool valid = surfaceDwgReadBitLong(candidate, endBit, classVersion) | |||
| 1741 | && classVersion >= 0 && classVersion <= 10 | |||
| 1742 | && surfaceDwgReadBitLong(candidate, endBit, sweepEntityId) | |||
| 1743 | && sweepEntityId >= 0 | |||
| 1744 | && surfaceDwgReadBitLong(candidate, endBit, sweepDataSize) | |||
| 1745 | && surfaceDwgReadBytes(candidate, endBit, sweepDataSize, | |||
| 1746 | DRW_SweptSurface::kMaxSweepDataSize, | |||
| 1747 | sweepData) | |||
| 1748 | && surfaceDwgReadBitLong(candidate, endBit, pathEntityId) | |||
| 1749 | && pathEntityId >= 0 | |||
| 1750 | && surfaceDwgReadBitLong(candidate, endBit, pathDataSize) | |||
| 1751 | && surfaceDwgReadBytes(candidate, endBit, pathDataSize, | |||
| 1752 | DRW_SweptSurface::kMaxSweepDataSize, | |||
| 1753 | pathData) | |||
| 1754 | && surfaceDwgReadDouble(candidate, endBit, draftAngle) | |||
| 1755 | && surfaceDwgReadDouble(candidate, endBit, draftStartDistance) | |||
| 1756 | && surfaceDwgReadDouble(candidate, endBit, draftEndDistance) | |||
| 1757 | && surfaceDwgReadDouble(candidate, endBit, twistAngle) | |||
| 1758 | && surfaceDwgReadDouble(candidate, endBit, scaleFactor) | |||
| 1759 | && surfaceDwgReadDouble(candidate, endBit, alignAngle) | |||
| 1760 | && readMatrix(sweepEntityTransform) | |||
| 1761 | && readMatrix(pathEntityTransform) | |||
| 1762 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1763 | && surfaceDwgReadBitShort(candidate, endBit, sweepAlignmentFlags) | |||
| 1764 | && surfaceDwgReadBitShort(candidate, endBit, pathFlags) | |||
| 1765 | && surfaceDwgReadBit(candidate, endBit, alignStart) | |||
| 1766 | && surfaceDwgReadBit(candidate, endBit, bank) | |||
| 1767 | && surfaceDwgReadBit(candidate, endBit, basePointSet) | |||
| 1768 | && surfaceDwgReadBit(candidate, endBit, sweepEntityTransformComputed) | |||
| 1769 | && surfaceDwgReadBit(candidate, endBit, pathEntityTransformComputed) | |||
| 1770 | && surfaceDwgRead3BitDouble(candidate, endBit, referenceVector); | |||
| 1771 | if (valid) { | |||
| 1772 | info.sweptFieldsValid = true; | |||
| 1773 | info.sweptClassVersion = static_cast<std::uint32_t>(classVersion); | |||
| 1774 | info.sweptEntityId = static_cast<std::uint32_t>(sweepEntityId); | |||
| 1775 | info.sweptData = std::move(sweepData); | |||
| 1776 | info.sweptPathEntityId = static_cast<std::uint32_t>(pathEntityId); | |||
| 1777 | info.sweptPathData = std::move(pathData); | |||
| 1778 | info.sweptEntityTransform = sweepEntityTransform; | |||
| 1779 | info.sweptPathEntityTransform = pathEntityTransform; | |||
| 1780 | info.sweptDraftAngle = draftAngle; | |||
| 1781 | info.sweptDraftStartDistance = draftStartDistance; | |||
| 1782 | info.sweptDraftEndDistance = draftEndDistance; | |||
| 1783 | info.sweptTwistAngle = twistAngle; | |||
| 1784 | info.sweptScaleFactor = scaleFactor; | |||
| 1785 | info.sweptAlignAngle = alignAngle; | |||
| 1786 | info.sweptSolid = solid != 0; | |||
| 1787 | info.sweptAlignmentFlags = sweepAlignmentFlags; | |||
| 1788 | info.sweptPathFlags = pathFlags; | |||
| 1789 | info.sweptAlignStart = alignStart != 0; | |||
| 1790 | info.sweptBank = bank != 0; | |||
| 1791 | info.sweptBasePointSet = basePointSet != 0; | |||
| 1792 | info.sweptEntityTransformComputed = | |||
| 1793 | sweepEntityTransformComputed != 0; | |||
| 1794 | info.sweptPathEntityTransformComputed = | |||
| 1795 | pathEntityTransformComputed != 0; | |||
| 1796 | info.sweptReferenceVector = referenceVector; | |||
| 1797 | } | |||
| 1798 | } else if (type == DRW::NURBSURFACE && version >= DRW::AC1027) { | |||
| 1799 | dwgBuffer candidate = buffer; | |||
| 1800 | std::uint16_t short170 = 0; | |||
| 1801 | std::uint8_t cvHullDisplay = 0; | |||
| 1802 | DRW_Coord uvec1; | |||
| 1803 | DRW_Coord vvec1; | |||
| 1804 | DRW_Coord uvec2; | |||
| 1805 | DRW_Coord vvec2; | |||
| 1806 | const bool valid = surfaceDwgReadBitShort(candidate, endBit, short170) | |||
| 1807 | && surfaceDwgReadBit(candidate, endBit, cvHullDisplay) | |||
| 1808 | && surfaceDwgRead3BitDouble(candidate, endBit, uvec1) | |||
| 1809 | && surfaceDwgRead3BitDouble(candidate, endBit, vvec1) | |||
| 1810 | && surfaceDwgRead3BitDouble(candidate, endBit, uvec2) | |||
| 1811 | && surfaceDwgRead3BitDouble(candidate, endBit, vvec2); | |||
| 1812 | if (valid) { | |||
| 1813 | info.nurbsFieldsValid = true; | |||
| 1814 | info.nurbsShort170 = short170; | |||
| 1815 | info.nurbsCvHullDisplay = cvHullDisplay != 0; | |||
| 1816 | info.nurbsUvec1 = uvec1; | |||
| 1817 | info.nurbsVvec1 = vvec1; | |||
| 1818 | info.nurbsUvec2 = uvec2; | |||
| 1819 | info.nurbsVvec2 = vvec2; | |||
| 1820 | } | |||
| 1821 | } else if (type == DRW::REVOLVEDSURFACE) { | |||
| 1822 | // The AcDbRevolvedSurface tail is optional from the carrier's point | |||
| 1823 | // of view: retain the complete bounded body when a producer omits or | |||
| 1824 | // truncates it, but publish the typed values only as one transaction. | |||
| 1825 | dwgBuffer candidate = buffer; | |||
| 1826 | std::int32_t classVersion = 0; | |||
| 1827 | std::int32_t id = 0; | |||
| 1828 | DRW_Coord axisPoint; | |||
| 1829 | DRW_Coord axisVector; | |||
| 1830 | std::array<double, DRW_RevolvedSurface::kTransformSize> transform{}; | |||
| 1831 | double revolveAngle = 0.0; | |||
| 1832 | double startAngle = 0.0; | |||
| 1833 | double draftAngle = 0.0; | |||
| 1834 | double draftStartDistance = 0.0; | |||
| 1835 | double draftEndDistance = 0.0; | |||
| 1836 | double twistAngle = 0.0; | |||
| 1837 | std::uint8_t solid = 0; | |||
| 1838 | std::uint8_t closeToAxis = 0; | |||
| 1839 | bool valid = surfaceDwgReadBitLong(candidate, endBit, classVersion) | |||
| 1840 | && classVersion >= 0 && classVersion <= 10 | |||
| 1841 | && surfaceDwgReadBitLong(candidate, endBit, id) | |||
| 1842 | && id >= 0 | |||
| 1843 | && surfaceDwgRead3BitDouble(candidate, endBit, axisPoint) | |||
| 1844 | && surfaceDwgRead3BitDouble(candidate, endBit, axisVector) | |||
| 1845 | && surfaceDwgReadDouble(candidate, endBit, revolveAngle) | |||
| 1846 | && surfaceDwgReadDouble(candidate, endBit, startAngle); | |||
| 1847 | for (double& value : transform) { | |||
| 1848 | valid = valid && surfaceDwgReadDouble(candidate, endBit, value); | |||
| 1849 | } | |||
| 1850 | valid = valid | |||
| 1851 | && surfaceDwgReadDouble(candidate, endBit, draftAngle) | |||
| 1852 | && surfaceDwgReadDouble(candidate, endBit, draftStartDistance) | |||
| 1853 | && surfaceDwgReadDouble(candidate, endBit, draftEndDistance) | |||
| 1854 | && surfaceDwgReadDouble(candidate, endBit, twistAngle) | |||
| 1855 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1856 | && surfaceDwgReadBit(candidate, endBit, closeToAxis); | |||
| 1857 | if (valid) { | |||
| 1858 | info.revolvedFieldsValid = true; | |||
| 1859 | info.revolvedClassId = static_cast<std::uint32_t>(classVersion); | |||
| 1860 | info.revolvedId = static_cast<std::uint32_t>(id); | |||
| 1861 | info.revolvedAxisPoint = axisPoint; | |||
| 1862 | info.revolvedAxisVector = axisVector; | |||
| 1863 | info.revolvedAngle = revolveAngle; | |||
| 1864 | info.revolvedStartAngle = startAngle; | |||
| 1865 | info.revolvedTransform = transform; | |||
| 1866 | info.revolvedDraftAngle = draftAngle; | |||
| 1867 | info.revolvedDraftStartDistance = draftStartDistance; | |||
| 1868 | info.revolvedDraftEndDistance = draftEndDistance; | |||
| 1869 | info.revolvedTwistAngle = twistAngle; | |||
| 1870 | info.revolvedSolid = solid != 0; | |||
| 1871 | info.revolvedCloseToAxis = closeToAxis != 0; | |||
| 1872 | } | |||
| 1873 | } | |||
| 1874 | ||||
| 1875 | info.acisEmpty = acisEmpty; | |||
| 1876 | info.acisVersion = acisVersion; | |||
| 1877 | info.modelerFormatVersion = static_cast<int>(modelerFormatVersion); | |||
| 1878 | info.uIsolines = static_cast<int>(uIsolines); | |||
| 1879 | info.vIsolines = static_cast<int>(vIsolines); | |||
| 1880 | return true; | |||
| 1881 | } | |||
| 1882 | ||||
| 1883 | int proxyEntityDxfCode(std::uint8_t handleCode) { | |||
| 1884 | switch (handleCode) { | |||
| 1885 | case 3: return 340; | |||
| 1886 | case 4: | |||
| 1887 | case 6: | |||
| 1888 | case 8: | |||
| 1889 | case 10: | |||
| 1890 | case 12: return 350; | |||
| 1891 | case 5: return 360; | |||
| 1892 | default: return 330; | |||
| 1893 | } | |||
| 1894 | } | |||
| 1895 | ||||
| 1896 | DRW_DwgSubrecordRange makeDwgSubrecordRange(const char *name, std::uint64_t startBit, | |||
| 1897 | std::uint64_t endBit, DRW::Version version, | |||
| 1898 | std::uint32_t count, bool parseComplete) { | |||
| 1899 | DRW_DwgSubrecordRange range; | |||
| 1900 | range.m_name = name; | |||
| 1901 | range.m_startBit = startBit; | |||
| 1902 | range.m_bitSize = endBit >= startBit ? endBit - startBit : 0; | |||
| 1903 | range.m_version = version; | |||
| 1904 | range.m_count = count; | |||
| 1905 | range.m_parseComplete = parseComplete; | |||
| 1906 | return range; | |||
| 1907 | } | |||
| 1908 | ||||
| 1909 | bool isValidSplineDegree(int degree) { | |||
| 1910 | return degree >= 1 && degree <= kMaxSplineDegree; | |||
| 1911 | } | |||
| 1912 | ||||
| 1913 | bool isValidControlSplineLayout(int degree, std::int32_t knotCount, std::int32_t controlCount) { | |||
| 1914 | if (!isValidSplineDegree(degree) || !isValidCount(knotCount, kMaxSplineItems) || | |||
| 1915 | !isValidCount(controlCount, kMaxSplineItems)) { | |||
| 1916 | return false; | |||
| 1917 | } | |||
| 1918 | ||||
| 1919 | if (controlCount < degree + 1) { | |||
| 1920 | return false; | |||
| 1921 | } | |||
| 1922 | ||||
| 1923 | const std::int64_t expectedKnots = static_cast<std::int64_t>(controlCount) + degree + 1; | |||
| 1924 | return expectedKnots <= kMaxSplineItems && knotCount == expectedKnots; | |||
| 1925 | } | |||
| 1926 | ||||
| 1927 | bool isValidFitSplineLayout(int degree, std::int32_t fitCount) { | |||
| 1928 | return isValidSplineDegree(degree) && isValidCount(fitCount, kMaxSplineItems) && | |||
| 1929 | fitCount >= 2; | |||
| 1930 | } | |||
| 1931 | ||||
| 1932 | bool differsFromUnitWeight(double weight) { | |||
| 1933 | return std::fabs(weight - 1.0) > 1e-12; | |||
| 1934 | } | |||
| 1935 | ||||
| 1936 | //! \brief Compare two doubles by stored representation. | |||
| 1937 | //! For values a compact DWG form restores verbatim, the match has to be exact: | |||
| 1938 | //! dataFlags 3 makes the reader return exactly 1.0 and dataFlags 2 makes it | |||
| 1939 | //! return xscale for y and z (see DRW_Insert::parseDwg), so picking those forms | |||
| 1940 | //! on a tolerant match would silently round the scale that gets written. This | |||
| 1941 | //! asks the question that is actually meant - "will the reader reconstruct this | |||
| 1942 | //! value?" - without floating point comparison semantics, and as a side effect | |||
| 1943 | //! keeps -0.0 distinct from 0.0, which `==` does not. | |||
| 1944 | bool sameStoredDouble(double a, double b) { | |||
| 1945 | return std::memcmp(&a, &b, sizeof a) == 0; | |||
| 1946 | } | |||
| 1947 | ||||
| 1948 | void putDwgReference(dwgBufferW *buf, std::uint8_t code, | |||
| 1949 | std::uint32_t ref) { | |||
| 1950 | dwgHandle h; | |||
| 1951 | h.code = code; | |||
| 1952 | h.ref = ref; | |||
| 1953 | h.size = 0; | |||
| 1954 | if (ref != 0) { | |||
| 1955 | std::uint32_t t = ref; | |||
| 1956 | while (t != 0) { | |||
| 1957 | t >>= 8; | |||
| 1958 | ++h.size; | |||
| 1959 | } | |||
| 1960 | } | |||
| 1961 | buf->putHandle(h); | |||
| 1962 | } | |||
| 1963 | ||||
| 1964 | void putHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) { | |||
| 1965 | putDwgReference(buf, DRW::DwgHardPointer, ref); | |||
| 1966 | } | |||
| 1967 | ||||
| 1968 | void appendBitBuffer(dwgBufferW *destination, const dwgBufferW& source) { | |||
| 1969 | if (destination == nullptr) | |||
| 1970 | return; | |||
| 1971 | const auto& bytes = source.data(); | |||
| 1972 | for (std::uint32_t bit = 0; bit < source.bitCount(); ++bit) { | |||
| 1973 | const std::uint8_t value = | |||
| 1974 | static_cast<std::uint8_t>((bytes[bit / 8] >> (7 - (bit % 8))) & 1); | |||
| 1975 | destination->putBit(value); | |||
| 1976 | } | |||
| 1977 | } | |||
| 1978 | ||||
| 1979 | void putNullableHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) { | |||
| 1980 | dwgHandle h; | |||
| 1981 | h.code = ref == 0 ? 0 : 5; | |||
| 1982 | h.ref = ref; | |||
| 1983 | h.size = 0; | |||
| 1984 | if (ref != 0) { | |||
| 1985 | std::uint32_t t = ref; | |||
| 1986 | while (t != 0) { | |||
| 1987 | t >>= 8; | |||
| 1988 | ++h.size; | |||
| 1989 | } | |||
| 1990 | } | |||
| 1991 | buf->putHandle(h); | |||
| 1992 | } | |||
| 1993 | ||||
| 1994 | void putSurfaceHandle(dwgBufferW *buf, std::uint32_t ref) { | |||
| 1995 | dwgHandle h; | |||
| 1996 | h.code = 5; | |||
| 1997 | h.ref = ref; | |||
| 1998 | h.size = 0; | |||
| 1999 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 2000 | ++h.size; | |||
| 2001 | buf->putHandle(h); | |||
| 2002 | } | |||
| 2003 | ||||
| 2004 | std::size_t surfaceRawBitCapacity(const std::vector<std::uint8_t>& data) { | |||
| 2005 | constexpr std::size_t maxBitSize = | |||
| 2006 | std::numeric_limits<std::uint32_t>::max(); | |||
| 2007 | constexpr std::size_t maxBytes = maxBitSize / 8u; | |||
| 2008 | return data.size() > maxBytes ? maxBitSize : data.size() * 8u; | |||
| 2009 | } | |||
| 2010 | ||||
| 2011 | bool putSurfaceRawBits(dwgBufferW *buf, const std::vector<std::uint8_t>& data, | |||
| 2012 | std::uint32_t bitSize) { | |||
| 2013 | const std::size_t bitCapacity = surfaceRawBitCapacity(data); | |||
| 2014 | if (buf == nullptr || bitSize == 0 || bitSize > bitCapacity) | |||
| 2015 | return false; | |||
| 2016 | for (std::uint32_t bit = 0; bit < bitSize; ++bit) { | |||
| 2017 | const std::uint8_t byte = data[bit >> 3]; | |||
| 2018 | buf->putBit((byte >> (7u - (bit & 7u))) & 1u); | |||
| 2019 | } | |||
| 2020 | return true; | |||
| 2021 | } | |||
| 2022 | ||||
| 2023 | bool finiteSurfaceCoord(const DRW_Coord& value) { | |||
| 2024 | return std::isfinite(value.x) && std::isfinite(value.y) | |||
| 2025 | && std::isfinite(value.z); | |||
| 2026 | } | |||
| 2027 | ||||
| 2028 | template <std::size_t N> | |||
| 2029 | bool finiteSurfaceMatrix(const std::array<double, N>& values) { | |||
| 2030 | return std::all_of(values.begin(), values.end(), | |||
| 2031 | [](double value) { return std::isfinite(value); }); | |||
| 2032 | } | |||
| 2033 | ||||
| 2034 | std::uint16_t bitShortFromInt(int value) { | |||
| 2035 | if (value < 0) | |||
| 2036 | return 0; | |||
| 2037 | if (value > 0xffff) | |||
| 2038 | return 0xffff; | |||
| 2039 | return static_cast<std::uint16_t>(value); | |||
| 2040 | } | |||
| 2041 | ||||
| 2042 | std::uint32_t readTableHandle( | |||
| 2043 | dwgBuffer *hdlBuf, | |||
| 2044 | std::uint64_t endBit = std::numeric_limits<std::uint64_t>::max()) { | |||
| 2045 | if (hdlBuf == nullptr || !hdlBuf->isGood()) | |||
| 2046 | return 0; | |||
| 2047 | dwgBuffer probe = hdlBuf->forkIndependent(); | |||
| 2048 | dwgHandle h; | |||
| 2049 | if (!readBoundedDwgHandle(probe, endBit, 0, false, h)) { | |||
| 2050 | hdlBuf->invalidate(); | |||
| 2051 | return 0; | |||
| 2052 | } | |||
| 2053 | *hdlBuf = probe; | |||
| 2054 | return h.ref; | |||
| 2055 | } | |||
| 2056 | ||||
| 2057 | void seekTableObjectHandleStream(DRW::Version version, dwgBuffer *buf, std::uint32_t objSize) { | |||
| 2058 | if (version > DRW::AC1018) { | |||
| 2059 | buf->setPosition(objSize >> 3); | |||
| 2060 | buf->setBitPos(objSize & 7); | |||
| 2061 | } | |||
| 2062 | } | |||
| 2063 | ||||
| 2064 | bool readTableObjectCommonHandles(dwgBuffer *buf, std::uint32_t baseHandle, | |||
| 2065 | std::int32_t numReactors, std::uint8_t xDictFlag, | |||
| 2066 | std::uint32_t *parentHandle, | |||
| 2067 | std::vector<std::uint32_t> *reactorHandles, | |||
| 2068 | std::uint32_t *xDictHandle, | |||
| 2069 | std::uint64_t handleEndBit = | |||
| 2070 | std::numeric_limits<std::uint64_t>::max()) { | |||
| 2071 | if (buf == nullptr || !buf->isGood() | |||
| 2072 | || !dwgSafety::validReactorCount(numReactors)) { | |||
| 2073 | if (buf != nullptr) | |||
| 2074 | buf->invalidate(); | |||
| 2075 | return false; | |||
| 2076 | } | |||
| 2077 | std::vector<std::uint32_t> parsedReactors; | |||
| 2078 | dwgHandle parentH; | |||
| 2079 | if (!readBoundedDwgHandle(*buf, handleEndBit, baseHandle, true, parentH)) | |||
| 2080 | return false; | |||
| 2081 | if (!DRW::reserve(parsedReactors, numReactors)) | |||
| 2082 | return false; | |||
| 2083 | for (std::int32_t i = 0; i < numReactors; ++i) { | |||
| 2084 | dwgHandle reactor; | |||
| 2085 | if (!readBoundedDwgHandle(*buf, handleEndBit, baseHandle, true, | |||
| 2086 | reactor)) | |||
| 2087 | return false; | |||
| 2088 | parsedReactors.push_back(reactor.ref); | |||
| 2089 | } | |||
| 2090 | ||||
| 2091 | std::uint32_t parsedXDictHandle = 0; | |||
| 2092 | if (xDictFlag != 1) { | |||
| 2093 | dwgHandle xDict; | |||
| 2094 | if (!readBoundedDwgHandle(*buf, handleEndBit, baseHandle, true, | |||
| 2095 | xDict)) | |||
| 2096 | return false; | |||
| 2097 | parsedXDictHandle = xDict.ref; | |||
| 2098 | } | |||
| 2099 | if (parentHandle) | |||
| 2100 | *parentHandle = parentH.ref; | |||
| 2101 | if (reactorHandles) | |||
| 2102 | *reactorHandles = std::move(parsedReactors); | |||
| 2103 | if (xDictHandle) | |||
| 2104 | *xDictHandle = parsedXDictHandle; | |||
| 2105 | return true; | |||
| 2106 | } | |||
| 2107 | ||||
| 2108 | bool readTableValueBytes(dwgBuffer *buf, std::uint64_t bodyEndBit, | |||
| 2109 | std::vector<std::uint8_t>& raw, const char *label) { | |||
| 2110 | std::int32_t parsedByteCount = 0; | |||
| 2111 | if (buf == nullptr | |||
| 2112 | || !readBoundedBitLong(*buf, bodyEndBit, parsedByteCount) | |||
| 2113 | || parsedByteCount < 0 | |||
| 2114 | || static_cast<std::uint32_t>(parsedByteCount) > kMaxTableStringBytes) { | |||
| 2115 | if (buf != nullptr) | |||
| 2116 | buf->invalidate(); | |||
| 2117 | return false; | |||
| 2118 | } | |||
| 2119 | const std::uint32_t byteCount = static_cast<std::uint32_t>(parsedByteCount); | |||
| 2120 | if (byteCount > kMaxTableStringBytes) { | |||
| 2121 | 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"); | |||
| 2122 | return false; | |||
| 2123 | } | |||
| 2124 | if (!DRW::resize(raw, static_cast<int>(byteCount))) | |||
| 2125 | return false; | |||
| 2126 | const bool good = readBoundedBytes(*buf, bodyEndBit, raw.data(), raw.size()); | |||
| 2127 | if (!good) { | |||
| 2128 | 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); | |||
| 2129 | DRW_DBG(" remaining: ")DRW_dbg::dbg(" remaining: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2130 | } | |||
| 2131 | return good; | |||
| 2132 | } | |||
| 2133 | ||||
| 2134 | UTF8STRINGstd::string decodeTableValueText(DRW::Version version, dwgBuffer *buf, const std::vector<std::uint8_t>& raw) { | |||
| 2135 | if (raw.empty()) | |||
| 2136 | return UTF8STRINGstd::string(); | |||
| 2137 | std::string s(reinterpret_cast<const char*>(raw.data()), raw.size()); | |||
| 2138 | if (version > DRW::AC1018 && s.size() >= 2 && s[s.size() - 1] == '\0' | |||
| 2139 | && s[s.size() - 2] == '\0') { | |||
| 2140 | s.resize(s.size() - 2); | |||
| 2141 | } else { | |||
| 2142 | while (!s.empty() && s.back() == '\0') | |||
| 2143 | s.pop_back(); | |||
| 2144 | } | |||
| 2145 | if (buf->decoder) | |||
| 2146 | s = buf->decoder->toUtf8(s); | |||
| 2147 | return s; | |||
| 2148 | } | |||
| 2149 | ||||
| 2150 | UTF8STRINGstd::string readTableText(DRW::Version version, dwgBuffer *buf, | |||
| 2151 | std::uint64_t endBit) { | |||
| 2152 | if (!buf) | |||
| 2153 | return UTF8STRINGstd::string(); | |||
| 2154 | if (version <= DRW::AC1018) { | |||
| 2155 | UTF8STRINGstd::string value; | |||
| 2156 | if (!readBoundedVariableText(*buf, endBit, version, value)) | |||
| 2157 | buf->invalidate(); | |||
| 2158 | return value; | |||
| 2159 | } | |||
| 2160 | ||||
| 2161 | // R2007+ text is a BS count of UTF-16LE code units followed by two bytes | |||
| 2162 | // per unit (ODA spec TV/TU; the encoding dwgBuffer::getUCSText reads). The | |||
| 2163 | // count is not a byte count: taking `count` bytes leaves the second half of | |||
| 2164 | // every string unread and puts every later read of the string stream out | |||
| 2165 | // of step, which turns the next length into garbage. | |||
| 2166 | std::uint16_t parsedCharCount = 0; | |||
| 2167 | if (!readBoundedBitShort(*buf, endBit, parsedCharCount)) { | |||
| 2168 | buf->invalidate(); | |||
| 2169 | return UTF8STRINGstd::string(); | |||
| 2170 | } | |||
| 2171 | if (parsedCharCount == 0) | |||
| 2172 | return UTF8STRINGstd::string(); | |||
| 2173 | // At most 2 * 65535 bytes, far below kMaxTableStringBytes. | |||
| 2174 | const std::uint32_t byteLen = static_cast<std::uint32_t>(parsedCharCount) * 2u; | |||
| 2175 | ||||
| 2176 | std::vector<std::uint8_t> raw; | |||
| 2177 | if (!DRW::resize(raw, static_cast<int>(byteLen + 2))) | |||
| 2178 | return UTF8STRINGstd::string(); | |||
| 2179 | std::fill(raw.begin(), raw.end(), 0); | |||
| 2180 | if (!readBoundedBytes(*buf, endBit, raw.data(), byteLen)) { | |||
| 2181 | buf->invalidate(); | |||
| 2182 | return UTF8STRINGstd::string(); | |||
| 2183 | } | |||
| 2184 | ||||
| 2185 | std::string s(reinterpret_cast<const char*>(raw.data()), byteLen); | |||
| 2186 | if (buf->decoder) | |||
| 2187 | s = buf->decoder->toUtf8(s); | |||
| 2188 | while (!s.empty() && s.back() == '\0') | |||
| 2189 | s.pop_back(); | |||
| 2190 | return s; | |||
| 2191 | } | |||
| 2192 | ||||
| 2193 | bool readTableValuePoint(dwgBuffer *buf, std::uint64_t bodyEndBit, | |||
| 2194 | DRW_CadValue& value, int dimensions) { | |||
| 2195 | std::int32_t parsedDataSize = 0; | |||
| 2196 | if (buf == nullptr | |||
| 2197 | || !readBoundedBitLong(*buf, bodyEndBit, parsedDataSize) | |||
| 2198 | || parsedDataSize < 0) { | |||
| 2199 | if (buf != nullptr) | |||
| 2200 | buf->invalidate(); | |||
| 2201 | return false; | |||
| 2202 | } | |||
| 2203 | value.m_dataSize = static_cast<std::uint32_t>(parsedDataSize); | |||
| 2204 | const std::uint32_t expectedSize = static_cast<std::uint32_t>(dimensions) * 8; | |||
| 2205 | if (value.m_dataSize > kMaxTableStringBytes) | |||
| 2206 | return false; | |||
| 2207 | if (value.m_dataSize < expectedSize) { | |||
| 2208 | if (!DRW::resize(value.m_rawData, | |||
| 2209 | static_cast<int>(value.m_dataSize))) | |||
| 2210 | return false; | |||
| 2211 | if (!readBoundedBytes(*buf, bodyEndBit, value.m_rawData.data(), | |||
| 2212 | value.m_rawData.size())) | |||
| 2213 | return false; | |||
| 2214 | value.m_value.addBinary(310, value.m_rawData); | |||
| 2215 | return true; | |||
| 2216 | } | |||
| 2217 | ||||
| 2218 | DRW_Coord c; | |||
| 2219 | if (!readBoundedRawDouble(*buf, bodyEndBit, c.x) | |||
| 2220 | || !readBoundedRawDouble(*buf, bodyEndBit, c.y) | |||
| 2221 | || (dimensions == 3 | |||
| 2222 | && !readBoundedRawDouble(*buf, bodyEndBit, c.z))) | |||
| 2223 | return false; | |||
| 2224 | if (dimensions != 3) | |||
| 2225 | c.z = 0.0; | |||
| 2226 | value.m_value.addCoord(11, c); | |||
| 2227 | ||||
| 2228 | const std::uint32_t extraBytes = value.m_dataSize - expectedSize; | |||
| 2229 | if (!DRW::resize(value.m_rawData, static_cast<int>(extraBytes))) | |||
| 2230 | return false; | |||
| 2231 | return readBoundedBytes(*buf, bodyEndBit, value.m_rawData.data(), | |||
| 2232 | value.m_rawData.size()); | |||
| 2233 | } | |||
| 2234 | ||||
| 2235 | bool readTableCadValue(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2236 | dwgBuffer *hdlBuf, DRW_CadValue& value, | |||
| 2237 | const TableDwgBounds& bounds) { | |||
| 2238 | if (version > DRW::AC1018) { | |||
| 2239 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, value.m_formatFlags)) | |||
| 2240 | return false; | |||
| 2241 | } | |||
| 2242 | ||||
| 2243 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, value.m_dataType)) | |||
| 2244 | return false; | |||
| 2245 | // Only bit 0 of the value flags marks the payload absent for ACAD_TABLE | |||
| 2246 | // cell values (ACadSharp CadValue.IsEmpty). Bit 1 is set on values that do | |||
| 2247 | // carry a payload: R2007 cells hold flags 6 (title/data text) and 2 | |||
| 2248 | // (merged text), both with a kGeneral payload, and only flags 3 (empty | |||
| 2249 | // cell) has none. Testing `& 3` skips those payloads and desynchronises | |||
| 2250 | // every later cell. The FIELD object reads the same structure but tests | |||
| 2251 | // `& 3` (libredwg dwg_spec_shared.h); do not unify the two masks. | |||
| 2252 | const bool emptyR2007Value = version > DRW::AC1018 && (value.m_formatFlags & 1); | |||
| 2253 | if (!emptyR2007Value) { | |||
| 2254 | switch (value.m_dataType) { | |||
| 2255 | case 0: | |||
| 2256 | case 1: { | |||
| 2257 | std::int32_t intValue = 0; | |||
| 2258 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, intValue)) | |||
| 2259 | return false; | |||
| 2260 | value.m_value.addInt(91, intValue); | |||
| 2261 | break; | |||
| 2262 | } | |||
| 2263 | case 2: { | |||
| 2264 | double doubleValue = 0.0; | |||
| 2265 | if (!readBoundedBitDouble(*buf, bounds.bodyEndBit, doubleValue)) | |||
| 2266 | return false; | |||
| 2267 | value.m_value.addDouble(140, doubleValue); | |||
| 2268 | break; | |||
| 2269 | } | |||
| 2270 | case 4: | |||
| 2271 | case 512: | |||
| 2272 | if (!readTableValueBytes(buf, bounds.bodyEndBit, value.m_rawData, | |||
| 2273 | "TABLE value byte payload")) | |||
| 2274 | return false; | |||
| 2275 | value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size()); | |||
| 2276 | value.m_value.addString(1, decodeTableValueText(version, buf, value.m_rawData)); | |||
| 2277 | break; | |||
| 2278 | case 8: { | |||
| 2279 | if (!readTableValueBytes(buf, bounds.bodyEndBit, value.m_rawData, | |||
| 2280 | "TABLE value date payload")) | |||
| 2281 | return false; | |||
| 2282 | value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size()); | |||
| 2283 | value.m_value.addBinary(310, value.m_rawData); | |||
| 2284 | break; | |||
| 2285 | } | |||
| 2286 | case 16: | |||
| 2287 | if (!readTableValuePoint(buf, bounds.bodyEndBit, value, 2)) | |||
| 2288 | return false; | |||
| 2289 | break; | |||
| 2290 | case 32: | |||
| 2291 | if (!readTableValuePoint(buf, bounds.bodyEndBit, value, 3)) | |||
| 2292 | return false; | |||
| 2293 | break; | |||
| 2294 | case 64: | |||
| 2295 | value.m_handle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2296 | value.m_value.addInt(330, static_cast<std::uint32_t>(value.m_handle)); | |||
| 2297 | break; | |||
| 2298 | case 128: | |||
| 2299 | case 256: | |||
| 2300 | 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"); | |||
| 2301 | return false; | |||
| 2302 | default: | |||
| 2303 | 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"); | |||
| 2304 | return false; | |||
| 2305 | } | |||
| 2306 | } | |||
| 2307 | ||||
| 2308 | if (version > DRW::AC1018) { | |||
| 2309 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2310 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, value.m_unitType)) | |||
| 2311 | return false; | |||
| 2312 | const std::uint64_t textEndBit = tableTextEndBit(buf, textBuf, bounds); | |||
| 2313 | value.m_formatString = readTableText(version, textBuf, textEndBit); | |||
| 2314 | value.m_valueString = readTableText(version, textBuf, textEndBit); | |||
| 2315 | } | |||
| 2316 | ||||
| 2317 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2318 | if (!good) { | |||
| 2319 | 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); | |||
| 2320 | DRW_DBG(" type: ")DRW_dbg::dbg(" type: "); DRW_DBG(value.m_dataType)DRW_dbg::dbg(value.m_dataType); | |||
| 2321 | DRW_DBG(" unit: ")DRW_dbg::dbg(" unit: "); DRW_DBG(value.m_unitType)DRW_dbg::dbg(value.m_unitType); | |||
| 2322 | DRW_DBG(" bufGood: ")DRW_dbg::dbg(" bufGood: "); DRW_DBG(buf->isGood() ? 1 : 0)DRW_dbg::dbg(buf->isGood() ? 1 : 0); | |||
| 2323 | DRW_DBG(" strGood: ")DRW_dbg::dbg(" strGood: "); DRW_DBG((!strBuf || strBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!strBuf || strBuf->isGood()) ? 1 : 0); | |||
| 2324 | DRW_DBG(" hdlGood: ")DRW_dbg::dbg(" hdlGood: "); DRW_DBG((!hdlBuf || hdlBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!hdlBuf || hdlBuf->isGood()) ? 1 : 0); | |||
| 2325 | DRW_DBG(" bufPos: ")DRW_dbg::dbg(" bufPos: "); DRW_DBG(buf->getPosition())DRW_dbg::dbg(buf->getPosition()); | |||
| 2326 | 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); | |||
| 2327 | 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); | |||
| 2328 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2329 | } | |||
| 2330 | return good; | |||
| 2331 | } | |||
| 2332 | ||||
| 2333 | bool skipTableCustomData(DRW::Version version, dwgBuffer *buf, | |||
| 2334 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2335 | const TableDwgBounds& bounds) { | |||
| 2336 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2337 | UTF8STRINGstd::string key = readTableText( | |||
| 2338 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2339 | if (!textBuf->isGood()) { | |||
| 2340 | DRW_DBG("TABLE custom data key string read failed\n")DRW_dbg::dbg("TABLE custom data key string read failed\n"); | |||
| 2341 | return false; | |||
| 2342 | } | |||
| 2343 | DRW_CadValue value; | |||
| 2344 | const bool good = readTableCadValue(version, buf, strBuf, hdlBuf, value, | |||
| 2345 | bounds); | |||
| 2346 | if (!good) { | |||
| 2347 | 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"); | |||
| 2348 | } | |||
| 2349 | return good; | |||
| 2350 | } | |||
| 2351 | ||||
| 2352 | bool readTableCmColor(DRW::Version version, dwgBuffer *buf, | |||
| 2353 | dwgBuffer *strBuf, const TableDwgBounds& bounds) { | |||
| 2354 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2355 | if (version < DRW::AC1018) { | |||
| 2356 | std::uint16_t ignoredColor = 0; | |||
| 2357 | return readBoundedBitShort(*buf, bounds.bodyEndBit, ignoredColor); | |||
| 2358 | } | |||
| 2359 | ||||
| 2360 | std::uint16_t ignoredColorType = 0; | |||
| 2361 | std::int32_t rgb = 0; | |||
| 2362 | std::uint8_t colorFlags = 0; | |||
| 2363 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, ignoredColorType) | |||
| 2364 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, rgb) | |||
| 2365 | || !readBoundedRawChar8(*buf, bounds.bodyEndBit, colorFlags)) | |||
| 2366 | return false; | |||
| 2367 | DRW_DBG("\ntype COLOR: ")DRW_dbg::dbg("\ntype COLOR: "); DRW_DBGH(rgb >> 24)DRW_dbg::dbgH(rgb >> 24); | |||
| 2368 | DRW_DBG("\nRGB COLOR: ")DRW_dbg::dbg("\nRGB COLOR: "); DRW_DBGH(rgb)DRW_dbg::dbgH(rgb); | |||
| 2369 | DRW_DBG("\nbyte COLOR: ")DRW_dbg::dbg("\nbyte COLOR: "); DRW_DBGH(colorFlags)DRW_dbg::dbgH(colorFlags); | |||
| 2370 | const std::uint64_t textEndBit = tableTextEndBit(buf, textBuf, bounds); | |||
| 2371 | if (colorFlags & 1) | |||
| 2372 | readTableText(version, textBuf, textEndBit); | |||
| 2373 | if (colorFlags & 2) | |||
| 2374 | readTableText(version, textBuf, textEndBit); | |||
| 2375 | return textBuf->isGood(); | |||
| 2376 | } | |||
| 2377 | ||||
| 2378 | bool skipR2007TableCellOverrides(DRW::Version version, dwgBuffer *buf, | |||
| 2379 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2380 | DRW_TableCell& cell, | |||
| 2381 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2382 | const TableDwgBounds& bounds) { | |||
| 2383 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2384 | std::int32_t overrideFlags = 0; | |||
| 2385 | std::uint8_t virtualEdgeFlags = 0; | |||
| 2386 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, overrideFlags) | |||
| 2387 | || !readBoundedRawChar8(*buf, bounds.bodyEndBit, virtualEdgeFlags)) | |||
| 2388 | return false; | |||
| 2389 | cell.m_overrideFlags = static_cast<std::uint32_t>(overrideFlags); | |||
| 2390 | cell.m_virtualEdgeFlags = virtualEdgeFlags; | |||
| 2391 | ||||
| 2392 | // The ODA specification types the cell alignment override as RS, but the | |||
| 2393 | // value is stored as a BS (ACadSharp reads it that way). Read as a raw | |||
| 2394 | // 16-bit value it swallows bits that belong to the next field: the first | |||
| 2395 | // cell that overrides its alignment then decodes as garbage, and so does | |||
| 2396 | // every cell after it. | |||
| 2397 | if (cell.m_overrideFlags & 0x00001 | |||
| 2398 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2399 | return false; | |||
| 2400 | if (cell.m_overrideFlags & 0x00002 | |||
| 2401 | && !skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2402 | return false; | |||
| 2403 | if ((cell.m_overrideFlags & 0x00004) | |||
| 2404 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2405 | return false; | |||
| 2406 | if ((cell.m_overrideFlags & 0x00008) | |||
| 2407 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2408 | return false; | |||
| 2409 | if (cell.m_overrideFlags & 0x00010) | |||
| 2410 | cell.m_textStyleOverrideHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2411 | if (cell.m_overrideFlags & 0x00020 | |||
| 2412 | && !skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2413 | return false; | |||
| 2414 | if ((cell.m_overrideFlags & 0x00040) | |||
| 2415 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2416 | return false; | |||
| 2417 | if (cell.m_overrideFlags & 0x00400 | |||
| 2418 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2419 | return false; | |||
| 2420 | if (cell.m_overrideFlags & 0x04000 | |||
| 2421 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2422 | return false; | |||
| 2423 | if ((cell.m_overrideFlags & 0x00080) | |||
| 2424 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2425 | return false; | |||
| 2426 | if (cell.m_overrideFlags & 0x00800 | |||
| 2427 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2428 | return false; | |||
| 2429 | if (cell.m_overrideFlags & 0x08000 | |||
| 2430 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2431 | return false; | |||
| 2432 | if ((cell.m_overrideFlags & 0x00100) | |||
| 2433 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2434 | return false; | |||
| 2435 | if (cell.m_overrideFlags & 0x01000 | |||
| 2436 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2437 | return false; | |||
| 2438 | if (cell.m_overrideFlags & 0x10000 | |||
| 2439 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2440 | return false; | |||
| 2441 | if ((cell.m_overrideFlags & 0x00200) | |||
| 2442 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2443 | return false; | |||
| 2444 | if (cell.m_overrideFlags & 0x02000 | |||
| 2445 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2446 | return false; | |||
| 2447 | if (cell.m_overrideFlags & 0x20000 | |||
| 2448 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2449 | return false; | |||
| 2450 | ||||
| 2451 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2452 | if (ranges != nullptr) { | |||
| 2453 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2454 | "r2007-table-cell-overrides", startBit, currentDwgBit(buf), | |||
| 2455 | version, cell.m_overrideFlags, good)); | |||
| 2456 | } | |||
| 2457 | return good; | |||
| 2458 | } | |||
| 2459 | ||||
| 2460 | bool parseR2007TableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2461 | dwgBuffer *hdlBuf, DRW_TableCell& cell, | |||
| 2462 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2463 | const TableDwgBounds& bounds) { | |||
| 2464 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2465 | std::uint16_t type = 0; | |||
| 2466 | std::uint8_t edgeFlags = 0; | |||
| 2467 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, type) | |||
| 2468 | || !readBoundedRawChar8(*buf, bounds.bodyEndBit, edgeFlags) | |||
| 2469 | || !readBoundedBit(*buf, bounds.bodyEndBit, cell.m_isMerged) | |||
| 2470 | || !readBoundedBit(*buf, bounds.bodyEndBit, cell.m_autoFit) | |||
| 2471 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_mergedWidth) | |||
| 2472 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_mergedHeight) | |||
| 2473 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_rotation)) | |||
| 2474 | return false; | |||
| 2475 | cell.m_type = type; | |||
| 2476 | cell.m_edgeFlags = edgeFlags; | |||
| 2477 | cell.m_valueHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2478 | ||||
| 2479 | if (cell.m_type == 1) { | |||
| 2480 | cell.m_textStyleHandle = cell.m_valueHandle; | |||
| 2481 | if (cell.m_textStyleHandle == 0 && version < DRW::AC1021) { | |||
| 2482 | DRW_TableCellContent content; | |||
| 2483 | content.m_type = 1; | |||
| 2484 | content.m_text = readTableText( | |||
| 2485 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2486 | content.m_value.m_dataType = 4; | |||
| 2487 | content.m_value.m_value.addString(1, content.m_text); | |||
| 2488 | cell.m_contents.push_back(content); | |||
| 2489 | } | |||
| 2490 | } else if (cell.m_type == 2) { | |||
| 2491 | cell.m_blockHandle = cell.m_valueHandle; | |||
| 2492 | if (!readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_blockScale)) | |||
| 2493 | return false; | |||
| 2494 | bool hasAttributes = false; | |||
| 2495 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasAttributes)) | |||
| 2496 | return false; | |||
| 2497 | if (hasAttributes) { | |||
| 2498 | std::uint16_t numAttributes = 0; | |||
| 2499 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, | |||
| 2500 | numAttributes) | |||
| 2501 | || numAttributes > kMaxTableCellAttributes) | |||
| 2502 | return false; | |||
| 2503 | if (!DRW::reserve(cell.m_attributes, numAttributes)) | |||
| 2504 | return false; | |||
| 2505 | for (std::uint16_t i = 0; i < numAttributes; ++i) { | |||
| 2506 | DRW_TableCellAttribute attribute; | |||
| 2507 | attribute.m_attdefHandle = readTableHandle( | |||
| 2508 | hdlBuf, bounds.handleEndBit); | |||
| 2509 | std::uint16_t attributeIndex = 0; | |||
| 2510 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, | |||
| 2511 | attributeIndex)) | |||
| 2512 | return false; | |||
| 2513 | attribute.m_index = attributeIndex; | |||
| 2514 | attribute.m_text = readTableText( | |||
| 2515 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2516 | cell.m_attributes.push_back(attribute); | |||
| 2517 | } | |||
| 2518 | } | |||
| 2519 | ||||
| 2520 | DRW_TableCellContent content; | |||
| 2521 | content.m_type = 4; | |||
| 2522 | content.m_handle = cell.m_blockHandle; | |||
| 2523 | cell.m_contents.push_back(content); | |||
| 2524 | } | |||
| 2525 | ||||
| 2526 | bool hasOverrides = false; | |||
| 2527 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasOverrides)) | |||
| 2528 | return false; | |||
| 2529 | if (hasOverrides | |||
| 2530 | && !skipR2007TableCellOverrides(version, buf, strBuf, hdlBuf, cell, | |||
| 2531 | ranges, bounds)) | |||
| 2532 | return false; | |||
| 2533 | ||||
| 2534 | if (version > DRW::AC1018) { | |||
| 2535 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) | |||
| 2536 | return false; | |||
| 2537 | DRW_TableCellContent content; | |||
| 2538 | content.m_type = 1; | |||
| 2539 | if (!readTableCadValue(version, buf, strBuf, hdlBuf, content.m_value, | |||
| 2540 | bounds)) | |||
| 2541 | return false; | |||
| 2542 | if (content.m_value.m_value.type() == DRW_Variant::STRING) | |||
| 2543 | content.m_text = content.m_value.m_value.c_str(); | |||
| 2544 | else if (!content.m_value.m_valueString.empty()) | |||
| 2545 | content.m_text = content.m_value.m_valueString; | |||
| 2546 | cell.m_contents.push_back(content); | |||
| 2547 | } | |||
| 2548 | ||||
| 2549 | return buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2550 | } | |||
| 2551 | ||||
| 2552 | bool skipR2007TableOverrides(DRW::Version version, dwgBuffer *buf, | |||
| 2553 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2554 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2555 | const TableDwgBounds& bounds) { | |||
| 2556 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2557 | std::uint32_t maskCount = 0; | |||
| 2558 | auto readFlags = [&](std::uint32_t& flags) { | |||
| 2559 | std::int32_t parsed = 0; | |||
| 2560 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, parsed)) | |||
| 2561 | return false; | |||
| 2562 | flags = static_cast<std::uint32_t>(parsed); | |||
| 2563 | return true; | |||
| 2564 | }; | |||
| 2565 | bool hasMask = false; | |||
| 2566 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2567 | return false; | |||
| 2568 | if (hasMask) { | |||
| 2569 | std::uint32_t flags = 0; | |||
| 2570 | if (!readFlags(flags)) | |||
| 2571 | return false; | |||
| 2572 | ++maskCount; | |||
| 2573 | if (flags & 0x000001) | |||
| 2574 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2575 | return false; | |||
| 2576 | if (flags & 0x000004) | |||
| 2577 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2578 | return false; | |||
| 2579 | if (flags & 0x000008) | |||
| 2580 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2581 | return false; | |||
| 2582 | if (flags & 0x000010) | |||
| 2583 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2584 | return false; | |||
| 2585 | if ((flags & 0x000020) | |||
| 2586 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2587 | return false; | |||
| 2588 | if ((flags & 0x000040) | |||
| 2589 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2590 | return false; | |||
| 2591 | if ((flags & 0x000080) | |||
| 2592 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2593 | return false; | |||
| 2594 | if (flags & 0x000100) | |||
| 2595 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2596 | return false; | |||
| 2597 | if (flags & 0x000200) | |||
| 2598 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2599 | return false; | |||
| 2600 | if (flags & 0x000400) | |||
| 2601 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2602 | return false; | |||
| 2603 | if ((flags & 0x000800) | |||
| 2604 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2605 | return false; | |||
| 2606 | if ((flags & 0x001000) | |||
| 2607 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2608 | return false; | |||
| 2609 | if ((flags & 0x002000) | |||
| 2610 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2611 | return false; | |||
| 2612 | if (flags & 0x004000) | |||
| 2613 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2614 | return false; | |||
| 2615 | if (flags & 0x008000) | |||
| 2616 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2617 | return false; | |||
| 2618 | if (flags & 0x010000) | |||
| 2619 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2620 | return false; | |||
| 2621 | if (flags & 0x020000) | |||
| 2622 | if (readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2623 | && hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 2624 | return false; | |||
| 2625 | if (flags & 0x040000) | |||
| 2626 | if (readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2627 | && hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 2628 | return false; | |||
| 2629 | if (flags & 0x080000) | |||
| 2630 | if (readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2631 | && hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 2632 | return false; | |||
| 2633 | if (flags & 0x100000) | |||
| 2634 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2635 | return false; | |||
| 2636 | if (flags & 0x200000) | |||
| 2637 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2638 | return false; | |||
| 2639 | if (flags & 0x400000) | |||
| 2640 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2641 | return false; | |||
| 2642 | } | |||
| 2643 | ||||
| 2644 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2645 | return false; | |||
| 2646 | if (hasMask) { | |||
| 2647 | std::uint32_t flags = 0; | |||
| 2648 | if (!readFlags(flags)) | |||
| 2649 | return false; | |||
| 2650 | ++maskCount; | |||
| 2651 | for (int i = 0; i < 18; ++i) { | |||
| 2652 | if (flags & (1u << i) | |||
| 2653 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2654 | return false; | |||
| 2655 | } | |||
| 2656 | } | |||
| 2657 | ||||
| 2658 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2659 | return false; | |||
| 2660 | if (hasMask) { | |||
| 2661 | std::uint32_t flags = 0; | |||
| 2662 | if (!readFlags(flags)) | |||
| 2663 | return false; | |||
| 2664 | ++maskCount; | |||
| 2665 | for (int i = 0; i < 18; ++i) { | |||
| 2666 | if (flags & (1u << i)) | |||
| 2667 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2668 | return false; | |||
| 2669 | } | |||
| 2670 | } | |||
| 2671 | ||||
| 2672 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2673 | return false; | |||
| 2674 | if (hasMask) { | |||
| 2675 | std::uint32_t flags = 0; | |||
| 2676 | if (!readFlags(flags)) | |||
| 2677 | return false; | |||
| 2678 | ++maskCount; | |||
| 2679 | for (int i = 0; i < 18; ++i) { | |||
| 2680 | if (flags & (1u << i)) | |||
| 2681 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2682 | return false; | |||
| 2683 | } | |||
| 2684 | } | |||
| 2685 | ||||
| 2686 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2687 | if (ranges != nullptr && (maskCount != 0 || currentDwgBit(buf) != startBit)) { | |||
| 2688 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2689 | "r2007-table-overrides", startBit, currentDwgBit(buf), | |||
| 2690 | version, maskCount, good)); | |||
| 2691 | } | |||
| 2692 | return good; | |||
| 2693 | } | |||
| 2694 | ||||
| 2695 | bool skipTableContentFormat(DRW::Version version, dwgBuffer *buf, | |||
| 2696 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2697 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2698 | const TableDwgBounds& bounds) { | |||
| 2699 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2700 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2701 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // property override flags | |||
| 2702 | || !skipTableBitLong(*buf, bounds.bodyEndBit) // property flags | |||
| 2703 | || !skipTableBitLong(*buf, bounds.bodyEndBit) // value data type | |||
| 2704 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) { // value unit type | |||
| 2705 | return false; | |||
| 2706 | } | |||
| 2707 | readTableText(version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2708 | if (!textBuf->isGood()) | |||
| 2709 | return false; | |||
| 2710 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit) // rotation | |||
| 2711 | || !skipTableBitDouble(*buf, bounds.bodyEndBit) // block scale | |||
| 2712 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // alignment | |||
| 2713 | return false; | |||
| 2714 | std::int32_t rgb = -1; | |||
| 2715 | UTF8STRINGstd::string name; | |||
| 2716 | UTF8STRINGstd::string book; | |||
| 2717 | std::uint32_t color = 0; | |||
| 2718 | if (!readBoundedCmColor(*buf, strBuf, bounds.bodyEndBit, version, | |||
| 2719 | color, &rgb, nullptr, &name, &book, | |||
| 2720 | bounds.stringEndBit) | |||
| 2721 | || (hdlBuf != nullptr | |||
| 2722 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2723 | && !hdlBuf->isGood()) | |||
| 2724 | || !skipTableBitDouble(*buf, bounds.bodyEndBit)) // text height | |||
| 2725 | return false; | |||
| 2726 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2727 | if (ranges != nullptr) { | |||
| 2728 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2729 | "table-content-format", startBit, currentDwgBit(buf), | |||
| 2730 | version, 1, good)); | |||
| 2731 | } | |||
| 2732 | return good; | |||
| 2733 | } | |||
| 2734 | ||||
| 2735 | bool skipTableCellStyle(DRW::Version version, dwgBuffer *buf, | |||
| 2736 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2737 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2738 | const TableDwgBounds& bounds) { | |||
| 2739 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2740 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) // style type | |||
| 2741 | return false; | |||
| 2742 | std::uint16_t dataFlags = 0; | |||
| 2743 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, dataFlags)) | |||
| 2744 | return false; | |||
| 2745 | const bool hasData = dataFlags != 0; | |||
| 2746 | if (!hasData) { | |||
| 2747 | if (ranges != nullptr) { | |||
| 2748 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2749 | "table-cell-style", startBit, currentDwgBit(buf), | |||
| 2750 | version, 0, buf->isGood())); | |||
| 2751 | } | |||
| 2752 | return buf->isGood(); | |||
| 2753 | } | |||
| 2754 | ||||
| 2755 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // property override flags | |||
| 2756 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // merge flags | |||
| 2757 | return false; | |||
| 2758 | std::int32_t rgb = -1; | |||
| 2759 | UTF8STRINGstd::string name; | |||
| 2760 | UTF8STRINGstd::string book; | |||
| 2761 | std::uint32_t color = 0; | |||
| 2762 | if (!readBoundedCmColor(*buf, strBuf, bounds.bodyEndBit, version, | |||
| 2763 | color, &rgb, nullptr, &name, &book, | |||
| 2764 | bounds.stringEndBit) | |||
| 2765 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // content layout | |||
| 2766 | return false; | |||
| 2767 | if (!skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges, | |||
| 2768 | bounds)) | |||
| 2769 | return false; | |||
| 2770 | ||||
| 2771 | std::uint16_t marginFlags = 0; | |||
| 2772 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, marginFlags)) | |||
| 2773 | return false; | |||
| 2774 | if (marginFlags != 0) { | |||
| 2775 | for (int i = 0; i < 6; ++i) | |||
| 2776 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2777 | return false; | |||
| 2778 | } | |||
| 2779 | ||||
| 2780 | std::uint32_t borders = 0; | |||
| 2781 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, 6, 2, | |||
| 2782 | borders)) { | |||
| 2783 | 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"); | |||
| 2784 | return false; | |||
| 2785 | } | |||
| 2786 | for (std::uint32_t i = 0; i < borders; ++i) { | |||
| 2787 | std::int32_t edgeFlags = 0; | |||
| 2788 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, edgeFlags)) | |||
| 2789 | return false; | |||
| 2790 | if (edgeFlags == 0) | |||
| 2791 | continue; | |||
| 2792 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // border overrides | |||
| 2793 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // border type | |||
| 2794 | return false; | |||
| 2795 | if (!readBoundedCmColor(*buf, strBuf, bounds.bodyEndBit, version, | |||
| 2796 | color, &rgb, nullptr, &name, &book, | |||
| 2797 | bounds.stringEndBit) | |||
| 2798 | || (hdlBuf != nullptr | |||
| 2799 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2800 | && !hdlBuf->isGood()) | |||
| 2801 | || !skipTableBitLong(*buf, bounds.bodyEndBit) // visible/invisible | |||
| 2802 | || !skipTableBitDouble(*buf, bounds.bodyEndBit)) // double line spacing | |||
| 2803 | return false; | |||
| 2804 | } | |||
| 2805 | ||||
| 2806 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2807 | if (ranges != nullptr) { | |||
| 2808 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2809 | "table-cell-style", startBit, currentDwgBit(buf), | |||
| 2810 | version, borders, good)); | |||
| 2811 | } | |||
| 2812 | return good; | |||
| 2813 | } | |||
| 2814 | ||||
| 2815 | bool parseTableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2816 | dwgBuffer *hdlBuf, DRW_TableCell& cell, | |||
| 2817 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2818 | const TableDwgBounds& bounds) { | |||
| 2819 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2820 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_flags)) | |||
| 2821 | return false; | |||
| 2822 | cell.m_toolTip = readTableText( | |||
| 2823 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2824 | if (!textBuf->isGood()) { | |||
| 2825 | DRW_DBG("TABLE cell tooltip string read failed\n")DRW_dbg::dbg("TABLE cell tooltip string read failed\n"); | |||
| 2826 | return false; | |||
| 2827 | } | |||
| 2828 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) // custom data | |||
| 2829 | return false; | |||
| 2830 | ||||
| 2831 | std::uint32_t customItems = 0; | |||
| 2832 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, kMaxTableItems, 2, | |||
| 2833 | customItems)) { | |||
| 2834 | 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"); | |||
| 2835 | return false; | |||
| 2836 | } | |||
| 2837 | for (std::uint32_t i = 0; i < customItems; ++i) { | |||
| 2838 | if (!skipTableCustomData(version, buf, strBuf, hdlBuf, bounds)) { | |||
| 2839 | DRW_DBG("TABLE cell custom data parse incomplete\n")DRW_dbg::dbg("TABLE cell custom data parse incomplete\n"); | |||
| 2840 | return false; | |||
| 2841 | } | |||
| 2842 | } | |||
| 2843 | ||||
| 2844 | std::int32_t hasLinkedData = 0; | |||
| 2845 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, hasLinkedData)) | |||
| 2846 | return false; | |||
| 2847 | if (hasLinkedData != 0) { | |||
| 2848 | if (hdlBuf != nullptr | |||
| 2849 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2850 | && !hdlBuf->isGood()) | |||
| 2851 | return false; | |||
| 2852 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) | |||
| 2853 | || !skipTableBitLong(*buf, bounds.bodyEndBit) | |||
| 2854 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) | |||
| 2855 | return false; | |||
| 2856 | } | |||
| 2857 | ||||
| 2858 | std::uint32_t contentCount = 0; | |||
| 2859 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, kMaxTableItems, 2, | |||
| 2860 | contentCount)) { | |||
| 2861 | 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"); | |||
| 2862 | return false; | |||
| 2863 | } | |||
| 2864 | if (!DRW::reserve(cell.m_contents, static_cast<int>(contentCount))) | |||
| 2865 | return false; | |||
| 2866 | for (std::uint32_t i = 0; i < contentCount; ++i) { | |||
| 2867 | DRW_TableCellContent content; | |||
| 2868 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, content.m_type)) | |||
| 2869 | return false; | |||
| 2870 | if (content.m_type == 1) { | |||
| 2871 | if (!readTableCadValue(version, buf, strBuf, hdlBuf, | |||
| 2872 | content.m_value, bounds)) { | |||
| 2873 | DRW_DBG("TABLE cell value parse incomplete\n")DRW_dbg::dbg("TABLE cell value parse incomplete\n"); | |||
| 2874 | return false; | |||
| 2875 | } | |||
| 2876 | if (content.m_value.m_value.type() == DRW_Variant::STRING) | |||
| 2877 | content.m_text = content.m_value.m_value.c_str(); | |||
| 2878 | else if (!content.m_value.m_valueString.empty()) | |||
| 2879 | content.m_text = content.m_value.m_valueString; | |||
| 2880 | } else if (content.m_type == 2 || content.m_type == 4) { | |||
| 2881 | content.m_handle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2882 | } | |||
| 2883 | ||||
| 2884 | std::uint32_t numAttrs = 0; | |||
| 2885 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, kMaxTableItems, 2, | |||
| 2886 | numAttrs)) { | |||
| 2887 | 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"); | |||
| 2888 | return false; | |||
| 2889 | } | |||
| 2890 | for (std::uint32_t attr = 0; attr < numAttrs; ++attr) { | |||
| 2891 | if (hdlBuf != nullptr | |||
| 2892 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2893 | && !hdlBuf->isGood()) | |||
| 2894 | return false; | |||
| 2895 | readTableText(version, textBuf, | |||
| 2896 | tableTextEndBit(buf, textBuf, bounds)); | |||
| 2897 | if (!textBuf->isGood() | |||
| 2898 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) | |||
| 2899 | return false; | |||
| 2900 | } | |||
| 2901 | ||||
| 2902 | std::uint16_t contentFormatFlag = 0; | |||
| 2903 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, contentFormatFlag)) | |||
| 2904 | return false; | |||
| 2905 | const bool hasContentFormat = contentFormatFlag != 0; | |||
| 2906 | if (hasContentFormat | |||
| 2907 | && !skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges, | |||
| 2908 | bounds)) { | |||
| 2909 | DRW_DBG("TABLE cell content format parse incomplete\n")DRW_dbg::dbg("TABLE cell content format parse incomplete\n"); | |||
| 2910 | return false; | |||
| 2911 | } | |||
| 2912 | cell.m_contents.push_back(content); | |||
| 2913 | } | |||
| 2914 | ||||
| 2915 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, ranges, bounds)) { | |||
| 2916 | DRW_DBG("TABLE cell style override parse incomplete\n")DRW_dbg::dbg("TABLE cell style override parse incomplete\n"); | |||
| 2917 | return false; | |||
| 2918 | } | |||
| 2919 | ||||
| 2920 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_styleId)) | |||
| 2921 | return false; | |||
| 2922 | const std::uint64_t geometryStartBit = currentDwgBit(buf); | |||
| 2923 | std::int32_t hasGeometry = 0; | |||
| 2924 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, hasGeometry)) | |||
| 2925 | return false; | |||
| 2926 | if (hasGeometry != 0) { | |||
| 2927 | std::int32_t geometryFlags = 0; | |||
| 2928 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // unknown AC1027+ geometry marker | |||
| 2929 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_width) | |||
| 2930 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_height) | |||
| 2931 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, geometryFlags)) | |||
| 2932 | return false; | |||
| 2933 | cell.m_geometryFlags = geometryFlags; | |||
| 2934 | cell.m_geometryHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2935 | if (cell.m_geometryFlags != 0) { | |||
| 2936 | std::int32_t geometryRecordFlags = 0; | |||
| 2937 | if (!readBounded3BitDouble(*buf, bounds.bodyEndBit, | |||
| 2938 | cell.m_geometryTopLeft) | |||
| 2939 | || !readBounded3BitDouble(*buf, bounds.bodyEndBit, | |||
| 2940 | cell.m_geometryCenter) | |||
| 2941 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2942 | cell.m_contentWidth) | |||
| 2943 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2944 | cell.m_contentHeight) | |||
| 2945 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2946 | cell.m_geometryWidth) | |||
| 2947 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2948 | cell.m_geometryHeight) | |||
| 2949 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 2950 | geometryRecordFlags)) | |||
| 2951 | return false; | |||
| 2952 | cell.m_geometryRecordFlags = geometryRecordFlags; | |||
| 2953 | } | |||
| 2954 | if (ranges != nullptr) { | |||
| 2955 | const bool geometryGood = buf->isGood() && (!hdlBuf || hdlBuf->isGood()); | |||
| 2956 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2957 | "table-cell-geometry-tail", geometryStartBit, currentDwgBit(buf), | |||
| 2958 | version, cell.m_geometryFlags, geometryGood)); | |||
| 2959 | } | |||
| 2960 | } | |||
| 2961 | ||||
| 2962 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2963 | if (!good) | |||
| 2964 | DRW_DBG("TABLE cell stream ended unexpectedly\n")DRW_dbg::dbg("TABLE cell stream ended unexpectedly\n"); | |||
| 2965 | return good; | |||
| 2966 | } | |||
| 2967 | ||||
| 2968 | bool parseTableContent(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2969 | dwgBuffer *hdlBuf, DRW_TableContent& content, | |||
| 2970 | const TableDwgBounds& bounds) { | |||
| 2971 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2972 | const std::uint64_t textEndBit = tableTextEndBit(buf, textBuf, bounds); | |||
| 2973 | content.m_name = readTableText(version, textBuf, textEndBit); | |||
| 2974 | content.m_description = readTableText(version, textBuf, textEndBit); | |||
| 2975 | if (!textBuf->isGood()) | |||
| 2976 | return false; | |||
| 2977 | ||||
| 2978 | std::uint32_t columns = 0; | |||
| 2979 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2980 | kMaxTableColumns, 2, | |||
| 2981 | columns)) { | |||
| 2982 | 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"); | |||
| 2983 | return false; | |||
| 2984 | } | |||
| 2985 | content.m_columns.clear(); | |||
| 2986 | if (!DRW::reserve(content.m_columns, static_cast<int>(columns))) | |||
| 2987 | return false; | |||
| 2988 | for (std::uint32_t col = 0; col < columns; ++col) { | |||
| 2989 | DRW_TableColumn column; | |||
| 2990 | column.m_name = readTableText(version, textBuf, textEndBit); | |||
| 2991 | if (!textBuf->isGood() | |||
| 2992 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // custom data | |||
| 2993 | return false; | |||
| 2994 | std::uint32_t customItems = 0; | |||
| 2995 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2996 | kMaxTableItems, 2, | |||
| 2997 | customItems)) { | |||
| 2998 | 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"); | |||
| 2999 | return false; | |||
| 3000 | } | |||
| 3001 | for (std::uint32_t i = 0; i < customItems; ++i) { | |||
| 3002 | if (!skipTableCustomData(version, buf, strBuf, hdlBuf, bounds)) { | |||
| 3003 | DRW_DBG("TABLECONTENT column custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column custom data parse incomplete\n" ); | |||
| 3004 | return false; | |||
| 3005 | } | |||
| 3006 | } | |||
| 3007 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, | |||
| 3008 | &content.m_subrecordRanges, bounds)) { | |||
| 3009 | DRW_DBG("TABLECONTENT column cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column cell style parse incomplete\n" ); | |||
| 3010 | return false; | |||
| 3011 | } | |||
| 3012 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // style id | |||
| 3013 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 3014 | column.m_width)) | |||
| 3015 | return false; | |||
| 3016 | content.m_columns.push_back(column); | |||
| 3017 | } | |||
| 3018 | ||||
| 3019 | std::uint32_t rows = 0; | |||
| 3020 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 3021 | kMaxTableRows, 2, | |||
| 3022 | rows) | |||
| 3023 | || (columns != 0 && rows > kMaxTableCells / columns)) { | |||
| 3024 | 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"); | |||
| 3025 | return false; | |||
| 3026 | } | |||
| 3027 | content.m_rows.clear(); | |||
| 3028 | if (!DRW::reserve(content.m_rows, static_cast<int>(rows))) | |||
| 3029 | return false; | |||
| 3030 | for (std::uint32_t rowIndex = 0; rowIndex < rows; ++rowIndex) { | |||
| 3031 | DRW_TableRow row; | |||
| 3032 | std::uint32_t cells = 0; | |||
| 3033 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 3034 | kMaxTableColumns, 2, | |||
| 3035 | cells) | |||
| 3036 | || cells > kMaxTableItems) { | |||
| 3037 | 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"); | |||
| 3038 | return false; | |||
| 3039 | } | |||
| 3040 | if (!DRW::reserve(row.m_cells, static_cast<int>(cells))) | |||
| 3041 | return false; | |||
| 3042 | for (std::uint32_t cellIndex = 0; cellIndex < cells; ++cellIndex) { | |||
| 3043 | DRW_TableCell cell; | |||
| 3044 | if (!parseTableCell(version, buf, strBuf, hdlBuf, cell, | |||
| 3045 | &content.m_subrecordRanges, bounds)) { | |||
| 3046 | DRW_DBG("TABLECONTENT cell parse incomplete at row ")DRW_dbg::dbg("TABLECONTENT cell parse incomplete at row "); DRW_DBG(rowIndex)DRW_dbg::dbg(rowIndex); | |||
| 3047 | DRW_DBG(" cell ")DRW_dbg::dbg(" cell "); DRW_DBG(cellIndex)DRW_dbg::dbg(cellIndex); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3048 | return false; | |||
| 3049 | } | |||
| 3050 | row.m_cells.push_back(cell); | |||
| 3051 | } | |||
| 3052 | ||||
| 3053 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) // custom data | |||
| 3054 | return false; | |||
| 3055 | std::uint32_t customItems = 0; | |||
| 3056 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 3057 | kMaxTableItems, 2, | |||
| 3058 | customItems)) { | |||
| 3059 | 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"); | |||
| 3060 | return false; | |||
| 3061 | } | |||
| 3062 | for (std::uint32_t i = 0; i < customItems; ++i) { | |||
| 3063 | if (!skipTableCustomData(version, buf, strBuf, hdlBuf, bounds)) { | |||
| 3064 | DRW_DBG("TABLECONTENT row custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row custom data parse incomplete\n" ); | |||
| 3065 | return false; | |||
| 3066 | } | |||
| 3067 | } | |||
| 3068 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, | |||
| 3069 | &content.m_subrecordRanges, bounds)) { | |||
| 3070 | DRW_DBG("TABLECONTENT row cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row cell style parse incomplete\n" ); | |||
| 3071 | return false; | |||
| 3072 | } | |||
| 3073 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // style id | |||
| 3074 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, row.m_height)) | |||
| 3075 | return false; | |||
| 3076 | content.m_rows.push_back(row); | |||
| 3077 | } | |||
| 3078 | ||||
| 3079 | std::uint32_t fieldRefs = 0; | |||
| 3080 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 3081 | kMaxTableItems, 0, | |||
| 3082 | fieldRefs)) { | |||
| 3083 | 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"); | |||
| 3084 | return false; | |||
| 3085 | } | |||
| 3086 | content.m_fieldHandles.clear(); | |||
| 3087 | if (!DRW::reserve(content.m_fieldHandles, static_cast<int>(fieldRefs))) | |||
| 3088 | return false; | |||
| 3089 | for (std::uint32_t i = 0; i < fieldRefs; ++i) { | |||
| 3090 | const std::uint32_t ref = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 3091 | if (hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 3092 | return false; | |||
| 3093 | if (ref != 0) | |||
| 3094 | content.m_fieldHandles.push_back(ref); | |||
| 3095 | } | |||
| 3096 | ||||
| 3097 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, | |||
| 3098 | &content.m_subrecordRanges, bounds)) { | |||
| 3099 | DRW_DBG("TABLECONTENT table cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT table cell style parse incomplete\n" ); | |||
| 3100 | return false; | |||
| 3101 | } | |||
| 3102 | ||||
| 3103 | std::uint32_t mergedRanges = 0; | |||
| 3104 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 3105 | kMaxTableItems, 8, | |||
| 3106 | mergedRanges)) { | |||
| 3107 | 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"); | |||
| 3108 | return false; | |||
| 3109 | } | |||
| 3110 | content.m_mergedRanges.clear(); | |||
| 3111 | if (!DRW::reserve(content.m_mergedRanges, | |||
| 3112 | static_cast<int>(mergedRanges))) | |||
| 3113 | return false; | |||
| 3114 | for (std::uint32_t i = 0; i < mergedRanges; ++i) { | |||
| 3115 | DRW_TableMergedRange range; | |||
| 3116 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, range.m_topRow) | |||
| 3117 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 3118 | range.m_leftColumn) | |||
| 3119 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 3120 | range.m_bottomRow) | |||
| 3121 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 3122 | range.m_rightColumn)) | |||
| 3123 | return false; | |||
| 3124 | content.m_mergedRanges.push_back(range); | |||
| 3125 | } | |||
| 3126 | ||||
| 3127 | content.m_tableStyleHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 3128 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 3129 | if (!good) | |||
| 3130 | DRW_DBG("TABLECONTENT stream ended unexpectedly\n")DRW_dbg::dbg("TABLECONTENT stream ended unexpectedly\n"); | |||
| 3131 | return good; | |||
| 3132 | } | |||
| 3133 | ||||
| 3134 | } // namespace | |||
| 3135 | ||||
| 3136 | //! Calculate arbitrary axis | |||
| 3137 | /*! | |||
| 3138 | * Calculate arbitrary axis for apply extrusions | |||
| 3139 | * @author Rallaz | |||
| 3140 | */ | |||
| 3141 | void DRW_Entity::calculateAxis(DRW_Coord extPoint){ | |||
| 3142 | //Follow the arbitrary DXF definitions for extrusion axes. | |||
| 3143 | if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625) { | |||
| 3144 | //If we get here, implement Ax = Wy x N where Wy is [0,1,0] per the DXF spec. | |||
| 3145 | //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 | |||
| 3146 | //Factoring in the fixed values for Wy gives N.z,0,-N.x | |||
| 3147 | extAxisX.x = extPoint.z; | |||
| 3148 | extAxisX.y = 0; | |||
| 3149 | extAxisX.z = -extPoint.x; | |||
| 3150 | } else { | |||
| 3151 | //Otherwise, implement Ax = Wz x N where Wz is [0,0,1] per the DXF spec. | |||
| 3152 | //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 | |||
| 3153 | //Factoring in the fixed values for Wz gives -N.y,N.x,0. | |||
| 3154 | extAxisX.x = -extPoint.y; | |||
| 3155 | extAxisX.y = extPoint.x; | |||
| 3156 | extAxisX.z = 0; | |||
| 3157 | } | |||
| 3158 | ||||
| 3159 | extAxisX.unitize(); | |||
| 3160 | ||||
| 3161 | //Ay = N x Ax | |||
| 3162 | extAxisY.x = (extPoint.y * extAxisX.z) - (extAxisX.y * extPoint.z); | |||
| 3163 | extAxisY.y = (extPoint.z * extAxisX.x) - (extAxisX.z * extPoint.x); | |||
| 3164 | extAxisY.z = (extPoint.x * extAxisX.y) - (extAxisX.x * extPoint.y); | |||
| 3165 | ||||
| 3166 | extAxisY.unitize(); | |||
| 3167 | } | |||
| 3168 | ||||
| 3169 | //! Extrude a point using arbitrary axis | |||
| 3170 | /*! | |||
| 3171 | * apply extrusion in a point using arbitrary axis (previous calculated) | |||
| 3172 | * @author Rallaz | |||
| 3173 | */ | |||
| 3174 | void DRW_Entity::extrudePoint(DRW_Coord extPoint, DRW_Coord *point){ | |||
| 3175 | double px, py, pz; | |||
| 3176 | px = (extAxisX.x*point->x)+(extAxisY.x*point->y)+(extPoint.x*point->z); | |||
| 3177 | py = (extAxisX.y*point->x)+(extAxisY.y*point->y)+(extPoint.y*point->z); | |||
| 3178 | pz = (extAxisX.z*point->x)+(extAxisY.z*point->y)+(extPoint.z*point->z); | |||
| 3179 | ||||
| 3180 | point->x = px; | |||
| 3181 | point->y = py; | |||
| 3182 | point->z = pz; | |||
| 3183 | } | |||
| 3184 | ||||
| 3185 | bool DRW_Entity::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 3186 | try { | |||
| 3187 | switch (code) { | |||
| 3188 | case DRW::dxfCode::HANDLE: | |||
| 3189 | // A damaged file's empty or repeated handle on a typed entity is | |||
| 3190 | // dropped; the entity loads and gets a new handle when saved. | |||
| 3191 | if (reader->getString().empty()) | |||
| 3192 | break; | |||
| 3193 | if (!reader->isValidHandleString()) | |||
| 3194 | return false; | |||
| 3195 | if (reader->registerSelfHandle()) | |||
| 3196 | handle = reader->getHandleString(); | |||
| 3197 | break; | |||
| 3198 | case DRW::dxfCode::OWNER_HANDLE: | |||
| 3199 | parentHandle = reader->getHandleString(); | |||
| 3200 | break; | |||
| 3201 | case DRW::dxfCode::LAYER: | |||
| 3202 | layer = reader->getUtf8String(); | |||
| 3203 | break; | |||
| 3204 | case 6: | |||
| 3205 | lineType = reader->getUtf8String(); | |||
| 3206 | break; | |||
| 3207 | case DRW::dxfCode::COLOR: | |||
| 3208 | color = reader->getInt32(); | |||
| 3209 | break; | |||
| 3210 | case DRW::dxfCode::LINEWEIGHT: | |||
| 3211 | lWeight = DRW_LW_Conv::dxfInt2lineWidth(reader->getInt32()); | |||
| 3212 | break; | |||
| 3213 | case 48: | |||
| 3214 | ltypeScale = reader->getDouble(); | |||
| 3215 | break; | |||
| 3216 | case DRW::dxfCode::INVISIBLE: | |||
| 3217 | // DXF 60 is a scalar visibility value, not a DWG bit field. | |||
| 3218 | visible = reader->getInt32() == 0; | |||
| 3219 | break; | |||
| 3220 | case 420: | |||
| 3221 | color24 = reader->getInt32(); | |||
| 3222 | break; | |||
| 3223 | case 430: | |||
| 3224 | colorName = reader->getString(); | |||
| 3225 | break; | |||
| 3226 | case 67: | |||
| 3227 | { | |||
| 3228 | const int value = reader->getInt32(); | |||
| 3229 | if (value < DRW::ModelSpace || value > DRW::PaperSpace) | |||
| 3230 | return false; | |||
| 3231 | space = static_cast<DRW::Space>(value); | |||
| 3232 | } | |||
| 3233 | break; | |||
| 3234 | case 102: | |||
| 3235 | return parseDxfGroups(code, reader); | |||
| 3236 | case 284: | |||
| 3237 | { | |||
| 3238 | int value = 0; | |||
| 3239 | if (!readDxfIntInRange(reader, DRW::CastAndReceieveShadows, | |||
| 3240 | DRW::IgnoreShadows, value)) | |||
| 3241 | return false; | |||
| 3242 | shadow = static_cast<DRW::ShadowMode>(value); | |||
| 3243 | } | |||
| 3244 | break; | |||
| 3245 | case 347: | |||
| 3246 | material = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 3247 | break; | |||
| 3248 | case 348: | |||
| 3249 | fullVisualStyleHandle = reader->getHandleString(); | |||
| 3250 | break; | |||
| 3251 | case 360: | |||
| 3252 | xDictHandle = reader->getHandleString(); | |||
| 3253 | break; | |||
| 3254 | case DRW::dxfCode::PLOTSTYLE: | |||
| 3255 | plotStyle = reader->getHandleString(); | |||
| 3256 | break; | |||
| 3257 | case 440: | |||
| 3258 | transparency = reader->getInt32(); | |||
| 3259 | break; | |||
| 3260 | case 92: { | |||
| 3261 | // Proxy entity graphics byte count (ODA §20.4.95): 92 for R13–R2007. | |||
| 3262 | // Entities that repurpose 92 (for example MESH) handle it before this | |||
| 3263 | // base parser is reached. | |||
| 3264 | const std::int32_t value = reader->getInt32(); | |||
| 3265 | if (value < 0 | |||
| 3266 | || static_cast<std::uint32_t>(value) | |||
| 3267 | > DRW::kMaxDxfBinaryPayloadBytes) | |||
| 3268 | return false; | |||
| 3269 | numProxyGraph = value; | |||
| 3270 | proxyGraphics.clear(); | |||
| 3271 | break; | |||
| 3272 | } | |||
| 3273 | case 160: { | |||
| 3274 | // R2010+ uses a 64-bit DXF count (group 160), not group 92's 32-bit | |||
| 3275 | // storage. Keep the public legacy field bounded and representable. | |||
| 3276 | const std::int64_t value = reader->getInt64(); | |||
| 3277 | if (value < 0 | |||
| 3278 | || static_cast<std::uint64_t>(value) | |||
| 3279 | > DRW::kMaxDxfBinaryPayloadBytes) | |||
| 3280 | return false; | |||
| 3281 | numProxyGraph = static_cast<int>(value); | |||
| 3282 | proxyGraphics.clear(); | |||
| 3283 | break; | |||
| 3284 | } | |||
| 3285 | case 310: | |||
| 3286 | if (numProxyGraph != 0) { | |||
| 3287 | // Proxy graphics binary, hex-encoded across many ≤254-char chunks. | |||
| 3288 | const std::string& hex = reader->getString(); | |||
| 3289 | if (!appendHexBytesChecked( | |||
| 3290 | proxyGraphics, hex, | |||
| 3291 | std::min<std::size_t>( | |||
| 3292 | DRW::kMaxDxfBinaryPayloadBytes, | |||
| 3293 | static_cast<std::size_t>(numProxyGraph)))) | |||
| 3294 | return false; | |||
| 3295 | } | |||
| 3296 | break; | |||
| 3297 | case 1000: | |||
| 3298 | case 1001: | |||
| 3299 | case 1002: | |||
| 3300 | case 1003: | |||
| 3301 | case 1004: | |||
| 3302 | case 1005: | |||
| 3303 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3304 | return false; | |||
| 3305 | extData.push_back(std::make_shared<DRW_Variant>(code, | |||
| 3306 | reader->getString())); | |||
| 3307 | break; | |||
| 3308 | case 1010: | |||
| 3309 | case 1011: | |||
| 3310 | case 1012: | |||
| 3311 | case 1013: | |||
| 3312 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3313 | return false; | |||
| 3314 | curr = std::make_shared<DRW_Variant>( | |||
| 3315 | code, DRW_Coord(reader->getDouble(), 0.0, 0.0)); | |||
| 3316 | extData.push_back(curr); | |||
| 3317 | break; | |||
| 3318 | // Files repeat Y and Z after a point's Z (R12 ACAD_MATERIAL_MAPPER and | |||
| 3319 | // ASC_SEEDPOINT); a component with no open point is dropped. | |||
| 3320 | case 1020: | |||
| 3321 | case 1021: | |||
| 3322 | case 1022: | |||
| 3323 | case 1023: | |||
| 3324 | if (curr) | |||
| 3325 | curr->setCoordY(reader->getDouble()); | |||
| 3326 | break; | |||
| 3327 | case 1030: | |||
| 3328 | case 1031: | |||
| 3329 | case 1032: | |||
| 3330 | case 1033: | |||
| 3331 | if (curr) | |||
| 3332 | curr->setCoordZ(reader->getDouble()); | |||
| 3333 | curr.reset(); | |||
| 3334 | break; | |||
| 3335 | case 1040: | |||
| 3336 | case 1041: | |||
| 3337 | case 1042: | |||
| 3338 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3339 | return false; | |||
| 3340 | extData.push_back(std::make_shared<DRW_Variant>(code, | |||
| 3341 | reader->getDouble())); | |||
| 3342 | break; | |||
| 3343 | case 1070: | |||
| 3344 | case 1071: | |||
| 3345 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3346 | return false; | |||
| 3347 | extData.push_back(std::make_shared<DRW_Variant>(code, | |||
| 3348 | reader->getInt32())); | |||
| 3349 | break; | |||
| 3350 | default: | |||
| 3351 | break; | |||
| 3352 | } | |||
| 3353 | return true; | |||
| 3354 | } catch (...) { | |||
| 3355 | reset(); | |||
| 3356 | return false; | |||
| 3357 | } | |||
| 3358 | } | |||
| 3359 | ||||
| 3360 | //parses dxf 102 groups to read entity | |||
| 3361 | bool DRW_Entity::parseDxfGroups(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 3362 | if (appData.size() >= DRW::kMaxDxfApplicationGroups) | |||
| 3363 | return false; | |||
| 3364 | std::list<DRW_Variant> ls; | |||
| 3365 | DRW_Variant curr; | |||
| 3366 | std::string appName= reader->getString(); | |||
| 3367 | if (appName.size() <= 1 || appName.front() != '{') | |||
| 3368 | return false; | |||
| 3369 | ||||
| 3370 | const bool isReactors = appName == "{ACAD_REACTORS"; | |||
| 3371 | const bool isXDictionary = appName == "{ACAD_XDICTIONARY"; | |||
| 3372 | std::vector<std::uint32_t> parsedReactors; | |||
| 3373 | std::uint32_t parsedXDictionary = 0; | |||
| 3374 | ||||
| 3375 | curr.addString(code, appName.substr(1)); | |||
| 3376 | ls.push_back(curr); | |||
| 3377 | int depth = 1; | |||
| 3378 | int nextCode = 0; | |||
| 3379 | while (depth > 0 && reader->readRec(&nextCode)) { | |||
| 3380 | if (ls.size() >= DRW::kMaxDxfApplicationGroupPairs) | |||
| 3381 | return false; | |||
| 3382 | ||||
| 3383 | // A section/entity boundary before the matching 102 close would be | |||
| 3384 | // consumed irreversibly and leave the caller out of sync. | |||
| 3385 | if (nextCode == 0) | |||
| 3386 | return false; | |||
| 3387 | ||||
| 3388 | DRW_Variant value; | |||
| 3389 | if (nextCode == 102) { | |||
| 3390 | const std::string marker = reader->getString(); | |||
| 3391 | if (marker.empty() || (marker.front() == '{' && marker.size() == 1)) | |||
| 3392 | return false; | |||
| 3393 | if (marker.front() == '{') { | |||
| 3394 | if (++depth > DRW::kMaxDxfApplicationGroupNesting) | |||
| 3395 | return false; | |||
| 3396 | } else if (marker == "}") { | |||
| 3397 | --depth; | |||
| 3398 | } else { | |||
| 3399 | return false; | |||
| 3400 | } | |||
| 3401 | value.addString(nextCode, marker); | |||
| 3402 | } else if ((nextCode >= 320 && nextCode <= 369) | |||
| 3403 | || (nextCode >= 390 && nextCode <= 399) | |||
| 3404 | || nextCode == 480 || nextCode == 481 | |||
| 3405 | || nextCode == 1005) { | |||
| 3406 | const std::string rawHandle = reader->getString(); | |||
| 3407 | value.addString(nextCode, rawHandle); | |||
| 3408 | if (depth == 1 && isReactors && nextCode == 330) { | |||
| 3409 | const auto reactor = reader->getHandleString(); | |||
| 3410 | if (reactor != 0) { | |||
| 3411 | if (parsedReactors.size() >= dwgSafety::MaxReactorCount) | |||
| 3412 | return false; | |||
| 3413 | parsedReactors.push_back(static_cast<std::uint32_t>(reactor)); | |||
| 3414 | } | |||
| 3415 | } else if (depth == 1 && isXDictionary && nextCode == 360 | |||
| 3416 | && parsedXDictionary == 0) { | |||
| 3417 | parsedXDictionary = static_cast<std::uint32_t>( | |||
| 3418 | reader->getHandleString()); | |||
| 3419 | } | |||
| 3420 | } else { | |||
| 3421 | switch (reader->type) { | |||
| 3422 | case dxfReader::STRING: | |||
| 3423 | case dxfReader::BINARY: | |||
| 3424 | value.addString(nextCode, reader->getString()); | |||
| 3425 | break; | |||
| 3426 | case dxfReader::INT32: | |||
| 3427 | case dxfReader::BOOL: | |||
| 3428 | value.addInt(nextCode, reader->getInt32()); | |||
| 3429 | break; | |||
| 3430 | case dxfReader::INT64: | |||
| 3431 | value.addInt64(nextCode, static_cast<std::int64_t>(reader->getInt64())); | |||
| 3432 | break; | |||
| 3433 | case dxfReader::DOUBLE: | |||
| 3434 | value.addDouble(nextCode, reader->getDouble()); | |||
| 3435 | break; | |||
| 3436 | default: | |||
| 3437 | return false; | |||
| 3438 | } | |||
| 3439 | } | |||
| 3440 | ls.push_back(value); | |||
| 3441 | } | |||
| 3442 | ||||
| 3443 | if (depth != 0) | |||
| 3444 | return false; | |||
| 3445 | if (isReactors) | |||
| 3446 | reactorHandles = std::move(parsedReactors); | |||
| 3447 | if (isXDictionary && parsedXDictionary != 0) | |||
| 3448 | xDictHandle = parsedXDictionary; | |||
| 3449 | appData.push_back(std::move(ls)); | |||
| 3450 | return true; | |||
| 3451 | } | |||
| 3452 | ||||
| 3453 | bool DRW_Entity::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer* strBuf, std::uint32_t bs){ | |||
| 3454 | // This overload is also used by the two-stage common/handle tests and | |||
| 3455 | // callers; concrete record parsers own carrier reset so handle parsing can | |||
| 3456 | // remain transactional. | |||
| 3457 | if (buf == nullptr) | |||
| 3458 | return false; | |||
| 3459 | ||||
| 3460 | // The object size in bits is read at a version-dependent point: first | |||
| 3461 | // for R2000/R2004, derived for R2010+, and only after the EED and the | |||
| 3462 | // graphics data for R13/R14. Every bound computed before that point | |||
| 3463 | // spells "unknown" as 0 (the whole frame), so start from it instead of | |||
| 3464 | // whatever an earlier parse of this object, or the construction of a | |||
| 3465 | // probe entity, left behind. | |||
| 3466 | objSize = 0; | |||
| 3467 | ||||
| 3468 | DRW_DBG("\n***************************** parsing entity *********************************************\n")DRW_dbg::dbg("\n***************************** parsing entity *********************************************\n" ); | |||
| 3469 | oType = buf->getObjType(version); | |||
| 3470 | if (!buf->isGood()) | |||
| 3471 | return false; | |||
| 3472 | 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); | |||
| 3473 | ||||
| 3474 | if (version > DRW::AC1014 && version < DRW::AC1024) {//2000 & 2004 | |||
| 3475 | const std::uint64_t totalBits = static_cast<std::uint64_t>(buf->size()) * 8u; | |||
| 3476 | std::uint32_t parsedObjectSize = 0; | |||
| 3477 | if (!readBoundedRawLong32(*buf, totalBits, parsedObjectSize)) | |||
| 3478 | return false; | |||
| 3479 | objSize = parsedObjectSize; //RL 32bits object size in bits | |||
| 3480 | DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3481 | } | |||
| 3482 | if (version > DRW::AC1021) {//2010+ | |||
| 3483 | const std::uint64_t totalBits = static_cast<std::uint64_t>(buf->size()) * 8u; | |||
| 3484 | // Clamp: a corrupt bs > ms*8 would underflow objSize (unsigned) to a | |||
| 3485 | // huge value and drive strBuf->moveBitPos(objSize-1) past the buffer. | |||
| 3486 | if (totalBits > std::numeric_limits<std::uint32_t>::max() | |||
| 3487 | || bs > totalBits) | |||
| 3488 | return false; | |||
| 3489 | objSize = static_cast<std::uint32_t>(totalBits - bs); | |||
| 3490 | DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3491 | } | |||
| 3492 | ||||
| 3493 | if (strBuf != NULL__null && version > DRW::AC1018) {//2007+ | |||
| 3494 | if (!strBuf->seekR2007StringStream(objSize)) | |||
| 3495 | return false; | |||
| 3496 | 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"); | |||
| 3497 | 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"); | |||
| 3498 | } | |||
| 3499 | ||||
| 3500 | // R2007+ objSize includes the detached string stream and its footer. A | |||
| 3501 | // common entity prefix must stay in the data portion just like the | |||
| 3502 | // entity-specific readers below. Only a caller that supplies the real | |||
| 3503 | // modern string cursor can require the footer here; the null-cursor form | |||
| 3504 | // is retained for isolated common-prefix tests without object framing. | |||
| 3505 | std::uint64_t bodyEndBit = proxyEntityEndBit(*buf, objSize); | |||
| 3506 | if (version > DRW::AC1021 && strBuf != nullptr) { | |||
| 3507 | dwgBuffer stringBoundary = strBuf->forkIndependent(); | |||
| 3508 | if (!stringBoundary.seekR2007StringStream(objSize)) | |||
| 3509 | return false; | |||
| 3510 | bodyEndBit = currentDwgBit(&stringBoundary); | |||
| 3511 | } | |||
| 3512 | dwgDataEndBit = bodyEndBit; | |||
| 3513 | const auto bodyWithinBounds = [buf, &bodyEndBit]() { | |||
| 3514 | return currentDwgBit(buf) <= bodyEndBit; | |||
| 3515 | }; | |||
| 3516 | ||||
| 3517 | dwgHandle ho; | |||
| 3518 | if (!readBoundedDwgHandle(*buf, bodyEndBit, 0, false, ho)) | |||
| 3519 | return false; | |||
| 3520 | handle = ho.ref; | |||
| 3521 | 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); | |||
| 3522 | // EED is a bounded, repeated chunk stream. Parse all chunks before | |||
| 3523 | // changing the entity so a malformed item cannot leak partial metadata. | |||
| 3524 | std::vector<DwgEedChunk> eedChunks; | |||
| 3525 | if (!readDwgEed(version, *buf, eedChunks, bodyEndBit)) | |||
| 3526 | return false; | |||
| 3527 | if (!bodyWithinBounds()) | |||
| 3528 | return false; | |||
| 3529 | std::vector<std::shared_ptr<DRW_Variant>> parsedExtData; | |||
| 3530 | std::vector<PendingHandleRef> parsedAppIdResolutions; | |||
| 3531 | std::vector<PendingHandleRef> parsedLayerRefResolutions; | |||
| 3532 | try { | |||
| 3533 | for (const DwgEedChunk& chunk : eedChunks) { | |||
| 3534 | const std::size_t appIndex = | |||
| 3535 | extData.size() + parsedExtData.size(); | |||
| 3536 | parsedExtData.push_back( | |||
| 3537 | std::make_shared<DRW_Variant>(1001, std::string{})); | |||
| 3538 | parsedAppIdResolutions.push_back({appIndex, chunk.appHandle}); | |||
| 3539 | for (const DRW_Variant& item : chunk.items) | |||
| 3540 | parsedExtData.push_back(std::make_shared<DRW_Variant>(item)); | |||
| 3541 | for (const DwgEedHandleRef& ref : chunk.layerRefs) { | |||
| 3542 | parsedLayerRefResolutions.push_back( | |||
| 3543 | {appIndex + 1 + ref.itemIndex, ref.handleRef}); | |||
| 3544 | } | |||
| 3545 | } | |||
| 3546 | } catch (...) { | |||
| 3547 | return false; | |||
| 3548 | } | |||
| 3549 | 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"); | |||
| 3550 | bool graphFlag = false; | |||
| 3551 | if (!readBoundedBit(*buf, bodyEndBit, graphFlag)) | |||
| 3552 | return false; | |||
| 3553 | DRW_DBG(" graphFlag: ")DRW_dbg::dbg(" graphFlag: "); DRW_DBG(graphFlag)DRW_dbg::dbg(graphFlag); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3554 | if (!bodyWithinBounds()) | |||
| 3555 | return false; | |||
| 3556 | if (graphFlag) { | |||
| 3557 | 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"); | |||
| 3558 | std::uint64_t graphDataSize = 0; | |||
| 3559 | if (version >= DRW::AC1024) { | |||
| 3560 | if (!readBoundedBitLongLong(*buf, bodyEndBit, graphDataSize)) | |||
| 3561 | return false; | |||
| 3562 | } else { | |||
| 3563 | std::uint32_t parsedGraphDataSize = 0; | |||
| 3564 | if (!readBoundedRawLong32(*buf, bodyEndBit, | |||
| 3565 | parsedGraphDataSize)) | |||
| 3566 | return false; | |||
| 3567 | graphDataSize = parsedGraphDataSize; | |||
| 3568 | } | |||
| 3569 | 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"); | |||
| 3570 | if (!bodyWithinBounds()) | |||
| 3571 | return false; | |||
| 3572 | const std::uint64_t maxMoveBytes = static_cast<std::uint64_t>(std::numeric_limits<std::int32_t>::max() / 8); | |||
| 3573 | const std::uint64_t currentBit = currentDwgBit(buf); | |||
| 3574 | std::uint64_t graphBits = 0; | |||
| 3575 | if (!dwgSafety::multiply(graphDataSize, 8, graphBits) | |||
| 3576 | || currentBit > bodyEndBit | |||
| 3577 | || graphBits > bodyEndBit - currentBit | |||
| 3578 | || graphDataSize > static_cast<std::uint64_t>(buf->numRemainingBytes()) | |||
| 3579 | || graphDataSize > maxMoveBytes) { | |||
| 3580 | DRW_DBG("graphData size outside object body\n")DRW_dbg::dbg("graphData size outside object body\n"); | |||
| 3581 | return false; | |||
| 3582 | } | |||
| 3583 | // Capture the proxy-graphics byte stream instead of skipping it. These | |||
| 3584 | // are cached drawable primitives (lines/arcs/polylines/text) that any | |||
| 3585 | // reader can render for proxy/custom entities (STDPART2D, AEC_*, tables) | |||
| 3586 | // — previously discarded via moveBitPos, leaving proxyGraphics empty. | |||
| 3587 | // dwgBuffer::getBytes is bit-aware (reconstructs each byte at a non-zero | |||
| 3588 | // bitPos), so it lands at the exact same position moveBitPos(8N) did. | |||
| 3589 | // (write-review #32 / read-coverage gap #1) | |||
| 3590 | if (graphDataSize > 0) { | |||
| 3591 | if (!DRW::resize(proxyGraphics, static_cast<int>(graphDataSize))) | |||
| 3592 | return false; | |||
| 3593 | if (!readBoundedBytes( | |||
| 3594 | *buf, bodyEndBit, | |||
| 3595 | reinterpret_cast<std::uint8_t*>(&proxyGraphics[0]), | |||
| 3596 | static_cast<std::size_t>(graphDataSize))) | |||
| 3597 | return false; | |||
| 3598 | numProxyGraph = static_cast<int>(graphDataSize); | |||
| 3599 | } | |||
| 3600 | } | |||
| 3601 | if (version < DRW::AC1015) {//14- | |||
| 3602 | std::uint32_t parsedObjectSize = 0; | |||
| 3603 | if (!readBoundedRawLong32(*buf, proxyEntityEndBit(*buf, 0), | |||
| 3604 | parsedObjectSize)) | |||
| 3605 | return false; | |||
| 3606 | objSize = parsedObjectSize; //RL 32bits object size in bits | |||
| 3607 | 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"); | |||
| 3608 | bodyEndBit = proxyEntityEndBit(*buf, objSize); | |||
| 3609 | } | |||
| 3610 | ||||
| 3611 | std::uint8_t entmode = 0; | |||
| 3612 | if (!readBounded2Bits(*buf, bodyEndBit, entmode)) | |||
| 3613 | return false; | |||
| 3614 | if (entmode == 0) | |||
| 3615 | ownerHandle= true; | |||
| 3616 | // entmode = 2; | |||
| 3617 | else if(entmode ==2) | |||
| 3618 | entmode = 0; | |||
| 3619 | space = (DRW::Space)entmode; //RLZ verify cast values | |||
| 3620 | DRW_DBG("entmode: ")DRW_dbg::dbg("entmode: "); DRW_DBG(entmode)DRW_dbg::dbg(entmode); | |||
| 3621 | if (!readBoundedBitLong(*buf, bodyEndBit, numReactors)) | |||
| 3622 | return false; //BL per spec §20.4.1 | |||
| 3623 | DRW_DBG(", numReactors: ")DRW_dbg::dbg(", numReactors: "); DRW_DBG(numReactors)DRW_dbg::dbg(numReactors); | |||
| 3624 | if (!buf->isGood() || !dwgSafety::validReactorCount(numReactors)) | |||
| 3625 | return false; | |||
| 3626 | ||||
| 3627 | if (version < DRW::AC1015) {//14- | |||
| 3628 | bool isByLayer = false; | |||
| 3629 | if (!readBoundedBit(*buf, bodyEndBit, isByLayer)) | |||
| 3630 | return false; | |||
| 3631 | if (isByLayer) {//is bylayer line type | |||
| 3632 | lineType = "BYLAYER"; | |||
| 3633 | ltFlags = 0; | |||
| 3634 | } else { | |||
| 3635 | lineType = ""; | |||
| 3636 | ltFlags = 3; | |||
| 3637 | } | |||
| 3638 | DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str()); | |||
| 3639 | DRW_DBG(" ltFlags: ")DRW_dbg::dbg(" ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags); | |||
| 3640 | } | |||
| 3641 | if (version > DRW::AC1015) {//2004+ | |||
| 3642 | bool xDict = false; | |||
| 3643 | if (!readBoundedBit(*buf, bodyEndBit, xDict)) | |||
| 3644 | return false; | |||
| 3645 | xDictFlag = xDict; | |||
| 3646 | DRW_DBG(" xDictFlag: ")DRW_dbg::dbg(" xDictFlag: "); DRW_DBG(xDictFlag)DRW_dbg::dbg(xDictFlag); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3647 | } | |||
| 3648 | ||||
| 3649 | // libreDWG common_entity_data.spec — the bit at this stream position has two | |||
| 3650 | // disjoint meanings by version: | |||
| 3651 | // * R13..R2002 (version < AC1018): `nolinks` (B). 1 = no prev/next handles | |||
| 3652 | // in the handle section; 0 = read prev+next at parseDwgEntHandle. | |||
| 3653 | // * R2004..R2010 (AC1018..AC1024): NO bit in the stream — reader forces | |||
| 3654 | // haveNextLinks=1 to skip the prev/next handle reads. | |||
| 3655 | // * R2013+ (version > AC1024): `has_ds_data` (B). 1 = inline ACIS SAB | |||
| 3656 | // datastore present. Stored separately because it gates SAB handling, | |||
| 3657 | // not prev/next links (which are already version<AC1018 gated). | |||
| 3658 | // Total bit consumption is unchanged for every version. | |||
| 3659 | if (version < DRW::AC1018) { | |||
| 3660 | bool parsedHaveNextLinks = false; | |||
| 3661 | if (!readBoundedBit(*buf, bodyEndBit, parsedHaveNextLinks)) | |||
| 3662 | return false; //nolinks //B | |||
| 3663 | haveNextLinks = parsedHaveNextLinks ? 1 : 0; | |||
| 3664 | 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"); | |||
| 3665 | } else { | |||
| 3666 | haveNextLinks = 1; //AC1018+: not in stream, force 1 (no prev/next) | |||
| 3667 | DRW_DBG(", haveNextLinks (forced): ")DRW_dbg::dbg(", haveNextLinks (forced): "); DRW_DBG(haveNextLinks)DRW_dbg::dbg(haveNextLinks); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3668 | } | |||
| 3669 | if (version > DRW::AC1024) { | |||
| 3670 | bool parsedHasDsData = false; | |||
| 3671 | if (!readBoundedBit(*buf, bodyEndBit, parsedHasDsData)) | |||
| 3672 | return false; //has_ds_data //B (R2013+) | |||
| 3673 | hasDsData = parsedHasDsData ? 1 : 0; | |||
| 3674 | DRW_DBG(", hasDsData (R2013+): ")DRW_dbg::dbg(", hasDsData (R2013+): "); DRW_DBG(hasDsData)DRW_dbg::dbg(hasDsData); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3675 | } | |||
| 3676 | //ENC color | |||
| 3677 | std::uint32_t parsedColor = 0; | |||
| 3678 | if (!readBoundedEnColor(*buf, bodyEndBit, version, parsedColor)) | |||
| 3679 | return false; //BS or CMC //ok for R14 or negate | |||
| 3680 | color = static_cast<int>(parsedColor); | |||
| 3681 | // Capture the AcDbColor side-channel before the common handle stream. | |||
| 3682 | // The handle follows owner/reactors/xdictionary and precedes layer in the | |||
| 3683 | // R2004+ common entity handle data. | |||
| 3684 | hasAcDbColorH = buf->lastEnColorHadDbColorRef; | |||
| 3685 | // libreDWG common_entity_data.spec:432-453 — ENC alpha_raw (DXF code | |||
| 3686 | // 440) is encoded as (alpha_type<<24) | alpha. Stored verbatim; the | |||
| 3687 | // filter (RS_FilterDXFRW::setEntityAttributes) decodes alpha_type==3 | |||
| 3688 | // into a per-entity pen alpha, otherwise inherits from layer/block. | |||
| 3689 | if (buf->lastEnColorAlphaRaw != 0) { | |||
| 3690 | transparency = static_cast<int>(buf->lastEnColorAlphaRaw); | |||
| 3691 | } | |||
| 3692 | // libreDWG common_entity_data.spec:468-475 — inline TV name/book name | |||
| 3693 | // (flags 0x41/0x42) override any dbColorMap-resolved name. Captured | |||
| 3694 | // immediately; entryParse will skip the override only if colorName is | |||
| 3695 | // already populated here. | |||
| 3696 | if (!buf->lastEnColorName.empty()) { | |||
| 3697 | colorName = buf->lastEnColorBookName.empty() | |||
| 3698 | ? buf->lastEnColorName | |||
| 3699 | : (buf->lastEnColorBookName + "$" + buf->lastEnColorName); | |||
| 3700 | } | |||
| 3701 | color24 = buf->lastEnColorRgb; | |||
| 3702 | if (!readBoundedBitDouble(*buf, bodyEndBit, ltypeScale)) | |||
| 3703 | return false; //BD | |||
| 3704 | DRW_DBG(" entity color: ")DRW_dbg::dbg(" entity color: "); DRW_DBG(color)DRW_dbg::dbg(color); | |||
| 3705 | DRW_DBG(" ltScale: ")DRW_dbg::dbg(" ltScale: "); DRW_DBG(ltypeScale)DRW_dbg::dbg(ltypeScale); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3706 | if (version > DRW::AC1014) {//2000+ — §19.4.1: linetype-flags BB then plot-flags BB | |||
| 3707 | std::uint8_t parsedLtFlags = 0; | |||
| 3708 | if (!readBounded2Bits(*buf, bodyEndBit, parsedLtFlags)) | |||
| 3709 | return false; //BB | |||
| 3710 | ltFlags = parsedLtFlags; | |||
| 3711 | if (ltFlags == 0) lineType = "BYLAYER"; | |||
| 3712 | else if (ltFlags == 1) lineType = "BYBLOCK"; | |||
| 3713 | else if (ltFlags == 2) lineType = "CONTINUOUS"; | |||
| 3714 | else lineType = ""; //3 → handle at end | |||
| 3715 | DRW_DBG("ltFlags: ")DRW_dbg::dbg("ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags); | |||
| 3716 | DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str()); | |||
| 3717 | ||||
| 3718 | std::uint8_t parsedPlotFlags = 0; | |||
| 3719 | if (!readBounded2Bits(*buf, bodyEndBit, parsedPlotFlags)) | |||
| 3720 | return false; //BB | |||
| 3721 | plotFlags = parsedPlotFlags; | |||
| 3722 | DRW_DBG(", plotFlags: ")DRW_dbg::dbg(", plotFlags: "); DRW_DBG(plotFlags)DRW_dbg::dbg(plotFlags); | |||
| 3723 | } | |||
| 3724 | if (version > DRW::AC1018) {//2007+ | |||
| 3725 | std::uint8_t parsedMaterialFlag = 0; | |||
| 3726 | if (!readBounded2Bits(*buf, bodyEndBit, parsedMaterialFlag)) | |||
| 3727 | return false; //BB | |||
| 3728 | materialFlag = parsedMaterialFlag; | |||
| 3729 | DRW_DBG("materialFlag: ")DRW_dbg::dbg("materialFlag: "); DRW_DBG(materialFlag)DRW_dbg::dbg(materialFlag); | |||
| 3730 | std::uint8_t parsedShadowFlag = 0; | |||
| 3731 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedShadowFlag)) | |||
| 3732 | return false; //RC, low 2 bits is shadow mode 0..3 | |||
| 3733 | shadowFlag = parsedShadowFlag; | |||
| 3734 | DRW_DBG("shadowFlag: ")DRW_dbg::dbg("shadowFlag: "); DRW_DBG(shadowFlag)DRW_dbg::dbg(shadowFlag); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3735 | shadow = static_cast<DRW::ShadowMode>(shadowFlag & 0x3); | |||
| 3736 | } | |||
| 3737 | if (version > DRW::AC1021) {//2010+ — §19.4.1: three single-bit flags | |||
| 3738 | // Ground-truth: libreDWG common_entity_data.spec lines 523-528 | |||
| 3739 | // and ODA spec v5.4.1 §19.4.1 both define three FIELD_B (single bit) | |||
| 3740 | // flags here, one each for full/face/edge visual style. Total bit | |||
| 3741 | // consumption (3 bits) is identical to the historical BB+B shape; | |||
| 3742 | // only the semantics differ. The corresponding handles are read | |||
| 3743 | // conditionally in parseDwgEntHandle after the plotstyle handle. | |||
| 3744 | bool parsedHasFullVisualStyle = false; | |||
| 3745 | bool parsedHasFaceVisualStyle = false; | |||
| 3746 | bool parsedHasEdgeVisualStyle = false; | |||
| 3747 | if (!readBoundedBit(*buf, bodyEndBit, parsedHasFullVisualStyle) | |||
| 3748 | || !readBoundedBit(*buf, bodyEndBit, parsedHasFaceVisualStyle) | |||
| 3749 | || !readBoundedBit(*buf, bodyEndBit, parsedHasEdgeVisualStyle)) | |||
| 3750 | return false; //B | |||
| 3751 | hasFullVisualStyle = parsedHasFullVisualStyle ? 1 : 0; | |||
| 3752 | hasFaceVisualStyle = parsedHasFaceVisualStyle ? 1 : 0; | |||
| 3753 | hasEdgeVisualStyle = parsedHasEdgeVisualStyle ? 1 : 0; | |||
| 3754 | DRW_DBG("hasFull/Face/Edge VisualStyle: ")DRW_dbg::dbg("hasFull/Face/Edge VisualStyle: "); | |||
| 3755 | DRW_DBG(hasFullVisualStyle)DRW_dbg::dbg(hasFullVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" "); | |||
| 3756 | DRW_DBG(hasFaceVisualStyle)DRW_dbg::dbg(hasFaceVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" "); | |||
| 3757 | DRW_DBG(hasEdgeVisualStyle)DRW_dbg::dbg(hasEdgeVisualStyle); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3758 | } | |||
| 3759 | std::uint16_t parsedInvisibleFlag = 0; | |||
| 3760 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedInvisibleFlag)) | |||
| 3761 | return false; //BS | |||
| 3762 | const std::int16_t invisibleFlag = | |||
| 3763 | static_cast<std::int16_t>(parsedInvisibleFlag); | |||
| 3764 | DRW_DBG(" invisibleFlag: ")DRW_dbg::dbg(" invisibleFlag: "); DRW_DBG(invisibleFlag)DRW_dbg::dbg(invisibleFlag); | |||
| 3765 | // DXF group 60: bit 0 = invisible (1) / visible (0). libreDWG | |||
| 3766 | // common_entity_data.spec masks bit 0 only (`invisible & 1`) and ignores | |||
| 3767 | // the higher bits, so use the same mask rather than `== 0`. Paired with | |||
| 3768 | // the encode emit below. | |||
| 3769 | visible = ((invisibleFlag & 1) == 0); | |||
| 3770 | if (version > DRW::AC1014) {//2000+ | |||
| 3771 | std::uint8_t parsedLineWeight = 0; | |||
| 3772 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedLineWeight)) | |||
| 3773 | return false; //RC | |||
| 3774 | lWeight = DRW_LW_Conv::dwgInt2lineWidth(parsedLineWeight); | |||
| 3775 | DRW_DBG(" lwFlag (lWeight): ")DRW_dbg::dbg(" lwFlag (lWeight): "); DRW_DBG(lWeight)DRW_dbg::dbg(lWeight); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3776 | } | |||
| 3777 | //Only in blocks ???????? | |||
| 3778 | // if (version > DRW::AC1018) {//2007+ | |||
| 3779 | // std::uint8_t unk = buf->getBit(); | |||
| 3780 | // DRW_DBG("unknown bit: "); DRW_DBG(unk); DRW_DBG("\n"); | |||
| 3781 | // } | |||
| 3782 | if (!buf->isGood() || !bodyWithinBounds()) | |||
| 3783 | return false; | |||
| 3784 | ||||
| 3785 | const std::size_t oldExtDataSize = extData.size(); | |||
| 3786 | const std::size_t oldAppResolutionSize = | |||
| 3787 | pendingAppIdResolutions.size(); | |||
| 3788 | const std::size_t oldLayerResolutionSize = | |||
| 3789 | pendingLayerRefResolutions.size(); | |||
| 3790 | const auto rollbackEed = [this, oldExtDataSize, | |||
| 3791 | oldAppResolutionSize, oldLayerResolutionSize]() { | |||
| 3792 | extData.resize(oldExtDataSize); | |||
| 3793 | pendingAppIdResolutions.resize(oldAppResolutionSize); | |||
| 3794 | pendingLayerRefResolutions.resize(oldLayerResolutionSize); | |||
| 3795 | }; | |||
| 3796 | if (parsedExtData.size() > DRW_TableEntry::kMaxExtendedDataItems | |||
| 3797 | || extData.size() > DRW_TableEntry::kMaxExtendedDataItems | |||
| 3798 | || parsedExtData.size() | |||
| 3799 | > DRW_TableEntry::kMaxExtendedDataItems - extData.size()) | |||
| 3800 | return false; | |||
| 3801 | try { | |||
| 3802 | extData.insert(extData.end(), parsedExtData.begin(), | |||
| 3803 | parsedExtData.end()); | |||
| 3804 | pendingAppIdResolutions.insert( | |||
| 3805 | pendingAppIdResolutions.end(), parsedAppIdResolutions.begin(), | |||
| 3806 | parsedAppIdResolutions.end()); | |||
| 3807 | pendingLayerRefResolutions.insert( | |||
| 3808 | pendingLayerRefResolutions.end(), | |||
| 3809 | parsedLayerRefResolutions.begin(), parsedLayerRefResolutions.end()); | |||
| 3810 | } catch (...) { | |||
| 3811 | rollbackEed(); | |||
| 3812 | return false; | |||
| 3813 | } | |||
| 3814 | return true; | |||
| 3815 | } | |||
| 3816 | ||||
| 3817 | bool DRW_Entity::parseDwgEntHandle( | |||
| 3818 | DRW::Version version, dwgBuffer *buf, bool resetHandleStream, | |||
| 3819 | std::uint64_t handleEndBit){ | |||
| 3820 | if (buf == nullptr || !buf->isGood() | |||
| 3821 | || !dwgSafety::validReactorCount(numReactors)) | |||
| 3822 | return false; | |||
| 3823 | if (resetHandleStream && version > DRW::AC1018) {//2007+ skip string area | |||
| 3824 | if (!buf->setPosition(objSize >> 3)) | |||
| 3825 | return false; | |||
| 3826 | buf->setBitPos(objSize & 7); | |||
| 3827 | if (!buf->isGood()) | |||
| 3828 | return false; | |||
| 3829 | } | |||
| 3830 | if (handleEndBit != std::numeric_limits<std::uint64_t>::max() | |||
| 3831 | && currentDwgBit(buf) > handleEndBit) | |||
| 3832 | return false; | |||
| 3833 | ||||
| 3834 | std::uint32_t newAcDbColorHandle = acDbColorHandle; | |||
| 3835 | std::uint32_t newParentHandle = ownerHandle ? parentHandle : DRW::NoHandle; | |||
| 3836 | std::vector<std::uint32_t> newReactorHandles; | |||
| 3837 | const bool hasXDictionary = version <= DRW::AC1015 || xDictFlag != 1; | |||
| 3838 | std::uint32_t newXDictHandle = hasXDictionary ? xDictHandle : 0; | |||
| 3839 | dwgHandle newLayerH = layerH; | |||
| 3840 | dwgHandle newLTypeH = lTypeH; | |||
| 3841 | std::uint32_t newNextEntLink = nextEntLink; | |||
| 3842 | std::uint32_t newPrevEntLink = prevEntLink; | |||
| 3843 | const DRW::ShadowMode newShadow = version > DRW::AC1018 | |||
| 3844 | ? shadow : DRW::CastAndReceieveShadows; | |||
| 3845 | std::uint32_t newMaterial = materialFlag == 3 ? material | |||
| 3846 | : DRW::MaterialByLayer; | |||
| 3847 | int newPlotStyle = plotFlags == 3 ? plotStyle | |||
| 3848 | : DRW::DefaultPlotStyle; | |||
| 3849 | std::uint32_t newShadowHandle = shadowFlag == 3 ? shadowHandle : 0; | |||
| 3850 | std::uint32_t newFullVisualStyleHandle = hasFullVisualStyle | |||
| 3851 | ? fullVisualStyleHandle : 0; | |||
| 3852 | std::uint32_t newFaceVisualStyleHandle = hasFaceVisualStyle | |||
| 3853 | ? faceVisualStyleHandle : 0; | |||
| 3854 | std::uint32_t newEdgeVisualStyleHandle = hasEdgeVisualStyle | |||
| 3855 | ? edgeVisualStyleHandle : 0; | |||
| 3856 | if (version <= DRW::AC1018) { | |||
| 3857 | newMaterial = DRW::MaterialByLayer; | |||
| 3858 | newShadowHandle = 0; | |||
| 3859 | } | |||
| 3860 | if (version <= DRW::AC1021) { | |||
| 3861 | newFullVisualStyleHandle = 0; | |||
| 3862 | newFaceVisualStyleHandle = 0; | |||
| 3863 | newEdgeVisualStyleHandle = 0; | |||
| 3864 | } | |||
| 3865 | auto readOffsetHandle = [&](dwgHandle& out) { | |||
| 3866 | return handleEndBit == std::numeric_limits<std::uint64_t>::max() | |||
| 3867 | ? readDwgHandleChecked(*buf, handle, true, out) | |||
| 3868 | : readBoundedDwgHandle(*buf, handleEndBit, handle, true, out); | |||
| 3869 | }; | |||
| 3870 | auto readRawHandle = [&](dwgHandle& out) { | |||
| 3871 | return handleEndBit == std::numeric_limits<std::uint64_t>::max() | |||
| 3872 | ? readDwgHandleChecked(*buf, handle, false, out) | |||
| 3873 | : readBoundedDwgHandle(*buf, handleEndBit, handle, false, out); | |||
| 3874 | }; | |||
| 3875 | auto readHandleList = [&]() { | |||
| 3876 | if (handleEndBit == std::numeric_limits<std::uint64_t>::max()) | |||
| 3877 | return readDwgHandleList(*buf, handle, numReactors, false, | |||
| 3878 | &newReactorHandles); | |||
| 3879 | if (!dwgSafety::validReactorCount(numReactors)) | |||
| 3880 | return false; | |||
| 3881 | std::vector<std::uint32_t> parsed; | |||
| 3882 | if (!DRW::reserve(parsed, numReactors)) | |||
| 3883 | return false; | |||
| 3884 | for (std::int32_t i = 0; i < numReactors; ++i) { | |||
| 3885 | dwgHandle reactor; | |||
| 3886 | if (!readBoundedDwgHandle(*buf, handleEndBit, handle, false, | |||
| 3887 | reactor)) | |||
| 3888 | return false; | |||
| 3889 | parsed.push_back(reactor.ref); | |||
| 3890 | } | |||
| 3891 | newReactorHandles = std::move(parsed); | |||
| 3892 | return true; | |||
| 3893 | }; | |||
| 3894 | ||||
| 3895 | if(ownerHandle){//entity are in block or in a polyline | |||
| 3896 | dwgHandle ownerH; | |||
| 3897 | if (!readOffsetHandle(ownerH)) | |||
| 3898 | return false; | |||
| 3899 | 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"); | |||
| 3900 | 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"); | |||
| 3901 | newParentHandle = ownerH.ref; | |||
| 3902 | 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"); | |||
| 3903 | } else | |||
| 3904 | DRW_DBG("NO Block (parent) Handle\n")DRW_dbg::dbg("NO Block (parent) Handle\n"); | |||
| 3905 | ||||
| 3906 | 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"); | |||
| 3907 | if (!readHandleList()) | |||
| 3908 | return false; | |||
| 3909 | if (xDictFlag !=1){//linetype in 2004 seems not have XDicObjH or NULL handle | |||
| 3910 | dwgHandle XDicObjH; | |||
| 3911 | if (!readRawHandle(XDicObjH)) | |||
| 3912 | return false; | |||
| 3913 | newXDictHandle = XDicObjH.ref; // 2a.2: persist xdict | |||
| 3914 | 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"); | |||
| 3915 | } | |||
| 3916 | 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"); | |||
| 3917 | ||||
| 3918 | // ENC's optional AcDbColor reference follows the common owner, reactor, | |||
| 3919 | // and xdictionary handles in R2004+ files. The dwgReader resolves this | |||
| 3920 | // handle against dbColorMap after parsing the complete entity. | |||
| 3921 | if (hasAcDbColorH && version > DRW::AC1015) { | |||
| 3922 | dwgHandle dbcH; | |||
| 3923 | if (!readOffsetHandle(dbcH)) | |||
| 3924 | return false; | |||
| 3925 | newAcDbColorHandle = dbcH.ref; | |||
| 3926 | DRW_DBG(" AcDbColor Handle: ")DRW_dbg::dbg(" AcDbColor Handle: "); | |||
| 3927 | DRW_DBGHL(dbcH.code, dbcH.size, dbcH.ref)DRW_dbg::dbgHL(dbcH.code, dbcH.size, dbcH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3928 | } | |||
| 3929 | ||||
| 3930 | if (version < DRW::AC1015) {//R14- | |||
| 3931 | //layer handle | |||
| 3932 | if (!readOffsetHandle(newLayerH)) | |||
| 3933 | return false; | |||
| 3934 | 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"); | |||
| 3935 | 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"); | |||
| 3936 | //lineType handle | |||
| 3937 | if(ltFlags == 3){ | |||
| 3938 | if (!readOffsetHandle(newLTypeH)) | |||
| 3939 | return false; | |||
| 3940 | 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"); | |||
| 3941 | 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"); | |||
| 3942 | } | |||
| 3943 | } | |||
| 3944 | if (version < DRW::AC1018) {//2000+ | |||
| 3945 | if (haveNextLinks == 0) { | |||
| 3946 | dwgHandle nextLinkH; | |||
| 3947 | if (!readOffsetHandle(nextLinkH)) | |||
| 3948 | return false; | |||
| 3949 | 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"); | |||
| 3950 | 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"); | |||
| 3951 | const std::uint32_t prevLink = nextLinkH.ref; | |||
| 3952 | if (!readOffsetHandle(nextLinkH)) | |||
| 3953 | return false; | |||
| 3954 | 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"); | |||
| 3955 | 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"); | |||
| 3956 | newPrevEntLink = prevLink; | |||
| 3957 | newNextEntLink = nextLinkH.ref; | |||
| 3958 | } else { | |||
| 3959 | if (handle == 0 || handle == std::numeric_limits<std::uint32_t>::max()) | |||
| 3960 | return false; | |||
| 3961 | newNextEntLink = handle + 1; | |||
| 3962 | newPrevEntLink = handle - 1; | |||
| 3963 | } | |||
| 3964 | } | |||
| 3965 | if (version > DRW::AC1015) {//2004+ | |||
| 3966 | //Parses Bookcolor handle | |||
| 3967 | } | |||
| 3968 | if (version > DRW::AC1014) {//2000+ | |||
| 3969 | //layer handle | |||
| 3970 | if (!readOffsetHandle(newLayerH)) | |||
| 3971 | return false; | |||
| 3972 | 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"); | |||
| 3973 | 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"); | |||
| 3974 | //lineType handle | |||
| 3975 | if(ltFlags == 3){ | |||
| 3976 | if (!readOffsetHandle(newLTypeH)) | |||
| 3977 | return false; | |||
| 3978 | 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"); | |||
| 3979 | 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"); | |||
| 3980 | } | |||
| 3981 | } | |||
| 3982 | if (version > DRW::AC1014) {//2000+ | |||
| 3983 | if (version > DRW::AC1018) {//2007+ | |||
| 3984 | if (materialFlag == 3) { | |||
| 3985 | dwgHandle materialH; | |||
| 3986 | if (!readOffsetHandle(materialH)) | |||
| 3987 | return false; | |||
| 3988 | newMaterial = materialH.ref; | |||
| 3989 | 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"); | |||
| 3990 | 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"); | |||
| 3991 | } | |||
| 3992 | if (shadowFlag == 3) { | |||
| 3993 | // AcDbShadow object handle is separate from the mode encoded | |||
| 3994 | // in shadowFlag. Keep it even though LibreCAD has no render | |||
| 3995 | // consumer for the shadow object itself. | |||
| 3996 | dwgHandle shadowH; | |||
| 3997 | if (!readOffsetHandle(shadowH)) | |||
| 3998 | return false; | |||
| 3999 | newShadowHandle = shadowH.ref; | |||
| 4000 | 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"); | |||
| 4001 | 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"); | |||
| 4002 | } | |||
| 4003 | } | |||
| 4004 | if (plotFlags == 3) { | |||
| 4005 | dwgHandle plotStyleH; | |||
| 4006 | if (!readOffsetHandle(plotStyleH)) | |||
| 4007 | return false; | |||
| 4008 | newPlotStyle = static_cast<int>(plotStyleH.ref); | |||
| 4009 | 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"); | |||
| 4010 | 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"); | |||
| 4011 | } | |||
| 4012 | if (version > DRW::AC1021) {//2010+ — §19.4.2: visual-style handles | |||
| 4013 | // Ground-truth: libreDWG common_entity_handle_data.spec lines | |||
| 4014 | // 141-150 and ODA spec v5.4.1 §19.4.2. Order matches: full, | |||
| 4015 | // face, edge — each conditional on its single-bit flag from | |||
| 4016 | // §19.4.1 (set in parseDwg above). All three are hard pointers | |||
| 4017 | // (libreDWG FIELD_HANDLE code 5), matching the existing | |||
| 4018 | // material/shadow/plotstyle handles in this block. | |||
| 4019 | if (hasFullVisualStyle) { | |||
| 4020 | dwgHandle h; | |||
| 4021 | if (!readOffsetHandle(h)) | |||
| 4022 | return false; | |||
| 4023 | newFullVisualStyleHandle = h.ref; | |||
| 4024 | DRW_DBG(" full visual-style H: ")DRW_dbg::dbg(" full visual-style H: "); | |||
| 4025 | DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 4026 | } | |||
| 4027 | if (hasFaceVisualStyle) { | |||
| 4028 | dwgHandle h; | |||
| 4029 | if (!readOffsetHandle(h)) | |||
| 4030 | return false; | |||
| 4031 | newFaceVisualStyleHandle = h.ref; | |||
| 4032 | DRW_DBG(" face visual-style H: ")DRW_dbg::dbg(" face visual-style H: "); | |||
| 4033 | DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 4034 | } | |||
| 4035 | if (hasEdgeVisualStyle) { | |||
| 4036 | dwgHandle h; | |||
| 4037 | if (!readOffsetHandle(h)) | |||
| 4038 | return false; | |||
| 4039 | newEdgeVisualStyleHandle = h.ref; | |||
| 4040 | DRW_DBG(" edge visual-style H: ")DRW_dbg::dbg(" edge visual-style H: "); | |||
| 4041 | DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 4042 | } | |||
| 4043 | } | |||
| 4044 | } | |||
| 4045 | const int rb = buf->numRemainingBytes(); | |||
| 4046 | 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"); | |||
| 4047 | if (rb > 4) { // 2-byte CRC + slack | |||
| 4048 | DRW_DBG("\n*** parseDwgEntHandle leftover ")DRW_dbg::dbg("\n*** parseDwgEntHandle leftover "); | |||
| 4049 | DRW_DBG(rb)DRW_dbg::dbg(rb); | |||
| 4050 | DRW_DBG(" bytes; entity handle ")DRW_dbg::dbg(" bytes; entity handle "); | |||
| 4051 | DRW_DBGH(handle)DRW_dbg::dbgH(handle); | |||
| 4052 | DRW_DBG(" oType ")DRW_dbg::dbg(" oType "); | |||
| 4053 | DRW_DBG(oType)DRW_dbg::dbg(oType); | |||
| 4054 | DRW_DBG(" — possible bit-stream misalignment ***\n")DRW_dbg::dbg(" — possible bit-stream misalignment ***\n"); | |||
| 4055 | } | |||
| 4056 | if (!buf->isGood() | |||
| 4057 | || (handleEndBit != std::numeric_limits<std::uint64_t>::max() | |||
| 4058 | && currentDwgBit(buf) > handleEndBit)) | |||
| 4059 | return false; | |||
| 4060 | ||||
| 4061 | acDbColorHandle = newAcDbColorHandle; | |||
| 4062 | parentHandle = newParentHandle; | |||
| 4063 | reactorHandles = std::move(newReactorHandles); | |||
| 4064 | xDictHandle = newXDictHandle; | |||
| 4065 | layerH = newLayerH; | |||
| 4066 | lTypeH = newLTypeH; | |||
| 4067 | nextEntLink = newNextEntLink; | |||
| 4068 | prevEntLink = newPrevEntLink; | |||
| 4069 | material = newMaterial; | |||
| 4070 | plotStyle = newPlotStyle; | |||
| 4071 | shadow = newShadow; | |||
| 4072 | if (version <= DRW::AC1018) { | |||
| 4073 | materialFlag = 0; | |||
| 4074 | shadowFlag = 0; | |||
| 4075 | } | |||
| 4076 | shadowHandle = newShadowHandle; | |||
| 4077 | if (version <= DRW::AC1021) { | |||
| 4078 | hasFullVisualStyle = false; | |||
| 4079 | hasFaceVisualStyle = false; | |||
| 4080 | hasEdgeVisualStyle = false; | |||
| 4081 | } | |||
| 4082 | fullVisualStyleHandle = newFullVisualStyleHandle; | |||
| 4083 | faceVisualStyleHandle = newFaceVisualStyleHandle; | |||
| 4084 | edgeVisualStyleHandle = newEdgeVisualStyleHandle; | |||
| 4085 | // R2007+ separates this tail from the object data stream. Earlier typed | |||
| 4086 | // parsers may consume inline handles but cannot give raw metadata an | |||
| 4087 | // independently bounded common-link proof. | |||
| 4088 | commonLinkTailValidated = version > DRW::AC1018; | |||
| 4089 | return true; | |||
| 4090 | } | |||
| 4091 | ||||
| 4092 | bool DRW_Entity::parseDwgCommon(DRW::Version version, dwgBuffer *buf, | |||
| 4093 | std::uint32_t bs) { | |||
| 4094 | if (buf == nullptr) | |||
| 4095 | return false; | |||
| 4096 | // R2007 (AC1021) omits the footer when an object has no string stream; | |||
| 4097 | // the concrete readers using this helper have no detached text fields. | |||
| 4098 | if (version <= DRW::AC1021) | |||
| 4099 | return parseDwg(version, buf, nullptr, bs); | |||
| 4100 | ||||
| 4101 | // Keep the publishing cursor transactional: a missing string footer is | |||
| 4102 | // legal for body-only R2007-era inputs and for the low-level entity test | |||
| 4103 | // API, but must not leave the cursor half-consumed before that fallback. | |||
| 4104 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 4105 | dwgBuffer stringProbe = bodyProbe.forkIndependent(); | |||
| 4106 | if (parseDwg(version, &bodyProbe, &stringProbe, bs)) { | |||
| 4107 | *buf = bodyProbe; | |||
| 4108 | return true; | |||
| 4109 | } | |||
| 4110 | return parseDwg(version, buf, nullptr, bs); | |||
| 4111 | } | |||
| 4112 | ||||
| 4113 | bool DRW_ProxyEntity::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 4114 | std::uint32_t bs) { | |||
| 4115 | if (buf == nullptr || version < DRW::AC1012) | |||
| 4116 | return false; | |||
| 4117 | ||||
| 4118 | DRW_Entity::reset(); | |||
| 4119 | eType = DRW::PROXYENTITY; | |||
| 4120 | m_hasProxyClassId = false; | |||
| 4121 | m_proxyClassId = 0; | |||
| 4122 | m_hasProxyCarrierId = false; | |||
| 4123 | m_proxyCarrierId = 0; | |||
| 4124 | m_proxySubclass.clear(); | |||
| 4125 | m_hasProxyDrawingFormat = false; | |||
| 4126 | m_proxyDrawingFormat = 0; | |||
| 4127 | m_proxyDwgVersion = 0; | |||
| 4128 | m_proxyMaintenanceVersion = 0; | |||
| 4129 | m_hasFromDxf = false; | |||
| 4130 | m_fromDxf = false; | |||
| 4131 | m_hasProxyGraphicsByteSize = false; | |||
| 4132 | m_proxyGraphicsByteSize = 0; | |||
| 4133 | m_hasEntityDataBitSize = false; | |||
| 4134 | m_entityData.clear(); | |||
| 4135 | m_entityDataBitSize = 0; | |||
| 4136 | m_hasUnknownDataByteSize = false; | |||
| 4137 | m_unknownDataByteSize = 0; | |||
| 4138 | m_unknownData.clear(); | |||
| 4139 | m_objectIdRefs.clear(); | |||
| 4140 | ||||
| 4141 | dwgBuffer stringBuffer = *buf; | |||
| 4142 | dwgBuffer *stringBuf = version > DRW::AC1018 ? &stringBuffer : buf; | |||
| 4143 | if (!DRW_Entity::parseDwg(version, buf, stringBuf, bs)) | |||
| 4144 | return false; | |||
| 4145 | ||||
| 4146 | std::uint64_t dataEndBit = 0; | |||
| 4147 | std::uint64_t stringEndBit = 0; | |||
| 4148 | if (!entityBodyDataEndBit(*stringBuf, version, objSize, dataEndBit, | |||
| 4149 | &stringEndBit) | |||
| 4150 | || dataEndBit > proxyEntityEndBit(*buf, 0)) | |||
| 4151 | return false; | |||
| 4152 | ||||
| 4153 | bool present = false; | |||
| 4154 | std::int32_t value = 0; | |||
| 4155 | if (!readProxyEntityOptionalBitLong(*buf, dataEndBit, present, value)) | |||
| 4156 | return false; | |||
| 4157 | if (present) { | |||
| 4158 | m_hasProxyCarrierId = true; | |||
| 4159 | m_proxyCarrierId = value; | |||
| 4160 | } | |||
| 4161 | ||||
| 4162 | if (version >= DRW::AC1018 | |||
| 4163 | && proxyEntityHasBits(*stringBuf, stringEndBit, 2)) { | |||
| 4164 | if (!readBoundedVariableText(*stringBuf, stringEndBit, version, | |||
| 4165 | m_proxySubclass)) | |||
| 4166 | return false; | |||
| 4167 | } | |||
| 4168 | ||||
| 4169 | if (version >= DRW::AC1032) { | |||
| 4170 | bool hasDwgVersion = false; | |||
| 4171 | bool hasMaintenanceVersion = false; | |||
| 4172 | std::int32_t dwgVersion = 0; | |||
| 4173 | std::int32_t maintenanceVersion = 0; | |||
| 4174 | if (!readProxyEntityOptionalBitLong(*buf, dataEndBit, | |||
| 4175 | hasDwgVersion, dwgVersion) | |||
| 4176 | || !readProxyEntityOptionalBitLong(*buf, dataEndBit, | |||
| 4177 | hasMaintenanceVersion, | |||
| 4178 | maintenanceVersion)) { | |||
| 4179 | return false; | |||
| 4180 | } | |||
| 4181 | if (hasDwgVersion || hasMaintenanceVersion) { | |||
| 4182 | m_hasProxyDrawingFormat = true; | |||
| 4183 | m_proxyDwgVersion = static_cast<std::uint16_t>(dwgVersion); | |||
| 4184 | m_proxyMaintenanceVersion = | |||
| 4185 | static_cast<std::uint16_t>(maintenanceVersion); | |||
| 4186 | m_proxyDrawingFormat = | |||
| 4187 | (static_cast<std::uint32_t>(m_proxyMaintenanceVersion) << 16u) | |||
| 4188 | | m_proxyDwgVersion; | |||
| 4189 | } | |||
| 4190 | } else if (!readProxyEntityOptionalBitLong(*buf, dataEndBit, | |||
| 4191 | present, value)) { | |||
| 4192 | return false; | |||
| 4193 | } else if (present) { | |||
| 4194 | m_hasProxyDrawingFormat = true; | |||
| 4195 | m_proxyDrawingFormat = static_cast<std::uint32_t>(value); | |||
| 4196 | m_proxyDwgVersion = static_cast<std::uint16_t>(value); | |||
| 4197 | m_proxyMaintenanceVersion = static_cast<std::uint16_t>( | |||
| 4198 | static_cast<std::uint32_t>(value) >> 16u); | |||
| 4199 | } | |||
| 4200 | ||||
| 4201 | if (version >= DRW::AC1015 && proxyEntityHasBits(*buf, dataEndBit, 1)) { | |||
| 4202 | if (!readBoundedBit(*buf, dataEndBit, m_fromDxf)) | |||
| 4203 | return false; | |||
| 4204 | m_hasFromDxf = true; | |||
| 4205 | } | |||
| 4206 | ||||
| 4207 | const std::uint64_t payloadStartBit = currentDwgBit(buf); | |||
| 4208 | if (payloadStartBit > dataEndBit | |||
| 4209 | || !copyDwgBitRange(*buf, payloadStartBit, dataEndBit, m_entityData)) { | |||
| 4210 | return false; | |||
| 4211 | } | |||
| 4212 | m_entityDataBitSize = static_cast<std::uint32_t>( | |||
| 4213 | dataEndBit - payloadStartBit); | |||
| 4214 | ||||
| 4215 | dwgBuffer handleBuffer = *buf; | |||
| 4216 | if (!handleBuffer.setPosition(dataEndBit >> 3)) | |||
| 4217 | return false; | |||
| 4218 | handleBuffer.setBitPos(static_cast<std::uint8_t>(dataEndBit & 7u)); | |||
| 4219 | if (!handleBuffer.isGood()) | |||
| 4220 | return false; | |||
| 4221 | std::uint64_t handleEndBit = 0; | |||
| 4222 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit) | |||
| 4223 | || !DRW_Entity::parseDwgEntHandle(version, &handleBuffer, true, | |||
| 4224 | handleEndBit)) | |||
| 4225 | return false; | |||
| 4226 | while (proxyEntityHasBits(handleBuffer, handleEndBit, 8)) { | |||
| 4227 | dwgHandle rawHandle; | |||
| 4228 | dwgHandle resolvedHandle; | |||
| 4229 | if (!readBoundedDwgObjectId(handleBuffer, handleEndBit, handle, | |||
| 4230 | rawHandle, resolvedHandle)) | |||
| 4231 | return false; | |||
| 4232 | if (rawHandle.code == 0 && rawHandle.ref64 == 0) | |||
| 4233 | break; | |||
| 4234 | ||||
| 4235 | DRW_ProxyObjectIdRef ref; | |||
| 4236 | ref.m_dxfCode = proxyEntityDxfCode(rawHandle.code); | |||
| 4237 | ref.m_handleCode = rawHandle.code; | |||
| 4238 | ref.m_handle = resolvedHandle.ref64; | |||
| 4239 | ref.m_rawHandle = rawHandle.ref64; | |||
| 4240 | m_objectIdRefs.push_back(ref); | |||
| 4241 | } | |||
| 4242 | ||||
| 4243 | return buf->isGood() && stringBuf->isGood() && handleBuffer.isGood(); | |||
| 4244 | } | |||
| 4245 | ||||
| 4246 | bool DRW_Point::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 4247 | switch (code) { | |||
| 4248 | case 10: | |||
| 4249 | basePoint.x = reader->getDouble(); | |||
| 4250 | break; | |||
| 4251 | case 20: | |||
| 4252 | basePoint.y = reader->getDouble(); | |||
| 4253 | break; | |||
| 4254 | case 30: | |||
| 4255 | basePoint.z = reader->getDouble(); | |||
| 4256 | break; | |||
| 4257 | case 39: | |||
| 4258 | thickness = reader->getDouble(); | |||
| 4259 | break; | |||
| 4260 | case 50: | |||
| 4261 | // DXF code 50 is in degrees; the field is radians (matching the DWG | |||
| 4262 | // path, drw_entities.cpp:1787). degrees -> radians is /ARAD (x pi/180); | |||
| 4263 | // the prior *ARAD only canceled with the writer's /ARAD on DXF->DXF and | |||
| 4264 | // corrupted the value for DXF->DWG. ARAD = 180/pi. | |||
| 4265 | xAxisAngle = reader->getDouble() / ARAD57.29577951308232; // DXF degrees -> radians | |||
| 4266 | break; | |||
| 4267 | case 210: | |||
| 4268 | haveExtrusion = true; | |||
| 4269 | extPoint.x = reader->getDouble(); | |||
| 4270 | break; | |||
| 4271 | case 220: | |||
| 4272 | extPoint.y = reader->getDouble(); | |||
| 4273 | break; | |||
| 4274 | case 230: | |||
| 4275 | extPoint.z = reader->getDouble(); | |||
| 4276 | break; | |||
| 4277 | default: | |||
| 4278 | return DRW_Entity::parseCode(code, reader); | |||
| 4279 | } | |||
| 4280 | ||||
| 4281 | return true; | |||
| 4282 | } | |||
| 4283 | ||||
| 4284 | // --------------------------------------------------------------------------- | |||
| 4285 | // Phase 4a (drafted 2026-05-15) | |||
| 4286 | // --------------------------------------------------------------------------- | |||
| 4287 | // `DRW_Entity::encodeDwgCommon` and `encodeDwgEntHandle` mirror the common | |||
| 4288 | // entity-header fragments parsed above. Version gates intentionally follow | |||
| 4289 | // the DWG reader so newer headers retain their reference flags and handles. | |||
| 4290 | // | |||
| 4291 | // Discarded fields (Risk 4i): | |||
| 4292 | // - haveNextLinks B — we emit 1 (no prev/next chain). | |||
| 4293 | // - none of the common color side channels are discarded for R2004+; | |||
| 4294 | // ENC names remain the byte-oriented TV fields defined by the DWG | |||
| 4295 | // common-entity specification, while ordinary entity text uses strBuf. | |||
| 4296 | // | |||
| 4297 | // We still emit these fixed defaults: | |||
| 4298 | // - entmode = 2 (modelspace, no owner-handle in stream — caller can | |||
| 4299 | // override before calling encodeDwgCommon if entity needs an owner). | |||
| 4300 | // - numReactors = 0 (reactor handles are emitted by the handle phase when | |||
| 4301 | // present). | |||
| 4302 | // - ltFlags = 0 (BYLAYER); plotFlags follows plotStyle. | |||
| 4303 | // - invisibleFlag = 0 (visible) | |||
| 4304 | // | |||
| 4305 | // Caller must: | |||
| 4306 | // - Pre-populate `eType`, `handle`, `color`, `ltypeScale`, `lWeight`, | |||
| 4307 | // `layerH.ref` (handle of the layer this entity belongs to). | |||
| 4308 | // - The body emit between encodeDwgCommon and encodeDwgEntHandle is | |||
| 4309 | // per-entity (3BD basePoint for Point, etc.). | |||
| 4310 | ||||
| 4311 | // Phase-2a kill switch for the full common-entity-header write contract | |||
| 4312 | // (entity reactors/xdict/EED/visibility/entmode emission). Default ON. The | |||
| 4313 | // emission is gated by DATA PRESENCE (empty reactorHandles/extData + visible | |||
| 4314 | // == today's hardcoded zeros), so flipping this OFF restores the legacy | |||
| 4315 | // byte-identical output as an emergency escape hatch. The per-field emission | |||
| 4316 | // arms land in 2a.1..2a.5; this scaffolding commit changes no bytes. | |||
| 4317 | #ifndef LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4318 | #define LIBDXFRW_FULL_COMMON_HEADER1 1 | |||
| 4319 | #endif | |||
| 4320 | ||||
| 4321 | namespace { | |||
| 4322 | ||||
| 4323 | const DRW_Entity::PendingHandleRef* findEedWriteRef( | |||
| 4324 | const std::vector<DRW_Entity::PendingHandleRef>& refs, | |||
| 4325 | std::size_t index) { | |||
| 4326 | const auto it = std::find_if(refs.cbegin(), refs.cend(), | |||
| 4327 | [index](const auto& ref) { | |||
| 4328 | return ref.indexInExtData == index; | |||
| 4329 | }); | |||
| 4330 | if (it == refs.cend()) | |||
| 4331 | return nullptr; | |||
| 4332 | return &*it; | |||
| 4333 | } | |||
| 4334 | ||||
| 4335 | bool parseEedHexHandle(const std::string& text, std::uint64_t& handle) { | |||
| 4336 | if (text.empty()) | |||
| 4337 | return false; | |||
| 4338 | std::size_t index = 0; | |||
| 4339 | if (text.size() > 2 && text[0] == '0' | |||
| 4340 | && (text[1] == 'x' || text[1] == 'X')) { | |||
| 4341 | index = 2; | |||
| 4342 | } | |||
| 4343 | if (index == text.size()) | |||
| 4344 | return false; | |||
| 4345 | ||||
| 4346 | std::uint64_t parsed = 0; | |||
| 4347 | for (; index < text.size(); ++index) { | |||
| 4348 | const unsigned char character = | |||
| 4349 | static_cast<unsigned char>(text[index]); | |||
| 4350 | std::uint8_t digit = 0; | |||
| 4351 | if (character >= '0' && character <= '9') | |||
| 4352 | digit = static_cast<std::uint8_t>(character - '0'); | |||
| 4353 | else if (character >= 'a' && character <= 'f') | |||
| 4354 | digit = static_cast<std::uint8_t>(character - 'a' + 10); | |||
| 4355 | else if (character >= 'A' && character <= 'F') | |||
| 4356 | digit = static_cast<std::uint8_t>(character - 'A' + 10); | |||
| 4357 | else | |||
| 4358 | return false; | |||
| 4359 | if (parsed > (std::numeric_limits<std::uint64_t>::max() - digit) / 16U) | |||
| 4360 | return false; | |||
| 4361 | parsed = parsed * 16U + digit; | |||
| 4362 | } | |||
| 4363 | handle = parsed; | |||
| 4364 | return true; | |||
| 4365 | } | |||
| 4366 | ||||
| 4367 | void putEedRawHandleBE(dwgBufferW& buffer, std::uint64_t handle) { | |||
| 4368 | for (int index = 7; index >= 0; --index) { | |||
| 4369 | buffer.putRawChar8(static_cast<std::uint8_t>( | |||
| 4370 | (handle >> (index * 8)) & 0xFFU)); | |||
| 4371 | } | |||
| 4372 | } | |||
| 4373 | ||||
| 4374 | bool encodeEedItem(DRW::Version version, const DRW_Variant& value, | |||
| 4375 | dwgBufferW& textEncoder, dwgBufferW& output, | |||
| 4376 | std::uint64_t resolvedLayerHandle, | |||
| 4377 | std::uint16_t codePage) { | |||
| 4378 | const int groupCode = value.code(); | |||
| 4379 | switch (groupCode) { | |||
| 4380 | case 1000: { | |||
| 4381 | if (value.type() != DRW_Variant::STRING || value.content.s == nullptr) | |||
| 4382 | return false; | |||
| 4383 | const std::string encoded = textEncoder.encodeTextAreaString( | |||
| 4384 | *value.content.s, version > DRW::AC1018); | |||
| 4385 | if (version > DRW::AC1018) { | |||
| 4386 | if ((encoded.size() & 1U) != 0 | |||
| 4387 | || encoded.size() / 2U > std::numeric_limits<std::uint16_t>::max()) { | |||
| 4388 | return false; | |||
| 4389 | } | |||
| 4390 | output.putRawChar8(0); | |||
| 4391 | output.putRawShort16(static_cast<std::uint16_t>(encoded.size() / 2U)); | |||
| 4392 | } else { | |||
| 4393 | if (encoded.size() > std::numeric_limits<std::uint8_t>::max()) | |||
| 4394 | return false; | |||
| 4395 | output.putRawChar8(0); | |||
| 4396 | output.putRawChar8(static_cast<std::uint8_t>(encoded.size())); | |||
| 4397 | output.putBERawShort16(codePage); | |||
| 4398 | } | |||
| 4399 | output.putBytes(reinterpret_cast<const std::uint8_t*>(encoded.data()), | |||
| 4400 | encoded.size()); | |||
| 4401 | return output.isGood(); | |||
| 4402 | } | |||
| 4403 | case 1002: { | |||
| 4404 | if (value.type() != DRW_Variant::STRING || value.content.s == nullptr | |||
| 4405 | || (*value.content.s != "{" && *value.content.s != "}")) { | |||
| 4406 | return false; | |||
| 4407 | } | |||
| 4408 | output.putRawChar8(2); | |||
| 4409 | output.putRawChar8(*value.content.s == "{" ? 0 : 1); | |||
| 4410 | return output.isGood(); | |||
| 4411 | } | |||
| 4412 | case 1003: | |||
| 4413 | // Most significant byte first, as AutoCAD writes the layer handle. | |||
| 4414 | if (value.type() != DRW_Variant::STRING || resolvedLayerHandle == 0) | |||
| 4415 | return false; | |||
| 4416 | output.putRawChar8(3); | |||
| 4417 | putEedRawHandleBE(output, resolvedLayerHandle); | |||
| 4418 | return output.isGood(); | |||
| 4419 | case 1004: { | |||
| 4420 | std::vector<std::uint8_t> decoded; | |||
| 4421 | const auto* bytes = value.type() == DRW_Variant::BINARY ? value.binary() : nullptr; | |||
| 4422 | // DXF imports retain binary chunks as hexadecimal strings. | |||
| 4423 | if (value.type() == DRW_Variant::STRING && value.content.s != nullptr) { | |||
| 4424 | if (value.content.s->size() > 2U * std::numeric_limits<std::uint8_t>::max() | |||
| 4425 | || !decodeHexBytes(*value.content.s, decoded)) { | |||
| 4426 | return false; | |||
| 4427 | } | |||
| 4428 | bytes = &decoded; | |||
| 4429 | } | |||
| 4430 | if (bytes == nullptr || bytes->size() > std::numeric_limits<std::uint8_t>::max()) { | |||
| 4431 | return false; | |||
| 4432 | } | |||
| 4433 | output.putRawChar8(4); | |||
| 4434 | output.putRawChar8(static_cast<std::uint8_t>(bytes->size())); | |||
| 4435 | output.putBytes(bytes->data(), bytes->size()); | |||
| 4436 | return output.isGood(); | |||
| 4437 | } | |||
| 4438 | case 1005: { | |||
| 4439 | if (value.type() != DRW_Variant::STRING || value.content.s == nullptr) | |||
| 4440 | return false; | |||
| 4441 | std::uint64_t handle = 0; | |||
| 4442 | if (!parseEedHexHandle(*value.content.s, handle)) | |||
| 4443 | return false; | |||
| 4444 | output.putRawChar8(5); | |||
| 4445 | putEedRawHandleBE(output, handle); | |||
| 4446 | return output.isGood(); | |||
| 4447 | } | |||
| 4448 | case 1010: | |||
| 4449 | case 1011: | |||
| 4450 | case 1012: | |||
| 4451 | case 1013: { | |||
| 4452 | if (value.type() != DRW_Variant::COORD || value.coord() == nullptr) | |||
| 4453 | return false; | |||
| 4454 | const DRW_Coord& coordinate = *value.coord(); | |||
| 4455 | if (!std::isfinite(coordinate.x) || !std::isfinite(coordinate.y) | |||
| 4456 | || !std::isfinite(coordinate.z)) { | |||
| 4457 | return false; | |||
| 4458 | } | |||
| 4459 | output.putRawChar8(static_cast<std::uint8_t>(groupCode - 1000)); | |||
| 4460 | output.putRawDouble(coordinate.x); | |||
| 4461 | output.putRawDouble(coordinate.y); | |||
| 4462 | output.putRawDouble(coordinate.z); | |||
| 4463 | return output.isGood(); | |||
| 4464 | } | |||
| 4465 | case 1040: | |||
| 4466 | case 1041: | |||
| 4467 | case 1042: | |||
| 4468 | if (value.type() != DRW_Variant::DOUBLE || !std::isfinite(value.d_val())) | |||
| 4469 | return false; | |||
| 4470 | output.putRawChar8(static_cast<std::uint8_t>(groupCode - 1000)); | |||
| 4471 | output.putRawDouble(value.d_val()); | |||
| 4472 | return output.isGood(); | |||
| 4473 | case 1070: | |||
| 4474 | // DXF input stores the raw 16-bit field in an int32_t. Accept the | |||
| 4475 | // full unsigned bit pattern before writing it back to DWG. | |||
| 4476 | if (value.type() != DRW_Variant::INTEGER | |||
| 4477 | || value.i_val() < std::numeric_limits<std::int16_t>::min() | |||
| 4478 | || value.i_val() > std::numeric_limits<std::uint16_t>::max()) { | |||
| 4479 | return false; | |||
| 4480 | } | |||
| 4481 | output.putRawChar8(70); | |||
| 4482 | output.putRawShort16(static_cast<std::uint16_t>(value.i_val())); | |||
| 4483 | return output.isGood(); | |||
| 4484 | case 1071: { | |||
| 4485 | std::int64_t integer = 0; | |||
| 4486 | if (value.type() == DRW_Variant::INTEGER) | |||
| 4487 | integer = value.i_val(); | |||
| 4488 | else if (value.type() == DRW_Variant::INTEGER64) | |||
| 4489 | integer = value.i64_val(); | |||
| 4490 | else | |||
| 4491 | return false; | |||
| 4492 | if (integer < std::numeric_limits<std::int32_t>::min() | |||
| 4493 | || integer > std::numeric_limits<std::int32_t>::max()) { | |||
| 4494 | return false; | |||
| 4495 | } | |||
| 4496 | output.putRawChar8(71); | |||
| 4497 | output.putRawLong32(static_cast<std::uint32_t>( | |||
| 4498 | static_cast<std::int32_t>(integer))); | |||
| 4499 | return output.isGood(); | |||
| 4500 | } | |||
| 4501 | default: | |||
| 4502 | return false; | |||
| 4503 | } | |||
| 4504 | } | |||
| 4505 | ||||
| 4506 | } // namespace | |||
| 4507 | ||||
| 4508 | bool DRW_Entity::encodeDwgEed( | |||
| 4509 | DRW::Version version, const std::vector<DRW_Variant*>& extData, | |||
| 4510 | const std::vector<PendingHandleRef>& appIdRefs, | |||
| 4511 | const std::vector<PendingHandleRef>& layerRefs, | |||
| 4512 | std::uint16_t codePage, dwgBufferW& output) { | |||
| 4513 | if (extData.empty()) { | |||
| 4514 | output.putBitShort(0); | |||
| 4515 | return output.isGood(); | |||
| 4516 | } | |||
| 4517 | if (extData.size() > dwgSafety::MaxEedTotalItems) | |||
| 4518 | return false; | |||
| 4519 | ||||
| 4520 | std::size_t currentAppStart = 0; | |||
| 4521 | std::uint32_t appHandle = 0; | |||
| 4522 | std::uint32_t groupDepth = 0; | |||
| 4523 | std::uint32_t chunkCount = 0; | |||
| 4524 | // The current application's data is left out of the object. | |||
| 4525 | bool leavingOut = false; | |||
| 4526 | dwgBufferW payload; | |||
| 4527 | const auto flush = [&]() { | |||
| 4528 | if (payload.data().empty() || payload.data().size() | |||
| 4529 | > std::numeric_limits<std::uint16_t>::max() | |||
| 4530 | || appHandle == 0 || ++chunkCount > dwgSafety::MaxEedChunks) { | |||
| 4531 | return false; | |||
| 4532 | } | |||
| 4533 | output.putBitShort(static_cast<std::uint16_t>(payload.data().size())); | |||
| 4534 | dwgHandle appId; | |||
| 4535 | appId.code = 5; | |||
| 4536 | appId.ref = appHandle; | |||
| 4537 | output.putHandle(appId); | |||
| 4538 | output.putBytes(payload.data().data(), payload.data().size()); | |||
| 4539 | payload.reset(); | |||
| 4540 | return output.isGood(); | |||
| 4541 | }; | |||
| 4542 | ||||
| 4543 | for (std::size_t index = 0; index < extData.size(); ++index) { | |||
| 4544 | const DRW_Variant* value = extData[index]; | |||
| 4545 | if (value == nullptr) | |||
| 4546 | return false; | |||
| 4547 | if (value->code() == 1001) { | |||
| 4548 | if (index != currentAppStart && !leavingOut) { | |||
| 4549 | if (groupDepth != 0 || !flush()) | |||
| 4550 | return false; | |||
| 4551 | } | |||
| 4552 | const PendingHandleRef* appIdRef = findEedWriteRef(appIdRefs, index); | |||
| 4553 | if (appIdRef == nullptr | |||
| 4554 | || (appIdRef->handleRef == 0 && !appIdRef->leftOut)) { | |||
| 4555 | return false; | |||
| 4556 | } | |||
| 4557 | appHandle = appIdRef->handleRef; | |||
| 4558 | currentAppStart = index + 1; | |||
| 4559 | groupDepth = 0; | |||
| 4560 | leavingOut = appIdRef->leftOut; | |||
| 4561 | continue; | |||
| 4562 | } | |||
| 4563 | if (index < currentAppStart) | |||
| 4564 | return false; | |||
| 4565 | if (leavingOut) | |||
| 4566 | continue; | |||
| 4567 | if (value->code() == 1002) { | |||
| 4568 | if (value->type() != DRW_Variant::STRING || value->content.s == nullptr) | |||
| 4569 | return false; | |||
| 4570 | if (*value->content.s == "{") { | |||
| 4571 | ++groupDepth; | |||
| 4572 | } else if (*value->content.s == "}") { | |||
| 4573 | if (groupDepth == 0) | |||
| 4574 | return false; | |||
| 4575 | --groupDepth; | |||
| 4576 | } else { | |||
| 4577 | return false; | |||
| 4578 | } | |||
| 4579 | } | |||
| 4580 | ||||
| 4581 | std::uint64_t layerHandle = 0; | |||
| 4582 | if (value->code() == 1003) { | |||
| 4583 | const PendingHandleRef* layerRef = findEedWriteRef(layerRefs, index); | |||
| 4584 | if (layerRef == nullptr) | |||
| 4585 | return false; | |||
| 4586 | layerHandle = layerRef->useRawHandleRef | |||
| 4587 | ? layerRef->rawHandleRef : layerRef->handleRef; | |||
| 4588 | if (layerHandle == 0) | |||
| 4589 | return false; | |||
| 4590 | } | |||
| 4591 | dwgBufferW item; | |||
| 4592 | if (!encodeEedItem(version, *value, output, item, layerHandle, | |||
| 4593 | codePage)) | |||
| 4594 | return false; | |||
| 4595 | if (item.data().size() > std::numeric_limits<std::uint16_t>::max()) | |||
| 4596 | return false; | |||
| 4597 | if (!payload.data().empty() | |||
| 4598 | && payload.data().size() + item.data().size() | |||
| 4599 | > std::numeric_limits<std::uint16_t>::max()) { | |||
| 4600 | if (groupDepth != 0 || !flush()) | |||
| 4601 | return false; | |||
| 4602 | } | |||
| 4603 | payload.putBytes(item.data().data(), item.data().size()); | |||
| 4604 | } | |||
| 4605 | if (currentAppStart == 0) | |||
| 4606 | return false; | |||
| 4607 | if (!leavingOut && (groupDepth != 0 || !flush())) | |||
| 4608 | return false; | |||
| 4609 | output.putBitShort(0); | |||
| 4610 | return output.isGood(); | |||
| 4611 | } | |||
| 4612 | ||||
| 4613 | bool DRW_Entity::encodeDwgCommon(DRW::Version version, dwgBufferW *buf, | |||
| 4614 | dwgBufferW *strBuf) { | |||
| 4615 | (void)strBuf; // ENC names are byte-oriented TV fields in the data stream | |||
| 4616 | if (buf == nullptr || reactorHandles.size() > dwgSafety::MaxReactorCount || | |||
| 4617 | (version != DRW::AC1015 && version != DRW::AC1018 && | |||
| 4618 | version != DRW::AC1021 && | |||
| 4619 | version != DRW::AC1024 && version != DRW::AC1027 && | |||
| 4620 | version != DRW::AC1032)) return false; | |||
| 4621 | ||||
| 4622 | // Object type: BS for AC1015/AC1018, OT for AC1024+. | |||
| 4623 | buf->putObjType(version, static_cast<std::uint16_t>(oType)); | |||
| 4624 | ||||
| 4625 | // objSize stub — back-patched for AC1015/AC1018 only. AC1024 derives | |||
| 4626 | // objSize from the body buffer size, so no RL is emitted. | |||
| 4627 | if (version < DRW::AC1024) { | |||
| 4628 | buf->putRawLong32(0); | |||
| 4629 | } | |||
| 4630 | ||||
| 4631 | // Own handle: code 0 per spec §20.4.1. | |||
| 4632 | dwgHandle ownH; | |||
| 4633 | ownH.code = 0; | |||
| 4634 | ownH.ref = handle; | |||
| 4635 | ownH.size = 0; | |||
| 4636 | if (handle != 0) { | |||
| 4637 | std::uint32_t t = handle; | |||
| 4638 | while (t != 0) { t >>= 8; ++ownH.size; } | |||
| 4639 | } | |||
| 4640 | buf->putHandle(ownH); | |||
| 4641 | ||||
| 4642 | std::vector<DRW_Variant*> eedValues; | |||
| 4643 | try { | |||
| 4644 | eedValues.reserve(extData.size()); | |||
| 4645 | for (const auto& value : extData) | |||
| 4646 | eedValues.push_back(value.get()); | |||
| 4647 | } catch (...) { | |||
| 4648 | return false; | |||
| 4649 | } | |||
| 4650 | if (!encodeDwgEed(version, eedValues, dwgEedAppIdWriteRefs, | |||
| 4651 | dwgEedLayerWriteRefs, dwgEedCodePage, *buf)) | |||
| 4652 | return false; | |||
| 4653 | ||||
| 4654 | // Proxy graphics lives in the common data stream. Preserve it when the | |||
| 4655 | // entity has a bounded byte stream; it is the cached fallback geometry | |||
| 4656 | // used for unrecognised custom/proxy entities. | |||
| 4657 | if (proxyGraphics.size() | |||
| 4658 | > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max() | |||
| 4659 | / 8)) { | |||
| 4660 | return false; | |||
| 4661 | } | |||
| 4662 | const bool hasProxyGraphics = !proxyGraphics.empty(); | |||
| 4663 | buf->putBit(hasProxyGraphics); | |||
| 4664 | if (hasProxyGraphics) { | |||
| 4665 | const auto graphDataSize = static_cast<std::uint64_t>( | |||
| 4666 | proxyGraphics.size()); | |||
| 4667 | if (version >= DRW::AC1024) | |||
| 4668 | buf->putBitLongLong(graphDataSize); | |||
| 4669 | else | |||
| 4670 | buf->putRawLong32(static_cast<std::uint32_t>(graphDataSize)); | |||
| 4671 | buf->putBytes(reinterpret_cast<const std::uint8_t*>( | |||
| 4672 | proxyGraphics.data()), | |||
| 4673 | proxyGraphics.size()); | |||
| 4674 | if (!buf->isGood()) | |||
| 4675 | return false; | |||
| 4676 | } | |||
| 4677 | ||||
| 4678 | const bool hasOwner = parentHandle != DRW::NoHandle; | |||
| 4679 | // entmode BB (ODA §20.4.1 / Open Design FE): | |||
| 4680 | // 0 = owner handle follows in the handle stream | |||
| 4681 | // 1 = paperspace entity without owner-relative handle | |||
| 4682 | // 2 = modelspace entity without owner-relative handle | |||
| 4683 | // Prefer owner when present; otherwise honor DRW_Entity::space. | |||
| 4684 | std::uint8_t entmode = 2; | |||
| 4685 | if (hasOwner) | |||
| 4686 | entmode = 0; | |||
| 4687 | else if (space == DRW::PaperSpace) | |||
| 4688 | entmode = 1; | |||
| 4689 | buf->put2Bits(entmode); | |||
| 4690 | ||||
| 4691 | // numReactors (BL per spec §20.4.1). 2a.2: emit the real count; empty | |||
| 4692 | // reactorHandles → 0 → byte-identical to legacy. | |||
| 4693 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4694 | buf->putBitLong(static_cast<std::int32_t>(reactorHandles.size())); | |||
| 4695 | #else | |||
| 4696 | buf->putBitLong(0); | |||
| 4697 | #endif | |||
| 4698 | ||||
| 4699 | // R2004/R2010 (AC1018, AC1024): reader reads xDictFlag bit (version > AC1015) | |||
| 4700 | // then forces haveNextLinks=1 (no bit in stream). We always emit | |||
| 4701 | // xDictFlag=0 (xdic-present) so the reader reads exactly one xdic handle | |||
| 4702 | // in the handle section — we emit the real handle when xDictHandle!=0 and | |||
| 4703 | // a null handle otherwise. This keeps the empty case byte-identical to the | |||
| 4704 | // legacy path (bit 0 + null handle) while round-tripping a real xdict. | |||
| 4705 | // R2000 (AC1015): no xDictFlag bit; reader's xDictFlag stays 0 so it ALWAYS | |||
| 4706 | // reads an xdic handle — same emit rule applies. | |||
| 4707 | // R2013+ (AC1027+): xDictFlag is followed by the DataStorage flag. | |||
| 4708 | if (version == DRW::AC1015) { | |||
| 4709 | buf->putBit(m_dwgWriteExplicitLinks ? 0 : 1); | |||
| 4710 | } else { | |||
| 4711 | buf->putBit(0); // xDictFlag=0 (xdic present; real-or-null handle follows) | |||
| 4712 | if (version > DRW::AC1024) { | |||
| 4713 | // libreDWG common_entity_data.spec — R2013+ has_ds_data (B). libdxfrw | |||
| 4714 | // never inlines an ACIS SAB datastore, so emit hasDsData (default 0). | |||
| 4715 | // The old code emitted literal 1 (mislabeled haveNextLinks), falsely | |||
| 4716 | // advertising an SAB blob and risking misparse in strict readers. | |||
| 4717 | buf->putBit(hasDsData); | |||
| 4718 | } | |||
| 4719 | } | |||
| 4720 | ||||
| 4721 | // ENC color. R2004+ retains the true-color, transparency, DBCOLOR, and | |||
| 4722 | // byte-oriented color/book-name side channels; AC1015 falls back to BS. | |||
| 4723 | UTF8STRINGstd::string encColorName = colorName; | |||
| 4724 | UTF8STRINGstd::string encBookName; | |||
| 4725 | const std::string::size_type separator = encColorName.find('$'); | |||
| 4726 | if (separator != std::string::npos) { | |||
| 4727 | encBookName = encColorName.substr(0, separator); | |||
| 4728 | encColorName.erase(0, separator + 1); | |||
| 4729 | } | |||
| 4730 | buf->putEnColor(version, static_cast<std::uint16_t>(color), color24, | |||
| 4731 | encColorName, encBookName, | |||
| 4732 | static_cast<std::uint32_t>(transparency), | |||
| 4733 | version >= DRW::AC1018 && hasAcDbColorH); | |||
| 4734 | ||||
| 4735 | // ltypeScale BD. | |||
| 4736 | buf->putBitDouble(ltypeScale); | |||
| 4737 | ||||
| 4738 | // ltFlags BB: 0=BYLAYER, 1=BYBLOCK, 2=CONTINUOUS, 3=lTypeH present. | |||
| 4739 | // Prefer an already-set ltFlags; otherwise derive from lineType / lTypeH. | |||
| 4740 | { | |||
| 4741 | auto upper = [](std::string s) { | |||
| 4742 | for (char& c : s) | |||
| 4743 | c = static_cast<char>(std::toupper(static_cast<unsigned char>(c))); | |||
| 4744 | return s; | |||
| 4745 | }; | |||
| 4746 | std::uint8_t flags = ltFlags; | |||
| 4747 | if (flags > 3) | |||
| 4748 | flags = 0; | |||
| 4749 | if (flags == 0 && lTypeH.ref != 0) | |||
| 4750 | flags = 3; | |||
| 4751 | if (flags == 0) { | |||
| 4752 | const std::string lt = upper(lineType); | |||
| 4753 | if (lt.empty() || lt == "BYLAYER") | |||
| 4754 | flags = 0; | |||
| 4755 | else if (lt == "BYBLOCK") | |||
| 4756 | flags = 1; | |||
| 4757 | else if (lt == "CONTINUOUS") | |||
| 4758 | flags = 2; | |||
| 4759 | else | |||
| 4760 | flags = 3; // named linetype — handle required | |||
| 4761 | } | |||
| 4762 | ltFlags = flags; | |||
| 4763 | } | |||
| 4764 | buf->put2Bits(ltFlags); | |||
| 4765 | // plotFlags BB: a nonzero plot-style handle requires the hard-pointer | |||
| 4766 | // handle in the common handle stream. Keep the default zero path | |||
| 4767 | // unchanged for entities without an override. | |||
| 4768 | plotFlags = plotStyle > 0 ? 3 : 0; | |||
| 4769 | buf->put2Bits(plotFlags); | |||
| 4770 | ||||
| 4771 | // R2010 (AC1024): materialFlag BB + shadowFlag RC (version > AC1018). | |||
| 4772 | if (version > DRW::AC1018) { | |||
| 4773 | materialFlag = material == DRW::MaterialByLayer ? 0 : 3; | |||
| 4774 | shadowFlag = static_cast<std::uint8_t>(shadow) & 0x3; | |||
| 4775 | buf->put2Bits(materialFlag); | |||
| 4776 | buf->putRawChar8(shadowFlag); | |||
| 4777 | } | |||
| 4778 | ||||
| 4779 | // R2010 (AC1024): three visual-style flag bits (version > AC1021). | |||
| 4780 | if (version > DRW::AC1021) { | |||
| 4781 | hasFullVisualStyle = fullVisualStyleHandle != 0; | |||
| 4782 | hasFaceVisualStyle = faceVisualStyleHandle != 0; | |||
| 4783 | hasEdgeVisualStyle = edgeVisualStyleHandle != 0; | |||
| 4784 | buf->putBit(hasFullVisualStyle); | |||
| 4785 | buf->putBit(hasFaceVisualStyle); | |||
| 4786 | buf->putBit(hasEdgeVisualStyle); | |||
| 4787 | } | |||
| 4788 | ||||
| 4789 | // invisibleFlag BS (DXF 60). 2a.1: emit from `visible` (bit 0 = invisible) | |||
| 4790 | // instead of a hardcoded 0. visible==true → 0 → byte-identical to legacy. | |||
| 4791 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4792 | buf->putBitShort(visible ? 0 : 1); | |||
| 4793 | #else | |||
| 4794 | buf->putBitShort(0); | |||
| 4795 | #endif | |||
| 4796 | ||||
| 4797 | // lWeight RC (0 = byLayer per DRW_LW_Conv). | |||
| 4798 | buf->putRawChar8(static_cast<std::uint8_t>(lWeight)); | |||
| 4799 | ||||
| 4800 | return buf->isGood(); | |||
| 4801 | } | |||
| 4802 | ||||
| 4803 | bool DRW_Entity::encodeDwgEntHandle(DRW::Version version, dwgBufferW *buf, | |||
| 4804 | dwgBufferW *handleBuf) { | |||
| 4805 | if (buf == nullptr || reactorHandles.size() > dwgSafety::MaxReactorCount || | |||
| 4806 | (version != DRW::AC1015 && version != DRW::AC1018 && | |||
| 4807 | version != DRW::AC1021 && | |||
| 4808 | version != DRW::AC1024 && version != DRW::AC1027 && | |||
| 4809 | version != DRW::AC1032)) return false; | |||
| 4810 | ||||
| 4811 | // For AC1024, handles are directed to handleBuf (the separate handle section); | |||
| 4812 | // for AC1015/AC1018, handles go into buf alongside the data. | |||
| 4813 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 4814 | ||||
| 4815 | // Owner handle is present only when encodeDwgCommon emitted entmode=0. | |||
| 4816 | if (parentHandle != DRW::NoHandle) { | |||
| 4817 | dwgHandle owner; | |||
| 4818 | owner.code = 4; // soft pointer owner, read via getOffsetHandle() | |||
| 4819 | owner.ref = parentHandle; | |||
| 4820 | owner.size = 0; | |||
| 4821 | std::uint32_t t = parentHandle; | |||
| 4822 | while (t != 0) { t >>= 8; ++owner.size; } | |||
| 4823 | hb->putHandle(owner); | |||
| 4824 | } | |||
| 4825 | ||||
| 4826 | // Reactor handles (2a.2): emitted before xdic, one per numReactors written | |||
| 4827 | // in the DATA section, as ABSOLUTE handles (reader uses getHandle()). Empty | |||
| 4828 | // reactorHandles → nothing emitted → byte-identical to legacy. | |||
| 4829 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4830 | for (std::uint32_t ref : reactorHandles) { | |||
| 4831 | dwgHandle rh; | |||
| 4832 | rh.code = 4; // soft pointer | |||
| 4833 | rh.ref = ref; | |||
| 4834 | rh.size = 0; | |||
| 4835 | if (ref != 0) { std::uint32_t t = ref; while (t != 0) { t >>= 8; ++rh.size; } } | |||
| 4836 | hb->putHandle(rh); | |||
| 4837 | } | |||
| 4838 | #endif | |||
| 4839 | ||||
| 4840 | // XDic handle — xDictFlag=0 in the DATA section means the reader reads one | |||
| 4841 | // XDicObj handle here: emit the real handle when xDictHandle!=0, else the | |||
| 4842 | // null handle (matching the legacy byte-for-byte for the empty case). | |||
| 4843 | dwgHandle xDic; | |||
| 4844 | xDic.code = 3; | |||
| 4845 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4846 | xDic.ref = xDictHandle; | |||
| 4847 | xDic.size = 0; | |||
| 4848 | if (xDictHandle != 0) { | |||
| 4849 | std::uint32_t t = xDictHandle; while (t != 0) { t >>= 8; ++xDic.size; } | |||
| 4850 | } | |||
| 4851 | #else | |||
| 4852 | xDic.ref = 0; | |||
| 4853 | xDic.size = 0; | |||
| 4854 | #endif | |||
| 4855 | hb->putHandle(xDic); | |||
| 4856 | ||||
| 4857 | // R2004+ stores the optional AcDbColor reference after the common owner, | |||
| 4858 | // reactor, and xdictionary handles. Keep this order aligned with the | |||
| 4859 | // reader and the cross-project handle-stream contract. | |||
| 4860 | if (version > DRW::AC1015 && hasAcDbColorH) | |||
| 4861 | putHardPointerHandle(hb, acDbColorHandle); | |||
| 4862 | ||||
| 4863 | if (version == DRW::AC1015 && m_dwgWriteExplicitLinks) { | |||
| 4864 | // Fixed widths let the writer finalize owner chains after all entities | |||
| 4865 | // are known without moving object frames or their handle-map offsets. | |||
| 4866 | hb->putFixedHandle(4, 4, prevEntLink); | |||
| 4867 | hb->putFixedHandle(4, 4, nextEntLink); | |||
| 4868 | } | |||
| 4869 | ||||
| 4870 | // Layer handle (R2000+ unconditional). Hard pointer. | |||
| 4871 | dwgHandle lH; | |||
| 4872 | lH.code = layerH.ref == 0 ? 0 : 5; // 5 = hard pointer for layer ref | |||
| 4873 | lH.ref = layerH.ref; | |||
| 4874 | lH.size = 0; | |||
| 4875 | if (lH.ref != 0) { | |||
| 4876 | std::uint32_t t = lH.ref; | |||
| 4877 | while (t != 0) { t >>= 8; ++lH.size; } | |||
| 4878 | } | |||
| 4879 | hb->putHandle(lH); | |||
| 4880 | ||||
| 4881 | // ltFlags=3 → lTypeH (hard pointer, code 5) present; else omit. | |||
| 4882 | if (ltFlags == 3) { | |||
| 4883 | dwgHandle ltH; | |||
| 4884 | ltH.code = lTypeH.ref == 0 ? 0 : 5; | |||
| 4885 | ltH.ref = lTypeH.ref; | |||
| 4886 | ltH.size = 0; | |||
| 4887 | if (ltH.ref != 0) { | |||
| 4888 | std::uint32_t t = ltH.ref; | |||
| 4889 | while (t != 0) { t >>= 8; ++ltH.size; } | |||
| 4890 | } | |||
| 4891 | hb->putHandle(ltH); | |||
| 4892 | } | |||
| 4893 | auto putHardPointer = [hb](std::uint32_t ref) { | |||
| 4894 | dwgHandle h; | |||
| 4895 | h.code = ref == 0 ? 0 : 5; | |||
| 4896 | h.ref = ref; | |||
| 4897 | h.size = 0; | |||
| 4898 | if (ref != 0) { | |||
| 4899 | std::uint32_t t = ref; | |||
| 4900 | while (t != 0) { | |||
| 4901 | t >>= 8; | |||
| 4902 | ++h.size; | |||
| 4903 | } | |||
| 4904 | } | |||
| 4905 | hb->putHandle(h); | |||
| 4906 | }; | |||
| 4907 | ||||
| 4908 | if (version > DRW::AC1018) { | |||
| 4909 | if (materialFlag == 3) | |||
| 4910 | putHardPointer(material); | |||
| 4911 | if (shadowFlag == 3) | |||
| 4912 | putHardPointer(shadowHandle); | |||
| 4913 | } | |||
| 4914 | if (plotFlags == 3) | |||
| 4915 | putHardPointer(static_cast<std::uint32_t>(plotStyle)); | |||
| 4916 | if (version > DRW::AC1021) { | |||
| 4917 | if (hasFullVisualStyle) | |||
| 4918 | putHardPointer(fullVisualStyleHandle); | |||
| 4919 | if (hasFaceVisualStyle) | |||
| 4920 | putHardPointer(faceVisualStyleHandle); | |||
| 4921 | if (hasEdgeVisualStyle) | |||
| 4922 | putHardPointer(edgeVisualStyleHandle); | |||
| 4923 | } | |||
| 4924 | ||||
| 4925 | return buf->isGood() && hb->isGood(); | |||
| 4926 | } | |||
| 4927 | ||||
| 4928 | bool DRW_Point::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 4929 | (void)bs; (void)strBuf; | |||
| 4930 | oType = 27; // POINT class id — see dwgreader.cpp:1111 dispatch | |||
| 4931 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 4932 | ||||
| 4933 | // Point body — mirror of DRW_Point::parseDwg below. | |||
| 4934 | buf->putBitDouble(basePoint.x); | |||
| 4935 | buf->putBitDouble(basePoint.y); | |||
| 4936 | buf->putBitDouble(basePoint.z); | |||
| 4937 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 4938 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 4939 | buf->putBitDouble(xAxisAngle); // ODA §20.4.31 code 50 | |||
| 4940 | ||||
| 4941 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4942 | } | |||
| 4943 | ||||
| 4944 | void DRW_Point::resetDwgState() { | |||
| 4945 | DRW_Entity::reset(); | |||
| 4946 | basePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 4947 | thickness = 0.0; | |||
| 4948 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 4949 | xAxisAngle = 0.0; | |||
| 4950 | } | |||
| 4951 | ||||
| 4952 | bool DRW_Point::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 4953 | resetDwgState(); | |||
| 4954 | dwgBuffer *sourceBuf = buf; | |||
| 4955 | auto fail = [this, sourceBuf]() { | |||
| 4956 | if (sourceBuf != nullptr) | |||
| 4957 | sourceBuf->invalidate(); | |||
| 4958 | resetDwgState(); | |||
| 4959 | return false; | |||
| 4960 | }; | |||
| 4961 | if (sourceBuf == nullptr) | |||
| 4962 | return fail(); | |||
| 4963 | ||||
| 4964 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 4965 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 4966 | || !bodyProbe.isGood()) | |||
| 4967 | return fail(); | |||
| 4968 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 4969 | DRW_Coord parsedBasePoint; | |||
| 4970 | DRW_Coord parsedExtrusion; | |||
| 4971 | double parsedThickness = 0.0; | |||
| 4972 | double parsedXAxisAngle = 0.0; | |||
| 4973 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 4974 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 4975 | version > DRW::AC1014, parsedThickness) | |||
| 4976 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 4977 | version > DRW::AC1014, parsedExtrusion) | |||
| 4978 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedXAxisAngle) | |||
| 4979 | || !std::isfinite(parsedBasePoint.x) | |||
| 4980 | || !std::isfinite(parsedBasePoint.y) | |||
| 4981 | || !std::isfinite(parsedBasePoint.z) | |||
| 4982 | || !std::isfinite(parsedThickness) | |||
| 4983 | || !std::isfinite(parsedExtrusion.x) | |||
| 4984 | || !std::isfinite(parsedExtrusion.y) | |||
| 4985 | || !std::isfinite(parsedExtrusion.z) | |||
| 4986 | || !std::isfinite(parsedXAxisAngle)) | |||
| 4987 | return fail(); | |||
| 4988 | ||||
| 4989 | std::uint64_t handleEndBit = 0; | |||
| 4990 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 4991 | handleEndBit)) | |||
| 4992 | return fail(); | |||
| 4993 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 4994 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 4995 | handleEndBit) | |||
| 4996 | || !handleProbe.isGood()) | |||
| 4997 | return fail(); | |||
| 4998 | ||||
| 4999 | basePoint = parsedBasePoint; | |||
| 5000 | thickness = parsedThickness; | |||
| 5001 | extPoint = parsedExtrusion; | |||
| 5002 | xAxisAngle = parsedXAxisAngle; | |||
| 5003 | *sourceBuf = handleProbe; | |||
| 5004 | return true; | |||
| 5005 | } | |||
| 5006 | ||||
| 5007 | void DRW_Line::resetDwgState() { | |||
| 5008 | DRW_Point::resetDwgState(); | |||
| 5009 | secPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 5010 | } | |||
| 5011 | ||||
| 5012 | bool DRW_Line::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 5013 | switch (code) { | |||
| 5014 | case 11: | |||
| 5015 | secPoint.x = reader->getDouble(); | |||
| 5016 | break; | |||
| 5017 | case 21: | |||
| 5018 | secPoint.y = reader->getDouble(); | |||
| 5019 | break; | |||
| 5020 | case 31: | |||
| 5021 | secPoint.z = reader->getDouble(); | |||
| 5022 | break; | |||
| 5023 | default: | |||
| 5024 | return DRW_Point::parseCode(code, reader); | |||
| 5025 | } | |||
| 5026 | ||||
| 5027 | return true; | |||
| 5028 | } | |||
| 5029 | ||||
| 5030 | bool DRW_Line::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5031 | (void)bs; (void)strBuf; | |||
| 5032 | oType = 19; // LINE class id — see dwgreader.cpp:1105 | |||
| 5033 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5034 | ||||
| 5035 | // R2000+ Line body — zIsZero shortcut: if both z's are 0, omit the | |||
| 5036 | // z fields entirely. Reader reads `zIsZero` first, then RD x + | |||
| 5037 | // DD secX (default = x), RD y + DD secY (default = y), and | |||
| 5038 | // conditionally RD z + DD secZ. Our putDefaultDouble always emits | |||
| 5039 | // the full RD via code 0b11; reader's getDefaultDouble with code | |||
| 5040 | // 0b11 returns the raw double. | |||
| 5041 | bool zIsZero = (basePoint.z == 0.0 && secPoint.z == 0.0); | |||
| 5042 | buf->putBit(zIsZero ? 1 : 0); | |||
| 5043 | buf->putRawDouble(basePoint.x); | |||
| 5044 | buf->putDefaultDouble(basePoint.x, secPoint.x); | |||
| 5045 | buf->putRawDouble(basePoint.y); | |||
| 5046 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 5047 | if (!zIsZero) { | |||
| 5048 | buf->putRawDouble(basePoint.z); | |||
| 5049 | buf->putDefaultDouble(basePoint.z, secPoint.z); | |||
| 5050 | } | |||
| 5051 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5052 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5053 | ||||
| 5054 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5055 | } | |||
| 5056 | ||||
| 5057 | bool DRW_3DLine::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 5058 | std::uint32_t bs) { | |||
| 5059 | resetDwgState(); | |||
| 5060 | dwgBuffer *sourceBuf = buf; | |||
| 5061 | auto fail = [this, sourceBuf]() { | |||
| 5062 | if (sourceBuf != nullptr) | |||
| 5063 | sourceBuf->invalidate(); | |||
| 5064 | resetDwgState(); | |||
| 5065 | return false; | |||
| 5066 | }; | |||
| 5067 | if (sourceBuf == nullptr) | |||
| 5068 | return fail(); | |||
| 5069 | ||||
| 5070 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5071 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5072 | || !bodyProbe.isGood()) | |||
| 5073 | return fail(); | |||
| 5074 | ||||
| 5075 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5076 | double values[10]{}; | |||
| 5077 | for (double& value : values) { | |||
| 5078 | if (!readBoundedRawDouble(bodyProbe, bodyEndBit, value) | |||
| 5079 | || !std::isfinite(value)) | |||
| 5080 | return fail(); | |||
| 5081 | } | |||
| 5082 | ||||
| 5083 | std::uint64_t handleEndBit = 0; | |||
| 5084 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5085 | handleEndBit)) | |||
| 5086 | return fail(); | |||
| 5087 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5088 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5089 | handleEndBit) | |||
| 5090 | || !handleProbe.isGood()) | |||
| 5091 | return fail(); | |||
| 5092 | ||||
| 5093 | basePoint = DRW_Coord{values[0], values[1], values[2]}; | |||
| 5094 | secPoint = DRW_Coord{values[3], values[4], values[5]}; | |||
| 5095 | extPoint = DRW_Coord{values[6], values[7], values[8]}; | |||
| 5096 | thickness = values[9]; | |||
| 5097 | *sourceBuf = handleProbe; | |||
| 5098 | return true; | |||
| 5099 | } | |||
| 5100 | ||||
| 5101 | bool DRW_3DLine::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 5102 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 5103 | dwgBufferW *handleBuf) { | |||
| 5104 | (void)bs; | |||
| 5105 | if (version < DRW::AC1015 || buf == nullptr) | |||
| 5106 | return false; | |||
| 5107 | ||||
| 5108 | // 3DLINE is a modern custom class. Its class ordinal is writer-local, | |||
| 5109 | // while the body remains the fixed raw-double layout used by the reader. | |||
| 5110 | oType = kDwgClassNum; | |||
| 5111 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 5112 | return false; | |||
| 5113 | ||||
| 5114 | for (const double coordinate : {basePoint.x, basePoint.y, basePoint.z, | |||
| 5115 | secPoint.x, secPoint.y, secPoint.z, | |||
| 5116 | extPoint.x, extPoint.y, extPoint.z, | |||
| 5117 | thickness}) { | |||
| 5118 | buf->putRawDouble(coordinate); | |||
| 5119 | } | |||
| 5120 | ||||
| 5121 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5122 | } | |||
| 5123 | ||||
| 5124 | bool DRW_Circle::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5125 | (void)bs; (void)strBuf; | |||
| 5126 | oType = 18; // CIRCLE class id — see dwgreader.cpp:1099 | |||
| 5127 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5128 | ||||
| 5129 | // Circle body — mirror of DRW_Circle::parseDwg. | |||
| 5130 | buf->putBitDouble(basePoint.x); | |||
| 5131 | buf->putBitDouble(basePoint.y); | |||
| 5132 | buf->putBitDouble(basePoint.z); | |||
| 5133 | buf->putBitDouble(radious); | |||
| 5134 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5135 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5136 | ||||
| 5137 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5138 | } | |||
| 5139 | ||||
| 5140 | bool DRW_Ray::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5141 | (void)bs; (void)strBuf; | |||
| 5142 | // Ray = 40, Xline = 41 — derive from runtime type so DRW_Xline can | |||
| 5143 | // share this encoder (it inherits from DRW_Ray). | |||
| 5144 | oType = (eType == DRW::XLINE) ? 41 : 40; | |||
| 5145 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5146 | ||||
| 5147 | // 3 BD basePoint + 3 BD vector — same layout as parseDwg. | |||
| 5148 | buf->putBitDouble(basePoint.x); | |||
| 5149 | buf->putBitDouble(basePoint.y); | |||
| 5150 | buf->putBitDouble(basePoint.z); | |||
| 5151 | buf->putBitDouble(secPoint.x); | |||
| 5152 | buf->putBitDouble(secPoint.y); | |||
| 5153 | buf->putBitDouble(secPoint.z); | |||
| 5154 | ||||
| 5155 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5156 | } | |||
| 5157 | ||||
| 5158 | bool DRW_Trace::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5159 | (void)bs; (void)strBuf; | |||
| 5160 | oType = 32; // TRACE = 32 — see dwgreader.cpp:1317 | |||
| 5161 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5162 | ||||
| 5163 | // Trace body — mirror of parseDwg. Note the unusual layout: | |||
| 5164 | // thickness FIRST, then elevation (basePoint.z) as BD, then 4 | |||
| 5165 | // corners as 2RD (z values share basePoint.z). | |||
| 5166 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5167 | buf->putBitDouble(basePoint.z); | |||
| 5168 | buf->putRawDouble(basePoint.x); | |||
| 5169 | buf->putRawDouble(basePoint.y); | |||
| 5170 | buf->putRawDouble(secPoint.x); | |||
| 5171 | buf->putRawDouble(secPoint.y); | |||
| 5172 | buf->putRawDouble(thirdPoint.x); | |||
| 5173 | buf->putRawDouble(thirdPoint.y); | |||
| 5174 | buf->putRawDouble(fourPoint.x); | |||
| 5175 | buf->putRawDouble(fourPoint.y); | |||
| 5176 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5177 | ||||
| 5178 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5179 | } | |||
| 5180 | ||||
| 5181 | bool DRW_Spline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5182 | (void)bs; (void)strBuf; | |||
| 5183 | if (buf == nullptr || !validatePayloadFields()) | |||
| 5184 | return false; | |||
| 5185 | oType = 36; // SPLINE class id — see dwgreader.cpp:1329 | |||
| 5186 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5187 | encodeDwgSplineBody(version, buf); | |||
| 5188 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5189 | } | |||
| 5190 | ||||
| 5191 | // Spline body encode: the scenario/degree/knots/ctrl/fit section, WITHOUT the | |||
| 5192 | // leading encodeDwgCommon or the trailing encodeDwgEntHandle. Factored out so | |||
| 5193 | // DRW_Helix::encodeDwg can reuse the identical payload (Phase 8a-1). | |||
| 5194 | // Omits the DXF-only flag70/extrusion (210-230) which the DWG stream never | |||
| 5195 | // carries here. | |||
| 5196 | void DRW_Spline::encodeDwgSplineBody(DRW::Version version, dwgBufferW *buf) const { | |||
| 5197 | // Scenario: | |||
| 5198 | // 1 = control-point / rational / planar (uses knots + control + weights) | |||
| 5199 | // 2 = fit-point (uses fit points + tangents + tolerance) | |||
| 5200 | // When both lists are populated (e.g. DXF-sourced splines), prefer scenario 1 | |||
| 5201 | // (ctrl + knots) and drop the fit list from the DWG stream — scenario 1 has no | |||
| 5202 | // fit-point section, so writing both would corrupt all subsequent entities. | |||
| 5203 | const bool hasFit = !fitlist.empty(); | |||
| 5204 | const bool hasCtrl = !controllist.empty(); | |||
| 5205 | std::int32_t scenario = (hasFit && !hasCtrl) ? 2 : 1; | |||
| 5206 | if (m_scenario == 1 && hasCtrl) { | |||
| 5207 | scenario = 1; | |||
| 5208 | } else if (m_scenario == 2 && hasFit) { | |||
| 5209 | scenario = 2; | |||
| 5210 | } | |||
| 5211 | buf->putBitLong(scenario); | |||
| 5212 | if (version > DRW::AC1024) { | |||
| 5213 | // splFlag1 bit 0: method = fit points; bit 2: closed; | |||
| 5214 | // bit 3: knotParam participates in R2013+ scenario selection. | |||
| 5215 | std::int32_t splFlag1 = m_splineFlags1; | |||
| 5216 | splFlag1 &= ~(kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter | kSplineFlagClosed); | |||
| 5217 | if (scenario == 2) { | |||
| 5218 | splFlag1 |= kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter; | |||
| 5219 | if (flags & 0x01) splFlag1 |= kSplineFlagClosed; | |||
| 5220 | } else { | |||
| 5221 | if (flags & 0x01) splFlag1 |= kSplineFlagClosed; | |||
| 5222 | } | |||
| 5223 | buf->putBitLong(splFlag1); | |||
| 5224 | std::int32_t knotParam = m_knotParam; | |||
| 5225 | if (scenario == 1) { | |||
| 5226 | knotParam = kSplineKnotParamCustom; | |||
| 5227 | } else if (knotParam == kSplineKnotParamCustom) { | |||
| 5228 | knotParam = 0; | |||
| 5229 | } | |||
| 5230 | buf->putBitLong(knotParam); | |||
| 5231 | } | |||
| 5232 | buf->putBitLong(static_cast<std::int32_t>(degree)); | |||
| 5233 | ||||
| 5234 | if (scenario == 2) { | |||
| 5235 | buf->putBitDouble(tolfit); | |||
| 5236 | buf->put3BitDouble(tgStart); | |||
| 5237 | buf->put3BitDouble(tgEnd); | |||
| 5238 | const std::int32_t nFit = static_cast<std::int32_t>(fitlist.size()); | |||
| 5239 | buf->putBitLong(nFit); | |||
| 5240 | } else { | |||
| 5241 | // scenario == 1 | |||
| 5242 | // Reader at parseDwg reads three flag bits in this order: | |||
| 5243 | // rational bit (flags bit 2 → 0x04) | |||
| 5244 | // closed bit (flags bit 0 → 0x01) | |||
| 5245 | // periodic bit (flags bit 1 → 0x02) | |||
| 5246 | const bool hasNonDefaultWeights = std::any_of(weightlist.begin(), weightlist.end(), differsFromUnitWeight); | |||
| 5247 | buf->putBit(((flags & 0x4) || hasNonDefaultWeights) ? 1 : 0); // rational | |||
| 5248 | buf->putBit((flags & 0x1) ? 1 : 0); // closed | |||
| 5249 | buf->putBit((flags & 0x2) ? 1 : 0); // periodic | |||
| 5250 | buf->putBitDouble(tolknot); | |||
| 5251 | buf->putBitDouble(tolcontrol); | |||
| 5252 | const std::int32_t nKnots = static_cast<std::int32_t>(knotslist.size()); | |||
| 5253 | const std::int32_t nCtrl = static_cast<std::int32_t>(controllist.size()); | |||
| 5254 | buf->putBitLong(nKnots); | |||
| 5255 | buf->putBitLong(nCtrl); | |||
| 5256 | // weight bit: caller populates weightlist when each control point | |||
| 5257 | // has a non-default weight (NURBS conics). | |||
| 5258 | bool hasWeights = !weightlist.empty(); | |||
| 5259 | buf->putBit(hasWeights ? 1 : 0); | |||
| 5260 | } | |||
| 5261 | ||||
| 5262 | // Data sections are scenario-gated to avoid stream corruption: | |||
| 5263 | // parseDwg reads knots+ctrl only for scenario 1, fit only for scenario 2. | |||
| 5264 | if (scenario == 1) { | |||
| 5265 | for (double k : knotslist) buf->putBitDouble(k); | |||
| 5266 | for (size_t i = 0; i < controllist.size(); ++i) { | |||
| 5267 | buf->put3BitDouble(*controllist[i]); | |||
| 5268 | if (!weightlist.empty()) { | |||
| 5269 | double w = (i < weightlist.size()) ? weightlist[i] : 1.0; | |||
| 5270 | buf->putBitDouble(w); | |||
| 5271 | } | |||
| 5272 | } | |||
| 5273 | } else { | |||
| 5274 | for (const auto& fp : fitlist) buf->put3BitDouble(*fp); | |||
| 5275 | } | |||
| 5276 | } | |||
| 5277 | ||||
| 5278 | // DRW_Helix::encodeDwg — spline body (oType = HELIX class 503) + AcDbHelix | |||
| 5279 | // trailer, then the common entity handle data. Trailer field order MUST match | |||
| 5280 | // DRW_Helix::parseDwg (Phase 8a-1). | |||
| 5281 | bool DRW_Helix::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5282 | (void)bs; (void)strBuf; | |||
| 5283 | const auto finite = [](const DRW_Coord& point) { | |||
| 5284 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 5285 | && std::isfinite(point.z); | |||
| 5286 | }; | |||
| 5287 | if (buf == nullptr || !validatePayloadFields() | |||
| 5288 | || !finite(axisBasePt) || !finite(startPt) || !finite(axisVector) | |||
| 5289 | || !std::isfinite(radius) || !std::isfinite(turns) | |||
| 5290 | || !std::isfinite(turnHeight)) | |||
| 5291 | return false; | |||
| 5292 | oType = kDwgClassNum; // HELIX custom class 503 | |||
| 5293 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5294 | encodeDwgSplineBody(version, buf); | |||
| 5295 | ||||
| 5296 | // AcDbHelix trailer (same order as parseDwg): | |||
| 5297 | buf->putBitLong(m_majorVersion); | |||
| 5298 | buf->putBitLong(m_maintVersion); | |||
| 5299 | buf->put3BitDouble(axisBasePt); | |||
| 5300 | buf->put3BitDouble(startPt); | |||
| 5301 | buf->put3BitDouble(axisVector); | |||
| 5302 | buf->putBitDouble(radius); | |||
| 5303 | buf->putBitDouble(turns); | |||
| 5304 | buf->putBitDouble(turnHeight); | |||
| 5305 | buf->putBit(handedness ? 1 : 0); | |||
| 5306 | buf->putRawChar8(static_cast<std::uint8_t>(constraintType)); | |||
| 5307 | ||||
| 5308 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5309 | } | |||
| 5310 | ||||
| 5311 | bool DRW_MText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5312 | (void)bs; | |||
| 5313 | oType = 44; // MTEXT class id — see dwgreader.cpp:1215 | |||
| 5314 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5315 | ||||
| 5316 | // R2000/R2004/R2010 MTEXT body — mirror of DRW_MText::parseDwg. | |||
| 5317 | buf->put3BitDouble(basePoint); // insertion | |||
| 5318 | buf->put3BitDouble(extPoint); // extrusion | |||
| 5319 | buf->put3BitDouble(secPoint); // X-axis dir | |||
| 5320 | buf->putBitDouble(widthscale); // rect width | |||
| 5321 | if (version > DRW::AC1018) { | |||
| 5322 | buf->putBitDouble(0.0); // rect height, R2007+ | |||
| 5323 | } | |||
| 5324 | buf->putBitDouble(height); // text height | |||
| 5325 | buf->putBitShort(static_cast<std::uint16_t>(textgen)); // attachment | |||
| 5326 | buf->putBitShort(static_cast<std::uint16_t>(alignH)); // drawing dir | |||
| 5327 | buf->putBitDouble(0.0); // ext_ht (extents height; undocumented) | |||
| 5328 | buf->putBitDouble(0.0); // ext_wid (extents width; undocumented) | |||
| 5329 | // For AC1024: text goes to string buffer; for AC1015/AC1018: inline. | |||
| 5330 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 5331 | // R2000+ extras: | |||
| 5332 | buf->putBitShort(linespacingStyle); // linespacing style BS 73 | |||
| 5333 | buf->putBitDouble(interlin); // linespacing factor BD | |||
| 5334 | buf->putBit(0); // unknown bit | |||
| 5335 | if (version > DRW::AC1015) { // R2004+: background flags BL | |||
| 5336 | buf->putBitLong(m_backgroundFlags); | |||
| 5337 | if ((m_backgroundFlags & 0x01) || (version >= DRW::AC1032 && (m_backgroundFlags & 0x10))) { | |||
| 5338 | buf->putBitDouble(m_backgroundScale); // BitDouble (matches the read fix) | |||
| 5339 | buf->putCmColor(version, static_cast<std::uint16_t>(m_backgroundColor)); | |||
| 5340 | buf->putBitLong(m_backgroundTransparency); | |||
| 5341 | } | |||
| 5342 | } | |||
| 5343 | if (version >= DRW::AC1032) { | |||
| 5344 | buf->putBit(m_r2018IsNotAnnotative ? 1 : 0); | |||
| 5345 | if (m_r2018IsNotAnnotative | |||
| 5346 | && !putDwgMTextR2018Block(buf, dwgMTextR2018BlockOf(*this))) | |||
| 5347 | return false; | |||
| 5348 | } | |||
| 5349 | ||||
| 5350 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 5351 | ||||
| 5352 | // styleH — hard pointer to STYLE table record (default STANDARD). | |||
| 5353 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 5354 | putHardPointerHandle(hb, (styleH.ref == 0) ? 0x13 : styleH.ref); | |||
| 5355 | if (version >= DRW::AC1032 && m_r2018IsNotAnnotative) | |||
| 5356 | putHardPointerHandle(hb, (m_r2018AppIdHandle == 0) ? 0x14 : m_r2018AppIdHandle); | |||
| 5357 | return buf->isGood() && hb->isGood(); | |||
| 5358 | } | |||
| 5359 | ||||
| 5360 | bool DRW_Insert::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5361 | (void)bs; (void)strBuf; | |||
| 5362 | if (buf == nullptr) | |||
| 5363 | return false; | |||
| 5364 | const bool hasAttrib = !attribHandles.empty(); | |||
| 5365 | if (!hasAttrib) { | |||
| 5366 | if (seqendH.ref != DRW::NoHandle) | |||
| 5367 | return false; | |||
| 5368 | } else { | |||
| 5369 | if (seqendH.ref == DRW::NoHandle) | |||
| 5370 | return false; | |||
| 5371 | if (version < DRW::AC1018) { | |||
| 5372 | if (attribHandles.size() != 2 || | |||
| 5373 | (attribHandles.front().ref == DRW::NoHandle) != | |||
| 5374 | (attribHandles.back().ref == DRW::NoHandle)) { | |||
| 5375 | return false; | |||
| 5376 | } | |||
| 5377 | } else if (std::any_of(attribHandles.cbegin(), attribHandles.cend(), | |||
| 5378 | [](const dwgHandle& handle) { | |||
| 5379 | return handle.ref == DRW::NoHandle; | |||
| 5380 | })) { | |||
| 5381 | return false; | |||
| 5382 | } | |||
| 5383 | } | |||
| 5384 | if (attribHandles.size() > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) | |||
| 5385 | return false; | |||
| 5386 | ||||
| 5387 | // 2b.6: emit MINSERT (oType 8) when a column/row grid is present; | |||
| 5388 | // otherwise a plain INSERT (oType 7). The reader keys the grid block off | |||
| 5389 | // oType==8 (parseDwg :3189). | |||
| 5390 | oType = isMInsert() ? 8 : 7; | |||
| 5391 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5392 | ||||
| 5393 | // INSERT body — mirror of DRW_Insert::parseDwg for R2000. | |||
| 5394 | buf->putBitDouble(basePoint.x); | |||
| 5395 | buf->putBitDouble(basePoint.y); | |||
| 5396 | buf->putBitDouble(basePoint.z); | |||
| 5397 | ||||
| 5398 | // dataFlags: pick the most compact form based on actual scales. | |||
| 5399 | // 3 → all scales default to 1.0 (no emit) | |||
| 5400 | // 2 → uniform scale (xscale RD only; yscale=zscale=xscale) | |||
| 5401 | // 1 → xscale defaults to 1, yscale/zscale as DD against xscale | |||
| 5402 | // 0 → xscale RD; yscale/zscale as DD against xscale | |||
| 5403 | if (sameStoredDouble(xscale, 1.0) && sameStoredDouble(yscale, 1.0) | |||
| 5404 | && sameStoredDouble(zscale, 1.0)) { | |||
| 5405 | buf->put2Bits(3); | |||
| 5406 | } else if (sameStoredDouble(xscale, yscale) && sameStoredDouble(yscale, zscale)) { | |||
| 5407 | buf->put2Bits(2); | |||
| 5408 | buf->putRawDouble(xscale); | |||
| 5409 | } else if (sameStoredDouble(xscale, 1.0)) { | |||
| 5410 | // xscale is exactly 1.0 (parseDwg leaves it at its 1.0 default and | |||
| 5411 | // never reads it in this branch), so it can be omitted; y and z are | |||
| 5412 | // independent and go through the same DD-against-1.0 path parseDwg | |||
| 5413 | // reads them with. | |||
| 5414 | buf->put2Bits(1); | |||
| 5415 | buf->putDefaultDouble(1.0, yscale); | |||
| 5416 | buf->putDefaultDouble(1.0, zscale); | |||
| 5417 | } else { | |||
| 5418 | // Use dataFlags=0 (general case): RD x + DD y + DD z. | |||
| 5419 | buf->put2Bits(0); | |||
| 5420 | buf->putRawDouble(xscale); | |||
| 5421 | buf->putDefaultDouble(xscale, yscale); | |||
| 5422 | buf->putDefaultDouble(xscale, zscale); | |||
| 5423 | } | |||
| 5424 | ||||
| 5425 | buf->putBitDouble(angle); // radians | |||
| 5426 | buf->putExtrusion(extPoint, /*b_R2000_style=*/false); | |||
| 5427 | buf->putBit(hasAttrib ? 1 : 0); | |||
| 5428 | if (hasAttrib && version > DRW::AC1015) | |||
| 5429 | buf->putBitLong(static_cast<std::int32_t>(attribHandles.size())); | |||
| 5430 | // hasAttrib==0 ⇒ the SINCE-R2004 num_owned BL is absent (parse :3184), so | |||
| 5431 | // the MINSERT grid (oType==8) follows the hasAttrib bit directly. Field | |||
| 5432 | // order mirrors parseDwg :3190-3193 (colcount BS, rowcount BS, colspace BD, | |||
| 5433 | // rowspace BD) and libreDWG dwg.spec num_cols/num_rows/col_spacing/row_spacing. | |||
| 5434 | if (oType == 8) { // MINSERT grid | |||
| 5435 | buf->putBitShort(static_cast<std::uint16_t>(colcount)); | |||
| 5436 | buf->putBitShort(static_cast<std::uint16_t>(rowcount)); | |||
| 5437 | buf->putBitDouble(colspace); | |||
| 5438 | buf->putBitDouble(rowspace); | |||
| 5439 | } | |||
| 5440 | ||||
| 5441 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 5442 | ||||
| 5443 | // BLOCK_RECORD hard pointer. | |||
| 5444 | dwgHandle bhH; | |||
| 5445 | bhH.code = (blockRecH.ref == 0) ? 0 : 5; | |||
| 5446 | bhH.ref = blockRecH.ref; | |||
| 5447 | bhH.size = 0; | |||
| 5448 | if (bhH.ref != 0) { | |||
| 5449 | std::uint32_t t = bhH.ref; | |||
| 5450 | while (t != 0) { t >>= 8; ++bhH.size; } | |||
| 5451 | } | |||
| 5452 | (handleBuf ? handleBuf : buf)->putHandle(bhH); | |||
| 5453 | ||||
| 5454 | if (hasAttrib) { | |||
| 5455 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 5456 | if (version < DRW::AC1018) { | |||
| 5457 | for (const dwgHandle& attribHandle : attribHandles) | |||
| 5458 | putDwgReference(hb, DRW::DwgSoftPointer, attribHandle.ref); | |||
| 5459 | } else { | |||
| 5460 | const std::uint8_t attributeCode = | |||
| 5461 | oType == 8 ? DRW::DwgSoftPointer : DRW::DwgHardOwnership; | |||
| 5462 | for (const dwgHandle& attribHandle : attribHandles) | |||
| 5463 | putDwgReference(hb, attributeCode, attribHandle.ref); | |||
| 5464 | } | |||
| 5465 | putDwgReference(hb, DRW::DwgHardOwnership, seqendH.ref); | |||
| 5466 | } | |||
| 5467 | return buf->isGood() && (handleBuf == nullptr || handleBuf->isGood()); | |||
| 5468 | } | |||
| 5469 | ||||
| 5470 | bool DRW_3Dface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5471 | (void)bs; (void)strBuf; | |||
| 5472 | oType = 28; // 3DFACE class id — see dwgreader.cpp:1237 | |||
| 5473 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5474 | ||||
| 5475 | // R2000+ 3DFACE body — mirror of parseDwg's z_is_zero / has_no_flag | |||
| 5476 | // optimization. Reader checks `invisibleflag != NoEdge`; if NoEdge, | |||
| 5477 | // emit has_no_flag=1 to suppress the BS read. | |||
| 5478 | bool hasNoFlag = (invisibleflag == /*NoEdge*/0); | |||
| 5479 | bool zIsZero = (basePoint.z == 0.0); | |||
| 5480 | buf->putBit(hasNoFlag ? 1 : 0); | |||
| 5481 | buf->putBit(zIsZero ? 1 : 0); | |||
| 5482 | buf->putRawDouble(basePoint.x); | |||
| 5483 | buf->putRawDouble(basePoint.y); | |||
| 5484 | if (!zIsZero) buf->putRawDouble(basePoint.z); | |||
| 5485 | buf->putDefaultDouble(basePoint.x, secPoint.x); | |||
| 5486 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 5487 | buf->putDefaultDouble(basePoint.z, secPoint.z); | |||
| 5488 | buf->putDefaultDouble(secPoint.x, thirdPoint.x); | |||
| 5489 | buf->putDefaultDouble(secPoint.y, thirdPoint.y); | |||
| 5490 | buf->putDefaultDouble(secPoint.z, thirdPoint.z); | |||
| 5491 | buf->putDefaultDouble(thirdPoint.x, fourPoint.x); | |||
| 5492 | buf->putDefaultDouble(thirdPoint.y, fourPoint.y); | |||
| 5493 | buf->putDefaultDouble(thirdPoint.z, fourPoint.z); | |||
| 5494 | if (!hasNoFlag) buf->putBitShort(static_cast<std::uint16_t>(invisibleflag)); | |||
| 5495 | ||||
| 5496 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5497 | } | |||
| 5498 | ||||
| 5499 | bool DRW_Solid::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5500 | (void)bs; (void)strBuf; | |||
| 5501 | oType = 31; // SOLID class id — see dwgreader.cpp:1305 | |||
| 5502 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5503 | ||||
| 5504 | // Same body layout as TRACE (4 corners + extrusion). Duplicated | |||
| 5505 | // here rather than delegating to DRW_Trace::encodeDwg because that | |||
| 5506 | // hardcodes oType=32. | |||
| 5507 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5508 | buf->putBitDouble(basePoint.z); | |||
| 5509 | buf->putRawDouble(basePoint.x); | |||
| 5510 | buf->putRawDouble(basePoint.y); | |||
| 5511 | buf->putRawDouble(secPoint.x); | |||
| 5512 | buf->putRawDouble(secPoint.y); | |||
| 5513 | buf->putRawDouble(thirdPoint.x); | |||
| 5514 | buf->putRawDouble(thirdPoint.y); | |||
| 5515 | buf->putRawDouble(fourPoint.x); | |||
| 5516 | buf->putRawDouble(fourPoint.y); | |||
| 5517 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5518 | ||||
| 5519 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5520 | } | |||
| 5521 | ||||
| 5522 | bool DRW_LWPolyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5523 | (void)bs; (void)strBuf; | |||
| 5524 | if (buf == nullptr || !validatePayloadFields()) | |||
| 5525 | return false; | |||
| 5526 | oType = 77; // LWPOLYLINE class id — see dwgreader.cpp:1202 | |||
| 5527 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5528 | ||||
| 5529 | // DRW_LWPolyline::flags carries DXF-side bits (1=closed, 128=plinegen). | |||
| 5530 | // DWG-side flags are different: they signal which optional fields are | |||
| 5531 | // present. Per parseDwg, bit 9 (0x200) = closed, bit 8 (0x100) = | |||
| 5532 | // plinegen. Build the DWG flags from the DXF flags plus the data. | |||
| 5533 | std::uint16_t dwgFlags = 0; | |||
| 5534 | if (flags & 1) dwgFlags |= 0x200; // closed | |||
| 5535 | if (flags & 128) dwgFlags |= 0x100; // plinegen | |||
| 5536 | if (thickness != 0.0) dwgFlags |= 0x2; | |||
| 5537 | if (width != 0.0) dwgFlags |= 0x4; | |||
| 5538 | if (elevation != 0.0) dwgFlags |= 0x8; | |||
| 5539 | bool defaultExt = (extPoint.x == 0.0 && extPoint.y == 0.0 && extPoint.z == 1.0); | |||
| 5540 | if (!defaultExt) dwgFlags |= 0x1; | |||
| 5541 | // Detect per-vertex bulge / width data. | |||
| 5542 | bool anyBulge = false; | |||
| 5543 | bool anyWidth = false; | |||
| 5544 | bool anyVertexId = false; | |||
| 5545 | for (const auto& v : vertlist) { | |||
| 5546 | if (v && v->bulge != 0.0) anyBulge = true; | |||
| 5547 | if (v && (v->stawidth != 0.0 || v->endwidth != 0.0)) anyWidth = true; | |||
| 5548 | if (v && v->identifier != 0) anyVertexId = true; | |||
| 5549 | } | |||
| 5550 | if (anyBulge) dwgFlags |= 0x10; | |||
| 5551 | if (anyWidth) dwgFlags |= 0x20; | |||
| 5552 | if (version > DRW::AC1021 && anyVertexId) dwgFlags |= 0x400; | |||
| 5553 | ||||
| 5554 | buf->putBitShort(dwgFlags); | |||
| 5555 | if (dwgFlags & 0x4) buf->putBitDouble(width); | |||
| 5556 | if (dwgFlags & 0x8) buf->putBitDouble(elevation); | |||
| 5557 | if (dwgFlags & 0x2) buf->putBitDouble(thickness); | |||
| 5558 | if (dwgFlags & 0x1) buf->putExtrusion(extPoint, /*b_R2000_style=*/false); | |||
| 5559 | ||||
| 5560 | const std::int32_t numVerts = static_cast<std::int32_t>(vertlist.size()); | |||
| 5561 | buf->putBitLong(numVerts); | |||
| 5562 | if (dwgFlags & 0x10) buf->putBitLong(numVerts); // bulgesnum | |||
| 5563 | if (version > DRW::AC1021 && (dwgFlags & 0x400)) { | |||
| 5564 | buf->putBitLong(numVerts); // vertexIdCount | |||
| 5565 | } | |||
| 5566 | if (dwgFlags & 0x20) buf->putBitLong(numVerts); // widthsnum | |||
| 5567 | ||||
| 5568 | if (numVerts > 0) { | |||
| 5569 | // First vertex as 2RD. Subsequent vertices as 2DD relative to | |||
| 5570 | // the previous, with putDefaultDouble always emitting code 0b11 | |||
| 5571 | // (full RD); the reader's getDefaultDouble returns the raw value. | |||
| 5572 | buf->putRawDouble(vertlist[0]->x); | |||
| 5573 | buf->putRawDouble(vertlist[0]->y); | |||
| 5574 | for (size_t i = 1; i < vertlist.size(); ++i) { | |||
| 5575 | buf->putDefaultDouble(vertlist[i-1]->x, vertlist[i]->x); | |||
| 5576 | buf->putDefaultDouble(vertlist[i-1]->y, vertlist[i]->y); | |||
| 5577 | } | |||
| 5578 | if (dwgFlags & 0x10) { | |||
| 5579 | for (const auto& v : vertlist) | |||
| 5580 | buf->putBitDouble(v->bulge); | |||
| 5581 | } | |||
| 5582 | if (version > DRW::AC1021 && (dwgFlags & 0x400)) { | |||
| 5583 | for (const auto& v : vertlist) | |||
| 5584 | buf->putBitLong(static_cast<std::int32_t>(v->identifier)); | |||
| 5585 | } | |||
| 5586 | if (dwgFlags & 0x20) { | |||
| 5587 | for (const auto& v : vertlist) { | |||
| 5588 | buf->putBitDouble(v->stawidth); | |||
| 5589 | buf->putBitDouble(v->endwidth); | |||
| 5590 | } | |||
| 5591 | } | |||
| 5592 | } | |||
| 5593 | ||||
| 5594 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5595 | } | |||
| 5596 | ||||
| 5597 | bool DRW_Block::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5598 | (void)bs; | |||
| 5599 | // BLOCK = 4, ENDBLK = 5 per DWG spec. isEnd controls which. | |||
| 5600 | oType = isEnd ? 5 : 4; | |||
| 5601 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5602 | if (!isEnd) { | |||
| 5603 | (strBuf ? strBuf : buf)->putVariableText(version, name); | |||
| 5604 | } | |||
| 5605 | if (version > DRW::AC1018) { | |||
| 5606 | buf->putBit(0); // unknown bit (R2007+: always 0 for our output) | |||
| 5607 | } | |||
| 5608 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5609 | } | |||
| 5610 | ||||
| 5611 | bool DRW_Text::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5612 | (void)bs; | |||
| 5613 | oType = 1; // TEXT class id — see dwgreader.cpp:1208 | |||
| 5614 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5615 | ||||
| 5616 | // R2000+ TEXT body — mirror of DRW_Text::parseDwg. We emit | |||
| 5617 | // data_flags=0 so the reader sees every optional field rather than | |||
| 5618 | // substituting defaults — keeps the encoder simple, costs ~30 bytes | |||
| 5619 | // per TEXT versus the most compressed form. | |||
| 5620 | buf->putRawChar8(0); // data_flags=0 | |||
| 5621 | buf->putRawDouble(basePoint.z); // elevation RD | |||
| 5622 | buf->putRawDouble(basePoint.x); // insertion 2RD | |||
| 5623 | buf->putRawDouble(basePoint.y); | |||
| 5624 | buf->putDefaultDouble(basePoint.x, secPoint.x); // alignment 2DD | |||
| 5625 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 5626 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5627 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5628 | buf->putRawDouble(oblique); // oblique angle | |||
| 5629 | // Angle: struct holds degrees; on-disk format is radians. Reader | |||
| 5630 | // does `angle *= ARAD` (180/π) after read. Inverse: divide here. | |||
| 5631 | buf->putRawDouble(angle / ARAD57.29577951308232); | |||
| 5632 | buf->putRawDouble(height); // text height | |||
| 5633 | buf->putRawDouble(widthscale); // width factor | |||
| 5634 | (strBuf ? strBuf : buf)->putVariableText(version, text); // text string | |||
| 5635 | buf->putBitShort(static_cast<std::uint16_t>(textgen)); | |||
| 5636 | buf->putBitShort(static_cast<std::uint16_t>(alignH)); | |||
| 5637 | buf->putBitShort(static_cast<std::uint16_t>(alignV)); | |||
| 5638 | ||||
| 5639 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 5640 | ||||
| 5641 | // styleH — hard pointer to STYLE table record. Default points at | |||
| 5642 | // the STANDARD textstyle (handle 0x13) if caller hasn't set one. | |||
| 5643 | dwgHandle sH; | |||
| 5644 | std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref; | |||
| 5645 | sH.code = 5; // hard pointer | |||
| 5646 | sH.ref = sref; | |||
| 5647 | sH.size = 0; | |||
| 5648 | if (sref != 0) { | |||
| 5649 | std::uint32_t t = sref; | |||
| 5650 | while (t != 0) { t >>= 8; ++sH.size; } | |||
| 5651 | } | |||
| 5652 | (handleBuf ? handleBuf : buf)->putHandle(sH); | |||
| 5653 | return true; | |||
| 5654 | } | |||
| 5655 | ||||
| 5656 | bool DRW_Ellipse::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5657 | (void)bs; (void)strBuf; | |||
| 5658 | oType = 35; // ELLIPSE class id — see dwgreader.cpp:1117 | |||
| 5659 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5660 | ||||
| 5661 | // Ellipse body — mirror of DRW_Ellipse::parseDwg. | |||
| 5662 | buf->put3BitDouble(basePoint); // center | |||
| 5663 | buf->put3BitDouble(secPoint); // major axis vector | |||
| 5664 | buf->put3BitDouble(extPoint); // extrusion | |||
| 5665 | buf->putBitDouble(ratio); // minor/major ratio | |||
| 5666 | buf->putBitDouble(staparam); // start parameter | |||
| 5667 | buf->putBitDouble(endparam); // end parameter | |||
| 5668 | ||||
| 5669 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5670 | } | |||
| 5671 | ||||
| 5672 | bool DRW_Arc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5673 | (void)bs; (void)strBuf; | |||
| 5674 | oType = 17; // ARC class id — see dwgreader.cpp:1093 | |||
| 5675 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5676 | ||||
| 5677 | // Arc body — Circle body + 2 BD angles. | |||
| 5678 | buf->putBitDouble(basePoint.x); | |||
| 5679 | buf->putBitDouble(basePoint.y); | |||
| 5680 | buf->putBitDouble(basePoint.z); | |||
| 5681 | buf->putBitDouble(radious); | |||
| 5682 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5683 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5684 | buf->putBitDouble(staangle); | |||
| 5685 | buf->putBitDouble(endangle); | |||
| 5686 | ||||
| 5687 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5688 | } | |||
| 5689 | ||||
| 5690 | bool DRW_Line::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5691 | resetDwgState(); | |||
| 5692 | dwgBuffer *sourceBuf = buf; | |||
| 5693 | auto fail = [this, sourceBuf]() { | |||
| 5694 | if (sourceBuf != nullptr) | |||
| 5695 | sourceBuf->invalidate(); | |||
| 5696 | resetDwgState(); | |||
| 5697 | return false; | |||
| 5698 | }; | |||
| 5699 | if (sourceBuf == nullptr) | |||
| 5700 | return fail(); | |||
| 5701 | ||||
| 5702 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5703 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5704 | || !bodyProbe.isGood()) | |||
| 5705 | return fail(); | |||
| 5706 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5707 | DRW_Coord parsedBasePoint; | |||
| 5708 | DRW_Coord parsedSecPoint; | |||
| 5709 | DRW_Coord parsedExtrusion; | |||
| 5710 | double parsedThickness = 0.0; | |||
| 5711 | if (version < DRW::AC1015) { | |||
| 5712 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 5713 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedSecPoint)) | |||
| 5714 | return fail(); | |||
| 5715 | } else { | |||
| 5716 | if (!proxyEntityHasBits(bodyProbe, bodyEndBit, 1)) | |||
| 5717 | return fail(); | |||
| 5718 | const bool zIsZero = bodyProbe.getBit() != 0; | |||
| 5719 | if (!bodyProbe.isGood() | |||
| 5720 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 5721 | parsedBasePoint.x) | |||
| 5722 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, | |||
| 5723 | parsedBasePoint.x, | |||
| 5724 | parsedSecPoint.x) | |||
| 5725 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 5726 | parsedBasePoint.y) | |||
| 5727 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, | |||
| 5728 | parsedBasePoint.y, | |||
| 5729 | parsedSecPoint.y)) | |||
| 5730 | return fail(); | |||
| 5731 | if (zIsZero) { | |||
| 5732 | parsedBasePoint.z = 0.0; | |||
| 5733 | parsedSecPoint.z = 0.0; | |||
| 5734 | } else if (!readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 5735 | parsedBasePoint.z) | |||
| 5736 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, | |||
| 5737 | parsedBasePoint.z, | |||
| 5738 | parsedSecPoint.z)) | |||
| 5739 | return fail(); | |||
| 5740 | } | |||
| 5741 | if (!readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 5742 | version > DRW::AC1014, parsedThickness) | |||
| 5743 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 5744 | version > DRW::AC1014, parsedExtrusion) | |||
| 5745 | || !std::isfinite(parsedBasePoint.x) | |||
| 5746 | || !std::isfinite(parsedBasePoint.y) | |||
| 5747 | || !std::isfinite(parsedBasePoint.z) | |||
| 5748 | || !std::isfinite(parsedSecPoint.x) | |||
| 5749 | || !std::isfinite(parsedSecPoint.y) | |||
| 5750 | || !std::isfinite(parsedSecPoint.z) | |||
| 5751 | || !std::isfinite(parsedThickness) | |||
| 5752 | || !std::isfinite(parsedExtrusion.x) | |||
| 5753 | || !std::isfinite(parsedExtrusion.y) | |||
| 5754 | || !std::isfinite(parsedExtrusion.z)) | |||
| 5755 | return fail(); | |||
| 5756 | ||||
| 5757 | std::uint64_t handleEndBit = 0; | |||
| 5758 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5759 | handleEndBit)) | |||
| 5760 | return fail(); | |||
| 5761 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5762 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5763 | handleEndBit) | |||
| 5764 | || !handleProbe.isGood()) | |||
| 5765 | return fail(); | |||
| 5766 | ||||
| 5767 | basePoint = parsedBasePoint; | |||
| 5768 | secPoint = parsedSecPoint; | |||
| 5769 | thickness = parsedThickness; | |||
| 5770 | extPoint = parsedExtrusion; | |||
| 5771 | *sourceBuf = handleProbe; | |||
| 5772 | return true; | |||
| 5773 | } | |||
| 5774 | ||||
| 5775 | bool DRW_Ray::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5776 | resetDwgState(); | |||
| 5777 | dwgBuffer *sourceBuf = buf; | |||
| 5778 | auto fail = [this, sourceBuf]() { | |||
| 5779 | if (sourceBuf != nullptr) | |||
| 5780 | sourceBuf->invalidate(); | |||
| 5781 | resetDwgState(); | |||
| 5782 | return false; | |||
| 5783 | }; | |||
| 5784 | if (sourceBuf == nullptr) | |||
| 5785 | return fail(); | |||
| 5786 | ||||
| 5787 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5788 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5789 | || !bodyProbe.isGood()) | |||
| 5790 | return fail(); | |||
| 5791 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5792 | DRW_Coord parsedBasePoint; | |||
| 5793 | DRW_Coord parsedDirection; | |||
| 5794 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 5795 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedDirection) | |||
| 5796 | || !std::isfinite(parsedBasePoint.x) | |||
| 5797 | || !std::isfinite(parsedBasePoint.y) | |||
| 5798 | || !std::isfinite(parsedBasePoint.z) | |||
| 5799 | || !std::isfinite(parsedDirection.x) | |||
| 5800 | || !std::isfinite(parsedDirection.y) | |||
| 5801 | || !std::isfinite(parsedDirection.z)) | |||
| 5802 | return fail(); | |||
| 5803 | ||||
| 5804 | std::uint64_t handleEndBit = 0; | |||
| 5805 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5806 | handleEndBit)) | |||
| 5807 | return fail(); | |||
| 5808 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5809 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5810 | handleEndBit) | |||
| 5811 | || !handleProbe.isGood()) | |||
| 5812 | return fail(); | |||
| 5813 | ||||
| 5814 | basePoint = parsedBasePoint; | |||
| 5815 | secPoint = parsedDirection; | |||
| 5816 | *sourceBuf = handleProbe; | |||
| 5817 | return true; | |||
| 5818 | } | |||
| 5819 | ||||
| 5820 | void DRW_Circle::applyExtrusion(){ | |||
| 5821 | if (haveExtrusion) { | |||
| 5822 | //NOTE: Commenting these out causes the the arcs being tested to be located | |||
| 5823 | //on the other side of the y axis (all x dimensions are negated). | |||
| 5824 | calculateAxis(extPoint); | |||
| 5825 | extrudePoint(extPoint, &basePoint); | |||
| 5826 | } | |||
| 5827 | } | |||
| 5828 | ||||
| 5829 | bool DRW_Circle::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 5830 | switch (code) { | |||
| 5831 | case 40: | |||
| 5832 | radious = reader->getDouble(); | |||
| 5833 | break; | |||
| 5834 | default: | |||
| 5835 | return DRW_Point::parseCode(code, reader); | |||
| 5836 | } | |||
| 5837 | ||||
| 5838 | return true; | |||
| 5839 | } | |||
| 5840 | ||||
| 5841 | void DRW_Circle::resetDwgState() { | |||
| 5842 | DRW_Point::resetDwgState(); | |||
| 5843 | radious = 0.0; | |||
| 5844 | } | |||
| 5845 | ||||
| 5846 | bool DRW_Circle::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5847 | resetDwgState(); | |||
| 5848 | radious = 0.0; | |||
| 5849 | dwgBuffer *sourceBuf = buf; | |||
| 5850 | auto fail = [this, sourceBuf]() { | |||
| 5851 | if (sourceBuf != nullptr) | |||
| 5852 | sourceBuf->invalidate(); | |||
| 5853 | resetDwgState(); | |||
| 5854 | return false; | |||
| 5855 | }; | |||
| 5856 | if (sourceBuf == nullptr) | |||
| 5857 | return fail(); | |||
| 5858 | ||||
| 5859 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5860 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5861 | || !bodyProbe.isGood()) | |||
| 5862 | return fail(); | |||
| 5863 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5864 | DRW_Coord parsedCenter; | |||
| 5865 | DRW_Coord parsedExtrusion; | |||
| 5866 | double parsedRadius = 0.0; | |||
| 5867 | double parsedThickness = 0.0; | |||
| 5868 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedCenter) | |||
| 5869 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRadius) | |||
| 5870 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 5871 | version > DRW::AC1014, parsedThickness) | |||
| 5872 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 5873 | version > DRW::AC1014, parsedExtrusion) | |||
| 5874 | || !std::isfinite(parsedCenter.x) | |||
| 5875 | || !std::isfinite(parsedCenter.y) | |||
| 5876 | || !std::isfinite(parsedCenter.z) | |||
| 5877 | || !std::isfinite(parsedRadius) | |||
| 5878 | || !std::isfinite(parsedThickness) | |||
| 5879 | || !std::isfinite(parsedExtrusion.x) | |||
| 5880 | || !std::isfinite(parsedExtrusion.y) | |||
| 5881 | || !std::isfinite(parsedExtrusion.z)) | |||
| 5882 | return fail(); | |||
| 5883 | ||||
| 5884 | std::uint64_t handleEndBit = 0; | |||
| 5885 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5886 | handleEndBit)) | |||
| 5887 | return fail(); | |||
| 5888 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5889 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5890 | handleEndBit) | |||
| 5891 | || !handleProbe.isGood()) | |||
| 5892 | return fail(); | |||
| 5893 | ||||
| 5894 | basePoint = parsedCenter; | |||
| 5895 | radious = parsedRadius; | |||
| 5896 | thickness = parsedThickness; | |||
| 5897 | extPoint = parsedExtrusion; | |||
| 5898 | *sourceBuf = handleProbe; | |||
| 5899 | return true; | |||
| 5900 | } | |||
| 5901 | ||||
| 5902 | void DRW_Arc::applyExtrusion(){ | |||
| 5903 | DRW_Circle::applyExtrusion(); | |||
| 5904 | ||||
| 5905 | if(haveExtrusion){ | |||
| 5906 | // If the extrusion vector has a z value less than 0, the angles for the arc | |||
| 5907 | // have to be mirrored since DXF files use the right hand rule. | |||
| 5908 | // Note that the following code only handles the special case where there is a 2D | |||
| 5909 | // drawing with the z axis heading into the paper (or rather screen). An arbitrary | |||
| 5910 | // extrusion axis (with x and y values greater than 1/64) may still have issues. | |||
| 5911 | if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625 && extPoint.z < 0.0) { | |||
| 5912 | staangle=M_PI3.14159265358979323846-staangle; | |||
| 5913 | endangle=M_PI3.14159265358979323846-endangle; | |||
| 5914 | ||||
| 5915 | double temp = staangle; | |||
| 5916 | staangle=endangle; | |||
| 5917 | endangle=temp; | |||
| 5918 | } | |||
| 5919 | } | |||
| 5920 | } | |||
| 5921 | ||||
| 5922 | bool DRW_Arc::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 5923 | switch (code) { | |||
| 5924 | case 50: | |||
| 5925 | staangle = reader->getDouble()/ ARAD57.29577951308232; | |||
| 5926 | break; | |||
| 5927 | case 51: | |||
| 5928 | endangle = reader->getDouble()/ ARAD57.29577951308232; | |||
| 5929 | break; | |||
| 5930 | default: | |||
| 5931 | return DRW_Circle::parseCode(code, reader); | |||
| 5932 | } | |||
| 5933 | ||||
| 5934 | return true; | |||
| 5935 | } | |||
| 5936 | ||||
| 5937 | bool DRW_Arc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5938 | DRW_Circle::resetDwgState(); | |||
| 5939 | radious = 0.0; | |||
| 5940 | staangle = 0.0; | |||
| 5941 | endangle = 0.0; | |||
| 5942 | isccw = 1; | |||
| 5943 | dwgBuffer *sourceBuf = buf; | |||
| 5944 | auto fail = [this, sourceBuf]() { | |||
| 5945 | if (sourceBuf != nullptr) | |||
| 5946 | sourceBuf->invalidate(); | |||
| 5947 | DRW_Circle::resetDwgState(); | |||
| 5948 | staangle = 0.0; | |||
| 5949 | endangle = 0.0; | |||
| 5950 | isccw = 1; | |||
| 5951 | return false; | |||
| 5952 | }; | |||
| 5953 | if (sourceBuf == nullptr) | |||
| 5954 | return fail(); | |||
| 5955 | ||||
| 5956 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5957 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5958 | || !bodyProbe.isGood()) | |||
| 5959 | return fail(); | |||
| 5960 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5961 | DRW_Coord parsedCenter; | |||
| 5962 | DRW_Coord parsedExtrusion; | |||
| 5963 | double parsedRadius = 0.0; | |||
| 5964 | double parsedThickness = 0.0; | |||
| 5965 | double parsedStartAngle = 0.0; | |||
| 5966 | double parsedEndAngle = 0.0; | |||
| 5967 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedCenter) | |||
| 5968 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRadius) | |||
| 5969 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 5970 | version > DRW::AC1014, parsedThickness) | |||
| 5971 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 5972 | version > DRW::AC1014, parsedExtrusion) | |||
| 5973 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedStartAngle) | |||
| 5974 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedEndAngle) | |||
| 5975 | || !std::isfinite(parsedCenter.x) | |||
| 5976 | || !std::isfinite(parsedCenter.y) | |||
| 5977 | || !std::isfinite(parsedCenter.z) | |||
| 5978 | || !std::isfinite(parsedRadius) | |||
| 5979 | || !std::isfinite(parsedThickness) | |||
| 5980 | || !std::isfinite(parsedExtrusion.x) | |||
| 5981 | || !std::isfinite(parsedExtrusion.y) | |||
| 5982 | || !std::isfinite(parsedExtrusion.z) | |||
| 5983 | || !std::isfinite(parsedStartAngle) | |||
| 5984 | || !std::isfinite(parsedEndAngle)) | |||
| 5985 | return fail(); | |||
| 5986 | ||||
| 5987 | std::uint64_t handleEndBit = 0; | |||
| 5988 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5989 | handleEndBit)) | |||
| 5990 | return fail(); | |||
| 5991 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5992 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5993 | handleEndBit) | |||
| 5994 | || !handleProbe.isGood()) | |||
| 5995 | return fail(); | |||
| 5996 | ||||
| 5997 | basePoint = parsedCenter; | |||
| 5998 | radious = parsedRadius; | |||
| 5999 | thickness = parsedThickness; | |||
| 6000 | extPoint = parsedExtrusion; | |||
| 6001 | staangle = parsedStartAngle; | |||
| 6002 | endangle = parsedEndAngle; | |||
| 6003 | *sourceBuf = handleProbe; | |||
| 6004 | return true; | |||
| 6005 | } | |||
| 6006 | ||||
| 6007 | bool DRW_Ellipse::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 6008 | switch (code) { | |||
| 6009 | case 40: | |||
| 6010 | ratio = reader->getDouble(); | |||
| 6011 | break; | |||
| 6012 | case 41: | |||
| 6013 | staparam = reader->getDouble(); | |||
| 6014 | break; | |||
| 6015 | case 42: | |||
| 6016 | endparam = reader->getDouble(); | |||
| 6017 | break; | |||
| 6018 | default: | |||
| 6019 | return DRW_Line::parseCode(code, reader); | |||
| 6020 | } | |||
| 6021 | ||||
| 6022 | return true; | |||
| 6023 | } | |||
| 6024 | ||||
| 6025 | void DRW_Ellipse::applyExtrusion(){ | |||
| 6026 | if (haveExtrusion) { | |||
| 6027 | calculateAxis(extPoint); | |||
| 6028 | extrudePoint(extPoint, &basePoint); | |||
| 6029 | extrudePoint(extPoint, &secPoint); | |||
| 6030 | double intialparam = staparam; | |||
| 6031 | if (extPoint.z < 0.){ | |||
| 6032 | staparam = M_PIx26.283185307179586 - endparam; | |||
| 6033 | endparam = M_PIx26.283185307179586 - intialparam; | |||
| 6034 | } | |||
| 6035 | } | |||
| 6036 | } | |||
| 6037 | ||||
| 6038 | //if ratio > 1 minor axis are greather than major axis, correct it | |||
| 6039 | void DRW_Ellipse::correctAxis(){ | |||
| 6040 | bool complete = false; | |||
| 6041 | if (staparam == endparam) { | |||
| 6042 | staparam = 0.0; | |||
| 6043 | endparam = M_PIx26.283185307179586; //2*M_PI; | |||
| 6044 | complete = true; | |||
| 6045 | } | |||
| 6046 | if (ratio > 1){ | |||
| 6047 | if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10) | |||
| 6048 | complete = true; | |||
| 6049 | double incX = secPoint.x; | |||
| 6050 | secPoint.x = -(secPoint.y * ratio); | |||
| 6051 | secPoint.y = incX*ratio; | |||
| 6052 | ratio = 1/ratio; | |||
| 6053 | if (!complete){ | |||
| 6054 | if (staparam < M_PI_21.57079632679489661923) | |||
| 6055 | staparam += M_PI3.14159265358979323846 *2; | |||
| 6056 | if (endparam < M_PI_21.57079632679489661923) | |||
| 6057 | endparam += M_PI3.14159265358979323846 *2; | |||
| 6058 | endparam -= M_PI_21.57079632679489661923; | |||
| 6059 | staparam -= M_PI_21.57079632679489661923; | |||
| 6060 | } | |||
| 6061 | } | |||
| 6062 | } | |||
| 6063 | ||||
| 6064 | bool DRW_Ellipse::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6065 | resetDwgState(); | |||
| 6066 | ratio = 1.0; | |||
| 6067 | staparam = 0.0; | |||
| 6068 | endparam = 0.0; | |||
| 6069 | isccw = 1; | |||
| 6070 | dwgBuffer *sourceBuf = buf; | |||
| 6071 | auto fail = [this, sourceBuf]() { | |||
| 6072 | if (sourceBuf != nullptr) | |||
| 6073 | sourceBuf->invalidate(); | |||
| 6074 | resetDwgState(); | |||
| 6075 | ratio = 1.0; | |||
| 6076 | staparam = 0.0; | |||
| 6077 | endparam = 0.0; | |||
| 6078 | isccw = 1; | |||
| 6079 | return false; | |||
| 6080 | }; | |||
| 6081 | if (sourceBuf == nullptr) | |||
| 6082 | return fail(); | |||
| 6083 | ||||
| 6084 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6085 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 6086 | || !bodyProbe.isGood()) | |||
| 6087 | return fail(); | |||
| 6088 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 6089 | DRW_Coord parsedCenter; | |||
| 6090 | DRW_Coord parsedAxis; | |||
| 6091 | DRW_Coord parsedExtrusion; | |||
| 6092 | double parsedRatio = 1.0; | |||
| 6093 | double parsedStart = 0.0; | |||
| 6094 | double parsedEnd = 0.0; | |||
| 6095 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedCenter) | |||
| 6096 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedAxis) | |||
| 6097 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedExtrusion) | |||
| 6098 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRatio) | |||
| 6099 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedStart) | |||
| 6100 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedEnd) | |||
| 6101 | || !std::isfinite(parsedCenter.x) | |||
| 6102 | || !std::isfinite(parsedCenter.y) | |||
| 6103 | || !std::isfinite(parsedCenter.z) | |||
| 6104 | || !std::isfinite(parsedAxis.x) | |||
| 6105 | || !std::isfinite(parsedAxis.y) | |||
| 6106 | || !std::isfinite(parsedAxis.z) | |||
| 6107 | || !std::isfinite(parsedExtrusion.x) | |||
| 6108 | || !std::isfinite(parsedExtrusion.y) | |||
| 6109 | || !std::isfinite(parsedExtrusion.z) | |||
| 6110 | || !std::isfinite(parsedRatio) | |||
| 6111 | || !std::isfinite(parsedStart) | |||
| 6112 | || !std::isfinite(parsedEnd)) | |||
| 6113 | return fail(); | |||
| 6114 | ||||
| 6115 | std::uint64_t handleEndBit = 0; | |||
| 6116 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 6117 | handleEndBit)) | |||
| 6118 | return fail(); | |||
| 6119 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6120 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 6121 | handleEndBit) | |||
| 6122 | || !handleProbe.isGood()) | |||
| 6123 | return fail(); | |||
| 6124 | ||||
| 6125 | basePoint = parsedCenter; | |||
| 6126 | secPoint = parsedAxis; | |||
| 6127 | extPoint = parsedExtrusion; | |||
| 6128 | ratio = parsedRatio; | |||
| 6129 | staparam = parsedStart; | |||
| 6130 | endparam = parsedEnd; | |||
| 6131 | *sourceBuf = handleProbe; | |||
| 6132 | return true; | |||
| 6133 | } | |||
| 6134 | ||||
| 6135 | //parts are the number of vertex to split polyline, default 128 | |||
| 6136 | void DRW_Ellipse::toPolyline(DRW_Polyline *pol, int parts){ | |||
| 6137 | double radMajor, radMinor, cosRot, sinRot, incAngle, curAngle; | |||
| 6138 | double cosCurr, sinCurr; | |||
| 6139 | radMajor = hypot(secPoint.x, secPoint.y); | |||
| 6140 | radMinor = radMajor*ratio; | |||
| 6141 | //calculate sin & cos of included angle | |||
| 6142 | incAngle = atan2(secPoint.y, secPoint.x); | |||
| 6143 | cosRot = cos(incAngle); | |||
| 6144 | sinRot = sin(incAngle); | |||
| 6145 | incAngle = M_PIx26.283185307179586 / parts; | |||
| 6146 | curAngle = staparam; | |||
| 6147 | int i = static_cast<int>(curAngle / incAngle); | |||
| 6148 | do { | |||
| 6149 | if (curAngle > endparam) { | |||
| 6150 | curAngle = endparam; | |||
| 6151 | i = parts+2; | |||
| 6152 | } | |||
| 6153 | cosCurr = cos(curAngle); | |||
| 6154 | sinCurr = sin(curAngle); | |||
| 6155 | double x = basePoint.x + (cosCurr*cosRot*radMajor) - (sinCurr*sinRot*radMinor); | |||
| 6156 | double y = basePoint.y + (cosCurr*sinRot*radMajor) + (sinCurr*cosRot*radMinor); | |||
| 6157 | pol->addVertex( DRW_Vertex(x, y, 0.0, 0.0)); | |||
| 6158 | curAngle = (++i)*incAngle; | |||
| 6159 | } while (i<parts); | |||
| 6160 | if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10){ | |||
| 6161 | pol->flags = 1; | |||
| 6162 | } | |||
| 6163 | pol->layer = this->layer; | |||
| 6164 | pol->lineType = this->lineType; | |||
| 6165 | pol->color = this->color; | |||
| 6166 | pol->lWeight = this->lWeight; | |||
| 6167 | pol->extPoint = this->extPoint; | |||
| 6168 | } | |||
| 6169 | ||||
| 6170 | void DRW_Trace::applyExtrusion(){ | |||
| 6171 | if (haveExtrusion) { | |||
| 6172 | calculateAxis(extPoint); | |||
| 6173 | extrudePoint(extPoint, &basePoint); | |||
| 6174 | extrudePoint(extPoint, &secPoint); | |||
| 6175 | extrudePoint(extPoint, &thirdPoint); | |||
| 6176 | extrudePoint(extPoint, &fourPoint); | |||
| 6177 | } | |||
| 6178 | } | |||
| 6179 | ||||
| 6180 | bool DRW_Trace::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 6181 | switch (code) { | |||
| 6182 | case 12: | |||
| 6183 | thirdPoint.x = reader->getDouble(); | |||
| 6184 | break; | |||
| 6185 | case 22: | |||
| 6186 | thirdPoint.y = reader->getDouble(); | |||
| 6187 | break; | |||
| 6188 | case 32: | |||
| 6189 | thirdPoint.z = reader->getDouble(); | |||
| 6190 | break; | |||
| 6191 | case 13: | |||
| 6192 | fourPoint.x = reader->getDouble(); | |||
| 6193 | break; | |||
| 6194 | case 23: | |||
| 6195 | fourPoint.y = reader->getDouble(); | |||
| 6196 | break; | |||
| 6197 | case 33: | |||
| 6198 | fourPoint.z = reader->getDouble(); | |||
| 6199 | break; | |||
| 6200 | default: | |||
| 6201 | return DRW_Line::parseCode(code, reader); | |||
| 6202 | } | |||
| 6203 | ||||
| 6204 | return true; | |||
| 6205 | } | |||
| 6206 | ||||
| 6207 | void DRW_Trace::resetDwgState() { | |||
| 6208 | DRW_Line::resetDwgState(); | |||
| 6209 | thirdPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 6210 | fourPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 6211 | } | |||
| 6212 | ||||
| 6213 | bool DRW_Trace::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 6214 | std::uint32_t bs) { | |||
| 6215 | resetDwgState(); | |||
| 6216 | dwgBuffer *sourceBuf = buf; | |||
| 6217 | auto fail = [this, sourceBuf]() { | |||
| 6218 | if (sourceBuf != nullptr) | |||
| 6219 | sourceBuf->invalidate(); | |||
| 6220 | resetDwgState(); | |||
| 6221 | return false; | |||
| 6222 | }; | |||
| 6223 | if (sourceBuf == nullptr) | |||
| 6224 | return fail(); | |||
| 6225 | ||||
| 6226 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6227 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 6228 | || !bodyProbe.isGood()) | |||
| 6229 | return fail(); | |||
| 6230 | ||||
| 6231 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 6232 | double parsedThickness = 0.0; | |||
| 6233 | double parsedElevation = 0.0; | |||
| 6234 | std::array<double, 8> coordinates{}; | |||
| 6235 | DRW_Coord parsedExtrusion{0.0, 0.0, 1.0}; | |||
| 6236 | if (!readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 6237 | version > DRW::AC1014, parsedThickness) | |||
| 6238 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedElevation)) | |||
| 6239 | return fail(); | |||
| 6240 | for (double& coordinate : coordinates) { | |||
| 6241 | if (!readBoundedRawDouble(bodyProbe, bodyEndBit, coordinate) | |||
| 6242 | || !std::isfinite(coordinate)) | |||
| 6243 | return fail(); | |||
| 6244 | } | |||
| 6245 | if (!std::isfinite(parsedThickness) | |||
| 6246 | || !std::isfinite(parsedElevation) | |||
| 6247 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 6248 | version > DRW::AC1014, parsedExtrusion) | |||
| 6249 | || !std::isfinite(parsedExtrusion.x) | |||
| 6250 | || !std::isfinite(parsedExtrusion.y) | |||
| 6251 | || !std::isfinite(parsedExtrusion.z)) | |||
| 6252 | return fail(); | |||
| 6253 | ||||
| 6254 | std::uint64_t handleEndBit = 0; | |||
| 6255 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 6256 | handleEndBit)) | |||
| 6257 | return fail(); | |||
| 6258 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6259 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 6260 | handleEndBit) | |||
| 6261 | || !handleProbe.isGood()) | |||
| 6262 | return fail(); | |||
| 6263 | ||||
| 6264 | thickness = parsedThickness; | |||
| 6265 | basePoint = DRW_Coord{coordinates[0], coordinates[1], parsedElevation}; | |||
| 6266 | secPoint = DRW_Coord{coordinates[2], coordinates[3], parsedElevation}; | |||
| 6267 | thirdPoint = DRW_Coord{coordinates[4], coordinates[5], parsedElevation}; | |||
| 6268 | fourPoint = DRW_Coord{coordinates[6], coordinates[7], parsedElevation}; | |||
| 6269 | extPoint = parsedExtrusion; | |||
| 6270 | *sourceBuf = handleProbe; | |||
| 6271 | return true; | |||
| 6272 | } | |||
| 6273 | ||||
| 6274 | bool DRW_Solid::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6275 | DRW_DBG("\n***************************** parsing Solid *********************************************\n")DRW_dbg::dbg("\n***************************** parsing Solid *********************************************\n" ); | |||
| 6276 | return DRW_Trace::parseDwg(v, buf, bs); | |||
| 6277 | } | |||
| 6278 | ||||
| 6279 | bool DRW_3Dface::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 6280 | switch (code) { | |||
| 6281 | case 70: | |||
| 6282 | invisibleflag = reader->getInt32(); | |||
| 6283 | break; | |||
| 6284 | default: | |||
| 6285 | return DRW_Trace::parseCode(code, reader); | |||
| 6286 | } | |||
| 6287 | ||||
| 6288 | return true; | |||
| 6289 | } | |||
| 6290 | ||||
| 6291 | bool DRW_3Dface::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 6292 | std::uint32_t bs) { | |||
| 6293 | DRW_Trace::resetDwgState(); | |||
| 6294 | invisibleflag = 0; | |||
| 6295 | dwgBuffer *sourceBuf = buf; | |||
| 6296 | auto fail = [this, sourceBuf]() { | |||
| 6297 | if (sourceBuf != nullptr) | |||
| 6298 | sourceBuf->invalidate(); | |||
| 6299 | DRW_Trace::resetDwgState(); | |||
| 6300 | invisibleflag = 0; | |||
| 6301 | return false; | |||
| 6302 | }; | |||
| 6303 | if (sourceBuf == nullptr) | |||
| 6304 | return fail(); | |||
| 6305 | ||||
| 6306 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6307 | if (!DRW_Entity::parseDwgCommon(v, &bodyProbe, bs) | |||
| 6308 | || !bodyProbe.isGood()) | |||
| 6309 | return fail(); | |||
| 6310 | ||||
| 6311 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 6312 | std::array<DRW_Coord, 4> points{}; | |||
| 6313 | std::uint16_t parsedInvisibleFlag = 0; | |||
| 6314 | if (v < DRW::AC1015) { | |||
| 6315 | for (DRW_Coord& point : points) { | |||
| 6316 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, point.x) | |||
| 6317 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, point.y) | |||
| 6318 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, point.z)) | |||
| 6319 | return fail(); | |||
| 6320 | } | |||
| 6321 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 6322 | parsedInvisibleFlag)) | |||
| 6323 | return fail(); | |||
| 6324 | } else { | |||
| 6325 | if (!proxyEntityHasBits(bodyProbe, bodyEndBit, 2)) | |||
| 6326 | return fail(); | |||
| 6327 | const bool hasNoFlag = bodyProbe.getBit() != 0; | |||
| 6328 | const bool zIsZero = bodyProbe.getBit() != 0; | |||
| 6329 | if (!bodyProbe.isGood() | |||
| 6330 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, points[0].x) | |||
| 6331 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, points[0].y)) | |||
| 6332 | return fail(); | |||
| 6333 | if (zIsZero) { | |||
| 6334 | points[0].z = 0.0; | |||
| 6335 | } else if (!readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 6336 | points[0].z)) { | |||
| 6337 | return fail(); | |||
| 6338 | } | |||
| 6339 | ||||
| 6340 | if (!readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[0].x, | |||
| 6341 | points[1].x) | |||
| 6342 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[0].y, | |||
| 6343 | points[1].y) | |||
| 6344 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[0].z, | |||
| 6345 | points[1].z) | |||
| 6346 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[1].x, | |||
| 6347 | points[2].x) | |||
| 6348 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[1].y, | |||
| 6349 | points[2].y) | |||
| 6350 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[1].z, | |||
| 6351 | points[2].z) | |||
| 6352 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[2].x, | |||
| 6353 | points[3].x) | |||
| 6354 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[2].y, | |||
| 6355 | points[3].y) | |||
| 6356 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[2].z, | |||
| 6357 | points[3].z)) | |||
| 6358 | return fail(); | |||
| 6359 | if (hasNoFlag) { | |||
| 6360 | parsedInvisibleFlag = NoEdge; | |||
| 6361 | } else if (!readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 6362 | parsedInvisibleFlag)) { | |||
| 6363 | return fail(); | |||
| 6364 | } | |||
| 6365 | } | |||
| 6366 | ||||
| 6367 | for (const DRW_Coord& point : points) { | |||
| 6368 | if (!std::isfinite(point.x) || !std::isfinite(point.y) | |||
| 6369 | || !std::isfinite(point.z)) | |||
| 6370 | return fail(); | |||
| 6371 | } | |||
| 6372 | if (parsedInvisibleFlag > AllEdges) | |||
| 6373 | return fail(); | |||
| 6374 | ||||
| 6375 | std::uint64_t handleEndBit = 0; | |||
| 6376 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 6377 | return fail(); | |||
| 6378 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6379 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 6380 | || !handleProbe.isGood()) | |||
| 6381 | return fail(); | |||
| 6382 | ||||
| 6383 | basePoint = points[0]; | |||
| 6384 | secPoint = points[1]; | |||
| 6385 | thirdPoint = points[2]; | |||
| 6386 | fourPoint = points[3]; | |||
| 6387 | invisibleflag = static_cast<int>(parsedInvisibleFlag); | |||
| 6388 | *sourceBuf = handleProbe; | |||
| 6389 | return true; | |||
| 6390 | } | |||
| 6391 | ||||
| 6392 | void DRW_ModelerGeometry::resetDwgState() { | |||
| 6393 | DRW_Entity::reset(); | |||
| 6394 | m_modelerVersion = 0; | |||
| 6395 | m_bodyBitSize = 0; | |||
| 6396 | m_objectSize = 0; | |||
| 6397 | m_isEmpty = false; | |||
| 6398 | m_hasModelerData = false; | |||
| 6399 | m_modelerDataUnknownBit = false; | |||
| 6400 | m_hasWireframe = false; | |||
| 6401 | m_historyHandle = 0; | |||
| 6402 | m_rawBytes.clear(); | |||
| 6403 | m_payloadRanges.clear(); | |||
| 6404 | m_wireframe = DRW_AcisBrep(); | |||
| 6405 | m_wireframeDecoded = false; | |||
| 6406 | } | |||
| 6407 | ||||
| 6408 | bool DRW_ModelerGeometry::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6409 | resetDwgState(); | |||
| 6410 | dwgBuffer *sourceBuf = buf; | |||
| 6411 | auto fail = [this, sourceBuf]() { | |||
| 6412 | if (sourceBuf != nullptr) | |||
| 6413 | sourceBuf->invalidate(); | |||
| 6414 | resetDwgState(); | |||
| 6415 | return false; | |||
| 6416 | }; | |||
| 6417 | if (sourceBuf == nullptr) | |||
| 6418 | return fail(); | |||
| 6419 | ||||
| 6420 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 6421 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 6422 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 6423 | bool ret = DRW_Entity::parseDwg(v, &probe, stringStream, bs); | |||
| 6424 | if (!ret) | |||
| 6425 | return fail(); | |||
| 6426 | DRW_DBG("\n***************************** parsing modeler geometry ******************\n")DRW_dbg::dbg("\n***************************** parsing modeler geometry ******************\n" ); | |||
| 6427 | ||||
| 6428 | std::uint64_t bodyEndBit = 0; | |||
| 6429 | if (!entityBodyDataEndBit( | |||
| 6430 | stringStream != nullptr ? *stringStream : probe, | |||
| 6431 | v, objSize, bodyEndBit)) | |||
| 6432 | return fail(); | |||
| 6433 | const std::uint64_t sourceEndBit = proxyEntityEndBit(*sourceBuf, 0); | |||
| 6434 | if ((v >= DRW::AC1015 && objSize == 0) || bodyEndBit > sourceEndBit | |||
| 6435 | || currentDwgBit(&probe) > bodyEndBit) | |||
| 6436 | return fail(); | |||
| 6437 | bool parsedIsEmpty = false; | |||
| 6438 | bool parsedUnknownBit = false; | |||
| 6439 | std::uint16_t parsedModelerVersion = 0; | |||
| 6440 | if (!readBoundedBit(probe, bodyEndBit, parsedIsEmpty) | |||
| 6441 | || !readBoundedBit(probe, bodyEndBit, parsedUnknownBit)) | |||
| 6442 | return fail(); | |||
| 6443 | const bool parsedHasModelerData = !parsedIsEmpty; | |||
| 6444 | if (parsedHasModelerData | |||
| 6445 | && !readBoundedBitShort(probe, bodyEndBit, parsedModelerVersion)) | |||
| 6446 | return fail(); | |||
| 6447 | if (!probe.isGood() || (stringStream != nullptr && !stringStream->isGood())) | |||
| 6448 | return fail(); | |||
| 6449 | ||||
| 6450 | std::uint64_t handleEndBit = 0; | |||
| 6451 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 6452 | return fail(); | |||
| 6453 | // R13-R2004 modeler bodies contain opaque ACIS/SAT data between this | |||
| 6454 | // header and the common handles. Do not interpret that payload: jump to | |||
| 6455 | // the bounded object-data end exactly as the surface/proxy readers do. | |||
| 6456 | dwgBuffer handleProbe = sourceBuf->forkIndependent(); | |||
| 6457 | if (v <= DRW::AC1018) { | |||
| 6458 | if (!handleProbe.setPosition(bodyEndBit >> 3)) | |||
| 6459 | return fail(); | |||
| 6460 | handleProbe.setBitPos(static_cast<std::uint8_t>(bodyEndBit & 7u)); | |||
| 6461 | if (!handleProbe.isGood()) | |||
| 6462 | return fail(); | |||
| 6463 | } | |||
| 6464 | ret = DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit); | |||
| 6465 | if (!ret || !handleProbe.isGood()) | |||
| 6466 | return fail(); | |||
| 6467 | std::uint32_t parsedHistoryHandle = 0; | |||
| 6468 | if (eType == DRW::E3DSOLID && v > DRW::AC1018 | |||
| 6469 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 6470 | dwgHandle historyH; | |||
| 6471 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 6472 | historyH)) | |||
| 6473 | return fail(); | |||
| 6474 | parsedHistoryHandle = historyH.ref; | |||
| 6475 | DRW_DBG(" 3DSOLID history Handle: ")DRW_dbg::dbg(" 3DSOLID history Handle: "); | |||
| 6476 | DRW_DBGHL(historyH.code, historyH.size, historyH.ref)DRW_dbg::dbgHL(historyH.code, historyH.size, historyH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 6477 | } | |||
| 6478 | ||||
| 6479 | if (handleProbe.size() > std::numeric_limits<std::uint32_t>::max()) | |||
| 6480 | return fail(); | |||
| 6481 | m_bodyBitSize = bs; | |||
| 6482 | m_objectSize = static_cast<std::uint32_t>(probe.size()); | |||
| 6483 | m_isEmpty = parsedIsEmpty; | |||
| 6484 | m_hasModelerData = parsedHasModelerData; | |||
| 6485 | m_modelerDataUnknownBit = parsedUnknownBit; | |||
| 6486 | m_modelerVersion = parsedModelerVersion; | |||
| 6487 | m_historyHandle = parsedHistoryHandle; | |||
| 6488 | *sourceBuf = handleProbe; | |||
| 6489 | return true; | |||
| 6490 | } | |||
| 6491 | ||||
| 6492 | bool DRW_ModelerGeometry::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 6493 | switch (code) { | |||
| 6494 | case 1: | |||
| 6495 | case 3: | |||
| 6496 | if (!appendTextBytesChecked(m_rawBytes, reader->getString(), | |||
| 6497 | dwgSafety::MaxBufferSize)) | |||
| 6498 | return false; | |||
| 6499 | break; | |||
| 6500 | case 70: { | |||
| 6501 | const int value = reader->getInt32(); | |||
| 6502 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 6503 | return false; | |||
| 6504 | m_modelerVersion = static_cast<std::uint16_t>(value); | |||
| 6505 | break; | |||
| 6506 | } | |||
| 6507 | case 350: | |||
| 6508 | case 360: | |||
| 6509 | m_historyHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 6510 | break; | |||
| 6511 | case 310: | |||
| 6512 | // AcDbEntity proxy graphics precede the AcDbModelerGeometry subclass, | |||
| 6513 | // so the announced bytes belong to the entity, not to the ACIS body. | |||
| 6514 | if (numProxyGraph > 0 | |||
| 6515 | && proxyGraphics.size() < static_cast<std::size_t>(numProxyGraph)) | |||
| 6516 | return DRW_Entity::parseCode(code, reader); | |||
| 6517 | { | |||
| 6518 | std::vector<std::uint8_t> decoded; | |||
| 6519 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 6520 | return false; | |||
| 6521 | if (!appendBytesChecked(m_rawBytes, decoded, | |||
| 6522 | dwgSafety::MaxBufferSize)) | |||
| 6523 | return false; | |||
| 6524 | } | |||
| 6525 | break; | |||
| 6526 | default: | |||
| 6527 | return DRW_Entity::parseCode(code, reader); | |||
| 6528 | } | |||
| 6529 | return true; | |||
| 6530 | } | |||
| 6531 | ||||
| 6532 | void DRW_Mesh::resetDwgState() { | |||
| 6533 | DRW_Entity::reset(); | |||
| 6534 | version = 2; | |||
| 6535 | blendCrease = false; | |||
| 6536 | subdivisionLevel = 0; | |||
| 6537 | subdivVertices.clear(); | |||
| 6538 | vertices.clear(); | |||
| 6539 | faces.clear(); | |||
| 6540 | edges.clear(); | |||
| 6541 | creases.clear(); | |||
| 6542 | unknown = 0; | |||
| 6543 | propertyOverrides.clear(); | |||
| 6544 | m_dxfMeshSubclassSeen = false; | |||
| 6545 | m_dxfState = 0; | |||
| 6546 | m_dxfVertexCount = -1; | |||
| 6547 | m_dxfFaceItemsRemaining = -1; | |||
| 6548 | m_dxfEdgeValuesRemaining = -1; | |||
| 6549 | m_dxfCreaseValuesRemaining = -1; | |||
| 6550 | m_dxfPending = 0; | |||
| 6551 | m_dxfEdgeFrom = -1; | |||
| 6552 | m_dxfOverrideEntityCount = -1; | |||
| 6553 | m_dxfOverridePropertyCount = -1; | |||
| 6554 | } | |||
| 6555 | ||||
| 6556 | // DRW_Mesh::parseDwg — AcDbSubDMesh, field order shared by ACadSharp and | |||
| 6557 | // dwgTs. DWG group 91 is the subdivision level, not a refined-vertex count; | |||
| 6558 | // the following BL is the level-0 vertex count. | |||
| 6559 | bool DRW_Mesh::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6560 | resetDwgState(); | |||
| 6561 | dwgBuffer *sourceBuf = buf; | |||
| 6562 | auto fail = [this, sourceBuf]() { | |||
| 6563 | if (sourceBuf != nullptr) | |||
| 6564 | sourceBuf->invalidate(); | |||
| 6565 | resetDwgState(); | |||
| 6566 | return false; | |||
| 6567 | }; | |||
| 6568 | if (sourceBuf == nullptr) | |||
| 6569 | return fail(); | |||
| 6570 | ||||
| 6571 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6572 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 6573 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 6574 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs)) | |||
| 6575 | return fail(); | |||
| 6576 | buf = &bodyProbe; | |||
| 6577 | DRW_DBG("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n")DRW_dbg::dbg("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n" ); | |||
| 6578 | std::uint64_t bodyEndBit = 0; | |||
| 6579 | if (!entityBodyDataEndBit( | |||
| 6580 | stringStream != nullptr ? *stringStream : bodyProbe, | |||
| 6581 | v, objSize, bodyEndBit)) | |||
| 6582 | return fail(); | |||
| 6583 | ||||
| 6584 | auto readCount = [&](std::uint32_t minimumBitsPerItem, | |||
| 6585 | std::uint32_t& count) { | |||
| 6586 | return readTableBodyCount( | |||
| 6587 | v, buf, static_cast<std::uint32_t>(bodyEndBit), | |||
| 6588 | DRW_Mesh::kMaxMeshItems, minimumBitsPerItem, count); | |||
| 6589 | }; | |||
| 6590 | ||||
| 6591 | std::uint16_t parsedVersion = 0; | |||
| 6592 | bool parsedBlendCrease = false; | |||
| 6593 | std::int32_t parsedSubdivisionLevel = 0; | |||
| 6594 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedVersion) | |||
| 6595 | || !readBoundedBit(*buf, bodyEndBit, parsedBlendCrease) | |||
| 6596 | || !readBoundedBitLong(*buf, bodyEndBit, parsedSubdivisionLevel) | |||
| 6597 | || parsedSubdivisionLevel < 0) { | |||
| 6598 | return fail(); | |||
| 6599 | } | |||
| 6600 | ||||
| 6601 | std::uint32_t nVert = 0; // BL vertex count (92) | |||
| 6602 | if (!readCount(6, nVert)) return fail(); // minimum 3BD width | |||
| 6603 | std::vector<DRW_Coord> parsedVertices; | |||
| 6604 | if (!DRW::reserve(parsedVertices, static_cast<int>(nVert))) | |||
| 6605 | return fail(); | |||
| 6606 | std::vector<std::vector<std::int32_t>> parsedFaces; | |||
| 6607 | std::vector<std::pair<std::int32_t, std::int32_t>> parsedEdges; | |||
| 6608 | std::vector<double> parsedCreases; | |||
| 6609 | for (std::uint32_t i = 0; i < nVert; ++i) { | |||
| 6610 | DRW_Coord point; | |||
| 6611 | if (!readBoundedBitCoord(*buf, bodyEndBit, point)) | |||
| 6612 | return fail(); | |||
| 6613 | parsedVertices.push_back(point); | |||
| 6614 | } | |||
| 6615 | const auto finite = [](const DRW_Coord& point) { | |||
| 6616 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 6617 | && std::isfinite(point.z); | |||
| 6618 | }; | |||
| 6619 | if (!buf->isGood() | |||
| 6620 | || (stringStream != nullptr && !stringStream->isGood()) | |||
| 6621 | || !std::all_of(parsedVertices.begin(), parsedVertices.end(), finite)) | |||
| 6622 | return fail(); | |||
| 6623 | ||||
| 6624 | // faces (93) is a FLAT BL stream of length num_faces; each face is | |||
| 6625 | // [count, idx0, idx1, ...]. num_faces is the stream length, not the polygon | |||
| 6626 | // count — group on the fly. | |||
| 6627 | std::uint32_t faceItems = 0; // BL face-list size (93) | |||
| 6628 | if (!readCount(2, faceItems)) return fail(); | |||
| 6629 | std::int32_t remaining = static_cast<std::int32_t>(faceItems); | |||
| 6630 | while (remaining > 0 && buf->isGood()) { | |||
| 6631 | std::int32_t cnt = 0; | |||
| 6632 | if (!readBoundedBitLong(*buf, bodyEndBit, cnt)) | |||
| 6633 | return fail(); | |||
| 6634 | --remaining; | |||
| 6635 | if (cnt < 0 || cnt > remaining) | |||
| 6636 | return fail(); | |||
| 6637 | std::vector<std::int32_t> face; | |||
| 6638 | if (!DRW::reserve(face, cnt)) | |||
| 6639 | return fail(); | |||
| 6640 | for (std::int32_t j = 0; j < cnt; ++j) { | |||
| 6641 | std::int32_t index = 0; | |||
| 6642 | if (!readBoundedBitLong(*buf, bodyEndBit, index)) | |||
| 6643 | return fail(); | |||
| 6644 | if (index < 0 || static_cast<std::uint32_t>(index) >= nVert) | |||
| 6645 | return fail(); | |||
| 6646 | face.push_back(index); | |||
| 6647 | --remaining; | |||
| 6648 | } | |||
| 6649 | if (!buf->isGood()) return fail(); | |||
| 6650 | parsedFaces.push_back(std::move(face)); | |||
| 6651 | } | |||
| 6652 | if (remaining != 0 || !buf->isGood()) return fail(); | |||
| 6653 | ||||
| 6654 | std::uint32_t nEdges = 0; // BL edge count (94) | |||
| 6655 | if (!readCount(4, nEdges)) return fail(); // two minimum-width BL values | |||
| 6656 | if (!DRW::reserve(parsedEdges, static_cast<int>(nEdges))) | |||
| 6657 | return fail(); | |||
| 6658 | for (std::uint32_t i = 0; i < nEdges; ++i) { | |||
| 6659 | std::int32_t from = 0; | |||
| 6660 | std::int32_t to = 0; | |||
| 6661 | if (!readBoundedBitLong(*buf, bodyEndBit, from) | |||
| 6662 | || !readBoundedBitLong(*buf, bodyEndBit, to)) | |||
| 6663 | return fail(); | |||
| 6664 | if (from < 0 || to < 0 | |||
| 6665 | || static_cast<std::uint32_t>(from) >= nVert | |||
| 6666 | || static_cast<std::uint32_t>(to) >= nVert) | |||
| 6667 | return fail(); | |||
| 6668 | parsedEdges.emplace_back(from, to); | |||
| 6669 | } | |||
| 6670 | if (!buf->isGood()) return fail(); | |||
| 6671 | ||||
| 6672 | std::uint32_t nCrease = 0; // BL crease count (95) | |||
| 6673 | if (!readCount(2, nCrease)) return fail(); // minimum-width BD value | |||
| 6674 | if (!DRW::reserve(parsedCreases, static_cast<int>(nCrease))) | |||
| 6675 | return fail(); | |||
| 6676 | for (std::uint32_t i = 0; i < nCrease; ++i) { | |||
| 6677 | double crease = 0.0; | |||
| 6678 | if (!readBoundedBitDouble(*buf, bodyEndBit, crease)) | |||
| 6679 | return fail(); | |||
| 6680 | parsedCreases.push_back(crease); | |||
| 6681 | } | |||
| 6682 | if (!buf->isGood() | |||
| 6683 | || !std::all_of(parsedCreases.begin(), parsedCreases.end(), | |||
| 6684 | [](double value) { return std::isfinite(value); })) | |||
| 6685 | return fail(); | |||
| 6686 | ||||
| 6687 | std::int32_t parsedUnknown = 0; | |||
| 6688 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedUnknown)) | |||
| 6689 | return fail(); // trailing unknown (BL) | |||
| 6690 | ||||
| 6691 | std::uint64_t handleEndBit = 0; | |||
| 6692 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 6693 | return fail(); | |||
| 6694 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6695 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 6696 | || !handleProbe.isGood()) | |||
| 6697 | return fail(); | |||
| 6698 | vertices = std::move(parsedVertices); | |||
| 6699 | faces = std::move(parsedFaces); | |||
| 6700 | edges = std::move(parsedEdges); | |||
| 6701 | creases = std::move(parsedCreases); | |||
| 6702 | version = parsedVersion; | |||
| 6703 | blendCrease = parsedBlendCrease; | |||
| 6704 | subdivisionLevel = parsedSubdivisionLevel; | |||
| 6705 | unknown = parsedUnknown; | |||
| 6706 | *sourceBuf = handleProbe; | |||
| 6707 | return true; | |||
| 6708 | } | |||
| 6709 | ||||
| 6710 | // DRW_Mesh::parseCode — DXF read (codes 71/72/91/92/10·20·30/93/90/94/95/140). | |||
| 6711 | // The 90 stream is shared by faces (after 93) and edges (after 94); m_dxfState | |||
| 6712 | // sequences which one is being filled (mirrors DRW_Image::parseCode's stateful | |||
| 6713 | // 91/14/24 WIPEOUT-vertex accumulation). After the crease stream, group 90 | |||
| 6714 | // starts the bounded property-override records described by AcDbSubDMesh. | |||
| 6715 | bool DRW_Mesh::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 6716 | try { | |||
| 6717 | switch (code) { | |||
| 6718 | case 71: { | |||
| 6719 | const std::int32_t value = reader->getInt32(); | |||
| 6720 | if (value < 0 || value > std::numeric_limits<std::int16_t>::max()) | |||
| 6721 | return false; | |||
| 6722 | version = static_cast<std::uint16_t>(value); | |||
| 6723 | return true; | |||
| 6724 | } | |||
| 6725 | case 72: { | |||
| 6726 | const std::int32_t value = reader->getInt32(); | |||
| 6727 | if (value != 0 && value != 1) | |||
| 6728 | return false; | |||
| 6729 | blendCrease = value != 0; | |||
| 6730 | return true; | |||
| 6731 | } | |||
| 6732 | case 91: { | |||
| 6733 | const std::int32_t value = reader->getInt32(); | |||
| 6734 | if (m_dxfOverrideEntityCount >= 0) { | |||
| 6735 | if (m_dxfState != 96 | |||
| 6736 | || (!propertyOverrides.empty() && m_dxfOverridePropertyCount != 0) | |||
| 6737 | || propertyOverrides.size() >= static_cast<std::size_t>(m_dxfOverrideEntityCount)) | |||
| 6738 | return false; | |||
| 6739 | propertyOverrides.push_back({value, {}}); | |||
| 6740 | m_dxfOverridePropertyCount = -1; | |||
| 6741 | return true; | |||
| 6742 | } | |||
| 6743 | if (value < 0) | |||
| 6744 | return false; | |||
| 6745 | subdivisionLevel = value; | |||
| 6746 | return true; | |||
| 6747 | } | |||
| 6748 | case 100: | |||
| 6749 | if (reader->getString() == "AcDbSubDMesh") | |||
| 6750 | m_dxfMeshSubclassSeen = true; | |||
| 6751 | return true; | |||
| 6752 | case 92: { // base-vertex count; later 92 values belong to overrides | |||
| 6753 | if (!m_dxfMeshSubclassSeen) | |||
| 6754 | return DRW_Entity::parseCode(code, reader); | |||
| 6755 | if (m_dxfVertexCount >= 0) { | |||
| 6756 | if (m_dxfOverrideEntityCount < 0 || m_dxfState != 96 | |||
| 6757 | || propertyOverrides.empty() || m_dxfOverridePropertyCount >= 0) | |||
| 6758 | return false; | |||
| 6759 | const std::int32_t count = reader->getInt32(); | |||
| 6760 | if (!isValidCount(count, 4)) | |||
| 6761 | return false; | |||
| 6762 | if (!DRW::reserve(propertyOverrides.back().propertyTypes, count)) | |||
| 6763 | return false; | |||
| 6764 | m_dxfOverridePropertyCount = count; | |||
| 6765 | return true; | |||
| 6766 | } | |||
| 6767 | const std::int32_t count = reader->getInt32(); | |||
| 6768 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6769 | return false; | |||
| 6770 | if (!DRW::reserve(vertices, count)) | |||
| 6771 | return false; | |||
| 6772 | m_dxfVertexCount = count; | |||
| 6773 | m_dxfState = 92; | |||
| 6774 | return true; | |||
| 6775 | } | |||
| 6776 | case 10: | |||
| 6777 | if (m_dxfState != 92 || m_dxfVertexCount < 0 | |||
| 6778 | || vertices.size() >= static_cast<std::size_t>(m_dxfVertexCount)) | |||
| 6779 | return false; | |||
| 6780 | { | |||
| 6781 | const double value = reader->getDouble(); | |||
| 6782 | if (!std::isfinite(value)) | |||
| 6783 | return false; | |||
| 6784 | vertices.emplace_back(); | |||
| 6785 | vertices.back().x = value; | |||
| 6786 | } | |||
| 6787 | return true; | |||
| 6788 | case 20: | |||
| 6789 | if (m_dxfState != 92 || vertices.empty()) | |||
| 6790 | return false; | |||
| 6791 | { | |||
| 6792 | const double value = reader->getDouble(); | |||
| 6793 | if (!std::isfinite(value)) | |||
| 6794 | return false; | |||
| 6795 | vertices.back().y = value; | |||
| 6796 | } | |||
| 6797 | return true; | |||
| 6798 | case 30: | |||
| 6799 | if (m_dxfState != 92 || vertices.empty()) | |||
| 6800 | return false; | |||
| 6801 | { | |||
| 6802 | const double value = reader->getDouble(); | |||
| 6803 | if (!std::isfinite(value)) | |||
| 6804 | return false; | |||
| 6805 | vertices.back().z = value; | |||
| 6806 | } | |||
| 6807 | return true; | |||
| 6808 | case 93: { // face-list item count | |||
| 6809 | if (m_dxfVertexCount < 0 | |||
| 6810 | || vertices.size() != static_cast<std::size_t>(m_dxfVertexCount)) | |||
| 6811 | return false; | |||
| 6812 | const std::int32_t count = reader->getInt32(); | |||
| 6813 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6814 | return false; | |||
| 6815 | m_dxfState = 93; | |||
| 6816 | m_dxfFaceItemsRemaining = count; | |||
| 6817 | m_dxfPending = 0; | |||
| 6818 | return true; | |||
| 6819 | } | |||
| 6820 | case 94: { // edge count; each edge consumes two code-90 values | |||
| 6821 | if (m_dxfFaceItemsRemaining != 0 || m_dxfPending != 0) | |||
| 6822 | return false; | |||
| 6823 | const std::int32_t count = reader->getInt32(); | |||
| 6824 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6825 | return false; | |||
| 6826 | m_dxfState = 94; | |||
| 6827 | m_dxfEdgeValuesRemaining = count * 2; | |||
| 6828 | m_dxfEdgeFrom = -1; | |||
| 6829 | if (!DRW::reserve(edges, count)) | |||
| 6830 | return false; | |||
| 6831 | return true; | |||
| 6832 | } | |||
| 6833 | case 90: { | |||
| 6834 | const std::int32_t val = reader->getInt32(); | |||
| 6835 | if (m_dxfState == 95) { | |||
| 6836 | if (m_dxfCreaseValuesRemaining != 0) | |||
| 6837 | return false; | |||
| 6838 | if (m_dxfOverrideEntityCount >= 0) | |||
| 6839 | return false; | |||
| 6840 | if (!isValidCount(val, DRW_Mesh::kMaxMeshItems)) | |||
| 6841 | return false; | |||
| 6842 | m_dxfOverrideEntityCount = val; | |||
| 6843 | m_dxfOverridePropertyCount = val == 0 ? 0 : -1; | |||
| 6844 | m_dxfState = 96; | |||
| 6845 | } else if (m_dxfState == 96) { | |||
| 6846 | if (m_dxfOverrideEntityCount < 0 || propertyOverrides.empty() | |||
| 6847 | || m_dxfOverridePropertyCount <= 0 || val < 0 || val > 3) | |||
| 6848 | return false; | |||
| 6849 | propertyOverrides.back().propertyTypes.push_back(val); | |||
| 6850 | --m_dxfOverridePropertyCount; | |||
| 6851 | } else if (m_dxfState == 93) { | |||
| 6852 | if (m_dxfFaceItemsRemaining <= 0) | |||
| 6853 | return false; | |||
| 6854 | if (m_dxfPending == 0) { | |||
| 6855 | if (val < 3 || val > m_dxfFaceItemsRemaining - 1) | |||
| 6856 | return false; | |||
| 6857 | faces.emplace_back(); | |||
| 6858 | m_dxfPending = val; | |||
| 6859 | --m_dxfFaceItemsRemaining; | |||
| 6860 | } else { | |||
| 6861 | if (val < 0 || val >= m_dxfVertexCount) | |||
| 6862 | return false; | |||
| 6863 | if (!faces.empty()) | |||
| 6864 | faces.back().push_back(val); | |||
| 6865 | --m_dxfFaceItemsRemaining; | |||
| 6866 | --m_dxfPending; | |||
| 6867 | } | |||
| 6868 | } else if (m_dxfState == 94) { | |||
| 6869 | if (m_dxfEdgeValuesRemaining <= 0 || val < 0 || val >= m_dxfVertexCount) | |||
| 6870 | return false; | |||
| 6871 | --m_dxfEdgeValuesRemaining; | |||
| 6872 | if (m_dxfEdgeFrom < 0) | |||
| 6873 | m_dxfEdgeFrom = val; | |||
| 6874 | else { | |||
| 6875 | edges.emplace_back(m_dxfEdgeFrom, val); | |||
| 6876 | m_dxfEdgeFrom = -1; | |||
| 6877 | } | |||
| 6878 | } else { | |||
| 6879 | return false; | |||
| 6880 | } | |||
| 6881 | return true; | |||
| 6882 | } | |||
| 6883 | case 95: { // edge crease count | |||
| 6884 | if (m_dxfEdgeValuesRemaining != 0 || m_dxfEdgeFrom != -1) | |||
| 6885 | return false; | |||
| 6886 | const std::int32_t count = reader->getInt32(); | |||
| 6887 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6888 | return false; | |||
| 6889 | m_dxfState = 95; | |||
| 6890 | m_dxfCreaseValuesRemaining = count; | |||
| 6891 | if (!DRW::reserve(creases, count)) | |||
| 6892 | return false; | |||
| 6893 | return true; | |||
| 6894 | } | |||
| 6895 | case 140: | |||
| 6896 | if (m_dxfState != 95 || m_dxfCreaseValuesRemaining <= 0) | |||
| 6897 | return false; | |||
| 6898 | { | |||
| 6899 | const double value = reader->getDouble(); | |||
| 6900 | if (!std::isfinite(value)) | |||
| 6901 | return false; | |||
| 6902 | creases.push_back(value); | |||
| 6903 | } | |||
| 6904 | --m_dxfCreaseValuesRemaining; | |||
| 6905 | return true; | |||
| 6906 | default: | |||
| 6907 | return DRW_Entity::parseCode(code, reader); | |||
| 6908 | } | |||
| 6909 | } catch (...) { | |||
| 6910 | return false; | |||
| 6911 | } | |||
| 6912 | } | |||
| 6913 | ||||
| 6914 | bool DRW_Mesh::validateGeometry() const { | |||
| 6915 | if (subdivisionLevel < 0 | |||
| 6916 | || vertices.size() > static_cast<std::size_t>(kMaxMeshItems) | |||
| 6917 | || edges.size() > static_cast<std::size_t>(kMaxMeshItems) | |||
| 6918 | || faces.size() > static_cast<std::size_t>(kMaxMeshItems) | |||
| 6919 | || creases.size() > static_cast<std::size_t>(kMaxMeshItems)) | |||
| 6920 | return false; | |||
| 6921 | ||||
| 6922 | const auto finite = [](const DRW_Coord& point) { | |||
| 6923 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 6924 | && std::isfinite(point.z); | |||
| 6925 | }; | |||
| 6926 | if (!std::all_of(vertices.cbegin(), vertices.cend(), finite) | |||
| 6927 | || !std::all_of(creases.cbegin(), creases.cend(), | |||
| 6928 | [](double value) { return std::isfinite(value); })) | |||
| 6929 | return false; | |||
| 6930 | std::int32_t faceStreamCount = 0; | |||
| 6931 | for (const auto& face : faces) { | |||
| 6932 | if (face.size() < 3 | |||
| 6933 | || face.size() > static_cast<std::size_t>(kMaxMeshItems - 1) | |||
| 6934 | || faceStreamCount > kMaxMeshItems | |||
| 6935 | - static_cast<std::int32_t>(face.size() + 1)) | |||
| 6936 | return false; | |||
| 6937 | for (std::int32_t index : face) { | |||
| 6938 | if (index < 0 | |||
| 6939 | || static_cast<std::size_t>(index) >= vertices.size()) | |||
| 6940 | return false; | |||
| 6941 | } | |||
| 6942 | faceStreamCount += static_cast<std::int32_t>(face.size() + 1); | |||
| 6943 | } | |||
| 6944 | for (const auto& edge : edges) { | |||
| 6945 | if (edge.first < 0 || edge.second < 0 | |||
| 6946 | || static_cast<std::size_t>(edge.first) >= vertices.size() | |||
| 6947 | || static_cast<std::size_t>(edge.second) >= vertices.size()) | |||
| 6948 | return false; | |||
| 6949 | } | |||
| 6950 | return true; | |||
| 6951 | } | |||
| 6952 | ||||
| 6953 | bool DRW_Mesh::validateDxf() const { | |||
| 6954 | if (!m_dxfMeshSubclassSeen | |||
| 6955 | || m_dxfVertexCount < 0 | |||
| 6956 | || vertices.size() != static_cast<std::size_t>(m_dxfVertexCount) | |||
| 6957 | || m_dxfFaceItemsRemaining != 0 | |||
| 6958 | || m_dxfPending != 0 | |||
| 6959 | || m_dxfEdgeValuesRemaining != 0 | |||
| 6960 | || m_dxfEdgeFrom != -1 | |||
| 6961 | || m_dxfCreaseValuesRemaining != 0 | |||
| 6962 | || (m_dxfOverrideEntityCount >= 0 | |||
| 6963 | && (m_dxfOverridePropertyCount < 0 | |||
| 6964 | || m_dxfOverridePropertyCount != 0 | |||
| 6965 | || propertyOverrides.size() != static_cast<std::size_t>(m_dxfOverrideEntityCount)))) | |||
| 6966 | return false; | |||
| 6967 | for (const auto& overrideData : propertyOverrides) { | |||
| 6968 | if (overrideData.subEntityMarker < 0 | |||
| 6969 | || overrideData.propertyTypes.size() > 4u) | |||
| 6970 | return false; | |||
| 6971 | if (!std::all_of(overrideData.propertyTypes.cbegin(), | |||
| 6972 | overrideData.propertyTypes.cend(), | |||
| 6973 | [](std::int32_t type) { return type >= 0 && type <= 3; })) | |||
| 6974 | return false; | |||
| 6975 | } | |||
| 6976 | return validateGeometry(); | |||
| 6977 | } | |||
| 6978 | ||||
| 6979 | bool DRW_Mesh::validateDxfOutput() const { | |||
| 6980 | if (version > static_cast<std::uint16_t>(std::numeric_limits<std::int16_t>::max()) | |||
| 6981 | || propertyOverrides.size() > static_cast<std::size_t>(kMaxMeshItems)) | |||
| 6982 | return false; | |||
| 6983 | for (const auto& overrideData : propertyOverrides) { | |||
| 6984 | if (overrideData.subEntityMarker < 0 | |||
| 6985 | || overrideData.propertyTypes.size() > 4u | |||
| 6986 | || !std::all_of(overrideData.propertyTypes.cbegin(), | |||
| 6987 | overrideData.propertyTypes.cend(), | |||
| 6988 | [](std::int32_t type) { return type >= 0 && type <= 3; })) | |||
| 6989 | return false; | |||
| 6990 | } | |||
| 6991 | return validateGeometry(); | |||
| 6992 | } | |||
| 6993 | ||||
| 6994 | bool DRW_Mesh::encodeDwg(DRW::Version dwgVersion, dwgBufferW *buf, std::uint32_t bs, | |||
| 6995 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 6996 | (void)bs; (void)strBuf; | |||
| 6997 | if (!validateGeometry()) | |||
| 6998 | return false; | |||
| 6999 | ||||
| 7000 | std::int32_t faceStreamCount = 0; | |||
| 7001 | for (const auto& face : faces) | |||
| 7002 | faceStreamCount += static_cast<std::int32_t>(face.size() + 1); | |||
| 7003 | ||||
| 7004 | oType = kDwgClassNum; | |||
| 7005 | if (!encodeDwgCommon(dwgVersion, buf)) return false; | |||
| 7006 | ||||
| 7007 | buf->putBitShort(version); | |||
| 7008 | buf->putBit(blendCrease ? 1 : 0); | |||
| 7009 | ||||
| 7010 | buf->putBitLong(subdivisionLevel); | |||
| 7011 | ||||
| 7012 | buf->putBitLong(static_cast<std::int32_t>(vertices.size())); | |||
| 7013 | for (const DRW_Coord& vertex : vertices) | |||
| 7014 | buf->put3BitDouble(vertex); | |||
| 7015 | ||||
| 7016 | buf->putBitLong(faceStreamCount); | |||
| 7017 | for (const auto& face : faces) { | |||
| 7018 | buf->putBitLong(static_cast<std::int32_t>(face.size())); | |||
| 7019 | for (std::int32_t index : face) | |||
| 7020 | buf->putBitLong(index); | |||
| 7021 | } | |||
| 7022 | ||||
| 7023 | buf->putBitLong(static_cast<std::int32_t>(edges.size())); | |||
| 7024 | for (const auto& edge : edges) { | |||
| 7025 | buf->putBitLong(edge.first); | |||
| 7026 | buf->putBitLong(edge.second); | |||
| 7027 | } | |||
| 7028 | ||||
| 7029 | buf->putBitLong(static_cast<std::int32_t>(creases.size())); | |||
| 7030 | for (double crease : creases) | |||
| 7031 | buf->putBitDouble(crease); | |||
| 7032 | ||||
| 7033 | buf->putBitLong(unknown); | |||
| 7034 | ||||
| 7035 | return encodeDwgEntHandle(dwgVersion, buf, handleBuf); | |||
| 7036 | } | |||
| 7037 | ||||
| 7038 | bool DRW_Shape::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 7039 | switch (code) { | |||
| 7040 | case 2: | |||
| 7041 | m_styleName = reader->getUtf8String(); | |||
| 7042 | break; | |||
| 7043 | case 10: | |||
| 7044 | m_insertionPoint.x = reader->getDouble(); | |||
| 7045 | break; | |||
| 7046 | case 20: | |||
| 7047 | m_insertionPoint.y = reader->getDouble(); | |||
| 7048 | break; | |||
| 7049 | case 30: | |||
| 7050 | m_insertionPoint.z = reader->getDouble(); | |||
| 7051 | break; | |||
| 7052 | case 39: | |||
| 7053 | m_thickness = reader->getDouble(); | |||
| 7054 | break; | |||
| 7055 | case 40: | |||
| 7056 | m_scale = reader->getDouble(); | |||
| 7057 | break; | |||
| 7058 | case 41: | |||
| 7059 | m_widthFactor = reader->getDouble(); | |||
| 7060 | break; | |||
| 7061 | case 50: | |||
| 7062 | m_rotation = reader->getDouble() / ARAD57.29577951308232; | |||
| 7063 | break; | |||
| 7064 | case 51: | |||
| 7065 | m_oblique = reader->getDouble() / ARAD57.29577951308232; | |||
| 7066 | break; | |||
| 7067 | case 210: | |||
| 7068 | m_extrusion.x = reader->getDouble(); | |||
| 7069 | break; | |||
| 7070 | case 220: | |||
| 7071 | m_extrusion.y = reader->getDouble(); | |||
| 7072 | break; | |||
| 7073 | case 230: | |||
| 7074 | m_extrusion.z = reader->getDouble(); | |||
| 7075 | break; | |||
| 7076 | default: | |||
| 7077 | return DRW_Entity::parseCode(code, reader); | |||
| 7078 | } | |||
| 7079 | return true; | |||
| 7080 | } | |||
| 7081 | ||||
| 7082 | void DRW_Shape::resetDwgState() { | |||
| 7083 | DRW_Entity::reset(); | |||
| 7084 | m_insertionPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7085 | m_scale = 1.0; | |||
| 7086 | m_rotation = 0.0; | |||
| 7087 | m_widthFactor = 1.0; | |||
| 7088 | m_oblique = 0.0; | |||
| 7089 | m_thickness = 0.0; | |||
| 7090 | m_shapeIndex = 0; | |||
| 7091 | m_extrusion = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 7092 | m_shapeFileHandle = 0; | |||
| 7093 | m_objectSize = 0; | |||
| 7094 | m_bodyBitSize = 0; | |||
| 7095 | m_rawBytes.clear(); | |||
| 7096 | } | |||
| 7097 | ||||
| 7098 | bool DRW_Shape::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 7099 | resetDwgState(); | |||
| 7100 | dwgBuffer *sourceBuf = buf; | |||
| 7101 | auto fail = [this, sourceBuf]() { | |||
| 7102 | if (sourceBuf != nullptr) | |||
| 7103 | sourceBuf->invalidate(); | |||
| 7104 | resetDwgState(); | |||
| 7105 | return false; | |||
| 7106 | }; | |||
| 7107 | if (sourceBuf == nullptr) | |||
| 7108 | return fail(); | |||
| 7109 | ||||
| 7110 | m_bodyBitSize = bs; | |||
| 7111 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7112 | if (!DRW_Entity::parseDwgCommon(v, &bodyProbe, bs)) | |||
| 7113 | return fail(); | |||
| 7114 | DRW_DBG("\n***************************** parsing SHAPE *****************************\n")DRW_dbg::dbg("\n***************************** parsing SHAPE *****************************\n" ); | |||
| 7115 | ||||
| 7116 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 7117 | DRW_Coord insertionPoint; | |||
| 7118 | DRW_Coord extrusion; | |||
| 7119 | double scale = 0.0; | |||
| 7120 | double rotation = 0.0; | |||
| 7121 | double widthFactor = 0.0; | |||
| 7122 | double oblique = 0.0; | |||
| 7123 | double thickness = 0.0; | |||
| 7124 | std::uint16_t shapeIndex = 0; | |||
| 7125 | if (!readBounded3BitDouble(bodyProbe, bodyEndBit, insertionPoint) | |||
| 7126 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, scale) | |||
| 7127 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, rotation) | |||
| 7128 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, widthFactor) | |||
| 7129 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, oblique) | |||
| 7130 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, thickness) | |||
| 7131 | || !readBoundedBitShort(bodyProbe, bodyEndBit, shapeIndex) | |||
| 7132 | || !readBounded3BitDouble(bodyProbe, bodyEndBit, extrusion)) | |||
| 7133 | return fail(); | |||
| 7134 | const auto finite = [](const DRW_Coord& point) { | |||
| 7135 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 7136 | && std::isfinite(point.z); | |||
| 7137 | }; | |||
| 7138 | if (!bodyProbe.isGood() || !finite(insertionPoint) || !finite(extrusion) | |||
| 7139 | || !std::isfinite(scale) || !std::isfinite(rotation) | |||
| 7140 | || !std::isfinite(widthFactor) || !std::isfinite(oblique) | |||
| 7141 | || !std::isfinite(thickness)) | |||
| 7142 | return fail(); | |||
| 7143 | ||||
| 7144 | std::uint64_t handleEndBit = 0; | |||
| 7145 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 7146 | return fail(); | |||
| 7147 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7148 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 7149 | || !handleProbe.isGood()) | |||
| 7150 | return fail(); | |||
| 7151 | ||||
| 7152 | // DwgObjectFrame removes the CRC trailer before exposing the body. The | |||
| 7153 | // SHAPEFILE hard pointer is therefore mandatory and must be parsed even | |||
| 7154 | // when only its exact handle bytes remain. | |||
| 7155 | dwgHandle shapeFileH; | |||
| 7156 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 7157 | shapeFileH) | |||
| 7158 | || shapeFileH.ref == 0) | |||
| 7159 | return fail(); | |||
| 7160 | ||||
| 7161 | m_insertionPoint = insertionPoint; | |||
| 7162 | m_scale = scale; | |||
| 7163 | m_rotation = rotation; | |||
| 7164 | m_widthFactor = widthFactor; | |||
| 7165 | m_oblique = oblique; | |||
| 7166 | m_thickness = thickness; | |||
| 7167 | m_shapeIndex = shapeIndex; | |||
| 7168 | m_extrusion = extrusion; | |||
| 7169 | m_shapeFileHandle = shapeFileH.ref; | |||
| 7170 | DRW_DBG(" SHAPEFILE Handle: ")DRW_dbg::dbg(" SHAPEFILE Handle: "); | |||
| 7171 | DRW_DBGHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref)DRW_dbg::dbgHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref ); | |||
| 7172 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 7173 | *sourceBuf = handleProbe; | |||
| 7174 | return true; | |||
| 7175 | } | |||
| 7176 | ||||
| 7177 | // Phase 6.1: SHAPE encoder (fixed oType 33). Exact inverse of parseDwg above. | |||
| 7178 | // Without this override a SHAPE would encode as a LINE (default DRW_Entity). | |||
| 7179 | bool DRW_Shape::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 7180 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 7181 | (void)bs; (void)strBuf; | |||
| 7182 | const auto finite = [](const DRW_Coord& point) { | |||
| 7183 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 7184 | && std::isfinite(point.z); | |||
| 7185 | }; | |||
| 7186 | if (!finite(m_insertionPoint) || !finite(m_extrusion) | |||
| 7187 | || !std::isfinite(m_scale) || !std::isfinite(m_rotation) | |||
| 7188 | || !std::isfinite(m_widthFactor) || !std::isfinite(m_oblique) | |||
| 7189 | || !std::isfinite(m_thickness) || m_shapeFileHandle == 0) { | |||
| 7190 | return false; | |||
| 7191 | } | |||
| 7192 | oType = 33; // SHAPE class id — see dwgreader.cpp case 33 | |||
| 7193 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 7194 | ||||
| 7195 | buf->put3BitDouble(m_insertionPoint); | |||
| 7196 | buf->putBitDouble(m_scale); | |||
| 7197 | buf->putBitDouble(m_rotation); | |||
| 7198 | buf->putBitDouble(m_widthFactor); | |||
| 7199 | buf->putBitDouble(m_oblique); | |||
| 7200 | buf->putBitDouble(m_thickness); | |||
| 7201 | buf->putBitShort(m_shapeIndex); | |||
| 7202 | buf->put3BitDouble(m_extrusion); | |||
| 7203 | ||||
| 7204 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 7205 | ||||
| 7206 | // Trailing SHAPEFILE style hard pointer (code 5), byte-count-sized. | |||
| 7207 | dwgHandle sH; | |||
| 7208 | sH.code = 5; | |||
| 7209 | sH.ref = m_shapeFileHandle; | |||
| 7210 | sH.size = 0; | |||
| 7211 | if (m_shapeFileHandle != 0) { | |||
| 7212 | std::uint32_t t = m_shapeFileHandle; | |||
| 7213 | while (t != 0) { t >>= 8; ++sH.size; } | |||
| 7214 | } else { | |||
| 7215 | sH.code = 0; // null handle | |||
| 7216 | } | |||
| 7217 | (handleBuf ? handleBuf : buf)->putHandle(sH); | |||
| 7218 | return true; | |||
| 7219 | } | |||
| 7220 | ||||
| 7221 | bool DRW_Ole2Frame::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 7222 | const auto readUnsigned = [&](std::uint32_t maximum, | |||
| 7223 | std::uint32_t& target) { | |||
| 7224 | const int value = reader->getInt32(); | |||
| 7225 | if (value < 0 || static_cast<std::uint32_t>(value) > maximum) | |||
| 7226 | return false; | |||
| 7227 | target = static_cast<std::uint32_t>(value); | |||
| 7228 | return true; | |||
| 7229 | }; | |||
| 7230 | ||||
| 7231 | switch (code) { | |||
| 7232 | case 3: | |||
| 7233 | m_oleClient = reader->getUtf8String(); | |||
| 7234 | break; | |||
| 7235 | case 10: | |||
| 7236 | m_pt1.x = reader->getDouble(); | |||
| 7237 | break; | |||
| 7238 | case 20: | |||
| 7239 | m_pt1.y = reader->getDouble(); | |||
| 7240 | break; | |||
| 7241 | case 30: | |||
| 7242 | m_pt1.z = reader->getDouble(); | |||
| 7243 | break; | |||
| 7244 | case 11: | |||
| 7245 | m_pt2.x = reader->getDouble(); | |||
| 7246 | break; | |||
| 7247 | case 21: | |||
| 7248 | m_pt2.y = reader->getDouble(); | |||
| 7249 | break; | |||
| 7250 | case 31: | |||
| 7251 | m_pt2.z = reader->getDouble(); | |||
| 7252 | break; | |||
| 7253 | case 70: { | |||
| 7254 | std::uint32_t value = 0; | |||
| 7255 | if (!readUnsigned(std::numeric_limits<std::uint16_t>::max(), value)) | |||
| 7256 | return false; | |||
| 7257 | m_oleVersion = static_cast<std::uint16_t>(value); | |||
| 7258 | break; | |||
| 7259 | } | |||
| 7260 | case 71: { | |||
| 7261 | std::uint32_t value = 0; | |||
| 7262 | if (!readUnsigned(std::numeric_limits<std::uint16_t>::max(), value)) | |||
| 7263 | return false; | |||
| 7264 | m_flags = static_cast<std::uint16_t>(value); | |||
| 7265 | break; | |||
| 7266 | } | |||
| 7267 | case 72: { | |||
| 7268 | std::uint32_t value = 0; | |||
| 7269 | if (!readUnsigned(std::numeric_limits<std::uint16_t>::max(), value)) | |||
| 7270 | return false; | |||
| 7271 | m_mode = static_cast<std::uint16_t>(value); | |||
| 7272 | break; | |||
| 7273 | } | |||
| 7274 | case 73: { | |||
| 7275 | std::uint32_t value = 0; | |||
| 7276 | if (!readUnsigned(std::numeric_limits<std::uint8_t>::max(), value)) | |||
| 7277 | return false; | |||
| 7278 | m_lockAspect = static_cast<std::uint8_t>(value); | |||
| 7279 | break; | |||
| 7280 | } | |||
| 7281 | case 90: { | |||
| 7282 | std::uint32_t value = 0; | |||
| 7283 | if (!readUnsigned(kMaxOlePayloadBytes, value)) | |||
| 7284 | return false; | |||
| 7285 | m_declaredPayloadLength = value; | |||
| 7286 | m_dxfPayloadLengthSpecified = true; | |||
| 7287 | m_payloadPresent = value != 0; | |||
| 7288 | break; | |||
| 7289 | } | |||
| 7290 | case 310: { | |||
| 7291 | std::vector<std::uint8_t> bytes; | |||
| 7292 | if (!decodeHexBytes(reader->getString(), bytes)) | |||
| 7293 | return false; | |||
| 7294 | if (!appendBytesChecked(m_payloadBytes, bytes, | |||
| 7295 | kMaxOlePayloadBytes)) { | |||
| 7296 | m_payloadTooLarge = m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7297 | || bytes.size() > kMaxOlePayloadBytes - | |||
| 7298 | std::min(m_payloadBytes.size(), | |||
| 7299 | static_cast<std::size_t>( | |||
| 7300 | kMaxOlePayloadBytes)); | |||
| 7301 | return false; | |||
| 7302 | } | |||
| 7303 | m_payloadPresent = true; | |||
| 7304 | break; | |||
| 7305 | } | |||
| 7306 | default: | |||
| 7307 | return DRW_Entity::parseCode(code, reader); | |||
| 7308 | } | |||
| 7309 | return true; | |||
| 7310 | } | |||
| 7311 | ||||
| 7312 | void DRW_Ole2Frame::resetDwgState() { | |||
| 7313 | DRW_Entity::reset(); | |||
| 7314 | m_flags = 0; | |||
| 7315 | m_mode = 0; | |||
| 7316 | m_declaredPayloadLength = 0; | |||
| 7317 | m_payloadByteCount = 0; | |||
| 7318 | m_payloadStartBit = 0; | |||
| 7319 | m_payloadPresent = false; | |||
| 7320 | m_payloadTruncated = false; | |||
| 7321 | m_payloadTooLarge = false; | |||
| 7322 | m_hasR2000TrailingByte = false; | |||
| 7323 | m_r2000TrailingByte = 0; | |||
| 7324 | m_objectSize = 0; | |||
| 7325 | m_bodyBitSize = 0; | |||
| 7326 | m_payloadBytes.clear(); | |||
| 7327 | m_pt1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7328 | m_pt2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7329 | m_lockAspect = 3; | |||
| 7330 | m_dxfPayloadLengthSpecified = false; | |||
| 7331 | m_oleVersion = 2; | |||
| 7332 | m_oleClient = "OLE"; | |||
| 7333 | m_rawBytes.clear(); | |||
| 7334 | } | |||
| 7335 | ||||
| 7336 | bool DRW_Ole2Frame::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 7337 | resetDwgState(); | |||
| 7338 | dwgBuffer *sourceBuf = buf; | |||
| 7339 | auto fail = [this, sourceBuf]() { | |||
| 7340 | if (sourceBuf != nullptr) | |||
| 7341 | sourceBuf->invalidate(); | |||
| 7342 | resetDwgState(); | |||
| 7343 | return false; | |||
| 7344 | }; | |||
| 7345 | if (sourceBuf == nullptr) | |||
| 7346 | return fail(); | |||
| 7347 | ||||
| 7348 | m_bodyBitSize = bs; | |||
| 7349 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7350 | if (!DRW_Entity::parseDwgCommon(v, &bodyProbe, bs)) | |||
| 7351 | return fail(); | |||
| 7352 | DRW_DBG("\n***************************** parsing OLE2FRAME ************************\n")DRW_dbg::dbg("\n***************************** parsing OLE2FRAME ************************\n" ); | |||
| 7353 | ||||
| 7354 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 7355 | std::uint16_t parsedFlags = 0; | |||
| 7356 | std::uint16_t parsedMode = 0; | |||
| 7357 | std::int32_t declaredLength = 0; | |||
| 7358 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedFlags) | |||
| 7359 | || (v > DRW::AC1014 | |||
| 7360 | && !readBoundedBitShort(bodyProbe, bodyEndBit, parsedMode)) | |||
| 7361 | || !readBoundedBitLong(bodyProbe, bodyEndBit, declaredLength) | |||
| 7362 | || declaredLength < 0 | |||
| 7363 | || static_cast<std::uint32_t>(declaredLength) > kMaxOlePayloadBytes) | |||
| 7364 | return fail(); | |||
| 7365 | ||||
| 7366 | const std::uint64_t payloadStartBit = currentDwgBit(&bodyProbe); | |||
| 7367 | const auto bodyRemainingBits = [&](const dwgBuffer& cursor, | |||
| 7368 | std::uint64_t& remaining) { | |||
| 7369 | const std::uint64_t currentBit = currentDwgBit(&cursor); | |||
| 7370 | if (v > DRW::AC1014 && objSize != 0) { | |||
| 7371 | if (currentBit > bodyEndBit) | |||
| 7372 | return false; | |||
| 7373 | remaining = bodyEndBit - currentBit; | |||
| 7374 | return true; | |||
| 7375 | } | |||
| 7376 | const int bytes = cursor.numRemainingBytes(); | |||
| 7377 | if (bytes < 0) | |||
| 7378 | return false; | |||
| 7379 | remaining = static_cast<std::uint64_t>(bytes) * 8u; | |||
| 7380 | return true; | |||
| 7381 | }; | |||
| 7382 | ||||
| 7383 | std::uint64_t remainingBits = 0; | |||
| 7384 | if (!bodyRemainingBits(bodyProbe, remainingBits)) | |||
| 7385 | return fail(); | |||
| 7386 | const std::uint64_t trailingBits = v > DRW::AC1014 ? 8u : 0u; | |||
| 7387 | if (remainingBits < trailingBits | |||
| 7388 | || static_cast<std::uint64_t>(declaredLength) | |||
| 7389 | > (remainingBits - trailingBits) / 8u) | |||
| 7390 | return fail(); | |||
| 7391 | ||||
| 7392 | std::vector<std::uint8_t> payload; | |||
| 7393 | if (!DRW::resize(payload, declaredLength)) | |||
| 7394 | return fail(); | |||
| 7395 | if (!readBoundedBytes(bodyProbe, bodyEndBit, payload.data(), | |||
| 7396 | payload.size())) | |||
| 7397 | return fail(); | |||
| 7398 | ||||
| 7399 | std::uint8_t trailingByte = 0; | |||
| 7400 | bool hasTrailingByte = false; | |||
| 7401 | if (v > DRW::AC1014) { | |||
| 7402 | if (!bodyRemainingBits(bodyProbe, remainingBits) | |||
| 7403 | || (remainingBits != 0 && remainingBits < 8)) | |||
| 7404 | return fail(); | |||
| 7405 | if (remainingBits >= 8) { | |||
| 7406 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, trailingByte)) | |||
| 7407 | return fail(); | |||
| 7408 | hasTrailingByte = true; | |||
| 7409 | } | |||
| 7410 | } | |||
| 7411 | ||||
| 7412 | // Decode the frame rectangle (DXF 10/11) from the OLE header. AutoCAD/ODA do | |||
| 7413 | // NOT store pt1/pt2 as DWG fields; they live in the first ~0x80 bytes of the | |||
| 7414 | // payload as raw little-endian doubles. Guarded so a non-finite/short | |||
| 7415 | // payload simply leaves both points at the origin. | |||
| 7416 | DRW_Coord point1; | |||
| 7417 | DRW_Coord point2; | |||
| 7418 | if (payload.size() >= 0x4a && payload[0] == 0x80) { | |||
| 7419 | auto rd = [&](std::size_t off) { | |||
| 7420 | double value = 0.0; | |||
| 7421 | std::memcpy(&value, payload.data() + off, sizeof(double)); | |||
| 7422 | return value; | |||
| 7423 | }; | |||
| 7424 | const DRW_Coord upperLeft(rd(0x02), rd(0x0a), rd(0x12)); | |||
| 7425 | const DRW_Coord lowerRight(rd(0x32), rd(0x3a), rd(0x42)); | |||
| 7426 | if (std::isfinite(upperLeft.x) && std::isfinite(upperLeft.y) | |||
| 7427 | && std::isfinite(upperLeft.z) && std::isfinite(lowerRight.x) | |||
| 7428 | && std::isfinite(lowerRight.y) && std::isfinite(lowerRight.z)) { | |||
| 7429 | point1 = upperLeft; | |||
| 7430 | point2 = lowerRight; | |||
| 7431 | } | |||
| 7432 | } | |||
| 7433 | ||||
| 7434 | std::uint64_t handleEndBit = 0; | |||
| 7435 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 7436 | return fail(); | |||
| 7437 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7438 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 7439 | || !handleProbe.isGood()) | |||
| 7440 | return fail(); | |||
| 7441 | ||||
| 7442 | m_flags = parsedFlags; | |||
| 7443 | m_mode = parsedMode; | |||
| 7444 | m_declaredPayloadLength = static_cast<std::uint32_t>(declaredLength); | |||
| 7445 | m_payloadStartBit = payloadStartBit; | |||
| 7446 | m_payloadPresent = declaredLength > 0; | |||
| 7447 | m_payloadByteCount = static_cast<std::uint32_t>(declaredLength); | |||
| 7448 | m_payloadBytes = std::move(payload); | |||
| 7449 | m_hasR2000TrailingByte = hasTrailingByte; | |||
| 7450 | m_r2000TrailingByte = trailingByte; | |||
| 7451 | m_pt1 = point1; | |||
| 7452 | m_pt2 = point2; | |||
| 7453 | *sourceBuf = handleProbe; | |||
| 7454 | return true; | |||
| 7455 | } | |||
| 7456 | ||||
| 7457 | // Phase 6.2: OLE2FRAME encoder (fixed oType 74). Inverse of parseDwg, emitting | |||
| 7458 | // the captured opaque payload byte-for-byte. Without this override an OLE2FRAME | |||
| 7459 | // would encode as a LINE. | |||
| 7460 | bool DRW_Ole2Frame::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 7461 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 7462 | (void)bs; (void)strBuf; | |||
| 7463 | if (m_payloadTooLarge || m_payloadTruncated | |||
| 7464 | || m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7465 | || (m_payloadPresent | |||
| 7466 | && m_declaredPayloadLength != m_payloadBytes.size())) { | |||
| 7467 | return false; | |||
| 7468 | } | |||
| 7469 | oType = 74; // OLE2FRAME class id — see dwgreader.cpp case 74 | |||
| 7470 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 7471 | ||||
| 7472 | buf->putBitShort(m_flags); | |||
| 7473 | if (version > DRW::AC1014) | |||
| 7474 | buf->putBitShort(m_mode); | |||
| 7475 | // Emit the actual captured length so the reader's data_size matches the | |||
| 7476 | // bytes that follow (avoids a declared-vs-actual mismatch on re-read). | |||
| 7477 | const std::uint32_t payloadLen = static_cast<std::uint32_t>(m_payloadBytes.size()); | |||
| 7478 | buf->putBitLong(static_cast<std::int32_t>(payloadLen)); | |||
| 7479 | if (payloadLen > 0) | |||
| 7480 | buf->putBytes(m_payloadBytes.data(), m_payloadBytes.size()); | |||
| 7481 | // R2000+ Unknown RC (ODA §20.4.88): emitted UNCONDITIONALLY for version > | |||
| 7482 | // AC1014. parseDwg reads it whenever bytes remain before the handle stream | |||
| 7483 | // (which is always — handle data always follows), so gating the write on | |||
| 7484 | // m_hasR2000TrailingByte desynced a directly-constructed OLE2FRAME (the | |||
| 7485 | // default false): the parser consumed the first handle byte as this RC and | |||
| 7486 | // shifted the entity handle stream. Default m_r2000TrailingByte is 0, so | |||
| 7487 | // constructed entities align and round-tripped ones keep the captured byte. | |||
| 7488 | if (version > DRW::AC1014) | |||
| 7489 | buf->putRawChar8(m_r2000TrailingByte); | |||
| 7490 | ||||
| 7491 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 7492 | } | |||
| 7493 | ||||
| 7494 | bool DRW_OleFrame::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 7495 | switch (code) { | |||
| 7496 | case 70: { | |||
| 7497 | const int value = reader->getInt32(); | |||
| 7498 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 7499 | return false; | |||
| 7500 | m_flags = static_cast<std::uint16_t>(value); | |||
| 7501 | break; | |||
| 7502 | } | |||
| 7503 | case 90: { | |||
| 7504 | const int value = reader->getInt32(); | |||
| 7505 | if (value < 0 | |||
| 7506 | || static_cast<std::uint32_t>(value) > kMaxOlePayloadBytes) { | |||
| 7507 | m_payloadTooLarge = value >= 0; | |||
| 7508 | return false; | |||
| 7509 | } | |||
| 7510 | m_declaredPayloadLength = static_cast<std::uint32_t>(value); | |||
| 7511 | m_dxfPayloadLengthSpecified = true; | |||
| 7512 | m_payloadPresent = value != 0; | |||
| 7513 | break; | |||
| 7514 | } | |||
| 7515 | case 310: { | |||
| 7516 | std::vector<std::uint8_t> bytes; | |||
| 7517 | if (!decodeHexBytes(reader->getString(), bytes)) | |||
| 7518 | return false; | |||
| 7519 | if (!appendBytesChecked(m_payloadBytes, bytes, | |||
| 7520 | kMaxOlePayloadBytes)) { | |||
| 7521 | m_payloadTooLarge = m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7522 | || bytes.size() > kMaxOlePayloadBytes - | |||
| 7523 | std::min(m_payloadBytes.size(), | |||
| 7524 | static_cast<std::size_t>( | |||
| 7525 | kMaxOlePayloadBytes)); | |||
| 7526 | return false; | |||
| 7527 | } | |||
| 7528 | m_payloadPresent = true; | |||
| 7529 | break; | |||
| 7530 | } | |||
| 7531 | default: | |||
| 7532 | return DRW_Entity::parseCode(code, reader); | |||
| 7533 | } | |||
| 7534 | return true; | |||
| 7535 | } | |||
| 7536 | ||||
| 7537 | void DRW_OleFrame::resetDwgState() { | |||
| 7538 | DRW_Entity::reset(); | |||
| 7539 | m_flags = 0; | |||
| 7540 | m_mode = 0; | |||
| 7541 | m_declaredPayloadLength = 0; | |||
| 7542 | m_payloadByteCount = 0; | |||
| 7543 | m_payloadPresent = false; | |||
| 7544 | m_payloadTruncated = false; | |||
| 7545 | m_payloadTooLarge = false; | |||
| 7546 | m_objectSize = 0; | |||
| 7547 | m_bodyBitSize = 0; | |||
| 7548 | m_payloadBytes.clear(); | |||
| 7549 | m_dxfPayloadLengthSpecified = false; | |||
| 7550 | m_rawBytes.clear(); | |||
| 7551 | } | |||
| 7552 | ||||
| 7553 | bool DRW_OleFrame::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 7554 | std::uint32_t bs) { | |||
| 7555 | resetDwgState(); | |||
| 7556 | dwgBuffer *sourceBuf = buf; | |||
| 7557 | auto fail = [this, sourceBuf]() { | |||
| 7558 | if (sourceBuf != nullptr) | |||
| 7559 | sourceBuf->invalidate(); | |||
| 7560 | resetDwgState(); | |||
| 7561 | return false; | |||
| 7562 | }; | |||
| 7563 | if (sourceBuf == nullptr) | |||
| 7564 | return fail(); | |||
| 7565 | ||||
| 7566 | m_bodyBitSize = bs; | |||
| 7567 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7568 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs)) | |||
| 7569 | return fail(); | |||
| 7570 | ||||
| 7571 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 7572 | std::uint16_t parsedFlags = 0; | |||
| 7573 | std::uint16_t parsedMode = 0; | |||
| 7574 | std::int32_t declaredLength = 0; | |||
| 7575 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedFlags) | |||
| 7576 | || (version > DRW::AC1014 | |||
| 7577 | && !readBoundedBitShort(bodyProbe, bodyEndBit, parsedMode)) | |||
| 7578 | || !readBoundedBitLong(bodyProbe, bodyEndBit, declaredLength) | |||
| 7579 | || declaredLength < 0 | |||
| 7580 | || static_cast<std::uint32_t>(declaredLength) > kMaxOlePayloadBytes) | |||
| 7581 | return fail(); | |||
| 7582 | ||||
| 7583 | std::uint64_t bodyRemainingBits = 0; | |||
| 7584 | const std::uint64_t currentBit = currentDwgBit(&bodyProbe); | |||
| 7585 | if (version > DRW::AC1014 && objSize != 0) { | |||
| 7586 | if (currentBit > bodyEndBit) | |||
| 7587 | return fail(); | |||
| 7588 | bodyRemainingBits = bodyEndBit - currentBit; | |||
| 7589 | } else { | |||
| 7590 | const int remainingBytes = bodyProbe.numRemainingBytes(); | |||
| 7591 | if (remainingBytes < 0) | |||
| 7592 | return fail(); | |||
| 7593 | bodyRemainingBits = static_cast<std::uint64_t>(remainingBytes) * 8u; | |||
| 7594 | } | |||
| 7595 | ||||
| 7596 | if (static_cast<std::uint64_t>(declaredLength) > bodyRemainingBits / 8u) | |||
| 7597 | return fail(); | |||
| 7598 | std::vector<std::uint8_t> payload; | |||
| 7599 | if (!DRW::resize(payload, declaredLength)) | |||
| 7600 | return fail(); | |||
| 7601 | if (!readBoundedBytes(bodyProbe, bodyEndBit, payload.data(), | |||
| 7602 | payload.size())) | |||
| 7603 | return fail(); | |||
| 7604 | ||||
| 7605 | std::uint64_t handleEndBit = 0; | |||
| 7606 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 7607 | handleEndBit)) | |||
| 7608 | return fail(); | |||
| 7609 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7610 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 7611 | handleEndBit) | |||
| 7612 | || !handleProbe.isGood()) | |||
| 7613 | return fail(); | |||
| 7614 | ||||
| 7615 | m_flags = parsedFlags; | |||
| 7616 | m_mode = parsedMode; | |||
| 7617 | m_declaredPayloadLength = static_cast<std::uint32_t>(declaredLength); | |||
| 7618 | m_payloadPresent = declaredLength != 0; | |||
| 7619 | m_payloadByteCount = static_cast<std::uint32_t>(declaredLength); | |||
| 7620 | m_payloadBytes = std::move(payload); | |||
| 7621 | *sourceBuf = handleProbe; | |||
| 7622 | return true; | |||
| 7623 | ||||
| 7624 | } | |||
| 7625 | ||||
| 7626 | bool DRW_OleFrame::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 7627 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 7628 | dwgBufferW *handleBuf) { | |||
| 7629 | (void)bs; | |||
| 7630 | (void)strBuf; | |||
| 7631 | if (buf == nullptr || m_payloadTooLarge || m_payloadTruncated | |||
| 7632 | || m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7633 | || (m_payloadPresent | |||
| 7634 | && m_declaredPayloadLength != m_payloadBytes.size())) { | |||
| 7635 | return false; | |||
| 7636 | } | |||
| 7637 | ||||
| 7638 | oType = 43; | |||
| 7639 | if (!encodeDwgCommon(version, buf)) | |||
| 7640 | return false; | |||
| 7641 | buf->putBitShort(m_flags); | |||
| 7642 | if (version > DRW::AC1014) | |||
| 7643 | buf->putBitShort(m_mode); | |||
| 7644 | const std::uint32_t payloadLength = | |||
| 7645 | static_cast<std::uint32_t>(m_payloadBytes.size()); | |||
| 7646 | buf->putBitLong(static_cast<std::int32_t>(payloadLength)); | |||
| 7647 | if (payloadLength != 0) | |||
| 7648 | buf->putBytes(m_payloadBytes.data(), m_payloadBytes.size()); | |||
| 7649 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 7650 | } | |||
| 7651 | ||||
| 7652 | void DRW_Light::resetDwgState() { | |||
| 7653 | DRW_Entity::reset(); | |||
| 7654 | m_classVersion = 0; | |||
| 7655 | m_name.clear(); | |||
| 7656 | m_type = 0; | |||
| 7657 | m_status = false; | |||
| 7658 | m_color = 0; | |||
| 7659 | m_plotGlyph = false; | |||
| 7660 | m_intensity = 0.0; | |||
| 7661 | m_position = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7662 | m_target = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7663 | m_attenuationType = 0; | |||
| 7664 | m_useAttenuationLimits = false; | |||
| 7665 | m_attenuationStartLimit = 0.0; | |||
| 7666 | m_attenuationEndLimit = 0.0; | |||
| 7667 | m_hotspotAngle = 0.0; | |||
| 7668 | m_falloffAngle = 0.0; | |||
| 7669 | m_castShadows = false; | |||
| 7670 | m_shadowType = 0; | |||
| 7671 | m_shadowMapSize = 0; | |||
| 7672 | m_shadowMapSoftness = 0; | |||
| 7673 | m_hasPhotometricData = false; | |||
| 7674 | m_hasWebFile = false; | |||
| 7675 | m_webFile.clear(); | |||
| 7676 | m_physicalIntensityMethod = 0; | |||
| 7677 | m_physicalIntensity = 0.0; | |||
| 7678 | m_illuminanceDistance = 0.0; | |||
| 7679 | m_lampColorType = 0; | |||
| 7680 | m_lampColorTemperature = 0.0; | |||
| 7681 | m_lampColorPreset = 0; | |||
| 7682 | m_webRotation = {1.0, 0.0, 0.0}; | |||
| 7683 | m_extendedLightShape = 0; | |||
| 7684 | m_extendedLightLength = 0.0; | |||
| 7685 | m_extendedLightWidth = 0.0; | |||
| 7686 | m_extendedLightRadius = 0.0; | |||
| 7687 | } | |||
| 7688 | ||||
| 7689 | bool DRW_Light::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 7690 | resetDwgState(); | |||
| 7691 | dwgBuffer *sourceBuf = buf; | |||
| 7692 | auto fail = [this, sourceBuf]() { | |||
| 7693 | if (sourceBuf != nullptr) | |||
| 7694 | sourceBuf->invalidate(); | |||
| 7695 | resetDwgState(); | |||
| 7696 | return false; | |||
| 7697 | }; | |||
| 7698 | if (sourceBuf == nullptr) | |||
| 7699 | return fail(); | |||
| 7700 | ||||
| 7701 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7702 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 7703 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 7704 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs) | |||
| 7705 | || !bodyProbe.isGood() || !stringProbe.isGood()) | |||
| 7706 | return fail(); | |||
| 7707 | DRW_DBG("\n***************************** parsing LIGHT *****************************\n")DRW_dbg::dbg("\n***************************** parsing LIGHT *****************************\n" ); | |||
| 7708 | ||||
| 7709 | const std::uint64_t bodyDataEndBit = dwgDataEndBit; | |||
| 7710 | std::uint64_t stringEndBit = bodyDataEndBit; | |||
| 7711 | if (stringStream != nullptr && v > DRW::AC1021) { | |||
| 7712 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 7713 | if (!entityBodyDataEndBit(*stringStream, v, objSize, | |||
| 7714 | ignoredBodyEndBit, &stringEndBit)) | |||
| 7715 | return fail(); | |||
| 7716 | } | |||
| 7717 | ||||
| 7718 | std::int32_t parsedClassVersion = 0; | |||
| 7719 | UTF8STRINGstd::string parsedName; | |||
| 7720 | std::int32_t parsedType = 0; | |||
| 7721 | bool parsedStatus = false; | |||
| 7722 | std::uint32_t parsedColor = 0; | |||
| 7723 | bool parsedPlotGlyph = false; | |||
| 7724 | double parsedIntensity = 0.0; | |||
| 7725 | DRW_Coord parsedPosition; | |||
| 7726 | DRW_Coord parsedTarget; | |||
| 7727 | std::int32_t parsedAttenuationType = 0; | |||
| 7728 | bool parsedUseAttenuationLimits = false; | |||
| 7729 | double parsedAttenuationStartLimit = 0.0; | |||
| 7730 | double parsedAttenuationEndLimit = 0.0; | |||
| 7731 | double parsedHotspotAngle = 0.0; | |||
| 7732 | double parsedFalloffAngle = 0.0; | |||
| 7733 | bool parsedCastShadows = false; | |||
| 7734 | std::int32_t parsedShadowType = 0; | |||
| 7735 | std::uint16_t parsedShadowMapSize = 0; | |||
| 7736 | std::uint8_t parsedShadowMapSoftness = 0; | |||
| 7737 | if (!readBoundedBitLong(bodyProbe, bodyDataEndBit, parsedClassVersion) | |||
| 7738 | || (stringStream != nullptr | |||
| 7739 | ? !readBoundedVariableText(stringProbe, stringEndBit, v, | |||
| 7740 | parsedName) | |||
| 7741 | : !readBoundedVariableText(bodyProbe, bodyDataEndBit, v, | |||
| 7742 | parsedName)) | |||
| 7743 | || !readBoundedBitLong(bodyProbe, bodyDataEndBit, parsedType) | |||
| 7744 | || !readBoundedBit(bodyProbe, bodyDataEndBit, parsedStatus) | |||
| 7745 | || !readBoundedCmColor(bodyProbe, stringStream, bodyDataEndBit, v, | |||
| 7746 | parsedColor, nullptr, nullptr, nullptr, | |||
| 7747 | nullptr, stringEndBit) | |||
| 7748 | || !readBoundedBit(bodyProbe, bodyDataEndBit, parsedPlotGlyph) | |||
| 7749 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, parsedIntensity) | |||
| 7750 | || !readBoundedBitCoord(bodyProbe, bodyDataEndBit, parsedPosition) | |||
| 7751 | || !readBoundedBitCoord(bodyProbe, bodyDataEndBit, parsedTarget) | |||
| 7752 | || !readBoundedBitLong(bodyProbe, bodyDataEndBit, | |||
| 7753 | parsedAttenuationType) | |||
| 7754 | || !readBoundedBit(bodyProbe, bodyDataEndBit, | |||
| 7755 | parsedUseAttenuationLimits) | |||
| 7756 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7757 | parsedAttenuationStartLimit) | |||
| 7758 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7759 | parsedAttenuationEndLimit) | |||
| 7760 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7761 | parsedHotspotAngle) | |||
| 7762 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7763 | parsedFalloffAngle) | |||
| 7764 | || !readBoundedBit(bodyProbe, bodyDataEndBit, parsedCastShadows) | |||
| 7765 | || !readBoundedBitLong(bodyProbe, bodyDataEndBit, parsedShadowType) | |||
| 7766 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7767 | parsedShadowMapSize) | |||
| 7768 | || !readBoundedRawChar8(bodyProbe, bodyDataEndBit, | |||
| 7769 | parsedShadowMapSoftness)) | |||
| 7770 | return fail(); | |||
| 7771 | ||||
| 7772 | bool hasPhotometricData = false; | |||
| 7773 | bool hasWebFile = false; | |||
| 7774 | UTF8STRINGstd::string webFile; | |||
| 7775 | std::uint16_t physicalIntensityMethod = 0; | |||
| 7776 | double physicalIntensity = 0.0; | |||
| 7777 | double illuminanceDistance = 0.0; | |||
| 7778 | std::uint16_t lampColorType = 0; | |||
| 7779 | double lampColorTemperature = 0.0; | |||
| 7780 | std::uint16_t lampColorPreset = 0; | |||
| 7781 | DRW_Coord webRotation{1.0, 0.0, 0.0}; | |||
| 7782 | std::uint16_t extendedLightShape = 0; | |||
| 7783 | double extendedLightLength = 0.0; | |||
| 7784 | double extendedLightWidth = 0.0; | |||
| 7785 | double extendedLightRadius = 0.0; | |||
| 7786 | if (v > DRW::AC1018 | |||
| 7787 | && proxyEntityHasBits(bodyProbe, bodyDataEndBit, 1)) { | |||
| 7788 | if (!readBoundedBit(bodyProbe, bodyDataEndBit, hasPhotometricData)) | |||
| 7789 | return fail(); | |||
| 7790 | if (hasPhotometricData) { | |||
| 7791 | if (!readBoundedBit(bodyProbe, bodyDataEndBit, hasWebFile) | |||
| 7792 | || !readBoundedVariableText(stringProbe, stringEndBit, v, | |||
| 7793 | webFile) | |||
| 7794 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7795 | physicalIntensityMethod) | |||
| 7796 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7797 | physicalIntensity) | |||
| 7798 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7799 | illuminanceDistance) | |||
| 7800 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7801 | lampColorType) | |||
| 7802 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7803 | lampColorTemperature) | |||
| 7804 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7805 | lampColorPreset) | |||
| 7806 | || !readBoundedBitCoord(bodyProbe, bodyDataEndBit, | |||
| 7807 | webRotation) | |||
| 7808 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7809 | extendedLightShape) | |||
| 7810 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7811 | extendedLightLength) | |||
| 7812 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7813 | extendedLightWidth) | |||
| 7814 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7815 | extendedLightRadius)) | |||
| 7816 | return fail(); | |||
| 7817 | } | |||
| 7818 | } | |||
| 7819 | ||||
| 7820 | const auto finite = [](const DRW_Coord& point) { | |||
| 7821 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 7822 | && std::isfinite(point.z); | |||
| 7823 | }; | |||
| 7824 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 7825 | || currentDwgBit(&bodyProbe) > bodyDataEndBit | |||
| 7826 | || (stringStream != nullptr && currentDwgBit(&stringProbe) > stringEndBit) | |||
| 7827 | || parsedClassVersion < 0 || parsedType < 0 | |||
| 7828 | || parsedAttenuationType < 0 || parsedShadowType < 0 | |||
| 7829 | || !finite(parsedPosition) || !finite(parsedTarget) | |||
| 7830 | || !finite(webRotation) | |||
| 7831 | || !std::isfinite(parsedIntensity) | |||
| 7832 | || !std::isfinite(parsedAttenuationStartLimit) | |||
| 7833 | || !std::isfinite(parsedAttenuationEndLimit) | |||
| 7834 | || !std::isfinite(parsedHotspotAngle) | |||
| 7835 | || !std::isfinite(parsedFalloffAngle) | |||
| 7836 | || !std::isfinite(physicalIntensity) | |||
| 7837 | || !std::isfinite(illuminanceDistance) | |||
| 7838 | || !std::isfinite(lampColorTemperature) | |||
| 7839 | || !std::isfinite(extendedLightLength) | |||
| 7840 | || !std::isfinite(extendedLightWidth) | |||
| 7841 | || !std::isfinite(extendedLightRadius)) | |||
| 7842 | return fail(); | |||
| 7843 | ||||
| 7844 | std::uint64_t handleEndBit = 0; | |||
| 7845 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 7846 | return fail(); | |||
| 7847 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7848 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 7849 | || !handleProbe.isGood()) | |||
| 7850 | return fail(); | |||
| 7851 | ||||
| 7852 | m_classVersion = static_cast<std::uint32_t>(parsedClassVersion); | |||
| 7853 | m_name = std::move(parsedName); | |||
| 7854 | m_type = static_cast<std::uint32_t>(parsedType); | |||
| 7855 | m_status = parsedStatus; | |||
| 7856 | m_color = parsedColor; | |||
| 7857 | m_plotGlyph = parsedPlotGlyph; | |||
| 7858 | m_intensity = parsedIntensity; | |||
| 7859 | m_position = parsedPosition; | |||
| 7860 | m_target = parsedTarget; | |||
| 7861 | m_attenuationType = static_cast<std::uint32_t>(parsedAttenuationType); | |||
| 7862 | m_useAttenuationLimits = parsedUseAttenuationLimits; | |||
| 7863 | m_attenuationStartLimit = parsedAttenuationStartLimit; | |||
| 7864 | m_attenuationEndLimit = parsedAttenuationEndLimit; | |||
| 7865 | m_hotspotAngle = parsedHotspotAngle; | |||
| 7866 | m_falloffAngle = parsedFalloffAngle; | |||
| 7867 | m_castShadows = parsedCastShadows; | |||
| 7868 | m_shadowType = static_cast<std::uint32_t>(parsedShadowType); | |||
| 7869 | m_shadowMapSize = parsedShadowMapSize; | |||
| 7870 | m_shadowMapSoftness = parsedShadowMapSoftness; | |||
| 7871 | m_hasPhotometricData = hasPhotometricData; | |||
| 7872 | m_hasWebFile = hasWebFile; | |||
| 7873 | m_webFile = std::move(webFile); | |||
| 7874 | m_physicalIntensityMethod = physicalIntensityMethod; | |||
| 7875 | m_physicalIntensity = physicalIntensity; | |||
| 7876 | m_illuminanceDistance = illuminanceDistance; | |||
| 7877 | m_lampColorType = lampColorType; | |||
| 7878 | m_lampColorTemperature = lampColorTemperature; | |||
| 7879 | m_lampColorPreset = lampColorPreset; | |||
| 7880 | m_webRotation = webRotation; | |||
| 7881 | m_extendedLightShape = extendedLightShape; | |||
| 7882 | m_extendedLightLength = extendedLightLength; | |||
| 7883 | m_extendedLightWidth = extendedLightWidth; | |||
| 7884 | m_extendedLightRadius = extendedLightRadius; | |||
| 7885 | 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"); | |||
| 7886 | *sourceBuf = handleProbe; | |||
| 7887 | return true; | |||
| 7888 | } | |||
| 7889 | ||||
| 7890 | bool DRW_Camera::parseCode(int code, | |||
| 7891 | const std::unique_ptr<dxfReader>& reader) { | |||
| 7892 | if (code == 340) { | |||
| 7893 | m_viewHandle = reader->getHandleString(); | |||
| 7894 | return true; | |||
| 7895 | } | |||
| 7896 | return DRW_Entity::parseCode(code, reader); | |||
| 7897 | } | |||
| 7898 | ||||
| 7899 | void DRW_Camera::resetDwgState() { | |||
| 7900 | DRW_Entity::reset(); | |||
| 7901 | m_viewHandle = 0; | |||
| 7902 | } | |||
| 7903 | ||||
| 7904 | bool DRW_Camera::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 7905 | std::uint32_t bs) { | |||
| 7906 | resetDwgState(); | |||
| 7907 | dwgBuffer *sourceBuf = buf; | |||
| 7908 | auto fail = [this, sourceBuf]() { | |||
| 7909 | if (sourceBuf != nullptr) | |||
| 7910 | sourceBuf->invalidate(); | |||
| 7911 | resetDwgState(); | |||
| 7912 | return false; | |||
| 7913 | }; | |||
| 7914 | if (sourceBuf == nullptr || v < DRW::AC1015) | |||
| 7915 | return fail(); | |||
| 7916 | ||||
| 7917 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7918 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 7919 | if (!DRW_Entity::parseDwg( | |||
| 7920 | v, &bodyProbe, v > DRW::AC1018 ? &stringProbe : nullptr, bs) | |||
| 7921 | || !bodyProbe.isGood() || !stringProbe.isGood()) | |||
| 7922 | return fail(); | |||
| 7923 | ||||
| 7924 | std::uint64_t handleEndBit = 0; | |||
| 7925 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 7926 | return fail(); | |||
| 7927 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7928 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 7929 | || !handleProbe.isGood()) | |||
| 7930 | return fail(); | |||
| 7931 | ||||
| 7932 | std::uint32_t viewHandle = 0; | |||
| 7933 | if (proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 7934 | dwgHandle viewH; | |||
| 7935 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, viewH)) | |||
| 7936 | return fail(); | |||
| 7937 | viewHandle = viewH.ref; | |||
| 7938 | } else if (currentDwgBit(&handleProbe) != handleEndBit) { | |||
| 7939 | return fail(); | |||
| 7940 | } | |||
| 7941 | ||||
| 7942 | m_viewHandle = viewHandle; | |||
| 7943 | *sourceBuf = handleProbe; | |||
| 7944 | return true; | |||
| 7945 | } | |||
| 7946 | ||||
| 7947 | bool DRW_Camera::encodeDwg(DRW::Version v, dwgBufferW *buf, | |||
| 7948 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 7949 | dwgBufferW *handleBuf) { | |||
| 7950 | (void)bs; | |||
| 7951 | if (v < DRW::AC1015 || buf == nullptr) | |||
| 7952 | return false; | |||
| 7953 | ||||
| 7954 | oType = kDwgClassNum; | |||
| 7955 | if (!encodeDwgCommon(v, buf, strBuf) | |||
| 7956 | || !encodeDwgEntHandle(v, buf, handleBuf)) { | |||
| 7957 | return false; | |||
| 7958 | } | |||
| 7959 | ||||
| 7960 | putHardPointerHandle(handleBuf ? handleBuf : buf, m_viewHandle); | |||
| 7961 | return true; | |||
| 7962 | } | |||
| 7963 | ||||
| 7964 | bool DRW_GeoPositionMarker::parseCode( | |||
| 7965 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 7966 | switch (code) { | |||
| 7967 | case 90: | |||
| 7968 | { | |||
| 7969 | int value = 0; | |||
| 7970 | if (!readDxfIntInRange(reader, 0, std::numeric_limits<int>::max(), value)) | |||
| 7971 | return false; | |||
| 7972 | m_classVersion = static_cast<std::uint32_t>(value); | |||
| 7973 | } | |||
| 7974 | return true; | |||
| 7975 | case 10: | |||
| 7976 | m_position.x = reader->getDouble(); | |||
| 7977 | return true; | |||
| 7978 | case 20: | |||
| 7979 | m_position.y = reader->getDouble(); | |||
| 7980 | return true; | |||
| 7981 | case 30: | |||
| 7982 | m_position.z = reader->getDouble(); | |||
| 7983 | return true; | |||
| 7984 | case 40: | |||
| 7985 | if (m_dxfDouble40Count++ == 0) | |||
| 7986 | m_radius = reader->getDouble(); | |||
| 7987 | else if (m_dxfDouble40Count == 2) | |||
| 7988 | m_landingGap = reader->getDouble(); | |||
| 7989 | else | |||
| 7990 | (void)reader->getDouble(); | |||
| 7991 | return true; | |||
| 7992 | case 1: | |||
| 7993 | m_notes = reader->getUtf8String(); | |||
| 7994 | return true; | |||
| 7995 | case 280: | |||
| 7996 | { | |||
| 7997 | const int value = reader->getInt32(); | |||
| 7998 | if (value < 0 || value > std::numeric_limits<std::uint8_t>::max()) | |||
| 7999 | return false; | |||
| 8000 | m_textAlignment = static_cast<std::uint8_t>(value); | |||
| 8001 | } | |||
| 8002 | return true; | |||
| 8003 | case 290: | |||
| 8004 | { | |||
| 8005 | int value = 0; | |||
| 8006 | if (!readDxfIntInRange(reader, 0, 1, value)) | |||
| 8007 | return false; | |||
| 8008 | if (m_dxfBool290Count++ == 0) | |||
| 8009 | m_mtextVisible = value != 0; | |||
| 8010 | else if (m_dxfBool290Count == 2) | |||
| 8011 | m_enableFrameText = value != 0; | |||
| 8012 | } | |||
| 8013 | return true; | |||
| 8014 | default: | |||
| 8015 | return DRW_Entity::parseCode(code, reader); | |||
| 8016 | } | |||
| 8017 | } | |||
| 8018 | ||||
| 8019 | bool DRW_GeoPositionMarker::parseDxfVariant(const DRW_Variant& value) { | |||
| 8020 | switch (value.code()) { | |||
| 8021 | case 90: | |||
| 8022 | if (value.type() != DRW_Variant::INTEGER) | |||
| 8023 | return false; | |||
| 8024 | if (value.i_val() < 0) | |||
| 8025 | return false; | |||
| 8026 | m_classVersion = static_cast<std::uint32_t>(value.i_val()); | |||
| 8027 | return true; | |||
| 8028 | case 10: | |||
| 8029 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 8030 | return false; | |||
| 8031 | m_position.x = value.d_val(); | |||
| 8032 | return true; | |||
| 8033 | case 20: | |||
| 8034 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 8035 | return false; | |||
| 8036 | m_position.y = value.d_val(); | |||
| 8037 | return true; | |||
| 8038 | case 30: | |||
| 8039 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 8040 | return false; | |||
| 8041 | m_position.z = value.d_val(); | |||
| 8042 | return true; | |||
| 8043 | case 40: | |||
| 8044 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 8045 | return false; | |||
| 8046 | if (m_dxfDouble40Count++ == 0) | |||
| 8047 | m_radius = value.d_val(); | |||
| 8048 | else if (m_dxfDouble40Count == 2) | |||
| 8049 | m_landingGap = value.d_val(); | |||
| 8050 | return true; | |||
| 8051 | case 1: | |||
| 8052 | if (value.type() != DRW_Variant::STRING) | |||
| 8053 | return false; | |||
| 8054 | m_notes = value.c_str(); | |||
| 8055 | return true; | |||
| 8056 | case 280: | |||
| 8057 | if (value.type() != DRW_Variant::INTEGER) | |||
| 8058 | return false; | |||
| 8059 | if (value.i_val() < 0 | |||
| 8060 | || value.i_val() > std::numeric_limits<std::uint8_t>::max()) | |||
| 8061 | return false; | |||
| 8062 | m_textAlignment = static_cast<std::uint8_t>(value.i_val()); | |||
| 8063 | return true; | |||
| 8064 | case 290: | |||
| 8065 | if (value.type() != DRW_Variant::INTEGER) | |||
| 8066 | return false; | |||
| 8067 | if (value.i_val() < 0 || value.i_val() > 1) | |||
| 8068 | return false; | |||
| 8069 | if (m_dxfBool290Count++ == 0) | |||
| 8070 | m_mtextVisible = value.i_val() != 0; | |||
| 8071 | else if (m_dxfBool290Count == 2) | |||
| 8072 | m_enableFrameText = value.i_val() != 0; | |||
| 8073 | return true; | |||
| 8074 | default: | |||
| 8075 | return true; // Common and unknown groups remain raw-authoritative. | |||
| 8076 | } | |||
| 8077 | } | |||
| 8078 | ||||
| 8079 | void DRW_GeoPositionMarker::resetDwgState() { | |||
| 8080 | DRW_Entity::reset(); | |||
| 8081 | m_classVersion = 0; | |||
| 8082 | m_position = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 8083 | m_radius = 0.0; | |||
| 8084 | m_notes.clear(); | |||
| 8085 | m_landingGap = 0.0; | |||
| 8086 | m_mtextVisible = false; | |||
| 8087 | m_textAlignment = 0; | |||
| 8088 | m_enableFrameText = false; | |||
| 8089 | mtext.reset(); | |||
| 8090 | m_dxfDouble40Count = 0; | |||
| 8091 | m_dxfBool290Count = 0; | |||
| 8092 | } | |||
| 8093 | ||||
| 8094 | bool DRW_GeoPositionMarker::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 8095 | std::uint32_t bs) { | |||
| 8096 | resetDwgState(); | |||
| 8097 | dwgBuffer *sourceBuf = buf; | |||
| 8098 | auto fail = [this, sourceBuf]() { | |||
| 8099 | if (sourceBuf != nullptr) | |||
| 8100 | sourceBuf->invalidate(); | |||
| 8101 | resetDwgState(); | |||
| 8102 | return false; | |||
| 8103 | }; | |||
| 8104 | if (sourceBuf == nullptr || v < DRW::AC1027) | |||
| 8105 | return fail(); | |||
| 8106 | ||||
| 8107 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 8108 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 8109 | if (!DRW_Entity::parseDwg(v, &bodyProbe, &stringProbe, bs) | |||
| 8110 | || !bodyProbe.isGood() || !stringProbe.isGood()) | |||
| 8111 | return fail(); | |||
| 8112 | ||||
| 8113 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 8114 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 8115 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 8116 | if (v > DRW::AC1018 | |||
| 8117 | && (!bodyProbe.getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 8118 | stringEndBit) | |||
| 8119 | || currentDwgBit(&stringProbe) > stringEndBit)) | |||
| 8120 | return fail(); | |||
| 8121 | ||||
| 8122 | std::int32_t parsedClassVersion = 0; | |||
| 8123 | DRW_Coord position; | |||
| 8124 | double radius = 0.0; | |||
| 8125 | UTF8STRINGstd::string notes; | |||
| 8126 | double landingGap = 0.0; | |||
| 8127 | bool mtextVisible = false; | |||
| 8128 | std::uint8_t textAlignment = 0; | |||
| 8129 | bool enableFrameText = false; | |||
| 8130 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, parsedClassVersion) | |||
| 8131 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, position) | |||
| 8132 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, radius) | |||
| 8133 | || !readBoundedVariableText(stringProbe, stringEndBit, v, notes) | |||
| 8134 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, landingGap) | |||
| 8135 | || !readBoundedBit(bodyProbe, bodyEndBit, mtextVisible) | |||
| 8136 | || !readBoundedRawChar8(bodyProbe, bodyEndBit, textAlignment) | |||
| 8137 | || !readBoundedBit(bodyProbe, bodyEndBit, enableFrameText)) | |||
| 8138 | return fail(); | |||
| 8139 | ||||
| 8140 | const auto finite = [](const DRW_Coord& point) { | |||
| 8141 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 8142 | && std::isfinite(point.z); | |||
| 8143 | }; | |||
| 8144 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 8145 | || !finite(position) || !std::isfinite(radius) | |||
| 8146 | || !std::isfinite(landingGap)) | |||
| 8147 | return fail(); | |||
| 8148 | ||||
| 8149 | // AcDbMTextObjectEmbedded follows the marker body when framing is enabled. | |||
| 8150 | // Parse it on a bounded probe before the parent and embedded handle passes; | |||
| 8151 | // otherwise a truncated nested body can consume parent handle bytes. | |||
| 8152 | dwgBuffer bodyTailProbe = bodyProbe.forkIndependent(); | |||
| 8153 | std::unique_ptr<DRW_MText> parsedMText; | |||
| 8154 | EmbeddedMTextHandleInfo embeddedHandles; | |||
| 8155 | if (enableFrameText) { | |||
| 8156 | if (objSize == 0 | |||
| 8157 | || !(parsedMText = std::make_unique<DRW_MText>()) | |||
| 8158 | || !parseEmbeddedMTextDwg(v, &bodyTailProbe, &stringProbe, | |||
| 8159 | *parsedMText, embeddedHandles, | |||
| 8160 | EmbeddedMTextForm::Short, | |||
| 8161 | bodyEndBit, stringEndBit) | |||
| 8162 | || !bodyTailProbe.isGood() || !stringProbe.isGood()) | |||
| 8163 | return fail(); | |||
| 8164 | } | |||
| 8165 | ||||
| 8166 | std::uint64_t handleEndBit = 0; | |||
| 8167 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 8168 | return fail(); | |||
| 8169 | ||||
| 8170 | dwgBuffer handleProbe = bodyTailProbe.forkIndependent(); | |||
| 8171 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 8172 | || !handleProbe.isGood()) | |||
| 8173 | return fail(); | |||
| 8174 | if (enableFrameText) { | |||
| 8175 | if (!consumeEmbeddedMTextHandles(v, &handleProbe, embeddedHandles, | |||
| 8176 | parsedMText.get(), handleEndBit)) | |||
| 8177 | return fail(); | |||
| 8178 | } | |||
| 8179 | ||||
| 8180 | m_classVersion = static_cast<std::uint32_t>(parsedClassVersion); | |||
| 8181 | m_position = position; | |||
| 8182 | m_radius = radius; | |||
| 8183 | m_notes = notes; | |||
| 8184 | m_landingGap = landingGap; | |||
| 8185 | m_mtextVisible = mtextVisible; | |||
| 8186 | m_textAlignment = textAlignment; | |||
| 8187 | m_enableFrameText = enableFrameText; | |||
| 8188 | mtext = std::move(parsedMText); | |||
| 8189 | *sourceBuf = handleProbe; | |||
| 8190 | return true; | |||
| 8191 | } | |||
| 8192 | ||||
| 8193 | bool DRW_Light::encodeDwg(DRW::Version v, dwgBufferW *buf, std::uint32_t bs, | |||
| 8194 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 8195 | (void)bs; | |||
| 8196 | if (v < DRW::AC1021) | |||
| 8197 | return false; | |||
| 8198 | ||||
| 8199 | oType = kDwgClassNum; | |||
| 8200 | if (!encodeDwgCommon(v, buf, strBuf)) | |||
| 8201 | return false; | |||
| 8202 | ||||
| 8203 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 8204 | buf->putBitLong(m_classVersion); | |||
| 8205 | sb->putVariableText(v, m_name); | |||
| 8206 | buf->putBitLong(m_type); | |||
| 8207 | buf->putBit(m_status ? 1 : 0); | |||
| 8208 | buf->putCmColor(v, static_cast<std::uint16_t>(m_color)); | |||
| 8209 | buf->putBit(m_plotGlyph ? 1 : 0); | |||
| 8210 | buf->putBitDouble(m_intensity); | |||
| 8211 | buf->put3BitDouble(m_position); | |||
| 8212 | buf->put3BitDouble(m_target); | |||
| 8213 | buf->putBitLong(m_attenuationType); | |||
| 8214 | buf->putBit(m_useAttenuationLimits ? 1 : 0); | |||
| 8215 | buf->putBitDouble(m_attenuationStartLimit); | |||
| 8216 | buf->putBitDouble(m_attenuationEndLimit); | |||
| 8217 | buf->putBitDouble(m_hotspotAngle); | |||
| 8218 | buf->putBitDouble(m_falloffAngle); | |||
| 8219 | buf->putBit(m_castShadows ? 1 : 0); | |||
| 8220 | buf->putBitLong(m_shadowType); | |||
| 8221 | buf->putBitShort(m_shadowMapSize); | |||
| 8222 | buf->putRawChar8(m_shadowMapSoftness); | |||
| 8223 | ||||
| 8224 | buf->putBit(m_hasPhotometricData ? 1 : 0); | |||
| 8225 | if (m_hasPhotometricData) { | |||
| 8226 | buf->putBit(m_hasWebFile ? 1 : 0); | |||
| 8227 | sb->putVariableText(v, m_webFile); | |||
| 8228 | buf->putBitShort(m_physicalIntensityMethod); | |||
| 8229 | buf->putBitDouble(m_physicalIntensity); | |||
| 8230 | buf->putBitDouble(m_illuminanceDistance); | |||
| 8231 | buf->putBitShort(m_lampColorType); | |||
| 8232 | buf->putBitDouble(m_lampColorTemperature); | |||
| 8233 | buf->putBitShort(m_lampColorPreset); | |||
| 8234 | buf->put3BitDouble(m_webRotation); | |||
| 8235 | buf->putBitShort(m_extendedLightShape); | |||
| 8236 | buf->putBitDouble(m_extendedLightLength); | |||
| 8237 | buf->putBitDouble(m_extendedLightWidth); | |||
| 8238 | buf->putBitDouble(m_extendedLightRadius); | |||
| 8239 | } | |||
| 8240 | ||||
| 8241 | return encodeDwgEntHandle(v, buf, handleBuf); | |||
| 8242 | } | |||
| 8243 | ||||
| 8244 | bool DRW_SectionObject::parseCode( | |||
| 8245 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 8246 | if (code != 100 && !m_dxfInBody) | |||
| 8247 | return DRW_Entity::parseCode(code, reader); | |||
| 8248 | switch (code) { | |||
| 8249 | case 100: | |||
| 8250 | m_dxfInBody = reader->getUtf8String() == "AcDbSection"; | |||
| 8251 | return true; | |||
| 8252 | case 90: | |||
| 8253 | m_state = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 8254 | return true; | |||
| 8255 | case 91: | |||
| 8256 | m_flags = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 8257 | return true; | |||
| 8258 | case 1: | |||
| 8259 | m_name = reader->getUtf8String(); | |||
| 8260 | return true; | |||
| 8261 | case 10: | |||
| 8262 | m_vertDir.x = reader->getDouble(); | |||
| 8263 | return true; | |||
| 8264 | case 20: | |||
| 8265 | m_vertDir.y = reader->getDouble(); | |||
| 8266 | return true; | |||
| 8267 | case 30: | |||
| 8268 | m_vertDir.z = reader->getDouble(); | |||
| 8269 | return true; | |||
| 8270 | case 40: | |||
| 8271 | m_topHeight = reader->getDouble(); | |||
| 8272 | return true; | |||
| 8273 | case 41: | |||
| 8274 | m_bottomHeight = reader->getDouble(); | |||
| 8275 | return true; | |||
| 8276 | case 70: | |||
| 8277 | { | |||
| 8278 | const int value = reader->getInt32(); | |||
| 8279 | if (value < 0 || value > 0xFFFF) | |||
| 8280 | return false; | |||
| 8281 | m_indicatorAlpha = static_cast<std::uint16_t>(value); | |||
| 8282 | } | |||
| 8283 | return true; | |||
| 8284 | case 62: | |||
| 8285 | m_indicatorColor = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 8286 | return true; | |||
| 8287 | case 92: | |||
| 8288 | { | |||
| 8289 | const int value = reader->getInt32(); | |||
| 8290 | if (value < 0 | |||
| 8291 | || static_cast<std::size_t>(value) > DRW_SectionObject::kMaxVertices) | |||
| 8292 | return false; | |||
| 8293 | m_verts.clear(); | |||
| 8294 | if (!DRW::reserve(m_verts, value)) | |||
| 8295 | return false; | |||
| 8296 | return true; | |||
| 8297 | } | |||
| 8298 | case 93: | |||
| 8299 | { | |||
| 8300 | const int value = reader->getInt32(); | |||
| 8301 | if (value < 0 | |||
| 8302 | || static_cast<std::size_t>(value) > DRW_SectionObject::kMaxVertices) | |||
| 8303 | return false; | |||
| 8304 | m_blVerts.clear(); | |||
| 8305 | if (!DRW::reserve(m_blVerts, value)) | |||
| 8306 | return false; | |||
| 8307 | return true; | |||
| 8308 | } | |||
| 8309 | case 11: | |||
| 8310 | if (m_verts.size() >= DRW_SectionObject::kMaxVertices) | |||
| 8311 | return false; | |||
| 8312 | m_verts.emplace_back(); | |||
| 8313 | m_verts.back().x = reader->getDouble(); | |||
| 8314 | return true; | |||
| 8315 | case 21: | |||
| 8316 | if (m_verts.empty()) | |||
| 8317 | return false; | |||
| 8318 | m_verts.back().y = reader->getDouble(); | |||
| 8319 | return true; | |||
| 8320 | case 31: | |||
| 8321 | if (m_verts.empty()) | |||
| 8322 | return false; | |||
| 8323 | m_verts.back().z = reader->getDouble(); | |||
| 8324 | return true; | |||
| 8325 | case 12: | |||
| 8326 | if (m_blVerts.size() >= DRW_SectionObject::kMaxVertices) | |||
| 8327 | return false; | |||
| 8328 | m_blVerts.emplace_back(); | |||
| 8329 | m_blVerts.back().x = reader->getDouble(); | |||
| 8330 | return true; | |||
| 8331 | case 22: | |||
| 8332 | if (m_blVerts.empty()) | |||
| 8333 | return false; | |||
| 8334 | m_blVerts.back().y = reader->getDouble(); | |||
| 8335 | return true; | |||
| 8336 | case 32: | |||
| 8337 | if (m_blVerts.empty()) | |||
| 8338 | return false; | |||
| 8339 | m_blVerts.back().z = reader->getDouble(); | |||
| 8340 | return true; | |||
| 8341 | case 360: | |||
| 8342 | m_sectionSettingsHandle = reader->getHandleString(); | |||
| 8343 | return true; | |||
| 8344 | default: | |||
| 8345 | return DRW_Entity::parseCode(code, reader); | |||
| 8346 | } | |||
| 8347 | } | |||
| 8348 | ||||
| 8349 | // DRW_SectionObject::parseDwg — SECTIONOBJECT / AcDbSection, field order per | |||
| 8350 | // libreDWG dwg2.spec DWG_ENTITY(SECTIONOBJECT): BL state, BL flags, T name, | |||
| 8351 | // 3BD vert_dir, BD top/bottom height, BS indicator_alpha, CMTC indicator_color, | |||
| 8352 | // BL num_verts + verts, BL num_blverts + blverts; then the common entity handle | |||
| 8353 | // data followed by the section_settings hard reference (H 5, 360). | |||
| 8354 | void DRW_SectionObject::resetDwgState() { | |||
| 8355 | DRW_Entity::reset(); | |||
| 8356 | m_state = 0; | |||
| 8357 | m_flags = 0; | |||
| 8358 | m_name.clear(); | |||
| 8359 | m_vertDir = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 8360 | m_topHeight = 0.0; | |||
| 8361 | m_bottomHeight = 0.0; | |||
| 8362 | m_indicatorAlpha = 0; | |||
| 8363 | m_indicatorColor = 0; | |||
| 8364 | m_verts.clear(); | |||
| 8365 | m_blVerts.clear(); | |||
| 8366 | m_sectionSettingsHandle = 0; | |||
| 8367 | m_dxfInBody = false; | |||
| 8368 | } | |||
| 8369 | ||||
| 8370 | bool DRW_SectionObject::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 8371 | std::uint32_t bs) { | |||
| 8372 | resetDwgState(); | |||
| 8373 | dwgBuffer *sourceBuf = buf; | |||
| 8374 | auto fail = [this, sourceBuf]() { | |||
| 8375 | if (sourceBuf != nullptr) | |||
| 8376 | sourceBuf->invalidate(); | |||
| 8377 | resetDwgState(); | |||
| 8378 | return false; | |||
| 8379 | }; | |||
| 8380 | if (sourceBuf == nullptr) | |||
| 8381 | return fail(); | |||
| 8382 | ||||
| 8383 | // R2007+ stores text in a separate stream. Independent cursors keep a | |||
| 8384 | // malformed field from consuming the source or a later handle stream. | |||
| 8385 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 8386 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 8387 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : &bodyProbe; | |||
| 8388 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs) | |||
| 8389 | || !bodyProbe.isGood() || !stringStream->isGood()) | |||
| 8390 | return fail(); | |||
| 8391 | DRW_DBG("\n***************************** parsing SECTIONOBJECT *********************\n")DRW_dbg::dbg("\n***************************** parsing SECTIONOBJECT *********************\n" ); | |||
| 8392 | ||||
| 8393 | // The common entity parser leaves bodyProbe at the first SECTIONOBJECT | |||
| 8394 | // field and stringStream at the detached string stream for R2007+. | |||
| 8395 | // Keep both cursors inside their declared data ranges while staging the | |||
| 8396 | // complete header before publishing it. | |||
| 8397 | const std::uint64_t bodyEndBit = tableBodyEndBit(v, stringStream, objSize); | |||
| 8398 | const std::uint64_t stringEndBit = v > DRW::AC1018 | |||
| 8399 | ? objSize : bodyEndBit; | |||
| 8400 | std::int32_t stateValue = 0; | |||
| 8401 | std::int32_t flagsValue = 0; | |||
| 8402 | UTF8STRINGstd::string name; | |||
| 8403 | DRW_Coord vertDir; | |||
| 8404 | double topHeight = 0.0; | |||
| 8405 | double bottomHeight = 0.0; | |||
| 8406 | std::uint16_t indicatorAlpha = 0; | |||
| 8407 | std::uint32_t indicatorColor = 0; | |||
| 8408 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, stateValue) | |||
| 8409 | || !readBoundedBitLong(bodyProbe, bodyEndBit, flagsValue) | |||
| 8410 | || !readBoundedVariableText(*stringStream, stringEndBit, v, name) | |||
| 8411 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, vertDir) | |||
| 8412 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, topHeight) | |||
| 8413 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, bottomHeight) | |||
| 8414 | || !readBoundedBitShort(bodyProbe, bodyEndBit, indicatorAlpha) | |||
| 8415 | || !readBoundedCmColor(bodyProbe, stringStream, bodyEndBit, v, | |||
| 8416 | indicatorColor, nullptr, nullptr, nullptr, | |||
| 8417 | nullptr, stringEndBit)) | |||
| 8418 | return fail(); | |||
| 8419 | ||||
| 8420 | std::uint32_t numVerts = 0; | |||
| 8421 | if (!readTableBodyCount( | |||
| 8422 | v, &bodyProbe, bodyEndBit, | |||
| 8423 | static_cast<std::uint32_t>(DRW_SectionObject::kMaxVertices), 6, | |||
| 8424 | numVerts) | |||
| 8425 | || !proxyEntityHasBits( | |||
| 8426 | bodyProbe, bodyEndBit, static_cast<std::uint64_t>(numVerts) * 6u)) | |||
| 8427 | return fail(); | |||
| 8428 | std::vector<DRW_Coord> verts; | |||
| 8429 | if (!DRW::reserve(verts, static_cast<int>(numVerts))) | |||
| 8430 | return fail(); | |||
| 8431 | for (std::uint32_t i = 0; i < numVerts; ++i) { | |||
| 8432 | DRW_Coord vertex; | |||
| 8433 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, vertex)) | |||
| 8434 | return fail(); | |||
| 8435 | verts.push_back(vertex); | |||
| 8436 | } | |||
| 8437 | ||||
| 8438 | std::uint32_t numBl = 0; | |||
| 8439 | if (!readTableBodyCount( | |||
| 8440 | v, &bodyProbe, bodyEndBit, | |||
| 8441 | static_cast<std::uint32_t>(DRW_SectionObject::kMaxVertices), 6, | |||
| 8442 | numBl) | |||
| 8443 | || !proxyEntityHasBits( | |||
| 8444 | bodyProbe, bodyEndBit, static_cast<std::uint64_t>(numBl) * 6u)) | |||
| 8445 | return fail(); | |||
| 8446 | std::vector<DRW_Coord> blVerts; | |||
| 8447 | if (!DRW::reserve(blVerts, static_cast<int>(numBl))) | |||
| 8448 | return fail(); | |||
| 8449 | for (std::uint32_t i = 0; i < numBl; ++i) { | |||
| 8450 | DRW_Coord vertex; | |||
| 8451 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, vertex)) | |||
| 8452 | return fail(); | |||
| 8453 | blVerts.push_back(vertex); | |||
| 8454 | } | |||
| 8455 | ||||
| 8456 | const auto finite = [](const DRW_Coord& point) { | |||
| 8457 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 8458 | && std::isfinite(point.z); | |||
| 8459 | }; | |||
| 8460 | if (!bodyProbe.isGood() || !stringStream->isGood() | |||
| 8461 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 8462 | || !finite(vertDir) || !std::isfinite(topHeight) | |||
| 8463 | || !std::isfinite(bottomHeight)) | |||
| 8464 | return fail(); | |||
| 8465 | if (!std::all_of(verts.begin(), verts.end(), finite) | |||
| 8466 | || !std::all_of(blVerts.begin(), blVerts.end(), finite)) | |||
| 8467 | return fail(); | |||
| 8468 | ||||
| 8469 | // The common entity handle stream starts at the object-data boundary for | |||
| 8470 | // R2007+ and follows the body inline in older versions. The section | |||
| 8471 | // settings reference is a hard pointer (H 5), after those common handles. | |||
| 8472 | std::uint64_t handleEndBit = 0; | |||
| 8473 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 8474 | return fail(); | |||
| 8475 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 8476 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 8477 | || !handleProbe.isGood()) | |||
| 8478 | return fail(); | |||
| 8479 | std::uint32_t sectionSettingsHandle = 0; | |||
| 8480 | if (proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 8481 | dwgHandle settingsHandle; | |||
| 8482 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 8483 | settingsHandle)) | |||
| 8484 | return fail(); | |||
| 8485 | sectionSettingsHandle = settingsHandle.ref; | |||
| 8486 | DRW_DBG(" section_settings Handle: ")DRW_dbg::dbg(" section_settings Handle: "); | |||
| 8487 | DRW_DBGHL(settingsHandle.code, settingsHandle.size,DRW_dbg::dbgHL(settingsHandle.code, settingsHandle.size, settingsHandle .ref) | |||
| 8488 | settingsHandle.ref)DRW_dbg::dbgHL(settingsHandle.code, settingsHandle.size, settingsHandle .ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8489 | } | |||
| 8490 | if (!handleProbe.isGood()) | |||
| 8491 | return fail(); | |||
| 8492 | ||||
| 8493 | m_state = static_cast<std::uint32_t>(stateValue); | |||
| 8494 | m_flags = static_cast<std::uint32_t>(flagsValue); | |||
| 8495 | m_name = name; | |||
| 8496 | m_vertDir = vertDir; | |||
| 8497 | m_topHeight = topHeight; | |||
| 8498 | m_bottomHeight = bottomHeight; | |||
| 8499 | m_indicatorAlpha = indicatorAlpha; | |||
| 8500 | m_indicatorColor = indicatorColor; | |||
| 8501 | m_verts = std::move(verts); | |||
| 8502 | m_blVerts = std::move(blVerts); | |||
| 8503 | m_sectionSettingsHandle = sectionSettingsHandle; | |||
| 8504 | *sourceBuf = handleProbe; | |||
| 8505 | DRW_DBG("SECTIONOBJECT name: ")DRW_dbg::dbg("SECTIONOBJECT name: "); DRW_DBG(m_name.c_str())DRW_dbg::dbg(m_name.c_str()); | |||
| 8506 | 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"); | |||
| 8507 | return true; | |||
| 8508 | } | |||
| 8509 | ||||
| 8510 | bool DRW_SectionObject::encodeDwg(DRW::Version v, dwgBufferW *buf, | |||
| 8511 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 8512 | dwgBufferW *handleBuf) { | |||
| 8513 | (void)bs; | |||
| 8514 | if (v < DRW::AC1021 || buf == nullptr | |||
| 8515 | || m_verts.size() > DRW_SectionObject::kMaxVertices | |||
| 8516 | || m_blVerts.size() > DRW_SectionObject::kMaxVertices) | |||
| 8517 | return false; | |||
| 8518 | oType = kDwgClassNum; | |||
| 8519 | if (!encodeDwgCommon(v, buf, strBuf)) | |||
| 8520 | return false; | |||
| 8521 | dwgBufferW *stringBuffer = strBuf != nullptr ? strBuf : buf; | |||
| 8522 | buf->putBitLong(static_cast<std::int32_t>(m_state)); | |||
| 8523 | buf->putBitLong(static_cast<std::int32_t>(m_flags)); | |||
| 8524 | stringBuffer->putVariableText(v, m_name); | |||
| 8525 | buf->put3BitDouble(m_vertDir); | |||
| 8526 | buf->putBitDouble(m_topHeight); | |||
| 8527 | buf->putBitDouble(m_bottomHeight); | |||
| 8528 | buf->putBitShort(m_indicatorAlpha); | |||
| 8529 | buf->putCmColor(v, static_cast<std::uint16_t>(m_indicatorColor)); | |||
| 8530 | buf->putBitLong(static_cast<std::int32_t>(m_verts.size())); | |||
| 8531 | for (const DRW_Coord& point : m_verts) | |||
| 8532 | buf->put3BitDouble(point); | |||
| 8533 | buf->putBitLong(static_cast<std::int32_t>(m_blVerts.size())); | |||
| 8534 | for (const DRW_Coord& point : m_blVerts) | |||
| 8535 | buf->put3BitDouble(point); | |||
| 8536 | if (!encodeDwgEntHandle(v, buf, handleBuf)) | |||
| 8537 | return false; | |||
| 8538 | putHardPointerHandle(handleBuf != nullptr ? handleBuf : buf, | |||
| 8539 | m_sectionSettingsHandle); | |||
| 8540 | return true; | |||
| 8541 | } | |||
| 8542 | ||||
| 8543 | bool DRW_Tolerance::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8544 | switch (code) { | |||
| 8545 | case 1: | |||
| 8546 | text = reader->getUtf8String(); | |||
| 8547 | break; | |||
| 8548 | case 3: | |||
| 8549 | dimStyleName = reader->getUtf8String(); | |||
| 8550 | break; | |||
| 8551 | case 10: | |||
| 8552 | insertionPoint.x = reader->getDouble(); | |||
| 8553 | break; | |||
| 8554 | case 20: | |||
| 8555 | insertionPoint.y = reader->getDouble(); | |||
| 8556 | break; | |||
| 8557 | case 30: | |||
| 8558 | insertionPoint.z = reader->getDouble(); | |||
| 8559 | break; | |||
| 8560 | case 11: | |||
| 8561 | xAxisDirectionVector.x = reader->getDouble(); | |||
| 8562 | break; | |||
| 8563 | case 21: | |||
| 8564 | xAxisDirectionVector.y = reader->getDouble(); | |||
| 8565 | break; | |||
| 8566 | case 31: | |||
| 8567 | xAxisDirectionVector.z = reader->getDouble(); | |||
| 8568 | break; | |||
| 8569 | case 210: | |||
| 8570 | extPoint.x = reader->getDouble(); | |||
| 8571 | break; | |||
| 8572 | case 220: | |||
| 8573 | extPoint.y = reader->getDouble(); | |||
| 8574 | break; | |||
| 8575 | case 230: | |||
| 8576 | extPoint.z = reader->getDouble(); | |||
| 8577 | break; | |||
| 8578 | default: | |||
| 8579 | return DRW_Entity::parseCode(code, reader); | |||
| 8580 | } | |||
| 8581 | return true; | |||
| 8582 | } | |||
| 8583 | ||||
| 8584 | void DRW_Tolerance::resetDwgState() { | |||
| 8585 | DRW_Entity::reset(); | |||
| 8586 | text.clear(); | |||
| 8587 | dimStyleName = "STANDARD"; | |||
| 8588 | dimStyleH = dwgHandle{}; | |||
| 8589 | insertionPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 8590 | xAxisDirectionVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 8591 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 8592 | } | |||
| 8593 | ||||
| 8594 | bool DRW_Tolerance::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 8595 | std::uint32_t bs) { | |||
| 8596 | resetDwgState(); | |||
| 8597 | dwgBuffer *sourceBuf = buf; | |||
| 8598 | auto fail = [this, sourceBuf]() { | |||
| 8599 | if (sourceBuf != nullptr) | |||
| 8600 | sourceBuf->invalidate(); | |||
| 8601 | resetDwgState(); | |||
| 8602 | return false; | |||
| 8603 | }; | |||
| 8604 | if (sourceBuf == nullptr) | |||
| 8605 | return fail(); | |||
| 8606 | ||||
| 8607 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 8608 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 8609 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : &bodyProbe; | |||
| 8610 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs) | |||
| 8611 | || !bodyProbe.isGood() || !stringStream->isGood()) | |||
| 8612 | return fail(); | |||
| 8613 | ||||
| 8614 | DRW_DBG("\n***************************** parsing tolerance *********************************************\n")DRW_dbg::dbg("\n***************************** parsing tolerance *********************************************\n" ); | |||
| 8615 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 8616 | const std::uint64_t stringStartBit = currentDwgBit(stringStream); | |||
| 8617 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 8618 | if (v > DRW::AC1021) { | |||
| 8619 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 8620 | if (!entityBodyDataEndBit(*stringStream, v, objSize, | |||
| 8621 | ignoredBodyEndBit, &stringEndBit)) | |||
| 8622 | return fail(); | |||
| 8623 | } | |||
| 8624 | auto read3BitDoubleChecked = [&](DRW_Coord& point) { | |||
| 8625 | return readBoundedBitDouble(bodyProbe, bodyEndBit, point.x) | |||
| 8626 | && readBoundedBitDouble(bodyProbe, bodyEndBit, point.y) | |||
| 8627 | && readBoundedBitDouble(bodyProbe, bodyEndBit, point.z); | |||
| 8628 | }; | |||
| 8629 | ||||
| 8630 | if (v < DRW::AC1015) { | |||
| 8631 | std::uint16_t unknown = 0; | |||
| 8632 | double heightAtCreation = 0.0; | |||
| 8633 | double dimGapAtCreation = 0.0; | |||
| 8634 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, unknown) | |||
| 8635 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 8636 | heightAtCreation) | |||
| 8637 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 8638 | dimGapAtCreation) | |||
| 8639 | || !std::isfinite(heightAtCreation) | |||
| 8640 | || !std::isfinite(dimGapAtCreation)) | |||
| 8641 | return fail(); | |||
| 8642 | } | |||
| 8643 | ||||
| 8644 | DRW_Coord parsedInsertionPoint; | |||
| 8645 | DRW_Coord parsedXAxisDirectionVector; | |||
| 8646 | DRW_Coord parsedExtPoint; | |||
| 8647 | if (!read3BitDoubleChecked(parsedInsertionPoint) | |||
| 8648 | || !read3BitDoubleChecked(parsedXAxisDirectionVector) | |||
| 8649 | || !read3BitDoubleChecked(parsedExtPoint)) | |||
| 8650 | return fail(); | |||
| 8651 | UTF8STRINGstd::string parsedText; | |||
| 8652 | if (v > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 8653 | parsedText.clear(); | |||
| 8654 | } else if (!readBoundedVariableText(*stringStream, stringEndBit, v, | |||
| 8655 | parsedText)) { | |||
| 8656 | return fail(); | |||
| 8657 | } | |||
| 8658 | ||||
| 8659 | const auto finite = [](const DRW_Coord& point) { | |||
| 8660 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 8661 | && std::isfinite(point.z); | |||
| 8662 | }; | |||
| 8663 | if (!bodyProbe.isGood() || !stringStream->isGood() | |||
| 8664 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 8665 | || currentDwgBit(stringStream) > stringEndBit | |||
| 8666 | || !finite(parsedInsertionPoint) | |||
| 8667 | || !finite(parsedXAxisDirectionVector) | |||
| 8668 | || !finite(parsedExtPoint)) | |||
| 8669 | return fail(); | |||
| 8670 | ||||
| 8671 | std::uint64_t handleEndBit = 0; | |||
| 8672 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 8673 | return fail(); | |||
| 8674 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 8675 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 8676 | || !handleProbe.isGood()) | |||
| 8677 | return fail(); | |||
| 8678 | dwgHandle parsedDimStyleH; | |||
| 8679 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 8680 | parsedDimStyleH) | |||
| 8681 | || !handleProbe.isGood()) | |||
| 8682 | return fail(); | |||
| 8683 | ||||
| 8684 | insertionPoint = parsedInsertionPoint; | |||
| 8685 | xAxisDirectionVector = parsedXAxisDirectionVector; | |||
| 8686 | extPoint = parsedExtPoint; | |||
| 8687 | text = parsedText; | |||
| 8688 | dimStyleH = parsedDimStyleH; | |||
| 8689 | *sourceBuf = handleProbe; | |||
| 8690 | DRW_DBG("insertionPoint: ")DRW_dbg::dbg("insertionPoint: "); | |||
| 8691 | DRW_DBGPT(insertionPoint.x, insertionPoint.y, insertionPoint.z)DRW_dbg::dbgPT(insertionPoint.x, insertionPoint.y, insertionPoint .z); | |||
| 8692 | 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"); | |||
| 8693 | DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); | |||
| 8694 | DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); | |||
| 8695 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8696 | return true; | |||
| 8697 | } | |||
| 8698 | ||||
| 8699 | bool DRW_Tolerance::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 8700 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 8701 | (void)bs; | |||
| 8702 | oType = 46; | |||
| 8703 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 8704 | return false; | |||
| 8705 | ||||
| 8706 | if (version < DRW::AC1015) { | |||
| 8707 | buf->putBitShort(0); | |||
| 8708 | buf->putBitDouble(0.0); | |||
| 8709 | buf->putBitDouble(0.0); | |||
| 8710 | } | |||
| 8711 | ||||
| 8712 | buf->put3BitDouble(insertionPoint); | |||
| 8713 | buf->put3BitDouble(xAxisDirectionVector); | |||
| 8714 | buf->put3BitDouble(extPoint); | |||
| 8715 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 8716 | ||||
| 8717 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 8718 | return false; | |||
| 8719 | ||||
| 8720 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 8721 | putHardPointerHandle(hb, (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref); | |||
| 8722 | return true; | |||
| 8723 | } | |||
| 8724 | ||||
| 8725 | ||||
| 8726 | bool DRW_Block::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8727 | switch (code) { | |||
| 8728 | case 1: | |||
| 8729 | xrefPath = reader->getUtf8String(); | |||
| 8730 | break; | |||
| 8731 | case 2: | |||
| 8732 | name = reader->getUtf8String(); | |||
| 8733 | break; | |||
| 8734 | case 70: | |||
| 8735 | flags = reader->getInt32(); | |||
| 8736 | break; | |||
| 8737 | default: | |||
| 8738 | return DRW_Point::parseCode(code, reader); | |||
| 8739 | } | |||
| 8740 | ||||
| 8741 | return true; | |||
| 8742 | } | |||
| 8743 | ||||
| 8744 | void DRW_Block::resetDwgState() { | |||
| 8745 | const bool endBlock = isEnd; | |||
| 8746 | DRW_Point::resetDwgState(); | |||
| 8747 | name = endBlock ? UTF8STRINGstd::string() : UTF8STRINGstd::string("*U0"); | |||
| 8748 | flags = 0; | |||
| 8749 | insUnits = 0; | |||
| 8750 | xrefPath.clear(); | |||
| 8751 | previewData.clear(); | |||
| 8752 | isEnd = endBlock; | |||
| 8753 | } | |||
| 8754 | ||||
| 8755 | bool DRW_Block::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 8756 | resetDwgState(); | |||
| 8757 | if (buf == nullptr) | |||
| 8758 | return false; | |||
| 8759 | auto fail = [this, buf]() { | |||
| 8760 | buf->invalidate(); | |||
| 8761 | resetDwgState(); | |||
| 8762 | return false; | |||
| 8763 | }; | |||
| 8764 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 8765 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 8766 | dwgBuffer *sBuf = &bodyProbe; | |||
| 8767 | if (version > DRW::AC1018) {//2007+ | |||
| 8768 | sBuf = &sBuff; //separate buffer for strings | |||
| 8769 | } | |||
| 8770 | bool ret = DRW_Entity::parseDwg(version, &bodyProbe, sBuf, bs); | |||
| 8771 | if (!ret) | |||
| 8772 | return fail(); | |||
| 8773 | ||||
| 8774 | // BLOCK/ENDBLK carry one entity-specific bit after the common data range; | |||
| 8775 | // the detached string stream begins at dwgDataEndBit and is independent. | |||
| 8776 | const std::uint64_t bodyEndBit = version > DRW::AC1018 | |||
| 8777 | && dwgDataEndBit < std::numeric_limits<std::uint64_t>::max() | |||
| 8778 | ? dwgDataEndBit + 1 : dwgDataEndBit; | |||
| 8779 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 8780 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 8781 | if (version > DRW::AC1018 | |||
| 8782 | && (!bodyProbe.getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 8783 | stringEndBit) | |||
| 8784 | || currentDwgBit(sBuf) > stringEndBit)) | |||
| 8785 | return fail(); | |||
| 8786 | ||||
| 8787 | UTF8STRINGstd::string parsedName; | |||
| 8788 | if (!isEnd){ | |||
| 8789 | DRW_DBG("\n***************************** parsing block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing block *********************************************\n" ); | |||
| 8790 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 8791 | parsedName)) | |||
| 8792 | return fail(); | |||
| 8793 | 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"); | |||
| 8794 | } else { | |||
| 8795 | DRW_DBG("\n***************************** parsing end block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing end block *********************************************\n" ); | |||
| 8796 | } | |||
| 8797 | if (version > DRW::AC1018) {//2007+ | |||
| 8798 | bool ignoredUnknown = false; | |||
| 8799 | if (!readBoundedBit(bodyProbe, bodyEndBit, ignoredUnknown)) | |||
| 8800 | return fail(); | |||
| 8801 | DRW_DBG("unknown bit: ")DRW_dbg::dbg("unknown bit: "); DRW_DBG(ignoredUnknown)DRW_dbg::dbg(ignoredUnknown); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8802 | } | |||
| 8803 | // X handleAssoc; //X | |||
| 8804 | if (!bodyProbe.isGood() || currentDwgBit(&bodyProbe) > bodyEndBit) | |||
| 8805 | return fail(); | |||
| 8806 | std::uint64_t handleEndBit = 0; | |||
| 8807 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit)) | |||
| 8808 | return fail(); | |||
| 8809 | ret = DRW_Entity::parseDwgEntHandle(version, &bodyProbe, true, | |||
| 8810 | handleEndBit); | |||
| 8811 | if (!ret || !bodyProbe.isGood()) | |||
| 8812 | return fail(); | |||
| 8813 | // RS crc; //RS */ | |||
| 8814 | // R13-R2004 keep the handle stream inline and may consume the final | |||
| 8815 | // byte-alignment padding beyond the declared object-data bit count. | |||
| 8816 | // Only R2007+ has a separate string stream range to validate here. | |||
| 8817 | if (!bodyProbe.isGood() || !sBuf->isGood() | |||
| 8818 | || (version > DRW::AC1018 && currentDwgBit(sBuf) > stringEndBit)) | |||
| 8819 | return fail(); | |||
| 8820 | *buf = bodyProbe; | |||
| 8821 | if (!isEnd) | |||
| 8822 | name = std::move(parsedName); | |||
| 8823 | return true; | |||
| 8824 | } | |||
| 8825 | ||||
| 8826 | bool DRW_Insert::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8827 | switch (code) { | |||
| 8828 | case 2: | |||
| 8829 | name = reader->getUtf8String(); | |||
| 8830 | break; | |||
| 8831 | case 41: | |||
| 8832 | xscale = reader->getDouble(); | |||
| 8833 | break; | |||
| 8834 | case 42: | |||
| 8835 | yscale = reader->getDouble(); | |||
| 8836 | break; | |||
| 8837 | case 43: | |||
| 8838 | zscale = reader->getDouble(); | |||
| 8839 | break; | |||
| 8840 | case 50: | |||
| 8841 | angle = reader->getDouble(); | |||
| 8842 | angle = angle/ARAD57.29577951308232; //convert to radian | |||
| 8843 | break; | |||
| 8844 | case 70: { | |||
| 8845 | int value = 0; | |||
| 8846 | if (!readDxfIntInRange(reader, 0, kMaxMInsertCount, value)) | |||
| 8847 | return false; | |||
| 8848 | colcount = value; | |||
| 8849 | break; | |||
| 8850 | } | |||
| 8851 | case 71: { | |||
| 8852 | int value = 0; | |||
| 8853 | if (!readDxfIntInRange(reader, 0, kMaxMInsertCount, value)) | |||
| 8854 | return false; | |||
| 8855 | rowcount = value; | |||
| 8856 | break; | |||
| 8857 | } | |||
| 8858 | case 44: | |||
| 8859 | colspace = reader->getDouble(); | |||
| 8860 | break; | |||
| 8861 | case 45: | |||
| 8862 | rowspace = reader->getDouble(); | |||
| 8863 | break; | |||
| 8864 | default: | |||
| 8865 | return DRW_Point::parseCode(code, reader); | |||
| 8866 | } | |||
| 8867 | ||||
| 8868 | return true; | |||
| 8869 | } | |||
| 8870 | ||||
| 8871 | bool DRW_Table::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8872 | auto ensureGrid = [this]() { | |||
| 8873 | if (m_dxfRowsExpected < 0 || m_dxfColumnsExpected < 0) | |||
| 8874 | return true; | |||
| 8875 | ||||
| 8876 | const std::uint32_t rows = static_cast<std::uint32_t>(m_dxfRowsExpected); | |||
| 8877 | const std::uint32_t columns = static_cast<std::uint32_t>(m_dxfColumnsExpected); | |||
| 8878 | if (rows > kMaxTableRows || columns > kMaxTableColumns | |||
| 8879 | || (columns != 0 && rows > kMaxTableCells / columns)) { | |||
| 8880 | return false; | |||
| 8881 | } | |||
| 8882 | ||||
| 8883 | if (m_content.m_columns.size() != columns) { | |||
| 8884 | m_content.m_columns.clear(); | |||
| 8885 | if (!DRW::reserve(m_content.m_columns, static_cast<int>(columns))) | |||
| 8886 | return false; | |||
| 8887 | if (!DRW::resize(m_content.m_columns, static_cast<int>(columns))) | |||
| 8888 | return false; | |||
| 8889 | m_dxfColumnWidthsRead = 0; | |||
| 8890 | } | |||
| 8891 | if (m_content.m_rows.size() != rows) { | |||
| 8892 | m_content.m_rows.clear(); | |||
| 8893 | if (!DRW::reserve(m_content.m_rows, static_cast<int>(rows))) | |||
| 8894 | return false; | |||
| 8895 | if (!DRW::resize(m_content.m_rows, static_cast<int>(rows))) | |||
| 8896 | return false; | |||
| 8897 | m_dxfRowHeightsRead = 0; | |||
| 8898 | } | |||
| 8899 | for (auto& row : m_content.m_rows) { | |||
| 8900 | if (!DRW::reserve(row.m_cells, static_cast<int>(columns))) | |||
| 8901 | return false; | |||
| 8902 | if (!DRW::resize(row.m_cells, static_cast<int>(columns))) | |||
| 8903 | return false; | |||
| 8904 | } | |||
| 8905 | ||||
| 8906 | m_hasSemanticContent = true; | |||
| 8907 | m_semanticContentComplete = true; | |||
| 8908 | return true; | |||
| 8909 | }; | |||
| 8910 | ||||
| 8911 | auto currentCell = [this]() -> DRW_TableCell* { | |||
| 8912 | if (m_dxfCurrentCell < 0 || m_content.m_columns.empty() | |||
| 8913 | || m_content.m_rows.empty()) { | |||
| 8914 | return nullptr; | |||
| 8915 | } | |||
| 8916 | ||||
| 8917 | const std::size_t columns = m_content.m_columns.size(); | |||
| 8918 | const std::size_t cell = static_cast<std::size_t>(m_dxfCurrentCell); | |||
| 8919 | const std::size_t row = cell / columns; | |||
| 8920 | const std::size_t column = cell % columns; | |||
| 8921 | if (row >= m_content.m_rows.size() | |||
| 8922 | || column >= m_content.m_rows[row].m_cells.size()) { | |||
| 8923 | return nullptr; | |||
| 8924 | } | |||
| 8925 | return &m_content.m_rows[row].m_cells[column]; | |||
| 8926 | }; | |||
| 8927 | ||||
| 8928 | auto currentContent = [¤tCell]() -> DRW_TableCellContent* { | |||
| 8929 | DRW_TableCell *cell = currentCell(); | |||
| 8930 | if (cell == nullptr) | |||
| 8931 | return nullptr; | |||
| 8932 | if (cell->m_contents.empty() || cell->m_contents.back().m_type != 1) { | |||
| 8933 | DRW_TableCellContent content; | |||
| 8934 | content.m_type = 1; | |||
| 8935 | cell->m_contents.push_back(content); | |||
| 8936 | } | |||
| 8937 | return &cell->m_contents.back(); | |||
| 8938 | }; | |||
| 8939 | ||||
| 8940 | if (code == 100) { | |||
| 8941 | const std::string subclass = reader->getString(); | |||
| 8942 | if (subclass == "AcDbBlockReference") { | |||
| 8943 | m_dxfSubclass = DxfSubclass::BlockReference; | |||
| 8944 | } else if (subclass == "AcDbTable") { | |||
| 8945 | m_dxfSubclass = DxfSubclass::Table; | |||
| 8946 | } else if (subclass == "AcDbEntity") { | |||
| 8947 | m_dxfSubclass = DxfSubclass::Entity; | |||
| 8948 | } | |||
| 8949 | return true; | |||
| 8950 | } | |||
| 8951 | ||||
| 8952 | if (m_dxfSubclass != DxfSubclass::Table) | |||
| 8953 | return DRW_Insert::parseCode(code, reader); | |||
| 8954 | ||||
| 8955 | // A cell value's point, double, date and object-id groups reuse codes the | |||
| 8956 | // table itself and its proxy graphics own; only the displayed text is kept. | |||
| 8957 | if (m_dxfInCellValue | |||
| 8958 | && (code == 11 || code == 21 || code == 31 || code == 140 | |||
| 8959 | || code == 310 || code == 330)) { | |||
| 8960 | return true; | |||
| 8961 | } | |||
| 8962 | ||||
| 8963 | switch (code) { | |||
| 8964 | case 342: | |||
| 8965 | m_tableStyleHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 8966 | m_content.m_tableStyleHandle = m_tableStyleHandle; | |||
| 8967 | break; | |||
| 8968 | case 343: | |||
| 8969 | reader->getHandleString(); | |||
| 8970 | break; | |||
| 8971 | case 11: | |||
| 8972 | m_horizontalDirection.x = reader->getDouble(); | |||
| 8973 | break; | |||
| 8974 | case 21: | |||
| 8975 | m_horizontalDirection.y = reader->getDouble(); | |||
| 8976 | break; | |||
| 8977 | case 31: | |||
| 8978 | m_horizontalDirection.z = reader->getDouble(); | |||
| 8979 | break; | |||
| 8980 | case 90: | |||
| 8981 | if (m_dxfInCellValue) { | |||
| 8982 | if (DRW_TableCellContent *content = currentContent()) | |||
| 8983 | content->m_value.m_dataType = reader->getInt32(); | |||
| 8984 | else | |||
| 8985 | reader->getInt32(); | |||
| 8986 | } else { | |||
| 8987 | m_valueFlag = reader->getInt32(); | |||
| 8988 | } | |||
| 8989 | break; | |||
| 8990 | case 91: | |||
| 8991 | if (m_dxfRowsExpected < 0 && !m_dxfInCellValue) { | |||
| 8992 | int value = 0; | |||
| 8993 | if (!readDxfIntInRange(reader, 0, | |||
| 8994 | static_cast<int>(kMaxTableRows), value)) | |||
| 8995 | return false; | |||
| 8996 | m_dxfRowsExpected = value; | |||
| 8997 | if (!ensureGrid()) | |||
| 8998 | return false; | |||
| 8999 | } else { | |||
| 9000 | reader->getInt32(); | |||
| 9001 | } | |||
| 9002 | break; | |||
| 9003 | case 92: | |||
| 9004 | if (m_dxfColumnsExpected < 0 && !m_dxfInCellValue) { | |||
| 9005 | int value = 0; | |||
| 9006 | if (!readDxfIntInRange(reader, 0, | |||
| 9007 | static_cast<int>(kMaxTableColumns), value)) | |||
| 9008 | return false; | |||
| 9009 | m_dxfColumnsExpected = value; | |||
| 9010 | if (!ensureGrid()) | |||
| 9011 | return false; | |||
| 9012 | } else { | |||
| 9013 | reader->getInt32(); | |||
| 9014 | } | |||
| 9015 | break; | |||
| 9016 | case 93: | |||
| 9017 | case 94: | |||
| 9018 | case 95: | |||
| 9019 | case 96: | |||
| 9020 | case 172: | |||
| 9021 | case 173: | |||
| 9022 | case 174: | |||
| 9023 | case 175: | |||
| 9024 | case 176: | |||
| 9025 | case 178: | |||
| 9026 | reader->getInt32(); | |||
| 9027 | break; | |||
| 9028 | case 141: | |||
| 9029 | if (!ensureGrid()) | |||
| 9030 | return false; | |||
| 9031 | if (m_dxfRowHeightsRead < m_content.m_rows.size()) | |||
| 9032 | m_content.m_rows[m_dxfRowHeightsRead++].m_height = reader->getDouble(); | |||
| 9033 | else | |||
| 9034 | reader->getDouble(); | |||
| 9035 | break; | |||
| 9036 | case 142: | |||
| 9037 | if (!ensureGrid()) | |||
| 9038 | return false; | |||
| 9039 | if (m_dxfColumnWidthsRead < m_content.m_columns.size()) | |||
| 9040 | m_content.m_columns[m_dxfColumnWidthsRead++].m_width = reader->getDouble(); | |||
| 9041 | else | |||
| 9042 | reader->getDouble(); | |||
| 9043 | break; | |||
| 9044 | case 145: | |||
| 9045 | reader->getDouble(); | |||
| 9046 | break; | |||
| 9047 | case 171: | |||
| 9048 | if (!ensureGrid()) | |||
| 9049 | return false; | |||
| 9050 | if (!m_content.m_rows.empty() && !m_content.m_columns.empty() | |||
| 9051 | && m_dxfNextCell < m_content.m_rows.size() * m_content.m_columns.size()) { | |||
| 9052 | m_dxfCurrentCell = static_cast<int>(m_dxfNextCell++); | |||
| 9053 | if (DRW_TableCell *cell = currentCell()) | |||
| 9054 | cell->m_flags = reader->getInt32(); | |||
| 9055 | else | |||
| 9056 | reader->getInt32(); | |||
| 9057 | } else { | |||
| 9058 | m_dxfCurrentCell = -1; | |||
| 9059 | reader->getInt32(); | |||
| 9060 | } | |||
| 9061 | m_dxfInCellValue = false; | |||
| 9062 | break; | |||
| 9063 | case 301: | |||
| 9064 | m_dxfInCellValue = reader->getString() == "CELL_VALUE"; | |||
| 9065 | if (m_dxfInCellValue) | |||
| 9066 | currentContent(); | |||
| 9067 | break; | |||
| 9068 | case 1: | |||
| 9069 | case 302: { | |||
| 9070 | const UTF8STRINGstd::string text = reader->getUtf8String(); | |||
| 9071 | if (m_dxfInCellValue) { | |||
| 9072 | if (DRW_TableCellContent *content = currentContent()) { | |||
| 9073 | content->m_text = text; | |||
| 9074 | content->m_value.m_dataType = 4; | |||
| 9075 | content->m_value.m_value.addString(1, text); | |||
| 9076 | } | |||
| 9077 | } | |||
| 9078 | break; | |||
| 9079 | } | |||
| 9080 | case 300: | |||
| 9081 | if (m_dxfInCellValue) { | |||
| 9082 | if (DRW_TableCellContent *content = currentContent()) | |||
| 9083 | content->m_value.m_valueString = reader->getUtf8String(); | |||
| 9084 | else | |||
| 9085 | reader->getUtf8String(); | |||
| 9086 | } else { | |||
| 9087 | reader->getUtf8String(); | |||
| 9088 | } | |||
| 9089 | break; | |||
| 9090 | case 304: | |||
| 9091 | reader->getString(); | |||
| 9092 | m_dxfInCellValue = false; | |||
| 9093 | break; | |||
| 9094 | default: | |||
| 9095 | return DRW_Entity::parseCode(code, reader); | |||
| 9096 | } | |||
| 9097 | ||||
| 9098 | return true; | |||
| 9099 | } | |||
| 9100 | ||||
| 9101 | void DRW_Insert::resetDwgState() { | |||
| 9102 | DRW_Point::resetDwgState(); | |||
| 9103 | name.clear(); | |||
| 9104 | xscale = yscale = zscale = 1.0; | |||
| 9105 | angle = 0.0; | |||
| 9106 | colcount = rowcount = 1; | |||
| 9107 | colspace = rowspace = 0.0; | |||
| 9108 | attlist.clear(); | |||
| 9109 | blockRecH = dwgHandle{}; | |||
| 9110 | seqendH = dwgHandle{}; | |||
| 9111 | attribHandles.clear(); | |||
| 9112 | } | |||
| 9113 | ||||
| 9114 | bool DRW_Insert::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 9115 | resetDwgState(); | |||
| 9116 | dwgBuffer *sourceBuf = buf; | |||
| 9117 | auto fail = [this, sourceBuf]() { | |||
| 9118 | if (sourceBuf != nullptr) | |||
| 9119 | sourceBuf->invalidate(); | |||
| 9120 | resetDwgState(); | |||
| 9121 | return false; | |||
| 9122 | }; | |||
| 9123 | if (sourceBuf == nullptr) | |||
| 9124 | return fail(); | |||
| 9125 | ||||
| 9126 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 9127 | buf = &bodyProbe; | |||
| 9128 | if (!DRW_Entity::parseDwgCommon(version, buf, bs) | |||
| 9129 | || !bodyProbe.isGood()) | |||
| 9130 | return fail(); | |||
| 9131 | ||||
| 9132 | std::int32_t objCount = 0; | |||
| 9133 | std::vector<dwgHandle> parsedAttribHandles; | |||
| 9134 | DRW_DBG("\n************************** parsing insert/minsert *****************************************\n")DRW_dbg::dbg("\n************************** parsing insert/minsert *****************************************\n" ); | |||
| 9135 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 9136 | DRW_Coord parsedBasePoint; | |||
| 9137 | DRW_Coord parsedExtPoint; | |||
| 9138 | double parsedXScale = 1.0; | |||
| 9139 | double parsedYScale = 1.0; | |||
| 9140 | double parsedZScale = 1.0; | |||
| 9141 | double parsedAngle = 0.0; | |||
| 9142 | bool hasAttrib = false; | |||
| 9143 | ||||
| 9144 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint)) | |||
| 9145 | return fail(); | |||
| 9146 | DRW_DBG("insertion point: ")DRW_dbg::dbg("insertion point: "); | |||
| 9147 | DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 9148 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9149 | if (version < DRW::AC1015) {//14- | |||
| 9150 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedXScale) | |||
| 9151 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedYScale) | |||
| 9152 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedZScale)) | |||
| 9153 | return fail(); | |||
| 9154 | } else { | |||
| 9155 | if (!proxyEntityHasBits(*buf, bodyEndBit, 2)) | |||
| 9156 | return fail(); | |||
| 9157 | const std::uint8_t dataFlags = buf->get2Bits(); | |||
| 9158 | if (!buf->isGood()) | |||
| 9159 | return fail(); | |||
| 9160 | if (dataFlags == 3) { | |||
| 9161 | //none default value 1,1,1 | |||
| 9162 | } else if (dataFlags == 1) { //x default value 1, y & z use DD(1) | |||
| 9163 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, 1.0, | |||
| 9164 | parsedYScale) | |||
| 9165 | || !readBoundedDefaultDouble(*buf, bodyEndBit, 1.0, | |||
| 9166 | parsedZScale)) | |||
| 9167 | return fail(); | |||
| 9168 | } else if (dataFlags == 2) { | |||
| 9169 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale)) | |||
| 9170 | return fail(); | |||
| 9171 | parsedYScale = parsedZScale = parsedXScale; | |||
| 9172 | } else { //dataFlags == 0 | |||
| 9173 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale) | |||
| 9174 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9175 | parsedYScale) | |||
| 9176 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9177 | parsedZScale)) | |||
| 9178 | return fail(); | |||
| 9179 | } | |||
| 9180 | } | |||
| 9181 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 9182 | || !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint) | |||
| 9183 | || !readBoundedBit(*buf, bodyEndBit, hasAttrib)) | |||
| 9184 | return fail(); | |||
| 9185 | DRW_DBG("scale : ")DRW_dbg::dbg("scale : "); | |||
| 9186 | DRW_DBGPT(parsedXScale, parsedYScale, parsedZScale)DRW_dbg::dbgPT(parsedXScale, parsedYScale, parsedZScale); | |||
| 9187 | DRW_DBG(", angle: ")DRW_dbg::dbg(", angle: "); DRW_DBG(parsedAngle)DRW_dbg::dbg(parsedAngle); | |||
| 9188 | DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); | |||
| 9189 | DRW_DBGPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint.z)DRW_dbg::dbgPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint .z); | |||
| 9190 | ||||
| 9191 | DRW_DBG(" has Attrib: ")DRW_dbg::dbg(" has Attrib: "); DRW_DBG(hasAttrib)DRW_dbg::dbg(hasAttrib); | |||
| 9192 | ||||
| 9193 | if (hasAttrib && version > DRW::AC1015) {//2004+ | |||
| 9194 | if (!readBoundedBitLong(*buf, bodyEndBit, objCount) | |||
| 9195 | || !dwgSafety::validOwnedObjectCount( | |||
| 9196 | objCount, buf->numRemainingBytes())) { | |||
| 9197 | DRW_DBG("\nWARNING: Invalid INSERT owned-attribute count\n")DRW_dbg::dbg("\nWARNING: Invalid INSERT owned-attribute count\n" ); | |||
| 9198 | return fail(); | |||
| 9199 | } | |||
| 9200 | DRW_DBG(" objCount: ")DRW_dbg::dbg(" objCount: "); DRW_DBG(objCount)DRW_dbg::dbg(objCount); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9201 | } | |||
| 9202 | int parsedColCount = 1; | |||
| 9203 | int parsedRowCount = 1; | |||
| 9204 | double parsedColSpace = 0.0; | |||
| 9205 | double parsedRowSpace = 0.0; | |||
| 9206 | if (oType == 8) {//entity are minsert | |||
| 9207 | std::uint16_t colCount = 0; | |||
| 9208 | std::uint16_t rowCount = 0; | |||
| 9209 | if (!readBoundedBitShort(*buf, bodyEndBit, colCount) | |||
| 9210 | || !readBoundedBitShort(*buf, bodyEndBit, rowCount) | |||
| 9211 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedColSpace) | |||
| 9212 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRowSpace)) | |||
| 9213 | return fail(); | |||
| 9214 | parsedColCount = static_cast<int>(colCount); | |||
| 9215 | parsedRowCount = static_cast<int>(rowCount); | |||
| 9216 | } | |||
| 9217 | const auto finite = [](const DRW_Coord& point) { | |||
| 9218 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 9219 | && std::isfinite(point.z); | |||
| 9220 | }; | |||
| 9221 | if (!finite(parsedBasePoint) || !finite(parsedExtPoint) | |||
| 9222 | || !std::isfinite(parsedXScale) || !std::isfinite(parsedYScale) | |||
| 9223 | || !std::isfinite(parsedZScale) || !std::isfinite(parsedAngle) | |||
| 9224 | || !std::isfinite(parsedColSpace) || !std::isfinite(parsedRowSpace)) | |||
| 9225 | return fail(); | |||
| 9226 | 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"); | |||
| 9227 | std::uint64_t handleEndBit = 0; | |||
| 9228 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 9229 | handleEndBit)) | |||
| 9230 | return fail(); | |||
| 9231 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 9232 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 9233 | handleEndBit)) | |||
| 9234 | return fail(); | |||
| 9235 | dwgHandle parsedBlockRecH; | |||
| 9236 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9237 | parsedBlockRecH)) | |||
| 9238 | return fail(); | |||
| 9239 | dwgHandle parsedSeqendH; | |||
| 9240 | 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"); | |||
| 9241 | 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"); | |||
| 9242 | ||||
| 9243 | /*attribs follows*/ | |||
| 9244 | if (hasAttrib) { | |||
| 9245 | const std::int32_t expectedCount = | |||
| 9246 | version < DRW::AC1018 ? 2 : objCount; | |||
| 9247 | if (!DRW::reserve(parsedAttribHandles, expectedCount)) | |||
| 9248 | return fail(); | |||
| 9249 | if (version < DRW::AC1018) {//2000- | |||
| 9250 | dwgHandle attH; | |||
| 9251 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9252 | attH)) | |||
| 9253 | return fail(); | |||
| 9254 | 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"); | |||
| 9255 | parsedAttribHandles.push_back(attH); | |||
| 9256 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9257 | attH)) | |||
| 9258 | return fail(); | |||
| 9259 | 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"); | |||
| 9260 | parsedAttribHandles.push_back(attH); | |||
| 9261 | } else { | |||
| 9262 | for (std::int32_t i=0; i < objCount; ++i){ | |||
| 9263 | dwgHandle attH; | |||
| 9264 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, | |||
| 9265 | false, attH)) | |||
| 9266 | return fail(); | |||
| 9267 | 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"); | |||
| 9268 | parsedAttribHandles.push_back(attH); | |||
| 9269 | } | |||
| 9270 | } | |||
| 9271 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9272 | parsedSeqendH)) | |||
| 9273 | return fail(); | |||
| 9274 | 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"); | |||
| 9275 | } | |||
| 9276 | 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"); | |||
| 9277 | ||||
| 9278 | if (!handleProbe.isGood()) | |||
| 9279 | return fail(); | |||
| 9280 | *sourceBuf = handleProbe; | |||
| 9281 | basePoint = parsedBasePoint; | |||
| 9282 | xscale = parsedXScale; | |||
| 9283 | yscale = parsedYScale; | |||
| 9284 | zscale = parsedZScale; | |||
| 9285 | angle = parsedAngle; | |||
| 9286 | extPoint = parsedExtPoint; | |||
| 9287 | colcount = parsedColCount; | |||
| 9288 | rowcount = parsedRowCount; | |||
| 9289 | colspace = parsedColSpace; | |||
| 9290 | rowspace = parsedRowSpace; | |||
| 9291 | blockRecH = parsedBlockRecH; | |||
| 9292 | seqendH = parsedSeqendH; | |||
| 9293 | attribHandles = std::move(parsedAttribHandles); | |||
| 9294 | // RS crc; //RS */ | |||
| 9295 | return true; | |||
| 9296 | } | |||
| 9297 | ||||
| 9298 | void DRW_Table::resetDwgState() { | |||
| 9299 | DRW_Insert::resetDwgState(); | |||
| 9300 | name.clear(); | |||
| 9301 | xscale = yscale = zscale = 1.0; | |||
| 9302 | angle = 0.0; | |||
| 9303 | colcount = rowcount = 1; | |||
| 9304 | colspace = rowspace = 0.0; | |||
| 9305 | m_valueFlag = 0; | |||
| 9306 | m_horizontalDirection = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 9307 | m_hasSemanticContent = false; | |||
| 9308 | m_semanticContentComplete = false; | |||
| 9309 | m_tableStyleHandle = 0; | |||
| 9310 | m_content = DRW_TableContent{}; | |||
| 9311 | m_dxfSubclass = DxfSubclass::Entity; | |||
| 9312 | m_dxfRowsExpected = -1; | |||
| 9313 | m_dxfColumnsExpected = -1; | |||
| 9314 | m_dxfRowHeightsRead = 0; | |||
| 9315 | m_dxfColumnWidthsRead = 0; | |||
| 9316 | m_dxfNextCell = 0; | |||
| 9317 | m_dxfCurrentCell = -1; | |||
| 9318 | m_dxfInCellValue = false; | |||
| 9319 | } | |||
| 9320 | ||||
| 9321 | bool DRW_Table::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 9322 | resetDwgState(); | |||
| 9323 | auto fail = [this, buf]() { | |||
| 9324 | if (buf != nullptr) | |||
| 9325 | buf->invalidate(); | |||
| 9326 | resetDwgState(); | |||
| 9327 | return false; | |||
| 9328 | }; | |||
| 9329 | if (buf == nullptr || version < DRW::AC1015) | |||
| 9330 | return fail(); | |||
| 9331 | ||||
| 9332 | dwgBuffer *sourceBuf = buf; | |||
| 9333 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 9334 | buf = &bodyProbe; | |||
| 9335 | auto commit = [&]() { | |||
| 9336 | *sourceBuf = bodyProbe; | |||
| 9337 | return true; | |||
| 9338 | }; | |||
| 9339 | ||||
| 9340 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 9341 | sBuff.setVariableTextByteLength(true); | |||
| 9342 | dwgBuffer *sBuf = &sBuff; | |||
| 9343 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 9344 | if (!ret) | |||
| 9345 | return fail(); | |||
| 9346 | ||||
| 9347 | DRW_DBG("\n************************** parsing table *****************************************\n")DRW_dbg::dbg("\n************************** parsing table *****************************************\n" ); | |||
| 9348 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 9349 | DRW_Coord parsedBasePoint; | |||
| 9350 | std::uint8_t dataFlags = 0; | |||
| 9351 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 9352 | || !proxyEntityHasBits(*buf, bodyEndBit, 2)) | |||
| 9353 | return fail(); | |||
| 9354 | dataFlags = buf->get2Bits(); | |||
| 9355 | if (!buf->isGood()) | |||
| 9356 | return fail(); | |||
| 9357 | ||||
| 9358 | double parsedXScale = 1.0; | |||
| 9359 | double parsedYScale = 1.0; | |||
| 9360 | double parsedZScale = 1.0; | |||
| 9361 | if (dataFlags == 3) { | |||
| 9362 | // default scale 1,1,1 | |||
| 9363 | } else if (dataFlags == 1) { | |||
| 9364 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9365 | parsedYScale) | |||
| 9366 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9367 | parsedZScale)) | |||
| 9368 | return fail(); | |||
| 9369 | } else if (dataFlags == 2) { | |||
| 9370 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale)) | |||
| 9371 | return fail(); | |||
| 9372 | parsedYScale = parsedZScale = parsedXScale; | |||
| 9373 | } else { | |||
| 9374 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale) | |||
| 9375 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9376 | parsedYScale) | |||
| 9377 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9378 | parsedZScale)) | |||
| 9379 | return fail(); | |||
| 9380 | } | |||
| 9381 | ||||
| 9382 | double parsedAngle = 0.0; | |||
| 9383 | DRW_Coord parsedExtPoint; | |||
| 9384 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 9385 | || !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint)) | |||
| 9386 | return fail(); | |||
| 9387 | ||||
| 9388 | if (!sBuf->isGood()) | |||
| 9389 | return fail(); | |||
| 9390 | ||||
| 9391 | std::int32_t objCount = 0; | |||
| 9392 | bool hasAttrib = false; | |||
| 9393 | if (!readBoundedBit(*buf, bodyEndBit, hasAttrib)) | |||
| 9394 | return fail(); | |||
| 9395 | if (hasAttrib && version > DRW::AC1015) { | |||
| 9396 | if (!readBoundedBitLong(*buf, bodyEndBit, objCount) | |||
| 9397 | || !dwgSafety::validOwnedObjectCount( | |||
| 9398 | objCount, buf->numRemainingBytes())) { | |||
| 9399 | DRW_DBG("\nWARNING: Invalid TABLE owned-attribute count\n")DRW_dbg::dbg("\nWARNING: Invalid TABLE owned-attribute count\n" ); | |||
| 9400 | return fail(); | |||
| 9401 | } | |||
| 9402 | } | |||
| 9403 | ||||
| 9404 | std::uint64_t handleEndBit = 0; | |||
| 9405 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 9406 | handleEndBit)) | |||
| 9407 | return fail(); | |||
| 9408 | dwgBuffer hBuff = buf->forkIndependent(); | |||
| 9409 | if (version <= DRW::AC1018) { | |||
| 9410 | // R2000/R2004: parseDwgEntHandle only re-seeks to the handle stream | |||
| 9411 | // for version > AC1018 (2007+ string area). For the legacy versions | |||
| 9412 | // seek the snapshot to the handle-stream start (objSize is the | |||
| 9413 | // bit offset of the handle stream, RL field read in | |||
| 9414 | // DRW_Entity::parseDwg) or every handle below reads mid-DATA garbage. | |||
| 9415 | if (!hBuff.setPosition(objSize >> 3)) | |||
| 9416 | return fail(); | |||
| 9417 | hBuff.setBitPos(objSize & 7); | |||
| 9418 | } | |||
| 9419 | ret = DRW_Entity::parseDwgEntHandle(version, &hBuff, true, | |||
| 9420 | handleEndBit); | |||
| 9421 | if (!ret) | |||
| 9422 | return fail(); | |||
| 9423 | dwgHandle parsedBlockRecH; | |||
| 9424 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9425 | parsedBlockRecH)) | |||
| 9426 | return fail(); | |||
| 9427 | ||||
| 9428 | std::vector<dwgHandle> parsedAttribHandles; | |||
| 9429 | dwgHandle parsedSeqendH; | |||
| 9430 | ||||
| 9431 | if (hasAttrib) { | |||
| 9432 | if (!DRW::reserve(parsedAttribHandles, objCount)) | |||
| 9433 | return fail(); | |||
| 9434 | for (std::int32_t i = 0; i < objCount; ++i) { | |||
| 9435 | dwgHandle attribHandle; | |||
| 9436 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9437 | attribHandle)) | |||
| 9438 | return fail(); | |||
| 9439 | parsedAttribHandles.push_back(attribHandle); | |||
| 9440 | } | |||
| 9441 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9442 | parsedSeqendH)) | |||
| 9443 | return fail(); | |||
| 9444 | } | |||
| 9445 | ||||
| 9446 | if (!hBuff.isGood()) | |||
| 9447 | return fail(); | |||
| 9448 | ||||
| 9449 | blockRecH = parsedBlockRecH; | |||
| 9450 | seqendH = parsedSeqendH; | |||
| 9451 | attribHandles = std::move(parsedAttribHandles); | |||
| 9452 | basePoint = parsedBasePoint; | |||
| 9453 | xscale = parsedXScale; | |||
| 9454 | yscale = parsedYScale; | |||
| 9455 | zscale = parsedZScale; | |||
| 9456 | angle = parsedAngle; | |||
| 9457 | extPoint = parsedExtPoint; | |||
| 9458 | ||||
| 9459 | if (version >= DRW::AC1024) { | |||
| 9460 | std::uint8_t ignoredTableVersion = 0; | |||
| 9461 | if (!readBoundedRawChar8(*buf, bodyEndBit, ignoredTableVersion)) | |||
| 9462 | return fail(); | |||
| 9463 | dwgHandle parsedTableStyleHandle; | |||
| 9464 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9465 | parsedTableStyleHandle)) | |||
| 9466 | return fail(); | |||
| 9467 | const std::uint32_t tableStyleHandle = parsedTableStyleHandle.ref; | |||
| 9468 | std::int32_t ignoredContentFlag = 0; | |||
| 9469 | if (!readBoundedBitLong(*buf, bodyEndBit, ignoredContentFlag)) | |||
| 9470 | return fail(); | |||
| 9471 | if (version >= DRW::AC1027) { | |||
| 9472 | std::int32_t ignoredContentVersion = 0; | |||
| 9473 | if (!readBoundedBitLong(*buf, bodyEndBit, ignoredContentVersion)) | |||
| 9474 | return fail(); | |||
| 9475 | } else { | |||
| 9476 | bool ignoredContentBit = false; | |||
| 9477 | if (!readBoundedBit(*buf, bodyEndBit, ignoredContentBit)) | |||
| 9478 | return fail(); | |||
| 9479 | } | |||
| 9480 | ||||
| 9481 | if (!buf->isGood() || !hBuff.isGood()) | |||
| 9482 | return fail(); | |||
| 9483 | ||||
| 9484 | m_hasSemanticContent = true; | |||
| 9485 | // TABLECONTENT is an optional semantic tail. Decode it on independent | |||
| 9486 | // cursors so a newer/partially supported cell variant cannot poison the | |||
| 9487 | // already validated entity prefix and common handle stream. | |||
| 9488 | dwgBuffer contentBuf = buf->forkIndependent(); | |||
| 9489 | dwgBuffer contentStringBuf = sBuf->forkIndependent(); | |||
| 9490 | dwgBuffer contentHandleBuf = hBuff.forkIndependent(); | |||
| 9491 | TableDwgBounds tableBounds; | |||
| 9492 | tableBounds.bodyEndBit = tableBodyEndBit(version, sBuf, objSize); | |||
| 9493 | if (version > DRW::AC1021) { | |||
| 9494 | std::uint64_t stringStartBit = 0; | |||
| 9495 | if (!contentStringBuf.getR2007StringStreamBounds( | |||
| 9496 | objSize, stringStartBit, tableBounds.stringEndBit)) | |||
| 9497 | return fail(); | |||
| 9498 | } else { | |||
| 9499 | tableBounds.stringEndBit = proxyEntityEndBit(contentStringBuf, 0); | |||
| 9500 | } | |||
| 9501 | tableBounds.handleEndBit = handleEndBit; | |||
| 9502 | DRW_TableContent parsedContent; | |||
| 9503 | m_semanticContentComplete = parseTableContent( | |||
| 9504 | version, &contentBuf, &contentStringBuf, &contentHandleBuf, | |||
| 9505 | parsedContent, tableBounds); | |||
| 9506 | // parseTableContent fills columns (and any rows before the row/cell | |||
| 9507 | // that failed) before reporting incompleteness. That grid geometry | |||
| 9508 | // was validated against its own bounds and is still useful even | |||
| 9509 | // when a later cell could not be decoded, so keep it regardless of | |||
| 9510 | // m_semanticContentComplete instead of dropping it with the shell. | |||
| 9511 | m_content = std::move(parsedContent); | |||
| 9512 | if (m_content.m_tableStyleHandle != 0) | |||
| 9513 | m_tableStyleHandle = m_content.m_tableStyleHandle; | |||
| 9514 | else | |||
| 9515 | m_tableStyleHandle = tableStyleHandle; | |||
| 9516 | if (!m_semanticContentComplete || !contentBuf.isGood() | |||
| 9517 | || !contentStringBuf.isGood() || !contentHandleBuf.isGood()) { | |||
| 9518 | // The frame, entity prefix, and common handles remain valid. Keep | |||
| 9519 | // the typed table shell and allow the raw DWG frame to preserve | |||
| 9520 | // content that this reader does not yet model. | |||
| 9521 | m_semanticContentComplete = false; | |||
| 9522 | return commit(); | |||
| 9523 | } | |||
| 9524 | *buf = contentBuf; | |||
| 9525 | *sBuf = contentStringBuf; | |||
| 9526 | hBuff = contentHandleBuf; | |||
| 9527 | if (!buf->isGood() || !sBuf->isGood() || !hBuff.isGood()) | |||
| 9528 | return fail(); | |||
| 9529 | if (!m_semanticContentComplete) { | |||
| 9530 | DRW_DBG("TABLECONTENT parse incomplete; anonymous block insert kept\n")DRW_dbg::dbg("TABLECONTENT parse incomplete; anonymous block insert kept\n" ); | |||
| 9531 | return commit(); | |||
| 9532 | } | |||
| 9533 | ||||
| 9534 | std::uint16_t ignoredTableFlags = 0; | |||
| 9535 | DRW_Coord parsedHorizontalDirection; | |||
| 9536 | if (!readBoundedBitShort(*buf, bodyEndBit, ignoredTableFlags) | |||
| 9537 | || !readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9538 | parsedHorizontalDirection)) | |||
| 9539 | return fail(); | |||
| 9540 | m_horizontalDirection = parsedHorizontalDirection; | |||
| 9541 | ||||
| 9542 | const std::uint64_t breakStartBit = currentDwgBit(buf); | |||
| 9543 | std::int32_t breakDataFlag = 0; | |||
| 9544 | if (!readBoundedBitLong(*buf, bodyEndBit, breakDataFlag)) | |||
| 9545 | return fail(); | |||
| 9546 | const bool hasBreakData = breakDataFlag != 0; | |||
| 9547 | if (hasBreakData) { | |||
| 9548 | std::int32_t ignoredBreakType = 0; | |||
| 9549 | double ignoredBreakDistance = 0.0; | |||
| 9550 | std::int32_t manualPositionCount = 0; | |||
| 9551 | if (!readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9552 | || !readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9553 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 9554 | ignoredBreakDistance) | |||
| 9555 | || !readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9556 | || !readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9557 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9558 | manualPositionCount)) | |||
| 9559 | return fail(); | |||
| 9560 | if (manualPositionCount < 0 | |||
| 9561 | || static_cast<std::uint32_t>(manualPositionCount) | |||
| 9562 | > kMaxTableItems) { | |||
| 9563 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9564 | "table-break-data", breakStartBit, currentDwgBit(buf), | |||
| 9565 | version, manualPositionCount, false)); | |||
| 9566 | return commit(); | |||
| 9567 | } | |||
| 9568 | for (std::int32_t i = 0; i < manualPositionCount; ++i) { | |||
| 9569 | DRW_Coord ignoredPosition; | |||
| 9570 | double ignoredRotation = 0.0; | |||
| 9571 | std::int32_t ignoredPositionType = 0; | |||
| 9572 | if (!readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9573 | ignoredPosition) | |||
| 9574 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 9575 | ignoredRotation) | |||
| 9576 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9577 | ignoredPositionType)) | |||
| 9578 | return fail(); | |||
| 9579 | } | |||
| 9580 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9581 | "table-break-data", breakStartBit, currentDwgBit(buf), | |||
| 9582 | version, static_cast<std::uint32_t>(manualPositionCount), | |||
| 9583 | buf->isGood())); | |||
| 9584 | } | |||
| 9585 | ||||
| 9586 | const std::uint64_t rowRangeStartBit = currentDwgBit(buf); | |||
| 9587 | std::int32_t rowRangeCount = 0; | |||
| 9588 | if (!readBoundedBitLong(*buf, bodyEndBit, rowRangeCount)) | |||
| 9589 | return fail(); | |||
| 9590 | if (rowRangeCount >= 0 | |||
| 9591 | && static_cast<std::uint32_t>(rowRangeCount) <= kMaxTableItems) { | |||
| 9592 | for (std::int32_t i = 0; i < rowRangeCount; ++i) { | |||
| 9593 | DRW_Coord ignoredRangePoint; | |||
| 9594 | std::int32_t ignoredRangeValue = 0; | |||
| 9595 | if (!readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9596 | ignoredRangePoint) | |||
| 9597 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9598 | ignoredRangeValue) | |||
| 9599 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9600 | ignoredRangeValue)) | |||
| 9601 | return fail(); | |||
| 9602 | } | |||
| 9603 | if (rowRangeCount != 0) { | |||
| 9604 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9605 | "table-row-ranges", rowRangeStartBit, currentDwgBit(buf), | |||
| 9606 | version, static_cast<std::uint32_t>(rowRangeCount), | |||
| 9607 | buf->isGood())); | |||
| 9608 | } | |||
| 9609 | } else { | |||
| 9610 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9611 | "table-row-ranges", rowRangeStartBit, currentDwgBit(buf), | |||
| 9612 | version, rowRangeCount, false)); | |||
| 9613 | } | |||
| 9614 | ||||
| 9615 | if (!buf->isGood() || !sBuf->isGood() || !hBuff.isGood()) | |||
| 9616 | return fail(); | |||
| 9617 | return commit(); | |||
| 9618 | } | |||
| 9619 | ||||
| 9620 | std::uint16_t parsedValueFlag = 0; | |||
| 9621 | DRW_Coord parsedHorizontalDirection; | |||
| 9622 | std::int32_t parsedColumnCount = 0; | |||
| 9623 | std::int32_t parsedRowCount = 0; | |||
| 9624 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedValueFlag) | |||
| 9625 | || !readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9626 | parsedHorizontalDirection) | |||
| 9627 | || !readBoundedBitLong(*buf, bodyEndBit, parsedColumnCount) | |||
| 9628 | || !readBoundedBitLong(*buf, bodyEndBit, parsedRowCount) | |||
| 9629 | || parsedColumnCount < 0 || parsedRowCount < 0) | |||
| 9630 | return fail(); | |||
| 9631 | const std::uint32_t columns = static_cast<std::uint32_t>(parsedColumnCount); | |||
| 9632 | const std::uint32_t rows = static_cast<std::uint32_t>(parsedRowCount); | |||
| 9633 | if (columns > kMaxTableColumns || rows > kMaxTableRows | |||
| 9634 | || (columns != 0 && rows > kMaxTableCells / columns)) { | |||
| 9635 | return fail(); | |||
| 9636 | } | |||
| 9637 | ||||
| 9638 | m_hasSemanticContent = true; | |||
| 9639 | m_semanticContentComplete = false; | |||
| 9640 | m_content.m_columns.clear(); | |||
| 9641 | m_content.m_rows.clear(); | |||
| 9642 | if (!DRW::reserve(m_content.m_columns, static_cast<int>(columns)) | |||
| 9643 | || !DRW::reserve(m_content.m_rows, static_cast<int>(rows))) | |||
| 9644 | return fail(); | |||
| 9645 | for (std::uint32_t i = 0; i < columns; ++i) { | |||
| 9646 | DRW_TableColumn column; | |||
| 9647 | if (!readBoundedBitDouble(*buf, bodyEndBit, column.m_width)) | |||
| 9648 | return fail(); | |||
| 9649 | m_content.m_columns.push_back(column); | |||
| 9650 | } | |||
| 9651 | for (std::uint32_t i = 0; i < rows; ++i) { | |||
| 9652 | DRW_TableRow row; | |||
| 9653 | if (!readBoundedBitDouble(*buf, bodyEndBit, row.m_height)) | |||
| 9654 | return fail(); | |||
| 9655 | if (!DRW::reserve(row.m_cells, static_cast<int>(columns))) | |||
| 9656 | return fail(); | |||
| 9657 | if (!DRW::resize(row.m_cells, static_cast<int>(columns))) | |||
| 9658 | return fail(); | |||
| 9659 | m_content.m_rows.push_back(row); | |||
| 9660 | } | |||
| 9661 | dwgHandle parsedTableStyleHandle; | |||
| 9662 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9663 | parsedTableStyleHandle)) | |||
| 9664 | return fail(); | |||
| 9665 | m_tableStyleHandle = parsedTableStyleHandle.ref; | |||
| 9666 | if (!hBuff.isGood()) | |||
| 9667 | return fail(); | |||
| 9668 | m_content.m_tableStyleHandle = m_tableStyleHandle; | |||
| 9669 | m_semanticContentComplete = true; | |||
| 9670 | // Decode the cell grid on independent cursors, as the R2010+ path does for | |||
| 9671 | // TABLECONTENT. Everything read so far (base point, block record, owned | |||
| 9672 | // attributes, grid geometry, table style) is validated, so a cell this | |||
| 9673 | // reader cannot decode costs the semantic grid and nothing else: the | |||
| 9674 | // anonymous *T block that the INSERT part refers to still draws the table. | |||
| 9675 | // A failing cell used to invalidate the shared cursors, and the closing | |||
| 9676 | // isGood() check then rejected the whole entity, which fails the block | |||
| 9677 | // that owns it. The cursors are adopted only when the whole grid decoded. | |||
| 9678 | dwgBuffer contentBuf = buf->forkIndependent(); | |||
| 9679 | dwgBuffer contentStringBuf = sBuf->forkIndependent(); | |||
| 9680 | dwgBuffer contentHandleBuf = hBuff.forkIndependent(); | |||
| 9681 | // For <=AC1018 (R2000/R2004) there is no separate R2007+ string stream: | |||
| 9682 | // DRW_Entity::parseDwg only seeks sBuf when version > AC1018 (see the | |||
| 9683 | // `strBuf != NULL && version > DRW::AC1018` guard there), so legacy cell | |||
| 9684 | // text is inline in `buf`. Passing the stale sBuf copy here would read | |||
| 9685 | // text from the wrong position and desync `buf`. Pass nullptr so the | |||
| 9686 | // cell readers' `textBuf = strBuf ? strBuf : buf` falls back to the | |||
| 9687 | // inline `buf`. R2007 (AC1021) keeps the separate sBuf stream. | |||
| 9688 | dwgBuffer *cellStrBuf = (version > DRW::AC1018) ? &contentStringBuf : nullptr; | |||
| 9689 | TableDwgBounds tableBounds; | |||
| 9690 | tableBounds.bodyEndBit = bodyEndBit; | |||
| 9691 | tableBounds.stringEndBit = cellStrBuf == nullptr | |||
| 9692 | ? bodyEndBit : proxyEntityEndBit(*cellStrBuf, 0); | |||
| 9693 | tableBounds.handleEndBit = handleEndBit; | |||
| 9694 | for (std::uint32_t row = 0; row < rows && m_semanticContentComplete; ++row) { | |||
| 9695 | for (std::uint32_t column = 0; column < columns; ++column) { | |||
| 9696 | if (!parseR2007TableCell(version, &contentBuf, cellStrBuf, | |||
| 9697 | &contentHandleBuf, | |||
| 9698 | m_content.m_rows[row].m_cells[column], | |||
| 9699 | &m_content.m_subrecordRanges, | |||
| 9700 | tableBounds)) { | |||
| 9701 | m_semanticContentComplete = false; | |||
| 9702 | break; | |||
| 9703 | } | |||
| 9704 | } | |||
| 9705 | } | |||
| 9706 | ||||
| 9707 | if (m_semanticContentComplete) | |||
| 9708 | m_semanticContentComplete = skipR2007TableOverrides( | |||
| 9709 | version, &contentBuf, cellStrBuf, &contentHandleBuf, | |||
| 9710 | &m_content.m_subrecordRanges, tableBounds); | |||
| 9711 | if (m_semanticContentComplete | |||
| 9712 | && (!contentBuf.isGood() | |||
| 9713 | || (cellStrBuf != nullptr && !contentStringBuf.isGood()) | |||
| 9714 | || !contentHandleBuf.isGood())) | |||
| 9715 | m_semanticContentComplete = false; | |||
| 9716 | if (m_semanticContentComplete) { | |||
| 9717 | *buf = contentBuf; | |||
| 9718 | if (cellStrBuf != nullptr) | |||
| 9719 | *sBuf = contentStringBuf; | |||
| 9720 | hBuff = contentHandleBuf; | |||
| 9721 | } else { | |||
| 9722 | 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" ); | |||
| 9723 | } | |||
| 9724 | ||||
| 9725 | if (!buf->isGood() || !sBuf->isGood() || !hBuff.isGood()) | |||
| 9726 | return fail(); | |||
| 9727 | m_valueFlag = parsedValueFlag; | |||
| 9728 | m_horizontalDirection = parsedHorizontalDirection; | |||
| 9729 | return commit(); | |||
| 9730 | } | |||
| 9731 | ||||
| 9732 | bool DRW_TableContentObject::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 9733 | reset(); | |||
| 9734 | const auto fail = [this, buf]() { | |||
| 9735 | if (buf != nullptr) | |||
| 9736 | buf->invalidate(); | |||
| 9737 | reset(); | |||
| 9738 | return false; | |||
| 9739 | }; | |||
| 9740 | if (buf == nullptr || version <= DRW::AC1018) | |||
| 9741 | return fail(); | |||
| 9742 | ||||
| 9743 | dwgBuffer sBuff = *buf; | |||
| 9744 | sBuff.setVariableTextByteLength(true); | |||
| 9745 | dwgBuffer *sBuf = &sBuff; | |||
| 9746 | bool ret = DRW_TableEntry::parseDwg(version, buf, sBuf, bs); | |||
| 9747 | DRW_DBG("\n************************** parsing table content object ************************\n")DRW_dbg::dbg("\n************************** parsing table content object ************************\n" ); | |||
| 9748 | if (!ret) | |||
| 9749 | return fail(); | |||
| 9750 | ||||
| 9751 | dwgBuffer bodyBuff = *buf; | |||
| 9752 | dwgBuffer *bodyBuf = &bodyBuff; | |||
| 9753 | ||||
| 9754 | dwgBuffer hBuff = *buf; | |||
| 9755 | seekTableObjectHandleStream(version, &hBuff, objSize); | |||
| 9756 | std::uint64_t handleEndBit = 0; | |||
| 9757 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit)) | |||
| 9758 | return fail(); | |||
| 9759 | std::uint32_t parsedParentHandle = 0; | |||
| 9760 | std::vector<std::uint32_t> parsedReactors; | |||
| 9761 | std::uint32_t parsedXDictHandle = 0; | |||
| 9762 | if (!readTableObjectCommonHandles(&hBuff, handle, numReactors, xDictFlag, | |||
| 9763 | &parsedParentHandle, &parsedReactors, | |||
| 9764 | &parsedXDictHandle, handleEndBit)) | |||
| 9765 | return fail(); | |||
| 9766 | ||||
| 9767 | DRW_TableContent parsedContent; | |||
| 9768 | TableDwgBounds tableBounds; | |||
| 9769 | tableBounds.bodyEndBit = tableBodyEndBit(version, sBuf, objSize); | |||
| 9770 | tableBounds.stringEndBit = proxyEntityEndBit(*sBuf, 0); | |||
| 9771 | tableBounds.handleEndBit = handleEndBit; | |||
| 9772 | const bool parseComplete = parseTableContent( | |||
| 9773 | version, bodyBuf, sBuf, &hBuff, parsedContent, tableBounds); | |||
| 9774 | const std::uint64_t bodyBitOffset = | |||
| 9775 | bodyBuf->getPosition() * 8u + bodyBuf->getBitPos(); | |||
| 9776 | if (!parseComplete || !bodyBuf->isGood() || !sBuf->isGood() | |||
| 9777 | || !hBuff.isGood() || bodyBitOffset > objSize) | |||
| 9778 | return fail(); | |||
| 9779 | ||||
| 9780 | m_content = std::move(parsedContent); | |||
| 9781 | m_parseComplete = true; | |||
| 9782 | parentHandle = parsedParentHandle; | |||
| 9783 | reactorHandles = std::move(parsedReactors); | |||
| 9784 | xDictHandle = parsedXDictHandle; | |||
| 9785 | return true; | |||
| 9786 | } | |||
| 9787 | ||||
| 9788 | void DRW_LWPolyline::applyExtrusion(){ | |||
| 9789 | if (haveExtrusion) { | |||
| 9790 | calculateAxis(extPoint); | |||
| 9791 | for (unsigned int i=0; i<vertlist.size(); i++) { | |||
| 9792 | auto& vert = vertlist.at(i); | |||
| 9793 | DRW_Coord v(vert->x, vert->y, elevation); | |||
| 9794 | extrudePoint(extPoint, &v); | |||
| 9795 | vert->x = v.x; | |||
| 9796 | vert->y = v.y; | |||
| 9797 | } | |||
| 9798 | } | |||
| 9799 | } | |||
| 9800 | ||||
| 9801 | bool DRW_LWPolyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 9802 | switch (code) { | |||
| 9803 | case 10: { | |||
| 9804 | if (vertlist.size() >= static_cast<std::size_t>(kMaxLWPolylineVertices) | |||
| 9805 | || (m_dxfVertexCountSeen | |||
| 9806 | && vertlist.size() >= static_cast<std::size_t>(vertexnum))) | |||
| 9807 | return false; | |||
| 9808 | vertex = std::make_shared<DRW_Vertex2D>(); | |||
| 9809 | vertlist.push_back(vertex); | |||
| 9810 | vertex->x = reader->getDouble(); | |||
| 9811 | break; } | |||
| 9812 | case 20: | |||
| 9813 | if(vertex) | |||
| 9814 | vertex->y = reader->getDouble(); | |||
| 9815 | break; | |||
| 9816 | case 40: | |||
| 9817 | if(vertex) | |||
| 9818 | vertex->stawidth = reader->getDouble(); | |||
| 9819 | break; | |||
| 9820 | case 41: | |||
| 9821 | if(vertex) | |||
| 9822 | vertex->endwidth = reader->getDouble(); | |||
| 9823 | break; | |||
| 9824 | case 42: | |||
| 9825 | if(vertex) | |||
| 9826 | vertex->bulge = reader->getDouble(); | |||
| 9827 | break; | |||
| 9828 | case 91: | |||
| 9829 | if (vertex) | |||
| 9830 | vertex->identifier = reader->getInt32(); | |||
| 9831 | break; | |||
| 9832 | case 38: | |||
| 9833 | elevation = reader->getDouble(); | |||
| 9834 | break; | |||
| 9835 | case 39: | |||
| 9836 | thickness = reader->getDouble(); | |||
| 9837 | break; | |||
| 9838 | case 43: | |||
| 9839 | width = reader->getDouble(); | |||
| 9840 | break; | |||
| 9841 | case 70: | |||
| 9842 | flags = reader->getInt32(); | |||
| 9843 | break; | |||
| 9844 | case 90: | |||
| 9845 | if (m_dxfVertexCountSeen) | |||
| 9846 | return false; | |||
| 9847 | vertexnum = reader->getInt32(); | |||
| 9848 | if (!isValidCount(vertexnum, kMaxLWPolylineVertices)) | |||
| 9849 | return false; | |||
| 9850 | m_dxfVertexCountSeen = true; | |||
| 9851 | return DRW::reserve(vertlist, vertexnum); | |||
| 9852 | case 210: | |||
| 9853 | haveExtrusion = true; | |||
| 9854 | extPoint.x = reader->getDouble(); | |||
| 9855 | break; | |||
| 9856 | case 220: | |||
| 9857 | extPoint.y = reader->getDouble(); | |||
| 9858 | break; | |||
| 9859 | case 230: | |||
| 9860 | extPoint.z = reader->getDouble(); | |||
| 9861 | break; | |||
| 9862 | default: | |||
| 9863 | return DRW_Entity::parseCode(code, reader); | |||
| 9864 | } | |||
| 9865 | ||||
| 9866 | return true; | |||
| 9867 | } | |||
| 9868 | ||||
| 9869 | bool DRW_LWPolyline::validateDxf() const { | |||
| 9870 | return (!m_dxfVertexCountSeen | |||
| 9871 | || vertlist.size() == static_cast<std::size_t>(vertexnum)) | |||
| 9872 | && validatePayloadFields(); | |||
| 9873 | } | |||
| 9874 | ||||
| 9875 | bool DRW_LWPolyline::validatePayloadFields() const { | |||
| 9876 | const auto finite = [](double value) { return std::isfinite(value); }; | |||
| 9877 | const auto finiteVertex = [&finite](const auto& vertex) { | |||
| 9878 | return vertex != nullptr && finite(vertex->x) && finite(vertex->y) | |||
| 9879 | && finite(vertex->stawidth) && finite(vertex->endwidth) | |||
| 9880 | && finite(vertex->bulge) | |||
| 9881 | && vertex->identifier >= std::numeric_limits<std::int32_t>::min() | |||
| 9882 | && vertex->identifier <= std::numeric_limits<std::int32_t>::max(); | |||
| 9883 | }; | |||
| 9884 | ||||
| 9885 | // LWPOLYLINE group 70 has only the closed and linetype-generation bits. | |||
| 9886 | return flags >= 0 && (flags & ~0x81) == 0 | |||
| 9887 | && finite(width) && finite(elevation) && finite(thickness) | |||
| 9888 | && finite(extPoint.x) && finite(extPoint.y) && finite(extPoint.z) | |||
| 9889 | && vertlist.size() <= static_cast<std::size_t>(kMaxLWPolylineVertices) | |||
| 9890 | && vertlist.size() | |||
| 9891 | <= static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max()) | |||
| 9892 | && std::all_of(vertlist.cbegin(), vertlist.cend(), finiteVertex); | |||
| 9893 | } | |||
| 9894 | ||||
| 9895 | bool DRW_LWPolyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 9896 | const auto resetState = [this]() { | |||
| 9897 | DRW_Entity::reset(); | |||
| 9898 | vertexnum = 0; | |||
| 9899 | flags = 0; | |||
| 9900 | width = 0.0; | |||
| 9901 | elevation = 0.0; | |||
| 9902 | thickness = 0.0; | |||
| 9903 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 9904 | vertlist.clear(); | |||
| 9905 | vertex.reset(); | |||
| 9906 | m_dxfVertexCountSeen = false; | |||
| 9907 | }; | |||
| 9908 | resetState(); | |||
| 9909 | dwgBuffer *sourceBuf = buf; | |||
| 9910 | const auto fail = [sourceBuf, resetState]() { | |||
| 9911 | if (sourceBuf != nullptr) | |||
| 9912 | sourceBuf->invalidate(); | |||
| 9913 | resetState(); | |||
| 9914 | return false; | |||
| 9915 | }; | |||
| 9916 | if (sourceBuf == nullptr) | |||
| 9917 | return fail(); | |||
| 9918 | ||||
| 9919 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 9920 | buf = &bodyProbe; | |||
| 9921 | bool ret = DRW_Entity::parseDwgCommon(version, buf, bs); | |||
| 9922 | if (!ret || !buf->isGood()) | |||
| 9923 | return fail(); | |||
| 9924 | DRW_DBG("\n***************************** parsing LWPolyline *******************************************\n")DRW_dbg::dbg("\n***************************** parsing LWPolyline *******************************************\n" ); | |||
| 9925 | ||||
| 9926 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 9927 | std::uint16_t rawFlagsValue = 0; | |||
| 9928 | if (!readBoundedBitShort(*buf, bodyEndBit, rawFlagsValue)) | |||
| 9929 | return fail(); | |||
| 9930 | const int rawFlags = static_cast<int>(rawFlagsValue); | |||
| 9931 | double parsedWidth = 0.0; | |||
| 9932 | double parsedElevation = 0.0; | |||
| 9933 | double parsedThickness = 0.0; | |||
| 9934 | DRW_Coord parsedExtPoint{0.0, 0.0, 1.0}; | |||
| 9935 | if ((rawFlags & 4) | |||
| 9936 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedWidth)) | |||
| 9937 | return fail(); | |||
| 9938 | if ((rawFlags & 8) | |||
| 9939 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedElevation)) | |||
| 9940 | return fail(); | |||
| 9941 | if ((rawFlags & 2) | |||
| 9942 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedThickness)) | |||
| 9943 | return fail(); | |||
| 9944 | if ((rawFlags & 1) | |||
| 9945 | && !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint)) | |||
| 9946 | return fail(); | |||
| 9947 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(rawFlags)DRW_dbg::dbg(rawFlags); | |||
| 9948 | ||||
| 9949 | const std::uint32_t minimumVertexBits = version < DRW::AC1015 ? 128u : 4u; | |||
| 9950 | std::uint32_t parsedVertexCount = 0; | |||
| 9951 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9952 | kMaxLWPolylineVertices, minimumVertexBits, | |||
| 9953 | parsedVertexCount)) { | |||
| 9954 | return fail(); | |||
| 9955 | } | |||
| 9956 | ||||
| 9957 | std::uint64_t vertexBits = 0; | |||
| 9958 | if (parsedVertexCount > 0) { | |||
| 9959 | if (version < DRW::AC1015) { | |||
| 9960 | if (!dwgSafety::multiply(parsedVertexCount, 128, vertexBits)) | |||
| 9961 | return fail(); | |||
| 9962 | } else { | |||
| 9963 | std::uint64_t deltaBits = 0; | |||
| 9964 | if (!dwgSafety::multiply(parsedVertexCount - 1, 4, deltaBits) | |||
| 9965 | || !dwgSafety::add(128, deltaBits, vertexBits)) | |||
| 9966 | return fail(); | |||
| 9967 | } | |||
| 9968 | } | |||
| 9969 | if (!proxyEntityHasBits(*buf, bodyEndBit, vertexBits)) | |||
| 9970 | return fail(); | |||
| 9971 | ||||
| 9972 | std::vector<std::shared_ptr<DRW_Vertex2D>> parsedVertices; | |||
| 9973 | if (!DRW::reserve(parsedVertices, parsedVertexCount)) | |||
| 9974 | return fail(); | |||
| 9975 | ||||
| 9976 | std::uint32_t bulgesnum = 0; | |||
| 9977 | if (rawFlags & 16) { | |||
| 9978 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9979 | kMaxLWPolylineVertices, 2, | |||
| 9980 | bulgesnum)) | |||
| 9981 | return fail(); | |||
| 9982 | } | |||
| 9983 | std::uint32_t vertexIdCount = 0; | |||
| 9984 | if (version > DRW::AC1021) {//2010+ | |||
| 9985 | if (rawFlags & 1024) { | |||
| 9986 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9987 | kMaxLWPolylineVertices, 2, | |||
| 9988 | vertexIdCount)) | |||
| 9989 | return fail(); | |||
| 9990 | } | |||
| 9991 | } | |||
| 9992 | std::uint32_t widthsnum = 0; | |||
| 9993 | if (rawFlags & 32) { | |||
| 9994 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9995 | kMaxLWPolylineVertices, 4, | |||
| 9996 | widthsnum)) | |||
| 9997 | return fail(); | |||
| 9998 | } | |||
| 9999 | std::uint64_t bulgeBits = 0; | |||
| 10000 | std::uint64_t vertexIdBits = 0; | |||
| 10001 | std::uint64_t widthBits = 0; | |||
| 10002 | std::uint64_t optionalBits = 0; | |||
| 10003 | if (!dwgSafety::multiply(bulgesnum, 2, bulgeBits) | |||
| 10004 | || !dwgSafety::multiply(vertexIdCount, 2, vertexIdBits) | |||
| 10005 | || !dwgSafety::multiply(widthsnum, 4, widthBits) | |||
| 10006 | || !dwgSafety::add(bulgeBits, vertexIdBits, optionalBits) | |||
| 10007 | || !dwgSafety::add(optionalBits, widthBits, optionalBits)) { | |||
| 10008 | return fail(); | |||
| 10009 | } | |||
| 10010 | if (!proxyEntityHasBits(*buf, bodyEndBit, optionalBits)) | |||
| 10011 | return fail(); | |||
| 10012 | 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); | |||
| 10013 | 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); | |||
| 10014 | ||||
| 10015 | if (parsedVertexCount > 0) { //verify if is lwpol without vertex (empty) | |||
| 10016 | // add vertexes | |||
| 10017 | auto parsedVertex = std::make_shared<DRW_Vertex2D>(); | |||
| 10018 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->x) | |||
| 10019 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->y)) | |||
| 10020 | return fail(); | |||
| 10021 | parsedVertices.push_back(parsedVertex); | |||
| 10022 | auto pv = parsedVertex; | |||
| 10023 | for (std::uint32_t i = 1; i < parsedVertexCount; ++i){ | |||
| 10024 | parsedVertex = std::make_shared<DRW_Vertex2D>(); | |||
| 10025 | if (version < DRW::AC1015) {//14- | |||
| 10026 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->x) | |||
| 10027 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->y)) | |||
| 10028 | return fail(); | |||
| 10029 | } else { | |||
| 10030 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, pv->x, | |||
| 10031 | parsedVertex->x) | |||
| 10032 | || !readBoundedDefaultDouble(*buf, bodyEndBit, pv->y, | |||
| 10033 | parsedVertex->y)) | |||
| 10034 | return fail(); | |||
| 10035 | } | |||
| 10036 | pv = parsedVertex; | |||
| 10037 | parsedVertices.push_back(parsedVertex); | |||
| 10038 | } | |||
| 10039 | } | |||
| 10040 | // The optional vectors are independent DWG fields, not per-point | |||
| 10041 | // conditionals. Consume them even when num_points is zero so the handle | |||
| 10042 | // stream remains aligned; values without a corresponding vertex are | |||
| 10043 | // intentionally discarded by the existing model. | |||
| 10044 | for (std::uint32_t i = 0; i < bulgesnum; i++){ | |||
| 10045 | double bulge = 0.0; | |||
| 10046 | if (!readBoundedBitDouble(*buf, bodyEndBit, bulge)) | |||
| 10047 | return fail(); | |||
| 10048 | if (i < parsedVertices.size()) | |||
| 10049 | parsedVertices.at(i)->bulge = bulge; | |||
| 10050 | } | |||
| 10051 | //add vertexId | |||
| 10052 | if (version > DRW::AC1021) {//2010+ | |||
| 10053 | for (std::uint32_t i = 0; i < vertexIdCount; i++){ | |||
| 10054 | std::int32_t vertexId = 0; | |||
| 10055 | if (!readBoundedBitLong(*buf, bodyEndBit, vertexId)) | |||
| 10056 | return fail(); | |||
| 10057 | if (i < parsedVertices.size()) | |||
| 10058 | parsedVertices.at(i)->identifier = vertexId; | |||
| 10059 | } | |||
| 10060 | } | |||
| 10061 | //add widths | |||
| 10062 | for (std::uint32_t i = 0; i < widthsnum; i++){ | |||
| 10063 | double staW = 0.0; | |||
| 10064 | double endW = 0.0; | |||
| 10065 | if (!readBoundedBitDouble(*buf, bodyEndBit, staW) | |||
| 10066 | || !readBoundedBitDouble(*buf, bodyEndBit, endW)) | |||
| 10067 | return fail(); | |||
| 10068 | if (i < parsedVertices.size()) { | |||
| 10069 | parsedVertices.at(i)->stawidth = staW; | |||
| 10070 | parsedVertices.at(i)->endwidth = endW; | |||
| 10071 | } | |||
| 10072 | } | |||
| 10073 | if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug){ | |||
| 10074 | DRW_DBG("\nVertex list: ")DRW_dbg::dbg("\nVertex list: "); | |||
| 10075 | for (auto& pv: parsedVertices) { | |||
| 10076 | 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); | |||
| 10077 | 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); | |||
| 10078 | DRW_DBG(" identifier: ")DRW_dbg::dbg(" identifier: "); DRW_DBG(pv->identifier)DRW_dbg::dbg(pv->identifier); | |||
| 10079 | } | |||
| 10080 | } | |||
| 10081 | ||||
| 10082 | const auto finite = [](const DRW_Coord& point) { | |||
| 10083 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10084 | && std::isfinite(point.z); | |||
| 10085 | }; | |||
| 10086 | if (!finite(parsedExtPoint) || !std::isfinite(parsedWidth) | |||
| 10087 | || !std::isfinite(parsedElevation) || !std::isfinite(parsedThickness) | |||
| 10088 | || !std::all_of(parsedVertices.begin(), parsedVertices.end(), | |||
| 10089 | [](const std::shared_ptr<DRW_Vertex2D>& point) { | |||
| 10090 | return point != nullptr | |||
| 10091 | && std::isfinite(point->x) | |||
| 10092 | && std::isfinite(point->y) | |||
| 10093 | && std::isfinite(point->bulge) | |||
| 10094 | && std::isfinite(point->stawidth) | |||
| 10095 | && std::isfinite(point->endwidth); | |||
| 10096 | })) | |||
| 10097 | return fail(); | |||
| 10098 | ||||
| 10099 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10100 | /* Common Entity Handle Data */ | |||
| 10101 | std::uint64_t handleEndBit = 0; | |||
| 10102 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 10103 | handleEndBit)) | |||
| 10104 | return fail(); | |||
| 10105 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 10106 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 10107 | handleEndBit); | |||
| 10108 | if (!ret || !handleProbe.isGood()) | |||
| 10109 | return fail(); | |||
| 10110 | ||||
| 10111 | // Translate DWG LWPLINE flag bits to DXF group 70 bits. | |||
| 10112 | int dxfFlags = 0; | |||
| 10113 | if (rawFlags & 512) | |||
| 10114 | dxfFlags |= 1; | |||
| 10115 | if (rawFlags & 256) | |||
| 10116 | dxfFlags |= 128; | |||
| 10117 | vertexnum = static_cast<std::int32_t>(parsedVertexCount); | |||
| 10118 | flags = dxfFlags; | |||
| 10119 | width = parsedWidth; | |||
| 10120 | elevation = parsedElevation; | |||
| 10121 | thickness = parsedThickness; | |||
| 10122 | extPoint = parsedExtPoint; | |||
| 10123 | vertlist = std::move(parsedVertices); | |||
| 10124 | *sourceBuf = handleProbe; | |||
| 10125 | DRW_DBG("end flags value: ")DRW_dbg::dbg("end flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags); | |||
| 10126 | /* CRC X --- */ | |||
| 10127 | return true; | |||
| 10128 | } | |||
| 10129 | ||||
| 10130 | ||||
| 10131 | // ---------------------------------------------------------------------------- | |||
| 10132 | // DRW_MLine — multiline entity (ODA §19.4.78, fixed type 0x2F = 47). | |||
| 10133 | // ---------------------------------------------------------------------------- | |||
| 10134 | ||||
| 10135 | bool DRW_MLine::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 10136 | switch (code) { | |||
| 10137 | case 2: | |||
| 10138 | styleName = reader->getUtf8String(); | |||
| 10139 | break; | |||
| 10140 | case 340: | |||
| 10141 | styleHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 10142 | break; | |||
| 10143 | case 40: | |||
| 10144 | scale = reader->getDouble(); | |||
| 10145 | break; | |||
| 10146 | case 70: | |||
| 10147 | { | |||
| 10148 | int value = 0; | |||
| 10149 | if (!readDxfIntInRange(reader, 0, 2, value)) | |||
| 10150 | return false; | |||
| 10151 | justification = static_cast<std::uint8_t>(value); | |||
| 10152 | } | |||
| 10153 | break; | |||
| 10154 | case 71: | |||
| 10155 | openClosed = reader->getInt32(); | |||
| 10156 | break; | |||
| 10157 | case 72: | |||
| 10158 | if (m_dxfVertexCountSeen) | |||
| 10159 | return false; | |||
| 10160 | { | |||
| 10161 | const std::int32_t count = reader->getInt32(); | |||
| 10162 | if (!isValidCount(count, kMaxDxfVertices)) | |||
| 10163 | return false; | |||
| 10164 | numVerts = static_cast<std::uint16_t>(count); | |||
| 10165 | m_dxfVertexCountSeen = true; | |||
| 10166 | } | |||
| 10167 | break; | |||
| 10168 | case 73: | |||
| 10169 | if (m_dxfLineCountSeen) | |||
| 10170 | return false; | |||
| 10171 | { | |||
| 10172 | const std::int32_t count = reader->getInt32(); | |||
| 10173 | if (!isValidCount(count, kMaxDxfLines)) | |||
| 10174 | return false; | |||
| 10175 | numLines = static_cast<std::uint8_t>(count); | |||
| 10176 | m_dxfLineCountSeen = true; | |||
| 10177 | } | |||
| 10178 | break; | |||
| 10179 | case 10: | |||
| 10180 | basePoint.x = reader->getDouble(); | |||
| 10181 | break; | |||
| 10182 | case 20: | |||
| 10183 | basePoint.y = reader->getDouble(); | |||
| 10184 | break; | |||
| 10185 | case 30: | |||
| 10186 | basePoint.z = reader->getDouble(); | |||
| 10187 | break; | |||
| 10188 | case 210: | |||
| 10189 | extPoint.x = reader->getDouble(); | |||
| 10190 | break; | |||
| 10191 | case 220: | |||
| 10192 | extPoint.y = reader->getDouble(); | |||
| 10193 | break; | |||
| 10194 | case 230: | |||
| 10195 | extPoint.z = reader->getDouble(); | |||
| 10196 | break; | |||
| 10197 | // Per-vertex block: code 11 starts a new vertex; 12/13 follow. | |||
| 10198 | case 11: | |||
| 10199 | if (m_currentSegExpected >= 0 || m_currentAreaExpected >= 0) | |||
| 10200 | return false; | |||
| 10201 | ++m_currentVertexIdx; | |||
| 10202 | m_currentElementIdx = 0; | |||
| 10203 | if (m_currentVertexIdx >= kMaxDxfVertices | |||
| 10204 | || (m_dxfVertexCountSeen | |||
| 10205 | && m_currentVertexIdx >= static_cast<int>(numVerts))) | |||
| 10206 | return false; | |||
| 10207 | vertlist.emplace_back(); | |||
| 10208 | vertlist[m_currentVertexIdx].position.x = reader->getDouble(); | |||
| 10209 | break; | |||
| 10210 | case 21: | |||
| 10211 | if (m_currentVertexIdx >= 0) | |||
| 10212 | vertlist[m_currentVertexIdx].position.y = reader->getDouble(); | |||
| 10213 | break; | |||
| 10214 | case 31: | |||
| 10215 | if (m_currentVertexIdx >= 0) | |||
| 10216 | vertlist[m_currentVertexIdx].position.z = reader->getDouble(); | |||
| 10217 | break; | |||
| 10218 | case 12: | |||
| 10219 | if (m_currentVertexIdx >= 0) | |||
| 10220 | vertlist[m_currentVertexIdx].vertexDir.x = reader->getDouble(); | |||
| 10221 | break; | |||
| 10222 | case 22: | |||
| 10223 | if (m_currentVertexIdx >= 0) | |||
| 10224 | vertlist[m_currentVertexIdx].vertexDir.y = reader->getDouble(); | |||
| 10225 | break; | |||
| 10226 | case 32: | |||
| 10227 | if (m_currentVertexIdx >= 0) | |||
| 10228 | vertlist[m_currentVertexIdx].vertexDir.z = reader->getDouble(); | |||
| 10229 | break; | |||
| 10230 | case 13: | |||
| 10231 | if (m_currentVertexIdx >= 0) | |||
| 10232 | vertlist[m_currentVertexIdx].miterDir.x = reader->getDouble(); | |||
| 10233 | break; | |||
| 10234 | case 23: | |||
| 10235 | if (m_currentVertexIdx >= 0) | |||
| 10236 | vertlist[m_currentVertexIdx].miterDir.y = reader->getDouble(); | |||
| 10237 | break; | |||
| 10238 | case 33: | |||
| 10239 | if (m_currentVertexIdx >= 0) | |||
| 10240 | vertlist[m_currentVertexIdx].miterDir.z = reader->getDouble(); | |||
| 10241 | break; | |||
| 10242 | // 74 = segment-param count for current element. Sets up the inner | |||
| 10243 | // vector and resets the running param count. 41 reads each param. | |||
| 10244 | // 75 = fill-param count; 42 reads each. After fills are consumed, | |||
| 10245 | // advance to the next element. AutoCAD emits 74/41*/75/42* per element. | |||
| 10246 | case 74: | |||
| 10247 | if (m_currentVertexIdx < 0 | |||
| 10248 | || m_currentSegExpected >= 0 || m_currentAreaExpected >= 0) | |||
| 10249 | return false; | |||
| 10250 | { | |||
| 10251 | auto& v = vertlist[m_currentVertexIdx]; | |||
| 10252 | if (m_currentElementIdx != static_cast<int>(v.segParms.size()) | |||
| 10253 | || m_currentElementIdx >= kMaxDxfLines | |||
| 10254 | || (m_dxfLineCountSeen | |||
| 10255 | && m_currentElementIdx >= static_cast<int>(numLines))) | |||
| 10256 | return false; | |||
| 10257 | const std::int32_t count = reader->getInt32(); | |||
| 10258 | if (!isValidCount(count, kMaxDxfParameters)) | |||
| 10259 | return false; | |||
| 10260 | v.segParms.emplace_back(); | |||
| 10261 | v.areaFillParms.emplace_back(); | |||
| 10262 | m_currentSegExpected = count; | |||
| 10263 | m_currentSegFillCount = 0; | |||
| 10264 | } | |||
| 10265 | break; | |||
| 10266 | case 41: | |||
| 10267 | if (m_currentVertexIdx < 0 || m_currentSegExpected < 0 | |||
| 10268 | || m_currentElementIdx >= static_cast<int>(vertlist[m_currentVertexIdx].segParms.size())) | |||
| 10269 | return false; | |||
| 10270 | if (static_cast<std::int32_t>( | |||
| 10271 | vertlist[m_currentVertexIdx].segParms[m_currentElementIdx].size()) | |||
| 10272 | >= m_currentSegExpected) | |||
| 10273 | return false; | |||
| 10274 | vertlist[m_currentVertexIdx].segParms[m_currentElementIdx] | |||
| 10275 | .push_back(reader->getDouble()); | |||
| 10276 | break; | |||
| 10277 | case 75: | |||
| 10278 | if (m_currentVertexIdx < 0 || m_currentSegExpected < 0 | |||
| 10279 | || m_currentAreaExpected >= 0 | |||
| 10280 | || m_currentElementIdx >= static_cast<int>(vertlist[m_currentVertexIdx].segParms.size())) | |||
| 10281 | return false; | |||
| 10282 | if (static_cast<std::int32_t>( | |||
| 10283 | vertlist[m_currentVertexIdx].segParms[m_currentElementIdx].size()) | |||
| 10284 | != m_currentSegExpected) | |||
| 10285 | return false; | |||
| 10286 | m_currentSegExpected = -1; | |||
| 10287 | m_currentSegFillCount = reader->getInt32(); | |||
| 10288 | if (!isValidCount(m_currentSegFillCount, kMaxDxfParameters)) | |||
| 10289 | return false; | |||
| 10290 | m_currentAreaExpected = m_currentSegFillCount; | |||
| 10291 | if (m_currentAreaExpected == 0) { | |||
| 10292 | m_currentAreaExpected = -1; | |||
| 10293 | ++m_currentElementIdx; | |||
| 10294 | } | |||
| 10295 | break; | |||
| 10296 | case 42: | |||
| 10297 | if (m_currentVertexIdx < 0 || m_currentAreaExpected < 0 | |||
| 10298 | || m_currentElementIdx >= static_cast<int>(vertlist[m_currentVertexIdx].areaFillParms.size())) | |||
| 10299 | return false; | |||
| 10300 | if (static_cast<std::int32_t>( | |||
| 10301 | vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx].size()) | |||
| 10302 | >= m_currentAreaExpected) | |||
| 10303 | return false; | |||
| 10304 | vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx] | |||
| 10305 | .push_back(reader->getDouble()); | |||
| 10306 | if (static_cast<std::int32_t>( | |||
| 10307 | vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx].size()) | |||
| 10308 | == m_currentAreaExpected) { | |||
| 10309 | m_currentAreaExpected = -1; | |||
| 10310 | ++m_currentElementIdx; | |||
| 10311 | } | |||
| 10312 | break; | |||
| 10313 | default: | |||
| 10314 | return DRW_Entity::parseCode(code, reader); | |||
| 10315 | } | |||
| 10316 | return true; | |||
| 10317 | } | |||
| 10318 | ||||
| 10319 | bool DRW_MLine::validateDxf() const { | |||
| 10320 | if (m_currentSegExpected >= 0 || m_currentAreaExpected >= 0) | |||
| 10321 | return false; | |||
| 10322 | if (m_dxfVertexCountSeen && vertlist.size() != numVerts) | |||
| 10323 | return false; | |||
| 10324 | if (!m_dxfLineCountSeen) | |||
| 10325 | return true; | |||
| 10326 | for (const DRW_MLineVertex& vertex : vertlist) { | |||
| 10327 | if (vertex.segParms.size() != numLines | |||
| 10328 | || vertex.areaFillParms.size() != numLines) | |||
| 10329 | return false; | |||
| 10330 | } | |||
| 10331 | return validatePayloadFields(); | |||
| 10332 | } | |||
| 10333 | ||||
| 10334 | bool DRW_MLine::validatePayloadFields() const { | |||
| 10335 | const auto finite = [](const DRW_Coord& point) { | |||
| 10336 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10337 | && std::isfinite(point.z); | |||
| 10338 | }; | |||
| 10339 | if (!finite(basePoint) || !finite(extPoint) || !std::isfinite(scale) | |||
| 10340 | || openClosed < 0 || openClosed > 0xffff | |||
| 10341 | || numVerts > static_cast<std::uint16_t>(kMaxDxfVertices) | |||
| 10342 | || vertlist.size() > static_cast<std::size_t>(kMaxDxfVertices) | |||
| 10343 | || vertlist.size() != static_cast<std::size_t>(numVerts)) | |||
| 10344 | return false; | |||
| 10345 | ||||
| 10346 | for (const DRW_MLineVertex& vertex : vertlist) { | |||
| 10347 | if (!finite(vertex.position) || !finite(vertex.vertexDir) | |||
| 10348 | || !finite(vertex.miterDir) | |||
| 10349 | || vertex.segParms.size() != numLines | |||
| 10350 | || vertex.areaFillParms.size() != numLines) | |||
| 10351 | return false; | |||
| 10352 | const auto validParameters = [](const auto& parameterLists) { | |||
| 10353 | return std::all_of( | |||
| 10354 | parameterLists.cbegin(), parameterLists.cend(), | |||
| 10355 | [](const std::vector<double>& values) { | |||
| 10356 | return values.size() <= static_cast<std::size_t>( | |||
| 10357 | DRW_MLine::kMaxDxfParameters) | |||
| 10358 | && std::all_of(values.cbegin(), values.cend(), | |||
| 10359 | [](double value) { | |||
| 10360 | return std::isfinite(value); | |||
| 10361 | }); | |||
| 10362 | }); | |||
| 10363 | }; | |||
| 10364 | if (!validParameters(vertex.segParms) | |||
| 10365 | || !validParameters(vertex.areaFillParms)) | |||
| 10366 | return false; | |||
| 10367 | } | |||
| 10368 | return true; | |||
| 10369 | } | |||
| 10370 | ||||
| 10371 | void DRW_MLine::resetDwgState() { | |||
| 10372 | DRW_Entity::reset(); | |||
| 10373 | scale = 1.0; | |||
| 10374 | justification = 0; | |||
| 10375 | basePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10376 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 10377 | openClosed = 1; | |||
| 10378 | numLines = 0; | |||
| 10379 | numVerts = 0; | |||
| 10380 | styleName.clear(); | |||
| 10381 | styleHandle = 0; | |||
| 10382 | vertlist.clear(); | |||
| 10383 | m_currentVertexIdx = -1; | |||
| 10384 | m_currentElementIdx = 0; | |||
| 10385 | m_currentSegFillCount = 0; | |||
| 10386 | m_currentSegExpected = -1; | |||
| 10387 | m_currentAreaExpected = -1; | |||
| 10388 | m_dxfVertexCountSeen = false; | |||
| 10389 | m_dxfLineCountSeen = false; | |||
| 10390 | } | |||
| 10391 | ||||
| 10392 | bool DRW_MLine::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 10393 | resetDwgState(); | |||
| 10394 | dwgBuffer *sourceBuf = buf; | |||
| 10395 | auto fail = [this, sourceBuf]() { | |||
| 10396 | if (sourceBuf != nullptr) | |||
| 10397 | sourceBuf->invalidate(); | |||
| 10398 | resetDwgState(); | |||
| 10399 | return false; | |||
| 10400 | }; | |||
| 10401 | if (sourceBuf == nullptr) | |||
| 10402 | return fail(); | |||
| 10403 | ||||
| 10404 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 10405 | buf = &bodyProbe; | |||
| 10406 | ||||
| 10407 | if (!DRW_Entity::parseDwgCommon(version, buf, bs)) return fail(); | |||
| 10408 | DRW_DBG("\n***************************** parsing MLINE *********************\n")DRW_dbg::dbg("\n***************************** parsing MLINE *********************\n" ); | |||
| 10409 | // Per ODA §19.4.78 / libreDWG dwg_decode_MLINE: | |||
| 10410 | // BD scale, RC justification, 3BD basePoint, BE extrusion, | |||
| 10411 | // BS open/closed flag, RC num_lines, BS num_verts, | |||
| 10412 | // then per-vertex: 3BD pos, 3BD vdir, 3BD mdir, | |||
| 10413 | // per-line: BS num_segparms × BD parm, BS num_areafillparms × BD parm. | |||
| 10414 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 10415 | double parsedScale = 0.0; | |||
| 10416 | std::uint8_t parsedJustification = 0; | |||
| 10417 | DRW_Coord parsedBasePoint; | |||
| 10418 | DRW_Coord parsedExtPoint; | |||
| 10419 | std::uint16_t parsedOpenClosed = 0; | |||
| 10420 | std::uint8_t parsedNumLines = 0; | |||
| 10421 | std::uint16_t parsedNumVerts = 0; | |||
| 10422 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedScale) | |||
| 10423 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedJustification) | |||
| 10424 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 10425 | || !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint) | |||
| 10426 | || !readBoundedBitShort(*buf, bodyEndBit, parsedOpenClosed) | |||
| 10427 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedNumLines) | |||
| 10428 | || !readBoundedBitShort(*buf, bodyEndBit, parsedNumVerts)) | |||
| 10429 | return fail(); | |||
| 10430 | if (!std::isfinite(parsedScale) | |||
| 10431 | || !std::isfinite(parsedBasePoint.x) | |||
| 10432 | || !std::isfinite(parsedBasePoint.y) | |||
| 10433 | || !std::isfinite(parsedBasePoint.z) | |||
| 10434 | || !std::isfinite(parsedExtPoint.x) | |||
| 10435 | || !std::isfinite(parsedExtPoint.y) | |||
| 10436 | || !std::isfinite(parsedExtPoint.z)) | |||
| 10437 | return fail(); | |||
| 10438 | DRW_DBG(" mline scale: ")DRW_dbg::dbg(" mline scale: "); DRW_DBG(parsedScale)DRW_dbg::dbg(parsedScale); | |||
| 10439 | DRW_DBG(" just: ")DRW_dbg::dbg(" just: "); DRW_DBG(static_cast<int>(parsedJustification))DRW_dbg::dbg(static_cast<int>(parsedJustification)); | |||
| 10440 | DRW_DBG(" openClosed: ")DRW_dbg::dbg(" openClosed: "); DRW_DBG(parsedOpenClosed)DRW_dbg::dbg(parsedOpenClosed); | |||
| 10441 | DRW_DBG(" lines: ")DRW_dbg::dbg(" lines: "); DRW_DBG(static_cast<int>(parsedNumLines))DRW_dbg::dbg(static_cast<int>(parsedNumLines)); | |||
| 10442 | DRW_DBG(" verts: ")DRW_dbg::dbg(" verts: "); DRW_DBG(parsedNumVerts)DRW_dbg::dbg(parsedNumVerts); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10443 | if (!buf->isGood() | |||
| 10444 | || !isValidCount(static_cast<std::int32_t>(parsedNumVerts), kMaxDxfVertices) | |||
| 10445 | || !isValidCount(static_cast<std::int32_t>(parsedNumLines), kMaxDxfLines)) | |||
| 10446 | return fail(); | |||
| 10447 | ||||
| 10448 | // Each vertex always contains three minimum-width 3BD values and one | |||
| 10449 | // minimum-width BS for each segment/fill parameter count. Check this | |||
| 10450 | // before allocating the per-vertex/per-line vector grid. | |||
| 10451 | const std::uint64_t minimumBitsPerVertex = | |||
| 10452 | 18u + static_cast<std::uint64_t>(parsedNumLines) * 4u; | |||
| 10453 | std::uint64_t minimumVertexBits = 0; | |||
| 10454 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(parsedNumVerts), | |||
| 10455 | minimumBitsPerVertex, minimumVertexBits) | |||
| 10456 | || !proxyEntityHasBits(*buf, bodyEndBit, minimumVertexBits)) | |||
| 10457 | return fail(); | |||
| 10458 | ||||
| 10459 | // The per-vertex parameter lists are also capped by the DWG spec. Keep a | |||
| 10460 | // combined budget so a valid per-list maximum cannot multiply into an | |||
| 10461 | // unbounded number of vector allocations on hostile input. | |||
| 10462 | constexpr std::uint64_t kMaxDwgParameters = 1000000; | |||
| 10463 | std::uint64_t totalParameters = 0; | |||
| 10464 | std::vector<DRW_MLineVertex> parsedVertices; | |||
| 10465 | if (!DRW::reserve(parsedVertices, parsedNumVerts)) | |||
| 10466 | return fail(); | |||
| 10467 | for (int vi = 0; vi < parsedNumVerts; ++vi) { | |||
| 10468 | DRW_MLineVertex vtx; | |||
| 10469 | if (!readBoundedBitCoord(*buf, bodyEndBit, vtx.position) | |||
| 10470 | || !readBoundedBitCoord(*buf, bodyEndBit, vtx.vertexDir) | |||
| 10471 | || !readBoundedBitCoord(*buf, bodyEndBit, vtx.miterDir)) | |||
| 10472 | return fail(); | |||
| 10473 | if (!DRW::reserve(vtx.segParms, parsedNumLines) | |||
| 10474 | || !DRW::reserve(vtx.areaFillParms, parsedNumLines)) | |||
| 10475 | return fail(); | |||
| 10476 | if (!DRW::resize(vtx.segParms, parsedNumLines) | |||
| 10477 | || !DRW::resize(vtx.areaFillParms, parsedNumLines)) | |||
| 10478 | return fail(); | |||
| 10479 | for (int li = 0; li < parsedNumLines; ++li) { | |||
| 10480 | std::uint16_t nSeg = 0; | |||
| 10481 | if (!readBoundedBitShort(*buf, bodyEndBit, nSeg) | |||
| 10482 | || !proxyEntityHasBits(*buf, bodyEndBit, | |||
| 10483 | static_cast<std::uint64_t>(nSeg) * 2u)) | |||
| 10484 | return fail(); | |||
| 10485 | if (!buf->isGood() | |||
| 10486 | || !isValidCount(static_cast<std::int32_t>(nSeg), | |||
| 10487 | kMaxDxfParameters) | |||
| 10488 | || totalParameters > kMaxDwgParameters - nSeg) | |||
| 10489 | return fail(); | |||
| 10490 | totalParameters += nSeg; | |||
| 10491 | if (!DRW::reserve(vtx.segParms[li], nSeg)) | |||
| 10492 | return fail(); | |||
| 10493 | for (int s = 0; s < nSeg; ++s) { | |||
| 10494 | double value = 0.0; | |||
| 10495 | if (!readBoundedBitDouble(*buf, bodyEndBit, value) | |||
| 10496 | || !std::isfinite(value)) | |||
| 10497 | return fail(); | |||
| 10498 | vtx.segParms[li].push_back(value); | |||
| 10499 | } | |||
| 10500 | std::uint16_t nFill = 0; | |||
| 10501 | if (!readBoundedBitShort(*buf, bodyEndBit, nFill) | |||
| 10502 | || !proxyEntityHasBits(*buf, bodyEndBit, | |||
| 10503 | static_cast<std::uint64_t>(nFill) * 2u)) | |||
| 10504 | return fail(); | |||
| 10505 | if (!buf->isGood() | |||
| 10506 | || !isValidCount(static_cast<std::int32_t>(nFill), | |||
| 10507 | kMaxDxfParameters) | |||
| 10508 | || totalParameters > kMaxDwgParameters - nFill) | |||
| 10509 | return fail(); | |||
| 10510 | totalParameters += nFill; | |||
| 10511 | if (!DRW::reserve(vtx.areaFillParms[li], nFill)) | |||
| 10512 | return fail(); | |||
| 10513 | for (int f = 0; f < nFill; ++f) { | |||
| 10514 | double value = 0.0; | |||
| 10515 | if (!readBoundedBitDouble(*buf, bodyEndBit, value) | |||
| 10516 | || !std::isfinite(value)) | |||
| 10517 | return fail(); | |||
| 10518 | vtx.areaFillParms[li].push_back(value); | |||
| 10519 | } | |||
| 10520 | } | |||
| 10521 | const auto finite = [](const DRW_Coord& point) { | |||
| 10522 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10523 | && std::isfinite(point.z); | |||
| 10524 | }; | |||
| 10525 | if (!finite(vtx.position) || !finite(vtx.vertexDir) | |||
| 10526 | || !finite(vtx.miterDir)) | |||
| 10527 | return fail(); | |||
| 10528 | parsedVertices.push_back(std::move(vtx)); | |||
| 10529 | } | |||
| 10530 | if (!buf->isGood()) | |||
| 10531 | return fail(); | |||
| 10532 | ||||
| 10533 | std::uint64_t handleEndBit = 0; | |||
| 10534 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 10535 | handleEndBit)) | |||
| 10536 | return fail(); | |||
| 10537 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 10538 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 10539 | handleEndBit)) | |||
| 10540 | return fail(); | |||
| 10541 | // MLINE has one extra handle in the handle stream after the standard | |||
| 10542 | // entity handles: the MLINESTYLE reference. Read if available — some | |||
| 10543 | // older files (R14) store the style name inline instead. | |||
| 10544 | std::uint32_t parsedStyleHandle = 0; | |||
| 10545 | if (version > DRW::AC1014 | |||
| 10546 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 10547 | dwgHandle styleH; | |||
| 10548 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 10549 | styleH)) | |||
| 10550 | return fail(); | |||
| 10551 | if (!handleProbe.isGood()) | |||
| 10552 | return fail(); | |||
| 10553 | parsedStyleHandle = styleH.ref; | |||
| 10554 | DRW_DBG(" MLINE style handle: ")DRW_dbg::dbg(" MLINE style handle: "); | |||
| 10555 | DRW_DBGHL(styleH.code, styleH.size, styleH.ref)DRW_dbg::dbgHL(styleH.code, styleH.size, styleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10556 | } | |||
| 10557 | if (!handleProbe.isGood()) | |||
| 10558 | return fail(); | |||
| 10559 | *sourceBuf = handleProbe; | |||
| 10560 | scale = parsedScale; | |||
| 10561 | justification = parsedJustification; | |||
| 10562 | basePoint = parsedBasePoint; | |||
| 10563 | extPoint = parsedExtPoint; | |||
| 10564 | openClosed = parsedOpenClosed; | |||
| 10565 | numLines = parsedNumLines; | |||
| 10566 | numVerts = parsedNumVerts; | |||
| 10567 | styleHandle = parsedStyleHandle; | |||
| 10568 | vertlist = std::move(parsedVertices); | |||
| 10569 | return true; | |||
| 10570 | } | |||
| 10571 | ||||
| 10572 | ||||
| 10573 | // ---------------------------------------------------------------------------- | |||
| 10574 | // DRW_Underlay — UNDERLAY entity (PDFUNDERLAY/DGNUNDERLAY/DWFUNDERLAY). | |||
| 10575 | // libreDWG UNDERLAYREFERENCE.spec field order: | |||
| 10576 | // extrusion (BE) -> position (3BD) -> angle (BD radians) -> scale (BD x 3) | |||
| 10577 | // -> flags (RC) -> contrast (RC) -> fade (RC) -> num_clip (BL) | |||
| 10578 | // -> clip_verts (2RD × num_clip). | |||
| 10579 | // Handle stream after standard entity handles: definition_id (H). | |||
| 10580 | // ---------------------------------------------------------------------------- | |||
| 10581 | ||||
| 10582 | bool DRW_Underlay::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 10583 | switch (code) { | |||
| 10584 | case 340: | |||
| 10585 | definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 10586 | break; | |||
| 10587 | case 10: position.x = reader->getDouble(); break; | |||
| 10588 | case 20: position.y = reader->getDouble(); break; | |||
| 10589 | case 30: position.z = reader->getDouble(); break; | |||
| 10590 | case 41: scale.x = reader->getDouble(); break; | |||
| 10591 | case 42: scale.y = reader->getDouble(); break; | |||
| 10592 | case 43: scale.z = reader->getDouble(); break; | |||
| 10593 | case 50: rotation = reader->getDouble(); break; // degrees in DXF | |||
| 10594 | case 210: extPoint.x = reader->getDouble(); break; | |||
| 10595 | case 220: extPoint.y = reader->getDouble(); break; | |||
| 10596 | case 230: extPoint.z = reader->getDouble(); break; | |||
| 10597 | case 280: { | |||
| 10598 | int value = 0; | |||
| 10599 | if (!readDxfIntInRange(reader, 0, 0xFF, value)) | |||
| 10600 | return false; | |||
| 10601 | flags = static_cast<std::uint8_t>(value); | |||
| 10602 | break; | |||
| 10603 | } | |||
| 10604 | case 281: { | |||
| 10605 | int value = 0; | |||
| 10606 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 10607 | return false; | |||
| 10608 | contrast = static_cast<std::uint8_t>(value); | |||
| 10609 | break; | |||
| 10610 | } | |||
| 10611 | case 282: { | |||
| 10612 | int value = 0; | |||
| 10613 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 10614 | return false; | |||
| 10615 | fade = static_cast<std::uint8_t>(value); | |||
| 10616 | break; | |||
| 10617 | } | |||
| 10618 | case 11: { | |||
| 10619 | if (clipBoundary.size() >= kMaxClipVertices) | |||
| 10620 | return false; | |||
| 10621 | ++m_currentClipVertexIdx; | |||
| 10622 | if (m_currentClipVertexIdx >= static_cast<int>(clipBoundary.size())) { | |||
| 10623 | if (!DRW::resize(clipBoundary, m_currentClipVertexIdx + 1)) | |||
| 10624 | return false; | |||
| 10625 | } | |||
| 10626 | clipBoundary[m_currentClipVertexIdx].x = reader->getDouble(); | |||
| 10627 | break; | |||
| 10628 | } | |||
| 10629 | case 21: | |||
| 10630 | if (m_currentClipVertexIdx >= 0 | |||
| 10631 | && m_currentClipVertexIdx < static_cast<int>(clipBoundary.size())) { | |||
| 10632 | clipBoundary[m_currentClipVertexIdx].y = reader->getDouble(); | |||
| 10633 | } | |||
| 10634 | break; | |||
| 10635 | case 170: { | |||
| 10636 | const int count = reader->getInt32(); | |||
| 10637 | if (!isValidCount(count, static_cast<std::int32_t>(kMaxClipVertices))) | |||
| 10638 | return false; | |||
| 10639 | m_inverseClipVertexCount = static_cast<std::uint32_t>(count); | |||
| 10640 | m_inverseClipCountSeen = true; | |||
| 10641 | if (!DRW::reserve(inverseClipBoundary, count)) | |||
| 10642 | return false; | |||
| 10643 | break; | |||
| 10644 | } | |||
| 10645 | case 12: { | |||
| 10646 | if (inverseClipBoundary.size() >= kMaxClipVertices | |||
| 10647 | || (m_inverseClipCountSeen | |||
| 10648 | && inverseClipBoundary.size() >= m_inverseClipVertexCount)) | |||
| 10649 | return false; | |||
| 10650 | ++m_currentInverseClipVertexIdx; | |||
| 10651 | if (m_currentInverseClipVertexIdx | |||
| 10652 | >= static_cast<int>(inverseClipBoundary.size())) { | |||
| 10653 | if (!DRW::resize(inverseClipBoundary, | |||
| 10654 | m_currentInverseClipVertexIdx + 1)) | |||
| 10655 | return false; | |||
| 10656 | } | |||
| 10657 | inverseClipBoundary[m_currentInverseClipVertexIdx].x = reader->getDouble(); | |||
| 10658 | break; | |||
| 10659 | } | |||
| 10660 | case 22: | |||
| 10661 | if (m_currentInverseClipVertexIdx >= 0 | |||
| 10662 | && m_currentInverseClipVertexIdx | |||
| 10663 | < static_cast<int>(inverseClipBoundary.size())) { | |||
| 10664 | inverseClipBoundary[m_currentInverseClipVertexIdx].y = reader->getDouble(); | |||
| 10665 | } | |||
| 10666 | break; | |||
| 10667 | default: | |||
| 10668 | return DRW_Entity::parseCode(code, reader); | |||
| 10669 | } | |||
| 10670 | return true; | |||
| 10671 | } | |||
| 10672 | ||||
| 10673 | void DRW_Underlay::resetDwgState() { | |||
| 10674 | DRW_Entity::reset(); | |||
| 10675 | // Entity carriers can be reused by callers. Clip payloads and their | |||
| 10676 | // parser counters belong to this record, not to the carrier lifetime. | |||
| 10677 | position = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10678 | scale = DRW_Coord{1.0, 1.0, 1.0}; | |||
| 10679 | rotation = 0.0; | |||
| 10680 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 10681 | flags = 2; | |||
| 10682 | contrast = 100; | |||
| 10683 | fade = 0; | |||
| 10684 | clipBoundary.clear(); | |||
| 10685 | inverseClipBoundary.clear(); | |||
| 10686 | m_currentClipVertexIdx = -1; | |||
| 10687 | m_currentInverseClipVertexIdx = -1; | |||
| 10688 | m_inverseClipVertexCount = 0; | |||
| 10689 | m_inverseClipCountSeen = false; | |||
| 10690 | definitionHandle = 0; | |||
| 10691 | } | |||
| 10692 | ||||
| 10693 | bool DRW_Underlay::validatePayloadFields() const { | |||
| 10694 | const auto finite = [](const DRW_Coord& point) { | |||
| 10695 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10696 | && std::isfinite(point.z); | |||
| 10697 | }; | |||
| 10698 | const auto finiteClipPoint = [](const DRW_Coord& point) { | |||
| 10699 | return std::isfinite(point.x) && std::isfinite(point.y); | |||
| 10700 | }; | |||
| 10701 | return finite(position) && finite(scale) && finite(extPoint) | |||
| 10702 | && std::isfinite(rotation) | |||
| 10703 | && std::all_of(clipBoundary.cbegin(), clipBoundary.cend(), | |||
| 10704 | finiteClipPoint) | |||
| 10705 | && std::all_of(inverseClipBoundary.cbegin(), | |||
| 10706 | inverseClipBoundary.cend(), finiteClipPoint); | |||
| 10707 | } | |||
| 10708 | ||||
| 10709 | bool DRW_Underlay::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 10710 | resetDwgState(); | |||
| 10711 | dwgBuffer *sourceBuf = buf; | |||
| 10712 | auto fail = [this, sourceBuf]() { | |||
| 10713 | if (sourceBuf != nullptr) | |||
| 10714 | sourceBuf->invalidate(); | |||
| 10715 | resetDwgState(); | |||
| 10716 | return false; | |||
| 10717 | }; | |||
| 10718 | if (sourceBuf == nullptr) | |||
| 10719 | return fail(); | |||
| 10720 | ||||
| 10721 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 10722 | buf = &bodyProbe; | |||
| 10723 | ||||
| 10724 | if (!DRW_Entity::parseDwgCommon(version, buf, bs)) return fail(); | |||
| 10725 | DRW_DBG("\n***************************** parsing UNDERLAY ***************\n")DRW_dbg::dbg("\n***************************** parsing UNDERLAY ***************\n" ); | |||
| 10726 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 10727 | DRW_Coord parsedExtPoint; | |||
| 10728 | DRW_Coord parsedPosition; | |||
| 10729 | DRW_Coord parsedScale; | |||
| 10730 | double parsedRotation = 0.0; | |||
| 10731 | std::uint8_t parsedFlags = 0; | |||
| 10732 | std::uint8_t parsedContrast = 0; | |||
| 10733 | std::uint8_t parsedFade = 0; | |||
| 10734 | if (!readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint) | |||
| 10735 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedPosition) | |||
| 10736 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRotation) | |||
| 10737 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale.x) | |||
| 10738 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale.y) | |||
| 10739 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale.z) | |||
| 10740 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedFlags) | |||
| 10741 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedContrast) | |||
| 10742 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedFade)) | |||
| 10743 | return fail(); | |||
| 10744 | const auto finite = [](const DRW_Coord& point) { | |||
| 10745 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10746 | && std::isfinite(point.z); | |||
| 10747 | }; | |||
| 10748 | if (!finite(parsedExtPoint) || !finite(parsedPosition) | |||
| 10749 | || !finite(parsedScale) || !std::isfinite(parsedRotation)) | |||
| 10750 | return fail(); | |||
| 10751 | std::uint32_t nClip = 0; | |||
| 10752 | DRW_DBG(" UNDERLAY pos: ")DRW_dbg::dbg(" UNDERLAY pos: "); DRW_DBG(parsedPosition.x)DRW_dbg::dbg(parsedPosition.x); DRW_DBG(",")DRW_dbg::dbg(","); | |||
| 10753 | DRW_DBG(parsedPosition.y)DRW_dbg::dbg(parsedPosition.y); DRW_DBG(" rot: ")DRW_dbg::dbg(" rot: "); DRW_DBG(parsedRotation)DRW_dbg::dbg(parsedRotation); | |||
| 10754 | DRW_DBG(" flags: ")DRW_dbg::dbg(" flags: "); DRW_DBGH(parsedFlags)DRW_dbg::dbgH(parsedFlags); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10755 | if (!readTableBodyCount(version, buf, objSize, kMaxClipVertices, 128, | |||
| 10756 | nClip) | |||
| 10757 | || !proxyEntityHasBits(*buf, bodyEndBit, | |||
| 10758 | static_cast<std::uint64_t>(nClip) * 128u)) | |||
| 10759 | return fail(); | |||
| 10760 | std::vector<DRW_Coord> parsedClipBoundary; | |||
| 10761 | if (!DRW::reserve(parsedClipBoundary, static_cast<std::size_t>(nClip))) | |||
| 10762 | return fail(); | |||
| 10763 | for (std::uint32_t i = 0; i < nClip; ++i) { | |||
| 10764 | DRW_Coord p; | |||
| 10765 | if (!readBoundedRawDouble(*buf, bodyEndBit, p.x) | |||
| 10766 | || !readBoundedRawDouble(*buf, bodyEndBit, p.y) | |||
| 10767 | || !std::isfinite(p.x) || !std::isfinite(p.y)) | |||
| 10768 | return fail(); | |||
| 10769 | p.z = 0.0; | |||
| 10770 | parsedClipBoundary.push_back(p); | |||
| 10771 | } | |||
| 10772 | std::vector<DRW_Coord> parsedInverseClipBoundary; | |||
| 10773 | if (version > DRW::AC1021 && (parsedFlags & 0x10) != 0) { | |||
| 10774 | std::uint16_t nInverse = 0; | |||
| 10775 | if (!readBoundedBitShort(*buf, bodyEndBit, nInverse) | |||
| 10776 | || nInverse > kMaxClipVertices | |||
| 10777 | || !proxyEntityHasBits( | |||
| 10778 | *buf, bodyEndBit, | |||
| 10779 | static_cast<std::uint64_t>(nInverse) * 128u) | |||
| 10780 | || !DRW::reserve(parsedInverseClipBoundary, | |||
| 10781 | static_cast<std::size_t>(nInverse))) | |||
| 10782 | return fail(); | |||
| 10783 | for (std::uint16_t i = 0; i < nInverse; ++i) { | |||
| 10784 | DRW_Coord p; | |||
| 10785 | if (!readBoundedRawDouble(*buf, bodyEndBit, p.x) | |||
| 10786 | || !readBoundedRawDouble(*buf, bodyEndBit, p.y) | |||
| 10787 | || !std::isfinite(p.x) || !std::isfinite(p.y)) | |||
| 10788 | return fail(); | |||
| 10789 | p.z = 0.0; | |||
| 10790 | parsedInverseClipBoundary.push_back(p); | |||
| 10791 | } | |||
| 10792 | } | |||
| 10793 | if (!buf->isGood()) | |||
| 10794 | return fail(); | |||
| 10795 | ||||
| 10796 | std::uint64_t handleEndBit = 0; | |||
| 10797 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 10798 | handleEndBit)) | |||
| 10799 | return fail(); | |||
| 10800 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 10801 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 10802 | handleEndBit)) | |||
| 10803 | return fail(); | |||
| 10804 | // The definition follows the common entity handles in every version: R13 | |||
| 10805 | // and R14 keep both behind the data of the same record. | |||
| 10806 | std::uint32_t parsedDefinitionHandle = 0; | |||
| 10807 | if (proxyEntityHasBits(handleProbe, handleEndBit, 16)) { | |||
| 10808 | dwgHandle defH; | |||
| 10809 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 10810 | defH)) | |||
| 10811 | return fail(); | |||
| 10812 | if (!handleProbe.isGood()) | |||
| 10813 | return fail(); | |||
| 10814 | parsedDefinitionHandle = defH.ref; | |||
| 10815 | DRW_DBG(" UNDERLAY definitionHandle: ")DRW_dbg::dbg(" UNDERLAY definitionHandle: "); | |||
| 10816 | DRW_DBGHL(defH.code, defH.size, defH.ref)DRW_dbg::dbgHL(defH.code, defH.size, defH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10817 | } | |||
| 10818 | if (!handleProbe.isGood()) | |||
| 10819 | return fail(); | |||
| 10820 | *sourceBuf = handleProbe; | |||
| 10821 | extPoint = parsedExtPoint; | |||
| 10822 | position = parsedPosition; | |||
| 10823 | rotation = parsedRotation; | |||
| 10824 | scale = parsedScale; | |||
| 10825 | flags = parsedFlags; | |||
| 10826 | contrast = parsedContrast; | |||
| 10827 | fade = parsedFade; | |||
| 10828 | clipBoundary = std::move(parsedClipBoundary); | |||
| 10829 | inverseClipBoundary = std::move(parsedInverseClipBoundary); | |||
| 10830 | definitionHandle = parsedDefinitionHandle; | |||
| 10831 | return true; | |||
| 10832 | } | |||
| 10833 | ||||
| 10834 | bool DRW_Underlay::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 10835 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 10836 | dwgBufferW *handleBuf) { | |||
| 10837 | (void)bs; (void)strBuf; | |||
| 10838 | if (!validatePayloadFields() | |||
| 10839 | || clipBoundary.size() > kMaxClipVertices | |||
| 10840 | || inverseClipBoundary.size() > kMaxClipVertices | |||
| 10841 | || (version <= DRW::AC1021 && !inverseClipBoundary.empty())) | |||
| 10842 | return false; | |||
| 10843 | ||||
| 10844 | switch (kind) { | |||
| 10845 | case DGN: | |||
| 10846 | oType = kDwgClassNumDgn; | |||
| 10847 | break; | |||
| 10848 | case DWF: | |||
| 10849 | oType = kDwgClassNumDwf; | |||
| 10850 | break; | |||
| 10851 | case PDF: | |||
| 10852 | default: | |||
| 10853 | oType = kDwgClassNumPdf; | |||
| 10854 | break; | |||
| 10855 | } | |||
| 10856 | if (!encodeDwgCommon(version, buf)) | |||
| 10857 | return false; | |||
| 10858 | ||||
| 10859 | const bool hasInverseClip = !inverseClipBoundary.empty() || (flags & 0x10) != 0; | |||
| 10860 | const std::uint8_t wireFlags = | |||
| 10861 | hasInverseClip ? static_cast<std::uint8_t>(flags | 0x10) : flags; | |||
| 10862 | ||||
| 10863 | buf->putExtrusion(extPoint, false); | |||
| 10864 | buf->put3BitDouble(position); | |||
| 10865 | buf->putBitDouble(rotation); | |||
| 10866 | buf->putBitDouble(scale.x); | |||
| 10867 | buf->putBitDouble(scale.y); | |||
| 10868 | buf->putBitDouble(scale.z); | |||
| 10869 | buf->putRawChar8(wireFlags); | |||
| 10870 | buf->putRawChar8(contrast); | |||
| 10871 | buf->putRawChar8(fade); | |||
| 10872 | buf->putBitLong(static_cast<std::int32_t>(clipBoundary.size())); | |||
| 10873 | for (const auto& vertex : clipBoundary) { | |||
| 10874 | buf->putRawDouble(vertex.x); | |||
| 10875 | buf->putRawDouble(vertex.y); | |||
| 10876 | } | |||
| 10877 | if (version > DRW::AC1021 && hasInverseClip) { | |||
| 10878 | buf->putBitShort(static_cast<std::uint16_t>(inverseClipBoundary.size())); | |||
| 10879 | for (const auto& vertex : inverseClipBoundary) { | |||
| 10880 | buf->putRawDouble(vertex.x); | |||
| 10881 | buf->putRawDouble(vertex.y); | |||
| 10882 | } | |||
| 10883 | } | |||
| 10884 | ||||
| 10885 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 10886 | return false; | |||
| 10887 | putNullableHardPointerHandle(handleBuf ? handleBuf : buf, definitionHandle); | |||
| 10888 | return true; | |||
| 10889 | } | |||
| 10890 | ||||
| 10891 | ||||
| 10892 | bool DRW_Text::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 10893 | switch (code) { | |||
| 10894 | case 40: | |||
| 10895 | height = reader->getDouble(); | |||
| 10896 | break; | |||
| 10897 | case 41: | |||
| 10898 | widthscale = reader->getDouble(); | |||
| 10899 | break; | |||
| 10900 | case 50: | |||
| 10901 | angle = reader->getDouble(); | |||
| 10902 | break; | |||
| 10903 | case 51: | |||
| 10904 | oblique = reader->getDouble(); | |||
| 10905 | break; | |||
| 10906 | case 71: | |||
| 10907 | textgen = reader->getInt32(); | |||
| 10908 | break; | |||
| 10909 | case 72: | |||
| 10910 | alignH = (HAlign)reader->getInt32(); | |||
| 10911 | break; | |||
| 10912 | case 73: | |||
| 10913 | alignV = (VAlign)reader->getInt32(); | |||
| 10914 | break; | |||
| 10915 | case 1: | |||
| 10916 | text = reader->getUtf8String(); | |||
| 10917 | break; | |||
| 10918 | case 7: | |||
| 10919 | style = reader->getUtf8String(); | |||
| 10920 | break; | |||
| 10921 | default: | |||
| 10922 | return DRW_Line::parseCode(code, reader); | |||
| 10923 | } | |||
| 10924 | ||||
| 10925 | return true; | |||
| 10926 | } | |||
| 10927 | ||||
| 10928 | void DRW_Text::resetDwgState() { | |||
| 10929 | DRW_Entity::reset(); | |||
| 10930 | basePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10931 | secPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10932 | thickness = 0.0; | |||
| 10933 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 10934 | xAxisAngle = 0.0; | |||
| 10935 | height = 0.0; | |||
| 10936 | text.clear(); | |||
| 10937 | angle = 0.0; | |||
| 10938 | widthscale = 1.0; | |||
| 10939 | oblique = 0.0; | |||
| 10940 | style = "STANDARD"; | |||
| 10941 | textgen = 0; | |||
| 10942 | alignH = HLeft; | |||
| 10943 | alignV = VBaseLine; | |||
| 10944 | styleH = dwgHandle{}; | |||
| 10945 | } | |||
| 10946 | ||||
| 10947 | bool DRW_Text::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 10948 | resetDwgState(); | |||
| 10949 | dwgBuffer *sourceBuf = buf; | |||
| 10950 | auto fail = [this, sourceBuf]() { | |||
| 10951 | if (sourceBuf != nullptr) | |||
| 10952 | sourceBuf->invalidate(); | |||
| 10953 | resetDwgState(); | |||
| 10954 | return false; | |||
| 10955 | }; | |||
| 10956 | if (sourceBuf == nullptr) | |||
| 10957 | return fail(); | |||
| 10958 | ||||
| 10959 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 10960 | buf = &bodyProbe; | |||
| 10961 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 10962 | dwgBuffer *sBuf = buf; | |||
| 10963 | if (version > DRW::AC1018) {//2007+ | |||
| 10964 | sBuf = &sBuff; //separate buffer for strings | |||
| 10965 | } | |||
| 10966 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 10967 | if (!ret) | |||
| 10968 | return fail(); | |||
| 10969 | DRW_DBG("\n***************************** parsing text *********************************************\n")DRW_dbg::dbg("\n***************************** parsing text *********************************************\n" ); | |||
| 10970 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 10971 | ||||
| 10972 | // DataFlags RC Used to determine presence of subsequent data, set to 0xFF for R14- | |||
| 10973 | std::uint8_t data_flags = 0x00; | |||
| 10974 | if (version > DRW::AC1014) {//2000+ | |||
| 10975 | if (!readBoundedRawChar8(*buf, bodyEndBit, data_flags)) | |||
| 10976 | return fail(); /* DataFlags RC Used to determine presence of subsequent data */ | |||
| 10977 | 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"); | |||
| 10978 | if ( !(data_flags & 0x01) ) { /* Elevation RD --- present if !(DataFlags & 0x01) */ | |||
| 10979 | if (!readBoundedRawDouble(*buf, bodyEndBit, basePoint.z)) | |||
| 10980 | return fail(); | |||
| 10981 | } | |||
| 10982 | } else {//14- | |||
| 10983 | if (!readBoundedBitDouble(*buf, bodyEndBit, basePoint.z)) | |||
| 10984 | return fail(); /* Elevation BD --- */ | |||
| 10985 | } | |||
| 10986 | if (!readBoundedRawDouble(*buf, bodyEndBit, basePoint.x) | |||
| 10987 | || !readBoundedRawDouble(*buf, bodyEndBit, basePoint.y)) | |||
| 10988 | return fail(); /* Insertion pt 2RD 10 */ | |||
| 10989 | 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"); | |||
| 10990 | if (version > DRW::AC1014) {//2000+ | |||
| 10991 | if ( !(data_flags & 0x02) ) { /* Alignment pt 2DD 11 present if !(DataFlags & 0x02), use 10 & 20 values for 2 default values.*/ | |||
| 10992 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, basePoint.x, | |||
| 10993 | secPoint.x) | |||
| 10994 | || !readBoundedDefaultDouble(*buf, bodyEndBit, basePoint.y, | |||
| 10995 | secPoint.y)) | |||
| 10996 | return fail(); | |||
| 10997 | } else { | |||
| 10998 | secPoint = basePoint; | |||
| 10999 | } | |||
| 11000 | } else {//14- | |||
| 11001 | if (!readBoundedRawDouble(*buf, bodyEndBit, secPoint.x) | |||
| 11002 | || !readBoundedRawDouble(*buf, bodyEndBit, secPoint.y)) | |||
| 11003 | return fail(); /* Alignment pt 2RD 11 */ | |||
| 11004 | } | |||
| 11005 | secPoint.z = basePoint.z; | |||
| 11006 | 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"); | |||
| 11007 | if (!readBoundedExtrusion(*buf, bodyEndBit, version > DRW::AC1014, | |||
| 11008 | extPoint)) | |||
| 11009 | return fail(); | |||
| 11010 | 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"); | |||
| 11011 | if (!readBoundedThickness(*buf, bodyEndBit, version > DRW::AC1014, | |||
| 11012 | thickness)) | |||
| 11013 | return fail(); /* Thickness BD 39 */ | |||
| 11014 | ||||
| 11015 | if (version > DRW::AC1014) {//2000+ | |||
| 11016 | if ( !(data_flags & 0x04) ) { /* Oblique ang RD 51 present if !(DataFlags & 0x04) */ | |||
| 11017 | if (!readBoundedRawDouble(*buf, bodyEndBit, oblique)) | |||
| 11018 | return fail(); | |||
| 11019 | } | |||
| 11020 | if ( !(data_flags & 0x08) ) { /* Rotation ang RD 50 present if !(DataFlags & 0x08) */ | |||
| 11021 | if (!readBoundedRawDouble(*buf, bodyEndBit, angle)) | |||
| 11022 | return fail(); | |||
| 11023 | } | |||
| 11024 | if (!readBoundedRawDouble(*buf, bodyEndBit, height)) | |||
| 11025 | return fail(); /* Height RD 40 */ | |||
| 11026 | if ( !(data_flags & 0x10) ) { /* Width factor RD 41 present if !(DataFlags & 0x10) */ | |||
| 11027 | if (!readBoundedRawDouble(*buf, bodyEndBit, widthscale)) | |||
| 11028 | return fail(); | |||
| 11029 | } | |||
| 11030 | } else {//14- | |||
| 11031 | if (!readBoundedBitDouble(*buf, bodyEndBit, oblique) | |||
| 11032 | || !readBoundedBitDouble(*buf, bodyEndBit, angle) | |||
| 11033 | || !readBoundedBitDouble(*buf, bodyEndBit, height) | |||
| 11034 | || !readBoundedBitDouble(*buf, bodyEndBit, widthscale)) | |||
| 11035 | return fail(); /* Oblique/rotation/height/width BD */ | |||
| 11036 | } | |||
| 11037 | angle *= ARAD57.29577951308232; | |||
| 11038 | if (!std::isfinite(basePoint.x) || !std::isfinite(basePoint.y) | |||
| 11039 | || !std::isfinite(basePoint.z) || !std::isfinite(secPoint.x) | |||
| 11040 | || !std::isfinite(secPoint.y) || !std::isfinite(secPoint.z) | |||
| 11041 | || !std::isfinite(extPoint.x) || !std::isfinite(extPoint.y) | |||
| 11042 | || !std::isfinite(extPoint.z) || !std::isfinite(thickness) | |||
| 11043 | || !std::isfinite(oblique) || !std::isfinite(angle) | |||
| 11044 | || !std::isfinite(height) || !std::isfinite(widthscale)) | |||
| 11045 | return fail(); | |||
| 11046 | 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: "); | |||
| 11047 | 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"); | |||
| 11048 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 11049 | if (version > DRW::AC1021) { | |||
| 11050 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 11051 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 11052 | ignoredBodyEndBit, &stringEndBit)) | |||
| 11053 | return fail(); | |||
| 11054 | } | |||
| 11055 | UTF8STRINGstd::string parsedText; | |||
| 11056 | if (version > DRW::AC1018 | |||
| 11057 | && currentDwgBit(sBuf) >= stringEndBit) { | |||
| 11058 | parsedText.clear(); | |||
| 11059 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11060 | parsedText)) { | |||
| 11061 | return fail(); | |||
| 11062 | } | |||
| 11063 | 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"); | |||
| 11064 | //textgen, alignH, alignV always present in R14-, data_flags set in initialisation | |||
| 11065 | if ( !(data_flags & 0x20) ) { /* Generation BS 71 present if !(DataFlags & 0x20) */ | |||
| 11066 | std::uint16_t parsedTextgen = 0; | |||
| 11067 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedTextgen)) | |||
| 11068 | return fail(); | |||
| 11069 | textgen = parsedTextgen; | |||
| 11070 | DRW_DBG("textgen: ")DRW_dbg::dbg("textgen: "); DRW_DBG(textgen)DRW_dbg::dbg(textgen); | |||
| 11071 | } | |||
| 11072 | if ( !(data_flags & 0x40) ) { /* Horiz align. BS 72 present if !(DataFlags & 0x40) */ | |||
| 11073 | std::uint16_t parsedAlignH = 0; | |||
| 11074 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedAlignH)) | |||
| 11075 | return fail(); | |||
| 11076 | alignH = static_cast<HAlign>(parsedAlignH); | |||
| 11077 | DRW_DBG(", alignH: ")DRW_dbg::dbg(", alignH: "); DRW_DBG(alignH)DRW_dbg::dbg(alignH); | |||
| 11078 | } | |||
| 11079 | if ( !(data_flags & 0x80) ) { /* Vert align. BS 73 present if !(DataFlags & 0x80) */ | |||
| 11080 | std::uint16_t parsedAlignV = 0; | |||
| 11081 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedAlignV)) | |||
| 11082 | return fail(); | |||
| 11083 | alignV = static_cast<VAlign>(parsedAlignV); | |||
| 11084 | DRW_DBG(", alignV: ")DRW_dbg::dbg(", alignV: "); DRW_DBG(alignV)DRW_dbg::dbg(alignV); | |||
| 11085 | } | |||
| 11086 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 11087 | ||||
| 11088 | if (!buf->isGood() || !sBuf->isGood() | |||
| 11089 | || currentDwgBit(buf) > bodyEndBit | |||
| 11090 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 11091 | return fail(); | |||
| 11092 | ||||
| 11093 | /* Common Entity Handle Data */ | |||
| 11094 | std::uint64_t handleEndBit = 0; | |||
| 11095 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 11096 | handleEndBit)) | |||
| 11097 | return fail(); | |||
| 11098 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 11099 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 11100 | handleEndBit); | |||
| 11101 | if (!ret) | |||
| 11102 | return fail(); | |||
| 11103 | ||||
| 11104 | dwgHandle parsedStyleH; | |||
| 11105 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 11106 | parsedStyleH) | |||
| 11107 | || !handleProbe.isGood() || !sBuf->isGood()) | |||
| 11108 | return fail(); | |||
| 11109 | ||||
| 11110 | *sourceBuf = handleProbe; | |||
| 11111 | text = std::move(parsedText); | |||
| 11112 | styleH = parsedStyleH; | |||
| 11113 | 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"); | |||
| 11114 | /* CRC X --- */ | |||
| 11115 | return true; | |||
| 11116 | } | |||
| 11117 | ||||
| 11118 | // --------------------------------------------------------------------------- | |||
| 11119 | // RTEXT (RText, Express Tools) — read-only, mapped onto DRW_Text. | |||
| 11120 | // --------------------------------------------------------------------------- | |||
| 11121 | bool DRW_RText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 11122 | // RTEXT's DXF layout is a TEXT subset (1 text, 7 style, 10/20/30 insertion, | |||
| 11123 | // 40 height, 50 rotation deg, 210/220/230 extrusion) plus a flags long (70) | |||
| 11124 | // that plain TEXT does not carry. | |||
| 11125 | if (70 == code) { | |||
| 11126 | m_rTextFlags = reader->getInt32(); | |||
| 11127 | return true; | |||
| 11128 | } | |||
| 11129 | return DRW_Text::parseCode(code, reader); | |||
| 11130 | } | |||
| 11131 | ||||
| 11132 | bool DRW_RText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 11133 | resetDwgState(); | |||
| 11134 | m_rTextFlags = 0; | |||
| 11135 | dwgBuffer *sourceBuf = buf; | |||
| 11136 | auto fail = [this, sourceBuf]() { | |||
| 11137 | if (sourceBuf != nullptr) | |||
| 11138 | sourceBuf->invalidate(); | |||
| 11139 | resetDwgState(); | |||
| 11140 | m_rTextFlags = 0; | |||
| 11141 | return false; | |||
| 11142 | }; | |||
| 11143 | if (sourceBuf == nullptr) | |||
| 11144 | return fail(); | |||
| 11145 | ||||
| 11146 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 11147 | buf = &bodyProbe; | |||
| 11148 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 11149 | dwgBuffer *sBuf = buf; | |||
| 11150 | if (version > DRW::AC1018) // 2007+ strings live in a separate stream | |||
| 11151 | sBuf = &sBuff; | |||
| 11152 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 11153 | if (!ret) | |||
| 11154 | return fail(); | |||
| 11155 | DRW_DBG("\n***************************** parsing rtext ********************************************\n")DRW_dbg::dbg("\n***************************** parsing rtext ********************************************\n" ); | |||
| 11156 | ||||
| 11157 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 11158 | DRW_Coord parsedBasePoint; | |||
| 11159 | DRW_Coord parsedExtrusion; | |||
| 11160 | double parsedAngle = 0.0; | |||
| 11161 | double parsedHeight = 0.0; | |||
| 11162 | std::uint16_t parsedFlags = 0; | |||
| 11163 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 11164 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtrusion) | |||
| 11165 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 11166 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedHeight) | |||
| 11167 | || !readBoundedBitShort(*buf, bodyEndBit, parsedFlags) | |||
| 11168 | || !std::isfinite(parsedBasePoint.x) | |||
| 11169 | || !std::isfinite(parsedBasePoint.y) | |||
| 11170 | || !std::isfinite(parsedBasePoint.z) | |||
| 11171 | || !std::isfinite(parsedExtrusion.x) | |||
| 11172 | || !std::isfinite(parsedExtrusion.y) | |||
| 11173 | || !std::isfinite(parsedExtrusion.z) | |||
| 11174 | || !std::isfinite(parsedAngle) | |||
| 11175 | || !std::isfinite(parsedHeight)) | |||
| 11176 | return fail(); | |||
| 11177 | basePoint = parsedBasePoint; // insertion 3BD | |||
| 11178 | secPoint = parsedBasePoint; // no separate alignment point | |||
| 11179 | extPoint = parsedExtrusion; // extrusion 3BD | |||
| 11180 | angle = parsedAngle * ARAD57.29577951308232; // rotation BD (radians) -> degrees | |||
| 11181 | height = parsedHeight; // height BD | |||
| 11182 | m_rTextFlags = parsedFlags; // flags BS | |||
| 11183 | if (!std::isfinite(angle)) | |||
| 11184 | return fail(); | |||
| 11185 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 11186 | if (version > DRW::AC1021) { | |||
| 11187 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 11188 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 11189 | ignoredBodyEndBit, &stringEndBit)) | |||
| 11190 | return fail(); | |||
| 11191 | } | |||
| 11192 | UTF8STRINGstd::string parsedText; | |||
| 11193 | if (version > DRW::AC1018 | |||
| 11194 | && currentDwgBit(sBuf) >= stringEndBit) { | |||
| 11195 | parsedText.clear(); | |||
| 11196 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11197 | parsedText)) { | |||
| 11198 | return fail(); | |||
| 11199 | } | |||
| 11200 | 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"); | |||
| 11201 | ||||
| 11202 | if (!buf->isGood() || !sBuf->isGood() | |||
| 11203 | || currentDwgBit(buf) > bodyEndBit | |||
| 11204 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 11205 | return fail(); | |||
| 11206 | ||||
| 11207 | std::uint64_t handleEndBit = 0; | |||
| 11208 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 11209 | handleEndBit)) | |||
| 11210 | return fail(); | |||
| 11211 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 11212 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 11213 | handleEndBit); | |||
| 11214 | if (!ret) | |||
| 11215 | return fail(); | |||
| 11216 | dwgHandle parsedStyleH; | |||
| 11217 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 11218 | parsedStyleH) | |||
| 11219 | || !handleProbe.isGood() || !sBuf->isGood()) | |||
| 11220 | return fail(); | |||
| 11221 | ||||
| 11222 | *sourceBuf = handleProbe; | |||
| 11223 | text = std::move(parsedText); | |||
| 11224 | styleH = parsedStyleH; | |||
| 11225 | return true; | |||
| 11226 | } | |||
| 11227 | ||||
| 11228 | // --------------------------------------------------------------------------- | |||
| 11229 | // ARCALIGNEDTEXT (AcDbArcAlignedText, Express Tools) — read-only, mapped onto | |||
| 11230 | // DRW_Text as a 2D approximation (text at the arc mid-point, tangent baseline). | |||
| 11231 | // --------------------------------------------------------------------------- | |||
| 11232 | bool DRW_RText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 11233 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 11234 | (void)bs; | |||
| 11235 | oType = kDwgClassNum; | |||
| 11236 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 11237 | ||||
| 11238 | buf->put3BitDouble(basePoint); | |||
| 11239 | buf->put3BitDouble(extPoint); | |||
| 11240 | buf->putBitDouble(angle / ARAD57.29577951308232); | |||
| 11241 | buf->putBitDouble(height); | |||
| 11242 | buf->putBitShort(bitShortFromInt(m_rTextFlags)); | |||
| 11243 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 11244 | ||||
| 11245 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 11246 | putHardPointerHandle(handleBuf ? handleBuf : buf, | |||
| 11247 | (styleH.ref == 0) ? 0x13 : styleH.ref); | |||
| 11248 | return true; | |||
| 11249 | } | |||
| 11250 | ||||
| 11251 | void DRW_ArcAlignedText::applyArcApproximation(){ | |||
| 11252 | const double mid = 0.5 * (m_startAngle + m_endAngle); | |||
| 11253 | basePoint.x = m_center.x + m_radius * std::cos(mid); | |||
| 11254 | basePoint.y = m_center.y + m_radius * std::sin(mid); | |||
| 11255 | basePoint.z = m_center.z; | |||
| 11256 | secPoint = basePoint; | |||
| 11257 | // Baseline tangent to the arc at the mid-point; angle stored in degrees to | |||
| 11258 | // match DRW_Text (which the DWG path fills via `angle *= ARAD`). | |||
| 11259 | angle = (mid + M_PI_21.57079632679489661923) * ARAD57.29577951308232; | |||
| 11260 | // Height from the text-size D2T string when parseable, else a fraction of | |||
| 11261 | // the radius so the approximation is at least visible. | |||
| 11262 | double h = 0.0; | |||
| 11263 | try { h = std::stod(m_textSize); } catch (...) { h = 0.0; } | |||
| 11264 | if (h > 0.0) | |||
| 11265 | height = h; | |||
| 11266 | else if (height <= 0.0) | |||
| 11267 | height = 0.1 * m_radius; | |||
| 11268 | } | |||
| 11269 | ||||
| 11270 | // Format a D2T (double-to-text) field the way the ARCALIGNEDTEXT model stores | |||
| 11271 | // it: the DWG body carries these as text ("2.5", "1", "0"), while the DXF path | |||
| 11272 | // reads them as doubles (group codes 41-46 fall in the double range, so the | |||
| 11273 | // reader populates doubleData and leaves strData stale — getString() is unsafe | |||
| 11274 | // here). %g reproduces the same compact textual form. | |||
| 11275 | static std::string arcAlignedD2T(double v){ | |||
| 11276 | char buf[32]; | |||
| 11277 | std::snprintf(buf, sizeof(buf), "%g", v); | |||
| 11278 | return std::string(buf); | |||
| 11279 | } | |||
| 11280 | ||||
| 11281 | static std::string arcAlignedStringOrDefault(const UTF8STRINGstd::string& value, | |||
| 11282 | const std::string& fallback) { | |||
| 11283 | return value.empty() ? fallback : value; | |||
| 11284 | } | |||
| 11285 | ||||
| 11286 | bool DRW_ArcAlignedText::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 11287 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 11288 | dwgBufferW *handleBuf) { | |||
| 11289 | (void)bs; | |||
| 11290 | oType = kDwgClassNum; | |||
| 11291 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 11292 | ||||
| 11293 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 11294 | sb->putVariableText(version, arcAlignedStringOrDefault( | |||
| 11295 | m_textSize, arcAlignedD2T(height > 0.0 ? height : 0.0))); | |||
| 11296 | sb->putVariableText(version, arcAlignedStringOrDefault( | |||
| 11297 | m_xScale, arcAlignedD2T(widthscale > 0.0 ? widthscale : 1.0))); | |||
| 11298 | sb->putVariableText(version, arcAlignedStringOrDefault(m_charSpacing, "1")); | |||
| 11299 | sb->putVariableText(version, style.empty() ? "Standard" : style); | |||
| 11300 | sb->putVariableText(version, m_fontName); | |||
| 11301 | sb->putVariableText(version, m_bigFontName); | |||
| 11302 | sb->putVariableText(version, text); | |||
| 11303 | sb->putVariableText(version, arcAlignedStringOrDefault(m_offsetFromArc, "0")); | |||
| 11304 | sb->putVariableText(version, arcAlignedStringOrDefault(m_rightOffset, "0")); | |||
| 11305 | sb->putVariableText(version, arcAlignedStringOrDefault(m_leftOffset, "0")); | |||
| 11306 | ||||
| 11307 | buf->put3BitDouble(m_center); | |||
| 11308 | buf->putBitDouble(m_radius); | |||
| 11309 | buf->putBitDouble(m_startAngle); | |||
| 11310 | buf->putBitDouble(m_endAngle); | |||
| 11311 | buf->put3BitDouble(extPoint); | |||
| 11312 | buf->putBitLong(static_cast<std::int32_t>(m_rawColor)); | |||
| 11313 | buf->putBitShort(bitShortFromInt(m_characterSet)); | |||
| 11314 | buf->putBitShort(bitShortFromInt(m_pitchAndFamily)); | |||
| 11315 | buf->putBitShort(bitShortFromInt(m_isShx)); | |||
| 11316 | buf->putBitShort(bitShortFromInt(m_isBold)); | |||
| 11317 | buf->putBitShort(bitShortFromInt(m_isItalic)); | |||
| 11318 | buf->putBitShort(bitShortFromInt(m_isUnderlined)); | |||
| 11319 | buf->putBitShort(bitShortFromInt(m_alignment)); | |||
| 11320 | buf->putBitShort(bitShortFromInt(m_isReverse)); | |||
| 11321 | buf->putBitShort(bitShortFromInt(m_wizardFlag)); | |||
| 11322 | buf->putBitShort(bitShortFromInt(m_textPosition)); | |||
| 11323 | buf->putBitShort(bitShortFromInt(m_textDirection)); | |||
| 11324 | ||||
| 11325 | if (version <= DRW::AC1018) | |||
| 11326 | putNullableHardPointerHandle(buf, m_arcHandle); | |||
| 11327 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 11328 | if (version > DRW::AC1018) | |||
| 11329 | putNullableHardPointerHandle(handleBuf ? handleBuf : buf, m_arcHandle); | |||
| 11330 | return true; | |||
| 11331 | } | |||
| 11332 | ||||
| 11333 | bool DRW_ArcAlignedText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 11334 | // ARCALIGNEDTEXT repurposes several TEXT codes (2/10/40/41/50/51/70…), so it | |||
| 11335 | // must not delegate those to DRW_Text; unknown codes fall through to the | |||
| 11336 | // AcDbEntity common parser. Angles (50/51) are DXF degrees -> radians. | |||
| 11337 | switch (code) { | |||
| 11338 | case 1: text = reader->getUtf8String(); break; | |||
| 11339 | case 2: m_fontName = reader->getUtf8String(); break; | |||
| 11340 | case 3: m_bigFontName = reader->getUtf8String(); break; | |||
| 11341 | case 7: style = reader->getUtf8String(); break; | |||
| 11342 | case 10: m_center.x = reader->getDouble(); break; | |||
| 11343 | case 20: m_center.y = reader->getDouble(); break; | |||
| 11344 | case 30: m_center.z = reader->getDouble(); break; | |||
| 11345 | case 40: m_radius = reader->getDouble(); break; | |||
| 11346 | case 41: m_xScale = arcAlignedD2T(reader->getDouble()); break; | |||
| 11347 | case 42: m_textSize = arcAlignedD2T(reader->getDouble()); break; | |||
| 11348 | case 43: m_charSpacing = arcAlignedD2T(reader->getDouble()); break; | |||
| 11349 | case 44: m_offsetFromArc = arcAlignedD2T(reader->getDouble()); break; | |||
| 11350 | case 45: m_rightOffset = arcAlignedD2T(reader->getDouble()); break; | |||
| 11351 | case 46: m_leftOffset = arcAlignedD2T(reader->getDouble()); break; | |||
| 11352 | case 50: m_startAngle = reader->getDouble() / ARAD57.29577951308232; break; | |||
| 11353 | case 51: m_endAngle = reader->getDouble() / ARAD57.29577951308232; break; | |||
| 11354 | case 70: m_isReverse = reader->getInt32(); break; | |||
| 11355 | case 71: m_textDirection = reader->getInt32(); break; | |||
| 11356 | case 72: m_alignment = reader->getInt32(); break; | |||
| 11357 | case 73: m_textPosition = reader->getInt32(); break; | |||
| 11358 | case 74: m_isBold = reader->getInt32(); break; | |||
| 11359 | case 75: m_isItalic = reader->getInt32(); break; | |||
| 11360 | case 76: m_isUnderlined = reader->getInt32(); break; | |||
| 11361 | case 77: m_characterSet = reader->getInt32(); break; | |||
| 11362 | case 78: m_pitchAndFamily = reader->getInt32(); break; | |||
| 11363 | case 79: m_isShx = reader->getInt32(); break; | |||
| 11364 | case 90: m_rawColor = reader->getInt32(); break; | |||
| 11365 | case 210: extPoint.x = reader->getDouble(); break; | |||
| 11366 | case 220: extPoint.y = reader->getDouble(); break; | |||
| 11367 | case 230: extPoint.z = reader->getDouble(); break; | |||
| 11368 | case 280: m_wizardFlag = reader->getInt32(); break; | |||
| 11369 | default: return DRW_Entity::parseCode(code, reader); | |||
| 11370 | } | |||
| 11371 | return true; | |||
| 11372 | } | |||
| 11373 | ||||
| 11374 | void DRW_ArcAlignedText::resetDwgState() { | |||
| 11375 | DRW_Text::resetDwgState(); | |||
| 11376 | m_center = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 11377 | m_radius = 0.0; | |||
| 11378 | m_startAngle = 0.0; | |||
| 11379 | m_endAngle = 0.0; | |||
| 11380 | m_textSize.clear(); | |||
| 11381 | m_xScale.clear(); | |||
| 11382 | m_charSpacing.clear(); | |||
| 11383 | m_offsetFromArc.clear(); | |||
| 11384 | m_rightOffset.clear(); | |||
| 11385 | m_leftOffset.clear(); | |||
| 11386 | m_fontName.clear(); | |||
| 11387 | m_bigFontName.clear(); | |||
| 11388 | m_rawColor = 0; | |||
| 11389 | m_characterSet = 0; | |||
| 11390 | m_pitchAndFamily = 0; | |||
| 11391 | m_isShx = 0; | |||
| 11392 | m_isBold = 0; | |||
| 11393 | m_isItalic = 0; | |||
| 11394 | m_isUnderlined = 0; | |||
| 11395 | m_alignment = 0; | |||
| 11396 | m_isReverse = 0; | |||
| 11397 | m_wizardFlag = 0; | |||
| 11398 | m_textPosition = 0; | |||
| 11399 | m_textDirection = 0; | |||
| 11400 | m_arcHandle = 0; | |||
| 11401 | } | |||
| 11402 | ||||
| 11403 | bool DRW_ArcAlignedText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 11404 | // The arc reference is an optional trailer whose position depends on the | |||
| 11405 | // DWG version. Never carry it across a reused or truncated record. | |||
| 11406 | resetDwgState(); | |||
| 11407 | dwgBuffer *sourceBuf = buf; | |||
| 11408 | auto fail = [this, sourceBuf]() { | |||
| 11409 | if (sourceBuf != nullptr) | |||
| 11410 | sourceBuf->invalidate(); | |||
| 11411 | resetDwgState(); | |||
| 11412 | return false; | |||
| 11413 | }; | |||
| 11414 | if (sourceBuf == nullptr) | |||
| 11415 | return fail(); | |||
| 11416 | ||||
| 11417 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 11418 | buf = &bodyProbe; | |||
| 11419 | ||||
| 11420 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 11421 | dwgBuffer *sBuf = buf; | |||
| 11422 | if (version > DRW::AC1018) // 2007+ strings live in a separate stream | |||
| 11423 | sBuf = &sBuff; | |||
| 11424 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 11425 | if (!ret) | |||
| 11426 | return fail(); | |||
| 11427 | DRW_DBG("\n***************************** parsing arcalignedtext **********************************\n")DRW_dbg::dbg("\n***************************** parsing arcalignedtext **********************************\n" ); | |||
| 11428 | ||||
| 11429 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 11430 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 11431 | if (version > DRW::AC1021) { | |||
| 11432 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 11433 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 11434 | ignoredBodyEndBit, &stringEndBit)) | |||
| 11435 | return fail(); | |||
| 11436 | } | |||
| 11437 | ||||
| 11438 | UTF8STRINGstd::string parsedTextSize; | |||
| 11439 | UTF8STRINGstd::string parsedXScale; | |||
| 11440 | UTF8STRINGstd::string parsedCharSpacing; | |||
| 11441 | UTF8STRINGstd::string parsedStyle; | |||
| 11442 | UTF8STRINGstd::string parsedFontName; | |||
| 11443 | UTF8STRINGstd::string parsedBigFontName; | |||
| 11444 | UTF8STRINGstd::string parsedText; | |||
| 11445 | UTF8STRINGstd::string parsedOffsetFromArc; | |||
| 11446 | UTF8STRINGstd::string parsedRightOffset; | |||
| 11447 | UTF8STRINGstd::string parsedLeftOffset; | |||
| 11448 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11449 | parsedTextSize) | |||
| 11450 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11451 | parsedXScale) | |||
| 11452 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11453 | parsedCharSpacing) | |||
| 11454 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11455 | parsedStyle) | |||
| 11456 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11457 | parsedFontName) | |||
| 11458 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11459 | parsedBigFontName) | |||
| 11460 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11461 | parsedText) | |||
| 11462 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11463 | parsedOffsetFromArc) | |||
| 11464 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11465 | parsedRightOffset) | |||
| 11466 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11467 | parsedLeftOffset)) | |||
| 11468 | return fail(); | |||
| 11469 | ||||
| 11470 | DRW_Coord parsedCenter; | |||
| 11471 | double parsedRadius = 0.0; | |||
| 11472 | double parsedStartAngle = 0.0; | |||
| 11473 | double parsedEndAngle = 0.0; | |||
| 11474 | DRW_Coord parsedExtPoint; | |||
| 11475 | std::int32_t parsedRawColor = 0; | |||
| 11476 | std::uint16_t parsedCharacterSet = 0; | |||
| 11477 | std::uint16_t parsedPitchAndFamily = 0; | |||
| 11478 | std::uint16_t parsedIsShx = 0; | |||
| 11479 | std::uint16_t parsedIsBold = 0; | |||
| 11480 | std::uint16_t parsedIsItalic = 0; | |||
| 11481 | std::uint16_t parsedIsUnderlined = 0; | |||
| 11482 | std::uint16_t parsedAlignment = 0; | |||
| 11483 | std::uint16_t parsedIsReverse = 0; | |||
| 11484 | std::uint16_t parsedWizardFlag = 0; | |||
| 11485 | std::uint16_t parsedTextPosition = 0; | |||
| 11486 | std::uint16_t parsedTextDirection = 0; | |||
| 11487 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 11488 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRadius) | |||
| 11489 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedStartAngle) | |||
| 11490 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedEndAngle) | |||
| 11491 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtPoint) | |||
| 11492 | || !readBoundedBitLong(*buf, bodyEndBit, parsedRawColor) | |||
| 11493 | || !readBoundedBitShort(*buf, bodyEndBit, parsedCharacterSet) | |||
| 11494 | || !readBoundedBitShort(*buf, bodyEndBit, parsedPitchAndFamily) | |||
| 11495 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsShx) | |||
| 11496 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsBold) | |||
| 11497 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsItalic) | |||
| 11498 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsUnderlined) | |||
| 11499 | || !readBoundedBitShort(*buf, bodyEndBit, parsedAlignment) | |||
| 11500 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsReverse) | |||
| 11501 | || !readBoundedBitShort(*buf, bodyEndBit, parsedWizardFlag) | |||
| 11502 | || !readBoundedBitShort(*buf, bodyEndBit, parsedTextPosition) | |||
| 11503 | || !readBoundedBitShort(*buf, bodyEndBit, parsedTextDirection)) | |||
| 11504 | return fail(); | |||
| 11505 | DRW_DBG("arcalignedtext string: ")DRW_dbg::dbg("arcalignedtext string: "); DRW_DBG(parsedText.c_str())DRW_dbg::dbg(parsedText.c_str()); | |||
| 11506 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 11507 | ||||
| 11508 | if (!buf->isGood() || !sBuf->isGood() | |||
| 11509 | || currentDwgBit(buf) > bodyEndBit | |||
| 11510 | || currentDwgBit(sBuf) > stringEndBit | |||
| 11511 | || !std::isfinite(parsedCenter.x) || !std::isfinite(parsedCenter.y) | |||
| 11512 | || !std::isfinite(parsedCenter.z) || !std::isfinite(parsedRadius) | |||
| 11513 | || parsedRadius < 0.0 || !std::isfinite(parsedStartAngle) | |||
| 11514 | || !std::isfinite(parsedEndAngle) || !std::isfinite(parsedExtPoint.x) | |||
| 11515 | || !std::isfinite(parsedExtPoint.y) | |||
| 11516 | || !std::isfinite(parsedExtPoint.z)) | |||
| 11517 | return fail(); | |||
| 11518 | ||||
| 11519 | std::uint64_t handleEndBit = 0; | |||
| 11520 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 11521 | handleEndBit)) | |||
| 11522 | return fail(); | |||
| 11523 | // R2004- keeps the arc handle before the common handle stream; R2007+ after. | |||
| 11524 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 11525 | std::uint32_t parsedArcHandle = 0; | |||
| 11526 | if (version <= DRW::AC1018 | |||
| 11527 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 11528 | dwgHandle arcHandle; | |||
| 11529 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 11530 | arcHandle)) | |||
| 11531 | return fail(); | |||
| 11532 | parsedArcHandle = arcHandle.ref; | |||
| 11533 | } | |||
| 11534 | ||||
| 11535 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 11536 | handleEndBit); | |||
| 11537 | if (!ret) | |||
| 11538 | return fail(); | |||
| 11539 | if (version > DRW::AC1018 | |||
| 11540 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 11541 | dwgHandle arcHandle; | |||
| 11542 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 11543 | arcHandle)) | |||
| 11544 | return fail(); | |||
| 11545 | parsedArcHandle = arcHandle.ref; | |||
| 11546 | } | |||
| 11547 | if (!handleProbe.isGood()) | |||
| 11548 | return fail(); | |||
| 11549 | ||||
| 11550 | *sourceBuf = handleProbe; | |||
| 11551 | m_textSize = std::move(parsedTextSize); | |||
| 11552 | m_xScale = std::move(parsedXScale); | |||
| 11553 | m_charSpacing = std::move(parsedCharSpacing); | |||
| 11554 | style = std::move(parsedStyle); | |||
| 11555 | m_fontName = std::move(parsedFontName); | |||
| 11556 | m_bigFontName = std::move(parsedBigFontName); | |||
| 11557 | text = std::move(parsedText); | |||
| 11558 | m_offsetFromArc = std::move(parsedOffsetFromArc); | |||
| 11559 | m_rightOffset = std::move(parsedRightOffset); | |||
| 11560 | m_leftOffset = std::move(parsedLeftOffset); | |||
| 11561 | m_center = parsedCenter; | |||
| 11562 | m_radius = parsedRadius; | |||
| 11563 | m_startAngle = parsedStartAngle; | |||
| 11564 | m_endAngle = parsedEndAngle; | |||
| 11565 | extPoint = parsedExtPoint; | |||
| 11566 | m_rawColor = parsedRawColor; | |||
| 11567 | m_characterSet = parsedCharacterSet; | |||
| 11568 | m_pitchAndFamily = parsedPitchAndFamily; | |||
| 11569 | m_isShx = parsedIsShx; | |||
| 11570 | m_isBold = parsedIsBold; | |||
| 11571 | m_isItalic = parsedIsItalic; | |||
| 11572 | m_isUnderlined = parsedIsUnderlined; | |||
| 11573 | m_alignment = parsedAlignment; | |||
| 11574 | m_isReverse = parsedIsReverse; | |||
| 11575 | m_wizardFlag = parsedWizardFlag; | |||
| 11576 | m_textPosition = parsedTextPosition; | |||
| 11577 | m_textDirection = parsedTextDirection; | |||
| 11578 | m_arcHandle = parsedArcHandle; | |||
| 11579 | applyArcApproximation(); | |||
| 11580 | return true; | |||
| 11581 | } | |||
| 11582 | ||||
| 11583 | // Out-of-line special members: required because mtext is a unique_ptr<DRW_MText> | |||
| 11584 | // declared with a forward-declared element type in the header. | |||
| 11585 | DRW_Attrib::~DRW_Attrib() = default; | |||
| 11586 | DRW_Attrib::DRW_Attrib(const DRW_Attrib& o) | |||
| 11587 | : DRW_Text(o), tag(o.tag), attribFlags(o.attribFlags), | |||
| 11588 | m_fieldLength(o.m_fieldLength), | |||
| 11589 | lockPosition(o.lockPosition), attVersion(o.attVersion), | |||
| 11590 | m_attributeType(o.m_attributeType), | |||
| 11591 | keepDuplicateRecords(o.keepDuplicateRecords), | |||
| 11592 | mtext(o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr), | |||
| 11593 | dxfInAttributeSubclass(o.dxfInAttributeSubclass), | |||
| 11594 | dxfEmbeddedMarker(o.dxfEmbeddedMarker) {} | |||
| 11595 | DRW_Attrib& DRW_Attrib::operator=(const DRW_Attrib& o) { | |||
| 11596 | if (this != &o) { | |||
| 11597 | DRW_Text::operator=(o); | |||
| 11598 | tag = o.tag; | |||
| 11599 | attribFlags = o.attribFlags; | |||
| 11600 | m_fieldLength = o.m_fieldLength; | |||
| 11601 | lockPosition = o.lockPosition; | |||
| 11602 | attVersion = o.attVersion; | |||
| 11603 | m_attributeType = o.m_attributeType; | |||
| 11604 | keepDuplicateRecords = o.keepDuplicateRecords; | |||
| 11605 | mtext = o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr; | |||
| 11606 | dxfInAttributeSubclass = o.dxfInAttributeSubclass; | |||
| 11607 | dxfEmbeddedMarker = o.dxfEmbeddedMarker; | |||
| 11608 | } | |||
| 11609 | return *this; | |||
| 11610 | } | |||
| 11611 | DRW_Attrib::DRW_Attrib(DRW_Attrib&&) noexcept = default; | |||
| 11612 | DRW_Attrib& DRW_Attrib::operator=(DRW_Attrib&&) noexcept = default; | |||
| 11613 | ||||
| 11614 | bool DRW_Attrib::hasAmbiguousLegacyEmbeddedXData() const { | |||
| 11615 | return dxfEmbeddedMarker == EmbeddedDxfMarker::Legacy100 | |||
| 11616 | && mtext != nullptr && !mtext->extData.empty(); | |||
| 11617 | } | |||
| 11618 | ||||
| 11619 | DRW_GeoPositionMarker::~DRW_GeoPositionMarker() = default; | |||
| 11620 | DRW_GeoPositionMarker::DRW_GeoPositionMarker( | |||
| 11621 | const DRW_GeoPositionMarker& o) | |||
| 11622 | : DRW_Entity(o), m_classVersion(o.m_classVersion), | |||
| 11623 | m_position(o.m_position), m_radius(o.m_radius), m_notes(o.m_notes), | |||
| 11624 | m_landingGap(o.m_landingGap), m_mtextVisible(o.m_mtextVisible), | |||
| 11625 | m_textAlignment(o.m_textAlignment), | |||
| 11626 | m_enableFrameText(o.m_enableFrameText), | |||
| 11627 | mtext(o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr), | |||
| 11628 | m_dxfDouble40Count(o.m_dxfDouble40Count), | |||
| 11629 | m_dxfBool290Count(o.m_dxfBool290Count) {} | |||
| 11630 | DRW_GeoPositionMarker& DRW_GeoPositionMarker::operator=( | |||
| 11631 | const DRW_GeoPositionMarker& o) { | |||
| 11632 | if (this != &o) { | |||
| 11633 | DRW_Entity::operator=(o); | |||
| 11634 | m_classVersion = o.m_classVersion; | |||
| 11635 | m_position = o.m_position; | |||
| 11636 | m_radius = o.m_radius; | |||
| 11637 | m_notes = o.m_notes; | |||
| 11638 | m_landingGap = o.m_landingGap; | |||
| 11639 | m_mtextVisible = o.m_mtextVisible; | |||
| 11640 | m_textAlignment = o.m_textAlignment; | |||
| 11641 | m_enableFrameText = o.m_enableFrameText; | |||
| 11642 | mtext = o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr; | |||
| 11643 | m_dxfDouble40Count = o.m_dxfDouble40Count; | |||
| 11644 | m_dxfBool290Count = o.m_dxfBool290Count; | |||
| 11645 | } | |||
| 11646 | return *this; | |||
| 11647 | } | |||
| 11648 | DRW_GeoPositionMarker::DRW_GeoPositionMarker( | |||
| 11649 | DRW_GeoPositionMarker&&) noexcept = default; | |||
| 11650 | DRW_GeoPositionMarker& DRW_GeoPositionMarker::operator=( | |||
| 11651 | DRW_GeoPositionMarker&&) noexcept = default; | |||
| 11652 | ||||
| 11653 | namespace { | |||
| 11654 | static bool parseEmbeddedMTextEntityMode(DRW::Version version, dwgBuffer *buf, | |||
| 11655 | std::uint64_t bodyEndBit, | |||
| 11656 | EmbeddedMTextHandleInfo& info, | |||
| 11657 | DRW_MText& mtext) { | |||
| 11658 | std::uint8_t entmode = 0; | |||
| 11659 | if (!readBounded2Bits(*buf, bodyEndBit, entmode)) | |||
| 11660 | return false; | |||
| 11661 | info.m_ownerHandle = entmode == 0; | |||
| 11662 | if (!readBoundedBitLong(*buf, bodyEndBit, info.m_numReactors) | |||
| 11663 | || !dwgSafety::validReactorCount(info.m_numReactors)) | |||
| 11664 | return false; | |||
| 11665 | if (version > DRW::AC1015) { | |||
| 11666 | bool xDictFlag = false; | |||
| 11667 | if (!readBoundedBit(*buf, bodyEndBit, xDictFlag)) | |||
| 11668 | return false; | |||
| 11669 | info.m_xDictFlag = xDictFlag ? 1 : 0; | |||
| 11670 | } | |||
| 11671 | if (version > DRW::AC1024) { | |||
| 11672 | bool hasDataStorage = false; | |||
| 11673 | if (!readBoundedBit(*buf, bodyEndBit, hasDataStorage)) | |||
| 11674 | return false; | |||
| 11675 | mtext.setHasDataStorageBinaryData(hasDataStorage); | |||
| 11676 | } else if (version < DRW::AC1018) { | |||
| 11677 | bool noLinks = false; | |||
| 11678 | if (!readBoundedBit(*buf, bodyEndBit, noLinks)) | |||
| 11679 | return false; // nolinks / have-next-links | |||
| 11680 | } | |||
| 11681 | std::uint32_t color = 0; | |||
| 11682 | if (!readBoundedEnColor(*buf, bodyEndBit, version, color)) | |||
| 11683 | return false; | |||
| 11684 | mtext.color = static_cast<int>(color); | |||
| 11685 | info.m_hasAcDbColorHandle = buf->lastEnColorHadDbColorRef; | |||
| 11686 | mtext.color24 = buf->lastEnColorRgb; | |||
| 11687 | if (!buf->lastEnColorName.empty()) { | |||
| 11688 | mtext.colorName = buf->lastEnColorBookName.empty() | |||
| 11689 | ? buf->lastEnColorName | |||
| 11690 | : (buf->lastEnColorBookName + "$" + buf->lastEnColorName); | |||
| 11691 | } | |||
| 11692 | if (buf->lastEnColorAlphaRaw != 0) | |||
| 11693 | mtext.transparency = static_cast<int>(buf->lastEnColorAlphaRaw); | |||
| 11694 | if (!readBoundedBitDouble(*buf, bodyEndBit, mtext.ltypeScale)) | |||
| 11695 | return false; | |||
| 11696 | if (version > DRW::AC1014) { | |||
| 11697 | std::uint8_t ltFlags = 0; | |||
| 11698 | std::uint8_t plotFlags = 0; | |||
| 11699 | if (!readBounded2Bits(*buf, bodyEndBit, ltFlags) | |||
| 11700 | || !readBounded2Bits(*buf, bodyEndBit, plotFlags)) | |||
| 11701 | return false; | |||
| 11702 | info.m_ltFlags = ltFlags; | |||
| 11703 | info.m_plotFlags = plotFlags; | |||
| 11704 | switch (info.m_ltFlags) { | |||
| 11705 | case 0: | |||
| 11706 | mtext.lineType = "BYLAYER"; | |||
| 11707 | break; | |||
| 11708 | case 1: | |||
| 11709 | mtext.lineType = "BYBLOCK"; | |||
| 11710 | break; | |||
| 11711 | case 2: | |||
| 11712 | mtext.lineType = "CONTINUOUS"; | |||
| 11713 | break; | |||
| 11714 | default: | |||
| 11715 | mtext.lineType.clear(); | |||
| 11716 | break; | |||
| 11717 | } | |||
| 11718 | } | |||
| 11719 | if (version > DRW::AC1018) { | |||
| 11720 | std::uint8_t materialFlag = 0; | |||
| 11721 | std::uint8_t shadowFlag = 0; | |||
| 11722 | if (!readBounded2Bits(*buf, bodyEndBit, materialFlag) | |||
| 11723 | || !readBoundedRawChar8(*buf, bodyEndBit, shadowFlag)) | |||
| 11724 | return false; | |||
| 11725 | info.m_materialFlag = materialFlag; | |||
| 11726 | info.m_shadowFlag = shadowFlag; | |||
| 11727 | mtext.shadow = static_cast<DRW::ShadowMode>(info.m_shadowFlag & 0x3); | |||
| 11728 | } | |||
| 11729 | if (version > DRW::AC1021) { | |||
| 11730 | if (!readBoundedBit(*buf, bodyEndBit, info.m_hasFullVisualStyle) | |||
| 11731 | || !readBoundedBit(*buf, bodyEndBit, info.m_hasFaceVisualStyle) | |||
| 11732 | || !readBoundedBit(*buf, bodyEndBit, info.m_hasEdgeVisualStyle)) | |||
| 11733 | return false; | |||
| 11734 | } | |||
| 11735 | std::uint16_t invisibleFlag = 0; | |||
| 11736 | if (!readBoundedBitShort(*buf, bodyEndBit, invisibleFlag)) | |||
| 11737 | return false; | |||
| 11738 | mtext.visible = (invisibleFlag & 1) == 0; | |||
| 11739 | if (version > DRW::AC1014) { | |||
| 11740 | std::uint8_t lineWeight = 0; | |||
| 11741 | if (!readBoundedRawChar8(*buf, bodyEndBit, lineWeight)) | |||
| 11742 | return false; | |||
| 11743 | mtext.lWeight = DRW_LW_Conv::dwgInt2lineWidth(lineWeight); | |||
| 11744 | } | |||
| 11745 | return buf->isGood() && currentDwgBit(buf) <= bodyEndBit; | |||
| 11746 | } | |||
| 11747 | ||||
| 11748 | static bool parseEmbeddedMTextDwgFields( | |||
| 11749 | DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, | |||
| 11750 | DRW_MText& mtext, EmbeddedMTextHandleInfo& info, EmbeddedMTextForm form, | |||
| 11751 | std::uint64_t bodyEndBit, std::uint64_t stringEndBit) { | |||
| 11752 | if (!parseEmbeddedMTextEntityMode(version, buf, bodyEndBit, info, mtext)) | |||
| 11753 | return false; | |||
| 11754 | ||||
| 11755 | if (!readBoundedBitCoord(*buf, bodyEndBit, mtext.basePoint) | |||
| 11756 | || !readBoundedBitCoord(*buf, bodyEndBit, mtext.extPoint) | |||
| 11757 | || !readBoundedBitCoord(*buf, bodyEndBit, mtext.secPoint)) | |||
| 11758 | return false; | |||
| 11759 | mtext.angle = atan2(mtext.secPoint.y, mtext.secPoint.x) * ARAD57.29577951308232; | |||
| 11760 | if (!readBoundedBitDouble(*buf, bodyEndBit, mtext.widthscale)) | |||
| 11761 | return false; | |||
| 11762 | // The writer puts these three back where they came from, so keep them: | |||
| 11763 | // an annotative MTEXT has no R2018 block to repeat them in. | |||
| 11764 | if (version > DRW::AC1018 | |||
| 11765 | && !readBoundedBitDouble(*buf, bodyEndBit, mtext.m_r2018RectHeight)) | |||
| 11766 | return false; | |||
| 11767 | if (!readBoundedBitDouble(*buf, bodyEndBit, mtext.height)) | |||
| 11768 | return false; | |||
| 11769 | std::uint16_t textgen = 0; | |||
| 11770 | std::uint16_t alignH = 0; | |||
| 11771 | if (!readBoundedBitShort(*buf, bodyEndBit, textgen) | |||
| 11772 | || !readBoundedBitShort(*buf, bodyEndBit, alignH) | |||
| 11773 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 11774 | mtext.m_r2018ExtentsHeight) | |||
| 11775 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 11776 | mtext.m_r2018ExtentsWidth)) | |||
| 11777 | return false; | |||
| 11778 | mtext.textgen = textgen; | |||
| 11779 | mtext.alignH = static_cast<DRW_Text::HAlign>(alignH); | |||
| 11780 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, mtext.text)) | |||
| 11781 | return false; | |||
| 11782 | ||||
| 11783 | if (version > DRW::AC1014) { | |||
| 11784 | bool ignoredLineSpacingUnknown = false; | |||
| 11785 | if (!readBoundedBitShort(*buf, bodyEndBit, | |||
| 11786 | mtext.linespacingStyle) | |||
| 11787 | || !readBoundedBitDouble(*buf, bodyEndBit, mtext.interlin) | |||
| 11788 | || !readBoundedBit(*buf, bodyEndBit, | |||
| 11789 | ignoredLineSpacingUnknown)) | |||
| 11790 | return false; | |||
| 11791 | mtext.alignV = static_cast<DRW_Text::VAlign>(mtext.linespacingStyle); | |||
| 11792 | } | |||
| 11793 | if (version > DRW::AC1015) { | |||
| 11794 | if (!readBoundedBitLong(*buf, bodyEndBit, mtext.m_backgroundFlags)) | |||
| 11795 | return false; | |||
| 11796 | if ((mtext.m_backgroundFlags & 0x01) | |||
| 11797 | || (version >= DRW::AC1032 && (mtext.m_backgroundFlags & 0x10))) { | |||
| 11798 | std::uint32_t backgroundColor = 0; | |||
| 11799 | if (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 11800 | mtext.m_backgroundScale) | |||
| 11801 | || !readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 11802 | backgroundColor, nullptr, nullptr, | |||
| 11803 | nullptr, nullptr, stringEndBit) | |||
| 11804 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 11805 | mtext.m_backgroundTransparency)) | |||
| 11806 | return false; | |||
| 11807 | mtext.m_backgroundColor = static_cast<int>(backgroundColor); | |||
| 11808 | } | |||
| 11809 | } | |||
| 11810 | ||||
| 11811 | if (version >= DRW::AC1032) { | |||
| 11812 | mtext.m_r2018ColumnHeights.clear(); | |||
| 11813 | if (!readBoundedBit(*buf, bodyEndBit, | |||
| 11814 | mtext.m_r2018IsNotAnnotative)) | |||
| 11815 | return false; | |||
| 11816 | info.m_hasR2018AppIdHandle = mtext.m_r2018IsNotAnnotative; | |||
| 11817 | if (form == EmbeddedMTextForm::Short) { | |||
| 11818 | if (!readBoundedBit(*buf, bodyEndBit, | |||
| 11819 | mtext.m_r2018ReallyLocked)) | |||
| 11820 | return false; | |||
| 11821 | } else if (mtext.m_r2018IsNotAnnotative) { | |||
| 11822 | // Where the block repeats a field read above, that one stays. | |||
| 11823 | DwgMTextR2018Block block; | |||
| 11824 | if (!readBoundedDwgMTextR2018Block(*buf, bodyEndBit, block)) | |||
| 11825 | return false; | |||
| 11826 | block.m_rectHeight = mtext.m_r2018RectHeight; | |||
| 11827 | block.m_extentsWidth = mtext.m_r2018ExtentsWidth; | |||
| 11828 | block.m_extentsHeight = mtext.m_r2018ExtentsHeight; | |||
| 11829 | storeDwgMTextR2018Block(std::move(block), mtext); | |||
| 11830 | } | |||
| 11831 | } | |||
| 11832 | ||||
| 11833 | std::uint16_t annotativeSize = 0; | |||
| 11834 | if (!readBoundedBitShort(*buf, bodyEndBit, annotativeSize)) | |||
| 11835 | return false; | |||
| 11836 | if (annotativeSize > 0) { | |||
| 11837 | std::vector<std::uint8_t> annotativeData; | |||
| 11838 | if (!DRW::reserve(annotativeData, annotativeSize)) | |||
| 11839 | return false; | |||
| 11840 | for (std::uint16_t i = 0; i < annotativeSize; ++i) { | |||
| 11841 | std::uint8_t value = 0; | |||
| 11842 | if (!readBoundedRawChar8(*buf, bodyEndBit, value)) | |||
| 11843 | return false; | |||
| 11844 | annotativeData.push_back(value); | |||
| 11845 | } | |||
| 11846 | mtext.m_r2018AnnotativeData = std::move(annotativeData); | |||
| 11847 | info.m_hasAnnotativeAppHandle = true; | |||
| 11848 | if (!readBoundedBitShort(*buf, bodyEndBit, | |||
| 11849 | mtext.m_r2018AnnotativeUnknown)) | |||
| 11850 | return false; | |||
| 11851 | } | |||
| 11852 | return buf->isGood() && sBuf->isGood() | |||
| 11853 | && currentDwgBit(buf) <= bodyEndBit | |||
| 11854 | && currentDwgBit(sBuf) <= stringEndBit; | |||
| 11855 | } | |||
| 11856 | ||||
| 11857 | static bool parseEmbeddedMTextDwg( | |||
| 11858 | DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, | |||
| 11859 | DRW_MText& mtext, EmbeddedMTextHandleInfo& info, EmbeddedMTextForm form, | |||
| 11860 | std::uint64_t bodyEndBit, std::uint64_t stringEndBit) { | |||
| 11861 | if (buf == nullptr || sBuf == nullptr || !buf->isGood() | |||
| 11862 | || !sBuf->isGood()) | |||
| 11863 | return false; | |||
| 11864 | ||||
| 11865 | const std::uint64_t bodyStartBit = currentDwgBit(buf); | |||
| 11866 | const std::uint64_t stringStartBit = currentDwgBit(sBuf); | |||
| 11867 | const auto totalBits = [](const dwgBuffer& buffer) { | |||
| 11868 | std::uint64_t bits = 0; | |||
| 11869 | return dwgSafety::multiply(buffer.size(), 8, bits) ? bits : 0; | |||
| 11870 | }; | |||
| 11871 | if (bodyEndBit == std::numeric_limits<std::uint64_t>::max()) | |||
| 11872 | bodyEndBit = totalBits(*buf); | |||
| 11873 | if (stringEndBit == std::numeric_limits<std::uint64_t>::max()) | |||
| 11874 | stringEndBit = totalBits(*sBuf); | |||
| 11875 | if (bodyStartBit > bodyEndBit || stringStartBit > stringEndBit) | |||
| 11876 | return false; | |||
| 11877 | ||||
| 11878 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 11879 | std::unique_ptr<dwgBuffer> separateStringProbe; | |||
| 11880 | dwgBuffer *stringProbe = &bodyProbe; | |||
| 11881 | if (sBuf != buf) { | |||
| 11882 | separateStringProbe = std::make_unique<dwgBuffer>( | |||
| 11883 | sBuf->forkIndependent()); | |||
| 11884 | stringProbe = separateStringProbe.get(); | |||
| 11885 | } | |||
| 11886 | if (!parseEmbeddedMTextDwgFields(version, &bodyProbe, stringProbe, | |||
| 11887 | mtext, info, form, bodyEndBit, | |||
| 11888 | stringEndBit)) | |||
| 11889 | return false; | |||
| 11890 | ||||
| 11891 | const std::uint64_t bodyConsumed = currentDwgBit(&bodyProbe); | |||
| 11892 | const std::uint64_t stringConsumed = currentDwgBit(stringProbe); | |||
| 11893 | if (bodyConsumed < bodyStartBit || stringConsumed < stringStartBit | |||
| 11894 | || bodyConsumed > bodyEndBit || stringConsumed > stringEndBit) | |||
| 11895 | return false; | |||
| 11896 | ||||
| 11897 | const auto seekBits = [](dwgBuffer& buffer, std::uint64_t bit) { | |||
| 11898 | if (!buffer.setPosition(bit >> 3)) | |||
| 11899 | return false; | |||
| 11900 | buffer.setBitPos(static_cast<std::uint8_t>(bit & 7u)); | |||
| 11901 | return buffer.isGood() && currentDwgBit(&buffer) == bit; | |||
| 11902 | }; | |||
| 11903 | if (!seekBits(*buf, bodyConsumed)) | |||
| 11904 | return false; | |||
| 11905 | if (sBuf != buf && !seekBits(*sBuf, stringConsumed)) | |||
| 11906 | return false; | |||
| 11907 | return true; | |||
| 11908 | } | |||
| 11909 | ||||
| 11910 | static bool consumeEmbeddedMTextHandles( | |||
| 11911 | DRW::Version version, dwgBuffer *buf, | |||
| 11912 | const EmbeddedMTextHandleInfo& info, DRW_MText *mtext, | |||
| 11913 | std::uint64_t handleEndBit) { | |||
| 11914 | if (buf == nullptr || !buf->isGood()) | |||
| 11915 | return false; | |||
| 11916 | ||||
| 11917 | if (handleEndBit == std::numeric_limits<std::uint64_t>::max()) { | |||
| 11918 | if (!dwgSafety::multiply(buf->size(), 8, handleEndBit)) | |||
| 11919 | return false; | |||
| 11920 | } | |||
| 11921 | dwgBuffer probe = buf->forkIndependent(); | |||
| 11922 | auto readHandle = [&](bool offset, dwgHandle& value) { | |||
| 11923 | return readBoundedDwgHandle(probe, handleEndBit, 0, offset, value); | |||
| 11924 | }; | |||
| 11925 | ||||
| 11926 | dwgHandle owner; | |||
| 11927 | if (info.m_ownerHandle && !readHandle(false, owner)) | |||
| 11928 | return false; | |||
| 11929 | ||||
| 11930 | std::vector<std::uint32_t> reactors; | |||
| 11931 | if (info.m_numReactors < 0 | |||
| 11932 | || !dwgSafety::validReactorCount(info.m_numReactors)) | |||
| 11933 | return false; | |||
| 11934 | if (!DRW::reserve(reactors, info.m_numReactors)) | |||
| 11935 | return false; | |||
| 11936 | for (int i = 0; i < info.m_numReactors; ++i) { | |||
| 11937 | dwgHandle reactor; | |||
| 11938 | if (!readHandle(false, reactor)) | |||
| 11939 | return false; | |||
| 11940 | if (reactor.ref != 0) | |||
| 11941 | reactors.push_back(reactor.ref); | |||
| 11942 | } | |||
| 11943 | ||||
| 11944 | dwgHandle xDict; | |||
| 11945 | const bool hasXDict = version <= DRW::AC1015 || info.m_xDictFlag != 1; | |||
| 11946 | if (hasXDict && !readHandle(false, xDict)) | |||
| 11947 | return false; | |||
| 11948 | ||||
| 11949 | dwgHandle color; | |||
| 11950 | if (info.m_hasAcDbColorHandle && !readHandle(false, color)) | |||
| 11951 | return false; | |||
| 11952 | ||||
| 11953 | dwgHandle layer; | |||
| 11954 | const bool hasLayer = version > DRW::AC1014; | |||
| 11955 | if (hasLayer && !readHandle(false, layer)) | |||
| 11956 | return false; | |||
| 11957 | ||||
| 11958 | dwgHandle lineType; | |||
| 11959 | const bool hasLineType = version > DRW::AC1014 && info.m_ltFlags == 3; | |||
| 11960 | if (hasLineType && !readHandle(false, lineType)) | |||
| 11961 | return false; | |||
| 11962 | ||||
| 11963 | dwgHandle material; | |||
| 11964 | const bool hasMaterial = version > DRW::AC1018 && info.m_materialFlag == 3; | |||
| 11965 | if (hasMaterial && !readHandle(false, material)) | |||
| 11966 | return false; | |||
| 11967 | ||||
| 11968 | dwgHandle shadow; | |||
| 11969 | const bool hasShadow = version > DRW::AC1018 && info.m_shadowFlag == 3; | |||
| 11970 | if (hasShadow && !readHandle(false, shadow)) | |||
| 11971 | return false; | |||
| 11972 | ||||
| 11973 | dwgHandle plotStyle; | |||
| 11974 | const bool hasPlotStyle = info.m_plotFlags == 3; | |||
| 11975 | if (hasPlotStyle && !readHandle(false, plotStyle)) | |||
| 11976 | return false; | |||
| 11977 | ||||
| 11978 | dwgHandle fullVisualStyle; | |||
| 11979 | const bool hasFullVisualStyle = version > DRW::AC1021 | |||
| 11980 | && info.m_hasFullVisualStyle; | |||
| 11981 | if (hasFullVisualStyle && !readHandle(false, fullVisualStyle)) | |||
| 11982 | return false; | |||
| 11983 | ||||
| 11984 | dwgHandle faceVisualStyle; | |||
| 11985 | const bool hasFaceVisualStyle = version > DRW::AC1021 | |||
| 11986 | && info.m_hasFaceVisualStyle; | |||
| 11987 | if (hasFaceVisualStyle && !readHandle(false, faceVisualStyle)) | |||
| 11988 | return false; | |||
| 11989 | ||||
| 11990 | dwgHandle edgeVisualStyle; | |||
| 11991 | const bool hasEdgeVisualStyle = version > DRW::AC1021 | |||
| 11992 | && info.m_hasEdgeVisualStyle; | |||
| 11993 | if (hasEdgeVisualStyle && !readHandle(false, edgeVisualStyle)) | |||
| 11994 | return false; | |||
| 11995 | ||||
| 11996 | dwgHandle style; | |||
| 11997 | if (info.m_hasStyleHandle && !readHandle(false, style)) | |||
| 11998 | return false; | |||
| 11999 | ||||
| 12000 | dwgHandle appId; | |||
| 12001 | if (info.m_hasR2018AppIdHandle && !readHandle(false, appId)) | |||
| 12002 | return false; | |||
| 12003 | ||||
| 12004 | dwgHandle annotativeApp; | |||
| 12005 | if (info.m_hasAnnotativeAppHandle && !readHandle(false, annotativeApp)) | |||
| 12006 | return false; | |||
| 12007 | ||||
| 12008 | if (mtext != nullptr) { | |||
| 12009 | if (info.m_ownerHandle) | |||
| 12010 | mtext->parentHandle = owner.ref; | |||
| 12011 | mtext->reactorHandles = std::move(reactors); | |||
| 12012 | if (hasXDict) | |||
| 12013 | mtext->xDictHandle = xDict.ref; | |||
| 12014 | if (info.m_hasAcDbColorHandle) | |||
| 12015 | mtext->setDwgAcDbColorHandle(true, color.ref); | |||
| 12016 | if (hasLayer) | |||
| 12017 | mtext->setDwgLayerHandle(layer.ref); | |||
| 12018 | if (hasLineType) | |||
| 12019 | mtext->setDwgLinetypeHandle(lineType.ref); | |||
| 12020 | if (hasMaterial) | |||
| 12021 | mtext->material = material.ref; | |||
| 12022 | if (hasShadow) | |||
| 12023 | mtext->shadowHandle = shadow.ref; | |||
| 12024 | if (hasPlotStyle) | |||
| 12025 | mtext->plotStyle = static_cast<int>(plotStyle.ref); | |||
| 12026 | if (hasFullVisualStyle) | |||
| 12027 | mtext->fullVisualStyleHandle = fullVisualStyle.ref; | |||
| 12028 | if (hasFaceVisualStyle) | |||
| 12029 | mtext->faceVisualStyleHandle = faceVisualStyle.ref; | |||
| 12030 | if (hasEdgeVisualStyle) | |||
| 12031 | mtext->edgeVisualStyleHandle = edgeVisualStyle.ref; | |||
| 12032 | if (info.m_hasStyleHandle) | |||
| 12033 | mtext->styleH = style; | |||
| 12034 | if (info.m_hasR2018AppIdHandle) | |||
| 12035 | mtext->m_r2018AppIdHandle = appId.ref; | |||
| 12036 | if (info.m_hasAnnotativeAppHandle) | |||
| 12037 | mtext->m_r2018AnnotativeAppHandle = annotativeApp.ref; | |||
| 12038 | } | |||
| 12039 | *buf = probe; | |||
| 12040 | return true; | |||
| 12041 | } | |||
| 12042 | ||||
| 12043 | static bool encodeEmbeddedMTextEntityMode(DRW::Version version, dwgBufferW *buf, | |||
| 12044 | const DRW_MText& mtext, | |||
| 12045 | bool hasOwnerHandle) { | |||
| 12046 | if (version < DRW::AC1032) | |||
| 12047 | return false; | |||
| 12048 | ||||
| 12049 | // Embedded MTEXT begins at AcDbEntity mode, not with an object type, | |||
| 12050 | // object size, own handle, EED, or graphics data. | |||
| 12051 | if (mtext.reactorHandles.size() | |||
| 12052 | > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) | |||
| 12053 | return false; | |||
| 12054 | buf->put2Bits(hasOwnerHandle ? 0 : 2); | |||
| 12055 | buf->putBitLong(static_cast<std::int32_t>(mtext.reactorHandles.size())); | |||
| 12056 | buf->putBit(mtext.xDictHandle == 0 ? 1 : 0); | |||
| 12057 | buf->putBit(mtext.hasDataStorageBinaryData() ? 1 : 0); | |||
| 12058 | UTF8STRINGstd::string colorName = mtext.colorName; | |||
| 12059 | UTF8STRINGstd::string bookName; | |||
| 12060 | const std::string::size_type separator = colorName.find('$'); | |||
| 12061 | if (separator != std::string::npos) { | |||
| 12062 | bookName = colorName.substr(0, separator); | |||
| 12063 | colorName.erase(0, separator + 1); | |||
| 12064 | } | |||
| 12065 | buf->putEnColor(version, static_cast<std::uint16_t>(mtext.color), | |||
| 12066 | mtext.color24, colorName, bookName, | |||
| 12067 | static_cast<std::uint32_t>(mtext.transparency), | |||
| 12068 | mtext.hasDwgAcDbColorHandle()); | |||
| 12069 | buf->putBitDouble(mtext.ltypeScale); | |||
| 12070 | std::uint8_t ltFlags = 0; | |||
| 12071 | if (mtext.dwgLinetypeHandle() != 0 || mtext.lineType.empty()) | |||
| 12072 | ltFlags = 3; | |||
| 12073 | else if (mtext.lineType == "BYBLOCK") | |||
| 12074 | ltFlags = 1; | |||
| 12075 | else if (mtext.lineType == "CONTINUOUS") | |||
| 12076 | ltFlags = 2; | |||
| 12077 | buf->put2Bits(ltFlags); | |||
| 12078 | buf->put2Bits(mtext.plotStyle == DRW::DefaultPlotStyle ? 0 : 3); | |||
| 12079 | buf->put2Bits(mtext.material == DRW::MaterialByLayer ? 0 : 3); | |||
| 12080 | buf->putRawChar8(static_cast<std::uint8_t>(mtext.shadow)); | |||
| 12081 | buf->putBit(mtext.fullVisualStyleHandle != 0); | |||
| 12082 | buf->putBit(mtext.faceVisualStyleHandle != 0); | |||
| 12083 | buf->putBit(mtext.edgeVisualStyleHandle != 0); | |||
| 12084 | buf->putBitShort(mtext.visible ? 0 : 1); | |||
| 12085 | buf->putRawChar8(static_cast<std::uint8_t>(mtext.lWeight)); | |||
| 12086 | return true; | |||
| 12087 | } | |||
| 12088 | ||||
| 12089 | // parentLayer and parentStyle are the handles the owning ATTRIB / ATTDEF | |||
| 12090 | // writes for itself; the embedded MTEXT falls back to them, and from there to | |||
| 12091 | // the writer's layer "0" and text style Standard. | |||
| 12092 | static bool encodeEmbeddedMTextDwg(DRW::Version version, dwgBufferW *buf, | |||
| 12093 | dwgBufferW *strBuf, dwgBufferW *handleBuf, | |||
| 12094 | const DRW_MText& mtext, | |||
| 12095 | EmbeddedMTextForm form, | |||
| 12096 | std::uint32_t parentLayer = 0, | |||
| 12097 | std::uint32_t parentStyle = 0) { | |||
| 12098 | // AutoCAD always stores an owner handle here, null when there is none. | |||
| 12099 | const bool hasOwnerHandle = form == EmbeddedMTextForm::Full | |||
| 12100 | || mtext.parentHandle != DRW::NoHandle; | |||
| 12101 | if (!encodeEmbeddedMTextEntityMode(version, buf, mtext, hasOwnerHandle)) | |||
| 12102 | return false; | |||
| 12103 | ||||
| 12104 | buf->put3BitDouble(mtext.basePoint); | |||
| 12105 | buf->put3BitDouble(mtext.extPoint); | |||
| 12106 | buf->put3BitDouble(mtext.secPoint); | |||
| 12107 | buf->putBitDouble(mtext.widthscale); | |||
| 12108 | buf->putBitDouble(mtext.m_r2018RectHeight); | |||
| 12109 | buf->putBitDouble(mtext.height); | |||
| 12110 | buf->putBitShort(static_cast<std::uint16_t>(mtext.textgen)); | |||
| 12111 | buf->putBitShort(static_cast<std::uint16_t>(mtext.alignH)); | |||
| 12112 | buf->putBitDouble(mtext.m_r2018ExtentsHeight); | |||
| 12113 | buf->putBitDouble(mtext.m_r2018ExtentsWidth); | |||
| 12114 | (strBuf ? strBuf : buf)->putVariableText(version, mtext.text); | |||
| 12115 | ||||
| 12116 | buf->putBitShort(mtext.linespacingStyle); | |||
| 12117 | buf->putBitDouble(mtext.interlin); | |||
| 12118 | buf->putBit(0); | |||
| 12119 | buf->putBitLong(mtext.m_backgroundFlags); | |||
| 12120 | if ((mtext.m_backgroundFlags & 0x01) | |||
| 12121 | || (mtext.m_backgroundFlags & 0x10)) { | |||
| 12122 | buf->putBitDouble(mtext.m_backgroundScale); // BitDouble, not BitLong | |||
| 12123 | buf->putCmColor(version, static_cast<std::uint16_t>(mtext.m_backgroundColor)); | |||
| 12124 | buf->putBitLong(mtext.m_backgroundTransparency); | |||
| 12125 | } | |||
| 12126 | ||||
| 12127 | buf->putBit(mtext.m_r2018IsNotAnnotative ? 1 : 0); | |||
| 12128 | if (form == EmbeddedMTextForm::Short) { | |||
| 12129 | buf->putBit(mtext.m_r2018ReallyLocked ? 1 : 0); | |||
| 12130 | } else if (mtext.m_r2018IsNotAnnotative) { | |||
| 12131 | // The block repeats fields written above. Take them from there, so an | |||
| 12132 | // MTEXT that never had the block, or was edited since it was read, | |||
| 12133 | // still gets a consistent one. | |||
| 12134 | DwgMTextR2018Block block = dwgMTextR2018BlockOf(mtext); | |||
| 12135 | block.m_attachment = mtext.textgen; | |||
| 12136 | block.m_xAxisDir = mtext.secPoint; | |||
| 12137 | block.m_insertionPoint = mtext.basePoint; | |||
| 12138 | block.m_rectWidth = mtext.widthscale; | |||
| 12139 | if (!putDwgMTextR2018Block(buf, block)) | |||
| 12140 | return false; | |||
| 12141 | } | |||
| 12142 | ||||
| 12143 | if (mtext.m_r2018AnnotativeData.size() > std::numeric_limits<std::uint16_t>::max()) | |||
| 12144 | return false; | |||
| 12145 | buf->putBitShort(static_cast<std::uint16_t>(mtext.m_r2018AnnotativeData.size())); | |||
| 12146 | for (std::uint8_t byte : mtext.m_r2018AnnotativeData) | |||
| 12147 | buf->putRawChar8(byte); | |||
| 12148 | if (!mtext.m_r2018AnnotativeData.empty()) { | |||
| 12149 | buf->putBitShort(mtext.m_r2018AnnotativeUnknown); | |||
| 12150 | } | |||
| 12151 | ||||
| 12152 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 12153 | if (form == EmbeddedMTextForm::Full) | |||
| 12154 | putDwgReference(hb, DRW::DwgSoftPointer, mtext.parentHandle); | |||
| 12155 | else if (hasOwnerHandle) | |||
| 12156 | putHardPointerHandle(hb, mtext.parentHandle); | |||
| 12157 | for (const std::uint32_t reactor : mtext.reactorHandles) | |||
| 12158 | putHardPointerHandle(hb, reactor); | |||
| 12159 | if (mtext.xDictHandle != 0) | |||
| 12160 | putHardPointerHandle(hb, mtext.xDictHandle); | |||
| 12161 | if (mtext.hasDwgAcDbColorHandle()) | |||
| 12162 | putHardPointerHandle(hb, mtext.dwgAcDbColorHandle()); | |||
| 12163 | if (parentLayer == 0) | |||
| 12164 | parentLayer = 0x12; | |||
| 12165 | putHardPointerHandle(hb, mtext.dwgLayerHandle() == 0 | |||
| 12166 | ? parentLayer : mtext.dwgLayerHandle()); | |||
| 12167 | if (mtext.dwgLinetypeHandle() != 0 || mtext.lineType.empty()) | |||
| 12168 | putHardPointerHandle(hb, mtext.dwgLinetypeHandle()); | |||
| 12169 | if (mtext.material != DRW::MaterialByLayer) | |||
| 12170 | putHardPointerHandle(hb, mtext.material); | |||
| 12171 | if (mtext.shadow == DRW::IgnoreShadows) | |||
| 12172 | putHardPointerHandle(hb, mtext.shadowHandle); | |||
| 12173 | if (mtext.plotStyle != DRW::DefaultPlotStyle) | |||
| 12174 | putHardPointerHandle(hb, static_cast<std::uint32_t>(mtext.plotStyle)); | |||
| 12175 | if (mtext.fullVisualStyleHandle != 0) | |||
| 12176 | putHardPointerHandle(hb, mtext.fullVisualStyleHandle); | |||
| 12177 | if (mtext.faceVisualStyleHandle != 0) | |||
| 12178 | putHardPointerHandle(hb, mtext.faceVisualStyleHandle); | |||
| 12179 | if (mtext.edgeVisualStyleHandle != 0) | |||
| 12180 | putHardPointerHandle(hb, mtext.edgeVisualStyleHandle); | |||
| 12181 | if (parentStyle == 0) | |||
| 12182 | parentStyle = 0x13; | |||
| 12183 | putHardPointerHandle(hb, (mtext.styleH.ref == 0) ? parentStyle | |||
| 12184 | : mtext.styleH.ref); | |||
| 12185 | if (mtext.m_r2018IsNotAnnotative) { | |||
| 12186 | // AutoCAD leaves the registered application of an attribute's MTEXT | |||
| 12187 | // null. | |||
| 12188 | const bool defaultsToAcad = mtext.m_r2018AppIdHandle == 0 | |||
| 12189 | && form == EmbeddedMTextForm::Short; | |||
| 12190 | putHardPointerHandle(hb, defaultsToAcad ? 0x14 | |||
| 12191 | : mtext.m_r2018AppIdHandle); | |||
| 12192 | } | |||
| 12193 | if (!mtext.m_r2018AnnotativeData.empty()) | |||
| 12194 | putHardPointerHandle(hb, (mtext.m_r2018AnnotativeAppHandle == 0) | |||
| 12195 | ? 0x14 : mtext.m_r2018AnnotativeAppHandle); | |||
| 12196 | return true; | |||
| 12197 | } | |||
| 12198 | ||||
| 12199 | // What follows the attribute type in an ATTRIB or ATTDEF. | |||
| 12200 | struct DwgAttributeTail { | |||
| 12201 | std::unique_ptr<DRW_MText> m_mtext; | |||
| 12202 | EmbeddedMTextHandleInfo m_embeddedHandles; | |||
| 12203 | EmbeddedMTextForm m_embeddedForm = EmbeddedMTextForm::Full; | |||
| 12204 | UTF8STRINGstd::string m_tag; | |||
| 12205 | std::uint16_t m_fieldLength = 0; | |||
| 12206 | std::uint8_t m_attribFlags = 0; | |||
| 12207 | bool m_lockPosition = false; | |||
| 12208 | UTF8STRINGstd::string m_prompt; | |||
| 12209 | }; | |||
| 12210 | ||||
| 12211 | // Everything an ATTRIB and an ATTDEF hold between the common entity data and | |||
| 12212 | // the handle stream. | |||
| 12213 | struct DwgAttributeBody { | |||
| 12214 | DwgTextBodyData m_text; | |||
| 12215 | std::uint8_t m_attVersion = 0; | |||
| 12216 | std::uint8_t m_attributeType = 1; | |||
| 12217 | DwgAttributeTail m_tail; | |||
| 12218 | }; | |||
| 12219 | ||||
| 12220 | bool readBoundedDwgAttributeTail( | |||
| 12221 | DRW::Version version, dwgBuffer& body, dwgBuffer& strings, | |||
| 12222 | std::uint64_t bodyEndBit, std::uint64_t stringStartBit, | |||
| 12223 | std::uint64_t stringEndBit, bool isAttdef, bool multiLine, | |||
| 12224 | EmbeddedMTextForm form, DwgAttributeTail& tail) { | |||
| 12225 | if (multiLine) { | |||
| 12226 | tail.m_mtext = std::make_unique<DRW_MText>(); | |||
| 12227 | tail.m_embeddedForm = form; | |||
| 12228 | if (!parseEmbeddedMTextDwg(version, &body, &strings, *tail.m_mtext, | |||
| 12229 | tail.m_embeddedHandles, form, bodyEndBit, | |||
| 12230 | stringEndBit)) | |||
| 12231 | return false; | |||
| 12232 | } | |||
| 12233 | ||||
| 12234 | const bool hasStrings = version <= DRW::AC1018 | |||
| 12235 | || stringStartBit < stringEndBit; | |||
| 12236 | if (hasStrings && !readBoundedVariableText(strings, stringEndBit, version, | |||
| 12237 | tail.m_tag)) | |||
| 12238 | return false; | |||
| 12239 | if (!readBoundedBitShort(body, bodyEndBit, tail.m_fieldLength) | |||
| 12240 | || !readBoundedRawChar8(body, bodyEndBit, tail.m_attribFlags)) | |||
| 12241 | return false; | |||
| 12242 | // lockPosition (DXF 280) is a bit in R2007+ DWG data. | |||
| 12243 | if (version >= DRW::AC1021 | |||
| 12244 | && !readBoundedBit(body, bodyEndBit, tail.m_lockPosition)) | |||
| 12245 | return false; | |||
| 12246 | ||||
| 12247 | if (isAttdef) { | |||
| 12248 | // An R2010+ ATTDEF repeats the version byte before its prompt. | |||
| 12249 | // LibreCAD used to leave it out, so read it only when the body has | |||
| 12250 | // room for it. | |||
| 12251 | std::uint8_t repeatedVersion = 0; | |||
| 12252 | if (version >= DRW::AC1024 && form == EmbeddedMTextForm::Full | |||
| 12253 | && bodyEndBit - currentDwgBit(&body) >= 8 | |||
| 12254 | && !readBoundedRawChar8(body, bodyEndBit, repeatedVersion)) | |||
| 12255 | return false; | |||
| 12256 | if (hasStrings && !readBoundedVariableText(strings, stringEndBit, | |||
| 12257 | version, tail.m_prompt)) | |||
| 12258 | return false; | |||
| 12259 | } | |||
| 12260 | return body.isGood() && strings.isGood() | |||
| 12261 | && currentDwgBit(&body) <= bodyEndBit; | |||
| 12262 | } | |||
| 12263 | ||||
| 12264 | bool readBoundedDwgAttributeBody( | |||
| 12265 | DRW::Version version, dwgBuffer& body, dwgBuffer& strings, | |||
| 12266 | std::uint64_t bodyEndBit, std::uint64_t stringStartBit, | |||
| 12267 | std::uint64_t stringEndBit, bool isAttdef, DwgAttributeBody& data) { | |||
| 12268 | if (!readBoundedDwgTextBody(version, body, strings, bodyEndBit, | |||
| 12269 | stringStartBit, stringEndBit, data.m_text)) | |||
| 12270 | return false; | |||
| 12271 | // R2010+ ATTRIB version follows the common TEXT data. R2018 adds the | |||
| 12272 | // attribute type immediately after it. | |||
| 12273 | if (version >= DRW::AC1024 | |||
| 12274 | && !readBoundedRawChar8(body, bodyEndBit, data.m_attVersion)) | |||
| 12275 | return false; | |||
| 12276 | if (version >= DRW::AC1032 | |||
| 12277 | && !readBoundedRawChar8(body, bodyEndBit, data.m_attributeType)) | |||
| 12278 | return false; | |||
| 12279 | ||||
| 12280 | const bool multiLine = version >= DRW::AC1032 | |||
| 12281 | && data.m_attributeType != 0 && data.m_attributeType != 1; | |||
| 12282 | if (!multiLine) | |||
| 12283 | return readBoundedDwgAttributeTail( | |||
| 12284 | version, body, strings, bodyEndBit, stringStartBit, stringEndBit, | |||
| 12285 | isAttdef, false, EmbeddedMTextForm::Full, data.m_tail); | |||
| 12286 | ||||
| 12287 | // A multi-line attribute is in AutoCAD's form unless only the form of | |||
| 12288 | // older LibreCAD files accounts for the whole body: both writers end the | |||
| 12289 | // body right before the string stream, give or take the padding to a | |||
| 12290 | // byte. The streams are separate here, the embedded MTEXT is R2018 only. | |||
| 12291 | struct Attempt { | |||
| 12292 | dwgBuffer m_body; | |||
| 12293 | dwgBuffer m_strings; | |||
| 12294 | DwgAttributeTail m_tail; | |||
| 12295 | bool m_read = false; | |||
| 12296 | bool m_fits = false; | |||
| 12297 | }; | |||
| 12298 | const auto read = [&](EmbeddedMTextForm form) { | |||
| 12299 | Attempt attempt{body.forkIndependent(), strings.forkIndependent(), | |||
| 12300 | DwgAttributeTail{}}; | |||
| 12301 | attempt.m_read = readBoundedDwgAttributeTail( | |||
| 12302 | version, attempt.m_body, attempt.m_strings, bodyEndBit, | |||
| 12303 | stringStartBit, stringEndBit, isAttdef, true, form, | |||
| 12304 | attempt.m_tail); | |||
| 12305 | attempt.m_fits = attempt.m_read | |||
| 12306 | && bodyEndBit - currentDwgBit(&attempt.m_body) < 8; | |||
| 12307 | return attempt; | |||
| 12308 | }; | |||
| 12309 | const auto accept = [&](Attempt& attempt) { | |||
| 12310 | body = attempt.m_body; | |||
| 12311 | strings = attempt.m_strings; | |||
| 12312 | data.m_tail = std::move(attempt.m_tail); | |||
| 12313 | return true; | |||
| 12314 | }; | |||
| 12315 | Attempt full = read(EmbeddedMTextForm::Full); | |||
| 12316 | if (full.m_fits) | |||
| 12317 | return accept(full); | |||
| 12318 | Attempt legacy = read(EmbeddedMTextForm::Short); | |||
| 12319 | if (legacy.m_fits) | |||
| 12320 | return accept(legacy); | |||
| 12321 | return full.m_read && accept(full); | |||
| 12322 | } | |||
| 12323 | ||||
| 12324 | // The attribute's own text style comes before what its embedded MTEXT refers | |||
| 12325 | // to; older LibreCAD files have the two the other way round. | |||
| 12326 | bool readBoundedDwgAttributeHandles( | |||
| 12327 | DRW::Version version, dwgBuffer& handles, std::uint64_t handleEndBit, | |||
| 12328 | DwgAttributeTail& tail, dwgHandle& styleH) { | |||
| 12329 | const bool embeddedFirst = tail.m_mtext != nullptr | |||
| 12330 | && tail.m_embeddedForm == EmbeddedMTextForm::Short; | |||
| 12331 | if (embeddedFirst | |||
| 12332 | && !consumeEmbeddedMTextHandles(version, &handles, | |||
| 12333 | tail.m_embeddedHandles, | |||
| 12334 | tail.m_mtext.get(), handleEndBit)) | |||
| 12335 | return false; | |||
| 12336 | if (!readBoundedDwgHandle(handles, handleEndBit, 0, false, styleH)) | |||
| 12337 | return false; | |||
| 12338 | if (tail.m_mtext != nullptr && !embeddedFirst | |||
| 12339 | && !consumeEmbeddedMTextHandles(version, &handles, | |||
| 12340 | tail.m_embeddedHandles, | |||
| 12341 | tail.m_mtext.get(), handleEndBit)) | |||
| 12342 | return false; | |||
| 12343 | return handles.isGood(); | |||
| 12344 | } | |||
| 12345 | ||||
| 12346 | // Writes what readBoundedDwgAttributeBody reads, always in AutoCAD's form. | |||
| 12347 | // prompt is null for an ATTRIB. The handles of an embedded MTEXT go to | |||
| 12348 | // embeddedHandles, for the caller to append after the text style handle. | |||
| 12349 | bool putDwgAttributeBody(DRW::Version version, dwgBufferW *buf, | |||
| 12350 | dwgBufferW *strBuf, const DRW_Attrib& attrib, | |||
| 12351 | const UTF8STRINGstd::string *prompt, | |||
| 12352 | dwgBufferW& embeddedHandles) { | |||
| 12353 | const std::uint8_t attributeType = | |||
| 12354 | (attrib.m_attributeType == 0) ? 1 : attrib.m_attributeType; | |||
| 12355 | const bool hasEmbeddedMText = version >= DRW::AC1032 && attributeType != 1; | |||
| 12356 | if (hasEmbeddedMText && !attrib.mtext) | |||
| 12357 | return false; | |||
| 12358 | ||||
| 12359 | // TEXT-body section. | |||
| 12360 | // data_flags=0: emit every optional field unconditionally (same | |||
| 12361 | // strategy as DRW_Text::encodeDwg — simpler encoder, ~30 bytes larger). | |||
| 12362 | buf->putRawChar8(0); // data_flags=0 | |||
| 12363 | buf->putRawDouble(attrib.basePoint.z); // elevation RD | |||
| 12364 | buf->putRawDouble(attrib.basePoint.x); // insertion 2RD | |||
| 12365 | buf->putRawDouble(attrib.basePoint.y); | |||
| 12366 | buf->putDefaultDouble(attrib.basePoint.x, attrib.secPoint.x); // alignment 2DD | |||
| 12367 | buf->putDefaultDouble(attrib.basePoint.y, attrib.secPoint.y); | |||
| 12368 | buf->putExtrusion(attrib.extPoint, /*b_R2000_style=*/true); | |||
| 12369 | buf->putThickness(attrib.thickness, /*b_R2000_style=*/true); | |||
| 12370 | buf->putRawDouble(attrib.oblique); // oblique angle RD | |||
| 12371 | buf->putRawDouble(attrib.angle / ARAD57.29577951308232); // angle in radians RD | |||
| 12372 | buf->putRawDouble(attrib.height); // text height RD | |||
| 12373 | buf->putRawDouble(attrib.widthscale); // width factor RD | |||
| 12374 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 12375 | sb->putVariableText(version, attrib.text); // text string TV | |||
| 12376 | buf->putBitShort(static_cast<std::uint16_t>(attrib.textgen)); // generation flags BS | |||
| 12377 | buf->putBitShort(static_cast<std::uint16_t>(attrib.alignH)); // horiz align BS | |||
| 12378 | buf->putBitShort(static_cast<std::uint16_t>(attrib.alignV)); // vert align BS | |||
| 12379 | ||||
| 12380 | // AutoCAD has version 0 on multi-line attributes too. | |||
| 12381 | if (version >= DRW::AC1024) | |||
| 12382 | buf->putRawChar8(attrib.attVersion); | |||
| 12383 | if (version >= DRW::AC1032) | |||
| 12384 | buf->putRawChar8(attributeType); | |||
| 12385 | ||||
| 12386 | if (hasEmbeddedMText | |||
| 12387 | && !encodeEmbeddedMTextDwg(version, buf, strBuf, &embeddedHandles, | |||
| 12388 | *attrib.mtext, EmbeddedMTextForm::Full, | |||
| 12389 | attrib.dwgLayerHandle(), | |||
| 12390 | attrib.styleH.ref)) | |||
| 12391 | return false; | |||
| 12392 | ||||
| 12393 | sb->putVariableText(version, attrib.tag); // tag TV | |||
| 12394 | buf->putBitShort(static_cast<std::uint16_t>(attrib.m_fieldLength)); // fieldLen BS | |||
| 12395 | buf->putRawChar8(attrib.attribFlags); // flags RC | |||
| 12396 | if (version >= DRW::AC1021) | |||
| 12397 | buf->putBit(attrib.lockPosition ? 1 : 0); // lock position B (R2007+) | |||
| 12398 | ||||
| 12399 | if (prompt != nullptr) { | |||
| 12400 | if (version >= DRW::AC1024) | |||
| 12401 | buf->putRawChar8(attrib.attVersion); // version RC, repeated | |||
| 12402 | sb->putVariableText(version, *prompt); // prompt TV | |||
| 12403 | } | |||
| 12404 | return true; | |||
| 12405 | } | |||
| 12406 | } | |||
| 12407 | ||||
| 12408 | bool DRW_GeoPositionMarker::encodeDwg(DRW::Version v, dwgBufferW *buf, | |||
| 12409 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 12410 | dwgBufferW *handleBuf) { | |||
| 12411 | (void)bs; | |||
| 12412 | if (v < DRW::AC1027 || buf == nullptr) | |||
| 12413 | return false; | |||
| 12414 | // The embedded AcDbMTextObjectEmbedded wire form was introduced with | |||
| 12415 | // AC1032. Reject an AC1027 framed marker rather than emitting a body that | |||
| 12416 | // a reader will interpret as the parent handle stream. | |||
| 12417 | if (m_enableFrameText && (v < DRW::AC1032 || mtext == nullptr)) | |||
| 12418 | return false; | |||
| 12419 | ||||
| 12420 | oType = kDwgType; | |||
| 12421 | if (!encodeDwgCommon(v, buf, strBuf)) | |||
| 12422 | return false; | |||
| 12423 | ||||
| 12424 | dwgBufferW *stringBuffer = strBuf ? strBuf : buf; | |||
| 12425 | buf->putBitLong(m_classVersion); | |||
| 12426 | buf->put3BitDouble(m_position); | |||
| 12427 | buf->putBitDouble(m_radius); | |||
| 12428 | stringBuffer->putVariableText(v, m_notes); | |||
| 12429 | buf->putBitDouble(m_landingGap); | |||
| 12430 | buf->putBit(m_mtextVisible ? 1 : 0); | |||
| 12431 | buf->putRawChar8(m_textAlignment); | |||
| 12432 | buf->putBit(m_enableFrameText ? 1 : 0); | |||
| 12433 | ||||
| 12434 | dwgBufferW embeddedHandles; | |||
| 12435 | if (m_enableFrameText | |||
| 12436 | && !encodeEmbeddedMTextDwg(v, buf, strBuf, &embeddedHandles, *mtext, | |||
| 12437 | EmbeddedMTextForm::Short)) | |||
| 12438 | return false; | |||
| 12439 | if (!encodeDwgEntHandle(v, buf, handleBuf)) | |||
| 12440 | return false; | |||
| 12441 | ||||
| 12442 | dwgBufferW *resolvedHandles = handleBuf ? handleBuf : buf; | |||
| 12443 | appendBitBuffer(resolvedHandles, embeddedHandles); | |||
| 12444 | return true; | |||
| 12445 | } | |||
| 12446 | ||||
| 12447 | bool DRW_Attrib::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 12448 | // Multi-line ATTRIB / ATTDEF (R2018+). AutoCAD ends the AcDbAttribute | |||
| 12449 | // groups with the attribute type (71), a flag (72) and a copy of the | |||
| 12450 | // alignment point (11/21/31), then opens the MTEXT with the marker | |||
| 12451 | // `101 / Embedded Object`. From there to the XDATA, or to the end of the | |||
| 12452 | // record, every group is the embedded object's: the AcDbMText groups | |||
| 12453 | // 10/20/30 insertion, 40 height, 41 width, 46 defined height, 71 | |||
| 12454 | // attachment, 72 direction, 3/1 text, 7 style, 210 extrusion, 11/21/31 | |||
| 12455 | // x-axis, 50 rotation, 73/44 line spacing and the background groups. | |||
| 12456 | // ezdxf and ACadSharp read the record the same way. LibreCAD wrote the | |||
| 12457 | // marker as group 100 until this was corrected; that spelling is still | |||
| 12458 | // read. | |||
| 12459 | if (code == 100 || code == 101) { | |||
| 12460 | const std::string sub = reader->getString(); | |||
| 12461 | if (sub == "Embedded Object") { | |||
| 12462 | // A further embedded object (ACadSharp appends the MTEXT column | |||
| 12463 | // data this way) is not modelled: the MTEXT skips its groups. | |||
| 12464 | if (mtext) | |||
| 12465 | return mtext->parseCode(101, reader); | |||
| 12466 | mtext = std::make_unique<DRW_MText>(); | |||
| 12467 | // Which spelling the record had; both are read the same way. | |||
| 12468 | dxfEmbeddedMarker = code == 101 ? EmbeddedDxfMarker::Canonical101 | |||
| 12469 | : EmbeddedDxfMarker::Legacy100; | |||
| 12470 | if (attVersion == 0) attVersion = 1; | |||
| 12471 | // The marker makes the attribute multi-line even in a record that | |||
| 12472 | // has no group 71; the DWG encoder drops the MTEXT of a type 1. | |||
| 12473 | if (m_attributeType <= 1) | |||
| 12474 | m_attributeType = eType == DRW::ATTDEF ? 4 : 2; | |||
| 12475 | return true; | |||
| 12476 | } | |||
| 12477 | if (code == 100) | |||
| 12478 | dxfInAttributeSubclass = sub == "AcDbAttribute" | |||
| 12479 | || sub == "AcDbAttributeDefinition"; | |||
| 12480 | return true; | |||
| 12481 | } | |||
| 12482 | if (dxfInAttributeSubclass && !mtext) { | |||
| 12483 | if (code == 71) { | |||
| 12484 | const int value = reader->getInt32(); | |||
| 12485 | if (value < 0 || value > std::numeric_limits<std::uint8_t>::max()) | |||
| 12486 | return false; | |||
| 12487 | m_attributeType = static_cast<std::uint8_t>(value); | |||
| 12488 | return true; | |||
| 12489 | } | |||
| 12490 | if (code == 72) { | |||
| 12491 | (void)reader->getInt32(); | |||
| 12492 | return true; | |||
| 12493 | } | |||
| 12494 | } | |||
| 12495 | // Past the marker everything short of XDATA goes to the embedded MTEXT, | |||
| 12496 | // group 3 (more text) included; AutoCAD, ezdxf and LibreCAD all write the | |||
| 12497 | // attribute's own groups before the marker. XDATA is the ATTRIB's. | |||
| 12498 | if (mtext && code < 1000) { | |||
| 12499 | const bool parsed = mtext->parseCode(code, reader); | |||
| 12500 | // No end-of-entity hook runs for an embedded MTEXT, so its rotation is | |||
| 12501 | // settled as the groups arrive. The last of 11/21/31 (WCS x-axis) and | |||
| 12502 | // 50 prevails, as for MTEXT, and the other is not kept: earlier | |||
| 12503 | // LibreCAD builds wrote a stale axis in front of the angle, and the | |||
| 12504 | // writer emits whichever of the two is set. | |||
| 12505 | if (!mtext->m_dxfInEmbeddedObject) { | |||
| 12506 | if (code == 11 || code == 21) | |||
| 12507 | mtext->updateAngle(); | |||
| 12508 | else if (code == 50) | |||
| 12509 | mtext->secPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 12510 | } | |||
| 12511 | return parsed; | |||
| 12512 | } | |||
| 12513 | switch (code) { | |||
| 12514 | case 2: | |||
| 12515 | tag = reader->getUtf8String(); | |||
| 12516 | break; | |||
| 12517 | case 70: | |||
| 12518 | attribFlags = reader->getInt32(); | |||
| 12519 | break; | |||
| 12520 | case 73: | |||
| 12521 | // AcDbAttribute code 73 = field length (obsolete); NOT the vertical | |||
| 12522 | // alignment from AcDbText (which is code 73 in TEXT but 74 in ATTRIB). | |||
| 12523 | m_fieldLength = reader->getInt32(); | |||
| 12524 | break; | |||
| 12525 | case 74: | |||
| 12526 | // AcDbAttribute vertical alignment (code 74); TEXT uses code 73 for | |||
| 12527 | // this but ATTRIB moves it here to free code 73 for field length. | |||
| 12528 | alignV = (VAlign)reader->getInt32(); | |||
| 12529 | break; | |||
| 12530 | case 280: | |||
| 12531 | // Lock position flag (R2010+ DXF group code) | |||
| 12532 | lockPosition = reader->getInt32() != 0; | |||
| 12533 | break; | |||
| 12534 | default: | |||
| 12535 | return DRW_Text::parseCode(code, reader); | |||
| 12536 | } | |||
| 12537 | return true; | |||
| 12538 | } | |||
| 12539 | ||||
| 12540 | void DRW_Attrib::resetAttribDwgState() { | |||
| 12541 | resetDwgState(); | |||
| 12542 | tag.clear(); | |||
| 12543 | attribFlags = 0; | |||
| 12544 | m_fieldLength = 0; | |||
| 12545 | lockPosition = false; | |||
| 12546 | attVersion = 0; | |||
| 12547 | m_attributeType = 1; | |||
| 12548 | keepDuplicateRecords = 0; | |||
| 12549 | mtext.reset(); | |||
| 12550 | dxfInAttributeSubclass = false; | |||
| 12551 | dxfEmbeddedMarker = EmbeddedDxfMarker::None; | |||
| 12552 | } | |||
| 12553 | ||||
| 12554 | bool DRW_Attrib::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 12555 | resetAttribDwgState(); | |||
| 12556 | dwgBuffer *sourceBuf = buf; | |||
| 12557 | auto fail = [this, sourceBuf]() { | |||
| 12558 | if (sourceBuf != nullptr) | |||
| 12559 | sourceBuf->invalidate(); | |||
| 12560 | resetAttribDwgState(); | |||
| 12561 | return false; | |||
| 12562 | }; | |||
| 12563 | if (sourceBuf == nullptr) | |||
| 12564 | return fail(); | |||
| 12565 | ||||
| 12566 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 12567 | buf = &bodyProbe; | |||
| 12568 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 12569 | dwgBuffer *sBuf = &bodyProbe; | |||
| 12570 | if (version > DRW::AC1018) {//2007+ | |||
| 12571 | sBuf = &sBuff; //separate buffer for strings | |||
| 12572 | } | |||
| 12573 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 12574 | if (!ret) | |||
| 12575 | return fail(); | |||
| 12576 | DRW_DBG("\n***************************** parsing attrib *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attrib *********************************************\n" ); | |||
| 12577 | ||||
| 12578 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 12579 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 12580 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 12581 | if (version > DRW::AC1018 | |||
| 12582 | && (!buf->getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 12583 | stringEndBit) | |||
| 12584 | || currentDwgBit(sBuf) > stringEndBit)) | |||
| 12585 | return fail(); | |||
| 12586 | ||||
| 12587 | DwgAttributeBody parsed; | |||
| 12588 | if (!readBoundedDwgAttributeBody(version, *buf, *sBuf, bodyEndBit, | |||
| 12589 | stringStartBit, stringEndBit, | |||
| 12590 | /*isAttdef=*/false, parsed)) { | |||
| 12591 | DRW_DBG("ATTRIB payload failed\n")DRW_dbg::dbg("ATTRIB payload failed\n"); | |||
| 12592 | return fail(); | |||
| 12593 | } | |||
| 12594 | ||||
| 12595 | /* Common Entity Handle Data */ | |||
| 12596 | // The parent ATTRIB handle stream starts at objSize; its text style and | |||
| 12597 | // the handles of an embedded MTEXT follow the common ones. | |||
| 12598 | std::uint64_t handleEndBit = 0; | |||
| 12599 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 12600 | handleEndBit)) | |||
| 12601 | return fail(); | |||
| 12602 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 12603 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 12604 | handleEndBit); | |||
| 12605 | if (!ret) | |||
| 12606 | return fail(); | |||
| 12607 | ||||
| 12608 | dwgHandle parsedStyleH; | |||
| 12609 | if (!readBoundedDwgAttributeHandles(version, handleProbe, handleEndBit, | |||
| 12610 | parsed.m_tail, parsedStyleH) | |||
| 12611 | || !sBuf->isGood() | |||
| 12612 | || currentDwgBit(buf) > bodyEndBit | |||
| 12613 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 12614 | return fail(); | |||
| 12615 | ||||
| 12616 | *sourceBuf = handleProbe; | |||
| 12617 | basePoint = parsed.m_text.basePoint; | |||
| 12618 | secPoint = parsed.m_text.secPoint; | |||
| 12619 | extPoint = parsed.m_text.extPoint; | |||
| 12620 | thickness = parsed.m_text.thickness; | |||
| 12621 | oblique = parsed.m_text.oblique; | |||
| 12622 | angle = parsed.m_text.angle; | |||
| 12623 | height = parsed.m_text.height; | |||
| 12624 | widthscale = parsed.m_text.widthscale; | |||
| 12625 | text = std::move(parsed.m_text.text); | |||
| 12626 | textgen = parsed.m_text.textgen; | |||
| 12627 | alignH = parsed.m_text.alignH; | |||
| 12628 | alignV = parsed.m_text.alignV; | |||
| 12629 | attVersion = parsed.m_attVersion; | |||
| 12630 | m_attributeType = parsed.m_attributeType; | |||
| 12631 | mtext = std::move(parsed.m_tail.m_mtext); | |||
| 12632 | tag = std::move(parsed.m_tail.m_tag); | |||
| 12633 | m_fieldLength = parsed.m_tail.m_fieldLength; | |||
| 12634 | attribFlags = parsed.m_tail.m_attribFlags; | |||
| 12635 | lockPosition = parsed.m_tail.m_lockPosition; | |||
| 12636 | styleH = parsedStyleH; | |||
| 12637 | 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"); | |||
| 12638 | return true; | |||
| 12639 | } | |||
| 12640 | ||||
| 12641 | bool DRW_Attrib::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 12642 | (void)bs; | |||
| 12643 | if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext)) | |||
| 12644 | return false; | |||
| 12645 | ||||
| 12646 | oType = 2; // ATTRIB class id — see dwgreader.cpp:1148 | |||
| 12647 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 12648 | ||||
| 12649 | dwgBufferW embeddedHandles; | |||
| 12650 | if (!putDwgAttributeBody(version, buf, strBuf, *this, /*prompt=*/nullptr, | |||
| 12651 | embeddedHandles)) | |||
| 12652 | return false; | |||
| 12653 | ||||
| 12654 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 12655 | ||||
| 12656 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 12657 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 12658 | putHardPointerHandle(hb, (styleH.ref == 0) ? 0x13 : styleH.ref); | |||
| 12659 | appendBitBuffer(hb, embeddedHandles); | |||
| 12660 | return buf->isGood() && sb->isGood() && hb->isGood(); | |||
| 12661 | } | |||
| 12662 | ||||
| 12663 | bool DRW_Attdef::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 12664 | // Group 3 is the prompt only up to the embedded-object marker; after it | |||
| 12665 | // the group carries MTEXT content. | |||
| 12666 | if (code == 3 && !mtext) { | |||
| 12667 | prompt = reader->getUtf8String(); | |||
| 12668 | return true; | |||
| 12669 | } | |||
| 12670 | return DRW_Attrib::parseCode(code, reader); | |||
| 12671 | } | |||
| 12672 | ||||
| 12673 | bool DRW_Attdef::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 12674 | // ATTDEF mirrors ATTRIB layout but adds a prompt string after the tag. | |||
| 12675 | resetAttribDwgState(); | |||
| 12676 | prompt.clear(); | |||
| 12677 | dwgBuffer *sourceBuf = buf; | |||
| 12678 | auto fail = [this, sourceBuf]() { | |||
| 12679 | if (sourceBuf != nullptr) | |||
| 12680 | sourceBuf->invalidate(); | |||
| 12681 | resetAttribDwgState(); | |||
| 12682 | prompt.clear(); | |||
| 12683 | return false; | |||
| 12684 | }; | |||
| 12685 | if (sourceBuf == nullptr) | |||
| 12686 | return fail(); | |||
| 12687 | ||||
| 12688 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 12689 | buf = &bodyProbe; | |||
| 12690 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 12691 | dwgBuffer *sBuf = &bodyProbe; | |||
| 12692 | if (version > DRW::AC1018) { | |||
| 12693 | sBuf = &sBuff; | |||
| 12694 | } | |||
| 12695 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 12696 | if (!ret) | |||
| 12697 | return fail(); | |||
| 12698 | DRW_DBG("\n***************************** parsing attdef *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attdef *********************************************\n" ); | |||
| 12699 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 12700 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 12701 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 12702 | if (version > DRW::AC1018 | |||
| 12703 | && (!buf->getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 12704 | stringEndBit) | |||
| 12705 | || currentDwgBit(sBuf) > stringEndBit)) | |||
| 12706 | return fail(); | |||
| 12707 | ||||
| 12708 | DwgAttributeBody parsed; | |||
| 12709 | if (!readBoundedDwgAttributeBody(version, *buf, *sBuf, bodyEndBit, | |||
| 12710 | stringStartBit, stringEndBit, | |||
| 12711 | /*isAttdef=*/true, parsed)) { | |||
| 12712 | DRW_DBG("ATTDEF payload failed\n")DRW_dbg::dbg("ATTDEF payload failed\n"); | |||
| 12713 | return fail(); | |||
| 12714 | } | |||
| 12715 | ||||
| 12716 | // The parent ATTDEF handle stream; its text style and the handles of an | |||
| 12717 | // embedded MTEXT follow the common ones. | |||
| 12718 | std::uint64_t handleEndBit = 0; | |||
| 12719 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 12720 | handleEndBit)) | |||
| 12721 | return fail(); | |||
| 12722 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 12723 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 12724 | handleEndBit); | |||
| 12725 | if (!ret) | |||
| 12726 | return fail(); | |||
| 12727 | ||||
| 12728 | dwgHandle parsedStyleH; | |||
| 12729 | if (!readBoundedDwgAttributeHandles(version, handleProbe, handleEndBit, | |||
| 12730 | parsed.m_tail, parsedStyleH) | |||
| 12731 | || !sBuf->isGood() | |||
| 12732 | || currentDwgBit(buf) > bodyEndBit | |||
| 12733 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 12734 | return fail(); | |||
| 12735 | ||||
| 12736 | *sourceBuf = handleProbe; | |||
| 12737 | basePoint = parsed.m_text.basePoint; | |||
| 12738 | secPoint = parsed.m_text.secPoint; | |||
| 12739 | extPoint = parsed.m_text.extPoint; | |||
| 12740 | thickness = parsed.m_text.thickness; | |||
| 12741 | oblique = parsed.m_text.oblique; | |||
| 12742 | angle = parsed.m_text.angle; | |||
| 12743 | height = parsed.m_text.height; | |||
| 12744 | widthscale = parsed.m_text.widthscale; | |||
| 12745 | text = std::move(parsed.m_text.text); | |||
| 12746 | textgen = parsed.m_text.textgen; | |||
| 12747 | alignH = parsed.m_text.alignH; | |||
| 12748 | alignV = parsed.m_text.alignV; | |||
| 12749 | attVersion = parsed.m_attVersion; | |||
| 12750 | m_attributeType = parsed.m_attributeType; | |||
| 12751 | mtext = std::move(parsed.m_tail.m_mtext); | |||
| 12752 | tag = std::move(parsed.m_tail.m_tag); | |||
| 12753 | m_fieldLength = parsed.m_tail.m_fieldLength; | |||
| 12754 | attribFlags = parsed.m_tail.m_attribFlags; | |||
| 12755 | lockPosition = parsed.m_tail.m_lockPosition; | |||
| 12756 | prompt = std::move(parsed.m_tail.m_prompt); | |||
| 12757 | styleH = parsedStyleH; | |||
| 12758 | return true; | |||
| 12759 | } | |||
| 12760 | ||||
| 12761 | bool DRW_Attdef::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 12762 | (void)bs; | |||
| 12763 | if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext)) | |||
| 12764 | return false; | |||
| 12765 | ||||
| 12766 | oType = 3; // ATTDEF class id — see dwgreader.cpp:1185 | |||
| 12767 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 12768 | ||||
| 12769 | dwgBufferW embeddedHandles; | |||
| 12770 | if (!putDwgAttributeBody(version, buf, strBuf, *this, &prompt, | |||
| 12771 | embeddedHandles)) | |||
| 12772 | return false; | |||
| 12773 | ||||
| 12774 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 12775 | ||||
| 12776 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 12777 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 12778 | putHardPointerHandle(hb, (styleH.ref == 0) ? 0x13 : styleH.ref); | |||
| 12779 | appendBitBuffer(hb, embeddedHandles); | |||
| 12780 | return buf->isGood() && sb->isGood() && hb->isGood(); | |||
| 12781 | } | |||
| 12782 | ||||
| 12783 | bool DRW_MText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 12784 | // R2018 appends the column data of an MTEXT as `101 / Embedded Object`. | |||
| 12785 | // That object reuses the MTEXT group codes with other meanings (10 is the | |||
| 12786 | // x-axis, 11 the insertion point, 40 the width, 71 the column type, 73 the | |||
| 12787 | // auto-height flag ...), so none of it may reach the fields below. XDATA | |||
| 12788 | // follows the object and is still the entity's. | |||
| 12789 | if (code == 101) { | |||
| 12790 | if (reader->getString() == "Embedded Object") | |||
| 12791 | m_dxfInEmbeddedObject = true; | |||
| 12792 | return true; | |||
| 12793 | } | |||
| 12794 | if (m_dxfInEmbeddedObject && code < 1000) | |||
| 12795 | return true; | |||
| 12796 | switch (code) { | |||
| 12797 | case 1: | |||
| 12798 | text += reader->getString(); | |||
| 12799 | text = reader->toUtf8String(text); | |||
| 12800 | break; | |||
| 12801 | case 11: | |||
| 12802 | hasXAxisVec = true; | |||
| 12803 | return DRW_Text::parseCode(code, reader); | |||
| 12804 | case 3: | |||
| 12805 | text += reader->getString(); | |||
| 12806 | break; | |||
| 12807 | case 44: | |||
| 12808 | interlin = reader->getDouble(); | |||
| 12809 | break; | |||
| 12810 | case 50: // djm: per dxf docs, last of code 11 or code 50 prevails | |||
| 12811 | hasXAxisVec = false; | |||
| 12812 | angle = reader->getDouble(); | |||
| 12813 | break; | |||
| 12814 | case 73: { | |||
| 12815 | const int value = reader->getInt32(); | |||
| 12816 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 12817 | return false; | |||
| 12818 | linespacingStyle = static_cast<std::uint16_t>(value); | |||
| 12819 | break; | |||
| 12820 | } | |||
| 12821 | case 42: | |||
| 12822 | m_r2018ExtentsWidth = reader->getDouble(); | |||
| 12823 | break; | |||
| 12824 | case 43: | |||
| 12825 | m_r2018ExtentsHeight = reader->getDouble(); | |||
| 12826 | break; | |||
| 12827 | case 46: | |||
| 12828 | m_r2018RectHeight = reader->getDouble(); | |||
| 12829 | break; | |||
| 12830 | case 45: | |||
| 12831 | m_backgroundScale = reader->getDouble(); | |||
| 12832 | break; | |||
| 12833 | case 63: | |||
| 12834 | m_backgroundColor = reader->getInt32(); | |||
| 12835 | break; | |||
| 12836 | case 90: | |||
| 12837 | m_backgroundFlags = reader->getInt32(); | |||
| 12838 | break; | |||
| 12839 | case 421: | |||
| 12840 | // True colour of the background fill; 63 keeps its ACI. | |||
| 12841 | m_backgroundTrueColor = reader->getInt32(); | |||
| 12842 | break; | |||
| 12843 | case 441: | |||
| 12844 | m_backgroundTransparency = reader->getInt32(); | |||
| 12845 | break; | |||
| 12846 | default: | |||
| 12847 | return DRW_Text::parseCode(code, reader); | |||
| 12848 | } | |||
| 12849 | ||||
| 12850 | return true; | |||
| 12851 | } | |||
| 12852 | ||||
| 12853 | void DRW_MText::resetDwgState() { | |||
| 12854 | DRW_Text::resetDwgState(); | |||
| 12855 | interlin = 1.0; | |||
| 12856 | linespacingStyle = 1; | |||
| 12857 | m_backgroundFlags = 0; | |||
| 12858 | m_backgroundScale = 0.0; | |||
| 12859 | m_backgroundColor = 0; | |||
| 12860 | m_backgroundTrueColor = -1; | |||
| 12861 | m_backgroundTransparency = 0; | |||
| 12862 | hasXAxisVec = false; | |||
| 12863 | m_dxfInEmbeddedObject = false; | |||
| 12864 | m_r2018IsNotAnnotative = false; | |||
| 12865 | m_r2018ReallyLocked = false; | |||
| 12866 | m_r2018Version = 0; | |||
| 12867 | m_r2018DefaultFlag = false; | |||
| 12868 | m_r2018AppIdHandle = 0; | |||
| 12869 | m_r2018Attachment = 0; | |||
| 12870 | m_r2018XAxisDir = {}; | |||
| 12871 | m_r2018InsertionPoint = {}; | |||
| 12872 | m_r2018RectWidth = 0.0; | |||
| 12873 | m_r2018RectHeight = 0.0; | |||
| 12874 | m_r2018ExtentsHeight = 0.0; | |||
| 12875 | m_r2018ExtentsWidth = 0.0; | |||
| 12876 | m_r2018ColumnType = 0; | |||
| 12877 | m_r2018ColumnCount = 0; | |||
| 12878 | m_r2018ColumnWidth = 0.0; | |||
| 12879 | m_r2018ColumnGutter = 0.0; | |||
| 12880 | m_r2018ColumnAutoHeight = false; | |||
| 12881 | m_r2018ColumnFlowReversed = false; | |||
| 12882 | m_r2018ColumnHeights.clear(); | |||
| 12883 | m_r2018AnnotativeData.clear(); | |||
| 12884 | m_r2018AnnotativeUnknown = 0; | |||
| 12885 | m_r2018AnnotativeAppHandle = 0; | |||
| 12886 | textgen = 1; | |||
| 12887 | alignV = static_cast<VAlign>(TopLeft); | |||
| 12888 | } | |||
| 12889 | ||||
| 12890 | bool DRW_MText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 12891 | // A reader may reuse an entity carrier while walking a compound stream. | |||
| 12892 | // R2018 context data is version-gated, so clear it before parsing an | |||
| 12893 | // older MTEXT or stale column/annotative state can leak into the result. | |||
| 12894 | resetDwgState(); | |||
| 12895 | dwgBuffer *sourceBuf = buf; | |||
| 12896 | auto fail = [this, sourceBuf]() { | |||
| 12897 | if (sourceBuf != nullptr) | |||
| 12898 | sourceBuf->invalidate(); | |||
| 12899 | resetDwgState(); | |||
| 12900 | return false; | |||
| 12901 | }; | |||
| 12902 | if (sourceBuf == nullptr) | |||
| 12903 | return fail(); | |||
| 12904 | ||||
| 12905 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 12906 | buf = &bodyProbe; | |||
| 12907 | ||||
| 12908 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 12909 | dwgBuffer *sBuf = buf; | |||
| 12910 | if (version > DRW::AC1018) {//2007+ | |||
| 12911 | sBuf = &sBuff; //separate buffer for strings | |||
| 12912 | } | |||
| 12913 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 12914 | if (!ret) | |||
| 12915 | return fail(); | |||
| 12916 | DRW_DBG("\n***************************** parsing mtext *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mtext *********************************************\n" ); | |||
| 12917 | ||||
| 12918 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 12919 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 12920 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 12921 | if (version > DRW::AC1018) { | |||
| 12922 | if (!buf->getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 12923 | stringEndBit) | |||
| 12924 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 12925 | return fail(); | |||
| 12926 | } | |||
| 12927 | ||||
| 12928 | const bool hasStringStream = stringStartBit < stringEndBit; | |||
| 12929 | const auto readText = [&](UTF8STRINGstd::string& value) { | |||
| 12930 | if (version > DRW::AC1018 && !hasStringStream) { | |||
| 12931 | value.clear(); | |||
| 12932 | return true; | |||
| 12933 | } | |||
| 12934 | const std::uint64_t endBit = version > DRW::AC1018 | |||
| 12935 | ? stringEndBit : bodyEndBit; | |||
| 12936 | return readBoundedVariableText(*sBuf, endBit, version, value); | |||
| 12937 | }; | |||
| 12938 | ||||
| 12939 | DRW_Coord parsedBasePoint; | |||
| 12940 | DRW_Coord parsedExtrusion; | |||
| 12941 | DRW_Coord parsedXAxisDirection; | |||
| 12942 | double parsedWidthScale = 0.0; | |||
| 12943 | double parsedRectangleHeight = 0.0; | |||
| 12944 | double parsedHeight = 0.0; | |||
| 12945 | std::uint16_t parsedAttachment = 1; | |||
| 12946 | std::uint16_t parsedDrawingDirection = 0; | |||
| 12947 | double ignoredExtentsHeight = 0.0; | |||
| 12948 | double ignoredExtentsWidth = 0.0; | |||
| 12949 | UTF8STRINGstd::string parsedText; | |||
| 12950 | std::uint16_t parsedLineSpacingStyle = 1; | |||
| 12951 | double parsedInterlin = 1.0; | |||
| 12952 | std::int32_t parsedBackgroundFlags = 0; | |||
| 12953 | double parsedBackgroundScale = 0.0; | |||
| 12954 | std::uint32_t parsedBackgroundColor = 0; | |||
| 12955 | std::int32_t parsedBackgroundTransparency = 0; | |||
| 12956 | bool parsedIsNotAnnotative = false; | |||
| 12957 | DwgMTextR2018Block parsedR2018; | |||
| 12958 | ||||
| 12959 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 12960 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtrusion) | |||
| 12961 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedXAxisDirection) | |||
| 12962 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedWidthScale) | |||
| 12963 | || (version > DRW::AC1018 | |||
| 12964 | && !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12965 | parsedRectangleHeight)) | |||
| 12966 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedHeight) | |||
| 12967 | || !readBoundedBitShort(*buf, bodyEndBit, parsedAttachment) | |||
| 12968 | || !readBoundedBitShort(*buf, bodyEndBit, parsedDrawingDirection) | |||
| 12969 | || !readBoundedBitDouble(*buf, bodyEndBit, ignoredExtentsHeight) | |||
| 12970 | || !readBoundedBitDouble(*buf, bodyEndBit, ignoredExtentsWidth) | |||
| 12971 | || !readText(parsedText)) | |||
| 12972 | return fail(); | |||
| 12973 | ||||
| 12974 | if (version > DRW::AC1014 | |||
| 12975 | && (!readBoundedBitShort(*buf, bodyEndBit, parsedLineSpacingStyle) | |||
| 12976 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedInterlin))) | |||
| 12977 | return fail(); | |||
| 12978 | bool ignoredBit = false; | |||
| 12979 | if (version > DRW::AC1014 && !readBoundedBit(*buf, bodyEndBit, | |||
| 12980 | ignoredBit)) | |||
| 12981 | return fail(); | |||
| 12982 | ||||
| 12983 | if (version > DRW::AC1015) { | |||
| 12984 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedBackgroundFlags)) | |||
| 12985 | return fail(); | |||
| 12986 | const bool hasBackgroundDetails = (parsedBackgroundFlags & 0x01) != 0 | |||
| 12987 | || (version >= DRW::AC1032 | |||
| 12988 | && (parsedBackgroundFlags & 0x10) != 0); | |||
| 12989 | if (hasBackgroundDetails | |||
| 12990 | && (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12991 | parsedBackgroundScale) | |||
| 12992 | || !readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 12993 | parsedBackgroundColor, nullptr, | |||
| 12994 | nullptr, nullptr, nullptr, | |||
| 12995 | stringEndBit) | |||
| 12996 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 12997 | parsedBackgroundTransparency))) | |||
| 12998 | return fail(); | |||
| 12999 | } | |||
| 13000 | ||||
| 13001 | bool hasR2018AppId = false; | |||
| 13002 | if (version >= DRW::AC1032) { | |||
| 13003 | if (!readBoundedBit(*buf, bodyEndBit, parsedIsNotAnnotative)) | |||
| 13004 | return fail(); | |||
| 13005 | if (parsedIsNotAnnotative) { | |||
| 13006 | hasR2018AppId = true; | |||
| 13007 | if (!readBoundedDwgMTextR2018Block(*buf, bodyEndBit, parsedR2018)) | |||
| 13008 | return fail(); | |||
| 13009 | } | |||
| 13010 | } | |||
| 13011 | ||||
| 13012 | const auto finite = [](const DRW_Coord& point) { | |||
| 13013 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 13014 | && std::isfinite(point.z); | |||
| 13015 | }; | |||
| 13016 | if (!buf->isGood() || !sBuf->isGood() | |||
| 13017 | || !finite(parsedBasePoint) || !finite(parsedExtrusion) | |||
| 13018 | || !finite(parsedXAxisDirection) | |||
| 13019 | || !std::isfinite(parsedWidthScale) | |||
| 13020 | || !std::isfinite(parsedRectangleHeight) | |||
| 13021 | || !std::isfinite(parsedHeight) | |||
| 13022 | || !std::isfinite(ignoredExtentsHeight) | |||
| 13023 | || !std::isfinite(ignoredExtentsWidth) | |||
| 13024 | || !std::isfinite(parsedInterlin)) | |||
| 13025 | return fail(); | |||
| 13026 | ||||
| 13027 | std::uint64_t handleEndBit = 0; | |||
| 13028 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 13029 | handleEndBit)) | |||
| 13030 | return fail(); | |||
| 13031 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 13032 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 13033 | handleEndBit)) | |||
| 13034 | return fail(); | |||
| 13035 | ||||
| 13036 | dwgHandle parsedStyleH; | |||
| 13037 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 13038 | parsedStyleH)) | |||
| 13039 | return fail(); | |||
| 13040 | dwgHandle parsedAppIdH; | |||
| 13041 | if (hasR2018AppId | |||
| 13042 | && !readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 13043 | parsedAppIdH)) | |||
| 13044 | return fail(); | |||
| 13045 | if (!handleProbe.isGood() || !sBuf->isGood()) | |||
| 13046 | return fail(); | |||
| 13047 | ||||
| 13048 | *sourceBuf = handleProbe; | |||
| 13049 | basePoint = parsedBasePoint; | |||
| 13050 | extPoint = parsedExtrusion; | |||
| 13051 | secPoint = parsedXAxisDirection; | |||
| 13052 | hasXAxisVec = true; | |||
| 13053 | widthscale = parsedWidthScale; | |||
| 13054 | height = parsedHeight; | |||
| 13055 | angle = atan2(secPoint.y, secPoint.x) * ARAD57.29577951308232; | |||
| 13056 | textgen = parsedAttachment; | |||
| 13057 | alignH = static_cast<HAlign>(parsedDrawingDirection); | |||
| 13058 | text = std::move(parsedText); | |||
| 13059 | linespacingStyle = parsedLineSpacingStyle; | |||
| 13060 | interlin = parsedInterlin; | |||
| 13061 | m_backgroundFlags = parsedBackgroundFlags; | |||
| 13062 | m_backgroundScale = parsedBackgroundScale; | |||
| 13063 | m_backgroundColor = static_cast<int>(parsedBackgroundColor); | |||
| 13064 | m_backgroundTransparency = parsedBackgroundTransparency; | |||
| 13065 | m_r2018IsNotAnnotative = parsedIsNotAnnotative; | |||
| 13066 | m_r2018AppIdHandle = hasR2018AppId ? parsedAppIdH.ref : 0; | |||
| 13067 | storeDwgMTextR2018Block(std::move(parsedR2018), *this); | |||
| 13068 | styleH = parsedStyleH; | |||
| 13069 | 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("."); | |||
| 13070 | 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"); | |||
| 13071 | return true; | |||
| 13072 | } | |||
| 13073 | ||||
| 13074 | void DRW_MText::updateAngle() { | |||
| 13075 | if (hasXAxisVec) { | |||
| 13076 | angle = atan2(secPoint.y, secPoint.x) * ARAD57.29577951308232; | |||
| 13077 | } | |||
| 13078 | } | |||
| 13079 | ||||
| 13080 | bool DRW_Polyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 13081 | switch (code) { | |||
| 13082 | case 70: | |||
| 13083 | flags = reader->getInt32(); | |||
| 13084 | break; | |||
| 13085 | case 40: | |||
| 13086 | defstawidth = reader->getDouble(); | |||
| 13087 | break; | |||
| 13088 | case 41: | |||
| 13089 | defendwidth = reader->getDouble(); | |||
| 13090 | break; | |||
| 13091 | case 71: | |||
| 13092 | vertexcount = reader->getInt32(); | |||
| 13093 | break; | |||
| 13094 | case 72: | |||
| 13095 | facecount = reader->getInt32(); | |||
| 13096 | break; | |||
| 13097 | case 73: | |||
| 13098 | smoothM = reader->getInt32(); | |||
| 13099 | break; | |||
| 13100 | case 74: | |||
| 13101 | smoothN = reader->getInt32(); | |||
| 13102 | break; | |||
| 13103 | case 75: | |||
| 13104 | curvetype = reader->getInt32(); | |||
| 13105 | break; | |||
| 13106 | default: | |||
| 13107 | return DRW_Point::parseCode(code, reader); | |||
| 13108 | } | |||
| 13109 | ||||
| 13110 | return true; | |||
| 13111 | } | |||
| 13112 | ||||
| 13113 | //0x0F polyline 2D bit 4(8) & 5(16) NOT set | |||
| 13114 | //0x10 polyline 3D bit 4(8) set | |||
| 13115 | //0x1D PFACE bit 5(16) set | |||
| 13116 | void DRW_Polyline::resetDwgState() { | |||
| 13117 | DRW_Point::resetDwgState(); | |||
| 13118 | flags = 0; | |||
| 13119 | defstawidth = 0.0; | |||
| 13120 | defendwidth = 0.0; | |||
| 13121 | vertexcount = 0; | |||
| 13122 | facecount = 0; | |||
| 13123 | smoothM = 0; | |||
| 13124 | smoothN = 0; | |||
| 13125 | curvetype = 0; | |||
| 13126 | vertlist.clear(); | |||
| 13127 | hadlesList.clear(); | |||
| 13128 | firstEH = 0; | |||
| 13129 | lastEH = 0; | |||
| 13130 | seqEndH = dwgHandle{}; | |||
| 13131 | } | |||
| 13132 | ||||
| 13133 | bool DRW_Polyline::validatePayloadFields() const { | |||
| 13134 | const auto finite = [](const DRW_Coord& point) { | |||
| 13135 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 13136 | && std::isfinite(point.z); | |||
| 13137 | }; | |||
| 13138 | const auto validBitShort = [](int value) { | |||
| 13139 | return value >= 0 | |||
| 13140 | && value <= std::numeric_limits<std::uint16_t>::max(); | |||
| 13141 | }; | |||
| 13142 | return flags >= 0 && flags <= std::numeric_limits<std::uint8_t>::max() | |||
| 13143 | && validBitShort(curvetype) && validBitShort(vertexcount) | |||
| 13144 | && validBitShort(facecount) && validBitShort(smoothM) | |||
| 13145 | && validBitShort(smoothN) && finite(basePoint) | |||
| 13146 | && finite(extPoint) && std::isfinite(defstawidth) | |||
| 13147 | && std::isfinite(defendwidth) && std::isfinite(thickness) | |||
| 13148 | && vertlist.size() <= dwgSafety::MaxOwnedObjectCount | |||
| 13149 | && vertlist.size() | |||
| 13150 | <= static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max()) | |||
| 13151 | && std::all_of(vertlist.cbegin(), vertlist.cend(), | |||
| 13152 | [](const auto& vertex) { return vertex != nullptr; }); | |||
| 13153 | } | |||
| 13154 | ||||
| 13155 | bool DRW_Polyline::isDwgVertexCompatible( | |||
| 13156 | const DRW_Vertex& vertex) const noexcept { | |||
| 13157 | if ((flags & 64) != 0) { | |||
| 13158 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Polyface | |||
| 13159 | || vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::PolyfaceFace; | |||
| 13160 | } | |||
| 13161 | if ((flags & 16) != 0) | |||
| 13162 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Mesh; | |||
| 13163 | if ((flags & 8) != 0) | |||
| 13164 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Vertex3D; | |||
| 13165 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Vertex2D; | |||
| 13166 | } | |||
| 13167 | ||||
| 13168 | bool DRW_Polyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 13169 | resetDwgState(); | |||
| 13170 | dwgBuffer *sourceBuf = buf; | |||
| 13171 | auto fail = [this, sourceBuf]() { | |||
| 13172 | if (sourceBuf != nullptr) | |||
| 13173 | sourceBuf->invalidate(); | |||
| 13174 | resetDwgState(); | |||
| 13175 | return false; | |||
| 13176 | }; | |||
| 13177 | ||||
| 13178 | if (sourceBuf == nullptr) | |||
| 13179 | return fail(); | |||
| 13180 | ||||
| 13181 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 13182 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 13183 | || !bodyProbe.isGood()) | |||
| 13184 | return fail(); | |||
| 13185 | DRW_DBG("\n***************************** parsing polyline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing polyline *********************************************\n" ); | |||
| 13186 | ||||
| 13187 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 13188 | int parsedFlags = 0; | |||
| 13189 | double parsedDefStartWidth = 0.0; | |||
| 13190 | double parsedDefEndWidth = 0.0; | |||
| 13191 | int parsedVertexCount = 0; | |||
| 13192 | int parsedFaceCount = 0; | |||
| 13193 | int parsedSmoothM = 0; | |||
| 13194 | int parsedSmoothN = 0; | |||
| 13195 | int parsedCurveType = 0; | |||
| 13196 | double parsedThickness = 0.0; | |||
| 13197 | DRW_Coord parsedBasePoint; | |||
| 13198 | DRW_Coord parsedExtrusion; | |||
| 13199 | std::int32_t ooCount = 0; | |||
| 13200 | if (oType == 0x0F) { //pline 2D | |||
| 13201 | std::uint16_t value = 0; | |||
| 13202 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13203 | return fail(); | |||
| 13204 | parsedFlags = value; | |||
| 13205 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13206 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13207 | return fail(); | |||
| 13208 | parsedCurveType = value; | |||
| 13209 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedDefStartWidth) | |||
| 13210 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedDefEndWidth) | |||
| 13211 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 13212 | version > DRW::AC1014, parsedThickness) | |||
| 13213 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedBasePoint.z) | |||
| 13214 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 13215 | version > DRW::AC1014, parsedExtrusion)) | |||
| 13216 | return fail(); | |||
| 13217 | } else if (oType == 0x10) { //pline 3D | |||
| 13218 | std::uint8_t tmpFlag = 0; | |||
| 13219 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, tmpFlag)) | |||
| 13220 | return fail(); | |||
| 13221 | DRW_DBG("flags 1 value: ")DRW_dbg::dbg("flags 1 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag); | |||
| 13222 | if (tmpFlag & 1) | |||
| 13223 | parsedCurveType = 5; // quadratic B-spline | |||
| 13224 | else if (tmpFlag & 2) | |||
| 13225 | parsedCurveType = 6; // cubic B-spline | |||
| 13226 | if (tmpFlag & 3) | |||
| 13227 | parsedFlags |= 4; // splined (bit 2); do NOT overwrite curvetype to 8 | |||
| 13228 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, tmpFlag)) | |||
| 13229 | return fail(); | |||
| 13230 | if (tmpFlag & 1) | |||
| 13231 | parsedFlags |= 1; | |||
| 13232 | parsedFlags |= 8; //indicate 3DPOL | |||
| 13233 | DRW_DBG("flags 2 value: ")DRW_dbg::dbg("flags 2 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag); | |||
| 13234 | } else if (oType == 0x1D) { //PFACE | |||
| 13235 | std::uint16_t vertexValue = 0; | |||
| 13236 | std::uint16_t faceValue = 0; | |||
| 13237 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, vertexValue) | |||
| 13238 | || !readBoundedBitShort(bodyProbe, bodyEndBit, faceValue)) | |||
| 13239 | return fail(); | |||
| 13240 | parsedFlags = 64; | |||
| 13241 | parsedVertexCount = vertexValue; | |||
| 13242 | parsedFaceCount = faceValue; | |||
| 13243 | DRW_DBG("vertex count: ")DRW_dbg::dbg("vertex count: "); DRW_DBG(parsedVertexCount)DRW_dbg::dbg(parsedVertexCount); | |||
| 13244 | DRW_DBG("face count: ")DRW_dbg::dbg("face count: "); DRW_DBG(parsedFaceCount)DRW_dbg::dbg(parsedFaceCount); | |||
| 13245 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13246 | } else if (oType == 0x1E) { //POLYLINE_MESH per ODA spec sec 19.4.31 | |||
| 13247 | std::uint16_t value = 0; | |||
| 13248 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13249 | return fail(); | |||
| 13250 | parsedFlags = value | 16; //bit 4 = 3D polygon mesh | |||
| 13251 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13252 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13253 | return fail(); | |||
| 13254 | parsedCurveType = value; | |||
| 13255 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13256 | return fail(); | |||
| 13257 | parsedVertexCount = value; //M-count | |||
| 13258 | DRW_DBG(" M count: ")DRW_dbg::dbg(" M count: "); DRW_DBG(parsedVertexCount)DRW_dbg::dbg(parsedVertexCount); | |||
| 13259 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13260 | return fail(); | |||
| 13261 | parsedFaceCount = value; //N-count | |||
| 13262 | DRW_DBG(" N count: ")DRW_dbg::dbg(" N count: "); DRW_DBG(parsedFaceCount)DRW_dbg::dbg(parsedFaceCount); | |||
| 13263 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13264 | return fail(); | |||
| 13265 | parsedSmoothM = value; //M smooth-surface density, DXF 73 | |||
| 13266 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13267 | return fail(); | |||
| 13268 | parsedSmoothN = value; //N smooth-surface density, DXF 74 | |||
| 13269 | 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); | |||
| 13270 | } else { | |||
| 13271 | return fail(); | |||
| 13272 | } | |||
| 13273 | if (version > DRW::AC1015){ //2004+ | |||
| 13274 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, ooCount) | |||
| 13275 | || !dwgSafety::validOwnedObjectCount( | |||
| 13276 | ooCount, bodyProbe.numRemainingBytes())) { | |||
| 13277 | DRW_DBG("\nWARNING: Invalid POLYLINE owned-object count\n")DRW_dbg::dbg("\nWARNING: Invalid POLYLINE owned-object count\n" ); | |||
| 13278 | return fail(); | |||
| 13279 | } | |||
| 13280 | } | |||
| 13281 | ||||
| 13282 | std::uint64_t handleEndBit = 0; | |||
| 13283 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 13284 | handleEndBit)) | |||
| 13285 | return fail(); | |||
| 13286 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 13287 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 13288 | handleEndBit) | |||
| 13289 | || !handleProbe.isGood()) | |||
| 13290 | return fail(); | |||
| 13291 | ||||
| 13292 | std::list<std::uint32_t> parsedHandles; | |||
| 13293 | std::uint32_t parsedFirstEH = 0; | |||
| 13294 | std::uint32_t parsedLastEH = 0; | |||
| 13295 | ||||
| 13296 | if (version < DRW::AC1018){ //2000- | |||
| 13297 | dwgHandle objectH; | |||
| 13298 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 13299 | objectH)) | |||
| 13300 | return fail(); | |||
| 13301 | parsedFirstEH = objectH.ref; | |||
| 13302 | 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"); | |||
| 13303 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 13304 | objectH)) | |||
| 13305 | return fail(); | |||
| 13306 | parsedLastEH = objectH.ref; | |||
| 13307 | 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"); | |||
| 13308 | 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"); | |||
| 13309 | } else { | |||
| 13310 | for (std::int32_t i = 0; i < ooCount; ++i){ | |||
| 13311 | dwgHandle objectH; | |||
| 13312 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, | |||
| 13313 | true, objectH)) | |||
| 13314 | return fail(); | |||
| 13315 | try { | |||
| 13316 | parsedHandles.push_back(objectH.ref); | |||
| 13317 | } catch (...) { | |||
| 13318 | return fail(); | |||
| 13319 | } | |||
| 13320 | 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"); | |||
| 13321 | 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"); | |||
| 13322 | } | |||
| 13323 | } | |||
| 13324 | dwgHandle parsedSeqEndH; | |||
| 13325 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 13326 | parsedSeqEndH)) | |||
| 13327 | return fail(); | |||
| 13328 | if (!handleProbe.isGood()) | |||
| 13329 | return fail(); | |||
| 13330 | *sourceBuf = handleProbe; | |||
| 13331 | flags = parsedFlags; | |||
| 13332 | defstawidth = parsedDefStartWidth; | |||
| 13333 | defendwidth = parsedDefEndWidth; | |||
| 13334 | vertexcount = parsedVertexCount; | |||
| 13335 | facecount = parsedFaceCount; | |||
| 13336 | smoothM = parsedSmoothM; | |||
| 13337 | smoothN = parsedSmoothN; | |||
| 13338 | curvetype = parsedCurveType; | |||
| 13339 | thickness = parsedThickness; | |||
| 13340 | basePoint = parsedBasePoint; | |||
| 13341 | extPoint = parsedExtrusion; | |||
| 13342 | firstEH = parsedFirstEH; | |||
| 13343 | lastEH = parsedLastEH; | |||
| 13344 | seqEndH = parsedSeqEndH; | |||
| 13345 | hadlesList = std::move(parsedHandles); | |||
| 13346 | 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"); | |||
| 13347 | 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"); | |||
| 13348 | ||||
| 13349 | // RS crc; //RS */ | |||
| 13350 | return buf->isGood(); | |||
| 13351 | } | |||
| 13352 | ||||
| 13353 | bool DRW_Vertex::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 13354 | switch (code) { | |||
| 13355 | case 70: | |||
| 13356 | flags = reader->getInt32(); | |||
| 13357 | break; | |||
| 13358 | case 40: | |||
| 13359 | stawidth = reader->getDouble(); | |||
| 13360 | break; | |||
| 13361 | case 41: | |||
| 13362 | endwidth = reader->getDouble(); | |||
| 13363 | break; | |||
| 13364 | case 42: | |||
| 13365 | bulge = reader->getDouble(); | |||
| 13366 | break; | |||
| 13367 | case 50: | |||
| 13368 | tgdir = reader->getDouble(); | |||
| 13369 | break; | |||
| 13370 | case 71: | |||
| 13371 | vindex1 = reader->getInt32(); | |||
| 13372 | break; | |||
| 13373 | case 72: | |||
| 13374 | vindex2 = reader->getInt32(); | |||
| 13375 | break; | |||
| 13376 | case 73: | |||
| 13377 | vindex3 = reader->getInt32(); | |||
| 13378 | break; | |||
| 13379 | case 74: | |||
| 13380 | vindex4 = reader->getInt32(); | |||
| 13381 | break; | |||
| 13382 | case 91: | |||
| 13383 | identifier = reader->getInt32(); | |||
| 13384 | break; | |||
| 13385 | default: | |||
| 13386 | return DRW_Point::parseCode(code, reader); | |||
| 13387 | } | |||
| 13388 | ||||
| 13389 | return true; | |||
| 13390 | } | |||
| 13391 | ||||
| 13392 | //0x0A vertex 2D | |||
| 13393 | //0x0B vertex 3D | |||
| 13394 | //0x0C MESH | |||
| 13395 | //0x0D PFACE | |||
| 13396 | //0x0E PFACE FACE | |||
| 13397 | void DRW_Vertex::resetDwgState() { | |||
| 13398 | DRW_Point::resetDwgState(); | |||
| 13399 | stawidth = 0.0; | |||
| 13400 | endwidth = 0.0; | |||
| 13401 | bulge = 0.0; | |||
| 13402 | flags = 0; | |||
| 13403 | tgdir = 0.0; | |||
| 13404 | vindex1 = vindex2 = vindex3 = vindex4 = 0; | |||
| 13405 | identifier = 0; | |||
| 13406 | m_dwgSubtype = DwgSubtype::Auto; | |||
| 13407 | } | |||
| 13408 | ||||
| 13409 | bool DRW_Vertex::validatePayloadFields() const { | |||
| 13410 | const auto finite = [](const DRW_Coord& point) { | |||
| 13411 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 13412 | && std::isfinite(point.z); | |||
| 13413 | }; | |||
| 13414 | const auto validFaceIndex = [](int value) { | |||
| 13415 | return value >= std::numeric_limits<std::int16_t>::min() | |||
| 13416 | && value <= std::numeric_limits<std::int16_t>::max(); | |||
| 13417 | }; | |||
| 13418 | const auto validInt32 = [](int value) { | |||
| 13419 | return value >= std::numeric_limits<std::int32_t>::min() | |||
| 13420 | && value <= std::numeric_limits<std::int32_t>::max(); | |||
| 13421 | }; | |||
| 13422 | return flags >= 0 && flags <= std::numeric_limits<std::uint8_t>::max() | |||
| 13423 | && validFaceIndex(vindex1) && validFaceIndex(vindex2) | |||
| 13424 | && validFaceIndex(vindex3) && validFaceIndex(vindex4) | |||
| 13425 | && validInt32(identifier) && finite(basePoint) | |||
| 13426 | && std::isfinite(stawidth) && std::isfinite(endwidth) | |||
| 13427 | && std::isfinite(bulge) && std::isfinite(tgdir); | |||
| 13428 | } | |||
| 13429 | ||||
| 13430 | bool DRW_Vertex::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs, double el){ | |||
| 13431 | resetDwgState(); | |||
| 13432 | dwgBuffer *sourceBuf = buf; | |||
| 13433 | auto fail = [this, sourceBuf]() { | |||
| 13434 | if (sourceBuf != nullptr) | |||
| 13435 | sourceBuf->invalidate(); | |||
| 13436 | resetDwgState(); | |||
| 13437 | return false; | |||
| 13438 | }; | |||
| 13439 | ||||
| 13440 | if (sourceBuf == nullptr) | |||
| 13441 | return fail(); | |||
| 13442 | ||||
| 13443 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 13444 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 13445 | || !bodyProbe.isGood()) | |||
| 13446 | return fail(); | |||
| 13447 | DRW_DBG("\n***************************** parsing pline Vertex *********************************************\n")DRW_dbg::dbg("\n***************************** parsing pline Vertex *********************************************\n" ); | |||
| 13448 | ||||
| 13449 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 13450 | DRW_Vertex::DwgSubtype parsedSubtype = DRW_Vertex::DwgSubtype::Auto; | |||
| 13451 | std::uint8_t parsedFlags = 0; | |||
| 13452 | DRW_Coord parsedBasePoint; | |||
| 13453 | double parsedStartWidth = 0.0; | |||
| 13454 | double parsedEndWidth = 0.0; | |||
| 13455 | double parsedBulge = 0.0; | |||
| 13456 | double parsedTangentDirection = 0.0; | |||
| 13457 | int parsedIndex1 = 0; | |||
| 13458 | int parsedIndex2 = 0; | |||
| 13459 | int parsedIndex3 = 0; | |||
| 13460 | int parsedIndex4 = 0; | |||
| 13461 | int parsedIdentifier = 0; | |||
| 13462 | if (oType == 0x0A) { //pline 2D, needed example | |||
| 13463 | parsedSubtype = DwgSubtype::Vertex2D; | |||
| 13464 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, parsedFlags) | |||
| 13465 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 13466 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedStartWidth)) | |||
| 13467 | return fail(); | |||
| 13468 | parsedBasePoint.z = el; | |||
| 13469 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13470 | DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 13471 | if (parsedStartWidth < 0.0) { | |||
| 13472 | parsedEndWidth = parsedStartWidth = std::fabs(parsedStartWidth); | |||
| 13473 | } else if (!readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 13474 | parsedEndWidth)) { | |||
| 13475 | return fail(); | |||
| 13476 | } | |||
| 13477 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedBulge)) | |||
| 13478 | return fail(); | |||
| 13479 | if (version > DRW::AC1021) { //2010+ | |||
| 13480 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, parsedIdentifier)) | |||
| 13481 | return fail(); | |||
| 13482 | DRW_DBG("Vertex ID: ")DRW_dbg::dbg("Vertex ID: "); DRW_DBG(parsedIdentifier)DRW_dbg::dbg(parsedIdentifier); | |||
| 13483 | } | |||
| 13484 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 13485 | parsedTangentDirection)) | |||
| 13486 | return fail(); | |||
| 13487 | } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) { //PFACE | |||
| 13488 | if (oType == 0x0B) | |||
| 13489 | parsedSubtype = DwgSubtype::Vertex3D; | |||
| 13490 | else if (oType == 0x0C) | |||
| 13491 | parsedSubtype = DwgSubtype::Mesh; | |||
| 13492 | else | |||
| 13493 | parsedSubtype = DwgSubtype::Polyface; | |||
| 13494 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, parsedFlags) | |||
| 13495 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint)) | |||
| 13496 | return fail(); | |||
| 13497 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13498 | DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 13499 | } else if (oType == 0x0E) { //PFACE FACE | |||
| 13500 | parsedSubtype = DwgSubtype::PolyfaceFace; | |||
| 13501 | auto signedIndex = [](std::uint16_t value) { | |||
| 13502 | return value > 32767 ? value - 65536 : value; | |||
| 13503 | }; | |||
| 13504 | std::uint16_t value = 0; | |||
| 13505 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13506 | return fail(); | |||
| 13507 | parsedIndex1 = signedIndex(value); | |||
| 13508 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13509 | return fail(); | |||
| 13510 | parsedIndex2 = signedIndex(value); | |||
| 13511 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13512 | return fail(); | |||
| 13513 | parsedIndex3 = signedIndex(value); | |||
| 13514 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13515 | return fail(); | |||
| 13516 | parsedIndex4 = signedIndex(value); | |||
| 13517 | } else { | |||
| 13518 | return fail(); | |||
| 13519 | } | |||
| 13520 | ||||
| 13521 | const auto finite = [](const DRW_Coord& point) { | |||
| 13522 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 13523 | && std::isfinite(point.z); | |||
| 13524 | }; | |||
| 13525 | if (!finite(parsedBasePoint) || !std::isfinite(parsedStartWidth) | |||
| 13526 | || !std::isfinite(parsedEndWidth) || !std::isfinite(parsedBulge) | |||
| 13527 | || !std::isfinite(parsedTangentDirection) | |||
| 13528 | || !std::isfinite(el)) | |||
| 13529 | return fail(); | |||
| 13530 | ||||
| 13531 | std::uint64_t handleEndBit = 0; | |||
| 13532 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 13533 | handleEndBit)) | |||
| 13534 | return fail(); | |||
| 13535 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 13536 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 13537 | handleEndBit) | |||
| 13538 | || !handleProbe.isGood()) | |||
| 13539 | return fail(); | |||
| 13540 | // RS crc; //RS */ | |||
| 13541 | *sourceBuf = handleProbe; | |||
| 13542 | m_dwgSubtype = parsedSubtype; | |||
| 13543 | flags = parsedFlags; | |||
| 13544 | basePoint = parsedBasePoint; | |||
| 13545 | stawidth = parsedStartWidth; | |||
| 13546 | endwidth = parsedEndWidth; | |||
| 13547 | bulge = parsedBulge; | |||
| 13548 | tgdir = parsedTangentDirection; | |||
| 13549 | vindex1 = parsedIndex1; | |||
| 13550 | vindex2 = parsedIndex2; | |||
| 13551 | vindex3 = parsedIndex3; | |||
| 13552 | vindex4 = parsedIndex4; | |||
| 13553 | identifier = parsedIdentifier; | |||
| 13554 | return true; | |||
| 13555 | } | |||
| 13556 | ||||
| 13557 | bool DRW_Hatch::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 13558 | try { | |||
| 13559 | switch (code) { | |||
| 13560 | case 2: | |||
| 13561 | name = reader->getUtf8String(); | |||
| 13562 | break; | |||
| 13563 | case 70: | |||
| 13564 | solid = reader->getInt32(); | |||
| 13565 | break; | |||
| 13566 | case 71: | |||
| 13567 | associative = reader->getInt32(); | |||
| 13568 | break; | |||
| 13569 | case 72: { /*edge type*/ | |||
| 13570 | if (ispol){ // polyline path: 72 is the has-bulge flag. Do NOT fold it | |||
| 13571 | // into pline->flags — bit 0 there is the *closed* flag (set by code | |||
| 13572 | // 73), and the per-vertex bulges arrive via code 42 regardless. Some | |||
| 13573 | // writers (e.g. ezdxf MPOLYGON) emit 73 before 72; the old code let | |||
| 13574 | // 72 clear the closed bit 73 had just set, leaving the boundary open | |||
| 13575 | // so RS_Hatch::validate() rejected the area. | |||
| 13576 | break; | |||
| 13577 | } | |||
| 13578 | if (spline && !validateCurrentSplineDxf()) | |||
| 13579 | return false; | |||
| 13580 | if (!loop | |||
| 13581 | || loop->objlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13582 | || (m_dxfLoopEdgeCountExpected >= 0 | |||
| 13583 | && loop->objlist.size() | |||
| 13584 | >= static_cast<std::size_t>(m_dxfLoopEdgeCountExpected))) | |||
| 13585 | return false; | |||
| 13586 | const int edgeType = reader->getInt32(); | |||
| 13587 | if (edgeType == 1){ //line | |||
| 13588 | addLine(); | |||
| 13589 | } else if (edgeType == 2){ //arc | |||
| 13590 | addArc(); | |||
| 13591 | } else if (edgeType == 3){ //elliptic arc | |||
| 13592 | addEllipse(); | |||
| 13593 | } else if (edgeType == 4){ //spline | |||
| 13594 | addSpline(); | |||
| 13595 | } else { | |||
| 13596 | return false; | |||
| 13597 | } | |||
| 13598 | break; | |||
| 13599 | } | |||
| 13600 | case 10: | |||
| 13601 | // Spline edge: 10 is a control-point x-coord. | |||
| 13602 | if (spline) { | |||
| 13603 | if (spline->controllist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13604 | || (m_dxfSplineControlCountExpected >= 0 | |||
| 13605 | && spline->controllist.size() | |||
| 13606 | >= static_cast<std::size_t>(m_dxfSplineControlCountExpected))) | |||
| 13607 | return false; | |||
| 13608 | spline->controllist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0)); | |||
| 13609 | break; | |||
| 13610 | } | |||
| 13611 | if (pt) pt->basePoint.x = reader->getDouble(); | |||
| 13612 | else if (pline) { | |||
| 13613 | if (pline->vertlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13614 | || (m_dxfPolylineVertexCountExpected >= 0 | |||
| 13615 | && pline->vertlist.size() | |||
| 13616 | >= static_cast<std::size_t>(m_dxfPolylineVertexCountExpected))) | |||
| 13617 | return false; | |||
| 13618 | plvert = pline->addVertex(); | |||
| 13619 | plvert->x = reader->getDouble(); | |||
| 13620 | } else if (m_dxfSeedPointsExpected < 0) { | |||
| 13621 | return DRW_Point::parseCode(code, reader); | |||
| 13622 | } else { | |||
| 13623 | // After group 98 the boundary path is closed; seed-point | |||
| 13624 | // coords arrive as group-10/20 pairs. | |||
| 13625 | if (seedPoints.size() >= static_cast<std::size_t>(m_dxfSeedPointsExpected)) | |||
| 13626 | return false; | |||
| 13627 | DRW_Coord seed; | |||
| 13628 | seed.x = reader->getDouble(); | |||
| 13629 | seedPoints.push_back(seed); | |||
| 13630 | } | |||
| 13631 | break; | |||
| 13632 | case 20: | |||
| 13633 | if (spline && !spline->controllist.empty()) { | |||
| 13634 | spline->controllist.back()->y = reader->getDouble(); | |||
| 13635 | break; | |||
| 13636 | } | |||
| 13637 | if (pt) pt->basePoint.y = reader->getDouble(); | |||
| 13638 | else if (plvert) plvert ->y = reader->getDouble(); | |||
| 13639 | else if (m_dxfSeedPointsExpected >= 0) { | |||
| 13640 | if (seedPoints.empty()) | |||
| 13641 | return false; | |||
| 13642 | seedPoints.back().y = reader->getDouble(); | |||
| 13643 | } else { | |||
| 13644 | return DRW_Point::parseCode(code, reader); | |||
| 13645 | } | |||
| 13646 | break; | |||
| 13647 | case 11: | |||
| 13648 | // Spline edge: 11 is a fit-point x-coord. | |||
| 13649 | if (spline) { | |||
| 13650 | if (spline->fitlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13651 | || (m_dxfSplineFitCountExpected >= 0 | |||
| 13652 | && spline->fitlist.size() | |||
| 13653 | >= static_cast<std::size_t>(m_dxfSplineFitCountExpected))) | |||
| 13654 | return false; | |||
| 13655 | spline->fitlist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0)); | |||
| 13656 | break; | |||
| 13657 | } | |||
| 13658 | if (line) line->secPoint.x = reader->getDouble(); | |||
| 13659 | else if (ellipse) ellipse->secPoint.x = reader->getDouble(); | |||
| 13660 | break; | |||
| 13661 | case 21: | |||
| 13662 | if (spline && !spline->fitlist.empty()) { | |||
| 13663 | spline->fitlist.back()->y = reader->getDouble(); | |||
| 13664 | break; | |||
| 13665 | } | |||
| 13666 | if (line) line->secPoint.y = reader->getDouble(); | |||
| 13667 | else if (ellipse) ellipse->secPoint.y = reader->getDouble(); | |||
| 13668 | break; | |||
| 13669 | case 12: | |||
| 13670 | if (spline) { spline->tgStart.x = reader->getDouble(); break; } | |||
| 13671 | break; | |||
| 13672 | case 22: | |||
| 13673 | if (spline) { spline->tgStart.y = reader->getDouble(); break; } | |||
| 13674 | break; | |||
| 13675 | case 13: | |||
| 13676 | if (spline) { spline->tgEnd.x = reader->getDouble(); break; } | |||
| 13677 | break; | |||
| 13678 | case 23: | |||
| 13679 | if (spline) { spline->tgEnd.y = reader->getDouble(); break; } | |||
| 13680 | break; | |||
| 13681 | case 40: | |||
| 13682 | // Spline edge: 40 is a knot value (occurs nknots times). | |||
| 13683 | if (spline) { | |||
| 13684 | if (spline->knotslist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13685 | || (m_dxfSplineKnotCountExpected >= 0 | |||
| 13686 | && spline->knotslist.size() | |||
| 13687 | >= static_cast<std::size_t>(m_dxfSplineKnotCountExpected))) | |||
| 13688 | return false; | |||
| 13689 | spline->knotslist.push_back(reader->getDouble()); | |||
| 13690 | break; | |||
| 13691 | } | |||
| 13692 | if (arc) arc->radious = reader->getDouble(); | |||
| 13693 | else if (ellipse) ellipse->ratio = reader->getDouble(); | |||
| 13694 | break; | |||
| 13695 | case 41: | |||
| 13696 | scale = reader->getDouble(); | |||
| 13697 | break; | |||
| 13698 | case 42: | |||
| 13699 | // Spline edge: 42 is a per-control-point weight. | |||
| 13700 | if (spline) { | |||
| 13701 | if (spline->weightlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13702 | || (m_dxfSplineControlCountExpected >= 0 | |||
| 13703 | && spline->weightlist.size() | |||
| 13704 | >= static_cast<std::size_t>(m_dxfSplineControlCountExpected))) | |||
| 13705 | return false; | |||
| 13706 | spline->weightlist.push_back(reader->getDouble()); | |||
| 13707 | break; | |||
| 13708 | } | |||
| 13709 | if (plvert) plvert ->bulge = reader->getDouble(); | |||
| 13710 | break; | |||
| 13711 | case 50: | |||
| 13712 | if (arc) arc->staangle = reader->getDouble()/ARAD57.29577951308232; | |||
| 13713 | else if (ellipse) ellipse->staparam = reader->getDouble()/ARAD57.29577951308232; | |||
| 13714 | break; | |||
| 13715 | case 51: | |||
| 13716 | if (arc) arc->endangle = reader->getDouble()/ARAD57.29577951308232; | |||
| 13717 | else if (ellipse) ellipse->endparam = reader->getDouble()/ARAD57.29577951308232; | |||
| 13718 | break; | |||
| 13719 | case 47: | |||
| 13720 | pixelSize = reader->getDouble(); | |||
| 13721 | break; | |||
| 13722 | case 52: | |||
| 13723 | angle = reader->getDouble() / ARAD57.29577951308232; | |||
| 13724 | break; | |||
| 13725 | case 53: // pattern line angle — starts a new PatternLine record | |||
| 13726 | if (!validateCurrentPatternLineDxf()) | |||
| 13727 | return false; | |||
| 13728 | if (m_dxfPatternLineCountExpected >= 0 | |||
| 13729 | && patternLines.size() >= static_cast<std::size_t>(m_dxfPatternLineCountExpected)) | |||
| 13730 | return false; | |||
| 13731 | if (patternLines.size() >= static_cast<std::size_t>(kMaxHatchItems)) | |||
| 13732 | return false; | |||
| 13733 | patternLines.push_back(PatternLine()); | |||
| 13734 | patternLines.back().angle = reader->getDouble() / ARAD57.29577951308232; | |||
| 13735 | m_dxfPatternDashCountExpected = -1; | |||
| 13736 | m_dxfPatternDashCountSeen = false; | |||
| 13737 | break; | |||
| 13738 | case 43: | |||
| 13739 | if (!patternLines.empty()) patternLines.back().baseX = reader->getDouble(); | |||
| 13740 | break; | |||
| 13741 | case 44: | |||
| 13742 | if (!patternLines.empty()) patternLines.back().baseY = reader->getDouble(); | |||
| 13743 | break; | |||
| 13744 | case 45: | |||
| 13745 | if (!patternLines.empty()) patternLines.back().offsetX = reader->getDouble(); | |||
| 13746 | break; | |||
| 13747 | case 46: | |||
| 13748 | if (!patternLines.empty()) patternLines.back().offsetY = reader->getDouble(); | |||
| 13749 | break; | |||
| 13750 | case 79: // dash count — the 49s that follow will accumulate | |||
| 13751 | if (patternLines.empty() || m_dxfPatternDashCountSeen) | |||
| 13752 | return false; | |||
| 13753 | m_dxfPatternDashCountExpected = reader->getInt32(); | |||
| 13754 | if (!isValidCount(m_dxfPatternDashCountExpected, kMaxHatchItems)) | |||
| 13755 | return false; | |||
| 13756 | m_dxfPatternDashCountSeen = true; | |||
| 13757 | return DRW::reserve(patternLines.back().dashList, m_dxfPatternDashCountExpected); | |||
| 13758 | case 49: | |||
| 13759 | if (patternLines.empty() | |||
| 13760 | || patternLines.back().dashList.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13761 | || (m_dxfPatternDashCountExpected >= 0 | |||
| 13762 | && patternLines.back().dashList.size() | |||
| 13763 | >= static_cast<std::size_t>(m_dxfPatternDashCountExpected))) | |||
| 13764 | return false; | |||
| 13765 | patternLines.back().dashList.push_back(reader->getDouble()); | |||
| 13766 | break; | |||
| 13767 | case 73: | |||
| 13768 | // Spline edge: 73 is the rational flag (1 = rational). | |||
| 13769 | if (spline) { | |||
| 13770 | if (reader->getInt32()) spline->flags |= 0x4; | |||
| 13771 | break; | |||
| 13772 | } | |||
| 13773 | if (arc) arc->isccw = reader->getInt32(); | |||
| 13774 | // polyline path: 73 is the is-closed flag -> set bit 0 only, leaving the | |||
| 13775 | // rest of pline->flags untouched (order-independent vs code 72). | |||
| 13776 | else if (pline) pline->flags = (pline->flags & ~1) | (reader->getInt32() ? 1 : 0); | |||
| 13777 | break; | |||
| 13778 | case 74: | |||
| 13779 | // Spline edge: 74 is the periodic flag (1 = periodic/closed). | |||
| 13780 | if (spline) { | |||
| 13781 | if (reader->getInt32()) spline->flags |= 0x2; | |||
| 13782 | } | |||
| 13783 | break; | |||
| 13784 | case 94: | |||
| 13785 | // Spline edge degree. | |||
| 13786 | if (spline) { | |||
| 13787 | spline->degree = reader->getInt32(); | |||
| 13788 | return isValidCount(spline->degree, kMaxSplineDegree) | |||
| 13789 | && spline->degree != 0; | |||
| 13790 | } | |||
| 13791 | break; | |||
| 13792 | case 95: | |||
| 13793 | // Spline edge number of knots. | |||
| 13794 | if (spline) { | |||
| 13795 | if (m_dxfSplineKnotCountExpected >= 0) | |||
| 13796 | return false; | |||
| 13797 | spline->nknots = reader->getInt32(); | |||
| 13798 | if (!isValidCount(spline->nknots, kMaxHatchItems)) | |||
| 13799 | return false; | |||
| 13800 | m_dxfSplineKnotCountExpected = spline->nknots; | |||
| 13801 | return DRW::reserve(spline->knotslist, spline->nknots); | |||
| 13802 | } | |||
| 13803 | break; | |||
| 13804 | case 96: | |||
| 13805 | // Spline edge number of control points. | |||
| 13806 | if (spline) { | |||
| 13807 | if (m_dxfSplineControlCountExpected >= 0) | |||
| 13808 | return false; | |||
| 13809 | spline->ncontrol = reader->getInt32(); | |||
| 13810 | if (!isValidCount(spline->ncontrol, kMaxHatchItems)) | |||
| 13811 | return false; | |||
| 13812 | m_dxfSplineControlCountExpected = spline->ncontrol; | |||
| 13813 | return DRW::reserve(spline->controllist, spline->ncontrol); | |||
| 13814 | } | |||
| 13815 | break; | |||
| 13816 | case 97: | |||
| 13817 | if (spline) { | |||
| 13818 | if (!m_splineNfitSet) { | |||
| 13819 | // First 97 in this spline edge = fit-point count (nfit). | |||
| 13820 | spline->nfit = reader->getInt32(); | |||
| 13821 | if (!isValidCount(spline->nfit, kMaxHatchItems)) | |||
| 13822 | return false; | |||
| 13823 | if (m_dxfSplineFitCountExpected >= 0) | |||
| 13824 | return false; | |||
| 13825 | m_dxfSplineFitCountExpected = spline->nfit; | |||
| 13826 | if (!DRW::reserve(spline->fitlist, spline->nfit)) | |||
| 13827 | return false; | |||
| 13828 | if (spline->nfit == 0) { | |||
| 13829 | if (!validateCurrentSplineDxf()) | |||
| 13830 | return false; | |||
| 13831 | // No fit points or tangents follow; safe to clear spline | |||
| 13832 | // so the next code-97 (loop boundary count) is not | |||
| 13833 | // misinterpreted as another nfit. | |||
| 13834 | spline.reset(); | |||
| 13835 | } else { | |||
| 13836 | m_splineNfitSet = true; | |||
| 13837 | } | |||
| 13838 | } else { | |||
| 13839 | // Second 97 while spline is active = loop boundary handle count. | |||
| 13840 | if (!validateCurrentSplineDxf()) | |||
| 13841 | return false; | |||
| 13842 | spline.reset(); | |||
| 13843 | m_splineNfitSet = false; | |||
| 13844 | m_boundaryHandleCount = reader->getInt32(); | |||
| 13845 | if (!isValidCount(m_boundaryHandleCount, kMaxHatchItems)) | |||
| 13846 | return false; | |||
| 13847 | if (m_dxfBoundaryHandleCountSeen) | |||
| 13848 | return false; | |||
| 13849 | m_dxfBoundaryHandleCountSeen = true; | |||
| 13850 | if (m_boundaryHandleCount > 0 && loop | |||
| 13851 | && !DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount)) | |||
| 13852 | return false; | |||
| 13853 | } | |||
| 13854 | break; | |||
| 13855 | } | |||
| 13856 | // No active spline: this is the loop boundary handle count. | |||
| 13857 | m_splineNfitSet = false; | |||
| 13858 | if (m_dxfBoundaryHandleCountSeen) | |||
| 13859 | return false; | |||
| 13860 | m_boundaryHandleCount = reader->getInt32(); | |||
| 13861 | if (!isValidCount(m_boundaryHandleCount, kMaxHatchItems)) | |||
| 13862 | return false; | |||
| 13863 | m_dxfBoundaryHandleCountSeen = true; | |||
| 13864 | if (m_boundaryHandleCount > 0 && loop | |||
| 13865 | && !DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount)) | |||
| 13866 | return false; | |||
| 13867 | break; | |||
| 13868 | case 330: | |||
| 13869 | if (m_boundaryHandleCount > 0 && loop) { | |||
| 13870 | // getHandleString() converts the hex string to int for us. | |||
| 13871 | loop->m_boundaryHandles.push_back( | |||
| 13872 | static_cast<std::uint32_t>(reader->getHandleString())); | |||
| 13873 | --m_boundaryHandleCount; | |||
| 13874 | break; | |||
| 13875 | } | |||
| 13876 | if (m_dxfBoundaryHandleCountSeen) | |||
| 13877 | return false; | |||
| 13878 | return DRW_Point::parseCode(code, reader); | |||
| 13879 | case 75: | |||
| 13880 | hstyle = reader->getInt32(); | |||
| 13881 | break; | |||
| 13882 | case 76: | |||
| 13883 | hpattern = reader->getInt32(); | |||
| 13884 | break; | |||
| 13885 | case 77: | |||
| 13886 | doubleflag = reader->getInt32(); | |||
| 13887 | break; | |||
| 13888 | case 78: | |||
| 13889 | if (m_dxfPatternLineCountSeen) | |||
| 13890 | return false; | |||
| 13891 | deflines = reader->getInt32(); | |||
| 13892 | if (!isValidCount(deflines, kMaxHatchItems)) | |||
| 13893 | return false; | |||
| 13894 | m_dxfPatternLineCountExpected = deflines; | |||
| 13895 | m_dxfPatternLineCountSeen = true; | |||
| 13896 | if (patternLines.size() > static_cast<std::size_t>(deflines)) | |||
| 13897 | return false; | |||
| 13898 | break; | |||
| 13899 | case 91: | |||
| 13900 | if (m_dxfLoopCountSeen) | |||
| 13901 | return false; | |||
| 13902 | loopsnum = reader->getInt32(); | |||
| 13903 | if (!isValidCount(loopsnum, kMaxHatchItems)) | |||
| 13904 | return false; | |||
| 13905 | m_dxfLoopCountExpected = loopsnum; | |||
| 13906 | m_dxfLoopCountSeen = true; | |||
| 13907 | return DRW::reserve( looplist, loopsnum); | |||
| 13908 | case 92: { | |||
| 13909 | if (!validateCurrentBoundaryPathDxf()) | |||
| 13910 | return false; | |||
| 13911 | if (m_dxfLoopCountExpected >= 0 | |||
| 13912 | && looplist.size() >= static_cast<std::size_t>(m_dxfLoopCountExpected)) | |||
| 13913 | return false; | |||
| 13914 | clearEntities(); | |||
| 13915 | m_dxfLoopEdgeCountExpected = -1; | |||
| 13916 | m_dxfLoopEdgeCountSeen = false; | |||
| 13917 | m_dxfPolylineVertexCountExpected = -1; | |||
| 13918 | m_dxfPolylineVertexCountSeen = false; | |||
| 13919 | m_dxfBoundaryHandleCountSeen = false; | |||
| 13920 | m_boundaryHandleCount = 0; | |||
| 13921 | loop = std::make_shared<DRW_HatchLoop>(reader->getInt32()); | |||
| 13922 | looplist.push_back(loop); | |||
| 13923 | if (reader->getInt32() & 2) { | |||
| 13924 | ispol = true; | |||
| 13925 | clearEntities(); | |||
| 13926 | pline = std::make_shared<DRW_LWPolyline>(); | |||
| 13927 | loop->objlist.push_back(pline); | |||
| 13928 | } else ispol = false; | |||
| 13929 | break; | |||
| 13930 | } | |||
| 13931 | case 93: | |||
| 13932 | if (pline) { | |||
| 13933 | if (m_dxfPolylineVertexCountSeen) | |||
| 13934 | return false; | |||
| 13935 | pline->vertexnum = reader->getInt32(); | |||
| 13936 | if (!isValidCount(pline->vertexnum, kMaxHatchItems)) | |||
| 13937 | return false; | |||
| 13938 | m_dxfPolylineVertexCountExpected = pline->vertexnum; | |||
| 13939 | m_dxfPolylineVertexCountSeen = true; | |||
| 13940 | } else if (loop) { | |||
| 13941 | if (m_dxfLoopEdgeCountSeen) | |||
| 13942 | return false; | |||
| 13943 | loop->numedges = reader->getInt32();//aqui reserve | |||
| 13944 | if (!isValidCount(loop->numedges, kMaxHatchItems)) | |||
| 13945 | return false; | |||
| 13946 | if (loop->objlist.size() > static_cast<std::size_t>(loop->numedges)) | |||
| 13947 | return false; | |||
| 13948 | m_dxfLoopEdgeCountExpected = loop->numedges; | |||
| 13949 | m_dxfLoopEdgeCountSeen = true; | |||
| 13950 | } | |||
| 13951 | break; | |||
| 13952 | case 98: { // seed-point count; coords follow as group-10/20 pairs | |||
| 13953 | if (!validateCurrentBoundaryPathDxf() || !validateCurrentPatternLineDxf()) | |||
| 13954 | return false; | |||
| 13955 | if (m_dxfSeedPointCountSeen) | |||
| 13956 | return false; | |||
| 13957 | clearEntities(); | |||
| 13958 | const int count = reader->getInt32(); | |||
| 13959 | if (!isValidCount(count, kMaxHatchItems) | |||
| 13960 | || !DRW::reserve(seedPoints, count)) | |||
| 13961 | return false; | |||
| 13962 | m_dxfSeedPointsExpected = count; | |||
| 13963 | m_dxfSeedPointCountSeen = true; | |||
| 13964 | break; | |||
| 13965 | } | |||
| 13966 | case 450: | |||
| 13967 | isGradient = reader->getInt32(); | |||
| 13968 | break; | |||
| 13969 | case 451: | |||
| 13970 | gradReserved = reader->getInt32(); | |||
| 13971 | break; | |||
| 13972 | case 452: | |||
| 13973 | singleColor = reader->getInt32(); | |||
| 13974 | break; | |||
| 13975 | case 453: { | |||
| 13976 | if (m_dxfGradientColorCountSeen) | |||
| 13977 | return false; | |||
| 13978 | const int n = reader->getInt32(); | |||
| 13979 | if (!isValidCount(n, kMaxHatchItems) | |||
| 13980 | || !DRW::reserve(gradColors, n)) | |||
| 13981 | return false; | |||
| 13982 | m_dxfGradientColorCountExpected = n; | |||
| 13983 | m_dxfGradientColorCountSeen = true; | |||
| 13984 | break; | |||
| 13985 | } | |||
| 13986 | case 460: | |||
| 13987 | gradAngle = reader->getDouble(); | |||
| 13988 | break; | |||
| 13989 | case 461: | |||
| 13990 | gradShift = reader->getDouble(); | |||
| 13991 | break; | |||
| 13992 | case 462: | |||
| 13993 | gradTint = reader->getDouble(); | |||
| 13994 | break; | |||
| 13995 | case 463: { | |||
| 13996 | if (m_dxfGradientColorCountExpected >= 0 | |||
| 13997 | && gradColors.size() >= static_cast<std::size_t>(m_dxfGradientColorCountExpected)) | |||
| 13998 | return false; | |||
| 13999 | if (gradColors.size() >= static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14000 | return false; | |||
| 14001 | DRW_Hatch::GradientStop stop; | |||
| 14002 | stop.value = reader->getDouble(); | |||
| 14003 | gradColors.push_back(stop); | |||
| 14004 | break; | |||
| 14005 | } | |||
| 14006 | case 421: | |||
| 14007 | if (!gradColors.empty()) | |||
| 14008 | gradColors.back().rgb = reader->getInt32(); | |||
| 14009 | break; | |||
| 14010 | case 63: | |||
| 14011 | if (!gradColors.empty()) | |||
| 14012 | gradColors.back().aciColor = reader->getInt32(); | |||
| 14013 | else | |||
| 14014 | return DRW_Point::parseCode(code, reader); | |||
| 14015 | break; | |||
| 14016 | case 431: | |||
| 14017 | if (!gradColors.empty()) | |||
| 14018 | gradColors.back().colorMethod = reader->getInt32(); | |||
| 14019 | break; | |||
| 14020 | case 432: | |||
| 14021 | if (!gradColors.empty()) | |||
| 14022 | gradColors.back().colorName = reader->getUtf8String(); | |||
| 14023 | break; | |||
| 14024 | case 433: | |||
| 14025 | if (!gradColors.empty()) | |||
| 14026 | gradColors.back().colorBookName = reader->getUtf8String(); | |||
| 14027 | break; | |||
| 14028 | case 470: | |||
| 14029 | gradName = reader->getUtf8String(); | |||
| 14030 | break; | |||
| 14031 | default: | |||
| 14032 | return DRW_Point::parseCode(code, reader); | |||
| 14033 | } | |||
| 14034 | ||||
| 14035 | return true; | |||
| 14036 | } | |||
| 14037 | catch (...) { | |||
| 14038 | return false; | |||
| 14039 | } | |||
| 14040 | } | |||
| 14041 | ||||
| 14042 | bool DRW_Hatch::validateCurrentSplineDxf() const { | |||
| 14043 | if (!spline) | |||
| 14044 | return true; | |||
| 14045 | if (m_dxfSplineKnotCountExpected >= 0 | |||
| 14046 | && spline->knotslist.size() | |||
| 14047 | != static_cast<std::size_t>(m_dxfSplineKnotCountExpected)) | |||
| 14048 | return false; | |||
| 14049 | if (m_dxfSplineControlCountExpected >= 0 | |||
| 14050 | && spline->controllist.size() | |||
| 14051 | != static_cast<std::size_t>(m_dxfSplineControlCountExpected)) | |||
| 14052 | return false; | |||
| 14053 | if (m_dxfSplineFitCountExpected >= 0 | |||
| 14054 | && spline->fitlist.size() | |||
| 14055 | != static_cast<std::size_t>(m_dxfSplineFitCountExpected)) | |||
| 14056 | return false; | |||
| 14057 | if (spline->flags & 0x4) | |||
| 14058 | return m_dxfSplineControlCountExpected < 0 | |||
| 14059 | || spline->weightlist.size() | |||
| 14060 | == static_cast<std::size_t>(m_dxfSplineControlCountExpected); | |||
| 14061 | return spline->weightlist.empty(); | |||
| 14062 | } | |||
| 14063 | ||||
| 14064 | bool DRW_Hatch::validateCurrentPatternLineDxf() const { | |||
| 14065 | if (patternLines.empty() || m_dxfPatternDashCountExpected < 0) | |||
| 14066 | return true; | |||
| 14067 | return patternLines.back().dashList.size() | |||
| 14068 | == static_cast<std::size_t>(m_dxfPatternDashCountExpected); | |||
| 14069 | } | |||
| 14070 | ||||
| 14071 | bool DRW_Hatch::validateCurrentBoundaryPathDxf() const { | |||
| 14072 | if (m_boundaryHandleCount != 0 || !validateCurrentSplineDxf()) | |||
| 14073 | return false; | |||
| 14074 | if (!loop) | |||
| 14075 | return true; | |||
| 14076 | if (ispol) { | |||
| 14077 | std::shared_ptr<DRW_LWPolyline> polyline = pline; | |||
| 14078 | if (!polyline && loop->objlist.size() == 1) | |||
| 14079 | polyline = std::dynamic_pointer_cast<DRW_LWPolyline>(loop->objlist.front()); | |||
| 14080 | if (!polyline) | |||
| 14081 | return false; | |||
| 14082 | return !m_dxfPolylineVertexCountSeen | |||
| 14083 | || polyline->vertlist.size() | |||
| 14084 | == static_cast<std::size_t>(m_dxfPolylineVertexCountExpected); | |||
| 14085 | } | |||
| 14086 | return !m_dxfLoopEdgeCountSeen | |||
| 14087 | || loop->objlist.size() | |||
| 14088 | == static_cast<std::size_t>(m_dxfLoopEdgeCountExpected); | |||
| 14089 | } | |||
| 14090 | ||||
| 14091 | bool DRW_Hatch::validateDxf() const { | |||
| 14092 | if (!validateCurrentBoundaryPathDxf() | |||
| 14093 | || !validateCurrentPatternLineDxf()) | |||
| 14094 | return false; | |||
| 14095 | if (m_dxfLoopCountExpected >= 0 | |||
| 14096 | && looplist.size() != static_cast<std::size_t>(m_dxfLoopCountExpected)) | |||
| 14097 | return false; | |||
| 14098 | if (m_dxfPatternLineCountExpected >= 0 | |||
| 14099 | && patternLines.size() | |||
| 14100 | != static_cast<std::size_t>(m_dxfPatternLineCountExpected)) | |||
| 14101 | return false; | |||
| 14102 | if (m_dxfGradientColorCountExpected >= 0 | |||
| 14103 | && gradColors.size() | |||
| 14104 | != static_cast<std::size_t>(m_dxfGradientColorCountExpected)) | |||
| 14105 | return false; | |||
| 14106 | return m_dxfSeedPointsExpected < 0 | |||
| 14107 | || seedPoints.size() == static_cast<std::size_t>(m_dxfSeedPointsExpected); | |||
| 14108 | } | |||
| 14109 | ||||
| 14110 | bool DRW_MPolygon::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 14111 | // MPOLYGON shares HATCH's boundary/pattern/gradient codes but overloads | |||
| 14112 | // several of them: 70 is the version (HATCH stores it as `solid`), 71 is | |||
| 14113 | // the solid flag (HATCH stores it as `associative`), the after-loop 73 | |||
| 14114 | // is annotatedBoundary, and 11/21 is the boundary x-direction vector that | |||
| 14115 | // DRW_Hatch would otherwise feed into a line-edge's end point. m_loopsDone | |||
| 14116 | // flips once the loop list is behind us so late 73/11/21 go to the trailer | |||
| 14117 | // instead of the current loop record. | |||
| 14118 | switch (code) { | |||
| 14119 | case 70: | |||
| 14120 | mpVersion = reader->getInt32(); | |||
| 14121 | return mpVersion >= 0 && mpVersion <= 32767; | |||
| 14122 | case 71: | |||
| 14123 | solid = reader->getInt32() != 0 ? 1 : 0; | |||
| 14124 | return true; | |||
| 14125 | case 76: | |||
| 14126 | // Flip into "trailer" mode first; DRW_Hatch::parseCode stores hpattern. | |||
| 14127 | m_loopsDone = true; | |||
| 14128 | break; | |||
| 14129 | case 73: | |||
| 14130 | if (m_loopsDone) { | |||
| 14131 | annotatedBoundary = reader->getInt32(); | |||
| 14132 | return true; | |||
| 14133 | } | |||
| 14134 | break; // loop's closed bit, let DRW_Hatch::parseCode handle it | |||
| 14135 | case 11: | |||
| 14136 | if (m_loopsDone) { | |||
| 14137 | xDirX = reader->getDouble(); | |||
| 14138 | return true; | |||
| 14139 | } | |||
| 14140 | break; // line-edge end inside an open loop | |||
| 14141 | case 21: | |||
| 14142 | if (m_loopsDone) { | |||
| 14143 | xDirY = reader->getDouble(); | |||
| 14144 | return true; | |||
| 14145 | } | |||
| 14146 | break; | |||
| 14147 | case 63: | |||
| 14148 | if (gradColors.empty()) { fillColorAci = reader->getInt32(); return true; } | |||
| 14149 | break; | |||
| 14150 | case 421: | |||
| 14151 | if (gradColors.empty()) { fillColorRgb = reader->getInt32(); return true; } | |||
| 14152 | break; | |||
| 14153 | case 430: | |||
| 14154 | fillColorName = reader->getUtf8String(); | |||
| 14155 | return true; | |||
| 14156 | case 99: | |||
| 14157 | degenerateLoops = reader->getInt32(); | |||
| 14158 | return true; | |||
| 14159 | default: | |||
| 14160 | break; | |||
| 14161 | } | |||
| 14162 | return DRW_Hatch::parseCode(code, reader); | |||
| 14163 | } | |||
| 14164 | ||||
| 14165 | bool DRW_MPolygon::polylineLoop(const DRW_HatchLoop& loop, DRW_LWPolyline& out) { | |||
| 14166 | out.vertlist.clear(); | |||
| 14167 | out.flags = 1; // closed | |||
| 14168 | // A polyline-loop record (bit 2) carries its single DRW_LWPolyline as the | |||
| 14169 | // only object. Copy it as-is. | |||
| 14170 | if ((loop.type & 2) == 2) { | |||
| 14171 | if (loop.objlist.empty()) | |||
| 14172 | return false; | |||
| 14173 | const DRW_LWPolyline* pl = dynamic_cast<const DRW_LWPolyline*>(loop.objlist.at(0).get()); | |||
| 14174 | if (pl == nullptr) | |||
| 14175 | return false; | |||
| 14176 | for (const std::shared_ptr<DRW_Vertex2D>& v : pl->vertlist) { | |||
| 14177 | if (!v) | |||
| 14178 | return false; | |||
| 14179 | out.vertlist.push_back(std::make_shared<DRW_Vertex2D>(*v)); | |||
| 14180 | } | |||
| 14181 | out.flags = (pl->flags & 1) ? 1 : 0; | |||
| 14182 | return !out.vertlist.empty(); | |||
| 14183 | } | |||
| 14184 | if (loop.objlist.empty()) | |||
| 14185 | return false; | |||
| 14186 | struct Seg { | |||
| 14187 | DRW_Coord p; | |||
| 14188 | DRW_Coord q; | |||
| 14189 | double bulge; | |||
| 14190 | }; | |||
| 14191 | std::vector<Seg> segs; | |||
| 14192 | segs.reserve(loop.objlist.size()); | |||
| 14193 | double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0; | |||
| 14194 | bool bboxInit = false; | |||
| 14195 | auto track = [&](const DRW_Coord& c) { | |||
| 14196 | if (!bboxInit) { | |||
| 14197 | bboxMinX = bboxMaxX = c.x; | |||
| 14198 | bboxMinY = bboxMaxY = c.y; | |||
| 14199 | bboxInit = true; | |||
| 14200 | } else { | |||
| 14201 | bboxMinX = std::min(bboxMinX, c.x); | |||
| 14202 | bboxMaxX = std::max(bboxMaxX, c.x); | |||
| 14203 | bboxMinY = std::min(bboxMinY, c.y); | |||
| 14204 | bboxMaxY = std::max(bboxMaxY, c.y); | |||
| 14205 | } | |||
| 14206 | }; | |||
| 14207 | for (const auto& ownedEdge : loop.objlist) { | |||
| 14208 | const DRW_Entity* edge = ownedEdge.get(); | |||
| 14209 | if (edge == nullptr) | |||
| 14210 | return false; | |||
| 14211 | if (edge->eType == DRW::LINE) { | |||
| 14212 | const DRW_Line* ln = static_cast<const DRW_Line*>(edge); | |||
| 14213 | Seg s{ln->basePoint, ln->secPoint, 0.0}; | |||
| 14214 | track(s.p); | |||
| 14215 | track(s.q); | |||
| 14216 | segs.push_back(s); | |||
| 14217 | } else if (edge->eType == DRW::ARC) { | |||
| 14218 | // Hatch arc convention: isccw selects between (a0, a1) and | |||
| 14219 | // (2*pi - a0, 2*pi - a1); the sweep is signed by direction. | |||
| 14220 | const DRW_Arc* a = static_cast<const DRW_Arc*>(edge); | |||
| 14221 | const int ccw = a->isccw; | |||
| 14222 | double s = ccw ? a->staangle : (2.0 * M_PI3.14159265358979323846 - a->staangle); | |||
| 14223 | double t = ccw ? a->endangle : (2.0 * M_PI3.14159265358979323846 - a->endangle); | |||
| 14224 | const double rawSweep = std::fabs(a->endangle - a->staangle); | |||
| 14225 | double sweep; | |||
| 14226 | if (rawSweep >= 2.0 * M_PI3.14159265358979323846 - 1e-12) { | |||
| 14227 | sweep = 2.0 * M_PI3.14159265358979323846; | |||
| 14228 | } else { | |||
| 14229 | double d = ccw ? (t - s) : (s - t); | |||
| 14230 | while (d < 0.0) d += 2.0 * M_PI3.14159265358979323846; | |||
| 14231 | while (d > 2.0 * M_PI3.14159265358979323846) d -= 2.0 * M_PI3.14159265358979323846; | |||
| 14232 | sweep = d; | |||
| 14233 | } | |||
| 14234 | const double sign = ccw ? +1.0 : -1.0; | |||
| 14235 | if (std::fabs(sweep - 2.0 * M_PI3.14159265358979323846) < 1e-12) { | |||
| 14236 | // Represent a full circle as two half-sweep bulges. | |||
| 14237 | DRW_Coord ps{a->basePoint.x + a->radious * std::cos(s), | |||
| 14238 | a->basePoint.y + a->radious * std::sin(s), | |||
| 14239 | 0.0}; | |||
| 14240 | DRW_Coord mid{2.0 * a->basePoint.x - ps.x, | |||
| 14241 | 2.0 * a->basePoint.y - ps.y, 0.0}; | |||
| 14242 | segs.push_back({ps, mid, sign * 1.0}); | |||
| 14243 | segs.push_back({mid, ps, sign * 1.0}); | |||
| 14244 | track(ps); | |||
| 14245 | track(mid); | |||
| 14246 | } else { | |||
| 14247 | DRW_Coord ps{a->basePoint.x + a->radious * std::cos(s), | |||
| 14248 | a->basePoint.y + a->radious * std::sin(s), | |||
| 14249 | 0.0}; | |||
| 14250 | DRW_Coord qs{a->basePoint.x + a->radious * std::cos(t), | |||
| 14251 | a->basePoint.y + a->radious * std::sin(t), | |||
| 14252 | 0.0}; | |||
| 14253 | segs.push_back({ps, qs, sign * std::tan(sweep / 4.0)}); | |||
| 14254 | track(ps); | |||
| 14255 | track(qs); | |||
| 14256 | } | |||
| 14257 | } else { | |||
| 14258 | // ELLIPSE / SPLINE / unknown: refused, as ezdxf does. | |||
| 14259 | return false; | |||
| 14260 | } | |||
| 14261 | } | |||
| 14262 | const double diag = std::hypot(bboxMaxX - bboxMinX, bboxMaxY - bboxMinY); | |||
| 14263 | const double tol = 1e-9 * std::max(1.0, diag); | |||
| 14264 | for (size_t i = 0; i < segs.size(); ++i) { | |||
| 14265 | const Seg& cur = segs[i]; | |||
| 14266 | const Seg& nxt = segs[(i + 1) % segs.size()]; | |||
| 14267 | if (std::hypot(cur.q.x - nxt.p.x, cur.q.y - nxt.p.y) > tol) | |||
| 14268 | return false; | |||
| 14269 | } | |||
| 14270 | for (const Seg& s : segs) { | |||
| 14271 | auto v = std::make_shared<DRW_Vertex2D>(); | |||
| 14272 | v->x = s.p.x; | |||
| 14273 | v->y = s.p.y; | |||
| 14274 | v->bulge = s.bulge; | |||
| 14275 | out.vertlist.push_back(v); | |||
| 14276 | } | |||
| 14277 | return !out.vertlist.empty(); | |||
| 14278 | } | |||
| 14279 | ||||
| 14280 | // Reset MPOLYGON-only carriers alongside DRW_Hatch::resetDwgState(). Also used | |||
| 14281 | // at the start of parseDwg and inside its fail lambda so a reused entity never | |||
| 14282 | // publishes stale additions after a failed parse. | |||
| 14283 | void DRW_MPolygon::resetMPolygonState() { | |||
| 14284 | fillColorAci = 0; | |||
| 14285 | fillColorRgb = -1; | |||
| 14286 | fillColorName.clear(); | |||
| 14287 | xDirX = 0.0; | |||
| 14288 | xDirY = 0.0; | |||
| 14289 | degenerateLoops = 0; | |||
| 14290 | mpVersion = 1; | |||
| 14291 | annotatedBoundary = 0; | |||
| 14292 | m_loopsDone = false; | |||
| 14293 | } | |||
| 14294 | ||||
| 14295 | // DRW_MPolygon::parseDwg — AcDbMPolygon DWG body in ODA's layout. | |||
| 14296 | // | |||
| 14297 | // AcDbMPolygon is HATCH-derived but has a different DWG body. The leading BS | |||
| 14298 | // is the version (DXF 70), not a style; there is no associative bit and no | |||
| 14299 | // second style BS after the loops; each loop is a `is_closed`/`hasBulge`/BL | |||
| 14300 | // count/vertices record (no derived-boundary bit, no edge paths); and only | |||
| 14301 | // the common entity handles follow — no boundary-source-handle list. The | |||
| 14302 | // trailer is HATCH-foreign too: fill CMC, 2RD x-direction and BL degenerate | |||
| 14303 | // path count instead of HATCH's pixel size and seed points. | |||
| 14304 | // | |||
| 14305 | // Decoded from ODA File Converter output: 8 AC1015 objects accounted to the | |||
| 14306 | // RL bit size, and 24 R2004/R2007/R2010/R2018 objects (including the repo | |||
| 14307 | // fixture) accounted to 0 bits by `mpoly_bitsize_check.py`, | |||
| 14308 | // `mpoly_generic_decode.py` and `mpoly_r2004plus_accounting.py`. | |||
| 14309 | bool DRW_MPolygon::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 14310 | resetDwgState(); | |||
| 14311 | resetMPolygonState(); | |||
| 14312 | dwgBuffer *sourceBuf = buf; | |||
| 14313 | auto fail = [this, sourceBuf]() { | |||
| 14314 | if (sourceBuf != nullptr) | |||
| 14315 | sourceBuf->invalidate(); | |||
| 14316 | resetDwgState(); | |||
| 14317 | resetMPolygonState(); | |||
| 14318 | return false; | |||
| 14319 | }; | |||
| 14320 | if (sourceBuf == nullptr) | |||
| 14321 | return fail(); | |||
| 14322 | ||||
| 14323 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 14324 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 14325 | buf = &bodyProbe; | |||
| 14326 | dwgBuffer *sBuf = version > DRW::AC1018 ? &stringProbe : buf; | |||
| 14327 | if (!DRW_Entity::parseDwg( | |||
| 14328 | version, buf, version > DRW::AC1018 ? &stringProbe : nullptr, bs) | |||
| 14329 | || !buf->isGood() || !sBuf->isGood()) | |||
| 14330 | return fail(); | |||
| 14331 | DRW_DBG("\n***************************** parsing mpolygon *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mpolygon *********************************************\n" ); | |||
| 14332 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 14333 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 14334 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 14335 | if (version > DRW::AC1018) { | |||
| 14336 | stringStartBit = currentDwgBit(sBuf); | |||
| 14337 | if (version > DRW::AC1021) { | |||
| 14338 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 14339 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 14340 | ignoredBodyEndBit, &stringEndBit)) | |||
| 14341 | return fail(); | |||
| 14342 | } | |||
| 14343 | } | |||
| 14344 | ||||
| 14345 | // Leading BS is MPOLYGON's version (DXF code 70), not HATCH's style. ODA | |||
| 14346 | // writes 1; a value above 32767 would overflow DXF's unsigned-16 field, so | |||
| 14347 | // refuse it before taking the parse any further. | |||
| 14348 | std::uint16_t parsedMpVersion = 0; | |||
| 14349 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedMpVersion)) | |||
| 14350 | return fail(); | |||
| 14351 | if (parsedMpVersion > 32767u) | |||
| 14352 | return fail(); | |||
| 14353 | mpVersion = static_cast<int>(parsedMpVersion); | |||
| 14354 | ||||
| 14355 | if (version > DRW::AC1015) { //2004+ gradient (same layout as HATCH) | |||
| 14356 | if (!readBoundedHatchGradient( | |||
| 14357 | *buf, sBuf, bodyEndBit, version, isGradient, gradReserved, | |||
| 14358 | gradAngle, gradShift, singleColor, gradTint, gradName, | |||
| 14359 | gradColors, stringEndBit)) | |||
| 14360 | return fail(); | |||
| 14361 | } | |||
| 14362 | if (!readBoundedBitDouble(*buf, bodyEndBit, basePoint.z) | |||
| 14363 | || !readBoundedBitCoord(*buf, bodyEndBit, extPoint) | |||
| 14364 | || !std::isfinite(basePoint.z) | |||
| 14365 | || !std::isfinite(extPoint.x) | |||
| 14366 | || !std::isfinite(extPoint.y) | |||
| 14367 | || !std::isfinite(extPoint.z)) | |||
| 14368 | return fail(); | |||
| 14369 | UTF8STRINGstd::string parsedName; | |||
| 14370 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 14371 | parsedName.clear(); | |||
| 14372 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 14373 | parsedName)) { | |||
| 14374 | return fail(); | |||
| 14375 | } | |||
| 14376 | bool parsedSolid = false; | |||
| 14377 | // MPOLYGON writes only the solid bit — there is no associative bit between | |||
| 14378 | // the name and the loop count in ODA's layout. associative stays 0. | |||
| 14379 | if (!sBuf->isGood() | |||
| 14380 | || currentDwgBit(sBuf) > stringEndBit | |||
| 14381 | || !readBoundedBit(*buf, bodyEndBit, parsedSolid)) | |||
| 14382 | return fail(); | |||
| 14383 | solid = parsedSolid; | |||
| 14384 | associative = 0; | |||
| 14385 | name = std::move(parsedName); | |||
| 14386 | ||||
| 14387 | // Each MPOLYGON loop is an is_closed/hasBulge/vertex-count record; no | |||
| 14388 | // derived-boundary bit, no edge paths, no boundary-source-handle count. | |||
| 14389 | std::uint32_t parsedLoopCount = 0; | |||
| 14390 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 4, | |||
| 14391 | parsedLoopCount)) | |||
| 14392 | return fail(); | |||
| 14393 | if (!DRW::reserve(looplist, parsedLoopCount)) | |||
| 14394 | return fail(); | |||
| 14395 | loopsnum = static_cast<std::int32_t>(parsedLoopCount); | |||
| 14396 | for (std::uint32_t i = 0; i < parsedLoopCount; ++i) { | |||
| 14397 | bool closed = false; | |||
| 14398 | bool asBulge = false; | |||
| 14399 | if (!proxyEntityHasBits(*buf, bodyEndBit, 2) | |||
| 14400 | || !readBoundedBit(*buf, bodyEndBit, closed) | |||
| 14401 | || !readBoundedBit(*buf, bodyEndBit, asBulge)) | |||
| 14402 | return fail(); | |||
| 14403 | std::uint32_t numVert = 0; | |||
| 14404 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, | |||
| 14405 | asBulge ? 130u : 128u, numVert)) | |||
| 14406 | return fail(); | |||
| 14407 | auto polyline = std::make_shared<DRW_LWPolyline>(); | |||
| 14408 | polyline->flags = closed ? 1 : 0; | |||
| 14409 | polyline->vertexnum = static_cast<int>(numVert); | |||
| 14410 | for (std::uint32_t j = 0; j < numVert; ++j) { | |||
| 14411 | DRW_Vertex2D v; | |||
| 14412 | if (!readBoundedRawDouble(*buf, bodyEndBit, v.x) | |||
| 14413 | || !readBoundedRawDouble(*buf, bodyEndBit, v.y) | |||
| 14414 | || !std::isfinite(v.x) || !std::isfinite(v.y)) | |||
| 14415 | return fail(); | |||
| 14416 | if (asBulge) { | |||
| 14417 | if (!readBoundedBitDouble(*buf, bodyEndBit, v.bulge) | |||
| 14418 | || !std::isfinite(v.bulge)) | |||
| 14419 | return fail(); | |||
| 14420 | } | |||
| 14421 | polyline->addVertex(v); | |||
| 14422 | } | |||
| 14423 | auto hatchLoop = std::make_shared<DRW_HatchLoop>(2); // polyline path | |||
| 14424 | hatchLoop->objlist.push_back(polyline); | |||
| 14425 | hatchLoop->update(); | |||
| 14426 | looplist.push_back(hatchLoop); | |||
| 14427 | } | |||
| 14428 | ||||
| 14429 | std::uint16_t parsedPattern = 0; | |||
| 14430 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedPattern)) | |||
| 14431 | return fail(); | |||
| 14432 | hpattern = parsedPattern; | |||
| 14433 | hstyle = 0; // MPOLYGON has no second style BS; HATCH's second style is absent. | |||
| 14434 | ||||
| 14435 | if (!solid) { | |||
| 14436 | double parsedAngle = 0.0; | |||
| 14437 | double parsedScale = 0.0; | |||
| 14438 | bool parsedDoubleFlag = false; | |||
| 14439 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 14440 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale) | |||
| 14441 | || !readBoundedBit(*buf, bodyEndBit, parsedDoubleFlag) | |||
| 14442 | || !std::isfinite(parsedAngle) | |||
| 14443 | || !std::isfinite(parsedScale)) | |||
| 14444 | return fail(); | |||
| 14445 | angle = parsedAngle; | |||
| 14446 | scale = parsedScale; | |||
| 14447 | doubleflag = parsedDoubleFlag; | |||
| 14448 | std::uint32_t parsedDeflines = 0; | |||
| 14449 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 12, | |||
| 14450 | parsedDeflines)) | |||
| 14451 | return fail(); | |||
| 14452 | if (!DRW::reserve(patternLines, parsedDeflines)) | |||
| 14453 | return fail(); | |||
| 14454 | deflines = static_cast<int>(parsedDeflines); | |||
| 14455 | for (std::uint32_t i = 0; i < parsedDeflines; ++i) { | |||
| 14456 | PatternLine patternLine; | |||
| 14457 | if (!readBoundedBitDouble(*buf, bodyEndBit, patternLine.angle) | |||
| 14458 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseX) | |||
| 14459 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseY) | |||
| 14460 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetX) | |||
| 14461 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetY) | |||
| 14462 | || !std::isfinite(patternLine.angle) | |||
| 14463 | || !std::isfinite(patternLine.baseX) | |||
| 14464 | || !std::isfinite(patternLine.baseY) | |||
| 14465 | || !std::isfinite(patternLine.offsetX) | |||
| 14466 | || !std::isfinite(patternLine.offsetY)) | |||
| 14467 | return fail(); | |||
| 14468 | std::uint32_t numDashL = 0; | |||
| 14469 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 2, | |||
| 14470 | numDashL) | |||
| 14471 | || !proxyEntityHasBits( | |||
| 14472 | *buf, bodyEndBit, static_cast<std::uint64_t>(numDashL) * 2u) | |||
| 14473 | || !DRW::reserve(patternLine.dashList, numDashL)) | |||
| 14474 | return fail(); | |||
| 14475 | for (std::uint32_t d = 0; d < numDashL; ++d) { | |||
| 14476 | double dash = 0.0; | |||
| 14477 | if (!readBoundedBitDouble(*buf, bodyEndBit, dash) | |||
| 14478 | || !std::isfinite(dash)) | |||
| 14479 | return fail(); | |||
| 14480 | patternLine.dashList.push_back(dash); | |||
| 14481 | } | |||
| 14482 | patternLines.push_back(std::move(patternLine)); | |||
| 14483 | } | |||
| 14484 | } | |||
| 14485 | ||||
| 14486 | // MPOLYGON trailer (differs from HATCH): fill CMC + x-direction + degenerate | |||
| 14487 | // path count. No pixel size / seed points here. | |||
| 14488 | std::int32_t rgb = -1; | |||
| 14489 | UTF8STRINGstd::string colName; | |||
| 14490 | std::uint32_t parsedFillColor = 0; | |||
| 14491 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 14492 | parsedFillColor, &rgb, nullptr, &colName)) | |||
| 14493 | return fail(); | |||
| 14494 | fillColorAci = static_cast<int>(parsedFillColor); | |||
| 14495 | fillColorRgb = rgb; | |||
| 14496 | fillColorName = colName; | |||
| 14497 | DRW_Coord xdir; | |||
| 14498 | if (!readBounded2RawDouble(*buf, bodyEndBit, xdir) | |||
| 14499 | || !std::isfinite(xdir.x) || !std::isfinite(xdir.y)) | |||
| 14500 | return fail(); | |||
| 14501 | xDirX = xdir.x; | |||
| 14502 | xDirY = xdir.y; | |||
| 14503 | std::uint32_t parsedDegenerateLoops = 0; | |||
| 14504 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 0, | |||
| 14505 | parsedDegenerateLoops)) | |||
| 14506 | return fail(); | |||
| 14507 | degenerateLoops = static_cast<std::int32_t>(parsedDegenerateLoops); | |||
| 14508 | ||||
| 14509 | // MPOLYGON carries only the common entity handles; HATCH's trailing | |||
| 14510 | // boundary-source-handle list is absent. | |||
| 14511 | std::uint64_t handleEndBit = 0; | |||
| 14512 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 14513 | handleEndBit)) | |||
| 14514 | return fail(); | |||
| 14515 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 14516 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 14517 | handleEndBit) | |||
| 14518 | || !handleProbe.isGood()) | |||
| 14519 | return fail(); | |||
| 14520 | ||||
| 14521 | *sourceBuf = handleProbe; | |||
| 14522 | return true; | |||
| 14523 | } | |||
| 14524 | ||||
| 14525 | // Shared DWG boundary-loop reader for HATCH and MPOLYGON (ODA §20.4.36). | |||
| 14526 | // Reads the loop count and, per loop, the derived-boundary flag plus its edge | |||
| 14527 | // list or polyline. Accumulates the running boundary-source-handle total and | |||
| 14528 | // whether any loop is derived (needs a trailing pixel size). Extracted from | |||
| 14529 | // DRW_Hatch::parseDwg so DRW_MPolygon::parseDwg reuses the identical body while | |||
| 14530 | // supplying its own differing leading (BS style) and trailing (fill CMC + | |||
| 14531 | // x-direction + degenerate count) field order. | |||
| 14532 | bool validateDwgHatchData(const DRW_Hatch& hatch) { | |||
| 14533 | if (hatch.looplist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14534 | || hatch.patternLines.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14535 | || hatch.gradColors.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14536 | || hatch.seedPoints.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14537 | return false; | |||
| 14538 | ||||
| 14539 | for (const auto& loop : hatch.looplist) { | |||
| 14540 | if (!loop | |||
| 14541 | || loop->objlist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14542 | || loop->m_boundaryHandles.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14543 | return false; | |||
| 14544 | ||||
| 14545 | if ((loop->type & 2) != 0) { | |||
| 14546 | if (loop->objlist.size() != 1) | |||
| 14547 | return false; | |||
| 14548 | const auto* polyline = | |||
| 14549 | dynamic_cast<const DRW_LWPolyline*>(loop->objlist.front().get()); | |||
| 14550 | if (!polyline || polyline->vertlist.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14551 | return false; | |||
| 14552 | for (const auto& vertex : polyline->vertlist) { | |||
| 14553 | if (!vertex) | |||
| 14554 | return false; | |||
| 14555 | } | |||
| 14556 | continue; | |||
| 14557 | } | |||
| 14558 | ||||
| 14559 | for (const auto& entity : loop->objlist) { | |||
| 14560 | if (dynamic_cast<const DRW_Line*>(entity.get()) | |||
| 14561 | || dynamic_cast<const DRW_Arc*>(entity.get()) | |||
| 14562 | || dynamic_cast<const DRW_Ellipse*>(entity.get())) { | |||
| 14563 | continue; | |||
| 14564 | } | |||
| 14565 | const auto* spline = dynamic_cast<const DRW_Spline*>(entity.get()); | |||
| 14566 | if (!spline | |||
| 14567 | || spline->knotslist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14568 | || spline->controllist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14569 | || spline->fitlist.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14570 | return false; | |||
| 14571 | for (const auto& point : spline->controllist) { | |||
| 14572 | if (!point) | |||
| 14573 | return false; | |||
| 14574 | } | |||
| 14575 | for (const auto& point : spline->fitlist) { | |||
| 14576 | if (!point) | |||
| 14577 | return false; | |||
| 14578 | } | |||
| 14579 | } | |||
| 14580 | } | |||
| 14581 | ||||
| 14582 | for (const auto& line : hatch.patternLines) { | |||
| 14583 | if (line.dashList.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14584 | return false; | |||
| 14585 | } | |||
| 14586 | return true; | |||
| 14587 | } | |||
| 14588 | ||||
| 14589 | bool DRW_MPolygon::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 14590 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 14591 | dwgBufferW *handleBuf) { | |||
| 14592 | (void)bs; | |||
| 14593 | if (!validateDwgHatchData(*this) | |||
| 14594 | || !isValidCount(degenerateLoops, kMaxHatchItems) | |||
| 14595 | || mpVersion < 0 || mpVersion > 32767 | |||
| 14596 | || annotatedBoundary != 0) | |||
| 14597 | return false; | |||
| 14598 | // Every loop must flatten into a bulge polyline (LINE / ARC only); refuse | |||
| 14599 | // ellipse, spline or any other edge up front so the file stays loss-free. | |||
| 14600 | for (const auto& loop : looplist) { | |||
| 14601 | if (!loop) | |||
| 14602 | return false; | |||
| 14603 | DRW_LWPolyline probe; | |||
| 14604 | if (!polylineLoop(*loop, probe)) | |||
| 14605 | return false; | |||
| 14606 | } | |||
| 14607 | oType = kDwgClassNum; | |||
| 14608 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 14609 | return false; | |||
| 14610 | ||||
| 14611 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 14612 | ||||
| 14613 | // AcDbMPolygon writes the version BS first (DXF code 70), not a style. | |||
| 14614 | buf->putBitShort(static_cast<std::uint16_t>(mpVersion)); | |||
| 14615 | encodeDwgGradientData(version, buf, sb); | |||
| 14616 | ||||
| 14617 | buf->putBitDouble(basePoint.z); | |||
| 14618 | buf->put3BitDouble(extPoint); | |||
| 14619 | sb->putVariableText(version, name); | |||
| 14620 | buf->putBit(static_cast<std::uint8_t>(solid)); | |||
| 14621 | // No associative bit: MPOLYGON is never associative in the ODA layout. | |||
| 14622 | ||||
| 14623 | // Each loop writes as is_closed/hasBulge/vertex-count/vertices; no derived | |||
| 14624 | // bit, no edge paths, no boundary-source-handle count. | |||
| 14625 | buf->putBitLong(static_cast<std::int32_t>(looplist.size())); | |||
| 14626 | for (const auto& loop : looplist) { | |||
| 14627 | DRW_LWPolyline polyline; | |||
| 14628 | if (!polylineLoop(*loop, polyline)) | |||
| 14629 | return false; | |||
| 14630 | const bool closed = (polyline.flags & 1) != 0; | |||
| 14631 | bool asBulge = false; | |||
| 14632 | for (const auto& v : polyline.vertlist) { | |||
| 14633 | if (v && v->bulge != 0.0) { asBulge = true; break; } | |||
| 14634 | } | |||
| 14635 | buf->putBit(static_cast<std::uint8_t>(closed)); | |||
| 14636 | buf->putBit(static_cast<std::uint8_t>(asBulge)); | |||
| 14637 | buf->putBitLong(static_cast<std::int32_t>(polyline.vertlist.size())); | |||
| 14638 | for (const auto& v : polyline.vertlist) { | |||
| 14639 | buf->putRawDouble(v->x); | |||
| 14640 | buf->putRawDouble(v->y); | |||
| 14641 | if (asBulge) | |||
| 14642 | buf->putBitDouble(v->bulge); | |||
| 14643 | } | |||
| 14644 | } | |||
| 14645 | ||||
| 14646 | buf->putBitShort(static_cast<std::uint16_t>(hpattern)); | |||
| 14647 | // No second style BS: hstyle is held locally at 0 and never emitted again. | |||
| 14648 | ||||
| 14649 | if (!solid) { | |||
| 14650 | buf->putBitDouble(angle); | |||
| 14651 | buf->putBitDouble(scale); | |||
| 14652 | buf->putBit(static_cast<std::uint8_t>(doubleflag)); | |||
| 14653 | buf->putBitShort(static_cast<std::uint16_t>(patternLines.size())); | |||
| 14654 | for (const PatternLine& pl : patternLines) { | |||
| 14655 | buf->putBitDouble(pl.angle); | |||
| 14656 | buf->putBitDouble(pl.baseX); | |||
| 14657 | buf->putBitDouble(pl.baseY); | |||
| 14658 | buf->putBitDouble(pl.offsetX); | |||
| 14659 | buf->putBitDouble(pl.offsetY); | |||
| 14660 | buf->putBitShort(static_cast<std::uint16_t>(pl.dashList.size())); | |||
| 14661 | for (double dash : pl.dashList) | |||
| 14662 | buf->putBitDouble(dash); | |||
| 14663 | } | |||
| 14664 | } | |||
| 14665 | ||||
| 14666 | buf->putCmColor(version, | |||
| 14667 | static_cast<std::uint16_t>(fillColorAci), | |||
| 14668 | fillColorRgb, | |||
| 14669 | fillColorName, | |||
| 14670 | {}, | |||
| 14671 | sb); | |||
| 14672 | buf->put2RawDouble(DRW_Coord{xDirX, xDirY, 0.0}); | |||
| 14673 | buf->putBitLong(degenerateLoops); | |||
| 14674 | ||||
| 14675 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 14676 | } | |||
| 14677 | ||||
| 14678 | bool DRW_Hatch::parseDwgBoundaryData(DRW::Version version, dwgBuffer *buf, | |||
| 14679 | std::uint32_t &totalBoundItems, bool &havePixelSize) { | |||
| 14680 | try { | |||
| 14681 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 14682 | std::uint32_t parsedLoopCount = 0; | |||
| 14683 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 4, | |||
| 14684 | parsedLoopCount)) | |||
| 14685 | return false; | |||
| 14686 | if (!DRW::reserve(looplist, parsedLoopCount)) | |||
| 14687 | return false; | |||
| 14688 | loopsnum = static_cast<std::int32_t>(parsedLoopCount); | |||
| 14689 | 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); | |||
| 14690 | DRW_DBG(" loopsnum: ")DRW_dbg::dbg(" loopsnum: "); DRW_DBG(loopsnum)DRW_dbg::dbg(loopsnum); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14691 | ||||
| 14692 | //read loops | |||
| 14693 | for (std::uint32_t i = 0 ; i < parsedLoopCount; ++i){ | |||
| 14694 | std::int32_t loopType = 0; | |||
| 14695 | if (!readBoundedBitLong(*buf, bodyEndBit, loopType) | |||
| 14696 | || loopType < 0) | |||
| 14697 | return false; | |||
| 14698 | loop = std::make_shared<DRW_HatchLoop>(loopType); | |||
| 14699 | havePixelSize = havePixelSize || ((loop->type & 4) != 0); | |||
| 14700 | 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); | |||
| 14701 | if (!(loop->type & 2)){ //Not polyline | |||
| 14702 | std::uint32_t numPathSeg = 0; | |||
| 14703 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 8, | |||
| 14704 | numPathSeg)) | |||
| 14705 | return false; | |||
| 14706 | if (!DRW::reserve(loop->objlist, numPathSeg)) | |||
| 14707 | return false; | |||
| 14708 | DRW_DBG(" numPathSeg: ")DRW_dbg::dbg(" numPathSeg: "); DRW_DBG(numPathSeg)DRW_dbg::dbg(numPathSeg); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14709 | for (std::uint32_t j = 0; j<numPathSeg;++j){ | |||
| 14710 | std::uint8_t typePath = 0; | |||
| 14711 | if (!readBoundedRawChar8(*buf, bodyEndBit, typePath) | |||
| 14712 | || typePath < 1 || typePath > 4) | |||
| 14713 | return false; | |||
| 14714 | 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"); | |||
| 14715 | if (typePath == 1){ //line | |||
| 14716 | DRW_Coord basePoint; | |||
| 14717 | DRW_Coord secPoint; | |||
| 14718 | if (!readBounded2RawDouble(*buf, bodyEndBit, basePoint) | |||
| 14719 | || !readBounded2RawDouble(*buf, bodyEndBit, secPoint)) | |||
| 14720 | return false; | |||
| 14721 | addLine(); | |||
| 14722 | line->basePoint = basePoint; | |||
| 14723 | line->secPoint = secPoint; | |||
| 14724 | } else if (typePath == 2){ //circle arc | |||
| 14725 | DRW_Coord basePoint; | |||
| 14726 | double radius = 0.0; | |||
| 14727 | double startAngle = 0.0; | |||
| 14728 | double endAngle = 0.0; | |||
| 14729 | bool isCcw = false; | |||
| 14730 | if (!readBounded2RawDouble(*buf, bodyEndBit, basePoint) | |||
| 14731 | || !readBoundedBitDouble(*buf, bodyEndBit, radius) | |||
| 14732 | || !readBoundedBitDouble(*buf, bodyEndBit, startAngle) | |||
| 14733 | || !readBoundedBitDouble(*buf, bodyEndBit, endAngle) | |||
| 14734 | || !readBoundedBit(*buf, bodyEndBit, isCcw) | |||
| 14735 | || !std::isfinite(basePoint.x) | |||
| 14736 | || !std::isfinite(basePoint.y) | |||
| 14737 | || !std::isfinite(radius) | |||
| 14738 | || !std::isfinite(startAngle) | |||
| 14739 | || !std::isfinite(endAngle)) | |||
| 14740 | return false; | |||
| 14741 | addArc(); | |||
| 14742 | arc->basePoint = basePoint; | |||
| 14743 | arc->radious = radius; | |||
| 14744 | arc->staangle = startAngle; | |||
| 14745 | arc->endangle = endAngle; | |||
| 14746 | arc->isccw = isCcw; | |||
| 14747 | } else if (typePath == 3){ //ellipse arc | |||
| 14748 | DRW_Coord basePoint; | |||
| 14749 | DRW_Coord secPoint; | |||
| 14750 | double ratio = 0.0; | |||
| 14751 | double startParam = 0.0; | |||
| 14752 | double endParam = 0.0; | |||
| 14753 | bool isCcw = false; | |||
| 14754 | if (!readBounded2RawDouble(*buf, bodyEndBit, basePoint) | |||
| 14755 | || !readBounded2RawDouble(*buf, bodyEndBit, secPoint) | |||
| 14756 | || !readBoundedBitDouble(*buf, bodyEndBit, ratio) | |||
| 14757 | || !readBoundedBitDouble(*buf, bodyEndBit, startParam) | |||
| 14758 | || !readBoundedBitDouble(*buf, bodyEndBit, endParam) | |||
| 14759 | || !readBoundedBit(*buf, bodyEndBit, isCcw) | |||
| 14760 | || !std::isfinite(basePoint.x) | |||
| 14761 | || !std::isfinite(basePoint.y) | |||
| 14762 | || !std::isfinite(secPoint.x) | |||
| 14763 | || !std::isfinite(secPoint.y) | |||
| 14764 | || !std::isfinite(ratio) | |||
| 14765 | || !std::isfinite(startParam) | |||
| 14766 | || !std::isfinite(endParam)) | |||
| 14767 | return false; | |||
| 14768 | addEllipse(); | |||
| 14769 | ellipse->basePoint = basePoint; | |||
| 14770 | ellipse->secPoint = secPoint; | |||
| 14771 | ellipse->ratio = ratio; | |||
| 14772 | ellipse->staparam = startParam; | |||
| 14773 | ellipse->endparam = endParam; | |||
| 14774 | ellipse->isccw = isCcw; | |||
| 14775 | } else if (typePath == 4){ //spline | |||
| 14776 | std::int32_t degree = 0; | |||
| 14777 | bool isRational = false; | |||
| 14778 | bool isPeriodic = false; | |||
| 14779 | if (!readBoundedBitLong(*buf, bodyEndBit, degree) | |||
| 14780 | || !isValidSplineDegree(degree) | |||
| 14781 | || !readBoundedBit(*buf, bodyEndBit, isRational) | |||
| 14782 | || !readBoundedBit(*buf, bodyEndBit, isPeriodic)) | |||
| 14783 | return false; | |||
| 14784 | std::uint32_t knotCount = 0; | |||
| 14785 | if (!readTableBodyCount(version, buf, objSize, | |||
| 14786 | kMaxHatchItems, 2, knotCount)) { | |||
| 14787 | return false; | |||
| 14788 | } | |||
| 14789 | std::uint32_t controlCount = 0; | |||
| 14790 | if (!readTableBodyCount(version, buf, objSize, | |||
| 14791 | kMaxHatchItems, 128, controlCount)) { | |||
| 14792 | return false; | |||
| 14793 | } | |||
| 14794 | DRW_Spline parsedSpline; | |||
| 14795 | parsedSpline.degree = degree; | |||
| 14796 | parsedSpline.nknots = static_cast<std::int32_t>(knotCount); | |||
| 14797 | parsedSpline.ncontrol = static_cast<std::int32_t>(controlCount); | |||
| 14798 | parsedSpline.flags = (isRational ? 4 : 0) | |||
| 14799 | | (isPeriodic ? 2 : 0); | |||
| 14800 | if (!DRW::reserve(parsedSpline.knotslist, knotCount) | |||
| 14801 | || !DRW::reserve(parsedSpline.controllist, controlCount)) | |||
| 14802 | return false; | |||
| 14803 | for (std::uint32_t j = 0; j < knotCount;++j){ | |||
| 14804 | double knot = 0.0; | |||
| 14805 | if (!readBoundedBitDouble(*buf, bodyEndBit, knot) | |||
| 14806 | || !std::isfinite(knot)) | |||
| 14807 | return false; | |||
| 14808 | parsedSpline.knotslist.push_back(knot); | |||
| 14809 | } | |||
| 14810 | for (std::uint32_t j = 0; j < controlCount;++j){ | |||
| 14811 | DRW_Coord control; | |||
| 14812 | if (!readBounded2RawDouble(*buf, bodyEndBit, control) | |||
| 14813 | || !std::isfinite(control.x) | |||
| 14814 | || !std::isfinite(control.y)) | |||
| 14815 | return false; | |||
| 14816 | if (isRational) { | |||
| 14817 | if (!readBoundedBitDouble(*buf, bodyEndBit, control.z) | |||
| 14818 | || !std::isfinite(control.z)) | |||
| 14819 | return false; | |||
| 14820 | } | |||
| 14821 | parsedSpline.controllist.push_back( | |||
| 14822 | std::make_shared<DRW_Coord>(control)); | |||
| 14823 | } | |||
| 14824 | if (version > DRW::AC1021) { //2010+ | |||
| 14825 | std::uint32_t fitCount = 0; | |||
| 14826 | if (!readTableBodyCount(version, buf, objSize, | |||
| 14827 | kMaxHatchItems, 128, fitCount)) | |||
| 14828 | return false; | |||
| 14829 | parsedSpline.nfit = static_cast<std::int32_t>(fitCount); | |||
| 14830 | // Fit points AND the start/end tangents are present only | |||
| 14831 | // when nfit > 0 (matches ACadSharp's `if (nfitPoints > 0)`). | |||
| 14832 | // Reading the two tangents unconditionally on an nfit==0 | |||
| 14833 | // spline edge over-runs the entity body and fails the parse | |||
| 14834 | // (e.g. svg/export_sample.dwg: a degree-3 non-rational | |||
| 14835 | // spline boundary edge with 9 control points / 0 fit points). | |||
| 14836 | if (parsedSpline.nfit > 0) { | |||
| 14837 | if (!DRW::reserve(parsedSpline.fitlist, fitCount)) { | |||
| 14838 | return false; | |||
| 14839 | } | |||
| 14840 | for (std::uint32_t j = 0; j < fitCount;++j){ | |||
| 14841 | DRW_Coord fit; | |||
| 14842 | if (!readBounded2RawDouble(*buf, bodyEndBit, fit) | |||
| 14843 | || !std::isfinite(fit.x) | |||
| 14844 | || !std::isfinite(fit.y)) | |||
| 14845 | return false; | |||
| 14846 | parsedSpline.fitlist.push_back( | |||
| 14847 | std::make_shared<DRW_Coord>(fit)); | |||
| 14848 | } | |||
| 14849 | if (!readBounded2RawDouble(*buf, bodyEndBit, | |||
| 14850 | parsedSpline.tgStart) | |||
| 14851 | || !readBounded2RawDouble(*buf, bodyEndBit, | |||
| 14852 | parsedSpline.tgEnd) | |||
| 14853 | || !std::isfinite(parsedSpline.tgStart.x) | |||
| 14854 | || !std::isfinite(parsedSpline.tgStart.y) | |||
| 14855 | || !std::isfinite(parsedSpline.tgEnd.x) | |||
| 14856 | || !std::isfinite(parsedSpline.tgEnd.y)) | |||
| 14857 | return false; | |||
| 14858 | } | |||
| 14859 | } | |||
| 14860 | addSpline(); | |||
| 14861 | *spline = std::move(parsedSpline); | |||
| 14862 | } | |||
| 14863 | } | |||
| 14864 | } else { //end not pline, start polyline | |||
| 14865 | if (!proxyEntityHasBits(*buf, bodyEndBit, 2)) | |||
| 14866 | return false; | |||
| 14867 | bool asBulge = false; | |||
| 14868 | bool closed = false; | |||
| 14869 | if (!readBoundedBit(*buf, bodyEndBit, asBulge) | |||
| 14870 | || !readBoundedBit(*buf, bodyEndBit, closed)) | |||
| 14871 | return false; | |||
| 14872 | std::uint32_t numVert = 0; | |||
| 14873 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, | |||
| 14874 | 128, numVert)) | |||
| 14875 | return false; | |||
| 14876 | if (!DRW::reserve(loop->objlist, 1)) | |||
| 14877 | return false; | |||
| 14878 | 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); | |||
| 14879 | DRW_DBG(" numVert: ")DRW_dbg::dbg(" numVert: "); DRW_DBG(numVert)DRW_dbg::dbg(numVert); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14880 | std::vector<DRW_Vertex2D> vertices; | |||
| 14881 | if (!DRW::reserve(vertices, numVert)) | |||
| 14882 | return false; | |||
| 14883 | for (std::uint32_t j = 0; j<numVert;++j){ | |||
| 14884 | DRW_Vertex2D v; | |||
| 14885 | if (!readBoundedRawDouble(*buf, bodyEndBit, v.x) | |||
| 14886 | || !readBoundedRawDouble(*buf, bodyEndBit, v.y) | |||
| 14887 | || !std::isfinite(v.x) || !std::isfinite(v.y)) | |||
| 14888 | return false; | |||
| 14889 | if (asBulge | |||
| 14890 | && (!readBoundedBitDouble(*buf, bodyEndBit, v.bulge) | |||
| 14891 | || !std::isfinite(v.bulge))) | |||
| 14892 | return false; | |||
| 14893 | vertices.push_back(v); | |||
| 14894 | } | |||
| 14895 | pline = std::make_shared<DRW_LWPolyline>(); | |||
| 14896 | pline->flags = closed; | |||
| 14897 | for (const DRW_Vertex2D& vertex : vertices) | |||
| 14898 | pline->addVertex(vertex); | |||
| 14899 | loop->objlist.push_back(pline); | |||
| 14900 | }//end polyline | |||
| 14901 | loop->update(); | |||
| 14902 | std::uint32_t boundaryHandleCount = 0; | |||
| 14903 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 0, | |||
| 14904 | boundaryHandleCount) | |||
| 14905 | || totalBoundItems > kMaxHatchItems - boundaryHandleCount) | |||
| 14906 | return false; | |||
| 14907 | looplist.push_back(loop); | |||
| 14908 | totalBoundItems += boundaryHandleCount; | |||
| 14909 | DRW_DBG(" totalBoundItems: ")DRW_dbg::dbg(" totalBoundItems: "); DRW_DBG(totalBoundItems)DRW_dbg::dbg(totalBoundItems); | |||
| 14910 | } //end read loops | |||
| 14911 | return buf->isGood(); | |||
| 14912 | } catch (...) { | |||
| 14913 | return false; | |||
| 14914 | } | |||
| 14915 | } | |||
| 14916 | ||||
| 14917 | bool DRW_Hatch::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 14918 | resetDwgState(); | |||
| 14919 | dwgBuffer *sourceBuf = buf; | |||
| 14920 | auto fail = [this, sourceBuf]() { | |||
| 14921 | if (sourceBuf != nullptr) | |||
| 14922 | sourceBuf->invalidate(); | |||
| 14923 | resetDwgState(); | |||
| 14924 | return false; | |||
| 14925 | }; | |||
| 14926 | if (sourceBuf == nullptr) | |||
| 14927 | return fail(); | |||
| 14928 | ||||
| 14929 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 14930 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 14931 | buf = &bodyProbe; | |||
| 14932 | dwgBuffer *sBuf = version > DRW::AC1018 ? &stringProbe : buf; | |||
| 14933 | std::uint32_t totalBoundItems = 0; | |||
| 14934 | bool havePixelSize = false; | |||
| 14935 | ||||
| 14936 | bool ret = DRW_Entity::parseDwg( | |||
| 14937 | version, buf, version > DRW::AC1018 ? &stringProbe : nullptr, bs); | |||
| 14938 | if (!ret || !buf->isGood() || !sBuf->isGood()) | |||
| 14939 | return fail(); | |||
| 14940 | DRW_DBG("\n***************************** parsing hatch *********************************************\n")DRW_dbg::dbg("\n***************************** parsing hatch *********************************************\n" ); | |||
| 14941 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 14942 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 14943 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 14944 | if (version > DRW::AC1018) { | |||
| 14945 | stringStartBit = currentDwgBit(sBuf); | |||
| 14946 | if (version > DRW::AC1021) { | |||
| 14947 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 14948 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 14949 | ignoredBodyEndBit, &stringEndBit)) | |||
| 14950 | return fail(); | |||
| 14951 | } | |||
| 14952 | } | |||
| 14953 | ||||
| 14954 | if (version > DRW::AC1015) { //2004+ | |||
| 14955 | if (!readBoundedHatchGradient( | |||
| 14956 | *buf, sBuf, bodyEndBit, version, isGradient, gradReserved, | |||
| 14957 | gradAngle, gradShift, singleColor, gradTint, gradName, | |||
| 14958 | gradColors, stringEndBit)) | |||
| 14959 | return fail(); | |||
| 14960 | 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"); | |||
| 14961 | } | |||
| 14962 | DRW_Coord parsedBasePoint = basePoint; | |||
| 14963 | DRW_Coord parsedExtPoint; | |||
| 14964 | UTF8STRINGstd::string parsedName; | |||
| 14965 | bool parsedSolid = false; | |||
| 14966 | bool parsedAssociative = false; | |||
| 14967 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedBasePoint.z) | |||
| 14968 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtPoint) | |||
| 14969 | || !std::isfinite(parsedBasePoint.z) | |||
| 14970 | || !std::isfinite(parsedExtPoint.x) | |||
| 14971 | || !std::isfinite(parsedExtPoint.y) | |||
| 14972 | || !std::isfinite(parsedExtPoint.z)) | |||
| 14973 | return fail(); | |||
| 14974 | DRW_DBG("base point: ")DRW_dbg::dbg("base point: "); DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y,DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z) | |||
| 14975 | parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 14976 | DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(parsedExtPoint.x, parsedExtPoint.y,DRW_dbg::dbgPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint .z) | |||
| 14977 | parsedExtPoint.z)DRW_dbg::dbgPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint .z); | |||
| 14978 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 14979 | parsedName.clear(); | |||
| 14980 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 14981 | parsedName)) { | |||
| 14982 | return fail(); | |||
| 14983 | } | |||
| 14984 | if (!sBuf->isGood() | |||
| 14985 | || currentDwgBit(sBuf) > stringEndBit | |||
| 14986 | || !readBoundedBit(*buf, bodyEndBit, parsedSolid) | |||
| 14987 | || !readBoundedBit(*buf, bodyEndBit, parsedAssociative)) | |||
| 14988 | return fail(); | |||
| 14989 | basePoint = parsedBasePoint; | |||
| 14990 | extPoint = parsedExtPoint; | |||
| 14991 | name = std::move(parsedName); | |||
| 14992 | solid = parsedSolid; | |||
| 14993 | associative = parsedAssociative; | |||
| 14994 | 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"); | |||
| 14995 | if (!parseDwgBoundaryData(version, buf, totalBoundItems, havePixelSize)) | |||
| 14996 | return fail(); | |||
| 14997 | ||||
| 14998 | std::uint16_t parsedStyle = 0; | |||
| 14999 | std::uint16_t parsedPattern = 0; | |||
| 15000 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedStyle) | |||
| 15001 | || !readBoundedBitShort(*buf, bodyEndBit, parsedPattern)) | |||
| 15002 | return fail(); | |||
| 15003 | hstyle = parsedStyle; | |||
| 15004 | hpattern = parsedPattern; | |||
| 15005 | 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); | |||
| 15006 | if (!solid){ | |||
| 15007 | double parsedAngle = 0.0; | |||
| 15008 | double parsedScale = 0.0; | |||
| 15009 | bool parsedDoubleFlag = false; | |||
| 15010 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 15011 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale) | |||
| 15012 | || !readBoundedBit(*buf, bodyEndBit, parsedDoubleFlag) | |||
| 15013 | || !std::isfinite(parsedAngle) | |||
| 15014 | || !std::isfinite(parsedScale)) | |||
| 15015 | return fail(); | |||
| 15016 | angle = parsedAngle; | |||
| 15017 | scale = parsedScale; | |||
| 15018 | doubleflag = parsedDoubleFlag; | |||
| 15019 | std::uint32_t parsedDeflines = 0; | |||
| 15020 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 12, | |||
| 15021 | parsedDeflines)) | |||
| 15022 | return fail(); | |||
| 15023 | deflines = static_cast<int>(parsedDeflines); | |||
| 15024 | for (std::uint32_t i = 0 ; i < parsedDeflines; ++i){ | |||
| 15025 | PatternLine patternLine; | |||
| 15026 | if (!readBoundedBitDouble(*buf, bodyEndBit, patternLine.angle) | |||
| 15027 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseX) | |||
| 15028 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseY) | |||
| 15029 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetX) | |||
| 15030 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetY) | |||
| 15031 | || !std::isfinite(patternLine.angle) | |||
| 15032 | || !std::isfinite(patternLine.baseX) | |||
| 15033 | || !std::isfinite(patternLine.baseY) | |||
| 15034 | || !std::isfinite(patternLine.offsetX) | |||
| 15035 | || !std::isfinite(patternLine.offsetY)) | |||
| 15036 | return fail(); | |||
| 15037 | std::uint32_t numDashL = 0; | |||
| 15038 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 2, | |||
| 15039 | numDashL) | |||
| 15040 | || !proxyEntityHasBits( | |||
| 15041 | *buf, bodyEndBit, static_cast<std::uint64_t>(numDashL) * 2u) | |||
| 15042 | || !DRW::reserve(patternLine.dashList, numDashL)) | |||
| 15043 | return fail(); | |||
| 15044 | DRW_DBG("\ndef line: ")DRW_dbg::dbg("\ndef line: "); DRW_DBG(patternLine.angle)DRW_dbg::dbg(patternLine.angle); DRW_DBG(",")DRW_dbg::dbg(","); | |||
| 15045 | DRW_DBG(patternLine.baseX)DRW_dbg::dbg(patternLine.baseX); DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(patternLine.baseY)DRW_dbg::dbg(patternLine.baseY); | |||
| 15046 | DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(patternLine.offsetX)DRW_dbg::dbg(patternLine.offsetX); DRW_DBG(",")DRW_dbg::dbg(","); | |||
| 15047 | DRW_DBG(patternLine.offsetY)DRW_dbg::dbg(patternLine.offsetY); | |||
| 15048 | for (std::uint32_t i = 0 ; i < numDashL; ++i){ | |||
| 15049 | double lengthL = 0.0; | |||
| 15050 | if (!readBoundedBitDouble(*buf, bodyEndBit, lengthL) | |||
| 15051 | || !std::isfinite(lengthL)) | |||
| 15052 | return fail(); | |||
| 15053 | patternLine.dashList.push_back(lengthL); | |||
| 15054 | DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(lengthL)DRW_dbg::dbg(lengthL); | |||
| 15055 | } | |||
| 15056 | patternLines.push_back(std::move(patternLine)); | |||
| 15057 | }//end deflines | |||
| 15058 | } //end not solid | |||
| 15059 | ||||
| 15060 | if (havePixelSize){ | |||
| 15061 | if (!readBoundedBitDouble(*buf, bodyEndBit, pixelSize) | |||
| 15062 | || !std::isfinite(pixelSize)) | |||
| 15063 | return fail(); | |||
| 15064 | DRW_DBG("\npixel size: ")DRW_dbg::dbg("\npixel size: "); DRW_DBG(pixelSize)DRW_dbg::dbg(pixelSize); | |||
| 15065 | } | |||
| 15066 | std::uint32_t numSeedPoints = 0; | |||
| 15067 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 128, | |||
| 15068 | numSeedPoints) | |||
| 15069 | || !proxyEntityHasBits( | |||
| 15070 | *buf, bodyEndBit, static_cast<std::uint64_t>(numSeedPoints) * 128u) | |||
| 15071 | || !DRW::reserve(seedPoints, numSeedPoints)) | |||
| 15072 | return fail(); | |||
| 15073 | DRW_DBG("\nnum Seed Points ")DRW_dbg::dbg("\nnum Seed Points "); DRW_DBG(numSeedPoints)DRW_dbg::dbg(numSeedPoints); | |||
| 15074 | for (std::uint32_t i = 0 ; i < numSeedPoints; ++i){ | |||
| 15075 | DRW_Coord seedPt; | |||
| 15076 | if (!readBounded2RawDouble(*buf, bodyEndBit, seedPt) | |||
| 15077 | || !std::isfinite(seedPt.x) | |||
| 15078 | || !std::isfinite(seedPt.y)) | |||
| 15079 | return fail(); | |||
| 15080 | 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); | |||
| 15081 | seedPoints.push_back(seedPt); | |||
| 15082 | } | |||
| 15083 | ||||
| 15084 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15085 | std::uint64_t handleEndBit = 0; | |||
| 15086 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 15087 | handleEndBit)) | |||
| 15088 | return fail(); | |||
| 15089 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 15090 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 15091 | handleEndBit); | |||
| 15092 | if (!ret || !handleProbe.isGood()) | |||
| 15093 | return fail(); | |||
| 15094 | 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"); | |||
| 15095 | ||||
| 15096 | for (std::uint32_t i = 0 ; i < totalBoundItems; ++i){ | |||
| 15097 | dwgHandle biH; | |||
| 15098 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 15099 | biH)) | |||
| 15100 | return fail(); | |||
| 15101 | 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); | |||
| 15102 | } | |||
| 15103 | 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"); | |||
| 15104 | // RS crc; //RS */ | |||
| 15105 | if (!handleProbe.isGood()) | |||
| 15106 | return fail(); | |||
| 15107 | *sourceBuf = handleProbe; | |||
| 15108 | return true; | |||
| 15109 | } | |||
| 15110 | ||||
| 15111 | void DRW_Hatch::encodeDwgGradientData(DRW::Version version, dwgBufferW *buf, | |||
| 15112 | dwgBufferW *strBuf) const { | |||
| 15113 | if (version <= DRW::AC1015) | |||
| 15114 | return; | |||
| 15115 | ||||
| 15116 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 15117 | buf->putBitLong(isGradient); | |||
| ||||
| 15118 | buf->putBitLong(gradReserved); | |||
| 15119 | buf->putBitDouble(gradAngle); | |||
| 15120 | buf->putBitDouble(gradShift); | |||
| 15121 | buf->putBitLong(singleColor); | |||
| 15122 | buf->putBitDouble(gradTint); | |||
| 15123 | buf->putBitLong(static_cast<std::int32_t>(gradColors.size())); | |||
| 15124 | for (const GradientStop& stop : gradColors) { | |||
| 15125 | buf->putBitDouble(stop.value); | |||
| 15126 | buf->putBitShort(static_cast<std::uint16_t>(stop.aciColor)); | |||
| 15127 | buf->putBitLong(static_cast<std::uint32_t>(stop.rgb)); | |||
| 15128 | buf->putRawChar8(0); | |||
| 15129 | } | |||
| 15130 | sb->putVariableText(version, gradName); | |||
| 15131 | } | |||
| 15132 | ||||
| 15133 | bool DRW_Hatch::encodeDwgBoundaryData(DRW::Version version, dwgBufferW *buf, | |||
| 15134 | bool includePixelSize) const { | |||
| 15135 | buf->putBitLong(static_cast<std::int32_t>(looplist.size())); | |||
| 15136 | ||||
| 15137 | for (const auto& lp : looplist) { | |||
| 15138 | buf->putBitLong(includePixelSize ? lp->type : lp->type & ~4); | |||
| 15139 | ||||
| 15140 | if (!(lp->type & 2)) { | |||
| 15141 | buf->putBitLong(static_cast<std::int32_t>(lp->objlist.size())); | |||
| 15142 | for (const auto& seg : lp->objlist) { | |||
| 15143 | if (const auto* ln = dynamic_cast<const DRW_Line*>(seg.get())) { | |||
| 15144 | buf->putRawChar8(1); // line | |||
| 15145 | buf->put2RawDouble(ln->basePoint); | |||
| 15146 | buf->put2RawDouble(ln->secPoint); | |||
| 15147 | } else if (const auto* arc = dynamic_cast<const DRW_Arc*>(seg.get())) { | |||
| 15148 | buf->putRawChar8(2); // circular arc | |||
| 15149 | buf->put2RawDouble(arc->basePoint); | |||
| 15150 | buf->putBitDouble(arc->radious); | |||
| 15151 | buf->putBitDouble(arc->staangle); | |||
| 15152 | buf->putBitDouble(arc->endangle); | |||
| 15153 | buf->putBit(static_cast<std::uint8_t>(arc->isccw)); | |||
| 15154 | } else if (const auto* el = dynamic_cast<const DRW_Ellipse*>(seg.get())) { | |||
| 15155 | buf->putRawChar8(3); // ellipse arc | |||
| 15156 | buf->put2RawDouble(el->basePoint); | |||
| 15157 | buf->put2RawDouble(el->secPoint); | |||
| 15158 | buf->putBitDouble(el->ratio); | |||
| 15159 | buf->putBitDouble(el->staparam); | |||
| 15160 | buf->putBitDouble(el->endparam); | |||
| 15161 | buf->putBit(static_cast<std::uint8_t>(el->isccw)); | |||
| 15162 | } else if (const auto* sp = dynamic_cast<const DRW_Spline*>(seg.get())) { | |||
| 15163 | buf->putRawChar8(4); // spline | |||
| 15164 | buf->putBitLong(sp->degree); | |||
| 15165 | bool isRational = (sp->flags & 4) != 0; | |||
| 15166 | bool isPeriodic = (sp->flags & 2) != 0; | |||
| 15167 | buf->putBit(static_cast<std::uint8_t>(isRational)); | |||
| 15168 | buf->putBit(static_cast<std::uint8_t>(isPeriodic)); | |||
| 15169 | buf->putBitLong(static_cast<std::int32_t>(sp->knotslist.size())); | |||
| 15170 | buf->putBitLong(static_cast<std::int32_t>(sp->controllist.size())); | |||
| 15171 | for (double k : sp->knotslist) | |||
| 15172 | buf->putBitDouble(k); | |||
| 15173 | for (const auto& cp : sp->controllist) { | |||
| 15174 | DRW_Coord c2{cp->x, cp->y, 0.0}; | |||
| 15175 | buf->put2RawDouble(c2); | |||
| 15176 | if (isRational) | |||
| 15177 | buf->putBitDouble(cp->z); | |||
| 15178 | } | |||
| 15179 | if (version > DRW::AC1021) { | |||
| 15180 | buf->putBitLong(static_cast<std::int32_t>(sp->fitlist.size())); | |||
| 15181 | for (const auto& fp : sp->fitlist) { | |||
| 15182 | DRW_Coord f2{fp->x, fp->y, 0.0}; | |||
| 15183 | buf->put2RawDouble(f2); | |||
| 15184 | } | |||
| 15185 | buf->put2RawDouble(sp->tgStart); | |||
| 15186 | buf->put2RawDouble(sp->tgEnd); | |||
| 15187 | } | |||
| 15188 | } else { | |||
| 15189 | return false; | |||
| 15190 | } | |||
| 15191 | } | |||
| 15192 | } else { | |||
| 15193 | const DRW_LWPolyline* pl = nullptr; | |||
| 15194 | if (!lp->objlist.empty()) | |||
| 15195 | pl = dynamic_cast<const DRW_LWPolyline*>(lp->objlist[0].get()); | |||
| 15196 | if (!pl) | |||
| 15197 | return false; | |||
| 15198 | ||||
| 15199 | bool asBulge = false; | |||
| 15200 | for (const auto& v : pl->vertlist) | |||
| 15201 | if (v->bulge != 0.0) { asBulge = true; break; } | |||
| 15202 | ||||
| 15203 | buf->putBit(static_cast<std::uint8_t>(asBulge)); | |||
| 15204 | buf->putBit(static_cast<std::uint8_t>(pl->flags & 1)); | |||
| 15205 | buf->putBitLong(static_cast<std::int32_t>(pl->vertlist.size())); | |||
| 15206 | for (const auto& v : pl->vertlist) { | |||
| 15207 | buf->putRawDouble(v->x); | |||
| 15208 | buf->putRawDouble(v->y); | |||
| 15209 | if (asBulge) | |||
| 15210 | buf->putBitDouble(v->bulge); | |||
| 15211 | } | |||
| 15212 | } | |||
| 15213 | ||||
| 15214 | buf->putBitLong(0); // numBoundHandles for this loop (0 = non-associative) | |||
| 15215 | } | |||
| 15216 | ||||
| 15217 | return true; | |||
| 15218 | } | |||
| 15219 | ||||
| 15220 | bool DRW_Hatch::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 15221 | (void)bs; | |||
| 15222 | if (!validateDwgHatchData(*this)) | |||
| ||||
| 15223 | return false; | |||
| 15224 | oType = 78; // HATCH class id — see dwgreader.cpp:1380 | |||
| 15225 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 15226 | ||||
| 15227 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 15228 | encodeDwgGradientData(version, buf, sb); | |||
| 15229 | ||||
| 15230 | buf->putBitDouble(basePoint.z); // BD: elevation | |||
| 15231 | buf->put3BitDouble(extPoint); // 3BD: extrusion (NOT BE-style for HATCH) | |||
| 15232 | sb->putVariableText(version, name); // TV: hatch pattern name | |||
| 15233 | buf->putBit(static_cast<std::uint8_t>(solid)); | |||
| 15234 | buf->putBit(static_cast<std::uint8_t>(associative)); | |||
| 15235 | if (!encodeDwgBoundaryData(version, buf, true)) return false; | |||
| 15236 | ||||
| 15237 | buf->putBitShort(static_cast<std::uint16_t>(hstyle)); | |||
| 15238 | buf->putBitShort(static_cast<std::uint16_t>(hpattern)); | |||
| 15239 | ||||
| 15240 | if (!solid) { | |||
| 15241 | buf->putBitDouble(angle); | |||
| 15242 | buf->putBitDouble(scale); | |||
| 15243 | buf->putBit(static_cast<std::uint8_t>(doubleflag)); | |||
| 15244 | buf->putBitShort(static_cast<std::uint16_t>(patternLines.size())); | |||
| 15245 | for (const PatternLine& patternLine : patternLines) { | |||
| 15246 | buf->putBitDouble(patternLine.angle); | |||
| 15247 | buf->putBitDouble(patternLine.baseX); | |||
| 15248 | buf->putBitDouble(patternLine.baseY); | |||
| 15249 | buf->putBitDouble(patternLine.offsetX); | |||
| 15250 | buf->putBitDouble(patternLine.offsetY); | |||
| 15251 | buf->putBitShort(static_cast<std::uint16_t>(patternLine.dashList.size())); | |||
| 15252 | for (double dash : patternLine.dashList) | |||
| 15253 | buf->putBitDouble(dash); | |||
| 15254 | } | |||
| 15255 | } | |||
| 15256 | ||||
| 15257 | bool havePixelSize = false; | |||
| 15258 | for (const auto& lp : looplist) | |||
| 15259 | havePixelSize = havePixelSize || (lp && ((lp->type & 4) != 0)); | |||
| 15260 | if (havePixelSize) | |||
| 15261 | buf->putBitDouble(pixelSize); | |||
| 15262 | ||||
| 15263 | buf->putBitLong(static_cast<std::int32_t>(seedPoints.size())); | |||
| 15264 | for (const auto& sp : seedPoints) { | |||
| 15265 | buf->putRawDouble(sp.x); | |||
| 15266 | buf->putRawDouble(sp.y); | |||
| 15267 | } | |||
| 15268 | ||||
| 15269 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 15270 | return true; | |||
| 15271 | } | |||
| 15272 | ||||
| 15273 | bool DRW_Spline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 15274 | switch (code) { | |||
| 15275 | case 210: | |||
| 15276 | normalVec.x = reader->getDouble(); | |||
| 15277 | break; | |||
| 15278 | case 220: | |||
| 15279 | normalVec.y = reader->getDouble(); | |||
| 15280 | break; | |||
| 15281 | case 230: | |||
| 15282 | normalVec.z = reader->getDouble(); | |||
| 15283 | break; | |||
| 15284 | case 12: | |||
| 15285 | tgStart.x = reader->getDouble(); | |||
| 15286 | break; | |||
| 15287 | case 22: | |||
| 15288 | tgStart.y = reader->getDouble(); | |||
| 15289 | break; | |||
| 15290 | case 32: | |||
| 15291 | tgStart.z = reader->getDouble(); | |||
| 15292 | break; | |||
| 15293 | case 13: | |||
| 15294 | tgEnd.x = reader->getDouble(); | |||
| 15295 | break; | |||
| 15296 | case 23: | |||
| 15297 | tgEnd.y = reader->getDouble(); | |||
| 15298 | break; | |||
| 15299 | case 33: | |||
| 15300 | tgEnd.z = reader->getDouble(); | |||
| 15301 | break; | |||
| 15302 | case 70: | |||
| 15303 | flags = reader->getInt32(); | |||
| 15304 | break; | |||
| 15305 | case 71: | |||
| 15306 | degree = reader->getInt32(); | |||
| 15307 | if (!isValidCount(degree, kMaxDxfDegree) || degree == 0) | |||
| 15308 | return false; | |||
| 15309 | m_dxfDegreeSeen = true; | |||
| 15310 | break; | |||
| 15311 | case 72: | |||
| 15312 | if (m_dxfKnotCountSeen) | |||
| 15313 | return false; | |||
| 15314 | nknots = reader->getInt32(); | |||
| 15315 | if (!isValidCount(nknots, kMaxDxfItems)) | |||
| 15316 | return false; | |||
| 15317 | m_dxfKnotCountSeen = true; | |||
| 15318 | break; | |||
| 15319 | case 73: | |||
| 15320 | if (m_dxfControlCountSeen) | |||
| 15321 | return false; | |||
| 15322 | ncontrol = reader->getInt32(); | |||
| 15323 | if (!isValidCount(ncontrol, kMaxDxfItems)) | |||
| 15324 | return false; | |||
| 15325 | m_dxfControlCountSeen = true; | |||
| 15326 | break; | |||
| 15327 | case 74: | |||
| 15328 | if (m_dxfFitCountSeen) | |||
| 15329 | return false; | |||
| 15330 | nfit = reader->getInt32(); | |||
| 15331 | if (!isValidCount(nfit, kMaxDxfItems)) | |||
| 15332 | return false; | |||
| 15333 | m_dxfFitCountSeen = true; | |||
| 15334 | break; | |||
| 15335 | case 42: | |||
| 15336 | tolknot = reader->getDouble(); | |||
| 15337 | break; | |||
| 15338 | case 43: | |||
| 15339 | tolcontrol = reader->getDouble(); | |||
| 15340 | break; | |||
| 15341 | case 44: | |||
| 15342 | tolfit = reader->getDouble(); | |||
| 15343 | break; | |||
| 15344 | case 10: { | |||
| 15345 | if (controllist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 15346 | || (m_dxfControlCountSeen | |||
| 15347 | && controllist.size() >= static_cast<std::size_t>(ncontrol))) | |||
| 15348 | return false; | |||
| 15349 | controlpoint = std::make_shared<DRW_Coord>(); | |||
| 15350 | controllist.push_back(controlpoint); | |||
| 15351 | controlpoint->x = reader->getDouble(); | |||
| 15352 | break; } | |||
| 15353 | case 20: | |||
| 15354 | if(controlpoint) | |||
| 15355 | controlpoint->y = reader->getDouble(); | |||
| 15356 | break; | |||
| 15357 | case 30: | |||
| 15358 | if(controlpoint) | |||
| 15359 | controlpoint->z = reader->getDouble(); | |||
| 15360 | break; | |||
| 15361 | case 11: { | |||
| 15362 | if (fitlist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 15363 | || (m_dxfFitCountSeen | |||
| 15364 | && fitlist.size() >= static_cast<std::size_t>(nfit))) | |||
| 15365 | return false; | |||
| 15366 | fitpoint = std::make_shared<DRW_Coord>(); | |||
| 15367 | fitlist.push_back(fitpoint); | |||
| 15368 | fitpoint->x = reader->getDouble(); | |||
| 15369 | break; } | |||
| 15370 | case 21: | |||
| 15371 | if(fitpoint) | |||
| 15372 | fitpoint->y = reader->getDouble(); | |||
| 15373 | break; | |||
| 15374 | case 31: | |||
| 15375 | if(fitpoint) | |||
| 15376 | fitpoint->z = reader->getDouble(); | |||
| 15377 | break; | |||
| 15378 | case 40: | |||
| 15379 | if (knotslist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 15380 | || (m_dxfKnotCountSeen | |||
| 15381 | && knotslist.size() >= static_cast<std::size_t>(nknots))) | |||
| 15382 | return false; | |||
| 15383 | knotslist.push_back(reader->getDouble()); | |||
| 15384 | break; | |||
| 15385 | case 41: | |||
| 15386 | if (weightlist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 15387 | || (m_dxfControlCountSeen | |||
| 15388 | && weightlist.size() >= static_cast<std::size_t>(ncontrol))) | |||
| 15389 | return false; | |||
| 15390 | weightlist.push_back(reader->getDouble()); | |||
| 15391 | break; | |||
| 15392 | default: | |||
| 15393 | return DRW_Entity::parseCode(code, reader); | |||
| 15394 | } | |||
| 15395 | ||||
| 15396 | return true; | |||
| 15397 | } | |||
| 15398 | ||||
| 15399 | bool DRW_Spline::validateDxf() const { | |||
| 15400 | if (m_dxfKnotCountSeen | |||
| 15401 | && knotslist.size() != static_cast<std::size_t>(nknots)) | |||
| 15402 | return false; | |||
| 15403 | if (m_dxfControlCountSeen | |||
| 15404 | && controllist.size() != static_cast<std::size_t>(ncontrol)) | |||
| 15405 | return false; | |||
| 15406 | if (m_dxfFitCountSeen | |||
| 15407 | && fitlist.size() != static_cast<std::size_t>(nfit)) | |||
| 15408 | return false; | |||
| 15409 | return validatePayloadFields(/*allowMixedLists=*/true); | |||
| 15410 | } | |||
| 15411 | ||||
| 15412 | bool DRW_Spline::validatePayloadFields(bool allowMixedLists) const { | |||
| 15413 | const auto finite = [](double value) { return std::isfinite(value); }; | |||
| 15414 | const auto finiteCoord = [&finite](const DRW_Coord& point) { | |||
| 15415 | return finite(point.x) && finite(point.y) && finite(point.z); | |||
| 15416 | }; | |||
| 15417 | const auto validCount = [](std::size_t count) { | |||
| 15418 | return count <= static_cast<std::size_t>(kMaxSplineItems) | |||
| 15419 | && count <= static_cast<std::size_t>( | |||
| 15420 | std::numeric_limits<std::int32_t>::max()); | |||
| 15421 | }; | |||
| 15422 | const auto validPointList = [&finiteCoord, &validCount](const auto& points) { | |||
| 15423 | return validCount(points.size()) | |||
| 15424 | && std::all_of(points.cbegin(), points.cend(), | |||
| 15425 | [&finiteCoord](const auto& point) { | |||
| 15426 | return point != nullptr && finiteCoord(*point); | |||
| 15427 | }); | |||
| 15428 | }; | |||
| 15429 | ||||
| 15430 | if (!isValidSplineDegree(degree) | |||
| 15431 | // Bits above 16 (AutoCAD 2013+ sets 32 and 1024 on fit splines) are | |||
| 15432 | // not used, but a 16-bit value is accepted. | |||
| 15433 | || flags < 0 || flags > 0xFFFF | |||
| 15434 | || !finiteCoord(normalVec) || !finiteCoord(tgStart) | |||
| 15435 | || !finiteCoord(tgEnd) || !finite(tolknot) | |||
| 15436 | || !finite(tolcontrol) || !finite(tolfit) | |||
| 15437 | || !validCount(knotslist.size()) | |||
| 15438 | || !std::all_of(knotslist.cbegin(), knotslist.cend(), finite) | |||
| 15439 | || !validCount(weightlist.size()) | |||
| 15440 | || !std::all_of(weightlist.cbegin(), weightlist.cend(), finite) | |||
| 15441 | || !validPointList(controllist) || !validPointList(fitlist) | |||
| 15442 | || weightlist.size() > controllist.size()) | |||
| 15443 | return false; | |||
| 15444 | ||||
| 15445 | // The DWG body has disjoint control-point and fit-point scenarios. When | |||
| 15446 | // both lists are present, the encoder selects control points and would | |||
| 15447 | // silently discard the fit points, so reject that lossy representation. | |||
| 15448 | if (!allowMixedLists && !fitlist.empty() && !controllist.empty()) | |||
| 15449 | return false; | |||
| 15450 | if (!fitlist.empty() && !controllist.empty()) | |||
| 15451 | return isValidControlSplineLayout( | |||
| 15452 | degree, static_cast<std::int32_t>(knotslist.size()), | |||
| 15453 | static_cast<std::int32_t>(controllist.size())) | |||
| 15454 | && isValidFitSplineLayout( | |||
| 15455 | degree, static_cast<std::int32_t>(fitlist.size())); | |||
| 15456 | if (!fitlist.empty()) | |||
| 15457 | return isValidFitSplineLayout( | |||
| 15458 | degree, static_cast<std::int32_t>(fitlist.size())); | |||
| 15459 | return isValidControlSplineLayout( | |||
| 15460 | degree, static_cast<std::int32_t>(knotslist.size()), | |||
| 15461 | static_cast<std::int32_t>(controllist.size())); | |||
| 15462 | } | |||
| 15463 | ||||
| 15464 | bool DRW_Helix::validateDxf() const { | |||
| 15465 | const auto finite = [](const DRW_Coord& point) { | |||
| 15466 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 15467 | && std::isfinite(point.z); | |||
| 15468 | }; | |||
| 15469 | return DRW_Spline::validateDxf() | |||
| 15470 | && finite(axisBasePt) && finite(startPt) && finite(axisVector) | |||
| 15471 | && std::isfinite(radius) && std::isfinite(turns) | |||
| 15472 | && std::isfinite(turnHeight); | |||
| 15473 | } | |||
| 15474 | ||||
| 15475 | bool DRW_Helix::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 15476 | if (code == 100) { | |||
| 15477 | const std::string subclass = reader->getString(); | |||
| 15478 | m_parsingHelixSubclass = (subclass == "AcDbHelix"); | |||
| 15479 | return true; | |||
| 15480 | } | |||
| 15481 | ||||
| 15482 | if (!m_parsingHelixSubclass) | |||
| 15483 | return DRW_Spline::parseCode(code, reader); | |||
| 15484 | ||||
| 15485 | switch (code) { | |||
| 15486 | case 90: | |||
| 15487 | m_majorVersion = reader->getInt32(); | |||
| 15488 | break; | |||
| 15489 | case 91: | |||
| 15490 | m_maintVersion = reader->getInt32(); | |||
| 15491 | break; | |||
| 15492 | case 10: | |||
| 15493 | axisBasePt.x = reader->getDouble(); | |||
| 15494 | break; | |||
| 15495 | case 20: | |||
| 15496 | axisBasePt.y = reader->getDouble(); | |||
| 15497 | break; | |||
| 15498 | case 30: | |||
| 15499 | axisBasePt.z = reader->getDouble(); | |||
| 15500 | break; | |||
| 15501 | case 11: | |||
| 15502 | startPt.x = reader->getDouble(); | |||
| 15503 | break; | |||
| 15504 | case 21: | |||
| 15505 | startPt.y = reader->getDouble(); | |||
| 15506 | break; | |||
| 15507 | case 31: | |||
| 15508 | startPt.z = reader->getDouble(); | |||
| 15509 | break; | |||
| 15510 | case 12: | |||
| 15511 | axisVector.x = reader->getDouble(); | |||
| 15512 | break; | |||
| 15513 | case 22: | |||
| 15514 | axisVector.y = reader->getDouble(); | |||
| 15515 | break; | |||
| 15516 | case 32: | |||
| 15517 | axisVector.z = reader->getDouble(); | |||
| 15518 | break; | |||
| 15519 | case 40: | |||
| 15520 | radius = reader->getDouble(); | |||
| 15521 | break; | |||
| 15522 | case 41: | |||
| 15523 | turns = reader->getDouble(); | |||
| 15524 | break; | |||
| 15525 | case 42: | |||
| 15526 | turnHeight = reader->getDouble(); | |||
| 15527 | break; | |||
| 15528 | case 290: | |||
| 15529 | { | |||
| 15530 | int value = 0; | |||
| 15531 | if (!readDxfIntInRange(reader, 0, 1, value)) | |||
| 15532 | return false; | |||
| 15533 | handedness = value != 0; | |||
| 15534 | } | |||
| 15535 | break; | |||
| 15536 | case 280: | |||
| 15537 | { | |||
| 15538 | int value = 0; | |||
| 15539 | if (!readDxfIntInRange(reader, 0, 0xFF, value)) | |||
| 15540 | return false; | |||
| 15541 | constraintType = static_cast<std::uint8_t>(value); | |||
| 15542 | } | |||
| 15543 | break; | |||
| 15544 | default: | |||
| 15545 | return DRW_Entity::parseCode(code, reader); | |||
| 15546 | } | |||
| 15547 | ||||
| 15548 | return true; | |||
| 15549 | } | |||
| 15550 | ||||
| 15551 | void DRW_Spline::resetDwgState() { | |||
| 15552 | DRW_Entity::reset(); | |||
| 15553 | normalVec = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15554 | tgStart = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15555 | tgEnd = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15556 | flags = 0; | |||
| 15557 | degree = 0; | |||
| 15558 | m_scenario = 0; | |||
| 15559 | m_splineFlags1 = 0; | |||
| 15560 | m_knotParam = 15; | |||
| 15561 | nknots = 0; | |||
| 15562 | ncontrol = 0; | |||
| 15563 | nfit = 0; | |||
| 15564 | tolknot = 0.0000001; | |||
| 15565 | tolcontrol = 0.0000001; | |||
| 15566 | tolfit = 0.0000001; | |||
| 15567 | knotslist.clear(); | |||
| 15568 | weightlist.clear(); | |||
| 15569 | controllist.clear(); | |||
| 15570 | fitlist.clear(); | |||
| 15571 | controlpoint.reset(); | |||
| 15572 | fitpoint.reset(); | |||
| 15573 | m_dxfDegreeSeen = false; | |||
| 15574 | m_dxfKnotCountSeen = false; | |||
| 15575 | m_dxfControlCountSeen = false; | |||
| 15576 | m_dxfFitCountSeen = false; | |||
| 15577 | } | |||
| 15578 | ||||
| 15579 | bool DRW_Spline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 15580 | resetDwgState(); | |||
| 15581 | dwgBuffer *sourceBuf = buf; | |||
| 15582 | auto fail = [this, sourceBuf]() { | |||
| 15583 | if (sourceBuf != nullptr) | |||
| 15584 | sourceBuf->invalidate(); | |||
| 15585 | resetDwgState(); | |||
| 15586 | return false; | |||
| 15587 | }; | |||
| 15588 | if (sourceBuf == nullptr) | |||
| 15589 | return fail(); | |||
| 15590 | ||||
| 15591 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 15592 | buf = &bodyProbe; | |||
| 15593 | bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs); | |||
| 15594 | if (!ret) | |||
| 15595 | return fail(); | |||
| 15596 | if (!parseDwgSplineBody(version, buf)) | |||
| 15597 | return fail(); | |||
| 15598 | ||||
| 15599 | std::uint64_t handleEndBit = 0; | |||
| 15600 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 15601 | handleEndBit)) | |||
| 15602 | return fail(); | |||
| 15603 | /* Common Entity Handle Data */ | |||
| 15604 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 15605 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 15606 | handleEndBit); | |||
| 15607 | if (!ret || !handleProbe.isGood()) | |||
| 15608 | return fail(); | |||
| 15609 | // RS crc; //RS */ | |||
| 15610 | *sourceBuf = handleProbe; | |||
| 15611 | return true; | |||
| 15612 | } | |||
| 15613 | ||||
| 15614 | // Spline body decode: the scenario/degree/knots/ctrl/fit section, WITHOUT | |||
| 15615 | // the leading DRW_Entity::parseDwg(common) or the trailing parseDwgEntHandle. | |||
| 15616 | // Factored out so DRW_Helix can reuse the identical spline payload before its | |||
| 15617 | // AcDbHelix trailer (Phase 8a-1). | |||
| 15618 | bool DRW_Spline::parseDwgSplineBody(DRW::Version version, dwgBuffer *buf){ | |||
| 15619 | try { | |||
| 15620 | DRW_DBG("\n***************************** parsing spline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing spline *********************************************\n" ); | |||
| 15621 | if (buf == nullptr || !buf->isGood()) | |||
| 15622 | return false; | |||
| 15623 | std::uint8_t weight = 0; // RLZ ??? flags, weight, code 70, bit 4 (16) | |||
| 15624 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 15625 | std::uint64_t controlBits = 0; | |||
| 15626 | ||||
| 15627 | std::int32_t scenario = 0; | |||
| 15628 | if (!readBoundedBitLong(*buf, bodyEndBit, scenario)) | |||
| 15629 | return false; | |||
| 15630 | m_scenario = scenario; | |||
| 15631 | DRW_DBG("scenario: ")DRW_dbg::dbg("scenario: "); DRW_DBG(scenario)DRW_dbg::dbg(scenario); | |||
| 15632 | if (version > DRW::AC1024) { | |||
| 15633 | std::int32_t splFlag1 = 0; | |||
| 15634 | std::int32_t knotParam = 0; | |||
| 15635 | if (!readBoundedBitLong(*buf, bodyEndBit, splFlag1) | |||
| 15636 | || !readBoundedBitLong(*buf, bodyEndBit, knotParam)) | |||
| 15637 | return false; | |||
| 15638 | m_splineFlags1 = splFlag1; | |||
| 15639 | m_knotParam = knotParam; | |||
| 15640 | if (knotParam == kSplineKnotParamCustom || !(splFlag1 & kSplineFlagUseKnotParameter)) { | |||
| 15641 | scenario = 1; | |||
| 15642 | } else if (splFlag1 & kSplineFlagMethodFitPoints) { | |||
| 15643 | scenario = 2; | |||
| 15644 | } | |||
| 15645 | m_scenario = scenario; | |||
| 15646 | DRW_DBG(" 2013 splFlag1: ")DRW_dbg::dbg(" 2013 splFlag1: "); DRW_DBG(splFlag1)DRW_dbg::dbg(splFlag1); | |||
| 15647 | DRW_DBG(" 2013 knotParam: ")DRW_dbg::dbg(" 2013 knotParam: "); DRW_DBG(knotParam)DRW_dbg::dbg(knotParam); | |||
| 15648 | // DRW_DBG("unk bit: "); DRW_DBG(buf->getBit()); | |||
| 15649 | } | |||
| 15650 | if (!readBoundedBitLong(*buf, bodyEndBit, degree)) | |||
| 15651 | return false; | |||
| 15652 | DRW_DBG(" degree: ")DRW_dbg::dbg(" degree: "); DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15653 | if (!isValidSplineDegree(degree)) { | |||
| 15654 | 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"); | |||
| 15655 | return false; | |||
| 15656 | } | |||
| 15657 | if (scenario == 2) { | |||
| 15658 | flags = 8;//scenario 2 = not rational & planar | |||
| 15659 | if (m_splineFlags1 & kSplineFlagClosed) | |||
| 15660 | flags |= 1; | |||
| 15661 | if (!readBoundedBitDouble(*buf, bodyEndBit, tolfit) | |||
| 15662 | || !readBoundedBitCoord(*buf, bodyEndBit, tgStart) | |||
| 15663 | || !readBoundedBitCoord(*buf, bodyEndBit, tgEnd)) | |||
| 15664 | return false; | |||
| 15665 | 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); | |||
| 15666 | 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); | |||
| 15667 | 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); | |||
| 15668 | std::uint32_t parsedFitCount = 0; | |||
| 15669 | if (!readTableBodyCount(version, buf, objSize, kMaxSplineItems, 6, | |||
| 15670 | parsedFitCount)) { | |||
| 15671 | return false; | |||
| 15672 | } | |||
| 15673 | nfit = static_cast<std::int32_t>(parsedFitCount); | |||
| 15674 | if (!isValidFitSplineLayout(degree, nfit)) { | |||
| 15675 | DRW_DBG("\ndwg Spline, invalid fit layout degree/count: ")DRW_dbg::dbg("\ndwg Spline, invalid fit layout degree/count: " ); | |||
| 15676 | 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"); | |||
| 15677 | return false; | |||
| 15678 | } | |||
| 15679 | DRW_DBG("\nnumber of fit points: ")DRW_dbg::dbg("\nnumber of fit points: "); DRW_DBG(nfit)DRW_dbg::dbg(nfit); | |||
| 15680 | } else if (scenario == 1) { | |||
| 15681 | flags = 8;//scenario 1 = rational & planar | |||
| 15682 | bool rational = false; | |||
| 15683 | bool closed = false; | |||
| 15684 | bool periodic = false; | |||
| 15685 | if (!readBoundedBit(*buf, bodyEndBit, rational) | |||
| 15686 | || !readBoundedBit(*buf, bodyEndBit, closed) | |||
| 15687 | || !readBoundedBit(*buf, bodyEndBit, periodic) | |||
| 15688 | || !readBoundedBitDouble(*buf, bodyEndBit, tolknot) | |||
| 15689 | || !readBoundedBitDouble(*buf, bodyEndBit, tolcontrol)) | |||
| 15690 | return false; | |||
| 15691 | flags |= rational ? 4 : 0; | |||
| 15692 | flags |= closed ? 1 : 0; | |||
| 15693 | flags |= periodic ? 2 : 0; | |||
| 15694 | 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); | |||
| 15695 | DRW_DBG(" control point tolerance: ")DRW_dbg::dbg(" control point tolerance: "); DRW_DBG(tolcontrol)DRW_dbg::dbg(tolcontrol); | |||
| 15696 | std::uint32_t parsedKnotCount = 0; | |||
| 15697 | if (!readTableBodyCount(version, buf, objSize, kMaxSplineItems, 2, | |||
| 15698 | parsedKnotCount)) { | |||
| 15699 | return false; | |||
| 15700 | } | |||
| 15701 | nknots = static_cast<std::int32_t>(parsedKnotCount); | |||
| 15702 | std::uint32_t parsedControlCount = 0; | |||
| 15703 | if (!readTableBodyCount(version, buf, objSize, kMaxSplineItems, 6, | |||
| 15704 | parsedControlCount)) { | |||
| 15705 | return false; | |||
| 15706 | } | |||
| 15707 | ncontrol = static_cast<std::int32_t>(parsedControlCount); | |||
| 15708 | if (!isValidControlSplineLayout(degree, nknots, ncontrol)) { | |||
| 15709 | DRW_DBG("\ndwg Spline, invalid control layout degree/knots/control: ")DRW_dbg::dbg("\ndwg Spline, invalid control layout degree/knots/control: " ); | |||
| 15710 | DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("/")DRW_dbg::dbg("/"); DRW_DBG(nknots)DRW_dbg::dbg(nknots); DRW_DBG("/")DRW_dbg::dbg("/"); | |||
| 15711 | DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15712 | return false; | |||
| 15713 | } | |||
| 15714 | bool hasWeights = false; | |||
| 15715 | if (!readBoundedBit(*buf, bodyEndBit, hasWeights)) | |||
| 15716 | return false; | |||
| 15717 | weight = hasWeights ? 1 : 0; // flags bit 4: weights present (code 70) | |||
| 15718 | if (weight) flags |= 0x10; | |||
| 15719 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(ncontrol), | |||
| 15720 | weight ? 8u : 6u, controlBits)) | |||
| 15721 | return false; | |||
| 15722 | if (!proxyEntityHasBits(*buf, bodyEndBit, controlBits)) { | |||
| 15723 | return false; | |||
| 15724 | } | |||
| 15725 | 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: "); | |||
| 15726 | DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG(" weight bit: ")DRW_dbg::dbg(" weight bit: "); DRW_DBG(weight)DRW_dbg::dbg(weight); | |||
| 15727 | } else { | |||
| 15728 | DRW_DBG("\ndwg Spline, unknown scenario ")DRW_dbg::dbg("\ndwg Spline, unknown scenario "); DRW_DBG(scenario)DRW_dbg::dbg(scenario); | |||
| 15729 | DRW_DBG(" (expected 1 or 2)\n")DRW_dbg::dbg(" (expected 1 or 2)\n"); | |||
| 15730 | return false; //RLZ: from doc only 1 or 2 are ok ? | |||
| 15731 | } | |||
| 15732 | ||||
| 15733 | std::vector<double> parsedKnots; | |||
| 15734 | std::vector<double> parsedWeights; | |||
| 15735 | std::vector<std::shared_ptr<DRW_Coord>> parsedControls; | |||
| 15736 | std::vector<std::shared_ptr<DRW_Coord>> parsedFits; | |||
| 15737 | std::uint64_t knotBits = 0; | |||
| 15738 | std::uint64_t fitBits = 0; | |||
| 15739 | std::uint64_t requiredBits = 0; | |||
| 15740 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(nknots), 2, | |||
| 15741 | knotBits) | |||
| 15742 | || !dwgSafety::multiply(static_cast<std::uint64_t>(nfit), 6, | |||
| 15743 | fitBits) | |||
| 15744 | || !dwgSafety::add(knotBits, controlBits, requiredBits) | |||
| 15745 | || !dwgSafety::add(requiredBits, fitBits, requiredBits) | |||
| 15746 | || !proxyEntityHasBits(*buf, bodyEndBit, requiredBits)) { | |||
| 15747 | return false; | |||
| 15748 | } | |||
| 15749 | if (!DRW::reserve(parsedKnots, nknots)) { | |||
| 15750 | return false; | |||
| 15751 | } | |||
| 15752 | for (std::int32_t i= 0; i<nknots; ++i){ | |||
| 15753 | double knot = 0.0; | |||
| 15754 | if (!readBoundedBitDouble(*buf, bodyEndBit, knot) | |||
| 15755 | || !std::isfinite(knot)) | |||
| 15756 | return false; | |||
| 15757 | parsedKnots.push_back(knot); | |||
| 15758 | } | |||
| 15759 | if (!DRW::reserve(parsedControls, ncontrol)) { | |||
| 15760 | return false; | |||
| 15761 | } | |||
| 15762 | if (weight && !DRW::reserve(parsedWeights, ncontrol)) { | |||
| 15763 | return false; | |||
| 15764 | } | |||
| 15765 | for (std::int32_t i= 0; i<ncontrol; ++i){ | |||
| 15766 | DRW_Coord control; | |||
| 15767 | if (!readBoundedBitCoord(*buf, bodyEndBit, control) | |||
| 15768 | || !std::isfinite(control.x) | |||
| 15769 | || !std::isfinite(control.y) | |||
| 15770 | || !std::isfinite(control.z)) | |||
| 15771 | return false; | |||
| 15772 | parsedControls.push_back(std::make_shared<DRW_Coord>(control)); | |||
| 15773 | if (weight) { | |||
| 15774 | //per-control-point weight; required for hyperbola/parabola | |||
| 15775 | //conic detection in consumers (e.g. LibreCAD addSpline) | |||
| 15776 | double w = 0.0; //RLZ Warning: D (BD or RD) | |||
| 15777 | if (!readBoundedBitDouble(*buf, bodyEndBit, w) | |||
| 15778 | || !std::isfinite(w)) | |||
| 15779 | return false; | |||
| 15780 | parsedWeights.push_back(w); | |||
| 15781 | DRW_DBG("\n w: ")DRW_dbg::dbg("\n w: "); DRW_DBG(w)DRW_dbg::dbg(w); | |||
| 15782 | } | |||
| 15783 | } | |||
| 15784 | if (!DRW::reserve(parsedFits, nfit)) { | |||
| 15785 | return false; | |||
| 15786 | } | |||
| 15787 | for (std::int32_t i= 0; i<nfit; ++i) { | |||
| 15788 | DRW_Coord fit; | |||
| 15789 | if (!readBoundedBitCoord(*buf, bodyEndBit, fit) | |||
| 15790 | || !std::isfinite(fit.x) | |||
| 15791 | || !std::isfinite(fit.y) | |||
| 15792 | || !std::isfinite(fit.z)) | |||
| 15793 | return false; | |||
| 15794 | parsedFits.push_back(std::make_shared<DRW_Coord>(fit)); | |||
| 15795 | } | |||
| 15796 | ||||
| 15797 | if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug) { | |||
| 15798 | DRW_DBG("\nknots list: ")DRW_dbg::dbg("\nknots list: "); | |||
| 15799 | for (auto const& v: parsedKnots) { | |||
| 15800 | DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBG(v)DRW_dbg::dbg(v); | |||
| 15801 | } | |||
| 15802 | DRW_DBG("\ncontrol point list: ")DRW_dbg::dbg("\ncontrol point list: "); | |||
| 15803 | for (auto const& v: parsedControls) { | |||
| 15804 | DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z); | |||
| 15805 | } | |||
| 15806 | DRW_DBG("\nfit point list: ")DRW_dbg::dbg("\nfit point list: "); | |||
| 15807 | for (auto const& v: parsedFits) { | |||
| 15808 | DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z); | |||
| 15809 | } | |||
| 15810 | } | |||
| 15811 | ||||
| 15812 | if (!buf->isGood()) | |||
| 15813 | return false; | |||
| 15814 | knotslist = std::move(parsedKnots); | |||
| 15815 | weightlist = std::move(parsedWeights); | |||
| 15816 | controllist = std::move(parsedControls); | |||
| 15817 | fitlist = std::move(parsedFits); | |||
| 15818 | return true; | |||
| 15819 | } catch (...) { | |||
| 15820 | return false; | |||
| 15821 | } | |||
| 15822 | } | |||
| 15823 | ||||
| 15824 | // AcDbHelix trailer order (libreDWG dwg2.spec:2493-2503): | |||
| 15825 | // major_version BL, maint_version BL, axis_base_pt 3BD, start_pt 3BD, | |||
| 15826 | // axis_vector 3BD, radius BD, turns BD, turn_height BD, handedness B, | |||
| 15827 | // constraint_type RC. | |||
| 15828 | void DRW_Helix::resetDwgState() { | |||
| 15829 | DRW_Spline::resetDwgState(); | |||
| 15830 | m_majorVersion = 0; | |||
| 15831 | m_maintVersion = 0; | |||
| 15832 | axisBasePt = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15833 | startPt = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15834 | axisVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15835 | radius = 0.0; | |||
| 15836 | turns = 0.0; | |||
| 15837 | turnHeight = 0.0; | |||
| 15838 | handedness = false; | |||
| 15839 | constraintType = 0; | |||
| 15840 | m_parsingHelixSubclass = false; | |||
| 15841 | } | |||
| 15842 | ||||
| 15843 | bool DRW_Helix::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 15844 | resetDwgState(); | |||
| 15845 | dwgBuffer *sourceBuf = buf; | |||
| 15846 | auto fail = [this, sourceBuf]() { | |||
| 15847 | if (sourceBuf != nullptr) | |||
| 15848 | sourceBuf->invalidate(); | |||
| 15849 | resetDwgState(); | |||
| 15850 | return false; | |||
| 15851 | }; | |||
| 15852 | if (sourceBuf == nullptr) | |||
| 15853 | return fail(); | |||
| 15854 | ||||
| 15855 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 15856 | buf = &bodyProbe; | |||
| 15857 | bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs); | |||
| 15858 | if (!ret) | |||
| 15859 | return fail(); | |||
| 15860 | DRW_DBG("\n***************************** parsing helix *********************************************\n")DRW_dbg::dbg("\n***************************** parsing helix *********************************************\n" ); | |||
| 15861 | if (!parseDwgSplineBody(version, buf)) | |||
| 15862 | return fail(); | |||
| 15863 | ||||
| 15864 | // AcDbHelix trailer (see field order above). | |||
| 15865 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 15866 | std::int32_t parsedMajorVersion = 0; | |||
| 15867 | std::int32_t parsedMaintVersion = 0; | |||
| 15868 | DRW_Coord parsedAxisBasePt; | |||
| 15869 | DRW_Coord parsedStartPt; | |||
| 15870 | DRW_Coord parsedAxisVector; | |||
| 15871 | double parsedRadius = 0.0; | |||
| 15872 | double parsedTurns = 0.0; | |||
| 15873 | double parsedTurnHeight = 0.0; | |||
| 15874 | bool parsedHandedness = false; | |||
| 15875 | std::uint8_t parsedConstraintType = 0; | |||
| 15876 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedMajorVersion) | |||
| 15877 | || !readBoundedBitLong(*buf, bodyEndBit, parsedMaintVersion) | |||
| 15878 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedAxisBasePt) | |||
| 15879 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedStartPt) | |||
| 15880 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedAxisVector) | |||
| 15881 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRadius) | |||
| 15882 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedTurns) | |||
| 15883 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedTurnHeight) | |||
| 15884 | || !readBoundedBit(*buf, bodyEndBit, parsedHandedness) | |||
| 15885 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedConstraintType) | |||
| 15886 | || !std::isfinite(parsedAxisBasePt.x) | |||
| 15887 | || !std::isfinite(parsedAxisBasePt.y) | |||
| 15888 | || !std::isfinite(parsedAxisBasePt.z) | |||
| 15889 | || !std::isfinite(parsedStartPt.x) | |||
| 15890 | || !std::isfinite(parsedStartPt.y) | |||
| 15891 | || !std::isfinite(parsedStartPt.z) | |||
| 15892 | || !std::isfinite(parsedAxisVector.x) | |||
| 15893 | || !std::isfinite(parsedAxisVector.y) | |||
| 15894 | || !std::isfinite(parsedAxisVector.z) | |||
| 15895 | || !std::isfinite(parsedRadius) | |||
| 15896 | || !std::isfinite(parsedTurns) | |||
| 15897 | || !std::isfinite(parsedTurnHeight)) | |||
| 15898 | return fail(); | |||
| 15899 | 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); | |||
| 15900 | ||||
| 15901 | std::uint64_t handleEndBit = 0; | |||
| 15902 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 15903 | handleEndBit)) | |||
| 15904 | return fail(); | |||
| 15905 | /* Common Entity Handle Data */ | |||
| 15906 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 15907 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 15908 | handleEndBit); | |||
| 15909 | if (!ret || !handleProbe.isGood()) | |||
| 15910 | return fail(); | |||
| 15911 | // RS crc; //RS */ | |||
| 15912 | m_majorVersion = parsedMajorVersion; | |||
| 15913 | m_maintVersion = parsedMaintVersion; | |||
| 15914 | axisBasePt = parsedAxisBasePt; | |||
| 15915 | startPt = parsedStartPt; | |||
| 15916 | axisVector = parsedAxisVector; | |||
| 15917 | radius = parsedRadius; | |||
| 15918 | turns = parsedTurns; | |||
| 15919 | turnHeight = parsedTurnHeight; | |||
| 15920 | handedness = parsedHandedness; | |||
| 15921 | constraintType = parsedConstraintType; | |||
| 15922 | *sourceBuf = handleProbe; | |||
| 15923 | return true; | |||
| 15924 | } | |||
| 15925 | ||||
| 15926 | bool DRW_Image::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 15927 | switch (code) { | |||
| 15928 | case 12: | |||
| 15929 | vVector.x = reader->getDouble(); | |||
| 15930 | break; | |||
| 15931 | case 22: | |||
| 15932 | vVector.y = reader->getDouble(); | |||
| 15933 | break; | |||
| 15934 | case 32: | |||
| 15935 | vVector.z = reader->getDouble(); | |||
| 15936 | break; | |||
| 15937 | case 13: | |||
| 15938 | sizeu = reader->getDouble(); | |||
| 15939 | break; | |||
| 15940 | case 23: | |||
| 15941 | sizev = reader->getDouble(); | |||
| 15942 | break; | |||
| 15943 | case 70: | |||
| 15944 | { | |||
| 15945 | int value = 0; | |||
| 15946 | if (!readDxfIntInRange(reader, 0, 0xFFFF, value)) | |||
| 15947 | return false; | |||
| 15948 | m_displayProps = value; | |||
| 15949 | } | |||
| 15950 | break; | |||
| 15951 | case 90: { | |||
| 15952 | const std::int32_t value = reader->getInt32(); | |||
| 15953 | if (value < 0 || value > kMaxClassVersion) | |||
| 15954 | return false; | |||
| 15955 | m_classVersion = value; | |||
| 15956 | break; | |||
| 15957 | } | |||
| 15958 | case 340: | |||
| 15959 | ref = reader->getHandleString(); | |||
| 15960 | break; | |||
| 15961 | case 360: | |||
| 15962 | m_imageDefReactorHandle = reader->getHandleString(); | |||
| 15963 | break; | |||
| 15964 | case 280: | |||
| 15965 | { | |||
| 15966 | int value = 0; | |||
| 15967 | if (!readDxfIntInRange(reader, 0, 1, value)) | |||
| 15968 | return false; | |||
| 15969 | clip = value; | |||
| 15970 | } | |||
| 15971 | break; | |||
| 15972 | case 281: | |||
| 15973 | { | |||
| 15974 | int value = 0; | |||
| 15975 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 15976 | return false; | |||
| 15977 | brightness = value; | |||
| 15978 | } | |||
| 15979 | break; | |||
| 15980 | case 282: | |||
| 15981 | { | |||
| 15982 | int value = 0; | |||
| 15983 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 15984 | return false; | |||
| 15985 | contrast = value; | |||
| 15986 | } | |||
| 15987 | break; | |||
| 15988 | case 283: | |||
| 15989 | { | |||
| 15990 | int value = 0; | |||
| 15991 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 15992 | return false; | |||
| 15993 | fade = value; | |||
| 15994 | } | |||
| 15995 | break; | |||
| 15996 | case 71: | |||
| 15997 | { | |||
| 15998 | int value = 0; | |||
| 15999 | if (!readDxfIntInRange(reader, 0, 2, value)) | |||
| 16000 | return false; | |||
| 16001 | m_clipBoundaryType = value; | |||
| 16002 | } | |||
| 16003 | break; | |||
| 16004 | case 91: | |||
| 16005 | // The declared count is a structural invariant: reject negative or | |||
| 16006 | // implausibly large values before reserve() can allocate unboundedly. | |||
| 16007 | { | |||
| 16008 | const std::int32_t count = reader->getInt32(); | |||
| 16009 | if (count < 0 || count > static_cast<std::int32_t>(DRW_Image::kMaxClipVertices)) | |||
| 16010 | return false; | |||
| 16011 | clipPath.clear(); | |||
| 16012 | if (!DRW::reserve(clipPath, count)) | |||
| 16013 | return false; | |||
| 16014 | m_declaredClipVertexCount = count; | |||
| 16015 | m_clipPathHasOpenVertex = false; | |||
| 16016 | } | |||
| 16017 | break; | |||
| 16018 | case 14: | |||
| 16019 | // WIPEOUT polygon vertex x — start a new vertex. Group 24 (y) follows. | |||
| 16020 | if (m_clipPathHasOpenVertex) | |||
| 16021 | return false; | |||
| 16022 | clipPath.emplace_back(reader->getDouble(), 0.0); | |||
| 16023 | m_clipPathHasOpenVertex = true; | |||
| 16024 | break; | |||
| 16025 | case 24: | |||
| 16026 | // WIPEOUT polygon vertex y — complete the most recently started vertex. | |||
| 16027 | if (!m_clipPathHasOpenVertex || clipPath.empty()) | |||
| 16028 | return false; | |||
| 16029 | clipPath.back().y = reader->getDouble(); | |||
| 16030 | m_clipPathHasOpenVertex = false; | |||
| 16031 | break; | |||
| 16032 | case 290: | |||
| 16033 | // R2010+ Clip mode (IMAGE/WIPEOUT, ODA spec §20.4.80): | |||
| 16034 | // 0 = mask outside the polygon, 1 = mask inside. | |||
| 16035 | clipMode = reader->getBool(); | |||
| 16036 | break; | |||
| 16037 | default: | |||
| 16038 | return DRW_Line::parseCode(code, reader); | |||
| 16039 | } | |||
| 16040 | ||||
| 16041 | return true; | |||
| 16042 | } | |||
| 16043 | ||||
| 16044 | bool DRW_Image::hasValidClipBoundary() const { | |||
| 16045 | if (m_clipPathHasOpenVertex | |||
| 16046 | || (m_declaredClipVertexCount >= 0 | |||
| 16047 | && static_cast<std::size_t>(m_declaredClipVertexCount) != clipPath.size())) { | |||
| 16048 | return false; | |||
| 16049 | } | |||
| 16050 | switch (m_clipBoundaryType) { | |||
| 16051 | case 0: | |||
| 16052 | return clipPath.empty(); | |||
| 16053 | case 1: | |||
| 16054 | return clipPath.size() == 2; | |||
| 16055 | case 2: | |||
| 16056 | return clipPath.size() >= 3; | |||
| 16057 | default: | |||
| 16058 | return false; | |||
| 16059 | } | |||
| 16060 | } | |||
| 16061 | ||||
| 16062 | bool DRW_Image::validatePayloadFields() const { | |||
| 16063 | const auto finite = [](const DRW_Coord& point) { | |||
| 16064 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 16065 | && std::isfinite(point.z); | |||
| 16066 | }; | |||
| 16067 | return m_classVersion >= 0 && m_classVersion <= kMaxClassVersion | |||
| 16068 | && m_displayProps >= 0 && m_displayProps <= 0xffff | |||
| 16069 | && clip >= 0 && clip <= 1 | |||
| 16070 | && brightness >= 0 && brightness <= 0xff | |||
| 16071 | && contrast >= 0 && contrast <= 0xff | |||
| 16072 | && fade >= 0 && fade <= 0xff | |||
| 16073 | && std::isfinite(sizeu) && std::isfinite(sizev) | |||
| 16074 | && finite(basePoint) && finite(secPoint) && finite(vVector) | |||
| 16075 | && clipPath.size() <= kMaxClipVertices | |||
| 16076 | && std::all_of(clipPath.cbegin(), clipPath.cend(), | |||
| 16077 | [](const DRW_Coord& point) { | |||
| 16078 | return std::isfinite(point.x) | |||
| 16079 | && std::isfinite(point.y); | |||
| 16080 | }); | |||
| 16081 | } | |||
| 16082 | ||||
| 16083 | void DRW_Image::resetDwgState() { | |||
| 16084 | DRW_Line::resetDwgState(); | |||
| 16085 | m_classVersion = 0; | |||
| 16086 | ref = 0; | |||
| 16087 | m_imageDefReactorHandle = 0; | |||
| 16088 | m_displayProps = 0; | |||
| 16089 | vVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16090 | sizeu = 0.0; | |||
| 16091 | sizev = 0.0; | |||
| 16092 | dz = 0.0; | |||
| 16093 | clip = 0; | |||
| 16094 | brightness = 50; | |||
| 16095 | contrast = 50; | |||
| 16096 | fade = 0; | |||
| 16097 | m_clipBoundaryType = 0; | |||
| 16098 | clipPath.clear(); | |||
| 16099 | clipMode = false; | |||
| 16100 | m_declaredClipVertexCount = -1; | |||
| 16101 | m_clipPathHasOpenVertex = false; | |||
| 16102 | } | |||
| 16103 | ||||
| 16104 | bool DRW_Image::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 16105 | resetDwgState(); | |||
| 16106 | dwgBuffer *sourceBuf = buf; | |||
| 16107 | auto fail = [this, sourceBuf]() { | |||
| 16108 | if (sourceBuf != nullptr) | |||
| 16109 | sourceBuf->invalidate(); | |||
| 16110 | resetDwgState(); | |||
| 16111 | return false; | |||
| 16112 | }; | |||
| 16113 | if (sourceBuf == nullptr) | |||
| 16114 | return fail(); | |||
| 16115 | ||||
| 16116 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 16117 | buf = &bodyProbe; | |||
| 16118 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 16119 | dwgBuffer *sBuf = buf; | |||
| 16120 | if (version > DRW::AC1018) {//2007+ | |||
| 16121 | sBuf = &sBuff; //separate buffer for strings | |||
| 16122 | } | |||
| 16123 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 16124 | if (!ret) | |||
| 16125 | return fail(); | |||
| 16126 | DRW_DBG("\n***************************** parsing image *********************************************\n")DRW_dbg::dbg("\n***************************** parsing image *********************************************\n" ); | |||
| 16127 | ||||
| 16128 | const auto finite = [](const DRW_Coord& point) { | |||
| 16129 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 16130 | && std::isfinite(point.z); | |||
| 16131 | }; | |||
| 16132 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 16133 | std::int32_t parsedClassVersion = 0; | |||
| 16134 | DRW_Coord parsedBasePoint; | |||
| 16135 | DRW_Coord parsedSecPoint; | |||
| 16136 | DRW_Coord parsedVVector; | |||
| 16137 | double parsedSizeU = 0.0; | |||
| 16138 | double parsedSizeV = 0.0; | |||
| 16139 | std::uint16_t parsedDisplayProps = 0; | |||
| 16140 | bool parsedClip = false; | |||
| 16141 | std::uint8_t parsedBrightness = 0; | |||
| 16142 | std::uint8_t parsedContrast = 0; | |||
| 16143 | std::uint8_t parsedFade = 0; | |||
| 16144 | bool parsedClipMode = false; | |||
| 16145 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedClassVersion) | |||
| 16146 | || parsedClassVersion < 0 || parsedClassVersion > kMaxClassVersion | |||
| 16147 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 16148 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedSecPoint) | |||
| 16149 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedVVector) | |||
| 16150 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedSizeU) | |||
| 16151 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedSizeV) | |||
| 16152 | || !readBoundedBitShort(*buf, bodyEndBit, parsedDisplayProps) | |||
| 16153 | || !readBoundedBit(*buf, bodyEndBit, parsedClip) | |||
| 16154 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedBrightness) | |||
| 16155 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedContrast) | |||
| 16156 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedFade) | |||
| 16157 | || (version > DRW::AC1021 | |||
| 16158 | && !readBoundedBit(*buf, bodyEndBit, parsedClipMode)) | |||
| 16159 | || !finite(parsedBasePoint) || !finite(parsedSecPoint) | |||
| 16160 | || !finite(parsedVVector) || !std::isfinite(parsedSizeU) | |||
| 16161 | || !std::isfinite(parsedSizeV)) | |||
| 16162 | return fail(); | |||
| 16163 | DRW_DBG("class Version: ")DRW_dbg::dbg("class Version: "); DRW_DBG(parsedClassVersion)DRW_dbg::dbg(parsedClassVersion); | |||
| 16164 | 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); | |||
| 16165 | 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); | |||
| 16166 | 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); | |||
| 16167 | 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); | |||
| 16168 | DRW_DBG("\ndisplay props: ")DRW_dbg::dbg("\ndisplay props: "); DRW_DBG(parsedDisplayProps)DRW_dbg::dbg(parsedDisplayProps); | |||
| 16169 | ||||
| 16170 | std::uint16_t parsedClipBoundaryType = 0; | |||
| 16171 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedClipBoundaryType)) | |||
| 16172 | return fail(); | |||
| 16173 | std::vector<DRW_Coord> parsedClipPath; | |||
| 16174 | std::int32_t parsedDeclaredClipVertexCount = -1; | |||
| 16175 | if (parsedClipBoundaryType == 0) { | |||
| 16176 | // No clip boundary payload. | |||
| 16177 | } else if (parsedClipBoundaryType == 1){ | |||
| 16178 | // Rectangles are encoded as exactly two opposite corners. Keep that | |||
| 16179 | // canonical payload intact; rendering expands it independently. | |||
| 16180 | DRW_Coord ll; | |||
| 16181 | DRW_Coord ur; | |||
| 16182 | if (!readBoundedRawDouble(*buf, bodyEndBit, ll.x) | |||
| 16183 | || !readBoundedRawDouble(*buf, bodyEndBit, ll.y) | |||
| 16184 | || !readBoundedRawDouble(*buf, bodyEndBit, ur.x) | |||
| 16185 | || !readBoundedRawDouble(*buf, bodyEndBit, ur.y) | |||
| 16186 | || !finite(ll) || !finite(ur)) | |||
| 16187 | return fail(); | |||
| 16188 | parsedClipPath.push_back(ll); | |||
| 16189 | parsedClipPath.push_back(ur); | |||
| 16190 | parsedDeclaredClipVertexCount = 2; | |||
| 16191 | } else if (parsedClipBoundaryType == 2) { | |||
| 16192 | std::uint32_t numVerts = 0; | |||
| 16193 | if (!readTableBodyCount(version, buf, objSize, | |||
| 16194 | static_cast<std::uint32_t>(kMaxClipVertices), | |||
| 16195 | 128, numVerts)) | |||
| 16196 | return fail(); | |||
| 16197 | std::uint64_t vertexBits = 0; | |||
| 16198 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(numVerts), 128, | |||
| 16199 | vertexBits) | |||
| 16200 | || !proxyEntityHasBits(*buf, bodyEndBit, vertexBits) | |||
| 16201 | || !DRW::reserve(parsedClipPath, numVerts)) | |||
| 16202 | return fail(); | |||
| 16203 | for (std::uint32_t i = 0; i < numVerts; ++i) { | |||
| 16204 | DRW_Coord point; | |||
| 16205 | if (!readBoundedRawDouble(*buf, bodyEndBit, point.x) | |||
| 16206 | || !readBoundedRawDouble(*buf, bodyEndBit, point.y) | |||
| 16207 | || !finite(point)) | |||
| 16208 | return fail(); | |||
| 16209 | parsedClipPath.push_back(point); | |||
| 16210 | } | |||
| 16211 | parsedDeclaredClipVertexCount = static_cast<std::int32_t>(numVerts); | |||
| 16212 | } else { | |||
| 16213 | 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"); | |||
| 16214 | return fail(); | |||
| 16215 | } | |||
| 16216 | ||||
| 16217 | if ((parsedClipBoundaryType == 0 && !parsedClipPath.empty()) | |||
| 16218 | || (parsedClipBoundaryType == 2 && parsedClipPath.size() < 3)) | |||
| 16219 | return fail(); | |||
| 16220 | ||||
| 16221 | if (!buf->isGood()) | |||
| 16222 | return fail(); | |||
| 16223 | std::uint64_t handleEndBit = 0; | |||
| 16224 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 16225 | handleEndBit)) | |||
| 16226 | return fail(); | |||
| 16227 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 16228 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 16229 | handleEndBit); | |||
| 16230 | if (!ret) | |||
| 16231 | return fail(); | |||
| 16232 | 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"); | |||
| 16233 | ||||
| 16234 | if (!proxyEntityHasBits(handleProbe, handleEndBit, 8)) | |||
| 16235 | return fail(); | |||
| 16236 | dwgHandle biH; | |||
| 16237 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, biH)) | |||
| 16238 | return fail(); | |||
| 16239 | 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); | |||
| 16240 | if (!proxyEntityHasBits(handleProbe, handleEndBit, 8)) | |||
| 16241 | return fail(); | |||
| 16242 | dwgHandle reactorH; | |||
| 16243 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 16244 | reactorH)) | |||
| 16245 | return fail(); | |||
| 16246 | 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); | |||
| 16247 | 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"); | |||
| 16248 | if (!handleProbe.isGood() || !sBuf->isGood()) | |||
| 16249 | return fail(); | |||
| 16250 | m_classVersion = parsedClassVersion; | |||
| 16251 | basePoint = parsedBasePoint; | |||
| 16252 | secPoint = parsedSecPoint; | |||
| 16253 | vVector = parsedVVector; | |||
| 16254 | sizeu = parsedSizeU; | |||
| 16255 | sizev = parsedSizeV; | |||
| 16256 | m_displayProps = parsedDisplayProps; | |||
| 16257 | clip = parsedClip ? 1 : 0; | |||
| 16258 | brightness = parsedBrightness; | |||
| 16259 | contrast = parsedContrast; | |||
| 16260 | fade = parsedFade; | |||
| 16261 | clipMode = parsedClipMode; | |||
| 16262 | m_clipBoundaryType = parsedClipBoundaryType; | |||
| 16263 | clipPath = std::move(parsedClipPath); | |||
| 16264 | m_declaredClipVertexCount = parsedDeclaredClipVertexCount; | |||
| 16265 | m_clipPathHasOpenVertex = false; | |||
| 16266 | *sourceBuf = handleProbe; | |||
| 16267 | ref = biH.ref; | |||
| 16268 | m_imageDefReactorHandle = reactorH.ref; | |||
| 16269 | return true; | |||
| 16270 | } | |||
| 16271 | ||||
| 16272 | // DRW_Image::encodeDwg — inverse of DRW_Image::parseDwg above (libreDWG | |||
| 16273 | // dwg.spec:5533-5563). Body field order: BL class_version, 3 x 3BD | |||
| 16274 | // (base/uvec/vvec), 2 x RD (sizeu/sizev), BS display_props, B clip, | |||
| 16275 | // 3 x RC (brightness/contrast/fade), [R2010+ B clip_mode], BS | |||
| 16276 | // clip_boundary_type + verts. Both handles (imagedef code 5 + reactor | |||
| 16277 | // code 3) are emitted UNCONDITIONALLY at the END of the handle stream, | |||
| 16278 | // matching parseDwg's order — NOT the spec's interleaved mid-stream slots. | |||
| 16279 | bool DRW_Image::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 16280 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 16281 | (void)bs; (void)strBuf; | |||
| 16282 | if (!validatePayloadFields()) { | |||
| 16283 | DRW_DBG("IMAGE has an invalid scalar or clip field\n")DRW_dbg::dbg("IMAGE has an invalid scalar or clip field\n"); | |||
| 16284 | return false; | |||
| 16285 | } | |||
| 16286 | // Callers sometimes populate clipPath without setting m_clipBoundaryType | |||
| 16287 | // (DXF import historically stored only the vertices). Infer a coherent type | |||
| 16288 | // so encode does not reject a well-formed polygon/rectangle path. | |||
| 16289 | if (m_clipBoundaryType == 0 && !clipPath.empty()) { | |||
| 16290 | if (clipPath.size() == 2) | |||
| 16291 | m_clipBoundaryType = 1; | |||
| 16292 | else if (clipPath.size() >= 3) | |||
| 16293 | m_clipBoundaryType = 2; | |||
| 16294 | } | |||
| 16295 | if (!hasValidClipBoundary()) { | |||
| 16296 | DRW_DBG("IMAGE has invalid clip boundary\n")DRW_dbg::dbg("IMAGE has invalid clip boundary\n"); | |||
| 16297 | return false; | |||
| 16298 | } | |||
| 16299 | oType = 101; // IMAGE class id — see dwgreader.cpp case 101 | |||
| 16300 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 16301 | ||||
| 16302 | buf->putBitLong(m_classVersion); | |||
| 16303 | buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z); | |||
| 16304 | buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z); // uvec | |||
| 16305 | buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z); | |||
| 16306 | buf->putRawDouble(sizeu); | |||
| 16307 | buf->putRawDouble(sizev); | |||
| 16308 | buf->putBitShort(static_cast<std::uint16_t>(m_displayProps)); | |||
| 16309 | buf->putBit(static_cast<std::uint8_t>(clip & 1)); | |||
| 16310 | buf->putRawChar8(static_cast<std::uint8_t>(brightness)); | |||
| 16311 | buf->putRawChar8(static_cast<std::uint8_t>(contrast)); | |||
| 16312 | buf->putRawChar8(static_cast<std::uint8_t>(fade)); | |||
| 16313 | if (version > DRW::AC1021) { // 2010+ clip mode | |||
| 16314 | buf->putBit(clipMode ? 1 : 0); | |||
| 16315 | } | |||
| 16316 | if (m_clipBoundaryType == 0) { | |||
| 16317 | buf->putBitShort(0); // clip_boundary_type 0 = none | |||
| 16318 | } else if (m_clipBoundaryType == 1) { | |||
| 16319 | buf->putBitShort(1); | |||
| 16320 | buf->put2RawDouble(clipPath[0]); | |||
| 16321 | buf->put2RawDouble(clipPath[1]); | |||
| 16322 | } else { | |||
| 16323 | buf->putBitShort(2); | |||
| 16324 | buf->putBitLong(static_cast<std::int32_t>(clipPath.size())); | |||
| 16325 | for (std::size_t i = 0; i < clipPath.size(); ++i) | |||
| 16326 | buf->put2RawDouble(clipPath[i]); | |||
| 16327 | } | |||
| 16328 | ||||
| 16329 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 16330 | ||||
| 16331 | // Emit both trailing handles UNCONDITIONALLY in parseDwg order: | |||
| 16332 | // imagedef (hard pointer, code 5) then imagedefreactor (hard owner, code 3). | |||
| 16333 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 16334 | auto makeHandle = [](std::uint8_t code, std::uint32_t r) { | |||
| 16335 | dwgHandle h; | |||
| 16336 | h.code = (r == 0) ? 0 : code; | |||
| 16337 | h.ref = r; | |||
| 16338 | h.size = 0; | |||
| 16339 | if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } } | |||
| 16340 | return h; | |||
| 16341 | }; | |||
| 16342 | hb->putHandle(makeHandle(5, ref)); // imagedef (340) | |||
| 16343 | hb->putHandle(makeHandle(3, m_imageDefReactorHandle)); // imagedefreactor (360) | |||
| 16344 | return true; | |||
| 16345 | } | |||
| 16346 | ||||
| 16347 | bool DRW_Wipeout::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 16348 | return DRW_Image::parseCode(code, reader); | |||
| 16349 | } | |||
| 16350 | ||||
| 16351 | bool DRW_Wipeout::hasValidBoundary() const { | |||
| 16352 | return m_clipBoundaryType != 0 && hasValidClipBoundary(); | |||
| 16353 | } | |||
| 16354 | ||||
| 16355 | bool DRW_Wipeout::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 16356 | if (buf == nullptr) | |||
| 16357 | return false; | |||
| 16358 | ||||
| 16359 | // Image parsing is transactional; keep it on a second cursor because a | |||
| 16360 | // valid image payload is still invalid for WIPEOUT when it has no clip | |||
| 16361 | // boundary. The wrapper must preserve the same failure contract. | |||
| 16362 | dwgBuffer probe = buf->forkIndependent(); | |||
| 16363 | if (!DRW_Image::parseDwg(version, &probe, bs)) { | |||
| 16364 | buf->invalidate(); | |||
| 16365 | resetDwgState(); | |||
| 16366 | return false; | |||
| 16367 | } | |||
| 16368 | if (!hasValidBoundary()) { | |||
| 16369 | buf->invalidate(); | |||
| 16370 | resetDwgState(); | |||
| 16371 | return false; | |||
| 16372 | } | |||
| 16373 | *buf = probe; | |||
| 16374 | return true; | |||
| 16375 | } | |||
| 16376 | ||||
| 16377 | bool DRW_Wipeout::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 16378 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 16379 | (void)bs; (void)strBuf; | |||
| 16380 | if (!validatePayloadFields()) { | |||
| 16381 | DRW_DBG("WIPEOUT has an invalid scalar or clip field\n")DRW_dbg::dbg("WIPEOUT has an invalid scalar or clip field\n"); | |||
| 16382 | return false; | |||
| 16383 | } | |||
| 16384 | if (clipPath.size() > DRW_Image::kMaxClipVertices) { | |||
| 16385 | DRW_DBG("WIPEOUT clip vertices exceed DWG limit\n")DRW_dbg::dbg("WIPEOUT clip vertices exceed DWG limit\n"); | |||
| 16386 | return false; | |||
| 16387 | } | |||
| 16388 | if (!hasValidBoundary()) { | |||
| 16389 | DRW_DBG("WIPEOUT has invalid clip boundary\n")DRW_dbg::dbg("WIPEOUT has invalid clip boundary\n"); | |||
| 16390 | return false; | |||
| 16391 | } | |||
| 16392 | // WIPEOUT is fixed DWG entity type 1109. It is not a custom class and | |||
| 16393 | // must not depend on a file-local CLASSES ordinal. | |||
| 16394 | oType = dwgType::WIPEOUT; | |||
| 16395 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 16396 | ||||
| 16397 | buf->putBitLong(0); | |||
| 16398 | buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z); | |||
| 16399 | buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z); | |||
| 16400 | buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z); | |||
| 16401 | buf->putRawDouble(sizeu); | |||
| 16402 | buf->putRawDouble(sizev); | |||
| 16403 | buf->putBitShort(static_cast<std::uint16_t>(m_displayProps)); | |||
| 16404 | buf->putBit(static_cast<std::uint8_t>(clip & 1)); | |||
| 16405 | buf->putRawChar8(static_cast<std::uint8_t>(brightness)); | |||
| 16406 | buf->putRawChar8(static_cast<std::uint8_t>(contrast)); | |||
| 16407 | buf->putRawChar8(static_cast<std::uint8_t>(fade)); | |||
| 16408 | if (version > DRW::AC1021) { | |||
| 16409 | buf->putBit(clipMode ? 1 : 0); | |||
| 16410 | } | |||
| 16411 | if (m_clipBoundaryType == 1) { | |||
| 16412 | buf->putBitShort(1); | |||
| 16413 | buf->put2RawDouble(clipPath[0]); | |||
| 16414 | buf->put2RawDouble(clipPath[1]); | |||
| 16415 | } else { | |||
| 16416 | buf->putBitShort(2); | |||
| 16417 | buf->putBitLong(static_cast<std::int32_t>(clipPath.size())); | |||
| 16418 | for (std::size_t i = 0; i < clipPath.size(); ++i) | |||
| 16419 | buf->put2RawDouble(clipPath[i]); | |||
| 16420 | } | |||
| 16421 | ||||
| 16422 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 16423 | ||||
| 16424 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 16425 | auto makeHandle = [](std::uint8_t code, std::uint32_t r) { | |||
| 16426 | dwgHandle h; | |||
| 16427 | h.code = (r == 0) ? 0 : code; | |||
| 16428 | h.ref = r; | |||
| 16429 | h.size = 0; | |||
| 16430 | if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } } | |||
| 16431 | return h; | |||
| 16432 | }; | |||
| 16433 | hb->putHandle(makeHandle(5, ref)); | |||
| 16434 | hb->putHandle(makeHandle(3, m_imageDefReactorHandle)); | |||
| 16435 | return true; | |||
| 16436 | } | |||
| 16437 | ||||
| 16438 | bool DRW_NavisworksModel::parseCode( | |||
| 16439 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 16440 | if (code == 100) { | |||
| 16441 | const std::string subclass = reader->getString(); | |||
| 16442 | if (subclass == "AcDbNavisworksModel") | |||
| 16443 | m_dxfInBody = true; | |||
| 16444 | return true; | |||
| 16445 | } | |||
| 16446 | if (!m_dxfInBody) | |||
| 16447 | return DRW_Entity::parseCode(code, reader); | |||
| 16448 | ||||
| 16449 | switch (code) { | |||
| 16450 | case 70: { | |||
| 16451 | const std::int32_t value = reader->getInt32(); | |||
| 16452 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 16453 | return false; | |||
| 16454 | flags = static_cast<std::uint16_t>(value); | |||
| 16455 | m_dxfSawFlags = true; | |||
| 16456 | return true; | |||
| 16457 | } | |||
| 16458 | case 340: | |||
| 16459 | definitionHandle = reader->getHandleString(); | |||
| 16460 | m_dxfSawDefinition = true; | |||
| 16461 | return true; | |||
| 16462 | case 40: | |||
| 16463 | if (m_dxfTransformCount < kTransformSize) { | |||
| 16464 | transform[m_dxfTransformCount++] = reader->getDouble(); | |||
| 16465 | return true; | |||
| 16466 | } | |||
| 16467 | if (m_dxfSawUnitFactor) | |||
| 16468 | return false; | |||
| 16469 | unitFactor = reader->getDouble(); | |||
| 16470 | m_dxfSawUnitFactor = true; | |||
| 16471 | return true; | |||
| 16472 | default: | |||
| 16473 | return DRW_Entity::parseCode(code, reader); | |||
| 16474 | } | |||
| 16475 | } | |||
| 16476 | ||||
| 16477 | bool DRW_NavisworksModel::finalizeDxf() { | |||
| 16478 | return m_dxfTransformCount == kTransformSize && m_dxfSawUnitFactor | |||
| 16479 | && std::isfinite(unitFactor) | |||
| 16480 | && std::all_of(transform.begin(), transform.end(), | |||
| 16481 | [](double value) { return std::isfinite(value); }); | |||
| 16482 | } | |||
| 16483 | ||||
| 16484 | void DRW_NavisworksModel::resetDwgState() { | |||
| 16485 | DRW_Entity::reset(); | |||
| 16486 | flags = 0; | |||
| 16487 | definitionHandle = 0; | |||
| 16488 | transform = {1.0, 0.0, 0.0, 0.0, | |||
| 16489 | 0.0, 1.0, 0.0, 0.0, | |||
| 16490 | 0.0, 0.0, 1.0, 0.0, | |||
| 16491 | 0.0, 0.0, 0.0, 1.0}; | |||
| 16492 | unitFactor = 1.0; | |||
| 16493 | } | |||
| 16494 | ||||
| 16495 | bool DRW_NavisworksModel::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 16496 | std::uint32_t bs) { | |||
| 16497 | resetDwgState(); | |||
| 16498 | dwgBuffer *sourceBuf = buf; | |||
| 16499 | auto fail = [this, sourceBuf]() { | |||
| 16500 | if (sourceBuf != nullptr) | |||
| 16501 | sourceBuf->invalidate(); | |||
| 16502 | resetDwgState(); | |||
| 16503 | return false; | |||
| 16504 | }; | |||
| 16505 | if (sourceBuf == nullptr) | |||
| 16506 | return fail(); | |||
| 16507 | if (version < DRW::AC1015) | |||
| 16508 | return fail(); | |||
| 16509 | ||||
| 16510 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 16511 | dwgBuffer stringBuffer = bodyProbe.forkIndependent(); | |||
| 16512 | dwgBuffer *stringBuf = version > DRW::AC1018 ? &stringBuffer : &bodyProbe; | |||
| 16513 | if (!DRW_Entity::parseDwg(version, &bodyProbe, stringBuf, bs)) | |||
| 16514 | return fail(); | |||
| 16515 | ||||
| 16516 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 16517 | std::uint64_t handleEndBit = 0; | |||
| 16518 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 16519 | handleEndBit)) | |||
| 16520 | return fail(); | |||
| 16521 | // BS is an unsigned bit-short at the codec boundary. The flags are a | |||
| 16522 | // mask, so values with bit 15 set must survive instead of being rejected | |||
| 16523 | // through an intermediate signed conversion. | |||
| 16524 | std::uint16_t parsedFlags = 0; | |||
| 16525 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedFlags)) | |||
| 16526 | return fail(); | |||
| 16527 | ||||
| 16528 | std::uint32_t parsedDefinitionHandle = 0; | |||
| 16529 | if (version <= DRW::AC1018) { | |||
| 16530 | dwgHandle definition; | |||
| 16531 | if (!readBoundedDwgHandle(bodyProbe, handleEndBit, 0, false, | |||
| 16532 | definition)) | |||
| 16533 | return fail(); | |||
| 16534 | parsedDefinitionHandle = definition.ref; | |||
| 16535 | } | |||
| 16536 | ||||
| 16537 | std::array<double, 16> parsedTransform{}; | |||
| 16538 | for (double& value : parsedTransform) { | |||
| 16539 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, value)) | |||
| 16540 | return fail(); | |||
| 16541 | } | |||
| 16542 | double parsedUnitFactor = 0.0; | |||
| 16543 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedUnitFactor)) | |||
| 16544 | return fail(); | |||
| 16545 | if (!std::all_of(parsedTransform.begin(), parsedTransform.end(), | |||
| 16546 | [](double value) { return std::isfinite(value); }) | |||
| 16547 | || !std::isfinite(parsedUnitFactor)) { | |||
| 16548 | return fail(); | |||
| 16549 | } | |||
| 16550 | ||||
| 16551 | if (!DRW_Entity::parseDwgEntHandle(version, &bodyProbe, true, | |||
| 16552 | handleEndBit)) | |||
| 16553 | return fail(); | |||
| 16554 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 16555 | if (version > DRW::AC1018) { | |||
| 16556 | dwgHandle definition; | |||
| 16557 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 16558 | definition)) | |||
| 16559 | return fail(); | |||
| 16560 | parsedDefinitionHandle = definition.ref; | |||
| 16561 | } | |||
| 16562 | if (!handleProbe.isGood() || !stringBuf->isGood()) | |||
| 16563 | return fail(); | |||
| 16564 | flags = parsedFlags; | |||
| 16565 | transform = parsedTransform; | |||
| 16566 | unitFactor = parsedUnitFactor; | |||
| 16567 | definitionHandle = parsedDefinitionHandle; | |||
| 16568 | *sourceBuf = handleProbe; | |||
| 16569 | return true; | |||
| 16570 | } | |||
| 16571 | ||||
| 16572 | bool DRW_NavisworksModel::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 16573 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 16574 | dwgBufferW *handleBuf) { | |||
| 16575 | (void)bs; | |||
| 16576 | if (version < DRW::AC1015 | |||
| 16577 | || !std::isfinite(unitFactor) | |||
| 16578 | || !std::all_of(transform.begin(), transform.end(), | |||
| 16579 | [](double value) { return std::isfinite(value); })) | |||
| 16580 | return false; | |||
| 16581 | ||||
| 16582 | oType = kDwgClassNum; | |||
| 16583 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 16584 | return false; | |||
| 16585 | ||||
| 16586 | buf->putBitShort(flags); | |||
| 16587 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 16588 | auto makeHandle = [](std::uint8_t code, std::uint32_t ref) { | |||
| 16589 | dwgHandle handle; | |||
| 16590 | handle.code = ref == 0 ? 0 : code; | |||
| 16591 | handle.ref = ref; | |||
| 16592 | handle.size = 0; | |||
| 16593 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 16594 | ++handle.size; | |||
| 16595 | return handle; | |||
| 16596 | }; | |||
| 16597 | ||||
| 16598 | // AC1015/AC1018 place this entity-specific handle before the matrix in | |||
| 16599 | // the legacy data stream. AC1021+ places it after the common handles. | |||
| 16600 | if (version <= DRW::AC1018) | |||
| 16601 | buf->putHandle(makeHandle(2, definitionHandle)); | |||
| 16602 | for (double value : transform) | |||
| 16603 | buf->putBitDouble(value); | |||
| 16604 | buf->putBitDouble(unitFactor); | |||
| 16605 | ||||
| 16606 | if (!DRW_Entity::encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 16607 | return false; | |||
| 16608 | if (version > DRW::AC1018) | |||
| 16609 | hb->putHandle(makeHandle(2, definitionHandle)); | |||
| 16610 | return true; | |||
| 16611 | } | |||
| 16612 | ||||
| 16613 | bool DRW_PointCloud::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 16614 | if (code == 100) { | |||
| 16615 | m_dxfInBody = reader->getString() == "AcDbPointCloud"; | |||
| 16616 | return true; | |||
| 16617 | } | |||
| 16618 | if (!m_dxfInBody) | |||
| 16619 | return DRW_Entity::parseCode(code, reader); | |||
| 16620 | switch (code) { | |||
| 16621 | case 70: | |||
| 16622 | m_dxfSawClassVersion = true; | |||
| 16623 | classVersion = reader->getInt32(); | |||
| 16624 | break; | |||
| 16625 | case 10: origin.x = reader->getDouble(); break; | |||
| 16626 | case 20: origin.y = reader->getDouble(); break; | |||
| 16627 | case 30: origin.z = reader->getDouble(); break; | |||
| 16628 | case 1: savedFilename = reader->getUtf8String(); break; | |||
| 16629 | case 90: | |||
| 16630 | if (m_dxfSawSourceCount) | |||
| 16631 | return false; | |||
| 16632 | m_dxfSawSourceCount = true; | |||
| 16633 | sourceFileCount = reader->getInt32(); | |||
| 16634 | if (!isValidCount(sourceFileCount, | |||
| 16635 | static_cast<std::int32_t>(kMaxItems))) { | |||
| 16636 | return false; | |||
| 16637 | } | |||
| 16638 | sourceFiles.clear(); | |||
| 16639 | if (!DRW::reserve(sourceFiles, sourceFileCount)) | |||
| 16640 | return false; | |||
| 16641 | break; | |||
| 16642 | case 2: | |||
| 16643 | if (sourceFiles.size() >= static_cast<std::size_t>(sourceFileCount)) | |||
| 16644 | return false; | |||
| 16645 | sourceFiles.push_back(reader->getUtf8String()); | |||
| 16646 | break; | |||
| 16647 | case 3: ucsName = reader->getUtf8String(); break; | |||
| 16648 | case 11: extentsMin.x = reader->getDouble(); break; | |||
| 16649 | case 21: extentsMin.y = reader->getDouble(); break; | |||
| 16650 | case 31: extentsMin.z = reader->getDouble(); break; | |||
| 16651 | case 12: extentsMax.x = reader->getDouble(); break; | |||
| 16652 | case 22: extentsMax.y = reader->getDouble(); break; | |||
| 16653 | case 32: extentsMax.z = reader->getDouble(); break; | |||
| 16654 | case 92: { | |||
| 16655 | if (m_dxfSawPointCount) | |||
| 16656 | return false; | |||
| 16657 | m_dxfSawPointCount = true; | |||
| 16658 | const std::int32_t count = reader->getInt32(); | |||
| 16659 | if (count < 0) | |||
| 16660 | return false; | |||
| 16661 | pointCount = static_cast<std::uint64_t>(count); | |||
| 16662 | break; | |||
| 16663 | } | |||
| 16664 | case 13: ucsOrigin.x = reader->getDouble(); break; | |||
| 16665 | case 23: ucsOrigin.y = reader->getDouble(); break; | |||
| 16666 | case 33: ucsOrigin.z = reader->getDouble(); break; | |||
| 16667 | case 210: ucsXDirection.x = reader->getDouble(); break; | |||
| 16668 | case 220: ucsXDirection.y = reader->getDouble(); break; | |||
| 16669 | case 230: ucsXDirection.z = reader->getDouble(); break; | |||
| 16670 | case 211: ucsYDirection.x = reader->getDouble(); break; | |||
| 16671 | case 221: ucsYDirection.y = reader->getDouble(); break; | |||
| 16672 | case 231: ucsYDirection.z = reader->getDouble(); break; | |||
| 16673 | case 212: ucsZDirection.x = reader->getDouble(); break; | |||
| 16674 | case 222: ucsZDirection.y = reader->getDouble(); break; | |||
| 16675 | case 232: ucsZDirection.z = reader->getDouble(); break; | |||
| 16676 | case 330: | |||
| 16677 | if (!m_dxfInBody) | |||
| 16678 | return DRW_Entity::parseCode(code, reader); | |||
| 16679 | definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 16680 | break; | |||
| 16681 | case 360: reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); break; | |||
| 16682 | case 71: intensityScheme = reader->getInt32(); break; | |||
| 16683 | case 40: intensityStyle.minIntensity = reader->getDouble(); break; | |||
| 16684 | case 41: intensityStyle.maxIntensity = reader->getDouble(); break; | |||
| 16685 | case 42: intensityStyle.lowThreshold = reader->getDouble(); break; | |||
| 16686 | case 43: intensityStyle.highThreshold = reader->getDouble(); break; | |||
| 16687 | default: | |||
| 16688 | return DRW_Entity::parseCode(code, reader); | |||
| 16689 | } | |||
| 16690 | return true; | |||
| 16691 | } | |||
| 16692 | ||||
| 16693 | bool DRW_PointCloud::finalizeDxf() { | |||
| 16694 | return m_dxfSawClassVersion && m_dxfSawSourceCount && m_dxfSawPointCount | |||
| 16695 | && isValidCount(sourceFileCount, | |||
| 16696 | static_cast<std::int32_t>(kMaxItems)) | |||
| 16697 | && sourceFiles.size() == static_cast<std::size_t>(sourceFileCount); | |||
| 16698 | } | |||
| 16699 | ||||
| 16700 | void DRW_PointCloud::resetDwgState() { | |||
| 16701 | DRW_Entity::reset(); | |||
| 16702 | classVersion = 0; | |||
| 16703 | origin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16704 | savedFilename.clear(); | |||
| 16705 | sourceFileCount = 0; | |||
| 16706 | sourceFiles.clear(); | |||
| 16707 | extentsMin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16708 | extentsMax = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16709 | pointCount = 0; | |||
| 16710 | ucsName.clear(); | |||
| 16711 | ucsOrigin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16712 | ucsXDirection = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 16713 | ucsYDirection = DRW_Coord{0.0, 1.0, 0.0}; | |||
| 16714 | ucsZDirection = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 16715 | definitionHandle = 0; | |||
| 16716 | reactorHandle = 0; | |||
| 16717 | showIntensity = false; | |||
| 16718 | intensityScheme = 0; | |||
| 16719 | intensityStyle = DRW_PointCloudIntensityStyle{}; | |||
| 16720 | showClipping = false; | |||
| 16721 | clippingCount = 0; | |||
| 16722 | clippings.clear(); | |||
| 16723 | m_dxfInBody = false; | |||
| 16724 | m_dxfSawClassVersion = false; | |||
| 16725 | m_dxfSawSourceCount = false; | |||
| 16726 | m_dxfSawPointCount = false; | |||
| 16727 | } | |||
| 16728 | ||||
| 16729 | bool DRW_PointCloud::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 16730 | resetDwgState(); | |||
| 16731 | dwgBuffer *sourceBuf = buf; | |||
| 16732 | auto fail = [this, sourceBuf]() { | |||
| 16733 | if (sourceBuf != nullptr) | |||
| 16734 | sourceBuf->invalidate(); | |||
| 16735 | resetDwgState(); | |||
| 16736 | return false; | |||
| 16737 | }; | |||
| 16738 | if (sourceBuf == nullptr || version <= DRW::AC1018) | |||
| 16739 | return fail(); | |||
| 16740 | ||||
| 16741 | const auto finite = [](const DRW_Coord& point) { | |||
| 16742 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 16743 | && std::isfinite(point.z); | |||
| 16744 | }; | |||
| 16745 | ||||
| 16746 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 16747 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 16748 | if (!DRW_Entity::parseDwg(version, &bodyProbe, &stringProbe, bs)) | |||
| 16749 | return fail(); | |||
| 16750 | ||||
| 16751 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 16752 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 16753 | if (version > DRW::AC1021) { | |||
| 16754 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 16755 | if (!entityBodyDataEndBit(stringProbe, version, objSize, | |||
| 16756 | ignoredBodyEndBit, &stringEndBit)) | |||
| 16757 | return fail(); | |||
| 16758 | } | |||
| 16759 | std::uint16_t parsedClassVersion = 0; | |||
| 16760 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedClassVersion) | |||
| 16761 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, origin)) | |||
| 16762 | return fail(); | |||
| 16763 | classVersion = parsedClassVersion; | |||
| 16764 | if (!finite(origin)) | |||
| 16765 | return fail(); | |||
| 16766 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16767 | savedFilename)) | |||
| 16768 | return fail(); | |||
| 16769 | std::uint32_t declaredSourceFiles = 0; | |||
| 16770 | if (!readTableBodyCount( | |||
| 16771 | version, &bodyProbe, objSize, | |||
| 16772 | static_cast<std::uint32_t>(kMaxItems), 2, | |||
| 16773 | declaredSourceFiles)) { | |||
| 16774 | return fail(); | |||
| 16775 | } | |||
| 16776 | sourceFileCount = static_cast<int>(declaredSourceFiles); | |||
| 16777 | sourceFiles.clear(); | |||
| 16778 | ||||
| 16779 | if (sourceFileCount == 0) { | |||
| 16780 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMin) | |||
| 16781 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMax) | |||
| 16782 | || !readBoundedRawLong64(bodyProbe, bodyEndBit, pointCount)) | |||
| 16783 | return fail(); | |||
| 16784 | if (!finite(extentsMin) || !finite(extentsMax)) | |||
| 16785 | return fail(); | |||
| 16786 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16787 | ucsName)) | |||
| 16788 | return fail(); | |||
| 16789 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, ucsOrigin) | |||
| 16790 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsXDirection) | |||
| 16791 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsYDirection) | |||
| 16792 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsZDirection)) | |||
| 16793 | return fail(); | |||
| 16794 | if (!finite(ucsOrigin) || !finite(ucsXDirection) | |||
| 16795 | || !finite(ucsYDirection) || !finite(ucsZDirection)) { | |||
| 16796 | return fail(); | |||
| 16797 | } | |||
| 16798 | ||||
| 16799 | if (version > DRW::AC1024) { | |||
| 16800 | std::uint16_t parsedIntensityScheme = 0; | |||
| 16801 | if (!readBoundedBit(bodyProbe, bodyEndBit, showIntensity) | |||
| 16802 | || !readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 16803 | parsedIntensityScheme) | |||
| 16804 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16805 | intensityStyle.minIntensity) | |||
| 16806 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16807 | intensityStyle.maxIntensity) | |||
| 16808 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16809 | intensityStyle.lowThreshold) | |||
| 16810 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16811 | intensityStyle.highThreshold)) | |||
| 16812 | return fail(); | |||
| 16813 | intensityScheme = static_cast<int>(parsedIntensityScheme); | |||
| 16814 | if (!std::isfinite(intensityStyle.minIntensity) | |||
| 16815 | || !std::isfinite(intensityStyle.maxIntensity) | |||
| 16816 | || !std::isfinite(intensityStyle.lowThreshold) | |||
| 16817 | || !std::isfinite(intensityStyle.highThreshold)) { | |||
| 16818 | return fail(); | |||
| 16819 | } | |||
| 16820 | if (!readBoundedBit(bodyProbe, bodyEndBit, showClipping)) | |||
| 16821 | return fail(); | |||
| 16822 | ||||
| 16823 | std::uint32_t declaredClippings = 0; | |||
| 16824 | if (!readTableBodyCount( | |||
| 16825 | version, &bodyProbe, objSize, | |||
| 16826 | static_cast<std::uint32_t>(kMaxItems), 2, | |||
| 16827 | declaredClippings)) { | |||
| 16828 | return fail(); | |||
| 16829 | } | |||
| 16830 | clippingCount = static_cast<int>(declaredClippings); | |||
| 16831 | clippings.clear(); | |||
| 16832 | if (!DRW::reserve(clippings, clippingCount)) | |||
| 16833 | return fail(); | |||
| 16834 | for (std::int32_t i = 0; i < clippingCount; ++i) { | |||
| 16835 | DRW_PointCloudClipping clipping; | |||
| 16836 | if (!readBoundedBit(bodyProbe, bodyEndBit, | |||
| 16837 | clipping.isInverted)) | |||
| 16838 | return fail(); | |||
| 16839 | std::uint16_t clippingType = 0; | |||
| 16840 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, clippingType)) | |||
| 16841 | return fail(); | |||
| 16842 | clipping.type = clippingType; | |||
| 16843 | if (clipping.type < 1 || clipping.type > 3) | |||
| 16844 | return fail(); | |||
| 16845 | std::uint32_t vertexCount = 2; | |||
| 16846 | if (clipping.type == 3 | |||
| 16847 | && !readTableBodyCount( | |||
| 16848 | version, &bodyProbe, objSize, | |||
| 16849 | static_cast<std::uint32_t>(kMaxItems), 128, | |||
| 16850 | vertexCount)) { | |||
| 16851 | return fail(); | |||
| 16852 | } | |||
| 16853 | clipping.vertexCount = static_cast<int>(vertexCount); | |||
| 16854 | if (!DRW::reserve(clipping.vertices, clipping.vertexCount)) | |||
| 16855 | return fail(); | |||
| 16856 | for (std::int32_t j = 0; j < clipping.vertexCount; ++j) { | |||
| 16857 | DRW_Coord vertex; | |||
| 16858 | if (!readBounded2RawDouble(bodyProbe, bodyEndBit, vertex)) | |||
| 16859 | return fail(); | |||
| 16860 | clipping.vertices.push_back(vertex); | |||
| 16861 | } | |||
| 16862 | if (clipping.type == 1) { | |||
| 16863 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16864 | clipping.zMin) | |||
| 16865 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16866 | clipping.zMax)) | |||
| 16867 | return fail(); | |||
| 16868 | } | |||
| 16869 | if (!std::all_of( | |||
| 16870 | clipping.vertices.begin(), clipping.vertices.end(), | |||
| 16871 | finite) | |||
| 16872 | || !std::isfinite(clipping.zMin) | |||
| 16873 | || !std::isfinite(clipping.zMax)) { | |||
| 16874 | return fail(); | |||
| 16875 | } | |||
| 16876 | clippings.push_back(std::move(clipping)); | |||
| 16877 | } | |||
| 16878 | } else { | |||
| 16879 | showIntensity = false; | |||
| 16880 | intensityScheme = 0; | |||
| 16881 | showClipping = false; | |||
| 16882 | clippingCount = 0; | |||
| 16883 | clippings.clear(); | |||
| 16884 | } | |||
| 16885 | } | |||
| 16886 | ||||
| 16887 | if (!DRW::reserve(sourceFiles, sourceFileCount)) | |||
| 16888 | return fail(); | |||
| 16889 | for (std::int32_t i = 0; i < sourceFileCount; ++i) { | |||
| 16890 | UTF8STRINGstd::string sourceFile; | |||
| 16891 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16892 | sourceFile)) | |||
| 16893 | return fail(); | |||
| 16894 | sourceFiles.push_back(std::move(sourceFile)); | |||
| 16895 | } | |||
| 16896 | ||||
| 16897 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 16898 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 16899 | || currentDwgBit(&stringProbe) > stringEndBit) | |||
| 16900 | return fail(); | |||
| 16901 | ||||
| 16902 | std::uint64_t handleEndBit = 0; | |||
| 16903 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 16904 | handleEndBit)) | |||
| 16905 | return fail(); | |||
| 16906 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 16907 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 16908 | handleEndBit) | |||
| 16909 | || !handleProbe.isGood()) | |||
| 16910 | return fail(); | |||
| 16911 | std::uint32_t parsedDefinitionHandle = 0; | |||
| 16912 | std::uint32_t parsedReactorHandle = 0; | |||
| 16913 | if (version > DRW::AC1024 && sourceFileCount == 0) { | |||
| 16914 | dwgHandle definition; | |||
| 16915 | dwgHandle reactor; | |||
| 16916 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 16917 | definition) | |||
| 16918 | || !readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 16919 | reactor)) | |||
| 16920 | return fail(); | |||
| 16921 | parsedDefinitionHandle = definition.ref; | |||
| 16922 | parsedReactorHandle = reactor.ref; | |||
| 16923 | } | |||
| 16924 | if (!handleProbe.isGood() || !stringProbe.isGood()) | |||
| 16925 | return fail(); | |||
| 16926 | definitionHandle = parsedDefinitionHandle; | |||
| 16927 | reactorHandle = parsedReactorHandle; | |||
| 16928 | *sourceBuf = handleProbe; | |||
| 16929 | return true; | |||
| 16930 | } | |||
| 16931 | ||||
| 16932 | bool DRW_PointCloud::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 16933 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 16934 | (void)bs; | |||
| 16935 | const auto finite = [](const DRW_Coord& point) { | |||
| 16936 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 16937 | && std::isfinite(point.z); | |||
| 16938 | }; | |||
| 16939 | if (version <= DRW::AC1018 | |||
| 16940 | || classVersion > std::numeric_limits<std::uint16_t>::max() | |||
| 16941 | || sourceFileCount < 0 | |||
| 16942 | || sourceFileCount > static_cast<int>(kMaxItems) | |||
| 16943 | || sourceFiles.size() != static_cast<std::size_t>(sourceFileCount) | |||
| 16944 | || clippingCount < 0 | |||
| 16945 | || (sourceFileCount == 0 && clippings.size() > kMaxItems) | |||
| 16946 | || (sourceFileCount != 0 | |||
| 16947 | && (clippingCount != 0 || !clippings.empty() | |||
| 16948 | || showIntensity || showClipping)) | |||
| 16949 | || intensityScheme < 0 | |||
| 16950 | || intensityScheme > std::numeric_limits<std::uint16_t>::max() | |||
| 16951 | || clippings.size() != static_cast<std::size_t>(clippingCount)) { | |||
| 16952 | return false; | |||
| 16953 | } | |||
| 16954 | if (!finite(origin) || !finite(extentsMin) || !finite(extentsMax) | |||
| 16955 | || !finite(ucsOrigin) || !finite(ucsXDirection) | |||
| 16956 | || !finite(ucsYDirection) || !finite(ucsZDirection) | |||
| 16957 | || !std::isfinite(intensityStyle.minIntensity) | |||
| 16958 | || !std::isfinite(intensityStyle.maxIntensity) | |||
| 16959 | || !std::isfinite(intensityStyle.lowThreshold) | |||
| 16960 | || !std::isfinite(intensityStyle.highThreshold)) { | |||
| 16961 | return false; | |||
| 16962 | } | |||
| 16963 | for (const DRW_PointCloudClipping& clipping : clippings) { | |||
| 16964 | if (clipping.type < 1 || clipping.type > 3 | |||
| 16965 | || clipping.vertexCount < 0 | |||
| 16966 | || clipping.vertexCount > static_cast<int>(kMaxItems) | |||
| 16967 | || clipping.vertices.size() != static_cast<std::size_t>(clipping.vertexCount) | |||
| 16968 | || (clipping.type != 3 && clipping.vertexCount != 2) | |||
| 16969 | || !std::isfinite(clipping.zMin) | |||
| 16970 | || !std::isfinite(clipping.zMax)) { | |||
| 16971 | return false; | |||
| 16972 | } | |||
| 16973 | for (const DRW_Coord& vertex : clipping.vertices) { | |||
| 16974 | if (!finite(vertex)) | |||
| 16975 | return false; | |||
| 16976 | } | |||
| 16977 | } | |||
| 16978 | ||||
| 16979 | oType = kDwgClassNum; | |||
| 16980 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 16981 | return false; | |||
| 16982 | dwgBufferW *sBuf = strBuf ? strBuf : buf; | |||
| 16983 | buf->putBitShort(static_cast<std::uint16_t>(classVersion)); | |||
| 16984 | buf->put3BitDouble(origin); | |||
| 16985 | sBuf->putVariableText(version, savedFilename); | |||
| 16986 | buf->putBitLong(sourceFileCount); | |||
| 16987 | if (sourceFileCount == 0) { | |||
| 16988 | buf->put3BitDouble(extentsMin); | |||
| 16989 | buf->put3BitDouble(extentsMax); | |||
| 16990 | buf->putRawLong64(pointCount); | |||
| 16991 | sBuf->putVariableText(version, ucsName); | |||
| 16992 | buf->put3BitDouble(ucsOrigin); | |||
| 16993 | buf->put3BitDouble(ucsXDirection); | |||
| 16994 | buf->put3BitDouble(ucsYDirection); | |||
| 16995 | buf->put3BitDouble(ucsZDirection); | |||
| 16996 | ||||
| 16997 | if (version > DRW::AC1024) { | |||
| 16998 | buf->putBit(showIntensity ? 1 : 0); | |||
| 16999 | buf->putBitShort(static_cast<std::uint16_t>(intensityScheme)); | |||
| 17000 | buf->putBitDouble(intensityStyle.minIntensity); | |||
| 17001 | buf->putBitDouble(intensityStyle.maxIntensity); | |||
| 17002 | buf->putBitDouble(intensityStyle.lowThreshold); | |||
| 17003 | buf->putBitDouble(intensityStyle.highThreshold); | |||
| 17004 | buf->putBit(showClipping ? 1 : 0); | |||
| 17005 | buf->putBitLong(clippingCount); | |||
| 17006 | for (const DRW_PointCloudClipping& clipping : clippings) { | |||
| 17007 | buf->putBit(clipping.isInverted ? 1 : 0); | |||
| 17008 | buf->putBitShort(static_cast<std::uint16_t>(clipping.type)); | |||
| 17009 | if (clipping.type == 3) | |||
| 17010 | buf->putBitLong(clipping.vertexCount); | |||
| 17011 | for (const DRW_Coord& vertex : clipping.vertices) | |||
| 17012 | buf->put2RawDouble(vertex); | |||
| 17013 | if (clipping.type == 1) { | |||
| 17014 | buf->putBitDouble(clipping.zMin); | |||
| 17015 | buf->putBitDouble(clipping.zMax); | |||
| 17016 | } | |||
| 17017 | } | |||
| 17018 | } | |||
| 17019 | } | |||
| 17020 | for (const UTF8STRINGstd::string& sourceFile : sourceFiles) | |||
| 17021 | sBuf->putVariableText(version, sourceFile); | |||
| 17022 | ||||
| 17023 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 17024 | return false; | |||
| 17025 | if (version > DRW::AC1024 && sourceFileCount == 0) { | |||
| 17026 | dwgBufferW *hBuf = handleBuf ? handleBuf : buf; | |||
| 17027 | auto putHandle = [hBuf](std::uint8_t code, std::uint32_t ref) { | |||
| 17028 | dwgHandle handle; | |||
| 17029 | handle.code = ref == 0 ? 0 : code; | |||
| 17030 | handle.ref = ref; | |||
| 17031 | handle.size = 0; | |||
| 17032 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 17033 | ++handle.size; | |||
| 17034 | hBuf->putHandle(handle); | |||
| 17035 | }; | |||
| 17036 | putHandle(5, definitionHandle); | |||
| 17037 | putHandle(3, reactorHandle); | |||
| 17038 | } | |||
| 17039 | return true; | |||
| 17040 | } | |||
| 17041 | ||||
| 17042 | bool DRW_PointCloudEx::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17043 | if (code == 100) { | |||
| 17044 | m_dxfInBody = reader->getString() == "AcDbPointCloud"; | |||
| 17045 | return true; | |||
| 17046 | } | |||
| 17047 | if (!m_dxfInBody) | |||
| 17048 | return DRW_Entity::parseCode(code, reader); | |||
| 17049 | switch (code) { | |||
| 17050 | case 70: | |||
| 17051 | if (m_dxfSeen70++ != 0) return false; | |||
| 17052 | classVersion = reader->getInt32(); | |||
| 17053 | break; | |||
| 17054 | case 10: extentsMin.x = reader->getDouble(); break; | |||
| 17055 | case 20: extentsMin.y = reader->getDouble(); break; | |||
| 17056 | case 30: extentsMin.z = reader->getDouble(); break; | |||
| 17057 | case 11: extentsMax.x = reader->getDouble(); break; | |||
| 17058 | case 21: extentsMax.y = reader->getDouble(); break; | |||
| 17059 | case 31: extentsMax.z = reader->getDouble(); break; | |||
| 17060 | case 12: ucsOrigin.x = reader->getDouble(); break; | |||
| 17061 | case 22: ucsOrigin.y = reader->getDouble(); break; | |||
| 17062 | case 32: ucsOrigin.z = reader->getDouble(); break; | |||
| 17063 | case 210: ucsXDirection.x = reader->getDouble(); break; | |||
| 17064 | case 220: ucsXDirection.y = reader->getDouble(); break; | |||
| 17065 | case 230: ucsXDirection.z = reader->getDouble(); break; | |||
| 17066 | case 211: ucsYDirection.x = reader->getDouble(); break; | |||
| 17067 | case 221: ucsYDirection.y = reader->getDouble(); break; | |||
| 17068 | case 231: ucsYDirection.z = reader->getDouble(); break; | |||
| 17069 | case 212: ucsZDirection.x = reader->getDouble(); break; | |||
| 17070 | case 222: ucsZDirection.y = reader->getDouble(); break; | |||
| 17071 | case 232: ucsZDirection.z = reader->getDouble(); break; | |||
| 17072 | case 290: | |||
| 17073 | if (m_dxfHasCropping) { | |||
| 17074 | if (m_dxfSeen290 % 2 == 0) | |||
| 17075 | m_dxfCurrentCropping.isInside = reader->getBool(); | |||
| 17076 | else | |||
| 17077 | m_dxfCurrentCropping.isInverted = reader->getBool(); | |||
| 17078 | ++m_dxfSeen290; | |||
| 17079 | } else { | |||
| 17080 | if (m_dxfSeen290++ != 0) return false; | |||
| 17081 | isLocked = reader->getBool(); | |||
| 17082 | } | |||
| 17083 | break; | |||
| 17084 | case 330: | |||
| 17085 | if (!m_dxfInBody) | |||
| 17086 | return DRW_Entity::parseCode(code, reader); | |||
| 17087 | definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 17088 | break; | |||
| 17089 | case 360: | |||
| 17090 | reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 17091 | break; | |||
| 17092 | case 1: | |||
| 17093 | switch (m_dxfTextCount++) { | |||
| 17094 | case 0: name = reader->getUtf8String(); break; | |||
| 17095 | case 1: intensityColorScheme = reader->getUtf8String(); break; | |||
| 17096 | case 2: currentColorScheme = reader->getUtf8String(); break; | |||
| 17097 | case 3: classificationColorScheme = reader->getUtf8String(); break; | |||
| 17098 | default: return false; | |||
| 17099 | } | |||
| 17100 | break; | |||
| 17101 | case 291: showIntensity = reader->getBool(); break; | |||
| 17102 | case 295: showCropping = reader->getBool(); break; | |||
| 17103 | case 71: | |||
| 17104 | if (m_dxfSeen71++ == 0) | |||
| 17105 | stylizationType = reader->getInt32(); | |||
| 17106 | else if (m_dxfSeen71 == 2) | |||
| 17107 | intensityOutOfRangeBehavior = reader->getInt32(); | |||
| 17108 | else | |||
| 17109 | return false; | |||
| 17110 | break; | |||
| 17111 | case 72: elevationOutOfRangeBehavior = reader->getInt32(); break; | |||
| 17112 | case 40: | |||
| 17113 | if (m_dxfSeen40++ == 0) | |||
| 17114 | elevationMin = reader->getDouble(); | |||
| 17115 | else if (m_dxfSeen40 == 2) | |||
| 17116 | elevationMax = reader->getDouble(); | |||
| 17117 | else | |||
| 17118 | return false; | |||
| 17119 | break; | |||
| 17120 | case 41: elevationMax = reader->getDouble(); break; | |||
| 17121 | case 90: | |||
| 17122 | if (m_dxfSeen90++ != 0) return false; | |||
| 17123 | intensityMin = reader->getInt32(); | |||
| 17124 | break; | |||
| 17125 | case 91: | |||
| 17126 | if (m_dxfSeen91++ != 0) return false; | |||
| 17127 | intensityMax = reader->getInt32(); | |||
| 17128 | break; | |||
| 17129 | case 292: elevationApplyToFixedRange = reader->getBool(); break; | |||
| 17130 | case 293: intensityAsGradient = reader->getBool(); break; | |||
| 17131 | case 294: elevationAsGradient = reader->getBool(); break; | |||
| 17132 | case 92: { | |||
| 17133 | if (m_dxfSawCroppingCount) return false; | |||
| 17134 | const std::int32_t count = reader->getInt32(); | |||
| 17135 | if (!isValidCount(count, static_cast<std::int32_t>(kMaxItems))) | |||
| 17136 | return false; | |||
| 17137 | croppingCount = count; | |||
| 17138 | m_dxfSawCroppingCount = true; | |||
| 17139 | break; | |||
| 17140 | } | |||
| 17141 | case 93: | |||
| 17142 | if (m_dxfHasCropping) { | |||
| 17143 | if (m_dxfSeen93++ != 0) return false; | |||
| 17144 | m_dxfCurrentCropping.pointCount = reader->getInt32(); | |||
| 17145 | if (!isValidCount(m_dxfCurrentCropping.pointCount, | |||
| 17146 | static_cast<std::int32_t>(kMaxItems))) { | |||
| 17147 | return false; | |||
| 17148 | } | |||
| 17149 | m_dxfCurrentCropping.points.clear(); | |||
| 17150 | if (!DRW::reserve(m_dxfCurrentCropping.points, | |||
| 17151 | m_dxfCurrentCropping.pointCount)) | |||
| 17152 | return false; | |||
| 17153 | } else if (m_dxfSawCroppingCount && croppingCount == 0) { | |||
| 17154 | if (m_dxfSeen93++ == 0) | |||
| 17155 | unknownInt0 = reader->getInt32(); | |||
| 17156 | else if (m_dxfSeen93 == 2) | |||
| 17157 | unknownInt1 = reader->getInt32(); | |||
| 17158 | else | |||
| 17159 | return false; | |||
| 17160 | } else { | |||
| 17161 | return false; | |||
| 17162 | } | |||
| 17163 | break; | |||
| 17164 | case 280: | |||
| 17165 | if (!m_dxfSawCroppingCount || croppingCount == 0 | |||
| 17166 | || !finishDxfCropping()) { | |||
| 17167 | return false; | |||
| 17168 | } | |||
| 17169 | m_dxfCurrentCropping = DRW_PointCloudExCropping{}; | |||
| 17170 | m_dxfCurrentCropping.type = reader->getInt32(); | |||
| 17171 | if (m_dxfCurrentCropping.type < 0 | |||
| 17172 | || m_dxfCurrentCropping.type > std::numeric_limits<std::uint16_t>::max()) { | |||
| 17173 | return false; | |||
| 17174 | } | |||
| 17175 | m_dxfHasCropping = true; | |||
| 17176 | m_dxfSeen290 = 0; | |||
| 17177 | m_dxfSeen93 = 0; | |||
| 17178 | m_dxfDirectionComponent = 0; | |||
| 17179 | m_dxfCropPlaneComponent = 0; | |||
| 17180 | m_dxfCropPointOpen = false; | |||
| 17181 | break; | |||
| 17182 | case 13: | |||
| 17183 | case 23: | |||
| 17184 | case 33: | |||
| 17185 | if (!m_dxfHasCropping) { | |||
| 17186 | if (code == 13) ucsOrigin.x = reader->getDouble(); | |||
| 17187 | else if (code == 23) ucsOrigin.y = reader->getDouble(); | |||
| 17188 | else ucsOrigin.z = reader->getDouble(); | |||
| 17189 | } else if (m_dxfCropPlaneComponent < 3) { | |||
| 17190 | if (code == 13 && m_dxfCropPlaneComponent != 0) return false; | |||
| 17191 | if (code == 23 && m_dxfCropPlaneComponent != 1) return false; | |||
| 17192 | if (code == 33 && m_dxfCropPlaneComponent != 2) return false; | |||
| 17193 | const double value = reader->getDouble(); | |||
| 17194 | if (code == 13) m_dxfCurrentCropping.cropPlane.x = value; | |||
| 17195 | else if (code == 23) m_dxfCurrentCropping.cropPlane.y = value; | |||
| 17196 | else m_dxfCurrentCropping.cropPlane.z = value; | |||
| 17197 | ++m_dxfCropPlaneComponent; | |||
| 17198 | } else { | |||
| 17199 | if (code == 13) { | |||
| 17200 | if (m_dxfCropPointOpen) return false; | |||
| 17201 | m_dxfCropPoint = DRW_Coord{}; | |||
| 17202 | m_dxfCropPointOpen = true; | |||
| 17203 | } else if (!m_dxfCropPointOpen) { | |||
| 17204 | return false; | |||
| 17205 | } | |||
| 17206 | const double value = reader->getDouble(); | |||
| 17207 | if (code == 13) m_dxfCropPoint.x = value; | |||
| 17208 | else if (code == 23) m_dxfCropPoint.y = value; | |||
| 17209 | else m_dxfCropPoint.z = value; | |||
| 17210 | if (code == 33) { | |||
| 17211 | m_dxfCurrentCropping.points.push_back(m_dxfCropPoint); | |||
| 17212 | m_dxfCropPointOpen = false; | |||
| 17213 | } | |||
| 17214 | } | |||
| 17215 | break; | |||
| 17216 | case 213: | |||
| 17217 | case 223: | |||
| 17218 | case 233: { | |||
| 17219 | if (!m_dxfHasCropping || m_dxfDirectionComponent >= 6) | |||
| 17220 | return false; | |||
| 17221 | const double value = reader->getDouble(); | |||
| 17222 | DRW_Coord *direction = m_dxfDirectionComponent < 3 | |||
| 17223 | ? &m_dxfCurrentCropping.cropXDirection | |||
| 17224 | : &m_dxfCurrentCropping.cropYDirection; | |||
| 17225 | const int component = static_cast<int>(m_dxfDirectionComponent % 3); | |||
| 17226 | if ((component == 0 && code != 213) | |||
| 17227 | || (component == 1 && code != 223) | |||
| 17228 | || (component == 2 && code != 233)) { | |||
| 17229 | return false; | |||
| 17230 | } | |||
| 17231 | if (component == 0) direction->x = value; | |||
| 17232 | else if (component == 1) direction->y = value; | |||
| 17233 | else direction->z = value; | |||
| 17234 | ++m_dxfDirectionComponent; | |||
| 17235 | break; | |||
| 17236 | } | |||
| 17237 | default: | |||
| 17238 | return DRW_Entity::parseCode(code, reader); | |||
| 17239 | } | |||
| 17240 | return true; | |||
| 17241 | } | |||
| 17242 | ||||
| 17243 | bool DRW_PointCloudEx::finishDxfCropping() { | |||
| 17244 | if (!m_dxfHasCropping) | |||
| 17245 | return true; | |||
| 17246 | if (m_dxfSeen290 != 2 || m_dxfDirectionComponent != 6 | |||
| 17247 | || m_dxfCropPlaneComponent != 3 || m_dxfCropPointOpen | |||
| 17248 | || m_dxfSeen93 != 1 | |||
| 17249 | || m_dxfCurrentCropping.points.size() | |||
| 17250 | != static_cast<std::size_t>(m_dxfCurrentCropping.pointCount)) { | |||
| 17251 | return false; | |||
| 17252 | } | |||
| 17253 | croppings.push_back(m_dxfCurrentCropping); | |||
| 17254 | m_dxfHasCropping = false; | |||
| 17255 | return true; | |||
| 17256 | } | |||
| 17257 | ||||
| 17258 | bool DRW_PointCloudEx::finalizeDxf() { | |||
| 17259 | if (!finishDxfCropping()) | |||
| 17260 | return false; | |||
| 17261 | if (m_dxfSeen70 != 1 || !m_dxfSawCroppingCount) | |||
| 17262 | return false; | |||
| 17263 | if (croppingCount == 0) | |||
| 17264 | return m_dxfSeen93 == 2 && croppings.empty(); | |||
| 17265 | return croppings.size() == static_cast<std::size_t>(croppingCount); | |||
| 17266 | } | |||
| 17267 | ||||
| 17268 | void DRW_PointCloudEx::resetDwgState() { | |||
| 17269 | DRW_Entity::reset(); | |||
| 17270 | classVersion = 0; | |||
| 17271 | extentsMin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 17272 | extentsMax = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 17273 | ucsOrigin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 17274 | ucsXDirection = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 17275 | ucsYDirection = DRW_Coord{0.0, 1.0, 0.0}; | |||
| 17276 | ucsZDirection = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 17277 | isLocked = false; | |||
| 17278 | definitionHandle = 0; | |||
| 17279 | reactorHandle = 0; | |||
| 17280 | name.clear(); | |||
| 17281 | showIntensity = false; | |||
| 17282 | showCropping = false; | |||
| 17283 | croppingCount = 0; | |||
| 17284 | unknownInt0 = 0; | |||
| 17285 | unknownInt1 = 0; | |||
| 17286 | stylizationType = 0; | |||
| 17287 | intensityColorScheme.clear(); | |||
| 17288 | currentColorScheme.clear(); | |||
| 17289 | classificationColorScheme.clear(); | |||
| 17290 | elevationMin = 0.0; | |||
| 17291 | elevationMax = 0.0; | |||
| 17292 | intensityMin = 0.0; | |||
| 17293 | intensityMax = 0.0; | |||
| 17294 | intensityOutOfRangeBehavior = 0; | |||
| 17295 | elevationOutOfRangeBehavior = 0; | |||
| 17296 | elevationApplyToFixedRange = false; | |||
| 17297 | intensityAsGradient = false; | |||
| 17298 | elevationAsGradient = false; | |||
| 17299 | croppings.clear(); | |||
| 17300 | m_dxfCurrentCropping = DRW_PointCloudExCropping{}; | |||
| 17301 | m_dxfTextCount = 0; | |||
| 17302 | m_dxfSeen70 = 0; | |||
| 17303 | m_dxfSeen71 = 0; | |||
| 17304 | m_dxfSeen90 = 0; | |||
| 17305 | m_dxfSeen91 = 0; | |||
| 17306 | m_dxfSeen93 = 0; | |||
| 17307 | m_dxfSeen290 = 0; | |||
| 17308 | m_dxfSeen40 = 0; | |||
| 17309 | m_dxfDirectionComponent = 0; | |||
| 17310 | m_dxfCropPlaneComponent = 0; | |||
| 17311 | m_dxfSawCroppingCount = false; | |||
| 17312 | m_dxfInBody = false; | |||
| 17313 | m_dxfHasCropping = false; | |||
| 17314 | m_dxfCropPointOpen = false; | |||
| 17315 | m_dxfCropPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 17316 | } | |||
| 17317 | ||||
| 17318 | bool DRW_PointCloudEx::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 17319 | resetDwgState(); | |||
| 17320 | dwgBuffer *sourceBuf = buf; | |||
| 17321 | auto fail = [this, sourceBuf]() { | |||
| 17322 | if (sourceBuf != nullptr) | |||
| 17323 | sourceBuf->invalidate(); | |||
| 17324 | resetDwgState(); | |||
| 17325 | return false; | |||
| 17326 | }; | |||
| 17327 | if (sourceBuf == nullptr || version <= DRW::AC1024) | |||
| 17328 | return fail(); | |||
| 17329 | ||||
| 17330 | const auto finite = [](const DRW_Coord& point) { | |||
| 17331 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 17332 | && std::isfinite(point.z); | |||
| 17333 | }; | |||
| 17334 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 17335 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 17336 | if (!DRW_Entity::parseDwg(version, &bodyProbe, &stringProbe, bs)) | |||
| 17337 | return fail(); | |||
| 17338 | ||||
| 17339 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 17340 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 17341 | if (version > DRW::AC1021) { | |||
| 17342 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 17343 | if (!entityBodyDataEndBit(stringProbe, version, objSize, | |||
| 17344 | ignoredBodyEndBit, &stringEndBit)) | |||
| 17345 | return fail(); | |||
| 17346 | } | |||
| 17347 | std::uint16_t parsedClassVersion = 0; | |||
| 17348 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedClassVersion) | |||
| 17349 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMin) | |||
| 17350 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMax) | |||
| 17351 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsOrigin) | |||
| 17352 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsXDirection) | |||
| 17353 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsYDirection) | |||
| 17354 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsZDirection)) | |||
| 17355 | return fail(); | |||
| 17356 | classVersion = parsedClassVersion; | |||
| 17357 | if (!finite(extentsMin) || !finite(extentsMax) || !finite(ucsOrigin) | |||
| 17358 | || !finite(ucsXDirection) || !finite(ucsYDirection) | |||
| 17359 | || !finite(ucsZDirection)) { | |||
| 17360 | return fail(); | |||
| 17361 | } | |||
| 17362 | if (!readBoundedBit(bodyProbe, bodyEndBit, isLocked)) | |||
| 17363 | return fail(); | |||
| 17364 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, name)) | |||
| 17365 | return fail(); | |||
| 17366 | if (!readBoundedBit(bodyProbe, bodyEndBit, showIntensity) | |||
| 17367 | || !readBoundedBit(bodyProbe, bodyEndBit, showCropping)) | |||
| 17368 | return fail(); | |||
| 17369 | std::uint32_t declaredCroppings = 0; | |||
| 17370 | if (!readTableBodyCount( | |||
| 17371 | version, &bodyProbe, objSize, | |||
| 17372 | static_cast<std::uint32_t>(kMaxItems), 24, | |||
| 17373 | declaredCroppings)) { | |||
| 17374 | return fail(); | |||
| 17375 | } | |||
| 17376 | croppingCount = static_cast<int>(declaredCroppings); | |||
| 17377 | croppings.clear(); | |||
| 17378 | if (croppingCount == 0) { | |||
| 17379 | std::uint16_t parsedStylizationType = 0; | |||
| 17380 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, unknownInt0) | |||
| 17381 | || !readBoundedBitLong(bodyProbe, bodyEndBit, unknownInt1) | |||
| 17382 | || !readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 17383 | parsedStylizationType)) | |||
| 17384 | return fail(); | |||
| 17385 | stylizationType = parsedStylizationType; | |||
| 17386 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 17387 | intensityColorScheme) | |||
| 17388 | || !readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 17389 | currentColorScheme) | |||
| 17390 | || !readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 17391 | classificationColorScheme)) | |||
| 17392 | return fail(); | |||
| 17393 | std::int32_t parsedIntensityMin = 0; | |||
| 17394 | std::int32_t parsedIntensityMax = 0; | |||
| 17395 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, elevationMin) | |||
| 17396 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, elevationMax) | |||
| 17397 | || !readBoundedBitLong(bodyProbe, bodyEndBit, parsedIntensityMin) | |||
| 17398 | || !readBoundedBitLong(bodyProbe, bodyEndBit, parsedIntensityMax)) | |||
| 17399 | return fail(); | |||
| 17400 | intensityMin = static_cast<double>(parsedIntensityMin); | |||
| 17401 | intensityMax = static_cast<double>(parsedIntensityMax); | |||
| 17402 | if (!std::isfinite(elevationMin) || !std::isfinite(elevationMax)) | |||
| 17403 | return fail(); | |||
| 17404 | std::uint16_t parsedIntensityBehavior = 0; | |||
| 17405 | std::uint16_t parsedElevationBehavior = 0; | |||
| 17406 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 17407 | parsedIntensityBehavior) | |||
| 17408 | || !readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 17409 | parsedElevationBehavior) | |||
| 17410 | || !readBoundedBit(bodyProbe, bodyEndBit, | |||
| 17411 | elevationApplyToFixedRange) | |||
| 17412 | || !readBoundedBit(bodyProbe, bodyEndBit, intensityAsGradient) | |||
| 17413 | || !readBoundedBit(bodyProbe, bodyEndBit, elevationAsGradient)) | |||
| 17414 | return fail(); | |||
| 17415 | intensityOutOfRangeBehavior = parsedIntensityBehavior; | |||
| 17416 | elevationOutOfRangeBehavior = parsedElevationBehavior; | |||
| 17417 | } else { | |||
| 17418 | unknownInt0 = 0; | |||
| 17419 | unknownInt1 = 0; | |||
| 17420 | } | |||
| 17421 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 17422 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 17423 | || currentDwgBit(&stringProbe) > stringEndBit) | |||
| 17424 | return fail(); | |||
| 17425 | ||||
| 17426 | if (!DRW::reserve(croppings, croppingCount)) | |||
| 17427 | return fail(); | |||
| 17428 | for (std::uint32_t i = 0; i < declaredCroppings; ++i) { | |||
| 17429 | DRW_PointCloudExCropping cropping; | |||
| 17430 | std::uint16_t croppingType = 0; | |||
| 17431 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, croppingType) | |||
| 17432 | || !readBoundedBit(bodyProbe, bodyEndBit, cropping.isInside) | |||
| 17433 | || !readBoundedBit(bodyProbe, bodyEndBit, cropping.isInverted) | |||
| 17434 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, | |||
| 17435 | cropping.cropPlane) | |||
| 17436 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, | |||
| 17437 | cropping.cropXDirection) | |||
| 17438 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, | |||
| 17439 | cropping.cropYDirection)) { | |||
| 17440 | return fail(); | |||
| 17441 | } | |||
| 17442 | cropping.type = static_cast<int>(croppingType); | |||
| 17443 | if (!finite(cropping.cropPlane) || !finite(cropping.cropXDirection) | |||
| 17444 | || !finite(cropping.cropYDirection)) { | |||
| 17445 | return fail(); | |||
| 17446 | } | |||
| 17447 | std::uint32_t declaredPoints = 0; | |||
| 17448 | if (!readTableBodyCount( | |||
| 17449 | version, &bodyProbe, objSize, | |||
| 17450 | static_cast<std::uint32_t>(kMaxItems), | |||
| 17451 | 6, declaredPoints)) { | |||
| 17452 | return fail(); | |||
| 17453 | } | |||
| 17454 | std::uint64_t pointBits = 0; | |||
| 17455 | if (!dwgSafety::multiply(declaredPoints, 6, pointBits) | |||
| 17456 | || !proxyEntityHasBits(bodyProbe, bodyEndBit, pointBits)) { | |||
| 17457 | return fail(); | |||
| 17458 | } | |||
| 17459 | cropping.pointCount = static_cast<int>(declaredPoints); | |||
| 17460 | if (!DRW::reserve(cropping.points, cropping.pointCount)) | |||
| 17461 | return fail(); | |||
| 17462 | for (std::uint32_t j = 0; j < declaredPoints; ++j) { | |||
| 17463 | DRW_Coord point; | |||
| 17464 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, point)) | |||
| 17465 | return fail(); | |||
| 17466 | cropping.points.push_back(point); | |||
| 17467 | } | |||
| 17468 | if (!std::all_of(cropping.points.begin(), cropping.points.end(), finite)) | |||
| 17469 | return fail(); | |||
| 17470 | croppings.push_back(std::move(cropping)); | |||
| 17471 | } | |||
| 17472 | ||||
| 17473 | std::uint64_t handleEndBit = 0; | |||
| 17474 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 17475 | handleEndBit)) | |||
| 17476 | return fail(); | |||
| 17477 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 17478 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 17479 | handleEndBit) | |||
| 17480 | || !handleProbe.isGood()) | |||
| 17481 | return fail(); | |||
| 17482 | dwgHandle definition; | |||
| 17483 | dwgHandle reactor; | |||
| 17484 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 17485 | definition) | |||
| 17486 | || !readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 17487 | reactor)) | |||
| 17488 | return fail(); | |||
| 17489 | const std::uint32_t parsedDefinitionHandle = definition.ref; | |||
| 17490 | const std::uint32_t parsedReactorHandle = reactor.ref; | |||
| 17491 | if (!handleProbe.isGood() || !stringProbe.isGood()) | |||
| 17492 | return fail(); | |||
| 17493 | definitionHandle = parsedDefinitionHandle; | |||
| 17494 | reactorHandle = parsedReactorHandle; | |||
| 17495 | *sourceBuf = handleProbe; | |||
| 17496 | return true; | |||
| 17497 | } | |||
| 17498 | ||||
| 17499 | bool DRW_PointCloudEx::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 17500 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 17501 | (void)bs; | |||
| 17502 | const auto finite = [](const DRW_Coord& point) { | |||
| 17503 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 17504 | && std::isfinite(point.z); | |||
| 17505 | }; | |||
| 17506 | const auto fitsUint16 = [](int value) { | |||
| 17507 | return value >= 0 | |||
| 17508 | && value <= std::numeric_limits<std::uint16_t>::max(); | |||
| 17509 | }; | |||
| 17510 | if (version <= DRW::AC1024 | |||
| 17511 | || classVersion > std::numeric_limits<std::uint16_t>::max() | |||
| 17512 | || croppingCount < 0 | |||
| 17513 | || croppingCount > static_cast<int>(kMaxItems) | |||
| 17514 | || croppings.size() != static_cast<std::size_t>(croppingCount)) { | |||
| 17515 | return false; | |||
| 17516 | } | |||
| 17517 | for (const DRW_PointCloudExCropping& cropping : croppings) { | |||
| 17518 | if (cropping.pointCount < 0 | |||
| 17519 | || cropping.pointCount > static_cast<int>(kMaxItems) | |||
| 17520 | || cropping.points.size() != static_cast<std::size_t>(cropping.pointCount)) { | |||
| 17521 | return false; | |||
| 17522 | } | |||
| 17523 | if (!fitsUint16(cropping.type) || !finite(cropping.cropPlane) | |||
| 17524 | || !finite(cropping.cropXDirection) | |||
| 17525 | || !finite(cropping.cropYDirection)) { | |||
| 17526 | return false; | |||
| 17527 | } | |||
| 17528 | for (const DRW_Coord& point : cropping.points) { | |||
| 17529 | if (!finite(point)) | |||
| 17530 | return false; | |||
| 17531 | } | |||
| 17532 | } | |||
| 17533 | if (!finite(extentsMin) || !finite(extentsMax) || !finite(ucsOrigin) | |||
| 17534 | || !finite(ucsXDirection) || !finite(ucsYDirection) | |||
| 17535 | || !finite(ucsZDirection) || !std::isfinite(elevationMin) | |||
| 17536 | || !std::isfinite(elevationMax) | |||
| 17537 | || !fitsUint16(stylizationType) | |||
| 17538 | || !fitsUint16(intensityOutOfRangeBehavior) | |||
| 17539 | || !fitsUint16(elevationOutOfRangeBehavior)) { | |||
| 17540 | return false; | |||
| 17541 | } | |||
| 17542 | const auto integral32 = [](double value) { | |||
| 17543 | return std::isfinite(value) | |||
| 17544 | && value >= static_cast<double>(std::numeric_limits<std::int32_t>::min()) | |||
| 17545 | && value <= static_cast<double>(std::numeric_limits<std::int32_t>::max()) | |||
| 17546 | && std::floor(value) == value; | |||
| 17547 | }; | |||
| 17548 | if (croppingCount == 0 | |||
| 17549 | && (!integral32(intensityMin) || !integral32(intensityMax))) { | |||
| 17550 | return false; | |||
| 17551 | } | |||
| 17552 | ||||
| 17553 | oType = kDwgClassNum; | |||
| 17554 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 17555 | return false; | |||
| 17556 | dwgBufferW *sBuf = strBuf ? strBuf : buf; | |||
| 17557 | buf->putBitShort(static_cast<std::uint16_t>(classVersion)); | |||
| 17558 | buf->put3BitDouble(extentsMin); | |||
| 17559 | buf->put3BitDouble(extentsMax); | |||
| 17560 | buf->put3BitDouble(ucsOrigin); | |||
| 17561 | buf->put3BitDouble(ucsXDirection); | |||
| 17562 | buf->put3BitDouble(ucsYDirection); | |||
| 17563 | buf->put3BitDouble(ucsZDirection); | |||
| 17564 | buf->putBit(isLocked ? 1 : 0); | |||
| 17565 | sBuf->putVariableText(version, name); | |||
| 17566 | buf->putBit(showIntensity ? 1 : 0); | |||
| 17567 | buf->putBit(showCropping ? 1 : 0); | |||
| 17568 | buf->putBitLong(croppingCount); | |||
| 17569 | if (croppingCount == 0) { | |||
| 17570 | buf->putBitLong(unknownInt0); | |||
| 17571 | buf->putBitLong(unknownInt1); | |||
| 17572 | buf->putBitShort(static_cast<std::uint16_t>(stylizationType)); | |||
| 17573 | sBuf->putVariableText(version, intensityColorScheme); | |||
| 17574 | sBuf->putVariableText(version, currentColorScheme); | |||
| 17575 | sBuf->putVariableText(version, classificationColorScheme); | |||
| 17576 | buf->putBitDouble(elevationMin); | |||
| 17577 | buf->putBitDouble(elevationMax); | |||
| 17578 | buf->putBitLong(static_cast<std::int32_t>(intensityMin)); | |||
| 17579 | buf->putBitLong(static_cast<std::int32_t>(intensityMax)); | |||
| 17580 | buf->putBitShort(static_cast<std::uint16_t>(intensityOutOfRangeBehavior)); | |||
| 17581 | buf->putBitShort(static_cast<std::uint16_t>(elevationOutOfRangeBehavior)); | |||
| 17582 | buf->putBit(elevationApplyToFixedRange ? 1 : 0); | |||
| 17583 | buf->putBit(intensityAsGradient ? 1 : 0); | |||
| 17584 | buf->putBit(elevationAsGradient ? 1 : 0); | |||
| 17585 | } | |||
| 17586 | for (const DRW_PointCloudExCropping& cropping : croppings) { | |||
| 17587 | buf->putBitShort(static_cast<std::uint16_t>(cropping.type)); | |||
| 17588 | buf->putBit(cropping.isInside ? 1 : 0); | |||
| 17589 | buf->putBit(cropping.isInverted ? 1 : 0); | |||
| 17590 | buf->put3BitDouble(cropping.cropPlane); | |||
| 17591 | buf->put3BitDouble(cropping.cropXDirection); | |||
| 17592 | buf->put3BitDouble(cropping.cropYDirection); | |||
| 17593 | buf->putBitLong(cropping.pointCount); | |||
| 17594 | for (const DRW_Coord& point : cropping.points) | |||
| 17595 | buf->put3BitDouble(point); | |||
| 17596 | } | |||
| 17597 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 17598 | return false; | |||
| 17599 | ||||
| 17600 | dwgBufferW *hBuf = handleBuf ? handleBuf : buf; | |||
| 17601 | auto putHandle = [hBuf](std::uint8_t code, std::uint32_t ref) { | |||
| 17602 | dwgHandle handle; | |||
| 17603 | handle.code = ref == 0 ? 0 : code; | |||
| 17604 | handle.ref = ref; | |||
| 17605 | handle.size = 0; | |||
| 17606 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 17607 | ++handle.size; | |||
| 17608 | hBuf->putHandle(handle); | |||
| 17609 | }; | |||
| 17610 | putHandle(5, definitionHandle); | |||
| 17611 | putHandle(3, reactorHandle); | |||
| 17612 | return true; | |||
| 17613 | } | |||
| 17614 | ||||
| 17615 | bool DRW_Surface::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17616 | switch (code) { | |||
| 17617 | case 1: | |||
| 17618 | case 3: | |||
| 17619 | // SURFACE ACIS payloads use text groups in the AcDbModelerGeometry | |||
| 17620 | // subclass. Keep the bytes verbatim; group 3 is a continuation of | |||
| 17621 | // the same payload and must not be interpreted as a surface field. | |||
| 17622 | if (!appendTextBytesChecked(rawAcisData, reader->getString(), | |||
| 17623 | dwgSafety::MaxBufferSize)) | |||
| 17624 | return false; | |||
| 17625 | break; | |||
| 17626 | case 70: | |||
| 17627 | modelerFormatVersion = reader->getInt32(); | |||
| 17628 | break; | |||
| 17629 | case 71: | |||
| 17630 | uIsolines = reader->getInt32(); | |||
| 17631 | break; | |||
| 17632 | case 72: | |||
| 17633 | vIsolines = reader->getInt32(); | |||
| 17634 | break; | |||
| 17635 | case 310: | |||
| 17636 | // AcDbEntity proxy graphics precede the AcDbModelerGeometry subclass, | |||
| 17637 | // so the announced bytes belong to the entity, not to the ACIS body. | |||
| 17638 | if (numProxyGraph > 0 | |||
| 17639 | && proxyGraphics.size() < static_cast<std::size_t>(numProxyGraph)) | |||
| 17640 | return DRW_Entity::parseCode(code, reader); | |||
| 17641 | { | |||
| 17642 | std::vector<std::uint8_t> decoded; | |||
| 17643 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 17644 | return false; | |||
| 17645 | if (!appendBytesChecked(rawAcisData, decoded, | |||
| 17646 | dwgSafety::MaxBufferSize)) | |||
| 17647 | return false; | |||
| 17648 | } | |||
| 17649 | break; | |||
| 17650 | default: | |||
| 17651 | return DRW_Entity::parseCode(code, reader); | |||
| 17652 | } | |||
| 17653 | return true; | |||
| 17654 | } | |||
| 17655 | ||||
| 17656 | bool DRW_ExtrudedSurface::parseCode( | |||
| 17657 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17658 | switch (code) { | |||
| 17659 | case 100: { | |||
| 17660 | const std::string marker = reader->getString(); | |||
| 17661 | if (marker == "AcDbExtrudedSurface") | |||
| 17662 | m_dxfInSubtype = true; | |||
| 17663 | else if (marker == "AcDbModelerGeometry" | |||
| 17664 | || marker == "AcDbSurface") | |||
| 17665 | m_dxfInSubtype = false; | |||
| 17666 | break; | |||
| 17667 | } | |||
| 17668 | case 90: | |||
| 17669 | { | |||
| 17670 | // The class id, then the size of the 310 data that follows. | |||
| 17671 | const std::int32_t value = reader->getInt32(); | |||
| 17672 | if (value < 0 || m_dxfDataSizeSeen) | |||
| 17673 | return false; | |||
| 17674 | if (m_dxfClassIdSeen) { | |||
| 17675 | m_dxfDataSizeSeen = true; | |||
| 17676 | break; | |||
| 17677 | } | |||
| 17678 | classId = static_cast<std::uint32_t>(value); | |||
| 17679 | m_dxfClassIdSeen = true; | |||
| 17680 | } | |||
| 17681 | break; | |||
| 17682 | case 310: | |||
| 17683 | // Extrusion data is not kept; it must not join the ACIS body. | |||
| 17684 | if (!m_dxfInSubtype) | |||
| 17685 | return DRW_Surface::parseCode(code, reader); | |||
| 17686 | break; | |||
| 17687 | case 10: | |||
| 17688 | sweepVector.x = reader->getDouble(); | |||
| 17689 | break; | |||
| 17690 | case 20: | |||
| 17691 | sweepVector.y = reader->getDouble(); | |||
| 17692 | break; | |||
| 17693 | case 30: | |||
| 17694 | sweepVector.z = reader->getDouble(); | |||
| 17695 | break; | |||
| 17696 | case 11: | |||
| 17697 | referenceVector.x = reader->getDouble(); | |||
| 17698 | break; | |||
| 17699 | case 21: | |||
| 17700 | referenceVector.y = reader->getDouble(); | |||
| 17701 | break; | |||
| 17702 | case 31: | |||
| 17703 | referenceVector.z = reader->getDouble(); | |||
| 17704 | break; | |||
| 17705 | case 40: | |||
| 17706 | if (m_dxfExtrudedTransformCount >= extrudedTransform.size()) | |||
| 17707 | return false; | |||
| 17708 | extrudedTransform[m_dxfExtrudedTransformCount++] = reader->getDouble(); | |||
| 17709 | break; | |||
| 17710 | case 41: | |||
| 17711 | // Code 41 is not part of the AcDbExtrudedSurface mapping. Keep an | |||
| 17712 | // unexpected value out of the common entity state. | |||
| 17713 | return false; | |||
| 17714 | case 42: | |||
| 17715 | if (!m_dxfInSubtype) | |||
| 17716 | return DRW_Surface::parseCode(code, reader); | |||
| 17717 | draftAngle = reader->getDouble(); | |||
| 17718 | break; | |||
| 17719 | case 43: | |||
| 17720 | draftStartDistance = reader->getDouble(); | |||
| 17721 | break; | |||
| 17722 | case 44: | |||
| 17723 | draftEndDistance = reader->getDouble(); | |||
| 17724 | break; | |||
| 17725 | case 45: | |||
| 17726 | twistAngle = reader->getDouble(); | |||
| 17727 | break; | |||
| 17728 | case 46: | |||
| 17729 | if (m_dxfSweepTransformCount >= sweepEntityTransform.size()) | |||
| 17730 | return false; | |||
| 17731 | sweepEntityTransform[m_dxfSweepTransformCount++] = reader->getDouble(); | |||
| 17732 | break; | |||
| 17733 | case 47: | |||
| 17734 | if (m_dxfPathTransformCount >= pathEntityTransform.size()) | |||
| 17735 | return false; | |||
| 17736 | pathEntityTransform[m_dxfPathTransformCount++] = reader->getDouble(); | |||
| 17737 | break; | |||
| 17738 | case 48: | |||
| 17739 | scaleFactor = reader->getDouble(); | |||
| 17740 | break; | |||
| 17741 | case 49: | |||
| 17742 | alignAngle = reader->getDouble(); | |||
| 17743 | break; | |||
| 17744 | case 70: | |||
| 17745 | if (!m_dxfInSubtype) | |||
| 17746 | return DRW_Surface::parseCode(code, reader); | |||
| 17747 | { | |||
| 17748 | const std::int32_t value = reader->getInt32(); | |||
| 17749 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17750 | return false; | |||
| 17751 | sweepAlignmentFlags = value; | |||
| 17752 | } | |||
| 17753 | break; | |||
| 17754 | case 71: | |||
| 17755 | if (!m_dxfInSubtype) | |||
| 17756 | return DRW_Surface::parseCode(code, reader); | |||
| 17757 | { | |||
| 17758 | const std::int32_t value = reader->getInt32(); | |||
| 17759 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17760 | return false; | |||
| 17761 | pathFlags = value; | |||
| 17762 | } | |||
| 17763 | break; | |||
| 17764 | case 290: | |||
| 17765 | solid = reader->getInt32() != 0; | |||
| 17766 | break; | |||
| 17767 | case 292: | |||
| 17768 | alignStart = reader->getInt32() != 0; | |||
| 17769 | break; | |||
| 17770 | case 293: | |||
| 17771 | bank = reader->getInt32() != 0; | |||
| 17772 | break; | |||
| 17773 | case 294: | |||
| 17774 | basePointSet = reader->getInt32() != 0; | |||
| 17775 | break; | |||
| 17776 | case 295: | |||
| 17777 | sweepEntityTransformComputed = reader->getInt32() != 0; | |||
| 17778 | break; | |||
| 17779 | case 296: | |||
| 17780 | pathEntityTransformComputed = reader->getInt32() != 0; | |||
| 17781 | break; | |||
| 17782 | default: | |||
| 17783 | return DRW_Surface::parseCode(code, reader); | |||
| 17784 | } | |||
| 17785 | return true; | |||
| 17786 | } | |||
| 17787 | ||||
| 17788 | bool DRW_ExtrudedSurface::finalizeDxf() const { | |||
| 17789 | if (!m_dxfClassIdSeen) | |||
| 17790 | return true; | |||
| 17791 | return m_dxfInSubtype | |||
| 17792 | && m_dxfExtrudedTransformCount == extrudedTransform.size() | |||
| 17793 | && m_dxfSweepTransformCount == sweepEntityTransform.size() | |||
| 17794 | && m_dxfPathTransformCount == pathEntityTransform.size(); | |||
| 17795 | } | |||
| 17796 | ||||
| 17797 | bool DRW_SweptSurface::parseCode( | |||
| 17798 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17799 | switch (code) { | |||
| 17800 | case 100: { | |||
| 17801 | const std::string marker = reader->getString(); | |||
| 17802 | if (marker == "AcDbSweptSurface") | |||
| 17803 | m_dxfInSubtype = true; | |||
| 17804 | else if (marker == "AcDbModelerGeometry" | |||
| 17805 | || marker == "AcDbSurface") | |||
| 17806 | m_dxfInSubtype = false; | |||
| 17807 | break; | |||
| 17808 | } | |||
| 17809 | case 90: | |||
| 17810 | if (!m_dxfInSubtype) | |||
| 17811 | return DRW_Surface::parseCode(code, reader); | |||
| 17812 | m_dxfTypedFieldSeen = true; | |||
| 17813 | { | |||
| 17814 | // Each entity id may be followed by the size of its 310 data. | |||
| 17815 | const std::int32_t value = reader->getInt32(); | |||
| 17816 | if (value < 0) | |||
| 17817 | return false; | |||
| 17818 | if (m_dxfSweepEntityIdSeen) { | |||
| 17819 | if (m_dxfDataSizeCount >= (m_dxfPathEntityIdSeen ? 2 : 1)) | |||
| 17820 | return false; | |||
| 17821 | ++m_dxfDataSizeCount; | |||
| 17822 | break; | |||
| 17823 | } | |||
| 17824 | sweepEntityId = static_cast<std::uint32_t>(value); | |||
| 17825 | m_dxfSweepEntityIdSeen = true; | |||
| 17826 | } | |||
| 17827 | break; | |||
| 17828 | case 91: | |||
| 17829 | if (!m_dxfInSubtype) | |||
| 17830 | return DRW_Surface::parseCode(code, reader); | |||
| 17831 | if (m_dxfPathEntityIdSeen) | |||
| 17832 | return false; | |||
| 17833 | m_dxfTypedFieldSeen = true; | |||
| 17834 | { | |||
| 17835 | const std::int32_t value = reader->getInt32(); | |||
| 17836 | if (value < 0) | |||
| 17837 | return false; | |||
| 17838 | pathEntityId = static_cast<std::uint32_t>(value); | |||
| 17839 | m_dxfPathEntityIdSeen = true; | |||
| 17840 | } | |||
| 17841 | break; | |||
| 17842 | case 310: { | |||
| 17843 | if (!m_dxfInSubtype) | |||
| 17844 | return DRW_Surface::parseCode(code, reader); | |||
| 17845 | m_dxfTypedFieldSeen = true; | |||
| 17846 | std::vector<std::uint8_t> decoded; | |||
| 17847 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 17848 | return false; | |||
| 17849 | auto& destination = m_dxfPathEntityIdSeen ? pathData : sweepData; | |||
| 17850 | if (!appendBytesChecked(destination, decoded, kMaxSweepDataSize)) | |||
| 17851 | return false; | |||
| 17852 | break; | |||
| 17853 | } | |||
| 17854 | case 11: | |||
| 17855 | if (!m_dxfInSubtype) | |||
| 17856 | return DRW_Surface::parseCode(code, reader); | |||
| 17857 | m_dxfTypedFieldSeen = true; | |||
| 17858 | referenceVector.x = reader->getDouble(); | |||
| 17859 | break; | |||
| 17860 | case 21: | |||
| 17861 | if (!m_dxfInSubtype) | |||
| 17862 | return DRW_Surface::parseCode(code, reader); | |||
| 17863 | m_dxfTypedFieldSeen = true; | |||
| 17864 | referenceVector.y = reader->getDouble(); | |||
| 17865 | break; | |||
| 17866 | case 31: | |||
| 17867 | if (!m_dxfInSubtype) | |||
| 17868 | return DRW_Surface::parseCode(code, reader); | |||
| 17869 | m_dxfTypedFieldSeen = true; | |||
| 17870 | referenceVector.z = reader->getDouble(); | |||
| 17871 | break; | |||
| 17872 | case 40: | |||
| 17873 | if (!m_dxfInSubtype) | |||
| 17874 | return DRW_Surface::parseCode(code, reader); | |||
| 17875 | m_dxfTypedFieldSeen = true; | |||
| 17876 | if (m_dxfSweepTransformCount >= sweepEntityTransformed.size()) | |||
| 17877 | return false; | |||
| 17878 | sweepEntityTransformed[m_dxfSweepTransformCount++] = reader->getDouble(); | |||
| 17879 | break; | |||
| 17880 | case 41: | |||
| 17881 | if (!m_dxfInSubtype) | |||
| 17882 | return DRW_Surface::parseCode(code, reader); | |||
| 17883 | m_dxfTypedFieldSeen = true; | |||
| 17884 | if (m_dxfPathTransformCount >= pathEntityTransformed.size()) | |||
| 17885 | return false; | |||
| 17886 | pathEntityTransformed[m_dxfPathTransformCount++] = reader->getDouble(); | |||
| 17887 | break; | |||
| 17888 | case 42: | |||
| 17889 | if (!m_dxfInSubtype) | |||
| 17890 | return DRW_Surface::parseCode(code, reader); | |||
| 17891 | m_dxfTypedFieldSeen = true; | |||
| 17892 | draftAngle = reader->getDouble(); | |||
| 17893 | break; | |||
| 17894 | case 43: | |||
| 17895 | if (!m_dxfInSubtype) | |||
| 17896 | return DRW_Surface::parseCode(code, reader); | |||
| 17897 | m_dxfTypedFieldSeen = true; | |||
| 17898 | draftStartDistance = reader->getDouble(); | |||
| 17899 | break; | |||
| 17900 | case 44: | |||
| 17901 | if (!m_dxfInSubtype) | |||
| 17902 | return DRW_Surface::parseCode(code, reader); | |||
| 17903 | m_dxfTypedFieldSeen = true; | |||
| 17904 | draftEndDistance = reader->getDouble(); | |||
| 17905 | break; | |||
| 17906 | case 45: | |||
| 17907 | if (!m_dxfInSubtype) | |||
| 17908 | return DRW_Surface::parseCode(code, reader); | |||
| 17909 | m_dxfTypedFieldSeen = true; | |||
| 17910 | twistAngle = reader->getDouble(); | |||
| 17911 | break; | |||
| 17912 | case 46: | |||
| 17913 | if (!m_dxfInSubtype) | |||
| 17914 | return DRW_Surface::parseCode(code, reader); | |||
| 17915 | m_dxfTypedFieldSeen = true; | |||
| 17916 | if (m_dxfSweepEntityTransformedCount >= sweepEntityTransform.size()) | |||
| 17917 | return false; | |||
| 17918 | sweepEntityTransform[m_dxfSweepEntityTransformedCount++] = | |||
| 17919 | reader->getDouble(); | |||
| 17920 | break; | |||
| 17921 | case 47: | |||
| 17922 | if (!m_dxfInSubtype) | |||
| 17923 | return DRW_Surface::parseCode(code, reader); | |||
| 17924 | m_dxfTypedFieldSeen = true; | |||
| 17925 | if (m_dxfPathEntityTransformedCount >= pathEntityTransform.size()) | |||
| 17926 | return false; | |||
| 17927 | pathEntityTransform[m_dxfPathEntityTransformedCount++] = | |||
| 17928 | reader->getDouble(); | |||
| 17929 | break; | |||
| 17930 | case 48: | |||
| 17931 | if (!m_dxfInSubtype) | |||
| 17932 | return DRW_Surface::parseCode(code, reader); | |||
| 17933 | m_dxfTypedFieldSeen = true; | |||
| 17934 | scaleFactor = reader->getDouble(); | |||
| 17935 | break; | |||
| 17936 | case 49: | |||
| 17937 | if (!m_dxfInSubtype) | |||
| 17938 | return DRW_Surface::parseCode(code, reader); | |||
| 17939 | m_dxfTypedFieldSeen = true; | |||
| 17940 | alignAngle = reader->getDouble(); | |||
| 17941 | break; | |||
| 17942 | case 70: | |||
| 17943 | if (!m_dxfInSubtype) | |||
| 17944 | return DRW_Surface::parseCode(code, reader); | |||
| 17945 | m_dxfTypedFieldSeen = true; | |||
| 17946 | { | |||
| 17947 | const std::int32_t value = reader->getInt32(); | |||
| 17948 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17949 | return false; | |||
| 17950 | sweepAlignmentFlags = value; | |||
| 17951 | } | |||
| 17952 | break; | |||
| 17953 | case 71: | |||
| 17954 | if (!m_dxfInSubtype) | |||
| 17955 | return DRW_Surface::parseCode(code, reader); | |||
| 17956 | m_dxfTypedFieldSeen = true; | |||
| 17957 | { | |||
| 17958 | const std::int32_t value = reader->getInt32(); | |||
| 17959 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17960 | return false; | |||
| 17961 | pathFlags = value; | |||
| 17962 | } | |||
| 17963 | break; | |||
| 17964 | case 290: | |||
| 17965 | if (!m_dxfInSubtype) | |||
| 17966 | return DRW_Surface::parseCode(code, reader); | |||
| 17967 | m_dxfTypedFieldSeen = true; | |||
| 17968 | solid = reader->getInt32() != 0; | |||
| 17969 | break; | |||
| 17970 | case 292: | |||
| 17971 | if (!m_dxfInSubtype) | |||
| 17972 | return DRW_Surface::parseCode(code, reader); | |||
| 17973 | m_dxfTypedFieldSeen = true; | |||
| 17974 | alignStart = reader->getInt32() != 0; | |||
| 17975 | break; | |||
| 17976 | case 293: | |||
| 17977 | if (!m_dxfInSubtype) | |||
| 17978 | return DRW_Surface::parseCode(code, reader); | |||
| 17979 | m_dxfTypedFieldSeen = true; | |||
| 17980 | bank = reader->getInt32() != 0; | |||
| 17981 | break; | |||
| 17982 | case 294: | |||
| 17983 | if (!m_dxfInSubtype) | |||
| 17984 | return DRW_Surface::parseCode(code, reader); | |||
| 17985 | m_dxfTypedFieldSeen = true; | |||
| 17986 | basePointSet = reader->getInt32() != 0; | |||
| 17987 | break; | |||
| 17988 | case 295: | |||
| 17989 | if (!m_dxfInSubtype) | |||
| 17990 | return DRW_Surface::parseCode(code, reader); | |||
| 17991 | m_dxfTypedFieldSeen = true; | |||
| 17992 | sweepEntityTransformComputed = reader->getInt32() != 0; | |||
| 17993 | break; | |||
| 17994 | case 296: | |||
| 17995 | if (!m_dxfInSubtype) | |||
| 17996 | return DRW_Surface::parseCode(code, reader); | |||
| 17997 | m_dxfTypedFieldSeen = true; | |||
| 17998 | pathEntityTransformComputed = reader->getInt32() != 0; | |||
| 17999 | break; | |||
| 18000 | default: | |||
| 18001 | return DRW_Surface::parseCode(code, reader); | |||
| 18002 | } | |||
| 18003 | return true; | |||
| 18004 | } | |||
| 18005 | ||||
| 18006 | bool DRW_SweptSurface::finalizeDxf() const { | |||
| 18007 | if (!m_dxfTypedFieldSeen) | |||
| 18008 | return true; | |||
| 18009 | return m_dxfInSubtype && m_dxfSweepEntityIdSeen | |||
| 18010 | && m_dxfPathEntityIdSeen | |||
| 18011 | && m_dxfSweepTransformCount == sweepEntityTransformed.size() | |||
| 18012 | && m_dxfPathTransformCount == pathEntityTransformed.size() | |||
| 18013 | && m_dxfSweepEntityTransformedCount == sweepEntityTransform.size() | |||
| 18014 | && m_dxfPathEntityTransformedCount == pathEntityTransform.size(); | |||
| 18015 | } | |||
| 18016 | ||||
| 18017 | bool DRW_LoftedSurface::parseCode( | |||
| 18018 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 18019 | switch (code) { | |||
| 18020 | case 100: { | |||
| 18021 | const std::string marker = reader->getString(); | |||
| 18022 | if (marker == "AcDbLoftedSurface") | |||
| 18023 | m_dxfInSubtype = true; | |||
| 18024 | else if (marker == "AcDbModelerGeometry" | |||
| 18025 | || marker == "AcDbSurface") | |||
| 18026 | m_dxfInSubtype = false; | |||
| 18027 | break; | |||
| 18028 | } | |||
| 18029 | case 40: | |||
| 18030 | if (!m_dxfInSubtype) | |||
| 18031 | return DRW_Surface::parseCode(code, reader); | |||
| 18032 | m_dxfTypedFieldSeen = true; | |||
| 18033 | if (m_dxfTransformCount >= loftEntityTransform.size()) | |||
| 18034 | return false; | |||
| 18035 | loftEntityTransform[m_dxfTransformCount++] = reader->getDouble(); | |||
| 18036 | break; | |||
| 18037 | case 70: | |||
| 18038 | if (!m_dxfInSubtype) | |||
| 18039 | return DRW_Surface::parseCode(code, reader); | |||
| 18040 | m_dxfTypedFieldSeen = true; | |||
| 18041 | planeNormalLoftingType = reader->getInt32(); | |||
| 18042 | break; | |||
| 18043 | case 41: | |||
| 18044 | if (!m_dxfInSubtype) | |||
| 18045 | return DRW_Surface::parseCode(code, reader); | |||
| 18046 | m_dxfTypedFieldSeen = true; | |||
| 18047 | startDraftAngle = reader->getDouble(); | |||
| 18048 | break; | |||
| 18049 | case 42: | |||
| 18050 | if (!m_dxfInSubtype) | |||
| 18051 | return DRW_Surface::parseCode(code, reader); | |||
| 18052 | m_dxfTypedFieldSeen = true; | |||
| 18053 | endDraftAngle = reader->getDouble(); | |||
| 18054 | break; | |||
| 18055 | case 43: | |||
| 18056 | if (!m_dxfInSubtype) | |||
| 18057 | return DRW_Surface::parseCode(code, reader); | |||
| 18058 | m_dxfTypedFieldSeen = true; | |||
| 18059 | startDraftMagnitude = reader->getDouble(); | |||
| 18060 | break; | |||
| 18061 | case 44: | |||
| 18062 | if (!m_dxfInSubtype) | |||
| 18063 | return DRW_Surface::parseCode(code, reader); | |||
| 18064 | m_dxfTypedFieldSeen = true; | |||
| 18065 | endDraftMagnitude = reader->getDouble(); | |||
| 18066 | break; | |||
| 18067 | case 90: { | |||
| 18068 | if (!m_dxfInSubtype) | |||
| 18069 | return DRW_Surface::parseCode(code, reader); | |||
| 18070 | if (m_dxfReferenceTokenCount >= kMaxReferenceTokenCount) | |||
| 18071 | return false; | |||
| 18072 | const std::int32_t value = reader->getInt32(); | |||
| 18073 | if (value < 0 || static_cast<std::size_t>(value) | |||
| 18074 | > kMaxReferenceTokenCount) | |||
| 18075 | return false; | |||
| 18076 | m_dxfTypedFieldSeen = true; | |||
| 18077 | dxfReferenceData.emplace_back(90, value); | |||
| 18078 | ++m_dxfReferenceTokenCount; | |||
| 18079 | break; | |||
| 18080 | } | |||
| 18081 | case 310: { | |||
| 18082 | if (!m_dxfInSubtype) | |||
| 18083 | return DRW_Surface::parseCode(code, reader); | |||
| 18084 | std::vector<std::uint8_t> decoded; | |||
| 18085 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 18086 | return false; | |||
| 18087 | if (m_dxfReferenceTokenCount >= kMaxReferenceTokenCount | |||
| 18088 | || decoded.size() > kMaxReferenceDataSize | |||
| 18089 | || m_dxfReferenceDataSize | |||
| 18090 | > kMaxReferenceDataSize - decoded.size()) | |||
| 18091 | return false; | |||
| 18092 | m_dxfTypedFieldSeen = true; | |||
| 18093 | dxfReferenceData.emplace_back(310, std::move(decoded)); | |||
| 18094 | m_dxfReferenceDataSize += dxfReferenceData.back().binary()->size(); | |||
| 18095 | ++m_dxfReferenceTokenCount; | |||
| 18096 | break; | |||
| 18097 | } | |||
| 18098 | case 290: | |||
| 18099 | if (!m_dxfInSubtype) | |||
| 18100 | return DRW_Surface::parseCode(code, reader); | |||
| 18101 | m_dxfTypedFieldSeen = true; | |||
| 18102 | arcLengthParameterization = reader->getInt32() != 0; | |||
| 18103 | break; | |||
| 18104 | case 291: | |||
| 18105 | if (!m_dxfInSubtype) | |||
| 18106 | return DRW_Surface::parseCode(code, reader); | |||
| 18107 | m_dxfTypedFieldSeen = true; | |||
| 18108 | noTwist = reader->getInt32() != 0; | |||
| 18109 | break; | |||
| 18110 | case 292: | |||
| 18111 | if (!m_dxfInSubtype) | |||
| 18112 | return DRW_Surface::parseCode(code, reader); | |||
| 18113 | m_dxfTypedFieldSeen = true; | |||
| 18114 | alignDirection = reader->getInt32() != 0; | |||
| 18115 | break; | |||
| 18116 | case 293: | |||
| 18117 | if (!m_dxfInSubtype) | |||
| 18118 | return DRW_Surface::parseCode(code, reader); | |||
| 18119 | m_dxfTypedFieldSeen = true; | |||
| 18120 | simpleSurfaces = reader->getInt32() != 0; | |||
| 18121 | break; | |||
| 18122 | case 294: | |||
| 18123 | if (!m_dxfInSubtype) | |||
| 18124 | return DRW_Surface::parseCode(code, reader); | |||
| 18125 | m_dxfTypedFieldSeen = true; | |||
| 18126 | closedSurfaces = reader->getInt32() != 0; | |||
| 18127 | break; | |||
| 18128 | case 295: | |||
| 18129 | if (!m_dxfInSubtype) | |||
| 18130 | return DRW_Surface::parseCode(code, reader); | |||
| 18131 | m_dxfTypedFieldSeen = true; | |||
| 18132 | solid = reader->getInt32() != 0; | |||
| 18133 | break; | |||
| 18134 | case 296: | |||
| 18135 | if (!m_dxfInSubtype) | |||
| 18136 | return DRW_Surface::parseCode(code, reader); | |||
| 18137 | m_dxfTypedFieldSeen = true; | |||
| 18138 | ruledSurface = reader->getInt32() != 0; | |||
| 18139 | break; | |||
| 18140 | case 297: | |||
| 18141 | if (!m_dxfInSubtype) | |||
| 18142 | return DRW_Surface::parseCode(code, reader); | |||
| 18143 | m_dxfTypedFieldSeen = true; | |||
| 18144 | virtualGuide = reader->getInt32() != 0; | |||
| 18145 | break; | |||
| 18146 | case 5: | |||
| 18147 | if (!m_dxfInSubtype) | |||
| 18148 | return DRW_Surface::parseCode(code, reader); | |||
| 18149 | if (!reader->isValidHandleString()) | |||
| 18150 | return false; | |||
| 18151 | m_dxfTypedFieldSeen = true; | |||
| 18152 | pathCurveHandle = reader->getHandleString(); | |||
| 18153 | break; | |||
| 18154 | default: | |||
| 18155 | return DRW_Surface::parseCode(code, reader); | |||
| 18156 | } | |||
| 18157 | return true; | |||
| 18158 | } | |||
| 18159 | ||||
| 18160 | bool DRW_LoftedSurface::finalizeDxf() const { | |||
| 18161 | if (!m_dxfTypedFieldSeen) | |||
| 18162 | return true; | |||
| 18163 | return m_dxfInSubtype | |||
| 18164 | && m_dxfTransformCount == loftEntityTransform.size() | |||
| 18165 | && std::all_of(loftEntityTransform.begin(), loftEntityTransform.end(), | |||
| 18166 | [](double value) { return std::isfinite(value); }) | |||
| 18167 | && std::isfinite(startDraftAngle) | |||
| 18168 | && std::isfinite(endDraftAngle) | |||
| 18169 | && std::isfinite(startDraftMagnitude) | |||
| 18170 | && std::isfinite(endDraftMagnitude); | |||
| 18171 | } | |||
| 18172 | ||||
| 18173 | bool DRW_NurbsSurface::parseCode( | |||
| 18174 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 18175 | switch (code) { | |||
| 18176 | case 100: { | |||
| 18177 | const std::string marker = reader->getString(); | |||
| 18178 | if (marker == "AcDbNurbSurface") | |||
| 18179 | m_dxfInSubtype = true; | |||
| 18180 | else if (marker == "AcDbModelerGeometry" | |||
| 18181 | || marker == "AcDbSurface") | |||
| 18182 | m_dxfInSubtype = false; | |||
| 18183 | break; | |||
| 18184 | } | |||
| 18185 | case 170: | |||
| 18186 | if (!m_dxfInSubtype) | |||
| 18187 | return DRW_Surface::parseCode(code, reader); | |||
| 18188 | { | |||
| 18189 | const std::int32_t value = reader->getInt32(); | |||
| 18190 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 18191 | return false; | |||
| 18192 | short170 = static_cast<std::uint16_t>(value); | |||
| 18193 | m_dxfTypedFieldSeen = true; | |||
| 18194 | } | |||
| 18195 | break; | |||
| 18196 | case 290: | |||
| 18197 | if (!m_dxfInSubtype) | |||
| 18198 | return DRW_Surface::parseCode(code, reader); | |||
| 18199 | cvHullDisplay = reader->getInt32() != 0; | |||
| 18200 | m_dxfTypedFieldSeen = true; | |||
| 18201 | break; | |||
| 18202 | case 10: | |||
| 18203 | if (!m_dxfInSubtype) | |||
| 18204 | return DRW_Surface::parseCode(code, reader); | |||
| 18205 | uvec1.x = reader->getDouble(); | |||
| 18206 | m_dxfCoordinateMask[0] |= 1; | |||
| 18207 | m_dxfTypedFieldSeen = true; | |||
| 18208 | break; | |||
| 18209 | case 20: | |||
| 18210 | if (!m_dxfInSubtype) | |||
| 18211 | return DRW_Surface::parseCode(code, reader); | |||
| 18212 | uvec1.y = reader->getDouble(); | |||
| 18213 | m_dxfCoordinateMask[0] |= 2; | |||
| 18214 | m_dxfTypedFieldSeen = true; | |||
| 18215 | break; | |||
| 18216 | case 30: | |||
| 18217 | if (!m_dxfInSubtype) | |||
| 18218 | return DRW_Surface::parseCode(code, reader); | |||
| 18219 | uvec1.z = reader->getDouble(); | |||
| 18220 | m_dxfCoordinateMask[0] |= 4; | |||
| 18221 | m_dxfTypedFieldSeen = true; | |||
| 18222 | break; | |||
| 18223 | case 11: | |||
| 18224 | if (!m_dxfInSubtype) | |||
| 18225 | return DRW_Surface::parseCode(code, reader); | |||
| 18226 | vvec1.x = reader->getDouble(); | |||
| 18227 | m_dxfCoordinateMask[1] |= 1; | |||
| 18228 | m_dxfTypedFieldSeen = true; | |||
| 18229 | break; | |||
| 18230 | case 21: | |||
| 18231 | if (!m_dxfInSubtype) | |||
| 18232 | return DRW_Surface::parseCode(code, reader); | |||
| 18233 | vvec1.y = reader->getDouble(); | |||
| 18234 | m_dxfCoordinateMask[1] |= 2; | |||
| 18235 | m_dxfTypedFieldSeen = true; | |||
| 18236 | break; | |||
| 18237 | case 31: | |||
| 18238 | if (!m_dxfInSubtype) | |||
| 18239 | return DRW_Surface::parseCode(code, reader); | |||
| 18240 | vvec1.z = reader->getDouble(); | |||
| 18241 | m_dxfCoordinateMask[1] |= 4; | |||
| 18242 | m_dxfTypedFieldSeen = true; | |||
| 18243 | break; | |||
| 18244 | case 12: | |||
| 18245 | if (!m_dxfInSubtype) | |||
| 18246 | return DRW_Surface::parseCode(code, reader); | |||
| 18247 | uvec2.x = reader->getDouble(); | |||
| 18248 | m_dxfCoordinateMask[2] |= 1; | |||
| 18249 | m_dxfTypedFieldSeen = true; | |||
| 18250 | break; | |||
| 18251 | case 22: | |||
| 18252 | if (!m_dxfInSubtype) | |||
| 18253 | return DRW_Surface::parseCode(code, reader); | |||
| 18254 | uvec2.y = reader->getDouble(); | |||
| 18255 | m_dxfCoordinateMask[2] |= 2; | |||
| 18256 | m_dxfTypedFieldSeen = true; | |||
| 18257 | break; | |||
| 18258 | case 32: | |||
| 18259 | if (!m_dxfInSubtype) | |||
| 18260 | return DRW_Surface::parseCode(code, reader); | |||
| 18261 | uvec2.z = reader->getDouble(); | |||
| 18262 | m_dxfCoordinateMask[2] |= 4; | |||
| 18263 | m_dxfTypedFieldSeen = true; | |||
| 18264 | break; | |||
| 18265 | case 13: | |||
| 18266 | if (!m_dxfInSubtype) | |||
| 18267 | return DRW_Surface::parseCode(code, reader); | |||
| 18268 | vvec2.x = reader->getDouble(); | |||
| 18269 | m_dxfCoordinateMask[3] |= 1; | |||
| 18270 | m_dxfTypedFieldSeen = true; | |||
| 18271 | break; | |||
| 18272 | case 23: | |||
| 18273 | if (!m_dxfInSubtype) | |||
| 18274 | return DRW_Surface::parseCode(code, reader); | |||
| 18275 | vvec2.y = reader->getDouble(); | |||
| 18276 | m_dxfCoordinateMask[3] |= 2; | |||
| 18277 | m_dxfTypedFieldSeen = true; | |||
| 18278 | break; | |||
| 18279 | case 33: | |||
| 18280 | if (!m_dxfInSubtype) | |||
| 18281 | return DRW_Surface::parseCode(code, reader); | |||
| 18282 | vvec2.z = reader->getDouble(); | |||
| 18283 | m_dxfCoordinateMask[3] |= 4; | |||
| 18284 | m_dxfTypedFieldSeen = true; | |||
| 18285 | break; | |||
| 18286 | default: | |||
| 18287 | return DRW_Surface::parseCode(code, reader); | |||
| 18288 | } | |||
| 18289 | return true; | |||
| 18290 | } | |||
| 18291 | ||||
| 18292 | bool DRW_NurbsSurface::finalizeDxf() const { | |||
| 18293 | if (!m_dxfTypedFieldSeen) | |||
| 18294 | return true; | |||
| 18295 | const bool coordinatesSeen = std::any_of( | |||
| 18296 | m_dxfCoordinateMask.begin(), m_dxfCoordinateMask.end(), | |||
| 18297 | [](std::uint8_t mask) { return mask != 0; }); | |||
| 18298 | if (!m_dxfInSubtype | |||
| 18299 | || (coordinatesSeen && std::any_of( | |||
| 18300 | m_dxfCoordinateMask.begin(), m_dxfCoordinateMask.end(), | |||
| 18301 | [](std::uint8_t mask) { return mask != 7; }))) { | |||
| 18302 | return false; | |||
| 18303 | } | |||
| 18304 | return std::all_of(m_dxfCoordinateMask.begin(), m_dxfCoordinateMask.end(), | |||
| 18305 | [](std::uint8_t mask) { return mask == 0 || mask == 7; }) | |||
| 18306 | && std::isfinite(uvec1.x) && std::isfinite(uvec1.y) | |||
| 18307 | && std::isfinite(uvec1.z) && std::isfinite(vvec1.x) | |||
| 18308 | && std::isfinite(vvec1.y) && std::isfinite(vvec1.z) | |||
| 18309 | && std::isfinite(uvec2.x) && std::isfinite(uvec2.y) | |||
| 18310 | && std::isfinite(uvec2.z) && std::isfinite(vvec2.x) | |||
| 18311 | && std::isfinite(vvec2.y) && std::isfinite(vvec2.z); | |||
| 18312 | } | |||
| 18313 | ||||
| 18314 | bool DRW_RevolvedSurface::parseCode( | |||
| 18315 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 18316 | switch (code) { | |||
| 18317 | case 90: | |||
| 18318 | if (!m_dxfClassIdSeen) { | |||
| 18319 | const std::int32_t value = reader->getInt32(); | |||
| 18320 | if (value < 0) | |||
| 18321 | return false; | |||
| 18322 | classId = static_cast<std::uint32_t>(value); | |||
| 18323 | m_dxfClassIdSeen = true; | |||
| 18324 | } else { | |||
| 18325 | const std::int32_t value = reader->getInt32(); | |||
| 18326 | if (value < 0) | |||
| 18327 | return false; | |||
| 18328 | id = static_cast<std::uint32_t>(value); | |||
| 18329 | } | |||
| 18330 | break; | |||
| 18331 | case 310: | |||
| 18332 | // Revolve data follows the subclass id; it must not join the ACIS body. | |||
| 18333 | if (!m_dxfClassIdSeen) | |||
| 18334 | return DRW_Surface::parseCode(code, reader); | |||
| 18335 | break; | |||
| 18336 | case 10: | |||
| 18337 | axisPoint.x = reader->getDouble(); | |||
| 18338 | break; | |||
| 18339 | case 20: | |||
| 18340 | axisPoint.y = reader->getDouble(); | |||
| 18341 | break; | |||
| 18342 | case 30: | |||
| 18343 | axisPoint.z = reader->getDouble(); | |||
| 18344 | break; | |||
| 18345 | case 11: | |||
| 18346 | axisVector.x = reader->getDouble(); | |||
| 18347 | break; | |||
| 18348 | case 21: | |||
| 18349 | axisVector.y = reader->getDouble(); | |||
| 18350 | break; | |||
| 18351 | case 31: | |||
| 18352 | axisVector.z = reader->getDouble(); | |||
| 18353 | break; | |||
| 18354 | case 40: | |||
| 18355 | revolveAngle = reader->getDouble(); | |||
| 18356 | break; | |||
| 18357 | case 41: | |||
| 18358 | startAngle = reader->getDouble(); | |||
| 18359 | break; | |||
| 18360 | case 42: | |||
| 18361 | if (m_dxfTransformCount >= transform.size()) | |||
| 18362 | return false; | |||
| 18363 | transform[m_dxfTransformCount++] = reader->getDouble(); | |||
| 18364 | break; | |||
| 18365 | case 43: | |||
| 18366 | draftAngle = reader->getDouble(); | |||
| 18367 | break; | |||
| 18368 | case 44: | |||
| 18369 | draftStartDistance = reader->getDouble(); | |||
| 18370 | break; | |||
| 18371 | case 45: | |||
| 18372 | draftEndDistance = reader->getDouble(); | |||
| 18373 | break; | |||
| 18374 | case 46: | |||
| 18375 | twistAngle = reader->getDouble(); | |||
| 18376 | break; | |||
| 18377 | case 290: | |||
| 18378 | solid = reader->getInt32() != 0; | |||
| 18379 | break; | |||
| 18380 | case 291: | |||
| 18381 | closeToAxis = reader->getInt32() != 0; | |||
| 18382 | break; | |||
| 18383 | default: | |||
| 18384 | return DRW_Surface::parseCode(code, reader); | |||
| 18385 | } | |||
| 18386 | return true; | |||
| 18387 | } | |||
| 18388 | ||||
| 18389 | void DRW_Surface::resetDwgState() { | |||
| 18390 | DRW_Entity::reset(); | |||
| 18391 | uIsolines = 0; | |||
| 18392 | vIsolines = 0; | |||
| 18393 | modelerFormatVersion = 0; | |||
| 18394 | acisEmpty = false; | |||
| 18395 | acisVersion = 0; | |||
| 18396 | rawAcisData.clear(); | |||
| 18397 | hasRawDwgBody = false; | |||
| 18398 | rawDwgBodyBitSize = 0; | |||
| 18399 | rawDwgBodyVersion = DRW::UNKNOWNV; | |||
| 18400 | crossSectionHandles.clear(); | |||
| 18401 | guideCurveHandles.clear(); | |||
| 18402 | dwgClassNum = 0; | |||
| 18403 | dwgPayloadDecoded = false; | |||
| 18404 | m_wireframe = DRW_AcisBrep(); | |||
| 18405 | m_wireframeDecoded = false; | |||
| 18406 | ||||
| 18407 | const auto identity = [] { | |||
| 18408 | return std::array<double, DRW_ExtrudedSurface::kTransformSize>{ | |||
| 18409 | 1.0, 0.0, 0.0, 0.0, | |||
| 18410 | 0.0, 1.0, 0.0, 0.0, | |||
| 18411 | 0.0, 0.0, 1.0, 0.0, | |||
| 18412 | 0.0, 0.0, 0.0, 1.0}; | |||
| 18413 | }; | |||
| 18414 | switch (eType) { | |||
| 18415 | case DRW::EXTRUDEDSURFACE: { | |||
| 18416 | auto *surface = static_cast<DRW_ExtrudedSurface *>(this); | |||
| 18417 | surface->classId = 0; | |||
| 18418 | surface->sweepVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18419 | surface->extrudedTransform = identity(); | |||
| 18420 | surface->sweepEntityTransform = identity(); | |||
| 18421 | surface->pathEntityTransform = identity(); | |||
| 18422 | surface->draftAngle = 0.0; | |||
| 18423 | surface->draftStartDistance = 0.0; | |||
| 18424 | surface->draftEndDistance = 0.0; | |||
| 18425 | surface->twistAngle = 0.0; | |||
| 18426 | surface->scaleFactor = 0.0; | |||
| 18427 | surface->alignAngle = 0.0; | |||
| 18428 | surface->solid = false; | |||
| 18429 | surface->sweepAlignmentFlags = 0; | |||
| 18430 | surface->pathFlags = 0; | |||
| 18431 | surface->alignStart = false; | |||
| 18432 | surface->bank = false; | |||
| 18433 | surface->basePointSet = false; | |||
| 18434 | surface->sweepEntityTransformComputed = false; | |||
| 18435 | surface->pathEntityTransformComputed = false; | |||
| 18436 | surface->referenceVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18437 | break; | |||
| 18438 | } | |||
| 18439 | case DRW::REVOLVEDSURFACE: { | |||
| 18440 | auto *surface = static_cast<DRW_RevolvedSurface *>(this); | |||
| 18441 | surface->classId = 0; | |||
| 18442 | surface->id = 0; | |||
| 18443 | surface->axisPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18444 | surface->axisVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18445 | surface->revolveAngle = 0.0; | |||
| 18446 | surface->startAngle = 0.0; | |||
| 18447 | surface->transform = identity(); | |||
| 18448 | surface->draftAngle = 0.0; | |||
| 18449 | surface->draftStartDistance = 0.0; | |||
| 18450 | surface->draftEndDistance = 0.0; | |||
| 18451 | surface->twistAngle = 0.0; | |||
| 18452 | surface->solid = false; | |||
| 18453 | surface->closeToAxis = false; | |||
| 18454 | break; | |||
| 18455 | } | |||
| 18456 | case DRW::SWEPTSURFACE: { | |||
| 18457 | auto *surface = static_cast<DRW_SweptSurface *>(this); | |||
| 18458 | surface->classVersion = 0; | |||
| 18459 | surface->sweepEntityId = 0; | |||
| 18460 | surface->sweepData.clear(); | |||
| 18461 | surface->pathEntityId = 0; | |||
| 18462 | surface->pathData.clear(); | |||
| 18463 | surface->sweepEntityTransform = identity(); | |||
| 18464 | surface->pathEntityTransform = identity(); | |||
| 18465 | surface->draftAngle = 0.0; | |||
| 18466 | surface->draftStartDistance = 0.0; | |||
| 18467 | surface->draftEndDistance = 0.0; | |||
| 18468 | surface->twistAngle = 0.0; | |||
| 18469 | surface->scaleFactor = 1.0; | |||
| 18470 | surface->alignAngle = 0.0; | |||
| 18471 | surface->sweepEntityTransformed = identity(); | |||
| 18472 | surface->pathEntityTransformed = identity(); | |||
| 18473 | surface->solid = false; | |||
| 18474 | surface->sweepAlignmentFlags = 0; | |||
| 18475 | surface->pathFlags = 0; | |||
| 18476 | surface->alignStart = false; | |||
| 18477 | surface->bank = false; | |||
| 18478 | surface->basePointSet = false; | |||
| 18479 | surface->sweepEntityTransformComputed = false; | |||
| 18480 | surface->pathEntityTransformComputed = false; | |||
| 18481 | surface->referenceVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18482 | break; | |||
| 18483 | } | |||
| 18484 | case DRW::LOFTEDSURFACE: { | |||
| 18485 | auto *surface = static_cast<DRW_LoftedSurface *>(this); | |||
| 18486 | surface->loftEntityTransform = identity(); | |||
| 18487 | surface->planeNormalLoftingType = 0; | |||
| 18488 | surface->startDraftAngle = 0.0; | |||
| 18489 | surface->endDraftAngle = 0.0; | |||
| 18490 | surface->startDraftMagnitude = 0.0; | |||
| 18491 | surface->endDraftMagnitude = 0.0; | |||
| 18492 | surface->arcLengthParameterization = false; | |||
| 18493 | surface->noTwist = true; | |||
| 18494 | surface->alignDirection = true; | |||
| 18495 | surface->simpleSurfaces = true; | |||
| 18496 | surface->closedSurfaces = false; | |||
| 18497 | surface->solid = false; | |||
| 18498 | surface->ruledSurface = false; | |||
| 18499 | surface->virtualGuide = false; | |||
| 18500 | surface->numCrossSections = 0; | |||
| 18501 | surface->numGuideCurves = 0; | |||
| 18502 | surface->dxfReferenceData.clear(); | |||
| 18503 | surface->pathCurveHandle = 0; | |||
| 18504 | break; | |||
| 18505 | } | |||
| 18506 | case DRW::NURBSURFACE: { | |||
| 18507 | auto *surface = static_cast<DRW_NurbsSurface *>(this); | |||
| 18508 | surface->short170 = 0; | |||
| 18509 | surface->cvHullDisplay = false; | |||
| 18510 | surface->uvec1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18511 | surface->vvec1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18512 | surface->uvec2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18513 | surface->vvec2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18514 | break; | |||
| 18515 | } | |||
| 18516 | default: | |||
| 18517 | break; | |||
| 18518 | } | |||
| 18519 | } | |||
| 18520 | ||||
| 18521 | bool DRW_Surface::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 18522 | resetDwgState(); | |||
| 18523 | dwgBuffer *sourceBuf = buf; | |||
| 18524 | auto fail = [this, sourceBuf]() { | |||
| 18525 | if (sourceBuf != nullptr) | |||
| 18526 | sourceBuf->invalidate(); | |||
| 18527 | resetDwgState(); | |||
| 18528 | return false; | |||
| 18529 | }; | |||
| 18530 | if (sourceBuf == nullptr) | |||
| 18531 | return fail(); | |||
| 18532 | ||||
| 18533 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 18534 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 18535 | dwgBuffer *stringStream = version > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 18536 | if (!DRW_Entity::parseDwg(version, &bodyProbe, stringStream, bs)) | |||
| 18537 | return fail(); | |||
| 18538 | buf = &bodyProbe; | |||
| 18539 | const std::uint64_t bodyStartBit = currentDwgBit(buf); | |||
| 18540 | ||||
| 18541 | // Surface bodies are opaque here, but their bounded bytes still carry the | |||
| 18542 | // ACIS payload and must be available for rendering and metadata replay. | |||
| 18543 | std::uint64_t bodyEndBit = bodyStartBit; | |||
| 18544 | if (!entityBodyDataEndBit( | |||
| 18545 | stringStream != nullptr ? *stringStream : bodyProbe, | |||
| 18546 | version, objSize, bodyEndBit)) | |||
| 18547 | return fail(); | |||
| 18548 | if (bodyEndBit < bodyStartBit) | |||
| 18549 | return fail(); | |||
| 18550 | if (bodyEndBit > bodyStartBit | |||
| 18551 | && bodyEndBit - bodyStartBit > std::numeric_limits<std::uint32_t>::max()) | |||
| 18552 | return fail(); | |||
| 18553 | hasRawDwgBody = bodyEndBit > bodyStartBit; | |||
| 18554 | rawDwgBodyBitSize = static_cast<std::uint32_t>( | |||
| 18555 | bodyEndBit >= bodyStartBit ? bodyEndBit - bodyStartBit : 0); | |||
| 18556 | rawDwgBodyVersion = version; | |||
| 18557 | dwgClassNum = oType >= 0 ? static_cast<std::uint16_t>(oType) : 0; | |||
| 18558 | dwgPayloadDecoded = false; | |||
| 18559 | crossSectionHandles.clear(); | |||
| 18560 | guideCurveHandles.clear(); | |||
| 18561 | if (bodyEndBit > bodyStartBit | |||
| 18562 | && !copyDwgBitRange(*buf, bodyStartBit, bodyEndBit, rawAcisData)) { | |||
| 18563 | return fail(); | |||
| 18564 | } | |||
| 18565 | ||||
| 18566 | // When has_ds_data is set, the bounded body is an inline DataStorage/SAB | |||
| 18567 | // payload. Keep it opaque, matching the cross-project reader contract; | |||
| 18568 | // interpreting its bytes as subtype fields can fabricate counts and make | |||
| 18569 | // a valid surface fail while reading a nonexistent handle tail. | |||
| 18570 | if (bodyEndBit > bodyStartBit && !hasDsData) { | |||
| 18571 | SurfaceDwgPayloadInfo payload; | |||
| 18572 | if (readSurfaceDwgPayload( | |||
| 18573 | rawAcisData, bodyEndBit - bodyStartBit, version, eType, | |||
| 18574 | surfaceHasModelerFormatVersion(eType), | |||
| 18575 | surfaceModelerFormatVersionLimit(eType), payload)) { | |||
| 18576 | acisEmpty = payload.acisEmpty; | |||
| 18577 | acisVersion = payload.acisVersion; | |||
| 18578 | modelerFormatVersion = payload.modelerFormatVersion; | |||
| 18579 | uIsolines = payload.uIsolines; | |||
| 18580 | vIsolines = payload.vIsolines; | |||
| 18581 | if (payload.extrudedFieldsValid | |||
| 18582 | && eType == DRW::EXTRUDEDSURFACE) { | |||
| 18583 | auto *extruded = static_cast<DRW_ExtrudedSurface *>(this); | |||
| 18584 | extruded->sweepVector = payload.extrudedSweepVector; | |||
| 18585 | extruded->extrudedTransform = payload.extrudedTransform; | |||
| 18586 | extruded->sweepEntityTransform = | |||
| 18587 | payload.extrudedSweepEntityTransform; | |||
| 18588 | extruded->pathEntityTransform = | |||
| 18589 | payload.extrudedPathEntityTransform; | |||
| 18590 | extruded->draftAngle = payload.extrudedDraftAngle; | |||
| 18591 | extruded->draftStartDistance = | |||
| 18592 | payload.extrudedDraftStartDistance; | |||
| 18593 | extruded->draftEndDistance = payload.extrudedDraftEndDistance; | |||
| 18594 | extruded->twistAngle = payload.extrudedTwistAngle; | |||
| 18595 | extruded->scaleFactor = payload.extrudedScaleFactor; | |||
| 18596 | extruded->alignAngle = payload.extrudedAlignAngle; | |||
| 18597 | extruded->solid = payload.extrudedSolid; | |||
| 18598 | extruded->sweepAlignmentFlags = | |||
| 18599 | payload.extrudedSweepAlignmentFlags; | |||
| 18600 | extruded->pathFlags = payload.extrudedPathFlags; | |||
| 18601 | extruded->alignStart = payload.extrudedAlignStart; | |||
| 18602 | extruded->bank = payload.extrudedBank; | |||
| 18603 | extruded->basePointSet = payload.extrudedBasePointSet; | |||
| 18604 | extruded->sweepEntityTransformComputed = | |||
| 18605 | payload.extrudedSweepEntityTransformComputed; | |||
| 18606 | extruded->pathEntityTransformComputed = | |||
| 18607 | payload.extrudedPathEntityTransformComputed; | |||
| 18608 | extruded->referenceVector = payload.extrudedReferenceVector; | |||
| 18609 | } | |||
| 18610 | if (payload.sweptFieldsValid && eType == DRW::SWEPTSURFACE) { | |||
| 18611 | auto *swept = static_cast<DRW_SweptSurface *>(this); | |||
| 18612 | swept->classVersion = payload.sweptClassVersion; | |||
| 18613 | swept->sweepEntityId = payload.sweptEntityId; | |||
| 18614 | swept->sweepData = payload.sweptData; | |||
| 18615 | swept->pathEntityId = payload.sweptPathEntityId; | |||
| 18616 | swept->pathData = payload.sweptPathData; | |||
| 18617 | swept->sweepEntityTransform = payload.sweptEntityTransform; | |||
| 18618 | swept->pathEntityTransform = payload.sweptPathEntityTransform; | |||
| 18619 | swept->draftAngle = payload.sweptDraftAngle; | |||
| 18620 | swept->draftStartDistance = payload.sweptDraftStartDistance; | |||
| 18621 | swept->draftEndDistance = payload.sweptDraftEndDistance; | |||
| 18622 | swept->twistAngle = payload.sweptTwistAngle; | |||
| 18623 | swept->scaleFactor = payload.sweptScaleFactor; | |||
| 18624 | swept->alignAngle = payload.sweptAlignAngle; | |||
| 18625 | swept->solid = payload.sweptSolid; | |||
| 18626 | swept->sweepAlignmentFlags = payload.sweptAlignmentFlags; | |||
| 18627 | swept->pathFlags = payload.sweptPathFlags; | |||
| 18628 | swept->alignStart = payload.sweptAlignStart; | |||
| 18629 | swept->bank = payload.sweptBank; | |||
| 18630 | swept->basePointSet = payload.sweptBasePointSet; | |||
| 18631 | swept->sweepEntityTransformComputed = | |||
| 18632 | payload.sweptEntityTransformComputed; | |||
| 18633 | swept->pathEntityTransformComputed = | |||
| 18634 | payload.sweptPathEntityTransformComputed; | |||
| 18635 | swept->referenceVector = payload.sweptReferenceVector; | |||
| 18636 | } | |||
| 18637 | if (payload.loftedFieldsValid && eType == DRW::LOFTEDSURFACE) { | |||
| 18638 | auto *lofted = static_cast<DRW_LoftedSurface *>(this); | |||
| 18639 | lofted->loftEntityTransform = payload.loftedEntityTransform; | |||
| 18640 | lofted->planeNormalLoftingType = | |||
| 18641 | payload.loftedPlaneNormalLoftingType; | |||
| 18642 | lofted->startDraftAngle = payload.loftedStartDraftAngle; | |||
| 18643 | lofted->endDraftAngle = payload.loftedEndDraftAngle; | |||
| 18644 | lofted->startDraftMagnitude = | |||
| 18645 | payload.loftedStartDraftMagnitude; | |||
| 18646 | lofted->endDraftMagnitude = payload.loftedEndDraftMagnitude; | |||
| 18647 | lofted->arcLengthParameterization = | |||
| 18648 | payload.loftedArcLengthParameterization; | |||
| 18649 | lofted->noTwist = payload.loftedNoTwist; | |||
| 18650 | lofted->alignDirection = payload.loftedAlignDirection; | |||
| 18651 | lofted->simpleSurfaces = payload.loftedSimpleSurfaces; | |||
| 18652 | lofted->closedSurfaces = payload.loftedClosedSurfaces; | |||
| 18653 | lofted->solid = payload.loftedSolid; | |||
| 18654 | lofted->ruledSurface = payload.loftedRuledSurface; | |||
| 18655 | lofted->virtualGuide = payload.loftedVirtualGuide; | |||
| 18656 | lofted->numCrossSections = payload.loftedNumCrossSections; | |||
| 18657 | lofted->numGuideCurves = payload.loftedNumGuideCurves; | |||
| 18658 | } | |||
| 18659 | if (payload.nurbsFieldsValid && eType == DRW::NURBSURFACE) { | |||
| 18660 | auto *nurbs = static_cast<DRW_NurbsSurface *>(this); | |||
| 18661 | nurbs->short170 = payload.nurbsShort170; | |||
| 18662 | nurbs->cvHullDisplay = payload.nurbsCvHullDisplay; | |||
| 18663 | nurbs->uvec1 = payload.nurbsUvec1; | |||
| 18664 | nurbs->vvec1 = payload.nurbsVvec1; | |||
| 18665 | nurbs->uvec2 = payload.nurbsUvec2; | |||
| 18666 | nurbs->vvec2 = payload.nurbsVvec2; | |||
| 18667 | } | |||
| 18668 | dwgPayloadDecoded = true; | |||
| 18669 | if (payload.revolvedFieldsValid | |||
| 18670 | && eType == DRW::REVOLVEDSURFACE) { | |||
| 18671 | auto *revolved = static_cast<DRW_RevolvedSurface *>(this); | |||
| 18672 | revolved->classId = payload.revolvedClassId; | |||
| 18673 | revolved->id = payload.revolvedId; | |||
| 18674 | revolved->axisPoint = payload.revolvedAxisPoint; | |||
| 18675 | revolved->axisVector = payload.revolvedAxisVector; | |||
| 18676 | revolved->revolveAngle = payload.revolvedAngle; | |||
| 18677 | revolved->startAngle = payload.revolvedStartAngle; | |||
| 18678 | revolved->transform = payload.revolvedTransform; | |||
| 18679 | revolved->draftAngle = payload.revolvedDraftAngle; | |||
| 18680 | revolved->draftStartDistance = payload.revolvedDraftStartDistance; | |||
| 18681 | revolved->draftEndDistance = payload.revolvedDraftEndDistance; | |||
| 18682 | revolved->twistAngle = payload.revolvedTwistAngle; | |||
| 18683 | revolved->solid = payload.revolvedSolid; | |||
| 18684 | revolved->closeToAxis = payload.revolvedCloseToAxis; | |||
| 18685 | } | |||
| 18686 | } | |||
| 18687 | } | |||
| 18688 | ||||
| 18689 | // R13-R2004 keep the handle stream inline; seek to the documented body | |||
| 18690 | // boundary before the common handle parser. R2007+ performs that seek in | |||
| 18691 | // parseDwgEntHandle() itself. | |||
| 18692 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 18693 | if (version <= DRW::AC1018 && bodyEndBit > bodyStartBit) { | |||
| 18694 | if (!handleProbe.setPosition(bodyEndBit >> 3)) | |||
| 18695 | return fail(); | |||
| 18696 | handleProbe.setBitPos(static_cast<std::uint8_t>(bodyEndBit & 7u)); | |||
| 18697 | if (!handleProbe.isGood()) | |||
| 18698 | return fail(); | |||
| 18699 | } | |||
| 18700 | std::uint64_t handleEndBit = 0; | |||
| 18701 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 18702 | handleEndBit)) | |||
| 18703 | return fail(); | |||
| 18704 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 18705 | handleEndBit) | |||
| 18706 | || !handleProbe.isGood()) | |||
| 18707 | return fail(); | |||
| 18708 | std::vector<std::uint32_t> parsedCrossSectionHandles; | |||
| 18709 | std::vector<std::uint32_t> parsedGuideCurveHandles; | |||
| 18710 | std::uint32_t parsedPathCurveHandle = 0; | |||
| 18711 | const auto readHandleList = [&](std::int32_t count, | |||
| 18712 | std::vector<std::uint32_t>& values) { | |||
| 18713 | if (count < 0 | |||
| 18714 | || count > static_cast<std::int32_t>( | |||
| 18715 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18716 | || !DRW::reserve(values, count)) | |||
| 18717 | return false; | |||
| 18718 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 18719 | dwgHandle value; | |||
| 18720 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 18721 | value)) | |||
| 18722 | return false; | |||
| 18723 | values.push_back(value.ref); | |||
| 18724 | } | |||
| 18725 | return true; | |||
| 18726 | }; | |||
| 18727 | if (eType == DRW::LOFTEDSURFACE && dwgPayloadDecoded) { | |||
| 18728 | auto *lofted = static_cast<DRW_LoftedSurface *>(this); | |||
| 18729 | if (!readHandleList(lofted->numCrossSections, | |||
| 18730 | parsedCrossSectionHandles) | |||
| 18731 | || !readHandleList(lofted->numGuideCurves, | |||
| 18732 | parsedGuideCurveHandles)) | |||
| 18733 | return fail(); | |||
| 18734 | dwgHandle pathCurve; | |||
| 18735 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 18736 | pathCurve)) | |||
| 18737 | return fail(); | |||
| 18738 | parsedPathCurveHandle = pathCurve.ref; | |||
| 18739 | } | |||
| 18740 | if (!handleProbe.isGood()) | |||
| 18741 | return fail(); | |||
| 18742 | crossSectionHandles = std::move(parsedCrossSectionHandles); | |||
| 18743 | guideCurveHandles = std::move(parsedGuideCurveHandles); | |||
| 18744 | if (eType == DRW::LOFTEDSURFACE) | |||
| 18745 | static_cast<DRW_LoftedSurface *>(this)->pathCurveHandle = | |||
| 18746 | parsedPathCurveHandle; | |||
| 18747 | *sourceBuf = handleProbe; | |||
| 18748 | return true; | |||
| 18749 | } | |||
| 18750 | ||||
| 18751 | bool DRW_Surface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 18752 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 18753 | (void)bs; | |||
| 18754 | if (buf == nullptr || version < DRW::AC1021 || dwgClassNum == 0) | |||
| 18755 | return false; | |||
| 18756 | ||||
| 18757 | const auto validBitShort = [](int value) { | |||
| 18758 | return value >= 0 | |||
| 18759 | && value <= std::numeric_limits<std::uint16_t>::max(); | |||
| 18760 | }; | |||
| 18761 | const auto validCount = [](std::int32_t value, std::size_t limit) { | |||
| 18762 | return value >= 0 && static_cast<std::size_t>(value) <= limit; | |||
| 18763 | }; | |||
| 18764 | const auto validTypedPayload = [&]() { | |||
| 18765 | if (!acisEmpty && !rawAcisData.empty()) | |||
| 18766 | return false; | |||
| 18767 | if (surfaceHasModelerFormatVersion(eType) | |||
| 18768 | && (!validBitShort(modelerFormatVersion) | |||
| 18769 | || (eType == DRW::LOFTEDSURFACE | |||
| 18770 | && modelerFormatVersion | |||
| 18771 | > surfaceModelerFormatVersionLimit(eType)))) | |||
| 18772 | return false; | |||
| 18773 | if (!validBitShort(uIsolines) || !validBitShort(vIsolines)) | |||
| 18774 | return false; | |||
| 18775 | ||||
| 18776 | switch (eType) { | |||
| 18777 | case DRW::EXTRUDEDSURFACE: { | |||
| 18778 | const auto *surface = static_cast<const DRW_ExtrudedSurface *>(this); | |||
| 18779 | return std::isfinite(surface->draftAngle) | |||
| 18780 | && std::isfinite(surface->draftStartDistance) | |||
| 18781 | && std::isfinite(surface->draftEndDistance) | |||
| 18782 | && std::isfinite(surface->twistAngle) | |||
| 18783 | && std::isfinite(surface->scaleFactor) | |||
| 18784 | && std::isfinite(surface->alignAngle) | |||
| 18785 | && finiteSurfaceCoord(surface->referenceVector) | |||
| 18786 | && finiteSurfaceCoord(surface->sweepVector) | |||
| 18787 | && validBitShort(surface->sweepAlignmentFlags) | |||
| 18788 | && validBitShort(surface->pathFlags) | |||
| 18789 | && finiteSurfaceMatrix(surface->extrudedTransform) | |||
| 18790 | && finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 18791 | && finiteSurfaceMatrix(surface->pathEntityTransform); | |||
| 18792 | } | |||
| 18793 | case DRW::LOFTEDSURFACE: { | |||
| 18794 | const auto *surface = static_cast<const DRW_LoftedSurface *>(this); | |||
| 18795 | return std::isfinite(surface->startDraftAngle) | |||
| 18796 | && std::isfinite(surface->endDraftAngle) | |||
| 18797 | && std::isfinite(surface->startDraftMagnitude) | |||
| 18798 | && std::isfinite(surface->endDraftMagnitude) | |||
| 18799 | && validCount(surface->numCrossSections, | |||
| 18800 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18801 | && validCount(surface->numGuideCurves, | |||
| 18802 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18803 | && surface->crossSectionHandles.size() | |||
| 18804 | == static_cast<std::size_t>(surface->numCrossSections) | |||
| 18805 | && surface->guideCurveHandles.size() | |||
| 18806 | == static_cast<std::size_t>(surface->numGuideCurves) | |||
| 18807 | && finiteSurfaceMatrix(surface->loftEntityTransform); | |||
| 18808 | } | |||
| 18809 | case DRW::REVOLVEDSURFACE: { | |||
| 18810 | const auto *surface = static_cast<const DRW_RevolvedSurface *>(this); | |||
| 18811 | return surface->classId <= std::numeric_limits<std::int32_t>::max() | |||
| 18812 | && surface->id <= std::numeric_limits<std::int32_t>::max() | |||
| 18813 | && finiteSurfaceCoord(surface->axisPoint) | |||
| 18814 | && finiteSurfaceCoord(surface->axisVector) | |||
| 18815 | && std::isfinite(surface->revolveAngle) | |||
| 18816 | && std::isfinite(surface->startAngle) | |||
| 18817 | && std::isfinite(surface->draftAngle) | |||
| 18818 | && std::isfinite(surface->draftStartDistance) | |||
| 18819 | && std::isfinite(surface->draftEndDistance) | |||
| 18820 | && std::isfinite(surface->twistAngle) | |||
| 18821 | && finiteSurfaceMatrix(surface->transform); | |||
| 18822 | } | |||
| 18823 | case DRW::SWEPTSURFACE: { | |||
| 18824 | const auto *surface = static_cast<const DRW_SweptSurface *>(this); | |||
| 18825 | return surface->classVersion <= 10 | |||
| 18826 | && surface->sweepEntityId | |||
| 18827 | <= std::numeric_limits<std::int32_t>::max() | |||
| 18828 | && surface->pathEntityId | |||
| 18829 | <= std::numeric_limits<std::int32_t>::max() | |||
| 18830 | && surface->sweepData.size() | |||
| 18831 | <= DRW_SweptSurface::kMaxSweepDataSize | |||
| 18832 | && surface->pathData.size() | |||
| 18833 | <= DRW_SweptSurface::kMaxSweepDataSize | |||
| 18834 | && std::isfinite(surface->draftAngle) | |||
| 18835 | && std::isfinite(surface->draftStartDistance) | |||
| 18836 | && std::isfinite(surface->draftEndDistance) | |||
| 18837 | && std::isfinite(surface->twistAngle) | |||
| 18838 | && std::isfinite(surface->scaleFactor) | |||
| 18839 | && std::isfinite(surface->alignAngle) | |||
| 18840 | && finiteSurfaceCoord(surface->referenceVector) | |||
| 18841 | && validBitShort(surface->sweepAlignmentFlags) | |||
| 18842 | && validBitShort(surface->pathFlags) | |||
| 18843 | && finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 18844 | && finiteSurfaceMatrix(surface->pathEntityTransform); | |||
| 18845 | } | |||
| 18846 | case DRW::NURBSURFACE: | |||
| 18847 | if (version < DRW::AC1027) | |||
| 18848 | return true; | |||
| 18849 | { | |||
| 18850 | const auto *surface = static_cast<const DRW_NurbsSurface *>(this); | |||
| 18851 | return finiteSurfaceCoord(surface->uvec1) | |||
| 18852 | && finiteSurfaceCoord(surface->vvec1) | |||
| 18853 | && finiteSurfaceCoord(surface->uvec2) | |||
| 18854 | && finiteSurfaceCoord(surface->vvec2); | |||
| 18855 | } | |||
| 18856 | case DRW::PLANESURFACE: | |||
| 18857 | return true; | |||
| 18858 | default: | |||
| 18859 | return false; | |||
| 18860 | } | |||
| 18861 | }; | |||
| 18862 | ||||
| 18863 | if (hasRawDwgBody && rawDwgBodyVersion == version) { | |||
| 18864 | if (rawDwgBodyBitSize == 0 | |||
| 18865 | || rawDwgBodyBitSize > surfaceRawBitCapacity(rawAcisData)) | |||
| 18866 | return false; | |||
| 18867 | } else if (!validTypedPayload()) { | |||
| 18868 | return false; | |||
| 18869 | } | |||
| 18870 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 18871 | return false; | |||
| 18872 | ||||
| 18873 | if (hasRawDwgBody && rawDwgBodyVersion == version) { | |||
| 18874 | if (!putSurfaceRawBits(buf, rawAcisData, rawDwgBodyBitSize)) | |||
| 18875 | return false; | |||
| 18876 | } else { | |||
| 18877 | // DXF ACIS/SAB bytes are not the bit-packed DWG ACTION_3DSOLID body. | |||
| 18878 | // Do not place them directly into a DWG object. Native ACIS emission | |||
| 18879 | // remains a separate conversion step; empty modeler bodies are valid | |||
| 18880 | // and allow metadata-only surfaces to round-trip safely. | |||
| 18881 | if (!acisEmpty && !rawAcisData.empty()) | |||
| 18882 | return false; | |||
| 18883 | buf->putBit(1); // ACTION_3DSOLID: no ACIS body | |||
| 18884 | ||||
| 18885 | const bool hasModelerFormat = surfaceHasModelerFormatVersion(eType); | |||
| 18886 | if (hasModelerFormat) { | |||
| 18887 | if (modelerFormatVersion < 0 | |||
| 18888 | || modelerFormatVersion > 0xFFFF | |||
| 18889 | || (eType == DRW::LOFTEDSURFACE && modelerFormatVersion > 3)) | |||
| 18890 | return false; | |||
| 18891 | buf->putBitShort(static_cast<std::uint16_t>(modelerFormatVersion)); | |||
| 18892 | } | |||
| 18893 | if (uIsolines < 0 || uIsolines > 0xFFFF | |||
| 18894 | || vIsolines < 0 || vIsolines > 0xFFFF) | |||
| 18895 | return false; | |||
| 18896 | buf->putBitShort(static_cast<std::uint16_t>(uIsolines)); | |||
| 18897 | buf->putBitShort(static_cast<std::uint16_t>(vIsolines)); | |||
| 18898 | ||||
| 18899 | auto putCoord = [&](const DRW_Coord& value) { | |||
| 18900 | if (!finiteSurfaceCoord(value)) | |||
| 18901 | return false; | |||
| 18902 | buf->put3BitDouble(value); | |||
| 18903 | return true; | |||
| 18904 | }; | |||
| 18905 | auto putBool = [&](bool value) { buf->putBit(value ? 1 : 0); }; | |||
| 18906 | auto putCount = [&](std::int32_t value, std::size_t limit) { | |||
| 18907 | return value >= 0 && static_cast<std::size_t>(value) <= limit; | |||
| 18908 | }; | |||
| 18909 | ||||
| 18910 | switch (eType) { | |||
| 18911 | case DRW::EXTRUDEDSURFACE: { | |||
| 18912 | const auto *surface = static_cast<const DRW_ExtrudedSurface *>(this); | |||
| 18913 | if (!std::isfinite(surface->draftAngle) | |||
| 18914 | || !std::isfinite(surface->draftStartDistance) | |||
| 18915 | || !std::isfinite(surface->draftEndDistance) | |||
| 18916 | || !std::isfinite(surface->twistAngle) | |||
| 18917 | || !std::isfinite(surface->scaleFactor) | |||
| 18918 | || !std::isfinite(surface->alignAngle) | |||
| 18919 | || !finiteSurfaceCoord(surface->referenceVector) | |||
| 18920 | || !finiteSurfaceCoord(surface->sweepVector) | |||
| 18921 | || surface->sweepAlignmentFlags < 0 | |||
| 18922 | || surface->sweepAlignmentFlags > 0xFFFF | |||
| 18923 | || surface->pathFlags < 0 || surface->pathFlags > 0xFFFF | |||
| 18924 | || !finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 18925 | || !finiteSurfaceMatrix(surface->pathEntityTransform)) | |||
| 18926 | return false; | |||
| 18927 | buf->putBitDouble(surface->draftAngle); | |||
| 18928 | buf->putBitDouble(surface->draftStartDistance); | |||
| 18929 | buf->putBitDouble(surface->draftEndDistance); | |||
| 18930 | buf->putBitDouble(surface->twistAngle); | |||
| 18931 | buf->putBitDouble(surface->scaleFactor); | |||
| 18932 | buf->putBitDouble(surface->alignAngle); | |||
| 18933 | // The matrices were validated above; emit them in their specified | |||
| 18934 | // position after SweepOptions' scalar fields. | |||
| 18935 | for (double value : surface->sweepEntityTransform) | |||
| 18936 | buf->putBitDouble(value); | |||
| 18937 | for (double value : surface->pathEntityTransform) | |||
| 18938 | buf->putBitDouble(value); | |||
| 18939 | putBool(surface->solid); | |||
| 18940 | buf->putBitShort(static_cast<std::uint16_t>(surface->sweepAlignmentFlags)); | |||
| 18941 | buf->putBitShort(static_cast<std::uint16_t>(surface->pathFlags)); | |||
| 18942 | putBool(surface->alignStart); | |||
| 18943 | putBool(surface->bank); | |||
| 18944 | putBool(surface->basePointSet); | |||
| 18945 | putBool(surface->sweepEntityTransformComputed); | |||
| 18946 | putBool(surface->pathEntityTransformComputed); | |||
| 18947 | if (!finiteSurfaceCoord(surface->referenceVector) | |||
| 18948 | || !finiteSurfaceCoord(surface->sweepVector) | |||
| 18949 | || !finiteSurfaceMatrix(surface->extrudedTransform)) | |||
| 18950 | return false; | |||
| 18951 | putCoord(surface->referenceVector); | |||
| 18952 | putCoord(surface->sweepVector); | |||
| 18953 | for (double value : surface->extrudedTransform) | |||
| 18954 | buf->putBitDouble(value); | |||
| 18955 | break; | |||
| 18956 | } | |||
| 18957 | case DRW::LOFTEDSURFACE: { | |||
| 18958 | const auto *surface = static_cast<const DRW_LoftedSurface *>(this); | |||
| 18959 | if (!std::isfinite(surface->startDraftAngle) | |||
| 18960 | || !std::isfinite(surface->endDraftAngle) | |||
| 18961 | || !std::isfinite(surface->startDraftMagnitude) | |||
| 18962 | || !std::isfinite(surface->endDraftMagnitude) | |||
| 18963 | || !putCount(surface->numCrossSections, | |||
| 18964 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18965 | || !putCount(surface->numGuideCurves, | |||
| 18966 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18967 | || !finiteSurfaceMatrix(surface->loftEntityTransform)) | |||
| 18968 | return false; | |||
| 18969 | for (double value : surface->loftEntityTransform) | |||
| 18970 | buf->putBitDouble(value); | |||
| 18971 | buf->putBitLong(surface->planeNormalLoftingType); | |||
| 18972 | buf->putBitDouble(surface->startDraftAngle); | |||
| 18973 | buf->putBitDouble(surface->endDraftAngle); | |||
| 18974 | buf->putBitDouble(surface->startDraftMagnitude); | |||
| 18975 | buf->putBitDouble(surface->endDraftMagnitude); | |||
| 18976 | putBool(surface->arcLengthParameterization); | |||
| 18977 | putBool(surface->noTwist); | |||
| 18978 | putBool(surface->alignDirection); | |||
| 18979 | putBool(surface->simpleSurfaces); | |||
| 18980 | putBool(surface->closedSurfaces); | |||
| 18981 | putBool(surface->solid); | |||
| 18982 | putBool(surface->ruledSurface); | |||
| 18983 | putBool(surface->virtualGuide); | |||
| 18984 | buf->putBitShort(static_cast<std::uint16_t>(surface->numCrossSections)); | |||
| 18985 | buf->putBitShort(static_cast<std::uint16_t>(surface->numGuideCurves)); | |||
| 18986 | break; | |||
| 18987 | } | |||
| 18988 | case DRW::REVOLVEDSURFACE: { | |||
| 18989 | const auto *surface = static_cast<const DRW_RevolvedSurface *>(this); | |||
| 18990 | if (surface->classId > std::numeric_limits<std::int32_t>::max() | |||
| 18991 | || surface->id > std::numeric_limits<std::int32_t>::max() | |||
| 18992 | || !finiteSurfaceCoord(surface->axisPoint) | |||
| 18993 | || !finiteSurfaceCoord(surface->axisVector) | |||
| 18994 | || !std::isfinite(surface->revolveAngle) | |||
| 18995 | || !std::isfinite(surface->startAngle) | |||
| 18996 | || !std::isfinite(surface->draftAngle) | |||
| 18997 | || !std::isfinite(surface->draftStartDistance) | |||
| 18998 | || !std::isfinite(surface->draftEndDistance) | |||
| 18999 | || !std::isfinite(surface->twistAngle) | |||
| 19000 | || !finiteSurfaceMatrix(surface->transform)) | |||
| 19001 | return false; | |||
| 19002 | buf->putBitLong(static_cast<std::int32_t>(surface->classId)); | |||
| 19003 | buf->putBitLong(static_cast<std::int32_t>(surface->id)); | |||
| 19004 | buf->put3BitDouble(surface->axisPoint); | |||
| 19005 | buf->put3BitDouble(surface->axisVector); | |||
| 19006 | buf->putBitDouble(surface->revolveAngle); | |||
| 19007 | buf->putBitDouble(surface->startAngle); | |||
| 19008 | for (double value : surface->transform) | |||
| 19009 | buf->putBitDouble(value); | |||
| 19010 | buf->putBitDouble(surface->draftAngle); | |||
| 19011 | buf->putBitDouble(surface->draftStartDistance); | |||
| 19012 | buf->putBitDouble(surface->draftEndDistance); | |||
| 19013 | buf->putBitDouble(surface->twistAngle); | |||
| 19014 | putBool(surface->solid); | |||
| 19015 | putBool(surface->closeToAxis); | |||
| 19016 | break; | |||
| 19017 | } | |||
| 19018 | case DRW::SWEPTSURFACE: { | |||
| 19019 | const auto *surface = static_cast<const DRW_SweptSurface *>(this); | |||
| 19020 | if (surface->classVersion > 10 | |||
| 19021 | || surface->sweepEntityId > std::numeric_limits<std::int32_t>::max() | |||
| 19022 | || surface->pathEntityId > std::numeric_limits<std::int32_t>::max() | |||
| 19023 | || surface->sweepData.size() > DRW_SweptSurface::kMaxSweepDataSize | |||
| 19024 | || surface->pathData.size() > DRW_SweptSurface::kMaxSweepDataSize | |||
| 19025 | || !std::isfinite(surface->draftAngle) | |||
| 19026 | || !std::isfinite(surface->draftStartDistance) | |||
| 19027 | || !std::isfinite(surface->draftEndDistance) | |||
| 19028 | || !std::isfinite(surface->twistAngle) | |||
| 19029 | || !std::isfinite(surface->scaleFactor) | |||
| 19030 | || !std::isfinite(surface->alignAngle) | |||
| 19031 | || !finiteSurfaceCoord(surface->referenceVector) | |||
| 19032 | || surface->sweepAlignmentFlags < 0 | |||
| 19033 | || surface->sweepAlignmentFlags > 0xFFFF | |||
| 19034 | || surface->pathFlags < 0 || surface->pathFlags > 0xFFFF | |||
| 19035 | || !finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 19036 | || !finiteSurfaceMatrix(surface->pathEntityTransform)) | |||
| 19037 | return false; | |||
| 19038 | buf->putBitLong(static_cast<std::int32_t>(surface->classVersion)); | |||
| 19039 | buf->putBitLong(static_cast<std::int32_t>(surface->sweepEntityId)); | |||
| 19040 | buf->putBitLong(static_cast<std::int32_t>(surface->sweepData.size())); | |||
| 19041 | if (!surface->sweepData.empty()) | |||
| 19042 | buf->putBytes(surface->sweepData.data(), surface->sweepData.size()); | |||
| 19043 | buf->putBitLong(static_cast<std::int32_t>(surface->pathEntityId)); | |||
| 19044 | buf->putBitLong(static_cast<std::int32_t>(surface->pathData.size())); | |||
| 19045 | if (!surface->pathData.empty()) | |||
| 19046 | buf->putBytes(surface->pathData.data(), surface->pathData.size()); | |||
| 19047 | buf->putBitDouble(surface->draftAngle); | |||
| 19048 | buf->putBitDouble(surface->draftStartDistance); | |||
| 19049 | buf->putBitDouble(surface->draftEndDistance); | |||
| 19050 | buf->putBitDouble(surface->twistAngle); | |||
| 19051 | buf->putBitDouble(surface->scaleFactor); | |||
| 19052 | buf->putBitDouble(surface->alignAngle); | |||
| 19053 | for (double value : surface->sweepEntityTransform) | |||
| 19054 | buf->putBitDouble(value); | |||
| 19055 | for (double value : surface->pathEntityTransform) | |||
| 19056 | buf->putBitDouble(value); | |||
| 19057 | putBool(surface->solid); | |||
| 19058 | buf->putBitShort(static_cast<std::uint16_t>(surface->sweepAlignmentFlags)); | |||
| 19059 | buf->putBitShort(static_cast<std::uint16_t>(surface->pathFlags)); | |||
| 19060 | putBool(surface->alignStart); | |||
| 19061 | putBool(surface->bank); | |||
| 19062 | putBool(surface->basePointSet); | |||
| 19063 | putBool(surface->sweepEntityTransformComputed); | |||
| 19064 | putBool(surface->pathEntityTransformComputed); | |||
| 19065 | if (!finiteSurfaceCoord(surface->referenceVector)) | |||
| 19066 | return false; | |||
| 19067 | putCoord(surface->referenceVector); | |||
| 19068 | break; | |||
| 19069 | } | |||
| 19070 | case DRW::NURBSURFACE: { | |||
| 19071 | if (version < DRW::AC1027) | |||
| 19072 | break; | |||
| 19073 | const auto *surface = static_cast<const DRW_NurbsSurface *>(this); | |||
| 19074 | if (!finiteSurfaceCoord(surface->uvec1) | |||
| 19075 | || !finiteSurfaceCoord(surface->vvec1) | |||
| 19076 | || !finiteSurfaceCoord(surface->uvec2) | |||
| 19077 | || !finiteSurfaceCoord(surface->vvec2)) | |||
| 19078 | return false; | |||
| 19079 | buf->putBitShort(surface->short170); | |||
| 19080 | putBool(surface->cvHullDisplay); | |||
| 19081 | buf->put3BitDouble(surface->uvec1); | |||
| 19082 | buf->put3BitDouble(surface->vvec1); | |||
| 19083 | buf->put3BitDouble(surface->uvec2); | |||
| 19084 | buf->put3BitDouble(surface->vvec2); | |||
| 19085 | break; | |||
| 19086 | } | |||
| 19087 | case DRW::PLANESURFACE: | |||
| 19088 | break; | |||
| 19089 | default: | |||
| 19090 | return false; | |||
| 19091 | } | |||
| 19092 | } | |||
| 19093 | ||||
| 19094 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 19095 | return false; | |||
| 19096 | if (eType == DRW::LOFTEDSURFACE) { | |||
| 19097 | dwgBufferW *hb = handleBuf != nullptr ? handleBuf : buf; | |||
| 19098 | for (std::uint32_t ref : crossSectionHandles) | |||
| 19099 | putSurfaceHandle(hb, ref); | |||
| 19100 | for (std::uint32_t ref : guideCurveHandles) | |||
| 19101 | putSurfaceHandle(hb, ref); | |||
| 19102 | putSurfaceHandle(hb, | |||
| 19103 | static_cast<const DRW_LoftedSurface *>(this) | |||
| 19104 | ->pathCurveHandle); | |||
| 19105 | } | |||
| 19106 | return true; | |||
| 19107 | } | |||
| 19108 | ||||
| 19109 | bool DRW_Dimension::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 19110 | switch (code) { | |||
| 19111 | case 1: | |||
| 19112 | text = reader->getUtf8String(); | |||
| 19113 | break; | |||
| 19114 | case 2: | |||
| 19115 | name = reader->getUtf8String(); | |||
| 19116 | break; | |||
| 19117 | case 3: | |||
| 19118 | style = reader->getUtf8String(); | |||
| 19119 | break; | |||
| 19120 | case 70: | |||
| 19121 | type = reader->getInt32(); | |||
| 19122 | break; | |||
| 19123 | case 71: | |||
| 19124 | align = reader->getInt32(); | |||
| 19125 | break; | |||
| 19126 | case 72: | |||
| 19127 | linesty = reader->getInt32(); | |||
| 19128 | break; | |||
| 19129 | case 10: | |||
| 19130 | defPoint.x = reader->getDouble(); | |||
| 19131 | break; | |||
| 19132 | case 20: | |||
| 19133 | defPoint.y = reader->getDouble(); | |||
| 19134 | break; | |||
| 19135 | case 30: | |||
| 19136 | defPoint.z = reader->getDouble(); | |||
| 19137 | break; | |||
| 19138 | case 11: | |||
| 19139 | textPoint.x = reader->getDouble(); | |||
| 19140 | break; | |||
| 19141 | case 21: | |||
| 19142 | textPoint.y = reader->getDouble(); | |||
| 19143 | break; | |||
| 19144 | case 31: | |||
| 19145 | textPoint.z = reader->getDouble(); | |||
| 19146 | break; | |||
| 19147 | case 12: | |||
| 19148 | clonePoint.x = reader->getDouble(); | |||
| 19149 | break; | |||
| 19150 | case 22: | |||
| 19151 | clonePoint.y = reader->getDouble(); | |||
| 19152 | break; | |||
| 19153 | case 32: | |||
| 19154 | clonePoint.z = reader->getDouble(); | |||
| 19155 | break; | |||
| 19156 | case 13: | |||
| 19157 | def1.x = reader->getDouble(); | |||
| 19158 | break; | |||
| 19159 | case 23: | |||
| 19160 | def1.y = reader->getDouble(); | |||
| 19161 | break; | |||
| 19162 | case 33: | |||
| 19163 | def1.z = reader->getDouble(); | |||
| 19164 | break; | |||
| 19165 | case 14: | |||
| 19166 | def2.x = reader->getDouble(); | |||
| 19167 | break; | |||
| 19168 | case 24: | |||
| 19169 | def2.y = reader->getDouble(); | |||
| 19170 | break; | |||
| 19171 | case 34: | |||
| 19172 | def2.z = reader->getDouble(); | |||
| 19173 | break; | |||
| 19174 | case 15: | |||
| 19175 | circlePoint.x = reader->getDouble(); | |||
| 19176 | break; | |||
| 19177 | case 25: | |||
| 19178 | circlePoint.y = reader->getDouble(); | |||
| 19179 | break; | |||
| 19180 | case 35: | |||
| 19181 | circlePoint.z = reader->getDouble(); | |||
| 19182 | break; | |||
| 19183 | case 16: | |||
| 19184 | arcPoint.x = reader->getDouble(); | |||
| 19185 | break; | |||
| 19186 | case 26: | |||
| 19187 | arcPoint.y = reader->getDouble(); | |||
| 19188 | break; | |||
| 19189 | case 36: | |||
| 19190 | arcPoint.z = reader->getDouble(); | |||
| 19191 | break; | |||
| 19192 | case 41: | |||
| 19193 | linefactor = reader->getDouble(); | |||
| 19194 | break; | |||
| 19195 | case 53: | |||
| 19196 | rot = reader->getDouble(); | |||
| 19197 | break; | |||
| 19198 | case 50: | |||
| 19199 | angle = reader->getDouble(); | |||
| 19200 | break; | |||
| 19201 | case 52: | |||
| 19202 | oblique = reader->getDouble(); | |||
| 19203 | break; | |||
| 19204 | case 40: | |||
| 19205 | length = reader->getDouble(); | |||
| 19206 | break; | |||
| 19207 | case 51: | |||
| 19208 | hdir = reader->getDouble(); | |||
| 19209 | break; | |||
| 19210 | case 42: | |||
| 19211 | measureValue = reader->getDouble(); | |||
| 19212 | break; | |||
| 19213 | case 74: | |||
| 19214 | flipArrow1 = reader->getInt32() != 0; | |||
| 19215 | break; | |||
| 19216 | case 75: | |||
| 19217 | flipArrow2 = reader->getInt32() != 0; | |||
| 19218 | break; | |||
| 19219 | case 76: | |||
| 19220 | genTol = reader->getInt32() != 0; | |||
| 19221 | break; | |||
| 19222 | case 77: | |||
| 19223 | limGen = reader->getInt32() != 0; | |||
| 19224 | break; | |||
| 19225 | case 43: | |||
| 19226 | tolPlus = reader->getDouble(); | |||
| 19227 | break; | |||
| 19228 | case 44: | |||
| 19229 | tolMinus = reader->getDouble(); | |||
| 19230 | break; | |||
| 19231 | case 45: | |||
| 19232 | tolScale = reader->getDouble(); | |||
| 19233 | break; | |||
| 19234 | case 78: | |||
| 19235 | tolDecimals = reader->getInt32(); | |||
| 19236 | break; | |||
| 19237 | case 79: | |||
| 19238 | tolAlign = reader->getInt32(); | |||
| 19239 | break; | |||
| 19240 | case 80: | |||
| 19241 | tolZero = reader->getInt32(); | |||
| 19242 | break; | |||
| 19243 | case 81: | |||
| 19244 | altTolDecimals = reader->getInt32(); | |||
| 19245 | break; | |||
| 19246 | case 82: | |||
| 19247 | altZero = reader->getInt32(); | |||
| 19248 | break; | |||
| 19249 | case 83: | |||
| 19250 | altTolZero = reader->getInt32(); | |||
| 19251 | break; | |||
| 19252 | case 84: | |||
| 19253 | textMove = reader->getInt32(); | |||
| 19254 | break; | |||
| 19255 | default: | |||
| 19256 | return DRW_Entity::parseCode(code, reader); | |||
| 19257 | } | |||
| 19258 | ||||
| 19259 | return true; | |||
| 19260 | } | |||
| 19261 | ||||
| 19262 | bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) | |||
| 19263 | { | |||
| 19264 | DRW_UNUSED( version)(void)version; | |||
| 19265 | DRW_UNUSED( buf)(void)buf; | |||
| 19266 | DRW_UNUSED( bs)(void)bs; | |||
| 19267 | ||||
| 19268 | 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" ); | |||
| 19269 | ||||
| 19270 | return false; | |||
| 19271 | } | |||
| 19272 | ||||
| 19273 | void DRW_Dimension::resetDwgState() { | |||
| 19274 | DRW_Entity::reset(); | |||
| 19275 | type = 0; | |||
| 19276 | name.clear(); | |||
| 19277 | defPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19278 | textPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19279 | text.clear(); | |||
| 19280 | style = "STANDARD"; | |||
| 19281 | align = 5; | |||
| 19282 | linesty = 1; | |||
| 19283 | linefactor = 1.0; | |||
| 19284 | rot = 0.0; | |||
| 19285 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 19286 | hdir = 0.0; | |||
| 19287 | clonePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19288 | def1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19289 | def2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19290 | angle = 0.0; | |||
| 19291 | oblique = 0.0; | |||
| 19292 | circlePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19293 | arcPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19294 | length = 0.0; | |||
| 19295 | measureValue = 0.0; | |||
| 19296 | flipArrow1 = false; | |||
| 19297 | flipArrow2 = false; | |||
| 19298 | genTol = false; | |||
| 19299 | limGen = false; | |||
| 19300 | tolPlus = 0.0; | |||
| 19301 | tolMinus = 0.0; | |||
| 19302 | tolScale = 0.0; | |||
| 19303 | tolDecimals = 0; | |||
| 19304 | tolAlign = 0; | |||
| 19305 | tolZero = 0; | |||
| 19306 | altTolDecimals = 0; | |||
| 19307 | altZero = 0; | |||
| 19308 | altTolZero = 0; | |||
| 19309 | textMove = 0; | |||
| 19310 | dimStyleH = dwgHandle{}; | |||
| 19311 | blockH = dwgHandle{}; | |||
| 19312 | } | |||
| 19313 | ||||
| 19314 | bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, std::uint32_t bs /*= 0*/) { | |||
| 19315 | (void)sBuf; | |||
| 19316 | resetDwgState(); | |||
| 19317 | if (buf == nullptr) | |||
| 19318 | return false; | |||
| 19319 | ||||
| 19320 | dwgBuffer sBuff = *buf; | |||
| 19321 | dwgBuffer *commonStringBuffer = buf; | |||
| 19322 | if (version > DRW::AC1018) {//2007+ | |||
| 19323 | commonStringBuffer = &sBuff; //separate buffer for strings | |||
| 19324 | } | |||
| 19325 | ||||
| 19326 | if (!DRW_Entity::parseDwg(version, buf, commonStringBuffer, bs)) | |||
| 19327 | return false; | |||
| 19328 | ||||
| 19329 | DRW_DBG("\n***************************** parsing dimension *********************************************")DRW_dbg::dbg("\n***************************** parsing dimension *********************************************" ); | |||
| 19330 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19331 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 19332 | dwgBuffer stringProbe = sBuff; | |||
| 19333 | dwgBuffer *textBuffer = &bodyProbe; | |||
| 19334 | if (version > DRW::AC1018) | |||
| 19335 | textBuffer = &stringProbe; | |||
| 19336 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 19337 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 19338 | if (version > DRW::AC1018) { | |||
| 19339 | stringStartBit = currentDwgBit(textBuffer); | |||
| 19340 | if (version > DRW::AC1021) { | |||
| 19341 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 19342 | if (!entityBodyDataEndBit(*textBuffer, version, objSize, | |||
| 19343 | ignoredBodyEndBit, &stringEndBit)) | |||
| 19344 | return false; | |||
| 19345 | } | |||
| 19346 | } | |||
| 19347 | ||||
| 19348 | std::uint8_t parsedDimVersion = 0; | |||
| 19349 | if (version > DRW::AC1021) { //2010+ | |||
| 19350 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, parsedDimVersion)) | |||
| 19351 | return false; | |||
| 19352 | DRW_DBG("\ndimVersion: ")DRW_dbg::dbg("\ndimVersion: "); DRW_DBG(parsedDimVersion)DRW_dbg::dbg(parsedDimVersion); | |||
| 19353 | } | |||
| 19354 | ||||
| 19355 | DRW_Coord parsedExtrusion; | |||
| 19356 | DRW_Coord parsedTextPoint; | |||
| 19357 | DRW_Coord ignoredInsertionPoint; | |||
| 19358 | double parsedTextPointZ = 0.0; | |||
| 19359 | double ignoredInsertionRotation = 0.0; | |||
| 19360 | std::uint8_t parsedType = 0; | |||
| 19361 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedExtrusion) | |||
| 19362 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, parsedTextPoint.x) | |||
| 19363 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, parsedTextPoint.y) | |||
| 19364 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedTextPointZ) | |||
| 19365 | || !readBoundedRawChar8(bodyProbe, bodyEndBit, parsedType)) { | |||
| 19366 | return false; | |||
| 19367 | } | |||
| 19368 | parsedTextPoint.z = parsedTextPointZ; | |||
| 19369 | ||||
| 19370 | // ODA §20.4.22: Extrusion is plain 3BD (NOT BE) — confirmed by libreDWG dwg_spec_shared.h | |||
| 19371 | DRW_DBG("\nextPoint: ")DRW_dbg::dbg("\nextPoint: "); DRW_DBGPT(parsedExtrusion.x, parsedExtrusion.y,DRW_dbg::dbgPT(parsedExtrusion.x, parsedExtrusion.y, parsedExtrusion .z) | |||
| 19372 | parsedExtrusion.z)DRW_dbg::dbgPT(parsedExtrusion.x, parsedExtrusion.y, parsedExtrusion .z); | |||
| 19373 | DRW_DBG("\ntextPoint: ")DRW_dbg::dbg("\ntextPoint: "); DRW_DBGPT(parsedTextPoint.x, parsedTextPoint.y,DRW_dbg::dbgPT(parsedTextPoint.x, parsedTextPoint.y, parsedTextPoint .z) | |||
| 19374 | parsedTextPoint.z)DRW_dbg::dbgPT(parsedTextPoint.x, parsedTextPoint.y, parsedTextPoint .z); | |||
| 19375 | DRW_DBG("\ntype (70) read: ")DRW_dbg::dbg("\ntype (70) read: "); DRW_DBG(parsedType)DRW_dbg::dbg(parsedType); | |||
| 19376 | const std::uint8_t parsedDimensionType = | |||
| 19377 | static_cast<std::uint8_t>((parsedType & 1) ? parsedType & 0x7F | |||
| 19378 | : parsedType | 0x80); | |||
| 19379 | int parsedTypeValue = (parsedDimensionType & 2) ? parsedDimensionType | 0x20 | |||
| 19380 | : parsedDimensionType & 0xDF; | |||
| 19381 | DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(parsedTypeValue)DRW_dbg::dbg(parsedTypeValue); | |||
| 19382 | //clear last 3 bits to set integer dim type | |||
| 19383 | parsedTypeValue &= 0xF8; | |||
| 19384 | UTF8STRINGstd::string parsedText; | |||
| 19385 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 19386 | parsedText.clear(); | |||
| 19387 | } else if (!readBoundedVariableText(*textBuffer, stringEndBit, version, | |||
| 19388 | parsedText)) { | |||
| 19389 | return false; | |||
| 19390 | } | |||
| 19391 | DRW_DBG("\nforced dim text: ")DRW_dbg::dbg("\nforced dim text: "); DRW_DBG(parsedText.c_str())DRW_dbg::dbg(parsedText.c_str()); | |||
| 19392 | double parsedRot = 0.0; | |||
| 19393 | double parsedHDir = 0.0; | |||
| 19394 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRot) | |||
| 19395 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedHDir) | |||
| 19396 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ignoredInsertionPoint) | |||
| 19397 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 19398 | ignoredInsertionRotation)) { | |||
| 19399 | return false; | |||
| 19400 | } | |||
| 19401 | DRW_DBG("\ninspoint: ")DRW_dbg::dbg("\ninspoint: "); DRW_DBGPT(ignoredInsertionPoint.x,DRW_dbg::dbgPT(ignoredInsertionPoint.x, ignoredInsertionPoint .y, ignoredInsertionPoint.z) | |||
| 19402 | ignoredInsertionPoint.y,DRW_dbg::dbgPT(ignoredInsertionPoint.x, ignoredInsertionPoint .y, ignoredInsertionPoint.z) | |||
| 19403 | ignoredInsertionPoint.z)DRW_dbg::dbgPT(ignoredInsertionPoint.x, ignoredInsertionPoint .y, ignoredInsertionPoint.z); | |||
| 19404 | DRW_DBG(" insRot_code54: ")DRW_dbg::dbg(" insRot_code54: "); DRW_DBG(ignoredInsertionRotation)DRW_dbg::dbg(ignoredInsertionRotation); | |||
| 19405 | ||||
| 19406 | std::uint16_t parsedAlign = 5; | |||
| 19407 | std::uint16_t parsedLineStyle = 1; | |||
| 19408 | double parsedLineFactor = 1.0; | |||
| 19409 | double parsedMeasureValue = 0.0; | |||
| 19410 | bool parsedFlipArrow1 = false; | |||
| 19411 | bool parsedFlipArrow2 = false; | |||
| 19412 | if (version > DRW::AC1014) { //2000+ | |||
| 19413 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedAlign) | |||
| 19414 | || !readBoundedBitShort(bodyProbe, bodyEndBit, parsedLineStyle) | |||
| 19415 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedLineFactor) | |||
| 19416 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 19417 | parsedMeasureValue)) | |||
| 19418 | return false; | |||
| 19419 | DRW_DBG("\n actMeas_code42: ")DRW_dbg::dbg("\n actMeas_code42: "); DRW_DBG(parsedMeasureValue)DRW_dbg::dbg(parsedMeasureValue); | |||
| 19420 | if (version > DRW::AC1018) { //2007+ | |||
| 19421 | bool ignoredBit = false; | |||
| 19422 | if (!readBoundedBit(bodyProbe, bodyEndBit, ignoredBit) | |||
| 19423 | || !readBoundedBit(bodyProbe, bodyEndBit, parsedFlipArrow1) | |||
| 19424 | || !readBoundedBit(bodyProbe, bodyEndBit, parsedFlipArrow2)) | |||
| 19425 | return false; | |||
| 19426 | DRW_DBG("\n2007, unk, flip1, flip2: ")DRW_dbg::dbg("\n2007, unk, flip1, flip2: "); DRW_DBG(ignoredBit)DRW_dbg::dbg(ignoredBit); | |||
| 19427 | DRW_DBG(parsedFlipArrow1)DRW_dbg::dbg(parsedFlipArrow1); DRW_DBG(parsedFlipArrow2)DRW_dbg::dbg(parsedFlipArrow2); | |||
| 19428 | } | |||
| 19429 | } | |||
| 19430 | DRW_Coord parsedClonePoint; | |||
| 19431 | if (!readBoundedRawDouble(bodyProbe, bodyEndBit, parsedClonePoint.x) | |||
| 19432 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, parsedClonePoint.y)) | |||
| 19433 | return false; | |||
| 19434 | parsedClonePoint.z = 0.0; | |||
| 19435 | if (!bodyProbe.isGood() || !textBuffer->isGood() | |||
| 19436 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 19437 | || currentDwgBit(textBuffer) > stringEndBit | |||
| 19438 | || !std::isfinite(parsedExtrusion.x) | |||
| 19439 | || !std::isfinite(parsedExtrusion.y) | |||
| 19440 | || !std::isfinite(parsedExtrusion.z) | |||
| 19441 | || !std::isfinite(parsedTextPoint.x) | |||
| 19442 | || !std::isfinite(parsedTextPoint.y) | |||
| 19443 | || !std::isfinite(parsedTextPoint.z) | |||
| 19444 | || !std::isfinite(ignoredInsertionPoint.x) | |||
| 19445 | || !std::isfinite(ignoredInsertionPoint.y) | |||
| 19446 | || !std::isfinite(ignoredInsertionPoint.z) | |||
| 19447 | || !std::isfinite(parsedRot) | |||
| 19448 | || !std::isfinite(parsedHDir) | |||
| 19449 | || !std::isfinite(ignoredInsertionRotation) | |||
| 19450 | || !std::isfinite(parsedLineFactor) | |||
| 19451 | || !std::isfinite(parsedMeasureValue) | |||
| 19452 | || !std::isfinite(parsedClonePoint.x) | |||
| 19453 | || !std::isfinite(parsedClonePoint.y)) | |||
| 19454 | return false; | |||
| 19455 | ||||
| 19456 | extPoint = parsedExtrusion; | |||
| 19457 | textPoint = parsedTextPoint; | |||
| 19458 | type = parsedTypeValue; | |||
| 19459 | text = parsedText; | |||
| 19460 | rot = parsedRot; | |||
| 19461 | hdir = parsedHDir; | |||
| 19462 | align = parsedAlign; | |||
| 19463 | linesty = parsedLineStyle; | |||
| 19464 | linefactor = parsedLineFactor; | |||
| 19465 | measureValue = parsedMeasureValue; | |||
| 19466 | flipArrow1 = parsedFlipArrow1; | |||
| 19467 | flipArrow2 = parsedFlipArrow2; | |||
| 19468 | clonePoint = parsedClonePoint; | |||
| 19469 | *buf = bodyProbe; | |||
| 19470 | return true; | |||
| 19471 | } | |||
| 19472 | ||||
| 19473 | bool DRW_Dimension::parseDwgDimensionHandles(DRW::Version version, | |||
| 19474 | dwgBuffer *buf, | |||
| 19475 | std::uint64_t handleEndBit) { | |||
| 19476 | if (buf == nullptr) | |||
| 19477 | return false; | |||
| 19478 | dwgBuffer probe = buf->forkIndependent(); | |||
| 19479 | if (!parseDwgEntHandle(version, &probe, true, handleEndBit)) | |||
| 19480 | return false; | |||
| 19481 | dwgHandle parsedDimStyle; | |||
| 19482 | dwgHandle parsedBlock; | |||
| 19483 | if (!readBoundedDwgHandle(probe, handleEndBit, 0, false, parsedDimStyle) | |||
| 19484 | || !readBoundedDwgHandle(probe, handleEndBit, 0, false, parsedBlock)) | |||
| 19485 | return false; | |||
| 19486 | dimStyleH = parsedDimStyle; | |||
| 19487 | blockH = parsedBlock; | |||
| 19488 | *buf = probe; | |||
| 19489 | return true; | |||
| 19490 | } | |||
| 19491 | ||||
| 19492 | bool DRW_DimAligned::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19493 | DRW_Dimension::resetDwgState(); | |||
| 19494 | dwgBuffer *sourceBuf = buf; | |||
| 19495 | auto fail = [this, sourceBuf]() { | |||
| 19496 | if (sourceBuf != nullptr) | |||
| 19497 | sourceBuf->invalidate(); | |||
| 19498 | DRW_Dimension::resetDwgState(); | |||
| 19499 | return false; | |||
| 19500 | }; | |||
| 19501 | if (sourceBuf == nullptr) | |||
| 19502 | return fail(); | |||
| 19503 | ||||
| 19504 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19505 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19506 | return fail(); | |||
| 19507 | buf = &probe; | |||
| 19508 | ||||
| 19509 | if (oType == 0x15) | |||
| 19510 | DRW_DBG("\n***************************** parsing dim linear *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim linear *********************************************\n" ); | |||
| 19511 | else | |||
| 19512 | DRW_DBG("\n***************************** parsing dim aligned *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim aligned *********************************************\n" ); | |||
| 19513 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19514 | DRW_Coord parsedDef1; | |||
| 19515 | DRW_Coord parsedDef2; | |||
| 19516 | DRW_Coord parsedDimPoint; | |||
| 19517 | double parsedOblique = 0.0; | |||
| 19518 | double parsedAngle = 0.0; | |||
| 19519 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19520 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19521 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDimPoint) | |||
| 19522 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedOblique)) | |||
| 19523 | return fail(); | |||
| 19524 | if (oType == 0x15 | |||
| 19525 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedAngle)) | |||
| 19526 | return fail(); | |||
| 19527 | const auto finite = [](const DRW_Coord& point) { | |||
| 19528 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19529 | && std::isfinite(point.z); | |||
| 19530 | }; | |||
| 19531 | if (!std::isfinite(parsedOblique) || !std::isfinite(parsedAngle) | |||
| 19532 | || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 19533 | || !finite(parsedDimPoint)) { | |||
| 19534 | return fail(); | |||
| 19535 | } | |||
| 19536 | setPt3(parsedDef1); //def1 | |||
| 19537 | setPt4(parsedDef2); | |||
| 19538 | setDefPoint(parsedDimPoint); | |||
| 19539 | setOb52(parsedOblique * ARAD57.29577951308232); // radians → degrees | |||
| 19540 | if (oType == 0x15) | |||
| 19541 | setAn50(parsedAngle * ARAD57.29577951308232); | |||
| 19542 | else | |||
| 19543 | type |= 1; | |||
| 19544 | 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"); | |||
| 19545 | ||||
| 19546 | std::uint64_t handleEndBit = 0; | |||
| 19547 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19548 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19549 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n" ); | |||
| 19550 | return fail(); | |||
| 19551 | } | |||
| 19552 | 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"); | |||
| 19553 | 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"); | |||
| 19554 | ||||
| 19555 | // RS crc; //RS */ | |||
| 19556 | if (!buf->isGood()) | |||
| 19557 | return fail(); | |||
| 19558 | *sourceBuf = probe; | |||
| 19559 | return true; | |||
| 19560 | } | |||
| 19561 | ||||
| 19562 | bool DRW_DimRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19563 | DRW_Dimension::resetDwgState(); | |||
| 19564 | dwgBuffer *sourceBuf = buf; | |||
| 19565 | auto fail = [this, sourceBuf]() { | |||
| 19566 | if (sourceBuf != nullptr) | |||
| 19567 | sourceBuf->invalidate(); | |||
| 19568 | DRW_Dimension::resetDwgState(); | |||
| 19569 | return false; | |||
| 19570 | }; | |||
| 19571 | if (sourceBuf == nullptr) | |||
| 19572 | return fail(); | |||
| 19573 | ||||
| 19574 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19575 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19576 | return fail(); | |||
| 19577 | buf = &probe; | |||
| 19578 | ||||
| 19579 | DRW_DBG("\n***************************** parsing dim radial *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim radial *********************************************\n" ); | |||
| 19580 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19581 | DRW_Coord parsedDefPoint; | |||
| 19582 | DRW_Coord parsedCenter; | |||
| 19583 | double parsedLength = 0.0; | |||
| 19584 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19585 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 19586 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedLength) | |||
| 19587 | || !std::isfinite(parsedDefPoint.x) | |||
| 19588 | || !std::isfinite(parsedDefPoint.y) | |||
| 19589 | || !std::isfinite(parsedDefPoint.z) | |||
| 19590 | || !std::isfinite(parsedCenter.x) | |||
| 19591 | || !std::isfinite(parsedCenter.y) | |||
| 19592 | || !std::isfinite(parsedCenter.z) | |||
| 19593 | || !std::isfinite(parsedLength)) | |||
| 19594 | return fail(); | |||
| 19595 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19596 | DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19597 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19598 | setPt5(parsedCenter); //center pt code 15 | |||
| 19599 | DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19600 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19601 | setRa40(parsedLength); //leader length code 40 | |||
| 19602 | DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40()); | |||
| 19603 | type |= 4; | |||
| 19604 | 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"); | |||
| 19605 | if (!buf->isGood()) | |||
| 19606 | return fail(); | |||
| 19607 | ||||
| 19608 | std::uint64_t handleEndBit = 0; | |||
| 19609 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19610 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19611 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n" ); | |||
| 19612 | return fail(); | |||
| 19613 | } | |||
| 19614 | 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"); | |||
| 19615 | 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"); | |||
| 19616 | ||||
| 19617 | // RS crc; //RS */ | |||
| 19618 | if (!buf->isGood()) | |||
| 19619 | return fail(); | |||
| 19620 | *sourceBuf = probe; | |||
| 19621 | return true; | |||
| 19622 | } | |||
| 19623 | ||||
| 19624 | // DRW_DimLargeRadial (AcDbRadialDimensionLarge, LARGE_RADIAL_DIMENSION). | |||
| 19625 | // DXF group-code parser: the AcDbRadialDimensionLarge subclass overloads codes | |||
| 19626 | // 13/14/15/40 (chord / override center / jog point / jog angle), so gate them on | |||
| 19627 | // the subclass marker (like DRW_DimArc). The chord point is stored as the radial | |||
| 19628 | // diameter point so the existing addDimRadial consumer renders center→chord. | |||
| 19629 | bool DRW_DimLargeRadial::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 19630 | if (code == 100) { | |||
| 19631 | std::string s = reader->getString(); | |||
| 19632 | if (s == "AcDbRadialDimensionLarge") { | |||
| 19633 | m_largeRadialSubclassSeen = true; | |||
| 19634 | return true; | |||
| 19635 | } | |||
| 19636 | return DRW_Dimension::parseCode(code, reader); | |||
| 19637 | } | |||
| 19638 | if (m_largeRadialSubclassSeen) { | |||
| 19639 | DRW_Coord chord; | |||
| 19640 | switch (code) { | |||
| 19641 | case 13: chord = getPt5(); chord.x = reader->getDouble(); setPt5(chord); return true; | |||
| 19642 | case 23: chord = getPt5(); chord.y = reader->getDouble(); setPt5(chord); return true; | |||
| 19643 | case 33: chord = getPt5(); chord.z = reader->getDouble(); setPt5(chord); return true; | |||
| 19644 | case 14: overrideCenterPoint.x = reader->getDouble(); return true; | |||
| 19645 | case 24: overrideCenterPoint.y = reader->getDouble(); return true; | |||
| 19646 | case 34: overrideCenterPoint.z = reader->getDouble(); return true; | |||
| 19647 | case 15: jogPoint.x = reader->getDouble(); return true; | |||
| 19648 | case 25: jogPoint.y = reader->getDouble(); return true; | |||
| 19649 | case 35: jogPoint.z = reader->getDouble(); return true; | |||
| 19650 | case 40: jogAngle = reader->getDouble(); return true; | |||
| 19651 | default: break; | |||
| 19652 | } | |||
| 19653 | } | |||
| 19654 | return DRW_Dimension::parseCode(code, reader); | |||
| 19655 | } | |||
| 19656 | ||||
| 19657 | // DRW_DimLargeRadial DWG body: five subclass reads then the dim-style and | |||
| 19658 | // anon-block handles. The three subclass points are ordered | |||
| 19659 | // definition point, JOG point, jog angle, CHORD point, OVERRIDDEN center | |||
| 19660 | // so that the decoded fields match the DXF group codes (chord=13, override=14, | |||
| 19661 | // jog=15) and libdxfrw's own DXF parseCode. The read-only reference parser | |||
| 19662 | // (parseLargeRadialDimension) labels the 2nd/4th/5th reads chord/override/jog, | |||
| 19663 | // i.e. a cyclic rotation of the point roles; that is inconsistent with the DXF | |||
| 19664 | // semantics and with an ODA File Converter DXF↔DWG round-trip (which preserves | |||
| 19665 | // codes 13/14/15 exactly). Verified by large_radial_dim_dwg_tests.cpp against | |||
| 19666 | // an ODA-synthesized fixture, cross-checked with the dwg-parser's DXF read. | |||
| 19667 | // Only the field labels change vs. the reference parser — the read sizes/order | |||
| 19668 | // (3BD, 3BD, BD, 3BD, 3BD) are identical, so buffer alignment is unchanged. | |||
| 19669 | bool DRW_DimLargeRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19670 | DRW_Dimension::resetDwgState(); | |||
| 19671 | overrideCenterPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19672 | jogPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19673 | jogAngle = 0.0; | |||
| 19674 | m_largeRadialSubclassSeen = false; | |||
| 19675 | dwgBuffer *sourceBuf = buf; | |||
| 19676 | auto fail = [this, sourceBuf]() { | |||
| 19677 | if (sourceBuf != nullptr) | |||
| 19678 | sourceBuf->invalidate(); | |||
| 19679 | DRW_Dimension::resetDwgState(); | |||
| 19680 | overrideCenterPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19681 | jogPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19682 | jogAngle = 0.0; | |||
| 19683 | m_largeRadialSubclassSeen = false; | |||
| 19684 | return false; | |||
| 19685 | }; | |||
| 19686 | if (sourceBuf == nullptr) | |||
| 19687 | return fail(); | |||
| 19688 | ||||
| 19689 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19690 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19691 | return fail(); | |||
| 19692 | buf = &probe; | |||
| 19693 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19694 | DRW_Coord parsedDefPoint; | |||
| 19695 | DRW_Coord parsedJogPoint; | |||
| 19696 | DRW_Coord parsedChordPoint; | |||
| 19697 | DRW_Coord parsedOverrideCenter; | |||
| 19698 | double parsedJogAngle = 0.0; | |||
| 19699 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19700 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedJogPoint) | |||
| 19701 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedJogAngle) | |||
| 19702 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedChordPoint) | |||
| 19703 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedOverrideCenter) | |||
| 19704 | || !std::isfinite(parsedDefPoint.x) | |||
| 19705 | || !std::isfinite(parsedDefPoint.y) | |||
| 19706 | || !std::isfinite(parsedDefPoint.z) | |||
| 19707 | || !std::isfinite(parsedJogPoint.x) | |||
| 19708 | || !std::isfinite(parsedJogPoint.y) | |||
| 19709 | || !std::isfinite(parsedJogPoint.z) | |||
| 19710 | || !std::isfinite(parsedChordPoint.x) | |||
| 19711 | || !std::isfinite(parsedChordPoint.y) | |||
| 19712 | || !std::isfinite(parsedChordPoint.z) | |||
| 19713 | || !std::isfinite(parsedOverrideCenter.x) | |||
| 19714 | || !std::isfinite(parsedOverrideCenter.y) | |||
| 19715 | || !std::isfinite(parsedOverrideCenter.z) | |||
| 19716 | || !std::isfinite(parsedJogAngle)) | |||
| 19717 | return fail(); | |||
| 19718 | setDefPoint(parsedDefPoint); // definition point (code 10) | |||
| 19719 | jogPoint = parsedJogPoint; // jog vertex (code 15) | |||
| 19720 | jogAngle = parsedJogAngle; // jog transverse angle (code 40) | |||
| 19721 | setPt5(parsedChordPoint); // chord point (code 13) | |||
| 19722 | overrideCenterPoint = parsedOverrideCenter; // overridden center (code 14) | |||
| 19723 | type |= 4; // radial dimension type bit | |||
| 19724 | if (!buf->isGood()) | |||
| 19725 | return fail(); | |||
| 19726 | std::uint64_t handleEndBit = 0; | |||
| 19727 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19728 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19729 | return fail(); | |||
| 19730 | } | |||
| 19731 | *sourceBuf = probe; | |||
| 19732 | return true; | |||
| 19733 | } | |||
| 19734 | ||||
| 19735 | bool DRW_DimDiametric::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19736 | DRW_Dimension::resetDwgState(); | |||
| 19737 | dwgBuffer *sourceBuf = buf; | |||
| 19738 | auto fail = [this, sourceBuf]() { | |||
| 19739 | if (sourceBuf != nullptr) | |||
| 19740 | sourceBuf->invalidate(); | |||
| 19741 | DRW_Dimension::resetDwgState(); | |||
| 19742 | return false; | |||
| 19743 | }; | |||
| 19744 | if (sourceBuf == nullptr) | |||
| 19745 | return fail(); | |||
| 19746 | ||||
| 19747 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19748 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19749 | return fail(); | |||
| 19750 | buf = &probe; | |||
| 19751 | ||||
| 19752 | DRW_DBG("\n***************************** parsing dim diametric *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim diametric *********************************************\n" ); | |||
| 19753 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19754 | DRW_Coord parsedCenter; | |||
| 19755 | DRW_Coord parsedDefPoint; | |||
| 19756 | double parsedLength = 0.0; | |||
| 19757 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 19758 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19759 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedLength) | |||
| 19760 | || !std::isfinite(parsedCenter.x) | |||
| 19761 | || !std::isfinite(parsedCenter.y) | |||
| 19762 | || !std::isfinite(parsedCenter.z) | |||
| 19763 | || !std::isfinite(parsedDefPoint.x) | |||
| 19764 | || !std::isfinite(parsedDefPoint.y) | |||
| 19765 | || !std::isfinite(parsedDefPoint.z) | |||
| 19766 | || !std::isfinite(parsedLength)) | |||
| 19767 | return fail(); | |||
| 19768 | setPt5(parsedCenter); //center pt code 15 | |||
| 19769 | DRW_DBG("center point: ")DRW_dbg::dbg("center point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19770 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19771 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19772 | DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19773 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19774 | setRa40(parsedLength); //leader length code 40 | |||
| 19775 | DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40()); | |||
| 19776 | type |= 3; | |||
| 19777 | 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"); | |||
| 19778 | if (!buf->isGood()) | |||
| 19779 | return fail(); | |||
| 19780 | ||||
| 19781 | std::uint64_t handleEndBit = 0; | |||
| 19782 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19783 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19784 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n" ); | |||
| 19785 | return fail(); | |||
| 19786 | } | |||
| 19787 | 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"); | |||
| 19788 | 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"); | |||
| 19789 | ||||
| 19790 | // RS crc; //RS */ | |||
| 19791 | if (!buf->isGood()) | |||
| 19792 | return fail(); | |||
| 19793 | *sourceBuf = probe; | |||
| 19794 | return true; | |||
| 19795 | } | |||
| 19796 | ||||
| 19797 | bool DRW_DimAngular::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19798 | DRW_Dimension::resetDwgState(); | |||
| 19799 | dwgBuffer *sourceBuf = buf; | |||
| 19800 | auto fail = [this, sourceBuf]() { | |||
| 19801 | if (sourceBuf != nullptr) | |||
| 19802 | sourceBuf->invalidate(); | |||
| 19803 | DRW_Dimension::resetDwgState(); | |||
| 19804 | return false; | |||
| 19805 | }; | |||
| 19806 | if (sourceBuf == nullptr) | |||
| 19807 | return fail(); | |||
| 19808 | ||||
| 19809 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19810 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19811 | return fail(); | |||
| 19812 | buf = &probe; | |||
| 19813 | ||||
| 19814 | DRW_DBG("\n***************************** parsing dim angular *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular *********************************************\n" ); | |||
| 19815 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19816 | DRW_Coord parsedArcPoint; | |||
| 19817 | DRW_Coord parsedDef1; | |||
| 19818 | DRW_Coord parsedDef2; | |||
| 19819 | DRW_Coord parsedCenter; | |||
| 19820 | DRW_Coord parsedDefPoint; | |||
| 19821 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedArcPoint.x) | |||
| 19822 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedArcPoint.y) | |||
| 19823 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19824 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19825 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 19826 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint)) | |||
| 19827 | return fail(); | |||
| 19828 | parsedArcPoint.z = 0.0; | |||
| 19829 | const auto finite = [](const DRW_Coord& point) { | |||
| 19830 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19831 | && std::isfinite(point.z); | |||
| 19832 | }; | |||
| 19833 | if (!finite(parsedArcPoint) || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 19834 | || !finite(parsedCenter) || !finite(parsedDefPoint)) | |||
| 19835 | return fail(); | |||
| 19836 | setPt6(parsedArcPoint); //code 16 | |||
| 19837 | DRW_DBG("arc Point: ")DRW_dbg::dbg("arc Point: "); DRW_DBGPT(parsedArcPoint.x, parsedArcPoint.y,DRW_dbg::dbgPT(parsedArcPoint.x, parsedArcPoint.y, parsedArcPoint .z) | |||
| 19838 | parsedArcPoint.z)DRW_dbg::dbgPT(parsedArcPoint.x, parsedArcPoint.y, parsedArcPoint .z); | |||
| 19839 | setPt3(parsedDef1); //def1 code 13 | |||
| 19840 | DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(parsedDef1.x, parsedDef1.y, parsedDef1.z)DRW_dbg::dbgPT(parsedDef1.x, parsedDef1.y, parsedDef1.z); | |||
| 19841 | setPt4(parsedDef2); //def2 code 14 | |||
| 19842 | DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(parsedDef2.x, parsedDef2.y, parsedDef2.z)DRW_dbg::dbgPT(parsedDef2.x, parsedDef2.y, parsedDef2.z); | |||
| 19843 | setPt5(parsedCenter); //center pt code 15 | |||
| 19844 | DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19845 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19846 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19847 | DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19848 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19849 | type |= 0x02; | |||
| 19850 | 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"); | |||
| 19851 | if (!buf->isGood()) | |||
| 19852 | return fail(); | |||
| 19853 | ||||
| 19854 | std::uint64_t handleEndBit = 0; | |||
| 19855 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19856 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19857 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n" ); | |||
| 19858 | return fail(); | |||
| 19859 | } | |||
| 19860 | 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"); | |||
| 19861 | 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"); | |||
| 19862 | ||||
| 19863 | // RS crc; //RS */ | |||
| 19864 | if (!buf->isGood()) | |||
| 19865 | return fail(); | |||
| 19866 | *sourceBuf = probe; | |||
| 19867 | return true; | |||
| 19868 | } | |||
| 19869 | ||||
| 19870 | bool DRW_DimAngular3p::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19871 | DRW_Dimension::resetDwgState(); | |||
| 19872 | dwgBuffer *sourceBuf = buf; | |||
| 19873 | auto fail = [this, sourceBuf]() { | |||
| 19874 | if (sourceBuf != nullptr) | |||
| 19875 | sourceBuf->invalidate(); | |||
| 19876 | DRW_Dimension::resetDwgState(); | |||
| 19877 | return false; | |||
| 19878 | }; | |||
| 19879 | if (sourceBuf == nullptr) | |||
| 19880 | return fail(); | |||
| 19881 | ||||
| 19882 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19883 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19884 | return fail(); | |||
| 19885 | buf = &probe; | |||
| 19886 | ||||
| 19887 | DRW_DBG("\n***************************** parsing dim angular3p *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular3p *********************************************\n" ); | |||
| 19888 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19889 | DRW_Coord parsedDefPoint; | |||
| 19890 | DRW_Coord parsedDef1; | |||
| 19891 | DRW_Coord parsedDef2; | |||
| 19892 | DRW_Coord parsedCenter; | |||
| 19893 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19894 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19895 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19896 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter)) | |||
| 19897 | return fail(); | |||
| 19898 | const auto finite = [](const DRW_Coord& point) { | |||
| 19899 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19900 | && std::isfinite(point.z); | |||
| 19901 | }; | |||
| 19902 | if (!finite(parsedDefPoint) || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 19903 | || !finite(parsedCenter)) | |||
| 19904 | return fail(); | |||
| 19905 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19906 | DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19907 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19908 | setPt3(parsedDef1); //def1 code 13 | |||
| 19909 | DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(parsedDef1.x, parsedDef1.y, parsedDef1.z)DRW_dbg::dbgPT(parsedDef1.x, parsedDef1.y, parsedDef1.z); | |||
| 19910 | setPt4(parsedDef2); //def2 code 14 | |||
| 19911 | DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(parsedDef2.x, parsedDef2.y, parsedDef2.z)DRW_dbg::dbgPT(parsedDef2.x, parsedDef2.y, parsedDef2.z); | |||
| 19912 | setPt5(parsedCenter); //center pt code 15 | |||
| 19913 | DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19914 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19915 | type |= 0x05; | |||
| 19916 | 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"); | |||
| 19917 | if (!buf->isGood()) | |||
| 19918 | return fail(); | |||
| 19919 | ||||
| 19920 | std::uint64_t handleEndBit = 0; | |||
| 19921 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19922 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19923 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n" ); | |||
| 19924 | return fail(); | |||
| 19925 | } | |||
| 19926 | 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"); | |||
| 19927 | 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"); | |||
| 19928 | ||||
| 19929 | // RS crc; //RS */ | |||
| 19930 | if (!buf->isGood()) | |||
| 19931 | return fail(); | |||
| 19932 | *sourceBuf = probe; | |||
| 19933 | return true; | |||
| 19934 | } | |||
| 19935 | ||||
| 19936 | bool DRW_DimOrdinate::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19937 | DRW_Dimension::resetDwgState(); | |||
| 19938 | dwgBuffer *sourceBuf = buf; | |||
| 19939 | auto fail = [this, sourceBuf]() { | |||
| 19940 | if (sourceBuf != nullptr) | |||
| 19941 | sourceBuf->invalidate(); | |||
| 19942 | DRW_Dimension::resetDwgState(); | |||
| 19943 | return false; | |||
| 19944 | }; | |||
| 19945 | if (sourceBuf == nullptr) | |||
| 19946 | return fail(); | |||
| 19947 | ||||
| 19948 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19949 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19950 | return fail(); | |||
| 19951 | buf = &probe; | |||
| 19952 | ||||
| 19953 | DRW_DBG("\n***************************** parsing dim ordinate *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim ordinate *********************************************\n" ); | |||
| 19954 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19955 | DRW_Coord parsedDefPoint; | |||
| 19956 | DRW_Coord parsedDef1; | |||
| 19957 | DRW_Coord parsedDef2; | |||
| 19958 | std::uint8_t type2 = 0; | |||
| 19959 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19960 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19961 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19962 | || !readBoundedRawChar8(*buf, bodyEndBit, type2)) | |||
| 19963 | return fail(); | |||
| 19964 | const auto finite = [](const DRW_Coord& point) { | |||
| 19965 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19966 | && std::isfinite(point.z); | |||
| 19967 | }; | |||
| 19968 | if (!finite(parsedDefPoint) || !finite(parsedDef1) || !finite(parsedDef2)) | |||
| 19969 | return fail(); | |||
| 19970 | setDefPoint(parsedDefPoint); | |||
| 19971 | DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19972 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19973 | setPt3(parsedDef1); //def1 | |||
| 19974 | DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(parsedDef1.x, parsedDef1.y, parsedDef1.z)DRW_dbg::dbgPT(parsedDef1.x, parsedDef1.y, parsedDef1.z); | |||
| 19975 | setPt4(parsedDef2); | |||
| 19976 | DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(parsedDef2.x, parsedDef2.y, parsedDef2.z)DRW_dbg::dbgPT(parsedDef2.x, parsedDef2.y, parsedDef2.z); | |||
| 19977 | DRW_DBG("type2 (70) read: ")DRW_dbg::dbg("type2 (70) read: "); DRW_DBG(type2)DRW_dbg::dbg(type2); | |||
| 19978 | // 0B.1: x-vs-y ordinate flag is DXF group-70 bit 6 (0x40), matching the | |||
| 19979 | // filter (rs_filterdxfrw.cpp `type & 64`) and the DWG parseCode path. | |||
| 19980 | // (Previously set bit 7/0x80, which the filter never checks.) The clear | |||
| 19981 | // mask 0xBF already clears 0x40. The DIMENSION base type byte (bit 7) is | |||
| 19982 | // a separate field — see :6141/:6409/:6660, NOT touched here. | |||
| 19983 | int parsedType = type; | |||
| 19984 | parsedType = (type2 & 1) ? parsedType | 0x40 : parsedType & 0xBF; | |||
| 19985 | DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(parsedType)DRW_dbg::dbg(parsedType); | |||
| 19986 | parsedType |= 6; | |||
| 19987 | 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"); | |||
| 19988 | ||||
| 19989 | std::uint64_t handleEndBit = 0; | |||
| 19990 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19991 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19992 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n" ); | |||
| 19993 | return fail(); | |||
| 19994 | } | |||
| 19995 | 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"); | |||
| 19996 | 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"); | |||
| 19997 | ||||
| 19998 | // RS crc; //RS */ | |||
| 19999 | if (!buf->isGood()) | |||
| 20000 | return fail(); | |||
| 20001 | type = parsedType; | |||
| 20002 | *sourceBuf = probe; | |||
| 20003 | return true; | |||
| 20004 | } | |||
| 20005 | ||||
| 20006 | // ---------------------------------------------------------------------------- | |||
| 20007 | // DRW_Dimension shared base encoder (R2000 / AC1015) | |||
| 20008 | // ---------------------------------------------------------------------------- | |||
| 20009 | bool DRW_Dimension::encodeDwgDimBase(DRW::Version version, dwgBufferW *buf, | |||
| 20010 | dwgBufferW *strBuf) const { | |||
| 20011 | // ODA §20.4.22: version RC present for R2010+ (mirrors parseDwg read at version > AC1021) | |||
| 20012 | if (version > DRW::AC1021) | |||
| 20013 | buf->putRawChar8(0); | |||
| 20014 | // R2007+: the dim text below is routed to strBuf (the separate string | |||
| 20015 | // stream) via the (strBuf ? strBuf : buf) selector in putVariableText. | |||
| 20016 | buf->put3BitDouble(extPoint); // 3BD per ODA §20.4.22 (NOT BE, NO padding bits) | |||
| 20017 | buf->putRawDouble(textPoint.x); | |||
| 20018 | buf->putRawDouble(textPoint.y); | |||
| 20019 | buf->putBitDouble(textPoint.z); | |||
| 20020 | // Reverse the parseDwg type-byte transformation: | |||
| 20021 | // parseDwg bit0=0 → type bit7 set; bit0=1 → type bit7 clear | |||
| 20022 | // parseDwg bit1=1 → type bit5 set; bit1=0 → type bit5 clear | |||
| 20023 | std::uint8_t rawByte = static_cast<std::uint8_t>( | |||
| 20024 | ((type & 0x80) ? 0 : 1) | ((type & 0x20) ? 2 : 0)); | |||
| 20025 | buf->putRawChar8(rawByte); | |||
| 20026 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 20027 | buf->putBitDouble(rot); | |||
| 20028 | buf->putBitDouble(hdir); | |||
| 20029 | // ins_scale (3BD) of the dimension's anonymous block — not stored by the | |||
| 20030 | // reader, but ODA/libreDWG default it to (1,1,1) (dwg.spec FIELD_3BD_1), not | |||
| 20031 | // (0,0,0). A zero scale is degenerate for ODA consumers. (write-review #46) | |||
| 20032 | const DRW_Coord insScale{1.0, 1.0, 1.0}; | |||
| 20033 | buf->put3BitDouble(insScale); | |||
| 20034 | buf->putBitDouble(0.0); // ins_rotation (code 54) — default 0, not stored | |||
| 20035 | // R2000 (version > AC1014): alignment, spacing, line factor, measure | |||
| 20036 | buf->putBitShort(static_cast<std::uint16_t>(align)); | |||
| 20037 | buf->putBitShort(static_cast<std::uint16_t>(linesty)); | |||
| 20038 | buf->putBitDouble(linefactor); | |||
| 20039 | buf->putBitDouble(measureValue); | |||
| 20040 | if (version > DRW::AC1018) { | |||
| 20041 | buf->putBit(0); // unknown R2007+ bit | |||
| 20042 | buf->putBit(flipArrow1 ? 1 : 0); | |||
| 20043 | buf->putBit(flipArrow2 ? 1 : 0); | |||
| 20044 | } | |||
| 20045 | buf->putRawDouble(clonePoint.x); | |||
| 20046 | buf->putRawDouble(clonePoint.y); | |||
| 20047 | return true; | |||
| 20048 | } | |||
| 20049 | ||||
| 20050 | // Helper: emit dimStyleH (defaults to STANDARD=0x15) and blockH. | |||
| 20051 | static void putDimHandles(dwgBufferW *buf, const dwgHandle& dimStyleH, const dwgHandle& blockH, | |||
| 20052 | dwgBufferW *hBuf = nullptr) { | |||
| 20053 | dwgBufferW *hb = hBuf ? hBuf : buf; | |||
| 20054 | dwgHandle dsH; | |||
| 20055 | dsH.code = 5; | |||
| 20056 | dsH.ref = (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref; | |||
| 20057 | dsH.size = 0; | |||
| 20058 | if (dsH.ref != 0) { std::uint32_t t = dsH.ref; while (t != 0) { t >>= 8; ++dsH.size; } } | |||
| 20059 | hb->putHandle(dsH); | |||
| 20060 | ||||
| 20061 | dwgHandle bhH; | |||
| 20062 | bhH.code = (blockH.ref == 0) ? 0 : 5; | |||
| 20063 | bhH.ref = blockH.ref; | |||
| 20064 | bhH.size = 0; | |||
| 20065 | if (bhH.ref != 0) { std::uint32_t t = bhH.ref; while (t != 0) { t >>= 8; ++bhH.size; } } | |||
| 20066 | hb->putHandle(bhH); | |||
| 20067 | } | |||
| 20068 | ||||
| 20069 | // ---------------------------------------------------------------------------- | |||
| 20070 | // DRW_DimAligned::encodeDwg (oType=22) | |||
| 20071 | // ---------------------------------------------------------------------------- | |||
| 20072 | bool DRW_DimAligned::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20073 | (void)bs; | |||
| 20074 | oType = 22; | |||
| 20075 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20076 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20077 | buf->put3BitDouble(getPt3()); // def1 | |||
| 20078 | buf->put3BitDouble(getPt4()); // def2 | |||
| 20079 | buf->put3BitDouble(getDefPoint()); // defPoint | |||
| 20080 | buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians | |||
| 20081 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20082 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20083 | return true; | |||
| 20084 | } | |||
| 20085 | ||||
| 20086 | // ---------------------------------------------------------------------------- | |||
| 20087 | // DRW_DimLinear::encodeDwg (oType=21) | |||
| 20088 | // ---------------------------------------------------------------------------- | |||
| 20089 | bool DRW_DimLinear::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20090 | (void)bs; | |||
| 20091 | oType = 21; | |||
| 20092 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20093 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20094 | buf->put3BitDouble(getPt3()); // def1 | |||
| 20095 | buf->put3BitDouble(getPt4()); // def2 | |||
| 20096 | buf->put3BitDouble(getDefPoint()); // defPoint | |||
| 20097 | buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians | |||
| 20098 | buf->putBitDouble(getAn50() / ARAD57.29577951308232); // rotation angle: degrees → radians | |||
| 20099 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20100 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20101 | return true; | |||
| 20102 | } | |||
| 20103 | ||||
| 20104 | // ---------------------------------------------------------------------------- | |||
| 20105 | // DRW_DimRadial::encodeDwg (oType=25) | |||
| 20106 | // ---------------------------------------------------------------------------- | |||
| 20107 | bool DRW_DimRadial::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20108 | (void)bs; | |||
| 20109 | oType = 25; | |||
| 20110 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20111 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20112 | buf->put3BitDouble(getDefPoint()); // center point (code 10) | |||
| 20113 | buf->put3BitDouble(getPt5()); // diameter point (code 15) | |||
| 20114 | buf->putBitDouble(getRa40()); // leader length (code 40) | |||
| 20115 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20116 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20117 | return true; | |||
| 20118 | } | |||
| 20119 | ||||
| 20120 | // ---------------------------------------------------------------------------- | |||
| 20121 | // DRW_DimLargeRadial::encodeDwg (oType=519, custom AcDbRadialDimensionLarge) | |||
| 20122 | // ---------------------------------------------------------------------------- | |||
| 20123 | bool DRW_DimLargeRadial::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 20124 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 20125 | dwgBufferW *handleBuf) { | |||
| 20126 | (void)bs; | |||
| 20127 | oType = kDwgClassNum; | |||
| 20128 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20129 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20130 | buf->put3BitDouble(getCenterPoint()); // definition point (code 10) | |||
| 20131 | buf->put3BitDouble(jogPoint); // jog vertex (code 15) | |||
| 20132 | buf->putBitDouble(jogAngle); // jog transverse angle (code 40) | |||
| 20133 | buf->put3BitDouble(getChordPoint()); // chord point (code 13) | |||
| 20134 | buf->put3BitDouble(overrideCenterPoint); // overridden center (code 14) | |||
| 20135 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20136 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20137 | return true; | |||
| 20138 | } | |||
| 20139 | ||||
| 20140 | // ---------------------------------------------------------------------------- | |||
| 20141 | // DRW_DimDiametric::encodeDwg (oType=26) | |||
| 20142 | // ---------------------------------------------------------------------------- | |||
| 20143 | bool DRW_DimDiametric::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20144 | (void)bs; | |||
| 20145 | oType = 26; | |||
| 20146 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20147 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20148 | buf->put3BitDouble(getPt5()); // first diameter point (code 15) — matches parseDwg order | |||
| 20149 | buf->put3BitDouble(getDefPoint()); // opposite point (code 10) | |||
| 20150 | buf->putBitDouble(getRa40()); // leader length (code 40) | |||
| 20151 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20152 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20153 | return true; | |||
| 20154 | } | |||
| 20155 | ||||
| 20156 | // ---------------------------------------------------------------------------- | |||
| 20157 | // DRW_DimAngular::encodeDwg (oType=24, 2-line angular) | |||
| 20158 | // ---------------------------------------------------------------------------- | |||
| 20159 | bool DRW_DimAngular::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20160 | (void)bs; | |||
| 20161 | oType = 24; | |||
| 20162 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20163 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20164 | // arcPoint is 2RD (not 3BD) in parseDwg — only x and y | |||
| 20165 | buf->putRawDouble(getPt6().x); | |||
| 20166 | buf->putRawDouble(getPt6().y); | |||
| 20167 | buf->put3BitDouble(getPt3()); // def1 (line 1 start) | |||
| 20168 | buf->put3BitDouble(getPt4()); // def2 (line 1 end) | |||
| 20169 | buf->put3BitDouble(getPt5()); // circlePoint (center) | |||
| 20170 | buf->put3BitDouble(getDefPoint()); // defPoint | |||
| 20171 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20172 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20173 | return true; | |||
| 20174 | } | |||
| 20175 | ||||
| 20176 | // ---------------------------------------------------------------------------- | |||
| 20177 | // DRW_DimAngular3p::encodeDwg (oType=23, 3-point angular) | |||
| 20178 | // ---------------------------------------------------------------------------- | |||
| 20179 | bool DRW_DimAngular3p::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20180 | (void)bs; | |||
| 20181 | oType = 23; | |||
| 20182 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20183 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20184 | buf->put3BitDouble(getDefPoint()); // defPoint (code 10) | |||
| 20185 | buf->put3BitDouble(getPt3()); // def1 (code 13) | |||
| 20186 | buf->put3BitDouble(getPt4()); // def2 (code 14) | |||
| 20187 | buf->put3BitDouble(getPt5()); // circlePoint / vertex (code 15) | |||
| 20188 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20189 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20190 | return true; | |||
| 20191 | } | |||
| 20192 | ||||
| 20193 | // ---------------------------------------------------------------------------- | |||
| 20194 | // DRW_DimArc::parseCode (DXF group-code parser) | |||
| 20195 | // ---------------------------------------------------------------------------- | |||
| 20196 | bool DRW_DimArc::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 20197 | if (code == 100) { | |||
| 20198 | std::string s = reader->getString(); | |||
| 20199 | if (s == "AcDbArcDimension") { | |||
| 20200 | m_arcSubclassSeen = true; | |||
| 20201 | return true; | |||
| 20202 | } | |||
| 20203 | // Fall through for AcDbEntity / AcDbDimension so base classes see them | |||
| 20204 | return DRW_Dimension::parseCode(code, reader); | |||
| 20205 | } | |||
| 20206 | if (m_arcSubclassSeen) { | |||
| 20207 | switch (code) { | |||
| 20208 | case 40: arcStartAngle = reader->getDouble(); return true; | |||
| 20209 | case 41: arcEndAngle = reader->getDouble(); return true; | |||
| 20210 | case 70: arcSymbol = reader->getInt32(); return true; | |||
| 20211 | case 71: isPartial = reader->getInt32() != 0; return true; | |||
| 20212 | } | |||
| 20213 | } | |||
| 20214 | switch (code) { | |||
| 20215 | case 17: leaderPt2.x = reader->getDouble(); return true; | |||
| 20216 | case 27: leaderPt2.y = reader->getDouble(); return true; | |||
| 20217 | case 37: leaderPt2.z = reader->getDouble(); return true; | |||
| 20218 | } | |||
| 20219 | return DRW_Dimension::parseCode(code, reader); | |||
| 20220 | } | |||
| 20221 | ||||
| 20222 | // ---------------------------------------------------------------------------- | |||
| 20223 | // DRW_DimArc::parseDwg (ODA DWG spec §20.4.19) | |||
| 20224 | // ---------------------------------------------------------------------------- | |||
| 20225 | bool DRW_DimArc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 20226 | DRW_Dimension::resetDwgState(); | |||
| 20227 | leaderPt2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20228 | arcStartAngle = 0.0; | |||
| 20229 | arcEndAngle = 0.0; | |||
| 20230 | arcSymbol = 0; | |||
| 20231 | isPartial = false; | |||
| 20232 | hasLeader = false; | |||
| 20233 | m_arcSubclassSeen = false; | |||
| 20234 | dwgBuffer *sourceBuf = buf; | |||
| 20235 | auto fail = [this, sourceBuf]() { | |||
| 20236 | if (sourceBuf != nullptr) | |||
| 20237 | sourceBuf->invalidate(); | |||
| 20238 | DRW_Dimension::resetDwgState(); | |||
| 20239 | leaderPt2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20240 | arcStartAngle = 0.0; | |||
| 20241 | arcEndAngle = 0.0; | |||
| 20242 | arcSymbol = 0; | |||
| 20243 | isPartial = false; | |||
| 20244 | hasLeader = false; | |||
| 20245 | m_arcSubclassSeen = false; | |||
| 20246 | return false; | |||
| 20247 | }; | |||
| 20248 | if (sourceBuf == nullptr) | |||
| 20249 | return fail(); | |||
| 20250 | ||||
| 20251 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 20252 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 20253 | return fail(); | |||
| 20254 | buf = &probe; | |||
| 20255 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 20256 | DRW_Coord parsedDefPoint; | |||
| 20257 | DRW_Coord parsedDef1; | |||
| 20258 | DRW_Coord parsedDef2; | |||
| 20259 | DRW_Coord parsedCenter; | |||
| 20260 | DRW_Coord parsedLeaderPoint1; | |||
| 20261 | DRW_Coord parsedLeaderPoint2; | |||
| 20262 | bool parsedPartial = false; | |||
| 20263 | double parsedStartAngle = 0.0; | |||
| 20264 | double parsedEndAngle = 0.0; | |||
| 20265 | bool parsedHasLeader = false; | |||
| 20266 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 20267 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 20268 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 20269 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 20270 | || !readBoundedBit(*buf, bodyEndBit, parsedPartial) | |||
| 20271 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedStartAngle) | |||
| 20272 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedEndAngle) | |||
| 20273 | || !readBoundedBit(*buf, bodyEndBit, parsedHasLeader) | |||
| 20274 | // ODA §20.4.19: leader points are unconditional in the stream. | |||
| 20275 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedLeaderPoint1) | |||
| 20276 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedLeaderPoint2)) | |||
| 20277 | return fail(); | |||
| 20278 | const auto finite = [](const DRW_Coord& point) { | |||
| 20279 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 20280 | && std::isfinite(point.z); | |||
| 20281 | }; | |||
| 20282 | if (!finite(parsedDefPoint) || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 20283 | || !finite(parsedCenter) || !finite(parsedLeaderPoint1) | |||
| 20284 | || !finite(parsedLeaderPoint2) || !std::isfinite(parsedStartAngle) | |||
| 20285 | || !std::isfinite(parsedEndAngle)) | |||
| 20286 | return fail(); | |||
| 20287 | setDefPoint(parsedDefPoint); | |||
| 20288 | setPt3(parsedDef1); | |||
| 20289 | setPt4(parsedDef2); | |||
| 20290 | setPt5(parsedCenter); | |||
| 20291 | setPt6(parsedLeaderPoint1); | |||
| 20292 | leaderPt2 = parsedLeaderPoint2; | |||
| 20293 | isPartial = parsedPartial; | |||
| 20294 | arcStartAngle = parsedStartAngle; | |||
| 20295 | arcEndAngle = parsedEndAngle; | |||
| 20296 | hasLeader = parsedHasLeader; | |||
| 20297 | std::uint64_t handleEndBit = 0; | |||
| 20298 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 20299 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) | |||
| 20300 | return fail(); | |||
| 20301 | *sourceBuf = probe; | |||
| 20302 | return true; | |||
| 20303 | } | |||
| 20304 | ||||
| 20305 | // ---------------------------------------------------------------------------- | |||
| 20306 | // DRW_DimArc::encodeDwg (oType=500 — dynamic class, classNum from writeDwgClasses) | |||
| 20307 | // ---------------------------------------------------------------------------- | |||
| 20308 | bool DRW_DimArc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 20309 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20310 | (void)bs; | |||
| 20311 | oType = DRW_DimArc::kDwgClassNum; // assigned in writeDwgClasses; reader resolves via classesmap | |||
| 20312 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20313 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20314 | buf->put3BitDouble(getDefPoint()); // arc dim-line arc point (code 10) | |||
| 20315 | buf->put3BitDouble(getPt3()); // extension line 1 (code 13) | |||
| 20316 | buf->put3BitDouble(getPt4()); // extension line 2 (code 14) | |||
| 20317 | buf->put3BitDouble(getPt5()); // arc center (code 15) | |||
| 20318 | buf->putBit(isPartial ? 1 : 0); | |||
| 20319 | buf->putBitDouble(arcStartAngle); | |||
| 20320 | buf->putBitDouble(arcEndAngle); | |||
| 20321 | buf->putBit(hasLeader ? 1 : 0); | |||
| 20322 | // ODA §20.4.19: leader points are UNCONDITIONAL — always written; default to ext-line pts | |||
| 20323 | DRW_Coord lp1 = hasLeader ? getPt6() : getPt3(); | |||
| 20324 | DRW_Coord lp2 = hasLeader ? leaderPt2 : getPt4(); | |||
| 20325 | buf->put3BitDouble(lp1); // leader point 1 (code 16) | |||
| 20326 | buf->put3BitDouble(lp2); // leader point 2 (code 17) | |||
| 20327 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20328 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20329 | return true; | |||
| 20330 | } | |||
| 20331 | ||||
| 20332 | // ---------------------------------------------------------------------------- | |||
| 20333 | // DRW_DimOrdinate::encodeDwg (oType=20) | |||
| 20334 | // ---------------------------------------------------------------------------- | |||
| 20335 | bool DRW_DimOrdinate::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 20336 | (void)bs; | |||
| 20337 | oType = 20; | |||
| 20338 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 20339 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 20340 | buf->put3BitDouble(getDefPoint()); // origin/definition point (code 10) | |||
| 20341 | buf->put3BitDouble(getPt3()); // feature location point (code 13) | |||
| 20342 | buf->put3BitDouble(getPt4()); // leader end point (code 14) | |||
| 20343 | // type2 byte encodes the x-vs-y ordinate flag (bit 6 / 0x40 of type, per | |||
| 20344 | // 0B.1) — keeps the DWG byte round-trip self-consistent with the parse | |||
| 20345 | // side while making the filter's `type & 64` check fire. | |||
| 20346 | std::uint8_t type2byte = (type & 0x40) ? 1 : 0; | |||
| 20347 | buf->putRawChar8(type2byte); | |||
| 20348 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 20349 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 20350 | return true; | |||
| 20351 | } | |||
| 20352 | ||||
| 20353 | bool DRW_Leader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 20354 | switch (code) { | |||
| 20355 | case 3: | |||
| 20356 | style = reader->getUtf8String(); | |||
| 20357 | break; | |||
| 20358 | case 71: | |||
| 20359 | arrow = reader->getInt32(); | |||
| 20360 | break; | |||
| 20361 | case 72: | |||
| 20362 | leadertype = reader->getInt32(); | |||
| 20363 | break; | |||
| 20364 | case 73: | |||
| 20365 | flag = reader->getInt32(); | |||
| 20366 | break; | |||
| 20367 | case 74: | |||
| 20368 | hookline = reader->getInt32(); | |||
| 20369 | break; | |||
| 20370 | case 75: | |||
| 20371 | hookflag = reader->getInt32(); | |||
| 20372 | break; | |||
| 20373 | case 76: | |||
| 20374 | vertnum = reader->getInt32(); | |||
| 20375 | hasVertexCount = true; | |||
| 20376 | break; | |||
| 20377 | case 77: | |||
| 20378 | coloruse = reader->getInt32(); | |||
| 20379 | break; | |||
| 20380 | case 40: | |||
| 20381 | textheight = reader->getDouble(); | |||
| 20382 | break; | |||
| 20383 | case 41: | |||
| 20384 | textwidth = reader->getDouble(); | |||
| 20385 | break; | |||
| 20386 | case 10: | |||
| 20387 | vertexpoint= std::make_shared<DRW_Coord>(); | |||
| 20388 | vertexlist.push_back(vertexpoint); | |||
| 20389 | vertexpoint->x = reader->getDouble(); | |||
| 20390 | break; | |||
| 20391 | case 20: | |||
| 20392 | if(vertexpoint) | |||
| 20393 | vertexpoint->y = reader->getDouble(); | |||
| 20394 | break; | |||
| 20395 | case 30: | |||
| 20396 | if(vertexpoint) | |||
| 20397 | vertexpoint->z = reader->getDouble(); | |||
| 20398 | break; | |||
| 20399 | case 340: | |||
| 20400 | annotHandle = reader->getHandleString(); | |||
| 20401 | break; | |||
| 20402 | case 210: | |||
| 20403 | extrusionPoint.x = reader->getDouble(); | |||
| 20404 | break; | |||
| 20405 | case 220: | |||
| 20406 | extrusionPoint.y = reader->getDouble(); | |||
| 20407 | break; | |||
| 20408 | case 230: | |||
| 20409 | extrusionPoint.z = reader->getDouble(); | |||
| 20410 | break; | |||
| 20411 | case 211: | |||
| 20412 | horizdir.x = reader->getDouble(); | |||
| 20413 | break; | |||
| 20414 | case 221: | |||
| 20415 | horizdir.y = reader->getDouble(); | |||
| 20416 | break; | |||
| 20417 | case 231: | |||
| 20418 | horizdir.z = reader->getDouble(); | |||
| 20419 | break; | |||
| 20420 | case 212: | |||
| 20421 | offsetblock.x = reader->getDouble(); | |||
| 20422 | break; | |||
| 20423 | case 222: | |||
| 20424 | offsetblock.y = reader->getDouble(); | |||
| 20425 | break; | |||
| 20426 | case 232: | |||
| 20427 | offsetblock.z = reader->getDouble(); | |||
| 20428 | break; | |||
| 20429 | case 213: | |||
| 20430 | offsettext.x = reader->getDouble(); | |||
| 20431 | break; | |||
| 20432 | case 223: | |||
| 20433 | offsettext.y = reader->getDouble(); | |||
| 20434 | break; | |||
| 20435 | case 233: | |||
| 20436 | offsettext.z = reader->getDouble(); | |||
| 20437 | break; | |||
| 20438 | default: | |||
| 20439 | return DRW_Entity::parseCode(code, reader); | |||
| 20440 | } | |||
| 20441 | ||||
| 20442 | return true; | |||
| 20443 | } | |||
| 20444 | ||||
| 20445 | bool DRW_Leader::validatePayloadFields() const { | |||
| 20446 | const auto finite = [](const DRW_Coord& point) { | |||
| 20447 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 20448 | && std::isfinite(point.z); | |||
| 20449 | }; | |||
| 20450 | if ((arrow != 0 && arrow != 1) || (hookline != 0 && hookline != 1) | |||
| 20451 | || (hookflag != 0 && hookflag != 1) || leadertype < 0 | |||
| 20452 | || leadertype > 1 || flag < 0 || flag > 3 | |||
| 20453 | || coloruse < 0 | |||
| 20454 | || coloruse > static_cast<int>(std::numeric_limits<std::uint16_t>::max()) | |||
| 20455 | || vertexlist.size() > static_cast<std::size_t>(kMaxLeaderVertices) | |||
| 20456 | || !std::isfinite(textheight) || !std::isfinite(textwidth) | |||
| 20457 | || !finite(origin) || !finite(extrusionPoint) || !finite(horizdir) | |||
| 20458 | || !finite(offsetblock) || !finite(offsettext)) { | |||
| 20459 | return false; | |||
| 20460 | } | |||
| 20461 | return std::all_of(vertexlist.begin(), vertexlist.end(), | |||
| 20462 | [&finite](const std::shared_ptr<DRW_Coord>& point) { | |||
| 20463 | return point != nullptr && finite(*point); | |||
| 20464 | }); | |||
| 20465 | } | |||
| 20466 | ||||
| 20467 | bool DRW_Leader::validateDxf() const { | |||
| 20468 | if (!validatePayloadFields()) | |||
| 20469 | return false; | |||
| 20470 | if (!hasVertexCount) | |||
| 20471 | return true; | |||
| 20472 | return vertnum >= 0 | |||
| 20473 | && vertnum <= kMaxLeaderVertices | |||
| 20474 | && static_cast<std::size_t>(vertnum) == vertexlist.size(); | |||
| 20475 | } | |||
| 20476 | ||||
| 20477 | void DRW_Leader::resetDwgState() { | |||
| 20478 | DRW_Entity::reset(); | |||
| 20479 | style.clear(); | |||
| 20480 | arrow = 1; | |||
| 20481 | leadertype = 0; | |||
| 20482 | flag = 3; | |||
| 20483 | hookline = 1; | |||
| 20484 | hookflag = 1; | |||
| 20485 | textheight = 1.0; | |||
| 20486 | textwidth = 1.0; | |||
| 20487 | vertnum = 0; | |||
| 20488 | coloruse = 7; | |||
| 20489 | annotHandle = 0; | |||
| 20490 | origin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20491 | extrusionPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 20492 | horizdir = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 20493 | offsetblock = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20494 | offsettext = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20495 | vertexlist.clear(); | |||
| 20496 | vertexpoint.reset(); | |||
| 20497 | hasVertexCount = false; | |||
| 20498 | dimStyleH = dwgHandle{}; | |||
| 20499 | AnnotH = dwgHandle{}; | |||
| 20500 | } | |||
| 20501 | ||||
| 20502 | bool DRW_Leader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 20503 | resetDwgState(); | |||
| 20504 | dwgBuffer *sourceBuf = buf; | |||
| 20505 | auto fail = [this, sourceBuf]() { | |||
| 20506 | if (sourceBuf != nullptr) | |||
| 20507 | sourceBuf->invalidate(); | |||
| 20508 | resetDwgState(); | |||
| 20509 | return false; | |||
| 20510 | }; | |||
| 20511 | if (sourceBuf == nullptr) | |||
| 20512 | return fail(); | |||
| 20513 | ||||
| 20514 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 20515 | buf = &bodyProbe; | |||
| 20516 | ||||
| 20517 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 20518 | dwgBuffer *sBuf = buf; | |||
| 20519 | if (version > DRW::AC1018) {//2007+ | |||
| 20520 | sBuf = &sBuff; //separate buffer for strings | |||
| 20521 | } | |||
| 20522 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 20523 | if (!ret || !buf->isGood() || !sBuf->isGood()) | |||
| 20524 | return fail(); | |||
| 20525 | DRW_DBG("\n***************************** parsing leader *********************************************\n")DRW_dbg::dbg("\n***************************** parsing leader *********************************************\n" ); | |||
| 20526 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 20527 | bool ignoredBit = false; | |||
| 20528 | std::uint16_t ignoredShort = 0; | |||
| 20529 | std::uint16_t parsedAnnotationType = 0; | |||
| 20530 | std::uint16_t parsedLeaderType = 0; | |||
| 20531 | if (!readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20532 | || !readBoundedBitShort(*buf, bodyEndBit, parsedAnnotationType) | |||
| 20533 | || !readBoundedBitShort(*buf, bodyEndBit, parsedLeaderType)) | |||
| 20534 | return fail(); | |||
| 20535 | if (parsedAnnotationType > 3 || parsedLeaderType > 1) | |||
| 20536 | return fail(); | |||
| 20537 | DRW_DBG(" Path type ")DRW_dbg::dbg(" Path type "); DRW_DBG(parsedLeaderType)DRW_dbg::dbg(parsedLeaderType); | |||
| 20538 | std::uint32_t parsedPointCount = 0; | |||
| 20539 | if (!readTableBodyCount(version, buf, objSize, kMaxLeaderVertices, 6, | |||
| 20540 | parsedPointCount)) | |||
| 20541 | return fail(); | |||
| 20542 | const std::int32_t nPt = static_cast<std::int32_t>(parsedPointCount); | |||
| 20543 | DRW_DBG(" Num pts ")DRW_dbg::dbg(" Num pts "); DRW_DBG(nPt)DRW_dbg::dbg(nPt); | |||
| 20544 | std::uint64_t pointBits = 0; | |||
| 20545 | if (!dwgSafety::multiply(parsedPointCount, 6, pointBits) | |||
| 20546 | || !proxyEntityHasBits(*buf, bodyEndBit, pointBits)) | |||
| 20547 | return fail(); | |||
| 20548 | ||||
| 20549 | // add vertexes | |||
| 20550 | std::vector<std::shared_ptr<DRW_Coord>> parsedVertices; | |||
| 20551 | if (!DRW::reserve(parsedVertices, nPt)) | |||
| 20552 | return fail(); | |||
| 20553 | for (std::uint32_t i = 0; i < parsedPointCount; i++){ | |||
| 20554 | DRW_Coord vertex; | |||
| 20555 | if (!readBoundedBitCoord(*buf, bodyEndBit, vertex)) | |||
| 20556 | return fail(); | |||
| 20557 | parsedVertices.push_back(std::make_shared<DRW_Coord>(vertex)); | |||
| 20558 | DRW_DBG("\nvertex ")DRW_dbg::dbg("\nvertex "); DRW_DBGPT(vertex.x, vertex.y, vertex.z)DRW_dbg::dbgPT(vertex.x, vertex.y, vertex.z); | |||
| 20559 | } | |||
| 20560 | DRW_Coord parsedOrigin; | |||
| 20561 | DRW_Coord parsedExtrusion; | |||
| 20562 | DRW_Coord parsedHorizdir; | |||
| 20563 | DRW_Coord parsedOffsetblock; | |||
| 20564 | DRW_Coord parsedOffsettext{0.0, 0.0, 0.0}; | |||
| 20565 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedOrigin) | |||
| 20566 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtrusion) | |||
| 20567 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedHorizdir) | |||
| 20568 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedOffsetblock)) | |||
| 20569 | return fail(); | |||
| 20570 | DRW_DBG("\norigin ")DRW_dbg::dbg("\norigin "); DRW_DBGPT(parsedOrigin.x, parsedOrigin.y, parsedOrigin.z)DRW_dbg::dbgPT(parsedOrigin.x, parsedOrigin.y, parsedOrigin.z ); | |||
| 20571 | // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — confirmed by libreDWG dwg.spec:3439 | |||
| 20572 | if (leaderHasEndpointProjection(version)) { | |||
| 20573 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedOffsettext)) | |||
| 20574 | return fail(); | |||
| 20575 | DRW_DBG("\nEndptproj ")DRW_dbg::dbg("\nEndptproj "); DRW_DBGPT(parsedOffsettext.x, parsedOffsettext.y, parsedOffsettext.z)DRW_dbg::dbgPT(parsedOffsettext.x, parsedOffsettext.y, parsedOffsettext .z); | |||
| 20576 | } | |||
| 20577 | if (version < DRW::AC1015) { //R14 - | |||
| 20578 | double ignoredDouble = 0.0; | |||
| 20579 | if (!readBoundedBitDouble(*buf, bodyEndBit, ignoredDouble)) | |||
| 20580 | return fail(); | |||
| 20581 | } | |||
| 20582 | double parsedTextheight = 0.0; | |||
| 20583 | double parsedTextwidth = 0.0; | |||
| 20584 | bool parsedHookline = false; | |||
| 20585 | bool parsedArrow = false; | |||
| 20586 | std::uint16_t parsedColoruse = 7; | |||
| 20587 | if ((leaderHasTextBox(version) | |||
| 20588 | && (!readBoundedBitDouble(*buf, bodyEndBit, parsedTextheight) | |||
| 20589 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedTextwidth))) | |||
| 20590 | || !readBoundedBit(*buf, bodyEndBit, parsedHookline) | |||
| 20591 | || !readBoundedBit(*buf, bodyEndBit, parsedArrow)) | |||
| 20592 | return fail(); | |||
| 20593 | 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); | |||
| 20594 | 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); | |||
| 20595 | ||||
| 20596 | // ODA §20.4.47 places arrowhead type immediately after the hook and | |||
| 20597 | // arrow flags in every DWG version. R2000+ keeps the field even though | |||
| 20598 | // the remaining legacy arrowhead data is absent. | |||
| 20599 | if (!readBoundedBitShort(*buf, bodyEndBit, ignoredShort)) | |||
| 20600 | return fail(); | |||
| 20601 | if (version < DRW::AC1015) { //R14 - | |||
| 20602 | double ignoredDimSize = 0.0; | |||
| 20603 | if (!readBoundedBitDouble(*buf, bodyEndBit, ignoredDimSize) | |||
| 20604 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20605 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20606 | || !readBoundedBitShort(*buf, bodyEndBit, ignoredShort) | |||
| 20607 | || !readBoundedBitShort(*buf, bodyEndBit, parsedColoruse) | |||
| 20608 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20609 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit)) | |||
| 20610 | return fail(); | |||
| 20611 | } else { //R2000+ | |||
| 20612 | if (!readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20613 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit)) | |||
| 20614 | return fail(); | |||
| 20615 | } | |||
| 20616 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 20617 | std::uint64_t handleEndBit = 0; | |||
| 20618 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 20619 | handleEndBit)) | |||
| 20620 | return fail(); | |||
| 20621 | ||||
| 20622 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 20623 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 20624 | handleEndBit); | |||
| 20625 | if (!ret || !handleProbe.isGood()) | |||
| 20626 | return fail(); | |||
| 20627 | 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"); | |||
| 20628 | dwgHandle parsedAnnotH; | |||
| 20629 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 20630 | parsedAnnotH)) | |||
| 20631 | return fail(); | |||
| 20632 | dwgHandle parsedDimStyleH; | |||
| 20633 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 20634 | parsedDimStyleH)) | |||
| 20635 | return fail(); /* H 7 STYLE (hard pointer) */ | |||
| 20636 | 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"); | |||
| 20637 | 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"); | |||
| 20638 | 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"); | |||
| 20639 | // RS crc; //RS */ | |||
| 20640 | const auto finite = [](const DRW_Coord& point) { | |||
| 20641 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 20642 | && std::isfinite(point.z); | |||
| 20643 | }; | |||
| 20644 | if (!handleProbe.isGood() || !sBuf->isGood() | |||
| 20645 | || !finite(parsedOrigin) || !finite(parsedExtrusion) | |||
| 20646 | || !finite(parsedHorizdir) || !finite(parsedOffsetblock) | |||
| 20647 | || !finite(parsedOffsettext) || !std::isfinite(parsedTextheight) | |||
| 20648 | || !std::isfinite(parsedTextwidth) | |||
| 20649 | || !std::all_of(parsedVertices.begin(), parsedVertices.end(), | |||
| 20650 | [](const std::shared_ptr<DRW_Coord>& point) { | |||
| 20651 | return point != nullptr | |||
| 20652 | && std::isfinite(point->x) | |||
| 20653 | && std::isfinite(point->y) | |||
| 20654 | && std::isfinite(point->z); | |||
| 20655 | })) | |||
| 20656 | return fail(); | |||
| 20657 | *sourceBuf = handleProbe; | |||
| 20658 | flag = static_cast<int>(parsedAnnotationType); | |||
| 20659 | leadertype = parsedLeaderType; | |||
| 20660 | vertnum = nPt; | |||
| 20661 | origin = parsedOrigin; | |||
| 20662 | extrusionPoint = parsedExtrusion; | |||
| 20663 | horizdir = parsedHorizdir; | |||
| 20664 | offsetblock = parsedOffsetblock; | |||
| 20665 | offsettext = parsedOffsettext; | |||
| 20666 | textheight = parsedTextheight; | |||
| 20667 | textwidth = parsedTextwidth; | |||
| 20668 | hookline = parsedHookline; | |||
| 20669 | arrow = parsedArrow; | |||
| 20670 | coloruse = static_cast<int>(parsedColoruse); | |||
| 20671 | AnnotH = parsedAnnotH; | |||
| 20672 | annotHandle = AnnotH.ref; | |||
| 20673 | dimStyleH = parsedDimStyleH; | |||
| 20674 | vertexlist = std::move(parsedVertices); | |||
| 20675 | return true; | |||
| 20676 | } | |||
| 20677 | ||||
| 20678 | // DXF CONTEXT_DATA{} nested-block state machine (§20.4.86). The nested blocks | |||
| 20679 | // open with 300 "CONTEXT_DATA{" / 302 "LEADER{" / 304 "LEADER_LINE{" and close | |||
| 20680 | // with the distinct codes 301 / 303 / 305, so the open block is tracked with a | |||
| 20681 | // single state int (no stack needed). The numeric group codes are overloaded | |||
| 20682 | // by block — e.g. 40 is the overall scale in CONTEXT, the landing distance in | |||
| 20683 | // LEADER and the arrow size in LEADER_LINE; 10/20/30 are the content base point, | |||
| 20684 | // the connection point and a polyline vertex respectively — so they are routed | |||
| 20685 | // per state into `context`. Returns true when the code belongs to the context | |||
| 20686 | // block (consumed); false at entity level so parseCode handles it. | |||
| 20687 | bool DRW_MLeader::parseDxfContextCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 20688 | try { | |||
| 20689 | switch (code) { // block open/close markers | |||
| 20690 | case 300: | |||
| 20691 | if (m_dxfCtxState != 0 || reader->getString() != "CONTEXT_DATA{") | |||
| 20692 | return false; | |||
| 20693 | m_dxfCtxState = 1; | |||
| 20694 | return true; | |||
| 20695 | case 301: | |||
| 20696 | if (m_dxfCtxState != 1 || reader->getString() != "}") | |||
| 20697 | return false; | |||
| 20698 | m_dxfCtxState = 0; | |||
| 20699 | return true; | |||
| 20700 | case 302: | |||
| 20701 | if (m_dxfCtxState != 1 || reader->getString() != "LEADER{" | |||
| 20702 | || context.roots.size() >= static_cast<std::size_t>(kMaxMLeaderItems)) | |||
| 20703 | return false; | |||
| 20704 | context.roots.emplace_back(); | |||
| 20705 | m_dxfCtxState = 2; | |||
| 20706 | return true; | |||
| 20707 | case 303: | |||
| 20708 | if (m_dxfCtxState != 2 || reader->getString() != "}") | |||
| 20709 | return false; | |||
| 20710 | m_dxfCtxState = 1; | |||
| 20711 | return true; | |||
| 20712 | case 304: | |||
| 20713 | if (m_dxfCtxState == 1) { | |||
| 20714 | context.textLabel = reader->getUtf8String(); | |||
| 20715 | return true; | |||
| 20716 | } | |||
| 20717 | if (m_dxfCtxState != 2 || reader->getString() != "LEADER_LINE{" | |||
| 20718 | || context.roots.empty() | |||
| 20719 | || context.roots.back().leaderLines.size() | |||
| 20720 | >= static_cast<std::size_t>(kMaxMLeaderItems)) | |||
| 20721 | return false; | |||
| 20722 | context.roots.back().leaderLines.emplace_back(); | |||
| 20723 | m_dxfCtxState = 3; | |||
| 20724 | return true; | |||
| 20725 | case 305: | |||
| 20726 | if (m_dxfCtxState != 3 || reader->getString() != "}") | |||
| 20727 | return false; | |||
| 20728 | m_dxfCtxState = 2; | |||
| 20729 | return true; | |||
| 20730 | default: break; | |||
| 20731 | } | |||
| 20732 | ||||
| 20733 | if (m_dxfCtxState == 0) | |||
| 20734 | return false; // entity level — parseCode handles it | |||
| 20735 | ||||
| 20736 | if (m_dxfCtxState == 3) { // LEADER_LINE{}: a polyline + overrides | |||
| 20737 | DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back(); | |||
| 20738 | DRW_MLeaderLeaderLine* line = | |||
| 20739 | (root && !root->leaderLines.empty()) ? &root->leaderLines.back() : nullptr; | |||
| 20740 | if (line) switch (code) { | |||
| 20741 | case 10: | |||
| 20742 | if (line->points.size() >= static_cast<std::size_t>(kMaxLeaderVertices)) | |||
| 20743 | return false; | |||
| 20744 | line->points.emplace_back(reader->getDouble(), 0.0, 0.0); | |||
| 20745 | return true; | |||
| 20746 | case 20: if (!line->points.empty()) line->points.back().y = reader->getDouble(); return true; | |||
| 20747 | case 30: if (!line->points.empty()) line->points.back().z = reader->getDouble(); return true; | |||
| 20748 | case 40: line->arrowSize = reader->getDouble(); return true; | |||
| 20749 | case 90: line->segmentIndex = reader->getInt32(); return true; | |||
| 20750 | case 91: line->leaderLineIndex = reader->getInt32(); return true; | |||
| 20751 | case 92: line->color = reader->getInt32(); return true; | |||
| 20752 | case 93: line->overrideFlags = reader->getInt32(); return true; | |||
| 20753 | case 170: line->leaderType = reader->getInt32(); return true; | |||
| 20754 | case 171: line->lineWeight = reader->getInt32(); return true; | |||
| 20755 | default: break; | |||
| 20756 | } | |||
| 20757 | return true; // swallow other line codes | |||
| 20758 | } | |||
| 20759 | ||||
| 20760 | if (m_dxfCtxState == 2) { // LEADER{}: one root attachment | |||
| 20761 | DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back(); | |||
| 20762 | if (root) switch (code) { | |||
| 20763 | case 290: root->isContentValid = (reader->getInt32() != 0); return true; | |||
| 20764 | case 291: root->unknown291 = (reader->getInt32() != 0); return true; | |||
| 20765 | case 10: root->connectionPoint.x = reader->getDouble(); return true; | |||
| 20766 | case 20: root->connectionPoint.y = reader->getDouble(); return true; | |||
| 20767 | case 30: root->connectionPoint.z = reader->getDouble(); return true; | |||
| 20768 | case 11: root->direction.x = reader->getDouble(); return true; | |||
| 20769 | case 21: root->direction.y = reader->getDouble(); return true; | |||
| 20770 | case 31: root->direction.z = reader->getDouble(); return true; | |||
| 20771 | case 90: root->leaderIndex = reader->getInt32(); return true; | |||
| 20772 | case 40: root->landingDistance = reader->getDouble(); return true; | |||
| 20773 | case 271: root->attachmentDirection = reader->getInt32(); return true; | |||
| 20774 | default: break; | |||
| 20775 | } | |||
| 20776 | return true; // swallow other leader codes | |||
| 20777 | } | |||
| 20778 | ||||
| 20779 | switch (code) { // m_dxfCtxState == 1: CONTEXT_DATA{} | |||
| 20780 | case 40: context.overallScale = reader->getDouble(); return true; | |||
| 20781 | case 10: context.contentBasePoint.x = reader->getDouble(); return true; | |||
| 20782 | case 20: context.contentBasePoint.y = reader->getDouble(); return true; | |||
| 20783 | case 30: context.contentBasePoint.z = reader->getDouble(); return true; | |||
| 20784 | case 41: context.textHeight = reader->getDouble(); return true; | |||
| 20785 | case 140: context.arrowHeadSize = reader->getDouble(); return true; | |||
| 20786 | case 145: context.landingGap = reader->getDouble(); return true; | |||
| 20787 | case 174: context.styleLeftAttach = reader->getInt32(); return true; | |||
| 20788 | case 175: context.styleRightAttach = reader->getInt32(); return true; | |||
| 20789 | case 176: context.textAlignType = reader->getInt32(); return true; | |||
| 20790 | case 177: context.attachmentType = reader->getInt32(); return true; | |||
| 20791 | case 290: context.hasTextContents = (reader->getInt32() != 0); return true; | |||
| 20792 | /* text-content branch */ | |||
| 20793 | case 11: context.textNormal.x = reader->getDouble(); return true; | |||
| 20794 | case 21: context.textNormal.y = reader->getDouble(); return true; | |||
| 20795 | case 31: context.textNormal.z = reader->getDouble(); return true; | |||
| 20796 | case 12: context.textLocation.x = reader->getDouble(); return true; | |||
| 20797 | case 22: context.textLocation.y = reader->getDouble(); return true; | |||
| 20798 | case 32: context.textLocation.z = reader->getDouble(); return true; | |||
| 20799 | case 13: context.textDirection.x = reader->getDouble(); return true; | |||
| 20800 | case 23: context.textDirection.y = reader->getDouble(); return true; | |||
| 20801 | case 33: context.textDirection.z = reader->getDouble(); return true; | |||
| 20802 | case 42: context.textRotation = reader->getDouble(); return true; | |||
| 20803 | case 43: context.boundaryWidth = reader->getDouble(); return true; | |||
| 20804 | case 44: context.boundaryHeight = reader->getDouble(); return true; | |||
| 20805 | case 45: context.lineSpacingFactor = reader->getDouble(); return true; | |||
| 20806 | case 170: context.lineSpacingStyle = reader->getInt32(); return true; | |||
| 20807 | case 90: context.textColor = reader->getInt32(); return true; | |||
| 20808 | case 171: context.alignment = reader->getInt32(); return true; | |||
| 20809 | case 172: context.flowDirection = reader->getInt32(); return true; | |||
| 20810 | case 91: context.bgFillColor = reader->getInt32(); return true; | |||
| 20811 | case 141: context.bgScaleFactor = reader->getDouble(); return true; | |||
| 20812 | case 92: context.bgTransparency = reader->getInt32(); return true; | |||
| 20813 | case 291: context.bgFillEnabled = (reader->getInt32() != 0); return true; | |||
| 20814 | case 292: context.bgMaskFillOn = (reader->getInt32() != 0); return true; | |||
| 20815 | case 173: context.columnType = reader->getInt32(); return true; | |||
| 20816 | case 293: context.textHeightAuto = (reader->getInt32() != 0); return true; | |||
| 20817 | case 142: context.columnWidth = reader->getDouble(); return true; | |||
| 20818 | case 143: context.columnGutter = reader->getDouble(); return true; | |||
| 20819 | case 294: context.columnFlowReversed = (reader->getInt32() != 0); return true; | |||
| 20820 | case 144: | |||
| 20821 | if (context.columnSizes.size() >= static_cast<std::size_t>(kMaxMLeaderItems)) | |||
| 20822 | return false; | |||
| 20823 | context.columnSizes.push_back(reader->getDouble()); | |||
| 20824 | return true; | |||
| 20825 | case 295: context.wordBreak = (reader->getInt32() != 0); return true; | |||
| 20826 | /* block-content branch */ | |||
| 20827 | case 296: context.hasContentsBlock = (reader->getInt32() != 0); return true; | |||
| 20828 | case 14: context.blockNormal.x = reader->getDouble(); return true; | |||
| 20829 | case 24: context.blockNormal.y = reader->getDouble(); return true; | |||
| 20830 | case 34: context.blockNormal.z = reader->getDouble(); return true; | |||
| 20831 | case 15: context.blockLocation.x = reader->getDouble(); return true; | |||
| 20832 | case 25: context.blockLocation.y = reader->getDouble(); return true; | |||
| 20833 | case 35: context.blockLocation.z = reader->getDouble(); return true; | |||
| 20834 | case 16: context.blockScale.x = reader->getDouble(); return true; | |||
| 20835 | case 26: context.blockScale.y = reader->getDouble(); return true; | |||
| 20836 | case 36: context.blockScale.z = reader->getDouble(); return true; | |||
| 20837 | case 46: context.blockRotation = reader->getDouble(); return true; | |||
| 20838 | case 93: context.blockColor = reader->getInt32(); return true; | |||
| 20839 | /* common tail */ | |||
| 20840 | case 110: case 120: case 130: | |||
| 20841 | case 111: case 121: case 131: | |||
| 20842 | case 112: case 122: case 132: | |||
| 20843 | // The helper answers true for every code in this set, so this | |||
| 20844 | // matches the nine `return true` arms it replaces. | |||
| 20845 | return readCoordTripletCode(code, reader, context.basePoint, | |||
| 20846 | context.baseDirection, | |||
| 20847 | context.baseVertical); | |||
| 20848 | case 297: context.isNormalReversed = (reader->getInt32() != 0); return true; | |||
| 20849 | case 272: context.styleBottomAttach = reader->getInt32(); return true; | |||
| 20850 | case 273: context.styleTopAttach = reader->getInt32(); return true; | |||
| 20851 | default: return true; // swallow any other context code | |||
| 20852 | } | |||
| 20853 | } catch (...) { | |||
| 20854 | return false; | |||
| 20855 | } | |||
| 20856 | } | |||
| 20857 | ||||
| 20858 | bool DRW_MLeader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 20859 | // The embedded CONTEXT_DATA{} block (§20.4.86) is routed by the nested-block | |||
| 20860 | // state machine; the remaining (entity-level) fields are read below and | |||
| 20861 | // mirror the DWG body parser. | |||
| 20862 | if (parseDxfContextCode(code, reader)) | |||
| 20863 | return true; | |||
| 20864 | // A failed nested parse must not fall through to the permissive base | |||
| 20865 | // parser: that would silently discard malformed controls or over-limit | |||
| 20866 | // collections and still publish the entity. | |||
| 20867 | if (m_dxfCtxState != 0 || (code >= 300 && code <= 305)) | |||
| 20868 | return false; | |||
| 20869 | switch (code) { | |||
| 20870 | case 170: leaderType = reader->getInt32(); break; | |||
| 20871 | case 171: leaderLineWeight = reader->getInt32(); break; | |||
| 20872 | case 172: styleContentType = reader->getInt32(); break; | |||
| 20873 | case 173: styleLeftAttach = reader->getInt32(); break; | |||
| 20874 | case 95: styleRightAttach = reader->getInt32(); break; | |||
| 20875 | case 174: styleTextAngleType = reader->getInt32(); break; | |||
| 20876 | case 175: unknown175 = reader->getInt32(); break; | |||
| 20877 | case 176: styleAttachmentType = reader->getInt32(); break; | |||
| 20878 | case 178: ipeAlign = reader->getInt32(); break; | |||
| 20879 | case 179: justification = reader->getInt32(); break; | |||
| 20880 | case 271: attachmentDirection = reader->getInt32(); break; | |||
| 20881 | case 272: styleBottomAttach = reader->getInt32(); break; | |||
| 20882 | case 273: styleTopAttach = reader->getInt32(); break; | |||
| 20883 | case 90: overrideFlags = reader->getInt32(); break; | |||
| 20884 | case 91: leaderColor = reader->getInt32(); break; | |||
| 20885 | case 92: styleTextColor = reader->getInt32(); break; | |||
| 20886 | case 93: styleBlockColor = reader->getInt32(); break; | |||
| 20887 | case 41: landingDistance = reader->getDouble(); break; | |||
| 20888 | case 42: defaultArrowHeadSize = reader->getDouble(); break; | |||
| 20889 | case 43: styleBlockRotation = reader->getDouble(); break; | |||
| 20890 | case 45: scaleFactor = reader->getDouble(); break; | |||
| 20891 | case 290: landingEnabled = (reader->getInt32() != 0); break; | |||
| 20892 | case 291: doglegEnabled = (reader->getInt32() != 0); break; | |||
| 20893 | case 292: styleTextFrameEnabled = (reader->getInt32() != 0); break; | |||
| 20894 | case 293: isAnnotative = (reader->getInt32() != 0); break; | |||
| 20895 | case 294: isTextDirectionNegative = (reader->getInt32() != 0); break; | |||
| 20896 | case 295: leaderExtendedToText = (reader->getInt32() != 0); break; | |||
| 20897 | default: | |||
| 20898 | return DRW_Entity::parseCode(code, reader); | |||
| 20899 | } | |||
| 20900 | return true; | |||
| 20901 | } | |||
| 20902 | ||||
| 20903 | // Helper: parse one AcDbMLeaderObjectContextData::LeaderRoot entry (§20.4.86). | |||
| 20904 | // | |||
| 20905 | // Each root has: connection point + direction, optional break pairs, leader | |||
| 20906 | // index, landing distance, then a count-and-list of leader lines. Lines | |||
| 20907 | // themselves carry: point list, break-info pairs, and (R2010+) per-line | |||
| 20908 | // style overrides. The handles inside (line-type / arrow per leader line) | |||
| 20909 | // are deferred to the entity-level handle stream and not stored here. | |||
| 20910 | static bool parseMLeaderRoot(DRW::Version version, dwgBuffer *buf, | |||
| 20911 | std::uint32_t objectSize, | |||
| 20912 | std::uint64_t bodyEndBit, | |||
| 20913 | DRW_MLeaderRoot& root) { | |||
| 20914 | // Layout per libreDWG dwg2.spec:1316-1366 (Dwg_LEADER_Node + Dwg_LEADER_Line). | |||
| 20915 | // The two 3BD coords at the head of the node are conditional on the | |||
| 20916 | // preceding B flags; reading them unconditionally drifts the bit stream | |||
| 20917 | // when either flag is 0. | |||
| 20918 | bool hasLastPt = false; | |||
| 20919 | bool hasDogleg = false; | |||
| 20920 | if (!readBoundedBit(*buf, bodyEndBit, hasLastPt) | |||
| 20921 | || !readBoundedBit(*buf, bodyEndBit, hasDogleg)) | |||
| 20922 | return false; // 290 has_lastleaderlinepoint, 291 has_dogleg | |||
| 20923 | root.isContentValid = hasLastPt; | |||
| 20924 | root.unknown291 = hasDogleg; | |||
| 20925 | if (hasLastPt) { | |||
| 20926 | if (!readBoundedBitCoord(*buf, bodyEndBit, root.connectionPoint)) | |||
| 20927 | return false; | |||
| 20928 | } | |||
| 20929 | if (hasDogleg) { | |||
| 20930 | if (!readBoundedBitCoord(*buf, bodyEndBit, root.direction)) | |||
| 20931 | return false; | |||
| 20932 | } | |||
| 20933 | ||||
| 20934 | std::uint32_t nBreaks = 0; | |||
| 20935 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 12, | |||
| 20936 | nBreaks)) | |||
| 20937 | return false; | |||
| 20938 | if (!DRW::reserve(root.breaks, static_cast<int>(nBreaks))) | |||
| 20939 | return false; | |||
| 20940 | for (std::uint32_t i = 0; i < nBreaks; ++i) { | |||
| 20941 | DRW_Coord a; | |||
| 20942 | DRW_Coord b; | |||
| 20943 | if (!readBoundedBitCoord(*buf, bodyEndBit, a) | |||
| 20944 | || !readBoundedBitCoord(*buf, bodyEndBit, b)) | |||
| 20945 | return false; | |||
| 20946 | root.breaks.emplace_back(a, b); | |||
| 20947 | } | |||
| 20948 | ||||
| 20949 | if (!readBoundedBitLong(*buf, bodyEndBit, root.leaderIndex) | |||
| 20950 | || !readBoundedBitDouble(*buf, bodyEndBit, root.landingDistance)) | |||
| 20951 | return false; | |||
| 20952 | ||||
| 20953 | std::uint32_t nLines = 0; | |||
| 20954 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 6, | |||
| 20955 | nLines)) | |||
| 20956 | return false; | |||
| 20957 | if (!DRW::reserve(root.leaderLines, static_cast<int>(nLines))) | |||
| 20958 | return false; | |||
| 20959 | for (std::uint32_t i = 0; i < nLines; ++i) { | |||
| 20960 | DRW_MLeaderLeaderLine line; | |||
| 20961 | // Per libreDWG: BL num_points, points, BL num_breaks, breaks, BL line_index. | |||
| 20962 | // The previous 5-BL layout (brkInfoCount + segmentIndex + nPairs + | |||
| 20963 | // pairs + leaderLineIndex) inserted two spurious BL reads, drifting | |||
| 20964 | // every subsequent entity-level field (overallScale, contentType, …). | |||
| 20965 | std::uint32_t nPts = 0; | |||
| 20966 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 6, | |||
| 20967 | nPts)) | |||
| 20968 | return false; | |||
| 20969 | if (!DRW::reserve(line.points, static_cast<int>(nPts))) | |||
| 20970 | return false; | |||
| 20971 | for (std::uint32_t j = 0; j < nPts; ++j) { | |||
| 20972 | DRW_Coord point; | |||
| 20973 | if (!readBoundedBitCoord(*buf, bodyEndBit, point)) | |||
| 20974 | return false; | |||
| 20975 | line.points.push_back(point); | |||
| 20976 | } | |||
| 20977 | std::uint32_t nLineBreaks = 0; | |||
| 20978 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, | |||
| 20979 | 12, nLineBreaks)) | |||
| 20980 | return false; | |||
| 20981 | for (std::uint32_t j = 0; j < nLineBreaks; ++j) { | |||
| 20982 | DRW_Coord a; | |||
| 20983 | DRW_Coord b; | |||
| 20984 | if (!readBoundedBitCoord(*buf, bodyEndBit, a) | |||
| 20985 | || !readBoundedBitCoord(*buf, bodyEndBit, b)) | |||
| 20986 | return false; | |||
| 20987 | line.breaks.emplace_back(a, b); | |||
| 20988 | } | |||
| 20989 | if (!readBoundedBitLong(*buf, bodyEndBit, line.leaderLineIndex)) | |||
| 20990 | return false; | |||
| 20991 | ||||
| 20992 | // R2010+ per-line override block. The spec marks this block "R2010" | |||
| 20993 | // (§20.4.86 page 215); the override flags BL 93 says which fields | |||
| 20994 | // were overridden. The handle fields (340 line-type, 341 arrow) are | |||
| 20995 | // deferred to the trailing handle stream. | |||
| 20996 | if (version >= DRW::AC1024) { | |||
| 20997 | if (!readBoundedBitShort(*buf, bodyEndBit, line.leaderType)) | |||
| 20998 | return false; | |||
| 20999 | std::uint32_t parsedColor = 0; | |||
| 21000 | if (!readBoundedCmColor(*buf, nullptr, bodyEndBit, version, | |||
| 21001 | parsedColor)) | |||
| 21002 | return false; | |||
| 21003 | line.color = static_cast<int>(parsedColor); | |||
| 21004 | // line type handle 340 — read from handles section later | |||
| 21005 | if (!readBoundedBitLong(*buf, bodyEndBit, line.lineWeight) | |||
| 21006 | || !readBoundedBitDouble(*buf, bodyEndBit, line.arrowSize) | |||
| 21007 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 21008 | line.overrideFlags)) | |||
| 21009 | return false; | |||
| 21010 | // arrow handle 341 — handles section | |||
| 21011 | } | |||
| 21012 | root.leaderLines.push_back(std::move(line)); | |||
| 21013 | } | |||
| 21014 | ||||
| 21015 | if (version >= DRW::AC1024) { | |||
| 21016 | if (!readBoundedBitShort(*buf, bodyEndBit, root.attachmentDirection)) | |||
| 21017 | return false; | |||
| 21018 | } | |||
| 21019 | ||||
| 21020 | return buf->isGood(); | |||
| 21021 | } | |||
| 21022 | ||||
| 21023 | // Helper: parse the AcDbMLeaderObjectContextData (§20.4.86) payload, the | |||
| 21024 | // large embedded block at the start of the MLEADER body that carries the | |||
| 21025 | // leader geometry plus either text or block content. | |||
| 21026 | static bool parseMLeaderAnnotContext(DRW::Version version, dwgBuffer *buf, | |||
| 21027 | dwgBuffer *sBuf, | |||
| 21028 | std::uint32_t objectSize, | |||
| 21029 | std::uint64_t bodyEndBit, | |||
| 21030 | std::uint64_t stringEndBit, | |||
| 21031 | DRW_MLeaderAnnotContext& ctx) { | |||
| 21032 | // NOTE: when AcDbMLeaderObjectContextData is embedded INSIDE the MLEADER | |||
| 21033 | // entity body (rather than serialized as a standalone object), the | |||
| 21034 | // AcDbObjectContextData base preamble (BS version, B has-file-ext-dict, | |||
| 21035 | // B default-flag) does NOT appear in the bit stream — those fields are | |||
| 21036 | // standalone-object metadata. The embedded AnnotContext starts directly | |||
| 21037 | // with the leader-roots count. Its standalone-object scale handle is | |||
| 21038 | // likewise absent from this embedded payload. | |||
| 21039 | ||||
| 21040 | // Number of leader roots. | |||
| 21041 | std::int32_t nRoots = 0; | |||
| 21042 | if (!readBoundedBitLong(*buf, bodyEndBit, nRoots)) | |||
| 21043 | return false; | |||
| 21044 | if (nRoots == 0) { | |||
| 21045 | if (!proxyEntityHasBits(*buf, bodyEndBit, 7)) | |||
| 21046 | return false; | |||
| 21047 | bool rootCountBits[7] = {}; | |||
| 21048 | for (bool& rootCountBit : rootCountBits) { | |||
| 21049 | if (!readBoundedBit(*buf, bodyEndBit, rootCountBit)) | |||
| 21050 | return false; | |||
| 21051 | } | |||
| 21052 | nRoots = rootCountBits[5] ? 2 : 1; | |||
| 21053 | } | |||
| 21054 | if (!isValidCount(nRoots, kMaxMLeaderItems)) return false; | |||
| 21055 | std::uint64_t minimumRootBits = 0; | |||
| 21056 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(nRoots), 10, | |||
| 21057 | minimumRootBits) | |||
| 21058 | || !proxyEntityHasBits(*buf, bodyEndBit, minimumRootBits)) { | |||
| 21059 | return false; | |||
| 21060 | } | |||
| 21061 | ctx.roots.clear(); | |||
| 21062 | if (!DRW::reserve(ctx.roots, nRoots)) | |||
| 21063 | return false; | |||
| 21064 | for (std::int32_t i = 0; i < nRoots; ++i) { | |||
| 21065 | DRW_MLeaderRoot root; | |||
| 21066 | if (!parseMLeaderRoot(version, buf, objectSize, bodyEndBit, root)) | |||
| 21067 | return false; | |||
| 21068 | ctx.roots.push_back(std::move(root)); | |||
| 21069 | } | |||
| 21070 | ||||
| 21071 | // Common content fields. | |||
| 21072 | if (!readBoundedBitDouble(*buf, bodyEndBit, ctx.overallScale) | |||
| 21073 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.contentBasePoint) | |||
| 21074 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.textHeight) | |||
| 21075 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.arrowHeadSize) | |||
| 21076 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.landingGap) | |||
| 21077 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.styleLeftAttach) | |||
| 21078 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.styleRightAttach) | |||
| 21079 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.textAlignType) | |||
| 21080 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.attachmentType) | |||
| 21081 | || !readBoundedBit(*buf, bodyEndBit, ctx.hasTextContents)) | |||
| 21082 | return false; | |||
| 21083 | ||||
| 21084 | if (ctx.hasTextContents) { | |||
| 21085 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 21086 | ctx.textLabel)) | |||
| 21087 | return false; | |||
| 21088 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.textNormal)) | |||
| 21089 | return false; | |||
| 21090 | // text style handle 340 — handles section | |||
| 21091 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.textLocation) | |||
| 21092 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.textDirection) | |||
| 21093 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.textRotation) | |||
| 21094 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.boundaryWidth) | |||
| 21095 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.boundaryHeight) | |||
| 21096 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 21097 | ctx.lineSpacingFactor) | |||
| 21098 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.lineSpacingStyle)) | |||
| 21099 | return false; | |||
| 21100 | std::uint32_t parsedTextColor = 0; | |||
| 21101 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 21102 | parsedTextColor, nullptr, nullptr, nullptr, | |||
| 21103 | nullptr, stringEndBit)) | |||
| 21104 | return false; | |||
| 21105 | ctx.textColor = static_cast<int>(parsedTextColor); | |||
| 21106 | if (!readBoundedBitShort(*buf, bodyEndBit, ctx.alignment) | |||
| 21107 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.flowDirection)) | |||
| 21108 | return false; | |||
| 21109 | std::uint32_t parsedBgFillColor = 0; | |||
| 21110 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 21111 | parsedBgFillColor, nullptr, nullptr, nullptr, | |||
| 21112 | nullptr, stringEndBit)) | |||
| 21113 | return false; | |||
| 21114 | ctx.bgFillColor = static_cast<int>(parsedBgFillColor); | |||
| 21115 | if (!readBoundedBitDouble(*buf, bodyEndBit, ctx.bgScaleFactor) | |||
| 21116 | || !readBoundedBitLong(*buf, bodyEndBit, ctx.bgTransparency) | |||
| 21117 | || !readBoundedBit(*buf, bodyEndBit, ctx.bgFillEnabled) | |||
| 21118 | || !readBoundedBit(*buf, bodyEndBit, ctx.bgMaskFillOn) | |||
| 21119 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.columnType) | |||
| 21120 | || !readBoundedBit(*buf, bodyEndBit, ctx.textHeightAuto) | |||
| 21121 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.columnWidth) | |||
| 21122 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.columnGutter) | |||
| 21123 | || !readBoundedBit(*buf, bodyEndBit, ctx.columnFlowReversed)) | |||
| 21124 | return false; | |||
| 21125 | std::uint32_t nColSizes = 0; | |||
| 21126 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 2, | |||
| 21127 | nColSizes)) | |||
| 21128 | return false; | |||
| 21129 | if (!DRW::reserve(ctx.columnSizes, static_cast<int>(nColSizes))) | |||
| 21130 | return false; | |||
| 21131 | for (std::uint32_t i = 0; i < nColSizes; ++i) { | |||
| 21132 | double columnSize = 0.0; | |||
| 21133 | if (!readBoundedBitDouble(*buf, bodyEndBit, columnSize)) | |||
| 21134 | return false; | |||
| 21135 | ctx.columnSizes.push_back(columnSize); | |||
| 21136 | } | |||
| 21137 | bool ignoredBit = false; | |||
| 21138 | if (!readBoundedBit(*buf, bodyEndBit, ctx.wordBreak) | |||
| 21139 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit)) | |||
| 21140 | return false; // unknown trailing bit | |||
| 21141 | } else { | |||
| 21142 | if (!readBoundedBit(*buf, bodyEndBit, ctx.hasContentsBlock)) | |||
| 21143 | return false; | |||
| 21144 | if (ctx.hasContentsBlock) { | |||
| 21145 | // BlockTableRecord handle 341 — deferred | |||
| 21146 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.blockNormal) | |||
| 21147 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.blockLocation) | |||
| 21148 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.blockScale) | |||
| 21149 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 21150 | ctx.blockRotation)) | |||
| 21151 | return false; | |||
| 21152 | std::uint32_t parsedBlockColor = 0; | |||
| 21153 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 21154 | parsedBlockColor, nullptr, nullptr, nullptr, | |||
| 21155 | nullptr, stringEndBit)) | |||
| 21156 | return false; | |||
| 21157 | ctx.blockColor = static_cast<int>(parsedBlockColor); | |||
| 21158 | for (size_t i = 0; i < 16; ++i) { | |||
| 21159 | if (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 21160 | ctx.blockTransform[i])) | |||
| 21161 | return false; | |||
| 21162 | } | |||
| 21163 | } | |||
| 21164 | } | |||
| 21165 | ||||
| 21166 | // Common tail. | |||
| 21167 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.basePoint) | |||
| 21168 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.baseDirection) | |||
| 21169 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.baseVertical) | |||
| 21170 | || !readBoundedBit(*buf, bodyEndBit, ctx.isNormalReversed)) | |||
| 21171 | return false; | |||
| 21172 | ||||
| 21173 | if (version >= DRW::AC1024) { | |||
| 21174 | if (!readBoundedBitShort(*buf, bodyEndBit, ctx.styleTopAttach) | |||
| 21175 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.styleBottomAttach)) | |||
| 21176 | return false; | |||
| 21177 | } | |||
| 21178 | ||||
| 21179 | return buf->isGood() && sBuf->isGood(); | |||
| 21180 | } | |||
| 21181 | ||||
| 21182 | static bool encodeMLeaderRoot(DRW::Version version, dwgBufferW *buf, | |||
| 21183 | const DRW_MLeaderRoot& root) { | |||
| 21184 | if (root.breaks.size() > DRW_MLeader::kMaxLeaderPoints | |||
| 21185 | || root.leaderLines.size() > DRW_MLeader::kMaxLeaderLines) | |||
| 21186 | return false; | |||
| 21187 | ||||
| 21188 | buf->putBit(root.isContentValid ? 1 : 0); | |||
| 21189 | buf->putBit(root.unknown291 ? 1 : 0); | |||
| 21190 | if (root.isContentValid) | |||
| 21191 | buf->put3BitDouble(root.connectionPoint); | |||
| 21192 | if (root.unknown291) | |||
| 21193 | buf->put3BitDouble(root.direction); | |||
| 21194 | ||||
| 21195 | buf->putBitLong(static_cast<std::int32_t>(root.breaks.size())); | |||
| 21196 | for (const auto& brk : root.breaks) { | |||
| 21197 | buf->put3BitDouble(brk.first); | |||
| 21198 | buf->put3BitDouble(brk.second); | |||
| 21199 | } | |||
| 21200 | ||||
| 21201 | buf->putBitLong(root.leaderIndex); | |||
| 21202 | buf->putBitDouble(root.landingDistance); | |||
| 21203 | ||||
| 21204 | buf->putBitLong(static_cast<std::int32_t>(root.leaderLines.size())); | |||
| 21205 | for (const DRW_MLeaderLeaderLine& line : root.leaderLines) { | |||
| 21206 | if (line.points.size() > DRW_MLeader::kMaxLeaderPoints | |||
| 21207 | || line.breaks.size() > DRW_MLeader::kMaxLeaderPoints) | |||
| 21208 | return false; | |||
| 21209 | buf->putBitLong(static_cast<std::int32_t>(line.points.size())); | |||
| 21210 | for (const DRW_Coord& point : line.points) | |||
| 21211 | buf->put3BitDouble(point); | |||
| 21212 | ||||
| 21213 | buf->putBitLong(static_cast<std::int32_t>(line.breaks.size())); | |||
| 21214 | for (const auto& brk : line.breaks) { | |||
| 21215 | buf->put3BitDouble(brk.first); | |||
| 21216 | buf->put3BitDouble(brk.second); | |||
| 21217 | } | |||
| 21218 | buf->putBitLong(line.leaderLineIndex); | |||
| 21219 | ||||
| 21220 | if (version >= DRW::AC1024) { | |||
| 21221 | buf->putBitShort(line.leaderType); | |||
| 21222 | buf->putCmColor(version, static_cast<std::uint16_t>(line.color)); | |||
| 21223 | buf->putBitLong(line.lineWeight); | |||
| 21224 | buf->putBitDouble(line.arrowSize); | |||
| 21225 | buf->putBitLong(line.overrideFlags); | |||
| 21226 | } | |||
| 21227 | } | |||
| 21228 | ||||
| 21229 | if (version >= DRW::AC1024) | |||
| 21230 | buf->putBitShort(root.attachmentDirection); | |||
| 21231 | ||||
| 21232 | return true; | |||
| 21233 | } | |||
| 21234 | ||||
| 21235 | static bool encodeMLeaderAnnotContext(DRW::Version version, dwgBufferW *buf, | |||
| 21236 | dwgBufferW *strBuf, | |||
| 21237 | const DRW_MLeaderAnnotContext& ctx) { | |||
| 21238 | if (ctx.roots.size() > DRW_MLeader::kMaxRoots | |||
| 21239 | || ctx.columnSizes.size() > DRW_MLeader::kMaxLeaderPoints) | |||
| 21240 | return false; | |||
| 21241 | if (ctx.hasContentsBlock) | |||
| 21242 | return false; | |||
| 21243 | ||||
| 21244 | buf->putBitLong(static_cast<std::int32_t>(ctx.roots.size())); | |||
| 21245 | for (const DRW_MLeaderRoot& root : ctx.roots) { | |||
| 21246 | if (!encodeMLeaderRoot(version, buf, root)) | |||
| 21247 | return false; | |||
| 21248 | } | |||
| 21249 | ||||
| 21250 | buf->putBitDouble(ctx.overallScale); | |||
| 21251 | buf->put3BitDouble(ctx.contentBasePoint); | |||
| 21252 | buf->putBitDouble(ctx.textHeight); | |||
| 21253 | buf->putBitDouble(ctx.arrowHeadSize); | |||
| 21254 | buf->putBitDouble(ctx.landingGap); | |||
| 21255 | buf->putBitShort(ctx.styleLeftAttach); | |||
| 21256 | buf->putBitShort(ctx.styleRightAttach); | |||
| 21257 | buf->putBitShort(ctx.textAlignType); | |||
| 21258 | buf->putBitShort(ctx.attachmentType); | |||
| 21259 | buf->putBit(ctx.hasTextContents ? 1 : 0); | |||
| 21260 | ||||
| 21261 | if (ctx.hasTextContents) { | |||
| 21262 | (strBuf ? strBuf : buf)->putVariableText(version, ctx.textLabel); | |||
| 21263 | buf->put3BitDouble(ctx.textNormal); | |||
| 21264 | buf->put3BitDouble(ctx.textLocation); | |||
| 21265 | buf->put3BitDouble(ctx.textDirection); | |||
| 21266 | buf->putBitDouble(ctx.textRotation); | |||
| 21267 | buf->putBitDouble(ctx.boundaryWidth); | |||
| 21268 | buf->putBitDouble(ctx.boundaryHeight); | |||
| 21269 | buf->putBitDouble(ctx.lineSpacingFactor); | |||
| 21270 | buf->putBitShort(ctx.lineSpacingStyle); | |||
| 21271 | buf->putCmColor(version, static_cast<std::uint16_t>(ctx.textColor)); | |||
| 21272 | buf->putBitShort(ctx.alignment); | |||
| 21273 | buf->putBitShort(ctx.flowDirection); | |||
| 21274 | buf->putCmColor(version, static_cast<std::uint16_t>(ctx.bgFillColor)); | |||
| 21275 | buf->putBitDouble(ctx.bgScaleFactor); | |||
| 21276 | buf->putBitLong(ctx.bgTransparency); | |||
| 21277 | buf->putBit(ctx.bgFillEnabled ? 1 : 0); | |||
| 21278 | buf->putBit(ctx.bgMaskFillOn ? 1 : 0); | |||
| 21279 | buf->putBitShort(ctx.columnType); | |||
| 21280 | buf->putBit(ctx.textHeightAuto ? 1 : 0); | |||
| 21281 | buf->putBitDouble(ctx.columnWidth); | |||
| 21282 | buf->putBitDouble(ctx.columnGutter); | |||
| 21283 | buf->putBit(ctx.columnFlowReversed ? 1 : 0); | |||
| 21284 | buf->putBitLong(static_cast<std::int32_t>(ctx.columnSizes.size())); | |||
| 21285 | for (double columnSize : ctx.columnSizes) | |||
| 21286 | buf->putBitDouble(columnSize); | |||
| 21287 | buf->putBit(ctx.wordBreak ? 1 : 0); | |||
| 21288 | buf->putBit(0); | |||
| 21289 | } else { | |||
| 21290 | buf->putBit(0); // hasContentsBlock | |||
| 21291 | } | |||
| 21292 | ||||
| 21293 | buf->put3BitDouble(ctx.basePoint); | |||
| 21294 | buf->put3BitDouble(ctx.baseDirection); | |||
| 21295 | buf->put3BitDouble(ctx.baseVertical); | |||
| 21296 | buf->putBit(ctx.isNormalReversed ? 1 : 0); | |||
| 21297 | ||||
| 21298 | if (version >= DRW::AC1024) { | |||
| 21299 | buf->putBitShort(ctx.styleTopAttach); | |||
| 21300 | buf->putBitShort(ctx.styleBottomAttach); | |||
| 21301 | } | |||
| 21302 | ||||
| 21303 | return true; | |||
| 21304 | } | |||
| 21305 | ||||
| 21306 | void DRW_MLeader::resetDwgState() { | |||
| 21307 | DRW_Entity::reset(); | |||
| 21308 | context = DRW_MLeaderAnnotContext{}; | |||
| 21309 | classVersion = 2; | |||
| 21310 | styleHandle = dwgHandle{}; | |||
| 21311 | overrideFlags = 0; | |||
| 21312 | leaderType = 1; | |||
| 21313 | leaderColor = 0; | |||
| 21314 | leaderLineTypeHandle = dwgHandle{}; | |||
| 21315 | leaderLineWeight = 0; | |||
| 21316 | landingEnabled = true; | |||
| 21317 | doglegEnabled = true; | |||
| 21318 | landingDistance = 0.0; | |||
| 21319 | arrowHeadHandle = dwgHandle{}; | |||
| 21320 | defaultArrowHeadSize = 0.0; | |||
| 21321 | styleContentType = 2; | |||
| 21322 | styleTextStyleHandle = dwgHandle{}; | |||
| 21323 | styleLeftAttach = 0; | |||
| 21324 | styleRightAttach = 0; | |||
| 21325 | styleTextAngleType = 0; | |||
| 21326 | unknown175 = 0; | |||
| 21327 | styleTextColor = 0; | |||
| 21328 | styleTextFrameEnabled = false; | |||
| 21329 | styleBlockHandle = dwgHandle{}; | |||
| 21330 | styleBlockColor = 0; | |||
| 21331 | styleBlockScale = DRW_Coord{1.0, 1.0, 1.0}; | |||
| 21332 | styleBlockRotation = 0.0; | |||
| 21333 | styleAttachmentType = 0; | |||
| 21334 | isAnnotative = false; | |||
| 21335 | arrowHeads.clear(); | |||
| 21336 | blockLabels.clear(); | |||
| 21337 | isTextDirectionNegative = false; | |||
| 21338 | ipeAlign = 0; | |||
| 21339 | justification = 0; | |||
| 21340 | scaleFactor = 1.0; | |||
| 21341 | attachmentDirection = 0; | |||
| 21342 | styleTopAttach = 0; | |||
| 21343 | styleBottomAttach = 0; | |||
| 21344 | leaderExtendedToText = false; | |||
| 21345 | m_dxfCtxState = 0; | |||
| 21346 | } | |||
| 21347 | ||||
| 21348 | bool DRW_MLeader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 21349 | resetDwgState(); | |||
| 21350 | dwgBuffer *sourceBuf = buf; | |||
| 21351 | auto fail = [this, sourceBuf]() { | |||
| 21352 | if (sourceBuf != nullptr) | |||
| 21353 | sourceBuf->invalidate(); | |||
| 21354 | resetDwgState(); | |||
| 21355 | return false; | |||
| 21356 | }; | |||
| 21357 | if (sourceBuf == nullptr) | |||
| 21358 | return fail(); | |||
| 21359 | ||||
| 21360 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 21361 | buf = &bodyProbe; | |||
| 21362 | ||||
| 21363 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 21364 | dwgBuffer *sBuf = buf; | |||
| 21365 | if (version > DRW::AC1018) { // 2007+ | |||
| 21366 | sBuf = &sBuff; | |||
| 21367 | } | |||
| 21368 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 21369 | if (!ret) return fail(); | |||
| 21370 | DRW_DBG("\n***************************** parsing MLEADER ***************\n")DRW_dbg::dbg("\n***************************** parsing MLEADER ***************\n" ); | |||
| 21371 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 21372 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 21373 | if (version > DRW::AC1021) { | |||
| 21374 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 21375 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 21376 | ignoredBodyEndBit, &stringEndBit)) | |||
| 21377 | return fail(); | |||
| 21378 | } | |||
| 21379 | ||||
| 21380 | // R2010b+ class version (BS, default 2; <=R2004 was 1). libreDWG | |||
| 21381 | // dwg2.spec:1303-1306. Absent in R2007 streams; reading it would drift. | |||
| 21382 | if (version >= DRW::AC1024) { | |||
| 21383 | if (!readBoundedBitShort(*buf, bodyEndBit, classVersion)) | |||
| 21384 | return fail(); | |||
| 21385 | if (classVersion > 10) { | |||
| 21386 | DRW_DBG("\nMLEADER: implausible classVersion=")DRW_dbg::dbg("\nMLEADER: implausible classVersion="); | |||
| 21387 | DRW_DBG(static_cast<int>(classVersion))DRW_dbg::dbg(static_cast<int>(classVersion)); | |||
| 21388 | DRW_DBG(", aborting body\n")DRW_dbg::dbg(", aborting body\n"); | |||
| 21389 | return fail(); | |||
| 21390 | } | |||
| 21391 | } | |||
| 21392 | ||||
| 21393 | // Phase 4 — embedded AcDbMLeaderObjectContextData / MLeaderAnnotContext. | |||
| 21394 | if (!parseMLeaderAnnotContext(version, buf, sBuf, objSize, bodyEndBit, | |||
| 21395 | stringEndBit, context)) { | |||
| 21396 | DRW_DBG("\nMLEADER: AnnotContext parse failed\n")DRW_dbg::dbg("\nMLEADER: AnnotContext parse failed\n"); | |||
| 21397 | return fail(); | |||
| 21398 | } | |||
| 21399 | ||||
| 21400 | // Phase 3 — entity-level fields per §20.4.48 (after the AnnotContext). | |||
| 21401 | // Many handle slots are deferred to the trailing handle stream and not | |||
| 21402 | // stored here yet (resolution comes in Phase 7). | |||
| 21403 | if (!readBoundedBitLong(*buf, bodyEndBit, overrideFlags) | |||
| 21404 | || !readBoundedBitShort(*buf, bodyEndBit, leaderType)) | |||
| 21405 | return fail(); | |||
| 21406 | std::uint32_t parsedColor = 0; | |||
| 21407 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, parsedColor, | |||
| 21408 | nullptr, nullptr, nullptr, nullptr, | |||
| 21409 | stringEndBit)) | |||
| 21410 | return fail(); | |||
| 21411 | leaderColor = static_cast<int>(parsedColor); | |||
| 21412 | // leader line type handle 341 — handle stream | |||
| 21413 | if (!readBoundedBitLong(*buf, bodyEndBit, leaderLineWeight) | |||
| 21414 | || !readBoundedBit(*buf, bodyEndBit, landingEnabled) | |||
| 21415 | || !readBoundedBit(*buf, bodyEndBit, doglegEnabled) | |||
| 21416 | || !readBoundedBitDouble(*buf, bodyEndBit, landingDistance)) | |||
| 21417 | return fail(); | |||
| 21418 | // arrow head handle 342 — handle stream | |||
| 21419 | if (!readBoundedBitDouble(*buf, bodyEndBit, defaultArrowHeadSize) | |||
| 21420 | || !readBoundedBitShort(*buf, bodyEndBit, styleContentType)) | |||
| 21421 | return fail(); | |||
| 21422 | // text style handle 343 — handle stream | |||
| 21423 | if (!readBoundedBitShort(*buf, bodyEndBit, styleLeftAttach) | |||
| 21424 | || !readBoundedBitShort(*buf, bodyEndBit, styleRightAttach) | |||
| 21425 | || !readBoundedBitShort(*buf, bodyEndBit, styleTextAngleType) | |||
| 21426 | || !readBoundedBitShort(*buf, bodyEndBit, unknown175)) | |||
| 21427 | return fail(); | |||
| 21428 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, parsedColor, | |||
| 21429 | nullptr, nullptr, nullptr, nullptr, | |||
| 21430 | stringEndBit)) | |||
| 21431 | return fail(); | |||
| 21432 | styleTextColor = static_cast<int>(parsedColor); | |||
| 21433 | if (!readBoundedBit(*buf, bodyEndBit, styleTextFrameEnabled)) | |||
| 21434 | return fail(); | |||
| 21435 | // style block handle 344 — handle stream (optional) | |||
| 21436 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, parsedColor, | |||
| 21437 | nullptr, nullptr, nullptr, nullptr, | |||
| 21438 | stringEndBit)) | |||
| 21439 | return fail(); | |||
| 21440 | styleBlockColor = static_cast<int>(parsedColor); | |||
| 21441 | if (!readBoundedBitCoord(*buf, bodyEndBit, styleBlockScale) | |||
| 21442 | || !readBoundedBitDouble(*buf, bodyEndBit, styleBlockRotation) | |||
| 21443 | || !readBoundedBitShort(*buf, bodyEndBit, styleAttachmentType) | |||
| 21444 | || !readBoundedBit(*buf, bodyEndBit, isAnnotative)) | |||
| 21445 | return fail(); | |||
| 21446 | ||||
| 21447 | // R2007 arrays (pre-R2010 only): per spec §20.4.48. Bounds-check the | |||
| 21448 | // counts; a misaligned bit stream would produce huge nonsense values. | |||
| 21449 | if (version < DRW::AC1024) { | |||
| 21450 | std::uint32_t nArrows = 0; | |||
| 21451 | if (!readTableBodyCount(version, buf, objSize, kMaxMLeaderItems, 1, | |||
| 21452 | nArrows)) | |||
| 21453 | return fail(); | |||
| 21454 | if (!DRW::reserve(arrowHeads, static_cast<int>(nArrows))) | |||
| 21455 | return fail(); | |||
| 21456 | for (std::uint32_t i = 0; i < nArrows; ++i) { | |||
| 21457 | ArrowHeadEntry e; | |||
| 21458 | if (!readBoundedBit(*buf, bodyEndBit, e.isDefault)) | |||
| 21459 | return fail(); | |||
| 21460 | arrowHeads.push_back(e); | |||
| 21461 | } | |||
| 21462 | std::uint32_t nLabels = 0; | |||
| 21463 | if (!readTableBodyCount(version, buf, objSize, kMaxMLeaderItems, 4, | |||
| 21464 | nLabels)) | |||
| 21465 | return fail(); | |||
| 21466 | if (!DRW::reserve(blockLabels, static_cast<int>(nLabels))) | |||
| 21467 | return fail(); | |||
| 21468 | for (std::uint32_t i = 0; i < nLabels; ++i) { | |||
| 21469 | BlockLabelEntry e; | |||
| 21470 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 21471 | e.labelText)) | |||
| 21472 | return fail(); | |||
| 21473 | if (!readBoundedBitShort(*buf, bodyEndBit, e.uiIndex) | |||
| 21474 | || !readBoundedBitDouble(*buf, bodyEndBit, e.width)) | |||
| 21475 | return fail(); | |||
| 21476 | blockLabels.push_back(std::move(e)); | |||
| 21477 | } | |||
| 21478 | if (!readBoundedBit(*buf, bodyEndBit, isTextDirectionNegative) | |||
| 21479 | || !readBoundedBitShort(*buf, bodyEndBit, ipeAlign) | |||
| 21480 | || !readBoundedBitShort(*buf, bodyEndBit, justification) | |||
| 21481 | || !readBoundedBitDouble(*buf, bodyEndBit, scaleFactor)) | |||
| 21482 | return fail(); | |||
| 21483 | } else { // R2010+ | |||
| 21484 | if (!readBoundedBitShort(*buf, bodyEndBit, attachmentDirection) | |||
| 21485 | || !readBoundedBitShort(*buf, bodyEndBit, styleTopAttach) | |||
| 21486 | || !readBoundedBitShort(*buf, bodyEndBit, styleBottomAttach)) | |||
| 21487 | return fail(); | |||
| 21488 | } | |||
| 21489 | if (version >= DRW::AC1027) { // R2013+ | |||
| 21490 | if (!readBoundedBit(*buf, bodyEndBit, leaderExtendedToText)) | |||
| 21491 | return fail(); | |||
| 21492 | } | |||
| 21493 | ||||
| 21494 | if (!buf->isGood() || !sBuf->isGood() | |||
| 21495 | || currentDwgBit(buf) > bodyEndBit | |||
| 21496 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 21497 | return fail(); | |||
| 21498 | ||||
| 21499 | std::uint64_t handleEndBit = 0; | |||
| 21500 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 21501 | handleEndBit)) | |||
| 21502 | return fail(); | |||
| 21503 | // Common entity handles first (owner/reactors/xdic/layer/ltype/...) — | |||
| 21504 | // entity-specific handles follow in declared order from libreDWG | |||
| 21505 | // dwg2.spec. Read order in the trailing handle stream: | |||
| 21506 | // 1. (R2010b+ only) per-leader-line ltype + arrow handles, in the | |||
| 21507 | // same iteration order as the body block. | |||
| 21508 | // 2. AnnotContext content handle (text_style 340 if hasTextContents, | |||
| 21509 | // else block_table 341 if hasContentsBlock). | |||
| 21510 | // 3. mleaderstyle (340), line_ltype (341), arrow_handle (342), | |||
| 21511 | // text_style (343), block_style (344) entity-level handles. | |||
| 21512 | // 4. (R14-R2007 only) per-arrowhead + per-blocklabel handles. | |||
| 21513 | ret = DRW_Entity::parseDwgEntHandle(version, buf, true, handleEndBit); | |||
| 21514 | if (!ret) | |||
| 21515 | return fail(); | |||
| 21516 | ||||
| 21517 | auto safeHandle = [&](dwgHandle& slot, const char* tag) { | |||
| 21518 | if (!readBoundedDwgHandle(*buf, handleEndBit, 0, false, slot)) | |||
| 21519 | return false; | |||
| 21520 | DRW_DBG(" ")DRW_dbg::dbg(" "); DRW_DBG(tag)DRW_dbg::dbg(tag); DRW_DBG(": ")DRW_dbg::dbg(": "); | |||
| 21521 | DRW_DBGHL(slot.code, slot.size, slot.ref)DRW_dbg::dbgHL(slot.code, slot.size, slot.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 21522 | return true; | |||
| 21523 | }; | |||
| 21524 | ||||
| 21525 | // 1. R2010b+ per-line handles, in body iteration order. | |||
| 21526 | if (version >= DRW::AC1024) { | |||
| 21527 | for (auto& root : context.roots) { | |||
| 21528 | for (auto& line : root.leaderLines) { | |||
| 21529 | if (!safeHandle(line.lineTypeHandle, "line.ltype")) return fail(); | |||
| 21530 | if (!safeHandle(line.arrowHandle, "line.arrow")) return fail(); | |||
| 21531 | } | |||
| 21532 | } | |||
| 21533 | } | |||
| 21534 | ||||
| 21535 | // 2. AnnotContext content handle. | |||
| 21536 | if (context.hasTextContents) { | |||
| 21537 | if (!safeHandle(context.textStyleHandle, "ctx.text_style")) return fail(); | |||
| 21538 | } else if (context.hasContentsBlock) { | |||
| 21539 | if (!safeHandle(context.blockTableRecordHandle, "ctx.block_table")) return fail(); | |||
| 21540 | } | |||
| 21541 | ||||
| 21542 | // 3. Entity-level handles. | |||
| 21543 | if (!safeHandle(styleHandle, "mleaderstyle")) return fail(); | |||
| 21544 | if (!safeHandle(leaderLineTypeHandle, "line_ltype")) return fail(); | |||
| 21545 | if (!safeHandle(arrowHeadHandle, "arrow_handle")) return fail(); | |||
| 21546 | if (!safeHandle(styleTextStyleHandle, "text_style")) return fail(); | |||
| 21547 | if (!safeHandle(styleBlockHandle, "block_style")) return fail(); | |||
| 21548 | ||||
| 21549 | // 4. R14-R2007 per-arrowhead + per-blocklabel handles (counts came | |||
| 21550 | // from the body-side arrays read earlier). | |||
| 21551 | if (version < DRW::AC1024) { | |||
| 21552 | for (auto& a : arrowHeads) | |||
| 21553 | if (!safeHandle(a.handle, "arrowheads.handle")) return fail(); | |||
| 21554 | for (auto& bl : blockLabels) | |||
| 21555 | if (!safeHandle(bl.attDefHandle, "blocklabels.attdef")) return fail(); | |||
| 21556 | } | |||
| 21557 | ||||
| 21558 | const int rb = buf->numRemainingBytes(); | |||
| 21559 | 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"); | |||
| 21560 | if (rb > 4) { | |||
| 21561 | DRW_DBG("MLEADER: handle-stream tail ")DRW_dbg::dbg("MLEADER: handle-stream tail "); DRW_DBG(rb)DRW_dbg::dbg(rb); | |||
| 21562 | DRW_DBG(" bytes unconsumed (handle ")DRW_dbg::dbg(" bytes unconsumed (handle "); | |||
| 21563 | DRW_DBGH(handle)DRW_dbg::dbgH(handle); DRW_DBG(") — review tail handle list\n")DRW_dbg::dbg(") — review tail handle list\n"); | |||
| 21564 | } | |||
| 21565 | ||||
| 21566 | if (!buf->isGood() || !sBuf->isGood()) | |||
| 21567 | return fail(); | |||
| 21568 | *sourceBuf = *buf; | |||
| 21569 | return true; | |||
| 21570 | } | |||
| 21571 | ||||
| 21572 | bool DRW_MLeader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 21573 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 21574 | (void)bs; | |||
| 21575 | if (version < DRW::AC1024) | |||
| 21576 | return false; | |||
| 21577 | ||||
| 21578 | oType = kDwgClassNum; | |||
| 21579 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 21580 | return false; | |||
| 21581 | ||||
| 21582 | buf->putBitShort(classVersion == 0 ? 2 : classVersion); | |||
| 21583 | if (!encodeMLeaderAnnotContext(version, buf, strBuf, context)) | |||
| 21584 | return false; | |||
| 21585 | ||||
| 21586 | buf->putBitLong(overrideFlags); | |||
| 21587 | buf->putBitShort(leaderType); | |||
| 21588 | buf->putCmColor(version, static_cast<std::uint16_t>(leaderColor)); | |||
| 21589 | buf->putBitLong(leaderLineWeight); | |||
| 21590 | buf->putBit(landingEnabled ? 1 : 0); | |||
| 21591 | buf->putBit(doglegEnabled ? 1 : 0); | |||
| 21592 | buf->putBitDouble(landingDistance); | |||
| 21593 | buf->putBitDouble(defaultArrowHeadSize); | |||
| 21594 | buf->putBitShort(styleContentType); | |||
| 21595 | buf->putBitShort(styleLeftAttach); | |||
| 21596 | buf->putBitShort(styleRightAttach); | |||
| 21597 | buf->putBitShort(styleTextAngleType); | |||
| 21598 | buf->putBitShort(unknown175); | |||
| 21599 | buf->putCmColor(version, static_cast<std::uint16_t>(styleTextColor)); | |||
| 21600 | buf->putBit(styleTextFrameEnabled ? 1 : 0); | |||
| 21601 | buf->putCmColor(version, static_cast<std::uint16_t>(styleBlockColor)); | |||
| 21602 | buf->put3BitDouble(styleBlockScale); | |||
| 21603 | buf->putBitDouble(styleBlockRotation); | |||
| 21604 | buf->putBitShort(styleAttachmentType); | |||
| 21605 | buf->putBit(isAnnotative ? 1 : 0); | |||
| 21606 | buf->putBitShort(attachmentDirection); | |||
| 21607 | buf->putBitShort(styleTopAttach); | |||
| 21608 | buf->putBitShort(styleBottomAttach); | |||
| 21609 | if (version >= DRW::AC1027) | |||
| 21610 | buf->putBit(leaderExtendedToText ? 1 : 0); | |||
| 21611 | ||||
| 21612 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 21613 | return false; | |||
| 21614 | ||||
| 21615 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 21616 | for (const DRW_MLeaderRoot& root : context.roots) { | |||
| 21617 | for (const DRW_MLeaderLeaderLine& line : root.leaderLines) { | |||
| 21618 | putHardPointerHandle(hb, line.lineTypeHandle.ref); | |||
| 21619 | putHardPointerHandle(hb, line.arrowHandle.ref); | |||
| 21620 | } | |||
| 21621 | } | |||
| 21622 | ||||
| 21623 | if (context.hasTextContents) { | |||
| 21624 | putHardPointerHandle(hb, context.textStyleHandle.ref); | |||
| 21625 | } else if (context.hasContentsBlock) { | |||
| 21626 | putHardPointerHandle(hb, context.blockTableRecordHandle.ref); | |||
| 21627 | } | |||
| 21628 | ||||
| 21629 | putHardPointerHandle(hb, styleHandle.ref); | |||
| 21630 | putHardPointerHandle(hb, leaderLineTypeHandle.ref); | |||
| 21631 | putHardPointerHandle(hb, arrowHeadHandle.ref); | |||
| 21632 | putHardPointerHandle(hb, styleTextStyleHandle.ref); | |||
| 21633 | putHardPointerHandle(hb, styleBlockHandle.ref); | |||
| 21634 | ||||
| 21635 | return true; | |||
| 21636 | } | |||
| 21637 | ||||
| 21638 | bool DRW_Viewport::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 21639 | switch (code) { | |||
| 21640 | case 40: | |||
| 21641 | pswidth = reader->getDouble(); | |||
| 21642 | break; | |||
| 21643 | case 41: | |||
| 21644 | psheight = reader->getDouble(); | |||
| 21645 | break; | |||
| 21646 | case 68: | |||
| 21647 | vpstatus = reader->getInt32(); | |||
| 21648 | break; | |||
| 21649 | case 69: | |||
| 21650 | vpID = reader->getInt32(); | |||
| 21651 | break; | |||
| 21652 | case 12: | |||
| 21653 | centerPX = reader->getDouble(); | |||
| 21654 | break; | |||
| 21655 | case 22: | |||
| 21656 | centerPY = reader->getDouble(); | |||
| 21657 | break; | |||
| 21658 | case 13: | |||
| 21659 | snapPX = reader->getDouble(); | |||
| 21660 | break; | |||
| 21661 | case 23: | |||
| 21662 | snapPY = reader->getDouble(); | |||
| 21663 | break; | |||
| 21664 | case 14: | |||
| 21665 | snapSpPX = reader->getDouble(); | |||
| 21666 | break; | |||
| 21667 | case 24: | |||
| 21668 | snapSpPY = reader->getDouble(); | |||
| 21669 | break; | |||
| 21670 | case 15: | |||
| 21671 | gridSpX = reader->getDouble(); | |||
| 21672 | break; | |||
| 21673 | case 25: | |||
| 21674 | gridSpY = reader->getDouble(); | |||
| 21675 | break; | |||
| 21676 | case 16: | |||
| 21677 | viewDir.x = reader->getDouble(); | |||
| 21678 | break; | |||
| 21679 | case 26: | |||
| 21680 | viewDir.y = reader->getDouble(); | |||
| 21681 | break; | |||
| 21682 | case 36: | |||
| 21683 | viewDir.z = reader->getDouble(); | |||
| 21684 | break; | |||
| 21685 | case 17: | |||
| 21686 | viewTarget.x = reader->getDouble(); | |||
| 21687 | break; | |||
| 21688 | case 27: | |||
| 21689 | viewTarget.y = reader->getDouble(); | |||
| 21690 | break; | |||
| 21691 | case 37: | |||
| 21692 | viewTarget.z = reader->getDouble(); | |||
| 21693 | break; | |||
| 21694 | case 42: | |||
| 21695 | viewLength = reader->getDouble(); | |||
| 21696 | break; | |||
| 21697 | case 43: | |||
| 21698 | frontClip = reader->getDouble(); | |||
| 21699 | break; | |||
| 21700 | case 44: | |||
| 21701 | backClip = reader->getDouble(); | |||
| 21702 | break; | |||
| 21703 | case 45: | |||
| 21704 | viewHeight = reader->getDouble(); | |||
| 21705 | break; | |||
| 21706 | case 50: | |||
| 21707 | snapAngle = reader->getDouble(); | |||
| 21708 | break; | |||
| 21709 | case 51: | |||
| 21710 | twistAngle = reader->getDouble(); | |||
| 21711 | break; | |||
| 21712 | case 46: | |||
| 21713 | circleZoom = reader->getInt32(); | |||
| 21714 | break; | |||
| 21715 | case 61: | |||
| 21716 | majorGridLines = reader->getInt32(); | |||
| 21717 | break; | |||
| 21718 | case 63: | |||
| 21719 | ambientColor = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 21720 | break; | |||
| 21721 | case 72: | |||
| 21722 | circleZoom = reader->getInt32(); | |||
| 21723 | break; | |||
| 21724 | case 90: | |||
| 21725 | statusFlags = reader->getInt32(); | |||
| 21726 | break; | |||
| 21727 | case 1: | |||
| 21728 | styleSheet = reader->getUtf8String(); | |||
| 21729 | break; | |||
| 21730 | case 281: | |||
| 21731 | renderMode = reader->getInt32(); | |||
| 21732 | break; | |||
| 21733 | case 71: | |||
| 21734 | ucsPerViewport = reader->getInt32() != 0; | |||
| 21735 | break; | |||
| 21736 | case 74: | |||
| 21737 | ucsAtOrigin = reader->getInt32() != 0; | |||
| 21738 | break; | |||
| 21739 | case 110: case 120: case 130: | |||
| 21740 | case 111: case 121: case 131: | |||
| 21741 | case 112: case 122: case 132: | |||
| 21742 | readCoordTripletCode(code, reader, ucsOrigin, ucsXAxis, ucsYAxis); | |||
| 21743 | break; | |||
| 21744 | case 146: | |||
| 21745 | ucsElevation = reader->getDouble(); | |||
| 21746 | break; | |||
| 21747 | case 76: | |||
| 21748 | break; | |||
| 21749 | case 79: | |||
| 21750 | ucsOrthographicType = reader->getInt32(); | |||
| 21751 | break; | |||
| 21752 | case 148: | |||
| 21753 | shadePlotMode = reader->getInt32(); | |||
| 21754 | break; | |||
| 21755 | case 170: | |||
| 21756 | shadePlotMode = reader->getInt32(); | |||
| 21757 | break; | |||
| 21758 | case 292: | |||
| 21759 | useDefaultLighting = reader->getInt32() != 0; | |||
| 21760 | break; | |||
| 21761 | case 282: | |||
| 21762 | defaultLightingType = reader->getInt32(); | |||
| 21763 | break; | |||
| 21764 | case 451: | |||
| 21765 | brightness = reader->getDouble(); | |||
| 21766 | break; | |||
| 21767 | case 452: | |||
| 21768 | contrast = reader->getDouble(); | |||
| 21769 | break; | |||
| 21770 | case 141: | |||
| 21771 | brightness = reader->getDouble(); | |||
| 21772 | break; | |||
| 21773 | case 142: | |||
| 21774 | contrast = reader->getDouble(); | |||
| 21775 | break; | |||
| 21776 | case 421: | |||
| 21777 | ambientColorRgb = reader->getInt32(); | |||
| 21778 | break; | |||
| 21779 | case 431: | |||
| 21780 | ambientColorName = reader->getUtf8String(); | |||
| 21781 | break; | |||
| 21782 | case 331: | |||
| 21783 | frozenLayerHandles.push_back( | |||
| 21784 | static_cast<std::uint32_t>(reader->getHandleString())); | |||
| 21785 | break; | |||
| 21786 | case 332: | |||
| 21787 | backgroundHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21788 | break; | |||
| 21789 | case 333: | |||
| 21790 | shadePlotHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21791 | break; | |||
| 21792 | case 340: | |||
| 21793 | clipBoundaryHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21794 | break; | |||
| 21795 | case 345: | |||
| 21796 | namedUcsHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21797 | break; | |||
| 21798 | case 346: | |||
| 21799 | baseUcsHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21800 | break; | |||
| 21801 | case 361: | |||
| 21802 | m_sunHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21803 | break; | |||
| 21804 | case 348: | |||
| 21805 | visualStyleHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21806 | fullVisualStyleHandle = visualStyleHandle; | |||
| 21807 | break; | |||
| 21808 | case 349: | |||
| 21809 | shadePlotHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21810 | break; | |||
| 21811 | default: | |||
| 21812 | return DRW_Point::parseCode(code, reader); | |||
| 21813 | } | |||
| 21814 | ||||
| 21815 | return true; | |||
| 21816 | } | |||
| 21817 | ||||
| 21818 | bool DRW_Viewport::validatePayloadFields() const { | |||
| 21819 | const auto finite = [](const DRW_Coord& point) { | |||
| 21820 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 21821 | && std::isfinite(point.z); | |||
| 21822 | }; | |||
| 21823 | const auto fitsSignedShort = [](int value) { | |||
| 21824 | return value >= static_cast<int>(std::numeric_limits<std::int16_t>::min()) | |||
| 21825 | && value <= static_cast<int>(std::numeric_limits<std::int16_t>::max()); | |||
| 21826 | }; | |||
| 21827 | const auto fitsByte = [](int value) { | |||
| 21828 | return value >= 0 | |||
| 21829 | && value <= static_cast<int>(std::numeric_limits<std::uint8_t>::max()); | |||
| 21830 | }; | |||
| 21831 | const auto fitsBitShort = [](int value) { | |||
| 21832 | return value >= 0 | |||
| 21833 | && value <= static_cast<int>(std::numeric_limits<std::uint16_t>::max()); | |||
| 21834 | }; | |||
| 21835 | const bool integralCircleZoom = std::isfinite(circleZoom) | |||
| 21836 | && std::trunc(circleZoom) == circleZoom; | |||
| 21837 | return finite(basePoint) && finite(viewTarget) && finite(viewDir) | |||
| 21838 | && finite(ucsOrigin) && finite(ucsXAxis) && finite(ucsYAxis) | |||
| 21839 | && std::isfinite(pswidth) && std::isfinite(psheight) | |||
| 21840 | && std::isfinite(centerPX) && std::isfinite(centerPY) | |||
| 21841 | && std::isfinite(snapPX) && std::isfinite(snapPY) | |||
| 21842 | && std::isfinite(snapSpPX) && std::isfinite(snapSpPY) | |||
| 21843 | && std::isfinite(gridSpX) && std::isfinite(gridSpY) | |||
| 21844 | && std::isfinite(viewLength) && std::isfinite(frontClip) | |||
| 21845 | && std::isfinite(backClip) && std::isfinite(viewHeight) | |||
| 21846 | && std::isfinite(snapAngle) && std::isfinite(twistAngle) | |||
| 21847 | && std::isfinite(ucsElevation) && std::isfinite(brightness) | |||
| 21848 | && std::isfinite(contrast) && fitsSignedShort(vpstatus) | |||
| 21849 | && fitsSignedShort(vpID) && integralCircleZoom | |||
| 21850 | && circleZoom >= 0.0 | |||
| 21851 | && circleZoom <= static_cast<double>(std::numeric_limits<std::uint16_t>::max()) | |||
| 21852 | && fitsBitShort(majorGridLines) && fitsByte(renderMode) | |||
| 21853 | && fitsBitShort(ucsOrthographicType) && fitsBitShort(shadePlotMode) | |||
| 21854 | && fitsByte(defaultLightingType) | |||
| 21855 | && ambientColor <= std::numeric_limits<std::uint16_t>::max() | |||
| 21856 | && ambientColorRgb >= -1 && ambientColorRgb <= 0xFFFFFF | |||
| 21857 | && frozenLayerHandles.size() <= kMaxViewportFrozenLayers; | |||
| 21858 | } | |||
| 21859 | ||||
| 21860 | bool DRW_Viewport::validateDxf() const { | |||
| 21861 | return validatePayloadFields(); | |||
| 21862 | } | |||
| 21863 | //ex 22 dec 34 | |||
| 21864 | void DRW_Viewport::resetDwgState() { | |||
| 21865 | DRW_Point::resetDwgState(); | |||
| 21866 | pswidth = 205.0; | |||
| 21867 | psheight = 156.0; | |||
| 21868 | vpstatus = 0; | |||
| 21869 | vpID = 0; | |||
| 21870 | centerPX = 128.5; | |||
| 21871 | centerPY = 97.5; | |||
| 21872 | snapPX = snapPY = 0.0; | |||
| 21873 | snapSpPX = snapSpPY = 10.0; | |||
| 21874 | gridSpX = gridSpY = 10.0; | |||
| 21875 | viewDir = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 21876 | viewTarget = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 21877 | viewLength = 50.0; | |||
| 21878 | frontClip = backClip = 0.0; | |||
| 21879 | viewHeight = 1.0; | |||
| 21880 | snapAngle = twistAngle = 0.0; | |||
| 21881 | circleZoom = 100.0; | |||
| 21882 | majorGridLines = 0; | |||
| 21883 | statusFlags = 0; | |||
| 21884 | styleSheet.clear(); | |||
| 21885 | renderMode = 0; | |||
| 21886 | ucsAtOrigin = false; | |||
| 21887 | ucsPerViewport = false; | |||
| 21888 | ucsOrigin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 21889 | ucsXAxis = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 21890 | ucsYAxis = DRW_Coord{0.0, 1.0, 0.0}; | |||
| 21891 | ucsElevation = 0.0; | |||
| 21892 | ucsOrthographicType = 0; | |||
| 21893 | shadePlotMode = 0; | |||
| 21894 | useDefaultLighting = true; | |||
| 21895 | defaultLightingType = 1; | |||
| 21896 | brightness = contrast = 0.0; | |||
| 21897 | ambientColor = 250; | |||
| 21898 | ambientColorRgb = -1; | |||
| 21899 | ambientColorMethod = 0; | |||
| 21900 | ambientColorName.clear(); | |||
| 21901 | vpHeaderHandle = 0; | |||
| 21902 | clipBoundaryHandle = 0; | |||
| 21903 | namedUcsHandle = 0; | |||
| 21904 | baseUcsHandle = 0; | |||
| 21905 | backgroundHandle = 0; | |||
| 21906 | visualStyleHandle = 0; | |||
| 21907 | shadePlotHandle = 0; | |||
| 21908 | m_sunHandle = 0; | |||
| 21909 | frozenLayerHandles.clear(); | |||
| 21910 | frozenLyCount = 0; | |||
| 21911 | } | |||
| 21912 | ||||
| 21913 | bool DRW_Viewport::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 21914 | resetDwgState(); | |||
| 21915 | dwgBuffer *sourceBuf = buf; | |||
| 21916 | auto fail = [this, sourceBuf]() { | |||
| 21917 | if (sourceBuf != nullptr) | |||
| 21918 | sourceBuf->invalidate(); | |||
| 21919 | resetDwgState(); | |||
| 21920 | return false; | |||
| 21921 | }; | |||
| 21922 | if (sourceBuf == nullptr) | |||
| 21923 | return fail(); | |||
| 21924 | ||||
| 21925 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 21926 | buf = &bodyProbe; | |||
| 21927 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 21928 | dwgBuffer *sBuf = buf; | |||
| 21929 | if (version > DRW::AC1018) {//2007+ | |||
| 21930 | sBuf = &sBuff; //separate buffer for strings | |||
| 21931 | } | |||
| 21932 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 21933 | if (!ret) | |||
| 21934 | return fail(); | |||
| 21935 | DRW_DBG("\n***************************** parsing viewport *****************************************\n")DRW_dbg::dbg("\n***************************** parsing viewport *****************************************\n" ); | |||
| 21936 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 21937 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 21938 | if (version > DRW::AC1021) { | |||
| 21939 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 21940 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 21941 | ignoredBodyEndBit, &stringEndBit)) | |||
| 21942 | return fail(); | |||
| 21943 | } | |||
| 21944 | if (!readBoundedBitCoord(*buf, bodyEndBit, basePoint) | |||
| 21945 | || !readBoundedBitDouble(*buf, bodyEndBit, pswidth) | |||
| 21946 | || !readBoundedBitDouble(*buf, bodyEndBit, psheight)) | |||
| 21947 | return fail(); | |||
| 21948 | DRW_DBG("center ")DRW_dbg::dbg("center "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z); | |||
| 21949 | 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"); | |||
| 21950 | //RLZ TODO: complete in dxf | |||
| 21951 | if (version > DRW::AC1014) {//2000+ | |||
| 21952 | if (!readBoundedBitCoord(*buf, bodyEndBit, viewTarget) | |||
| 21953 | || !readBoundedBitCoord(*buf, bodyEndBit, viewDir) | |||
| 21954 | || !readBoundedBitDouble(*buf, bodyEndBit, twistAngle) | |||
| 21955 | || !readBoundedBitDouble(*buf, bodyEndBit, viewHeight) | |||
| 21956 | || !readBoundedBitDouble(*buf, bodyEndBit, viewLength) | |||
| 21957 | || !readBoundedBitDouble(*buf, bodyEndBit, frontClip) | |||
| 21958 | || !readBoundedBitDouble(*buf, bodyEndBit, backClip) | |||
| 21959 | || !readBoundedBitDouble(*buf, bodyEndBit, snapAngle) | |||
| 21960 | || !readBoundedRawDouble(*buf, bodyEndBit, centerPX) | |||
| 21961 | || !readBoundedRawDouble(*buf, bodyEndBit, centerPY) | |||
| 21962 | || !readBoundedRawDouble(*buf, bodyEndBit, snapPX) | |||
| 21963 | || !readBoundedRawDouble(*buf, bodyEndBit, snapPY) | |||
| 21964 | || !readBoundedRawDouble(*buf, bodyEndBit, snapSpPX) | |||
| 21965 | || !readBoundedRawDouble(*buf, bodyEndBit, snapSpPY) | |||
| 21966 | || !readBoundedRawDouble(*buf, bodyEndBit, gridSpX) | |||
| 21967 | || !readBoundedRawDouble(*buf, bodyEndBit, gridSpY)) | |||
| 21968 | return fail(); | |||
| 21969 | 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); | |||
| 21970 | 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); | |||
| 21971 | DRW_DBG("\nView twist Angle: ")DRW_dbg::dbg("\nView twist Angle: "); DRW_DBG(twistAngle)DRW_dbg::dbg(twistAngle); | |||
| 21972 | DRW_DBG("\nview Height: ")DRW_dbg::dbg("\nview Height: "); DRW_DBG(viewHeight)DRW_dbg::dbg(viewHeight); | |||
| 21973 | DRW_DBG(" Lens Length: ")DRW_dbg::dbg(" Lens Length: "); DRW_DBG(viewLength)DRW_dbg::dbg(viewLength); | |||
| 21974 | DRW_DBG("\nfront Clip Z: ")DRW_dbg::dbg("\nfront Clip Z: "); DRW_DBG(frontClip)DRW_dbg::dbg(frontClip); | |||
| 21975 | DRW_DBG(" back Clip Z: ")DRW_dbg::dbg(" back Clip Z: "); DRW_DBG(backClip)DRW_dbg::dbg(backClip); | |||
| 21976 | DRW_DBG("\n snap Angle: ")DRW_dbg::dbg("\n snap Angle: "); DRW_DBG(snapAngle)DRW_dbg::dbg(snapAngle); | |||
| 21977 | 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); | |||
| 21978 | 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); | |||
| 21979 | 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); | |||
| 21980 | std::uint16_t parsedCircleZoom = 0; | |||
| 21981 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedCircleZoom)) | |||
| 21982 | return fail(); | |||
| 21983 | circleZoom = parsedCircleZoom; | |||
| 21984 | } | |||
| 21985 | if (version > DRW::AC1018) {//2007+ | |||
| 21986 | std::uint16_t parsedMajorGridLines = 0; | |||
| 21987 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedMajorGridLines)) | |||
| 21988 | return fail(); | |||
| 21989 | majorGridLines = parsedMajorGridLines; | |||
| 21990 | } | |||
| 21991 | if (version > DRW::AC1014) {//2000+ | |||
| 21992 | std::int32_t parsedFrozenLyCount = 0; | |||
| 21993 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedFrozenLyCount)) | |||
| 21994 | return fail(); | |||
| 21995 | if (!isValidCount(parsedFrozenLyCount, kMaxViewportFrozenLayers)) | |||
| 21996 | return fail(); | |||
| 21997 | frozenLyCount = static_cast<std::uint32_t>(parsedFrozenLyCount); | |||
| 21998 | 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"); | |||
| 21999 | if (!readBoundedBitLong(*buf, bodyEndBit, statusFlags)) | |||
| 22000 | return fail(); | |||
| 22001 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 22002 | styleSheet)) | |||
| 22003 | return fail(); | |||
| 22004 | std::uint8_t parsedRenderMode = 0; | |||
| 22005 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedRenderMode)) | |||
| 22006 | return fail(); | |||
| 22007 | renderMode = parsedRenderMode; | |||
| 22008 | // ODA order is UCS-at-origin (74), then UCS-per-viewport (71). | |||
| 22009 | if (!readBoundedBit(*buf, bodyEndBit, ucsAtOrigin) | |||
| 22010 | || !readBoundedBit(*buf, bodyEndBit, ucsPerViewport) | |||
| 22011 | || !readBoundedBitCoord(*buf, bodyEndBit, ucsOrigin) | |||
| 22012 | || !readBoundedBitCoord(*buf, bodyEndBit, ucsXAxis) | |||
| 22013 | || !readBoundedBitCoord(*buf, bodyEndBit, ucsYAxis) | |||
| 22014 | || !readBoundedBitDouble(*buf, bodyEndBit, ucsElevation)) | |||
| 22015 | return fail(); | |||
| 22016 | std::uint16_t parsedUcsOrthographicType = 0; | |||
| 22017 | if (!readBoundedBitShort(*buf, bodyEndBit, | |||
| 22018 | parsedUcsOrthographicType)) | |||
| 22019 | return fail(); | |||
| 22020 | ucsOrthographicType = parsedUcsOrthographicType; | |||
| 22021 | } | |||
| 22022 | if (version > DRW::AC1015) {//2004+ | |||
| 22023 | std::uint16_t parsedShadePlotMode = 0; | |||
| 22024 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedShadePlotMode)) | |||
| 22025 | return fail(); | |||
| 22026 | shadePlotMode = parsedShadePlotMode; | |||
| 22027 | } | |||
| 22028 | if (version > DRW::AC1018) {//2007+ | |||
| 22029 | std::uint8_t parsedDefaultLightingType = 0; | |||
| 22030 | if (!readBoundedBit(*buf, bodyEndBit, useDefaultLighting) | |||
| 22031 | || !readBoundedRawChar8(*buf, bodyEndBit, | |||
| 22032 | parsedDefaultLightingType) | |||
| 22033 | || !readBoundedBitDouble(*buf, bodyEndBit, brightness) | |||
| 22034 | || !readBoundedBitDouble(*buf, bodyEndBit, contrast)) | |||
| 22035 | return fail(); | |||
| 22036 | defaultLightingType = parsedDefaultLightingType; | |||
| 22037 | // ODA §20.4.38: ambient color is CMC, not ENC — confirmed by libreDWG dwg.spec:2512 | |||
| 22038 | bool hasRgbColor = false; | |||
| 22039 | int parsedAmbientColorRgb = -1; | |||
| 22040 | UTF8STRINGstd::string parsedAmbientColorName; | |||
| 22041 | UTF8STRINGstd::string parsedAmbientColorBookName; | |||
| 22042 | dwgBuffer colorProbe = buf->forkIndependent(); | |||
| 22043 | dwgBuffer colorStringProbe = sBuf->forkIndependent(); | |||
| 22044 | const std::uint32_t parsedAmbientColor = colorProbe.getCmColor( | |||
| 22045 | version, &parsedAmbientColorRgb, &colorStringProbe, | |||
| 22046 | &parsedAmbientColorName, &parsedAmbientColorBookName, | |||
| 22047 | &hasRgbColor); | |||
| 22048 | if (!colorProbe.isGood() || !colorStringProbe.isGood() | |||
| 22049 | || currentDwgBit(&colorProbe) > bodyEndBit | |||
| 22050 | || currentDwgBit(&colorStringProbe) > stringEndBit) | |||
| 22051 | return fail(); | |||
| 22052 | *buf = colorProbe; | |||
| 22053 | *sBuf = colorStringProbe; | |||
| 22054 | ambientColor = parsedAmbientColor; | |||
| 22055 | ambientColorRgb = parsedAmbientColorRgb; | |||
| 22056 | ambientColorName = parsedAmbientColorBookName.empty() | |||
| 22057 | ? std::move(parsedAmbientColorName) | |||
| 22058 | : (parsedAmbientColorBookName + "$" | |||
| 22059 | + parsedAmbientColorName); | |||
| 22060 | if (!hasRgbColor) | |||
| 22061 | ambientColorRgb = -1; | |||
| 22062 | } | |||
| 22063 | const auto finite = [](const DRW_Coord& point) { | |||
| 22064 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 22065 | && std::isfinite(point.z); | |||
| 22066 | }; | |||
| 22067 | if (!finite(basePoint) || !finite(viewTarget) || !finite(viewDir) | |||
| 22068 | || !finite(ucsOrigin) || !finite(ucsXAxis) || !finite(ucsYAxis) | |||
| 22069 | || !std::isfinite(pswidth) || !std::isfinite(psheight) | |||
| 22070 | || !std::isfinite(centerPX) || !std::isfinite(centerPY) | |||
| 22071 | || !std::isfinite(snapPX) || !std::isfinite(snapPY) | |||
| 22072 | || !std::isfinite(snapSpPX) || !std::isfinite(snapSpPY) | |||
| 22073 | || !std::isfinite(gridSpX) || !std::isfinite(gridSpY) | |||
| 22074 | || !std::isfinite(viewLength) || !std::isfinite(frontClip) | |||
| 22075 | || !std::isfinite(backClip) || !std::isfinite(viewHeight) | |||
| 22076 | || !std::isfinite(snapAngle) || !std::isfinite(twistAngle) | |||
| 22077 | || !std::isfinite(ucsElevation) || !std::isfinite(brightness) | |||
| 22078 | || !std::isfinite(contrast)) | |||
| 22079 | return fail(); | |||
| 22080 | if (!validatePayloadFields()) | |||
| 22081 | return fail(); | |||
| 22082 | std::uint64_t handleEndBit = 0; | |||
| 22083 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 22084 | handleEndBit)) | |||
| 22085 | return fail(); | |||
| 22086 | ret = DRW_Entity::parseDwgEntHandle(version, buf, true, handleEndBit); | |||
| 22087 | if (!ret || !buf->isGood() || !sBuf->isGood()) | |||
| 22088 | return fail(); | |||
| 22089 | ||||
| 22090 | // R13-R2004 keep the handle stream inline (sBuf aliases buf), so by this | |||
| 22091 | // point sBuf has necessarily moved past stringEndBit into the handle | |||
| 22092 | // data; only R2007+ has a detached string stream to bound here (see the | |||
| 22093 | // identical guard in DRW_Block::parseDwg). | |||
| 22094 | if (!buf->isGood() || !sBuf->isGood() | |||
| 22095 | || (version > DRW::AC1018 && currentDwgBit(sBuf) > stringEndBit)) | |||
| 22096 | return fail(); | |||
| 22097 | ||||
| 22098 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 22099 | auto readHandleRef = [&handleProbe, handleEndBit](std::uint32_t& target) { | |||
| 22100 | dwgHandle parsed; | |||
| 22101 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 22102 | parsed)) { | |||
| 22103 | return false; | |||
| 22104 | } | |||
| 22105 | target = parsed.ref; | |||
| 22106 | return true; | |||
| 22107 | }; | |||
| 22108 | if (version < DRW::AC1015) {//R13 & R14 only | |||
| 22109 | if (!readHandleRef(vpHeaderHandle)) | |||
| 22110 | return fail(); | |||
| 22111 | } | |||
| 22112 | if (version > DRW::AC1014) {//2000+ | |||
| 22113 | if (!DRW::reserve(frozenLayerHandles, static_cast<int>(frozenLyCount))) | |||
| 22114 | return fail(); | |||
| 22115 | for (std::uint32_t i = 0; i < frozenLyCount; ++i) { | |||
| 22116 | std::uint32_t ref = 0; | |||
| 22117 | if (!readHandleRef(ref)) | |||
| 22118 | return fail(); | |||
| 22119 | frozenLayerHandles.push_back(ref); | |||
| 22120 | } | |||
| 22121 | if (!readHandleRef(clipBoundaryHandle)) | |||
| 22122 | return fail(); | |||
| 22123 | if (version == DRW::AC1015) {//2000 only | |||
| 22124 | if (!readHandleRef(vpHeaderHandle)) | |||
| 22125 | return fail(); | |||
| 22126 | } | |||
| 22127 | if (!readHandleRef(namedUcsHandle) || !readHandleRef(baseUcsHandle)) | |||
| 22128 | return fail(); | |||
| 22129 | } | |||
| 22130 | if (version > DRW::AC1018) {//2007+ | |||
| 22131 | if (!readHandleRef(backgroundHandle) | |||
| 22132 | || !readHandleRef(visualStyleHandle) | |||
| 22133 | || !readHandleRef(shadePlotHandle)) | |||
| 22134 | return fail(); | |||
| 22135 | } | |||
| 22136 | if (version > DRW::AC1018 && !readHandleRef(m_sunHandle)) | |||
| 22137 | return fail(); | |||
| 22138 | if (!handleProbe.isGood() || !sBuf->isGood()) | |||
| 22139 | return fail(); | |||
| 22140 | *sourceBuf = handleProbe; | |||
| 22141 | return true; | |||
| 22142 | } | |||
| 22143 | ||||
| 22144 | // --------------------------------------------------------------------------- | |||
| 22145 | // Write helpers shared by the new encoders below. | |||
| 22146 | // --------------------------------------------------------------------------- | |||
| 22147 | ||||
| 22148 | namespace { | |||
| 22149 | // ODA handle reference codes: 3 hard owner, 4 soft pointer, 5 hard pointer. | |||
| 22150 | static void putTypedHandle(dwgBufferW *hb, std::uint32_t ref, | |||
| 22151 | std::uint8_t code) { | |||
| 22152 | dwgHandle h; | |||
| 22153 | h.code = ref == 0 ? 0 : code; | |||
| 22154 | h.ref = ref; | |||
| 22155 | h.ref64 = ref; | |||
| 22156 | h.size = 0; | |||
| 22157 | if (h.ref != 0) { | |||
| 22158 | std::uint32_t t = h.ref; | |||
| 22159 | while (t != 0) { t >>= 8; ++h.size; } | |||
| 22160 | } | |||
| 22161 | hb->putHandle(h); | |||
| 22162 | } | |||
| 22163 | ||||
| 22164 | static void putAbsHandle(dwgBufferW *hb, std::uint32_t ref) { | |||
| 22165 | putTypedHandle(hb, ref, 5); | |||
| 22166 | } | |||
| 22167 | } // namespace | |||
| 22168 | ||||
| 22169 | // --------------------------------------------------------------------------- | |||
| 22170 | // DRW_MLine::encodeDwg — OT=47 (AC1015/AC1018/AC1024) | |||
| 22171 | // --------------------------------------------------------------------------- | |||
| 22172 | ||||
| 22173 | bool DRW_MLine::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 22174 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 22175 | (void)bs; (void)strBuf; | |||
| 22176 | if (!validatePayloadFields()) | |||
| 22177 | return false; | |||
| 22178 | oType = 47; | |||
| 22179 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 22180 | ||||
| 22181 | buf->putBitDouble(scale); | |||
| 22182 | buf->putRawChar8(justification); | |||
| 22183 | buf->put3BitDouble(basePoint); | |||
| 22184 | buf->putExtrusion(extPoint, false); // false = pre-2000 style (getExtrusion(false) in parser) | |||
| 22185 | buf->putBitShort(static_cast<std::uint16_t>(openClosed)); | |||
| 22186 | buf->putRawChar8(numLines); | |||
| 22187 | buf->putBitShort(numVerts); | |||
| 22188 | ||||
| 22189 | for (const auto& vtx : vertlist) { | |||
| 22190 | buf->put3BitDouble(vtx.position); | |||
| 22191 | buf->put3BitDouble(vtx.vertexDir); | |||
| 22192 | buf->put3BitDouble(vtx.miterDir); | |||
| 22193 | for (int li = 0; li < static_cast<int>(numLines); ++li) { | |||
| 22194 | const auto& segs = (li < static_cast<int>(vtx.segParms.size())) | |||
| 22195 | ? vtx.segParms[li] : std::vector<double>{}; | |||
| 22196 | const auto& fills = (li < static_cast<int>(vtx.areaFillParms.size())) | |||
| 22197 | ? vtx.areaFillParms[li] : std::vector<double>{}; | |||
| 22198 | buf->putBitShort(static_cast<std::uint16_t>(segs.size())); | |||
| 22199 | for (double s : segs) buf->putBitDouble(s); | |||
| 22200 | buf->putBitShort(static_cast<std::uint16_t>(fills.size())); | |||
| 22201 | for (double f : fills) buf->putBitDouble(f); | |||
| 22202 | } | |||
| 22203 | } | |||
| 22204 | ||||
| 22205 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 22206 | ||||
| 22207 | // MLINE style handle — extra handle after standard entity handles. | |||
| 22208 | if (version > DRW::AC1014) { | |||
| 22209 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 22210 | putAbsHandle(hb, styleHandle); | |||
| 22211 | } | |||
| 22212 | return true; | |||
| 22213 | } | |||
| 22214 | ||||
| 22215 | // --------------------------------------------------------------------------- | |||
| 22216 | // DRW_Vertex::encodeDwg — OT varies by flags | |||
| 22217 | // --------------------------------------------------------------------------- | |||
| 22218 | ||||
| 22219 | bool DRW_Vertex::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 22220 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 22221 | (void)bs; (void)strBuf; | |||
| 22222 | if (buf == nullptr || !validatePayloadFields()) | |||
| 22223 | return false; | |||
| 22224 | switch (m_dwgSubtype) { | |||
| 22225 | case DwgSubtype::Vertex2D: oType = 0x0A; break; | |||
| 22226 | case DwgSubtype::Vertex3D: oType = 0x0B; break; | |||
| 22227 | case DwgSubtype::Mesh: oType = 0x0C; break; | |||
| 22228 | case DwgSubtype::Polyface: oType = 0x0D; break; | |||
| 22229 | case DwgSubtype::PolyfaceFace: oType = 0x0E; break; | |||
| 22230 | case DwgSubtype::Auto: | |||
| 22231 | if ((flags & 64) != 0) | |||
| 22232 | oType = 0x0D; // VERTEX_PFACE coordinate vertex | |||
| 22233 | else if ((flags & 128) != 0) | |||
| 22234 | oType = 0x0E; // VERTEX_PFACE_FACE | |||
| 22235 | else if ((flags & 16) != 0) | |||
| 22236 | oType = 0x0C; // VERTEX_MESH | |||
| 22237 | else if ((flags & 32) != 0 || (flags & 8) != 0) | |||
| 22238 | oType = 0x0B; // VERTEX_3D | |||
| 22239 | else | |||
| 22240 | oType = 0x0A; // VERTEX_2D | |||
| 22241 | break; | |||
| 22242 | } | |||
| 22243 | ||||
| 22244 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 22245 | ||||
| 22246 | if (oType == 0x0A) { | |||
| 22247 | buf->putRawChar8(static_cast<std::uint8_t>(flags)); | |||
| 22248 | buf->put3BitDouble(basePoint); | |||
| 22249 | buf->putBitDouble(stawidth); | |||
| 22250 | buf->putBitDouble(endwidth); | |||
| 22251 | buf->putBitDouble(bulge); | |||
| 22252 | if (version > DRW::AC1021) | |||
| 22253 | buf->putBitLong(static_cast<std::int32_t>(identifier)); | |||
| 22254 | buf->putBitDouble(tgdir); | |||
| 22255 | } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) { | |||
| 22256 | buf->putRawChar8(static_cast<std::uint8_t>(flags)); | |||
| 22257 | buf->put3BitDouble(basePoint); | |||
| 22258 | } else { // 0x0E pface face | |||
| 22259 | buf->putBitShort(static_cast<std::uint16_t>(vindex1)); | |||
| 22260 | buf->putBitShort(static_cast<std::uint16_t>(vindex2)); | |||
| 22261 | buf->putBitShort(static_cast<std::uint16_t>(vindex3)); | |||
| 22262 | buf->putBitShort(static_cast<std::uint16_t>(vindex4)); | |||
| 22263 | } | |||
| 22264 | ||||
| 22265 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 22266 | } | |||
| 22267 | ||||
| 22268 | bool DRW_SeqEnd::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 22269 | DRW_Entity::reset(); | |||
| 22270 | if (buf == nullptr) | |||
| 22271 | return false; | |||
| 22272 | ||||
| 22273 | auto fail = [this, buf]() { | |||
| 22274 | buf->invalidate(); | |||
| 22275 | DRW_Entity::reset(); | |||
| 22276 | return false; | |||
| 22277 | }; | |||
| 22278 | dwgBuffer probe = buf->forkIndependent(); | |||
| 22279 | if (!DRW_Entity::parseDwgCommon(version, &probe, bs) | |||
| 22280 | || !probe.isGood()) | |||
| 22281 | return fail(); | |||
| 22282 | std::uint64_t handleEndBit = 0; | |||
| 22283 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit) | |||
| 22284 | || !DRW_Entity::parseDwgEntHandle(version, &probe, true, | |||
| 22285 | handleEndBit) | |||
| 22286 | || !probe.isGood()) | |||
| 22287 | return fail(); | |||
| 22288 | ||||
| 22289 | *buf = probe; | |||
| 22290 | return true; | |||
| 22291 | } | |||
| 22292 | ||||
| 22293 | bool DRW_SeqEnd::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 22294 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 22295 | (void)bs; (void)strBuf; | |||
| 22296 | oType = 0x06; | |||
| 22297 | if (!encodeDwgCommon(version, buf)) | |||
| 22298 | return false; | |||
| 22299 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 22300 | } | |||
| 22301 | ||||
| 22302 | // --------------------------------------------------------------------------- | |||
| 22303 | // DRW_Polyline::encodeDwg — OT varies by flags; vertex handles emitted here. | |||
| 22304 | // --------------------------------------------------------------------------- | |||
| 22305 | ||||
| 22306 | bool DRW_Polyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 22307 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 22308 | (void)bs; (void)strBuf; | |||
| 22309 | if (buf == nullptr || !validatePayloadFields()) | |||
| 22310 | return false; | |||
| 22311 | // Determine object type from stored flags (mirror of parseDwg dispatch). | |||
| 22312 | if (flags & 64) oType = 0x1D; // POLYLINE_PFACE | |||
| 22313 | else if (flags & 16) oType = 0x1E; // POLYLINE_MESH | |||
| 22314 | else if (flags & 8) oType = 0x10; // POLYLINE_3D | |||
| 22315 | else oType = 0x0F; // POLYLINE_2D | |||
| 22316 | ||||
| 22317 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 22318 | ||||
| 22319 | if (oType == 0x0F) { | |||
| 22320 | buf->putBitShort(static_cast<std::uint16_t>(flags)); | |||
| 22321 | buf->putBitShort(static_cast<std::uint16_t>(curvetype)); | |||
| 22322 | buf->putBitDouble(defstawidth); | |||
| 22323 | buf->putBitDouble(defendwidth); | |||
| 22324 | buf->putThickness(thickness, version > DRW::AC1014); | |||
| 22325 | buf->putBitDouble(basePoint.z); | |||
| 22326 | buf->putExtrusion(extPoint, version > DRW::AC1014); | |||
| 22327 | } else if (oType == 0x10) { | |||
| 22328 | // curvetype → 2 RC flag bytes (mirror of parser decode) | |||
| 22329 | std::uint8_t rc1 = 0; | |||
| 22330 | if (curvetype == 5) rc1 = 1; | |||
| 22331 | else if (curvetype == 6) rc1 = 2; | |||
| 22332 | else if (curvetype == 8) rc1 = 3; | |||
| 22333 | buf->putRawChar8(rc1); | |||
| 22334 | buf->putRawChar8(static_cast<std::uint8_t>(flags & 1)); // bit 0 = closed | |||
| 22335 | } else if (oType == 0x1D) { | |||
| 22336 | buf->putBitShort(static_cast<std::uint16_t>(vertexcount)); | |||
| 22337 | buf->putBitShort(static_cast<std::uint16_t>(facecount)); | |||
| 22338 | } else { // 0x1E MESH | |||
| 22339 | buf->putBitShort(static_cast<std::uint16_t>(flags & ~16)); // strip reader-added bit 4 | |||
| 22340 | buf->putBitShort(static_cast<std::uint16_t>(curvetype)); | |||
| 22341 | buf->putBitShort(static_cast<std::uint16_t>(vertexcount)); // M count | |||
| 22342 | buf->putBitShort(static_cast<std::uint16_t>(facecount)); // N count | |||
| 22343 | buf->putBitShort(static_cast<std::uint16_t>(smoothM)); // mDensity, DXF 73 | |||
| 22344 | buf->putBitShort(static_cast<std::uint16_t>(smoothN)); // nDensity, DXF 74 | |||
| 22345 | } | |||
| 22346 | ||||
| 22347 | // AC2004+ (>AC1015): emit vertex count before the handle section. | |||
| 22348 | std::int32_t ooCount = static_cast<std::int32_t>(vertlist.size()); | |||
| 22349 | if (version > DRW::AC1015) | |||
| 22350 | buf->putBitLong(ooCount); | |||
| 22351 | ||||
| 22352 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 22353 | ||||
| 22354 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 22355 | ||||
| 22356 | if (version < DRW::AC1018) { | |||
| 22357 | // R2000-: first/last vertex handles (absolute hard pointers). | |||
| 22358 | putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.front()->handle); | |||
| 22359 | putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.back()->handle); | |||
| 22360 | } else { | |||
| 22361 | // R2004+: one handle per vertex. | |||
| 22362 | for (const auto& v : vertlist) | |||
| 22363 | putAbsHandle(hb, v ? v->handle : 0u); | |||
| 22364 | } | |||
| 22365 | putAbsHandle(hb, seqEndH.ref); | |||
| 22366 | ||||
| 22367 | return true; | |||
| 22368 | } | |||
| 22369 | ||||
| 22370 | // --------------------------------------------------------------------------- | |||
| 22371 | // DRW_Leader::encodeDwg — OT=45 (AC1015/AC1018/AC1024) | |||
| 22372 | // --------------------------------------------------------------------------- | |||
| 22373 | ||||
| 22374 | bool DRW_Leader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 22375 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 22376 | (void)bs; (void)strBuf; | |||
| 22377 | if (buf == nullptr || !validatePayloadFields()) | |||
| 22378 | return false; | |||
| 22379 | oType = 45; | |||
| 22380 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 22381 | ||||
| 22382 | buf->putBit(0); // unknown bit | |||
| 22383 | buf->putBitShort(static_cast<std::uint16_t>(flag)); // annotation type | |||
| 22384 | buf->putBitShort(static_cast<std::int16_t>(leadertype)); // pathType (DXF code 72) | |||
| 22385 | buf->putBitLong(static_cast<std::int32_t>(vertexlist.size())); | |||
| 22386 | for (const auto& vp : vertexlist) | |||
| 22387 | buf->put3BitDouble(*vp); | |||
| 22388 | buf->put3BitDouble(origin); // leader plane origin | |||
| 22389 | // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — matches parseDwg. | |||
| 22390 | buf->put3BitDouble(extrusionPoint); | |||
| 22391 | ||||
| 22392 | buf->put3BitDouble(horizdir); | |||
| 22393 | buf->put3BitDouble(offsetblock); | |||
| 22394 | ||||
| 22395 | if (leaderHasEndpointProjection(version)) | |||
| 22396 | buf->put3BitDouble(offsettext); // endpoint projection | |||
| 22397 | ||||
| 22398 | if (version < DRW::AC1015) | |||
| 22399 | buf->putBitDouble(0.0); // dimgap (pre-R2000) | |||
| 22400 | ||||
| 22401 | if (leaderHasTextBox(version)) { | |||
| 22402 | buf->putBitDouble(textheight); | |||
| 22403 | buf->putBitDouble(textwidth); | |||
| 22404 | } | |||
| 22405 | ||||
| 22406 | buf->putBit(static_cast<std::uint8_t>(hookline)); | |||
| 22407 | buf->putBit(static_cast<std::uint8_t>(arrow)); | |||
| 22408 | ||||
| 22409 | buf->putBitShort(0); // arrowHeadType (present in every DWG version) | |||
| 22410 | if (version < DRW::AC1015) { | |||
| 22411 | buf->putBitDouble(0.0); // dimasz | |||
| 22412 | buf->putBit(0); // unk | |||
| 22413 | buf->putBit(0); // unk | |||
| 22414 | buf->putBitShort(0); // unk short | |||
| 22415 | buf->putBitShort(static_cast<std::uint16_t>(coloruse)); // byBlock color | |||
| 22416 | buf->putBit(0); // unk | |||
| 22417 | buf->putBit(0); // unk | |||
| 22418 | } else { | |||
| 22419 | buf->putBit(0); // unk | |||
| 22420 | buf->putBit(0); // unk | |||
| 22421 | } | |||
| 22422 | ||||
| 22423 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 22424 | ||||
| 22425 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 22426 | putAbsHandle(hb, 0); // AnnotH — null (no annotation entity) | |||
| 22427 | putAbsHandle(hb, 0x15); // dimStyleH — hard ptr to STANDARD (handle 0x15) | |||
| 22428 | ||||
| 22429 | return buf->isGood() && hb->isGood(); | |||
| 22430 | } | |||
| 22431 | ||||
| 22432 | // --------------------------------------------------------------------------- | |||
| 22433 | // DRW_Viewport::encodeDwg — OT=34 (AC1015/AC1018/AC1024) | |||
| 22434 | // --------------------------------------------------------------------------- | |||
| 22435 | ||||
| 22436 | bool DRW_Viewport::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 22437 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 22438 | (void)bs; | |||
| 22439 | if (buf == nullptr || !validatePayloadFields()) | |||
| 22440 | return false; | |||
| 22441 | oType = 34; | |||
| 22442 | // Use strBuf for TV strings in AC1024; for AC1015/AC1018 strings go inline. | |||
| 22443 | dwgBufferW *sb = (strBuf && version > DRW::AC1018) ? strBuf : buf; | |||
| 22444 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 22445 | ||||
| 22446 | buf->putBitDouble(basePoint.x); | |||
| 22447 | buf->putBitDouble(basePoint.y); | |||
| 22448 | buf->putBitDouble(basePoint.z); | |||
| 22449 | buf->putBitDouble(pswidth); | |||
| 22450 | buf->putBitDouble(psheight); | |||
| 22451 | ||||
| 22452 | if (version > DRW::AC1014) { | |||
| 22453 | buf->putBitDouble(viewTarget.x); | |||
| 22454 | buf->putBitDouble(viewTarget.y); | |||
| 22455 | buf->putBitDouble(viewTarget.z); | |||
| 22456 | buf->putBitDouble(viewDir.x); | |||
| 22457 | buf->putBitDouble(viewDir.y); | |||
| 22458 | buf->putBitDouble(viewDir.z); | |||
| 22459 | buf->putBitDouble(twistAngle); | |||
| 22460 | buf->putBitDouble(viewHeight); | |||
| 22461 | buf->putBitDouble(viewLength); // lens length | |||
| 22462 | buf->putBitDouble(frontClip); | |||
| 22463 | buf->putBitDouble(backClip); | |||
| 22464 | buf->putBitDouble(snapAngle); | |||
| 22465 | buf->putRawDouble(centerPX); | |||
| 22466 | buf->putRawDouble(centerPY); | |||
| 22467 | buf->putRawDouble(snapPX); | |||
| 22468 | buf->putRawDouble(snapPY); | |||
| 22469 | buf->putRawDouble(snapSpPX); | |||
| 22470 | buf->putRawDouble(snapSpPY); | |||
| 22471 | buf->putRawDouble(gridSpX); | |||
| 22472 | buf->putRawDouble(gridSpY); | |||
| 22473 | buf->putBitShort(static_cast<std::uint16_t>(circleZoom)); | |||
| 22474 | } | |||
| 22475 | ||||
| 22476 | if (version > DRW::AC1018) | |||
| 22477 | buf->putBitShort(static_cast<std::uint16_t>(majorGridLines)); | |||
| 22478 | ||||
| 22479 | if (version > DRW::AC1014) { | |||
| 22480 | buf->putBitLong(static_cast<std::int32_t>(frozenLayerHandles.size())); | |||
| 22481 | buf->putBitLong(statusFlags); | |||
| 22482 | sb->putVariableText(version, styleSheet); | |||
| 22483 | buf->putRawChar8(static_cast<std::uint8_t>(renderMode)); | |||
| 22484 | buf->putBit(ucsAtOrigin ? 1 : 0); | |||
| 22485 | buf->putBit(ucsPerViewport ? 1 : 0); | |||
| 22486 | buf->put3BitDouble(ucsOrigin); | |||
| 22487 | buf->put3BitDouble(ucsXAxis); | |||
| 22488 | buf->put3BitDouble(ucsYAxis); | |||
| 22489 | buf->putBitDouble(ucsElevation); | |||
| 22490 | buf->putBitShort(static_cast<std::uint16_t>(ucsOrthographicType)); | |||
| 22491 | } | |||
| 22492 | ||||
| 22493 | if (version > DRW::AC1015) | |||
| 22494 | buf->putBitShort(static_cast<std::uint16_t>(shadePlotMode)); | |||
| 22495 | ||||
| 22496 | if (version > DRW::AC1018) { | |||
| 22497 | buf->putBit(useDefaultLighting ? 1 : 0); | |||
| 22498 | buf->putRawChar8(defaultLightingType); | |||
| 22499 | buf->putBitDouble(brightness); | |||
| 22500 | buf->putBitDouble(contrast); | |||
| 22501 | if (ambientColorRgb >= 0) { | |||
| 22502 | buf->putCmColor(version, static_cast<std::uint16_t>(ambientColor), | |||
| 22503 | ambientColorRgb, ambientColorName, "", strBuf); | |||
| 22504 | } else { | |||
| 22505 | buf->putCmColor(version, static_cast<std::uint16_t>(ambientColor)); | |||
| 22506 | } | |||
| 22507 | } | |||
| 22508 | ||||
| 22509 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 22510 | ||||
| 22511 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 22512 | ||||
| 22513 | if (version < DRW::AC1015) { | |||
| 22514 | putTypedHandle(hb, vpHeaderHandle, 5); | |||
| 22515 | } | |||
| 22516 | if (version > DRW::AC1014) { | |||
| 22517 | const std::uint8_t frozenCode = version == DRW::AC1015 ? 5 : 4; | |||
| 22518 | for (const std::uint32_t ref : frozenLayerHandles) | |||
| 22519 | putTypedHandle(hb, ref, frozenCode); | |||
| 22520 | putTypedHandle(hb, clipBoundaryHandle, 4); | |||
| 22521 | if (version == DRW::AC1015) | |||
| 22522 | putTypedHandle(hb, vpHeaderHandle, 5); | |||
| 22523 | putTypedHandle(hb, namedUcsHandle, 5); | |||
| 22524 | putTypedHandle(hb, baseUcsHandle, 5); | |||
| 22525 | } | |||
| 22526 | if (version > DRW::AC1018) { | |||
| 22527 | putTypedHandle(hb, backgroundHandle, 4); | |||
| 22528 | putTypedHandle(hb, visualStyleHandle, 5); | |||
| 22529 | putTypedHandle(hb, shadePlotHandle, 4); | |||
| 22530 | putTypedHandle(hb, m_sunHandle, 3); | |||
| 22531 | } | |||
| 22532 | ||||
| 22533 | return buf->isGood() && sb->isGood() && hb->isGood(); | |||
| 22534 | } |