Bug Summary

File:libraries/libdxfrw/src/drw_entities.cpp
Warning:line 6859, column 5
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name drw_entities.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/runner/work/LibreCAD/LibreCAD/libraries/libdxfrw -fcoverage-compilation-dir=/home/runner/work/LibreCAD/LibreCAD/libraries/libdxfrw -resource-dir /usr/lib/llvm-18/lib/clang/18 -D _REENTRANT -D MUPARSER_STATIC -D QT_NO_DEBUG -I . -I ../../../Qt/6.9.0/gcc_64/mkspecs/linux-g++ -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=gnu++1z -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/runner/work/LibreCAD/LibreCAD/out/2026-07-14-153100-5089-1 -x c++ src/drw_entities.cpp
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 <cmath>
17#include <cstdio>
18#include <cstdlib>
19#include <cstring>
20#include <limits>
21#include <vector>
22#include "drw_entities.h"
23#include "intern/dxfreader.h"
24#include "intern/dwgbuffer.h"
25#include "intern/dwgbufferw.h"
26#include "intern/drw_textcodec.h"
27#include "intern/drw_dbg.h"
28#include "intern/drw_reserve.h"
29#include "intern/dwgreader.h"
30
31namespace {
32
33constexpr std::uint32_t kMaxTableRows = 10000;
34constexpr std::uint32_t kMaxTableColumns = 1000;
35constexpr std::uint32_t kMaxTableCells = 200000;
36constexpr std::uint32_t kMaxTableItems = 100000;
37constexpr std::uint32_t kMaxTableStringBytes = 16 * 1024 * 1024;
38constexpr std::int32_t kMaxLWPolylineVertices = 1000000;
39constexpr std::int32_t kMaxSplineItems = 1000000;
40constexpr std::int32_t kMaxSplineDegree = 1024;
41
42constexpr std::int32_t kSplineFlagMethodFitPoints = 1;
43constexpr std::int32_t kSplineFlagClosed = 4;
44constexpr std::int32_t kSplineFlagUseKnotParameter = 8;
45constexpr std::int32_t kSplineKnotParamCustom = 15;
46
47bool isValidCount(std::int32_t count, std::int32_t maxCount) {
48 return count >= 0 && count <= maxCount;
49}
50
51int hexNibble(char c) {
52 if (c >= '0' && c <= '9')
53 return c - '0';
54 if (c >= 'A' && c <= 'F')
55 return c - 'A' + 10;
56 if (c >= 'a' && c <= 'f')
57 return c - 'a' + 10;
58 return -1;
59}
60
61bool decodeHexBytes(const std::string& hex, std::vector<std::uint8_t>& out) {
62 if ((hex.size() % 2) != 0)
63 return false;
64
65 std::vector<std::uint8_t> decoded;
66 decoded.reserve(hex.size() / 2);
67 for (std::size_t i = 0; i < hex.size(); i += 2) {
68 const int hi = hexNibble(hex[i]);
69 const int lo = hexNibble(hex[i + 1]);
70 if (hi < 0 || lo < 0)
71 return false;
72 decoded.push_back(static_cast<std::uint8_t>((hi << 4) | lo));
73 }
74
75 out = std::move(decoded);
76 return true;
77}
78
79void appendBytes(std::vector<std::uint8_t>& out,
80 const std::vector<std::uint8_t>& bytes) {
81 out.insert(out.end(), bytes.begin(), bytes.end());
82}
83
84void appendTextBytes(std::vector<std::uint8_t>& out, const std::string& text) {
85 out.insert(out.end(), text.begin(), text.end());
86}
87
88std::uint64_t currentDwgBit(const dwgBuffer *buf) {
89 return buf->getPosition() * 8 + buf->getBitPos();
90}
91
92DRW_DwgSubrecordRange makeDwgSubrecordRange(const char *name, std::uint64_t startBit,
93 std::uint64_t endBit, DRW::Version version,
94 std::uint32_t count, bool parseComplete) {
95 DRW_DwgSubrecordRange range;
96 range.m_name = name;
97 range.m_startBit = startBit;
98 range.m_bitSize = endBit >= startBit ? endBit - startBit : 0;
99 range.m_version = version;
100 range.m_count = count;
101 range.m_parseComplete = parseComplete;
102 return range;
103}
104
105bool isValidSplineDegree(int degree) {
106 return degree >= 1 && degree <= kMaxSplineDegree;
107}
108
109bool isValidControlSplineLayout(int degree, std::int32_t knotCount, std::int32_t controlCount) {
110 if (!isValidSplineDegree(degree) || !isValidCount(knotCount, kMaxSplineItems) ||
111 !isValidCount(controlCount, kMaxSplineItems)) {
112 return false;
113 }
114
115 if (controlCount < degree + 1) {
116 return false;
117 }
118
119 const std::int64_t expectedKnots = static_cast<std::int64_t>(controlCount) + degree + 1;
120 return expectedKnots <= kMaxSplineItems && knotCount == expectedKnots;
121}
122
123bool isValidFitSplineLayout(int degree, std::int32_t fitCount) {
124 return isValidSplineDegree(degree) && isValidCount(fitCount, kMaxSplineItems) &&
125 fitCount >= 2;
126}
127
128bool differsFromUnitWeight(double weight) {
129 return std::fabs(weight - 1.0) > 1e-12;
130}
131
132void putHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) {
133 dwgHandle h;
134 h.code = 5;
135 h.ref = ref;
136 h.size = 0;
137 if (ref != 0) {
138 std::uint32_t t = ref;
139 while (t != 0) {
140 t >>= 8;
141 ++h.size;
142 }
143 }
144 buf->putHandle(h);
145}
146
147void putNullableHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) {
148 dwgHandle h;
149 h.code = ref == 0 ? 0 : 5;
150 h.ref = ref;
151 h.size = 0;
152 if (ref != 0) {
153 std::uint32_t t = ref;
154 while (t != 0) {
155 t >>= 8;
156 ++h.size;
157 }
158 }
159 buf->putHandle(h);
160}
161
162std::uint16_t bitShortFromInt(int value) {
163 if (value < 0)
164 return 0;
165 if (value > 0xffff)
166 return 0xffff;
167 return static_cast<std::uint16_t>(value);
168}
169
170std::uint32_t readTableHandle(dwgBuffer *hdlBuf) {
171 if (hdlBuf == nullptr || !hdlBuf->isGood())
172 return 0;
173 dwgHandle h = hdlBuf->getHandle();
174 return h.ref;
175}
176
177void seekTableObjectHandleStream(DRW::Version version, dwgBuffer *buf, std::uint32_t objSize) {
178 if (version > DRW::AC1018) {
179 buf->setPosition(objSize >> 3);
180 buf->setBitPos(objSize & 7);
181 }
182}
183
184void readTableObjectCommonHandles(dwgBuffer *buf, std::uint32_t baseHandle,
185 std::int32_t numReactors, std::uint8_t xDictFlag,
186 int *parentHandle) {
187 dwgHandle parentH = buf->getOffsetHandle(baseHandle);
188 if (parentHandle)
189 *parentHandle = parentH.ref;
190 for (int i = 0; i < numReactors; ++i)
191 buf->getOffsetHandle(baseHandle);
192 if (xDictFlag != 1)
193 buf->getOffsetHandle(baseHandle);
194}
195
196bool readTableValueBytes(dwgBuffer *buf, std::vector<std::uint8_t>& raw, const char *label) {
197 const std::uint32_t byteCount = buf->getBitLong();
198 if (byteCount > kMaxTableStringBytes) {
199 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");
200 return false;
201 }
202 raw.resize(byteCount);
203 const bool good = byteCount == 0 || buf->getBytes(raw.data(), raw.size());
204 if (!good) {
205 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);
206 DRW_DBG(" remaining: ")DRW_dbg::dbg(" remaining: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n");
207 }
208 return good;
209}
210
211UTF8STRINGstd::string decodeTableValueText(DRW::Version version, dwgBuffer *buf, const std::vector<std::uint8_t>& raw) {
212 if (raw.empty())
213 return UTF8STRINGstd::string();
214 std::string s(reinterpret_cast<const char*>(raw.data()), raw.size());
215 if (version > DRW::AC1018 && s.size() >= 2 && s[s.size() - 1] == '\0'
216 && s[s.size() - 2] == '\0') {
217 s.resize(s.size() - 2);
218 } else {
219 while (!s.empty() && s.back() == '\0')
220 s.pop_back();
221 }
222 if (buf->decoder)
223 s = buf->decoder->toUtf8(s);
224 return s;
225}
226
227UTF8STRINGstd::string readTableText(DRW::Version version, dwgBuffer *buf) {
228 if (!buf)
229 return UTF8STRINGstd::string();
230 if (version <= DRW::AC1018)
231 return buf->getVariableText(version, false);
232
233 const std::uint32_t byteLen = buf->getBitShort();
234 if (byteLen == 0)
235 return UTF8STRINGstd::string();
236 if (byteLen > kMaxTableStringBytes) {
237 DRW_DBG("TABLE text byte length invalid: ")DRW_dbg::dbg("TABLE text byte length invalid: "); DRW_DBG(byteLen)DRW_dbg::dbg(byteLen); DRW_DBG("\n")DRW_dbg::dbg("\n");
238 return UTF8STRINGstd::string();
239 }
240
241 std::vector<std::uint8_t> raw(static_cast<size_t>(byteLen) + 2, 0);
242 if (!buf->getBytes(raw.data(), byteLen))
243 return UTF8STRINGstd::string();
244
245 std::string s(reinterpret_cast<const char*>(raw.data()), byteLen);
246 if (buf->decoder)
247 s = buf->decoder->toUtf8(s);
248 return s;
249}
250
251bool readTableValuePoint(dwgBuffer *buf, DRW_CadValue& value, int dimensions) {
252 value.m_dataSize = static_cast<std::uint32_t>(buf->getBitLong());
253 const std::uint32_t expectedSize = static_cast<std::uint32_t>(dimensions) * 8;
254 if (value.m_dataSize > kMaxTableStringBytes)
255 return false;
256 if (value.m_dataSize < expectedSize) {
257 value.m_rawData.resize(value.m_dataSize);
258 if (value.m_dataSize > 0 && !buf->getBytes(value.m_rawData.data(), value.m_rawData.size()))
259 return false;
260 value.m_value.addBinary(310, value.m_rawData);
261 return true;
262 }
263
264 DRW_Coord c;
265 c.x = buf->getRawDouble();
266 c.y = buf->getRawDouble();
267 c.z = dimensions == 3 ? buf->getRawDouble() : 0.0;
268 value.m_value.addCoord(11, c);
269
270 const std::uint32_t extraBytes = value.m_dataSize - expectedSize;
271 value.m_rawData.resize(extraBytes);
272 return extraBytes == 0 || buf->getBytes(value.m_rawData.data(), value.m_rawData.size());
273}
274
275bool readTableCadValue(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
276 dwgBuffer *hdlBuf, DRW_CadValue& value) {
277 if (version > DRW::AC1018)
278 value.m_formatFlags = buf->getBitLong();
279
280 value.m_dataType = buf->getBitLong();
281 const bool emptyR2007Value = version > DRW::AC1018 && (value.m_formatFlags & 3);
282 if (!emptyR2007Value) {
283 switch (value.m_dataType) {
284 case 0:
285 case 1:
286 value.m_value.addInt(91, buf->getBitLong());
287 break;
288 case 2:
289 value.m_value.addDouble(140, buf->getBitDouble());
290 break;
291 case 4:
292 case 512:
293 if (!readTableValueBytes(buf, value.m_rawData, "TABLE value byte payload"))
294 return false;
295 value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size());
296 value.m_value.addString(1, decodeTableValueText(version, buf, value.m_rawData));
297 break;
298 case 8: {
299 if (!readTableValueBytes(buf, value.m_rawData, "TABLE value date payload"))
300 return false;
301 value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size());
302 value.m_value.addBinary(310, value.m_rawData);
303 break;
304 }
305 case 16:
306 if (!readTableValuePoint(buf, value, 2))
307 return false;
308 break;
309 case 32:
310 if (!readTableValuePoint(buf, value, 3))
311 return false;
312 break;
313 case 64:
314 value.m_handle = readTableHandle(hdlBuf);
315 value.m_value.addInt(330, static_cast<std::uint32_t>(value.m_handle));
316 break;
317 case 128:
318 case 256:
319 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");
320 return false;
321 default:
322 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");
323 return false;
324 }
325 }
326
327 if (version > DRW::AC1018) {
328 dwgBuffer *textBuf = strBuf ? strBuf : buf;
329 value.m_unitType = buf->getBitLong();
330 value.m_formatString = readTableText(version, textBuf);
331 value.m_valueString = readTableText(version, textBuf);
332 }
333
334 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
335 if (!good) {
336 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);
337 DRW_DBG(" type: ")DRW_dbg::dbg(" type: "); DRW_DBG(value.m_dataType)DRW_dbg::dbg(value.m_dataType);
338 DRW_DBG(" unit: ")DRW_dbg::dbg(" unit: "); DRW_DBG(value.m_unitType)DRW_dbg::dbg(value.m_unitType);
339 DRW_DBG(" bufGood: ")DRW_dbg::dbg(" bufGood: "); DRW_DBG(buf->isGood() ? 1 : 0)DRW_dbg::dbg(buf->isGood() ? 1 : 0);
340 DRW_DBG(" strGood: ")DRW_dbg::dbg(" strGood: "); DRW_DBG((!strBuf || strBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!strBuf || strBuf->isGood()) ? 1 : 0);
341 DRW_DBG(" hdlGood: ")DRW_dbg::dbg(" hdlGood: "); DRW_DBG((!hdlBuf || hdlBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!hdlBuf || hdlBuf->isGood()) ? 1 : 0);
342 DRW_DBG(" bufPos: ")DRW_dbg::dbg(" bufPos: "); DRW_DBG(buf->getPosition())DRW_dbg::dbg(buf->getPosition());
343 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);
344 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);
345 DRW_DBG("\n")DRW_dbg::dbg("\n");
346 }
347 return good;
348}
349
350bool skipTableCustomData(DRW::Version version, dwgBuffer *buf,
351 dwgBuffer *strBuf, dwgBuffer *hdlBuf) {
352 dwgBuffer *textBuf = strBuf ? strBuf : buf;
353 UTF8STRINGstd::string key = readTableText(version, textBuf);
354 if (strBuf && !strBuf->isGood()) {
355 DRW_DBG("TABLE custom data key string read failed\n")DRW_dbg::dbg("TABLE custom data key string read failed\n");
356 return false;
357 }
358 DRW_CadValue value;
359 const bool good = readTableCadValue(version, buf, strBuf, hdlBuf, value);
360 if (!good) {
361 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");
362 }
363 return good;
364}
365
366void readTableCmColor(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf) {
367 dwgBuffer *textBuf = strBuf ? strBuf : buf;
368 if (version < DRW::AC1018) {
369 buf->getSBitShort();
370 return;
371 }
372
373 buf->getBitShort();
374 const std::uint32_t rgb = buf->getBitLong();
375 const std::uint8_t colorFlags = buf->getRawChar8();
376 DRW_DBG("\ntype COLOR: ")DRW_dbg::dbg("\ntype COLOR: "); DRW_DBGH(rgb >> 24)DRW_dbg::dbgH(rgb >> 24);
377 DRW_DBG("\nRGB COLOR: ")DRW_dbg::dbg("\nRGB COLOR: "); DRW_DBGH(rgb)DRW_dbg::dbgH(rgb);
378 DRW_DBG("\nbyte COLOR: ")DRW_dbg::dbg("\nbyte COLOR: "); DRW_DBGH(colorFlags)DRW_dbg::dbgH(colorFlags);
379 if (colorFlags & 1)
380 readTableText(version, textBuf);
381 if (colorFlags & 2)
382 readTableText(version, textBuf);
383}
384
385bool skipR2007TableCellOverrides(DRW::Version version, dwgBuffer *buf,
386 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
387 DRW_TableCell& cell,
388 std::vector<DRW_DwgSubrecordRange> *ranges) {
389 const std::uint64_t startBit = currentDwgBit(buf);
390 cell.m_overrideFlags = static_cast<std::uint32_t>(buf->getBitLong());
391 cell.m_virtualEdgeFlags = buf->getRawChar8();
392
393 if (cell.m_overrideFlags & 0x00001)
394 buf->getRawShort16();
395 if (cell.m_overrideFlags & 0x00002)
396 buf->getBit();
397 if (cell.m_overrideFlags & 0x00004)
398 readTableCmColor(version, buf, strBuf);
399 if (cell.m_overrideFlags & 0x00008)
400 readTableCmColor(version, buf, strBuf);
401 if (cell.m_overrideFlags & 0x00010)
402 cell.m_textStyleOverrideHandle = readTableHandle(hdlBuf);
403 if (cell.m_overrideFlags & 0x00020)
404 buf->getBitDouble();
405 if (cell.m_overrideFlags & 0x00040)
406 readTableCmColor(version, buf, strBuf);
407 if (cell.m_overrideFlags & 0x00400)
408 buf->getBitShort();
409 if (cell.m_overrideFlags & 0x04000)
410 buf->getBitShort();
411 if (cell.m_overrideFlags & 0x00080)
412 readTableCmColor(version, buf, strBuf);
413 if (cell.m_overrideFlags & 0x00800)
414 buf->getBitShort();
415 if (cell.m_overrideFlags & 0x08000)
416 buf->getBitShort();
417 if (cell.m_overrideFlags & 0x00100)
418 readTableCmColor(version, buf, strBuf);
419 if (cell.m_overrideFlags & 0x01000)
420 buf->getBitShort();
421 if (cell.m_overrideFlags & 0x10000)
422 buf->getBitShort();
423 if (cell.m_overrideFlags & 0x00200)
424 readTableCmColor(version, buf, strBuf);
425 if (cell.m_overrideFlags & 0x02000)
426 buf->getBitShort();
427 if (cell.m_overrideFlags & 0x20000)
428 buf->getBitShort();
429
430 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
431 if (ranges != nullptr) {
432 ranges->push_back(makeDwgSubrecordRange(
433 "r2007-table-cell-overrides", startBit, currentDwgBit(buf),
434 version, cell.m_overrideFlags, good));
435 }
436 return good;
437}
438
439bool parseR2007TableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
440 dwgBuffer *hdlBuf, DRW_TableCell& cell,
441 std::vector<DRW_DwgSubrecordRange> *ranges) {
442 dwgBuffer *textBuf = strBuf ? strBuf : buf;
443 cell.m_type = buf->getBitShort();
444 cell.m_edgeFlags = buf->getRawChar8();
445 cell.m_isMerged = buf->getBit() != 0;
446 cell.m_autoFit = buf->getBit() != 0;
447 cell.m_mergedWidth = buf->getBitLong();
448 cell.m_mergedHeight = buf->getBitLong();
449 cell.m_rotation = buf->getBitDouble();
450 cell.m_valueHandle = readTableHandle(hdlBuf);
451
452 if (cell.m_type == 1) {
453 cell.m_textStyleHandle = cell.m_valueHandle;
454 if (cell.m_textStyleHandle == 0 && version < DRW::AC1021) {
455 DRW_TableCellContent content;
456 content.m_type = 1;
457 content.m_text = readTableText(version, textBuf);
458 content.m_value.m_dataType = 4;
459 content.m_value.m_value.addString(1, content.m_text);
460 cell.m_contents.push_back(content);
461 }
462 } else if (cell.m_type == 2) {
463 cell.m_blockHandle = cell.m_valueHandle;
464 cell.m_blockScale = buf->getBitDouble();
465 if (buf->getBit() != 0) {
466 const std::uint16_t numAttributes = buf->getBitShort();
467 cell.m_attributes.reserve(numAttributes);
468 for (std::uint16_t i = 0; i < numAttributes; ++i) {
469 DRW_TableCellAttribute attribute;
470 attribute.m_attdefHandle = readTableHandle(hdlBuf);
471 attribute.m_index = buf->getBitShort();
472 attribute.m_text = readTableText(version, textBuf);
473 cell.m_attributes.push_back(attribute);
474 }
475 }
476
477 DRW_TableCellContent content;
478 content.m_type = 4;
479 content.m_handle = cell.m_blockHandle;
480 cell.m_contents.push_back(content);
481 }
482
483 if (buf->getBit() != 0
484 && !skipR2007TableCellOverrides(version, buf, strBuf, hdlBuf, cell, ranges))
485 return false;
486
487 if (version > DRW::AC1018) {
488 buf->getBitLong();
489 DRW_TableCellContent content;
490 content.m_type = 1;
491 if (!readTableCadValue(version, buf, strBuf, hdlBuf, content.m_value))
492 return false;
493 if (content.m_value.m_value.type() == DRW_Variant::STRING)
494 content.m_text = content.m_value.m_value.c_str();
495 else if (!content.m_value.m_valueString.empty())
496 content.m_text = content.m_value.m_valueString;
497 cell.m_contents.push_back(content);
498 }
499
500 return buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
501}
502
503bool skipR2007TableOverrides(DRW::Version version, dwgBuffer *buf,
504 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
505 std::vector<DRW_DwgSubrecordRange> *ranges = nullptr) {
506 const std::uint64_t startBit = currentDwgBit(buf);
507 std::uint32_t maskCount = 0;
508 if (buf->getBit() != 0) {
509 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
510 ++maskCount;
511 if (flags & 0x000001)
512 buf->getBit();
513 if (flags & 0x000004)
514 buf->getBitShort();
515 if (flags & 0x000008)
516 buf->getBitDouble();
517 if (flags & 0x000010)
518 buf->getBitDouble();
519 if (flags & 0x000020)
520 readTableCmColor(version, buf, strBuf);
521 if (flags & 0x000040)
522 readTableCmColor(version, buf, strBuf);
523 if (flags & 0x000080)
524 readTableCmColor(version, buf, strBuf);
525 if (flags & 0x000100)
526 buf->getBit();
527 if (flags & 0x000200)
528 buf->getBit();
529 if (flags & 0x000400)
530 buf->getBit();
531 if (flags & 0x000800)
532 readTableCmColor(version, buf, strBuf);
533 if (flags & 0x001000)
534 readTableCmColor(version, buf, strBuf);
535 if (flags & 0x002000)
536 readTableCmColor(version, buf, strBuf);
537 if (flags & 0x004000)
538 buf->getBitShort();
539 if (flags & 0x008000)
540 buf->getBitShort();
541 if (flags & 0x010000)
542 buf->getBitShort();
543 if (flags & 0x020000)
544 readTableHandle(hdlBuf);
545 if (flags & 0x040000)
546 readTableHandle(hdlBuf);
547 if (flags & 0x080000)
548 readTableHandle(hdlBuf);
549 if (flags & 0x100000)
550 buf->getBitDouble();
551 if (flags & 0x200000)
552 buf->getBitDouble();
553 if (flags & 0x400000)
554 buf->getBitDouble();
555 }
556
557 if (buf->getBit() != 0) {
558 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
559 ++maskCount;
560 for (int i = 0; i < 18; ++i) {
561 if (flags & (1u << i))
562 readTableCmColor(version, buf, strBuf);
563 }
564 }
565
566 if (buf->getBit() != 0) {
567 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
568 ++maskCount;
569 for (int i = 0; i < 18; ++i) {
570 if (flags & (1u << i))
571 buf->getBitShort();
572 }
573 }
574
575 if (buf->getBit() != 0) {
576 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
577 ++maskCount;
578 for (int i = 0; i < 18; ++i) {
579 if (flags & (1u << i))
580 buf->getBitShort();
581 }
582 }
583
584 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
585 if (ranges != nullptr && (maskCount != 0 || currentDwgBit(buf) != startBit)) {
586 ranges->push_back(makeDwgSubrecordRange(
587 "r2007-table-overrides", startBit, currentDwgBit(buf),
588 version, maskCount, good));
589 }
590 return good;
591}
592
593bool skipTableContentFormat(DRW::Version version, dwgBuffer *buf,
594 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
595 std::vector<DRW_DwgSubrecordRange> *ranges = nullptr) {
596 const std::uint64_t startBit = currentDwgBit(buf);
597 dwgBuffer *textBuf = strBuf ? strBuf : buf;
598 buf->getBitLong(); // property override flags
599 buf->getBitLong(); // property flags
600 buf->getBitLong(); // value data type
601 buf->getBitLong(); // value unit type
602 readTableText(version, textBuf);
603 buf->getBitDouble(); // rotation
604 buf->getBitDouble(); // block scale
605 buf->getBitLong(); // alignment
606 std::int32_t rgb = -1;
607 UTF8STRINGstd::string name;
608 UTF8STRINGstd::string book;
609 buf->getCmColor(version, &rgb, textBuf, &name, &book);
610 readTableHandle(hdlBuf); // text style
611 buf->getBitDouble(); // text height
612 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
613 if (ranges != nullptr) {
614 ranges->push_back(makeDwgSubrecordRange(
615 "table-content-format", startBit, currentDwgBit(buf),
616 version, 1, good));
617 }
618 return good;
619}
620
621bool skipTableCellStyle(DRW::Version version, dwgBuffer *buf,
622 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
623 std::vector<DRW_DwgSubrecordRange> *ranges = nullptr) {
624 const std::uint64_t startBit = currentDwgBit(buf);
625 buf->getBitLong(); // style type
626 const bool hasData = buf->getBitShort() != 0;
627 if (!hasData) {
628 if (ranges != nullptr) {
629 ranges->push_back(makeDwgSubrecordRange(
630 "table-cell-style", startBit, currentDwgBit(buf),
631 version, 0, buf->isGood()));
632 }
633 return buf->isGood();
634 }
635
636 buf->getBitLong(); // property override flags
637 buf->getBitLong(); // merge flags
638 std::int32_t rgb = -1;
639 UTF8STRINGstd::string name;
640 UTF8STRINGstd::string book;
641 dwgBuffer *textBuf = strBuf ? strBuf : buf;
642 buf->getCmColor(version, &rgb, textBuf, &name, &book);
643 buf->getBitLong(); // content layout
644 if (!skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges))
645 return false;
646
647 const std::uint16_t marginFlags = buf->getBitShort();
648 if (marginFlags != 0) {
649 for (int i = 0; i < 6; ++i)
650 buf->getBitDouble();
651 }
652
653 const std::uint32_t borders = buf->getBitLong();
654 if (borders > 6) {
655 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");
656 return false;
657 }
658 for (std::uint32_t i = 0; i < borders; ++i) {
659 const std::uint32_t edgeFlags = buf->getBitLong();
660 if (edgeFlags == 0)
661 continue;
662 buf->getBitLong(); // border overrides
663 buf->getBitLong(); // border type
664 buf->getCmColor(version, &rgb, textBuf, &name, &book);
665 buf->getBitLong(); // line weight
666 readTableHandle(hdlBuf); // linetype
667 buf->getBitLong(); // visible/invisible
668 buf->getBitDouble(); // double line spacing
669 }
670
671 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
672 if (ranges != nullptr) {
673 ranges->push_back(makeDwgSubrecordRange(
674 "table-cell-style", startBit, currentDwgBit(buf),
675 version, borders, good));
676 }
677 return good;
678}
679
680bool parseTableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
681 dwgBuffer *hdlBuf, DRW_TableCell& cell,
682 std::vector<DRW_DwgSubrecordRange> *ranges) {
683 dwgBuffer *textBuf = strBuf ? strBuf : buf;
684 cell.m_flags = buf->getBitLong();
685 cell.m_toolTip = readTableText(version, textBuf);
686 if (strBuf && !strBuf->isGood()) {
687 DRW_DBG("TABLE cell tooltip string read failed\n")DRW_dbg::dbg("TABLE cell tooltip string read failed\n");
688 return false;
689 }
690 buf->getBitLong(); // custom data
691
692 const std::uint32_t customItems = buf->getBitLong();
693 if (customItems > kMaxTableItems) {
694 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");
695 return false;
696 }
697 for (std::uint32_t i = 0; i < customItems; ++i) {
698 if (!skipTableCustomData(version, buf, strBuf, hdlBuf)) {
699 DRW_DBG("TABLE cell custom data parse incomplete\n")DRW_dbg::dbg("TABLE cell custom data parse incomplete\n");
700 return false;
701 }
702 }
703
704 if (buf->getBitLong() != 0) {
705 readTableHandle(hdlBuf);
706 buf->getBitLong();
707 buf->getBitLong();
708 buf->getBitLong();
709 }
710
711 const std::uint32_t contentCount = buf->getBitLong();
712 if (contentCount > kMaxTableItems) {
713 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");
714 return false;
715 }
716 cell.m_contents.reserve(contentCount);
717 for (std::uint32_t i = 0; i < contentCount; ++i) {
718 DRW_TableCellContent content;
719 content.m_type = buf->getBitLong();
720 if (content.m_type == 1) {
721 if (!readTableCadValue(version, buf, strBuf, hdlBuf, content.m_value)) {
722 DRW_DBG("TABLE cell value parse incomplete\n")DRW_dbg::dbg("TABLE cell value parse incomplete\n");
723 return false;
724 }
725 if (content.m_value.m_value.type() == DRW_Variant::STRING)
726 content.m_text = content.m_value.m_value.c_str();
727 else if (!content.m_value.m_valueString.empty())
728 content.m_text = content.m_value.m_valueString;
729 } else if (content.m_type == 2 || content.m_type == 4) {
730 content.m_handle = readTableHandle(hdlBuf);
731 }
732
733 const std::uint32_t numAttrs = buf->getBitLong();
734 if (numAttrs > kMaxTableItems) {
735 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");
736 return false;
737 }
738 for (std::uint32_t attr = 0; attr < numAttrs; ++attr) {
739 readTableHandle(hdlBuf);
740 readTableText(version, textBuf);
741 buf->getBitLong();
742 }
743
744 const bool hasContentFormat = buf->getBitShort() != 0;
745 if (hasContentFormat
746 && !skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges)) {
747 DRW_DBG("TABLE cell content format parse incomplete\n")DRW_dbg::dbg("TABLE cell content format parse incomplete\n");
748 return false;
749 }
750 cell.m_contents.push_back(content);
751 }
752
753 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, ranges)) {
754 DRW_DBG("TABLE cell style override parse incomplete\n")DRW_dbg::dbg("TABLE cell style override parse incomplete\n");
755 return false;
756 }
757
758 cell.m_styleId = buf->getBitLong();
759 const std::uint64_t geometryStartBit = currentDwgBit(buf);
760 const std::uint32_t hasGeometry = buf->getBitLong();
761 if (hasGeometry != 0) {
762 buf->getBitLong(); // unknown AC1027+ geometry marker
763 cell.m_width = buf->getBitDouble();
764 cell.m_height = buf->getBitDouble();
765 cell.m_geometryFlags = buf->getBitLong();
766 cell.m_geometryHandle = readTableHandle(hdlBuf);
767 if (cell.m_geometryFlags != 0) {
768 cell.m_geometryTopLeft = buf->get3BitDouble();
769 cell.m_geometryCenter = buf->get3BitDouble();
770 cell.m_contentWidth = buf->getBitDouble();
771 cell.m_contentHeight = buf->getBitDouble();
772 cell.m_geometryWidth = buf->getBitDouble();
773 cell.m_geometryHeight = buf->getBitDouble();
774 cell.m_geometryRecordFlags = buf->getBitLong();
775 }
776 if (ranges != nullptr) {
777 const bool geometryGood = buf->isGood() && (!hdlBuf || hdlBuf->isGood());
778 ranges->push_back(makeDwgSubrecordRange(
779 "table-cell-geometry-tail", geometryStartBit, currentDwgBit(buf),
780 version, cell.m_geometryFlags, geometryGood));
781 }
782 }
783
784 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
785 if (!good)
786 DRW_DBG("TABLE cell stream ended unexpectedly\n")DRW_dbg::dbg("TABLE cell stream ended unexpectedly\n");
787 return good;
788}
789
790bool parseTableContent(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
791 dwgBuffer *hdlBuf, DRW_TableContent& content) {
792 dwgBuffer *textBuf = strBuf ? strBuf : buf;
793 content.m_name = readTableText(version, textBuf);
794 content.m_description = readTableText(version, textBuf);
795
796 const std::uint32_t columns = buf->getBitLong();
797 if (columns > kMaxTableColumns) {
798 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");
799 return false;
800 }
801 content.m_columns.clear();
802 content.m_columns.reserve(columns);
803 for (std::uint32_t col = 0; col < columns; ++col) {
804 DRW_TableColumn column;
805 column.m_name = readTableText(version, textBuf);
806 buf->getBitLong(); // custom data
807 const std::uint32_t customItems = buf->getBitLong();
808 if (customItems > kMaxTableItems) {
809 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");
810 return false;
811 }
812 for (std::uint32_t i = 0; i < customItems; ++i) {
813 if (!skipTableCustomData(version, buf, strBuf, hdlBuf)) {
814 DRW_DBG("TABLECONTENT column custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column custom data parse incomplete\n"
)
;
815 return false;
816 }
817 }
818 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf,
819 &content.m_subrecordRanges)) {
820 DRW_DBG("TABLECONTENT column cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column cell style parse incomplete\n"
)
;
821 return false;
822 }
823 buf->getBitLong(); // style id
824 column.m_width = buf->getBitDouble();
825 content.m_columns.push_back(column);
826 }
827
828 const std::uint32_t rows = buf->getBitLong();
829 if (rows > kMaxTableRows || (columns != 0 && rows > kMaxTableCells / columns)) {
830 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");
831 return false;
832 }
833 content.m_rows.clear();
834 content.m_rows.reserve(rows);
835 for (std::uint32_t rowIndex = 0; rowIndex < rows; ++rowIndex) {
836 DRW_TableRow row;
837 const std::uint32_t cells = buf->getBitLong();
838 if (cells > kMaxTableColumns || cells > kMaxTableItems) {
839 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");
840 return false;
841 }
842 row.m_cells.reserve(cells);
843 for (std::uint32_t cellIndex = 0; cellIndex < cells; ++cellIndex) {
844 DRW_TableCell cell;
845 if (!parseTableCell(version, buf, strBuf, hdlBuf, cell,
846 &content.m_subrecordRanges)) {
847 DRW_DBG("TABLECONTENT cell parse incomplete at row ")DRW_dbg::dbg("TABLECONTENT cell parse incomplete at row "); DRW_DBG(rowIndex)DRW_dbg::dbg(rowIndex);
848 DRW_DBG(" cell ")DRW_dbg::dbg(" cell "); DRW_DBG(cellIndex)DRW_dbg::dbg(cellIndex); DRW_DBG("\n")DRW_dbg::dbg("\n");
849 return false;
850 }
851 row.m_cells.push_back(cell);
852 }
853
854 buf->getBitLong(); // custom data
855 const std::uint32_t customItems = buf->getBitLong();
856 if (customItems > kMaxTableItems) {
857 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");
858 return false;
859 }
860 for (std::uint32_t i = 0; i < customItems; ++i) {
861 if (!skipTableCustomData(version, buf, strBuf, hdlBuf)) {
862 DRW_DBG("TABLECONTENT row custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row custom data parse incomplete\n"
)
;
863 return false;
864 }
865 }
866 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf,
867 &content.m_subrecordRanges)) {
868 DRW_DBG("TABLECONTENT row cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row cell style parse incomplete\n"
)
;
869 return false;
870 }
871 buf->getBitLong(); // style id
872 row.m_height = buf->getBitDouble();
873 content.m_rows.push_back(row);
874 }
875
876 const std::uint32_t fieldRefs = buf->getBitLong();
877 if (fieldRefs > kMaxTableItems) {
878 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");
879 return false;
880 }
881 content.m_fieldHandles.clear();
882 content.m_fieldHandles.reserve(fieldRefs);
883 for (std::uint32_t i = 0; i < fieldRefs; ++i) {
884 const std::uint32_t ref = readTableHandle(hdlBuf);
885 if (ref != 0)
886 content.m_fieldHandles.push_back(ref);
887 }
888
889 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf,
890 &content.m_subrecordRanges)) {
891 DRW_DBG("TABLECONTENT table cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT table cell style parse incomplete\n"
)
;
892 return false;
893 }
894
895 const std::uint32_t mergedRanges = buf->getBitLong();
896 if (mergedRanges > kMaxTableItems) {
897 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");
898 return false;
899 }
900 content.m_mergedRanges.clear();
901 content.m_mergedRanges.reserve(mergedRanges);
902 for (std::uint32_t i = 0; i < mergedRanges; ++i) {
903 DRW_TableMergedRange range;
904 range.m_topRow = buf->getBitLong();
905 range.m_leftColumn = buf->getBitLong();
906 range.m_bottomRow = buf->getBitLong();
907 range.m_rightColumn = buf->getBitLong();
908 content.m_mergedRanges.push_back(range);
909 }
910
911 content.m_tableStyleHandle = readTableHandle(hdlBuf);
912 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
913 if (!good)
914 DRW_DBG("TABLECONTENT stream ended unexpectedly\n")DRW_dbg::dbg("TABLECONTENT stream ended unexpectedly\n");
915 return good;
916}
917
918} // namespace
919
920//! Calculate arbitrary axis
921/*!
922* Calculate arbitrary axis for apply extrusions
923* @author Rallaz
924*/
925void DRW_Entity::calculateAxis(DRW_Coord extPoint){
926 //Follow the arbitrary DXF definitions for extrusion axes.
927 if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625) {
928 //If we get here, implement Ax = Wy x N where Wy is [0,1,0] per the DXF spec.
929 //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
930 //Factoring in the fixed values for Wy gives N.z,0,-N.x
931 extAxisX.x = extPoint.z;
932 extAxisX.y = 0;
933 extAxisX.z = -extPoint.x;
934 } else {
935 //Otherwise, implement Ax = Wz x N where Wz is [0,0,1] per the DXF spec.
936 //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
937 //Factoring in the fixed values for Wz gives -N.y,N.x,0.
938 extAxisX.x = -extPoint.y;
939 extAxisX.y = extPoint.x;
940 extAxisX.z = 0;
941 }
942
943 extAxisX.unitize();
944
945 //Ay = N x Ax
946 extAxisY.x = (extPoint.y * extAxisX.z) - (extAxisX.y * extPoint.z);
947 extAxisY.y = (extPoint.z * extAxisX.x) - (extAxisX.z * extPoint.x);
948 extAxisY.z = (extPoint.x * extAxisX.y) - (extAxisX.x * extPoint.y);
949
950 extAxisY.unitize();
951}
952
953//! Extrude a point using arbitrary axis
954/*!
955* apply extrusion in a point using arbitrary axis (previous calculated)
956* @author Rallaz
957*/
958void DRW_Entity::extrudePoint(DRW_Coord extPoint, DRW_Coord *point){
959 double px, py, pz;
960 px = (extAxisX.x*point->x)+(extAxisY.x*point->y)+(extPoint.x*point->z);
961 py = (extAxisX.y*point->x)+(extAxisY.y*point->y)+(extPoint.y*point->z);
962 pz = (extAxisX.z*point->x)+(extAxisY.z*point->y)+(extPoint.z*point->z);
963
964 point->x = px;
965 point->y = py;
966 point->z = pz;
967}
968
969bool DRW_Entity::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
970 switch (code) {
971 case DRW::dxfCode::HANDLE:
972 handle = reader->getHandleString();
973 break;
974 case DRW::dxfCode::OWNER_HANDLE:
975 parentHandle = reader->getHandleString();
976 break;
977 case DRW::dxfCode::LAYER:
978 layer = reader->getUtf8String();
979 break;
980 case 6:
981 lineType = reader->getUtf8String();
982 break;
983 case DRW::dxfCode::COLOR:
984 color = reader->getInt32();
985 break;
986 case DRW::dxfCode::LINEWEIGHT:
987 lWeight = DRW_LW_Conv::dxfInt2lineWidth(reader->getInt32());
988 break;
989 case 48:
990 ltypeScale = reader->getDouble();
991 break;
992 case DRW::dxfCode::INVISIBLE:
993 visible = (reader->getInt32() & 1) == 0;
994 break;
995 case 420:
996 color24 = reader->getInt32();
997 break;
998 case 430:
999 colorName = reader->getString();
1000 break;
1001 case 67:
1002 space = static_cast<DRW::Space>(reader->getInt32());
1003 break;
1004 case 102:
1005 return parseDxfGroups(code, reader);
1006 case 284:
1007 shadow = static_cast<DRW::ShadowMode>(reader->getInt32() & 0x3);
1008 break;
1009 case 347:
1010 material = static_cast<std::uint32_t>(reader->getHandleString());
1011 break;
1012 case DRW::dxfCode::PLOTSTYLE:
1013 plotStyle = reader->getHandleString();
1014 break;
1015 case 440:
1016 transparency = reader->getInt32();
1017 break;
1018 case 92:
1019 case 160:
1020 // Proxy entity graphics byte count (ODA §20.4.95): 92 for R13–R2007,
1021 // 160 for R2010+. Introduces the 310 hex chunks below; gating the 310
1022 // capture on this keeps unrelated binary-310 streams out of the proxy
1023 // buffer. (Entities that repurpose 92 — e.g. MESH — handle it in their
1024 // own parseCode and never reach here.)
1025 numProxyGraph = reader->getInt32();
1026 break;
1027 case 310:
1028 if (numProxyGraph != 0) {
1029 // Proxy graphics binary, hex-encoded across many ≤254-char chunks.
1030 const std::string& hex = reader->getString();
1031 proxyGraphics.reserve(proxyGraphics.size() + hex.size() / 2);
1032 auto hexVal = [](char c) -> int {
1033 if (c >= '0' && c <= '9') return c - '0';
1034 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
1035 if (c >= 'A' && c <= 'F') return c - 'A' + 10;
1036 return -1;
1037 };
1038 for (std::size_t i = 0; i + 1 < hex.size(); i += 2) {
1039 int hi = hexVal(hex[i]), lo = hexVal(hex[i + 1]);
1040 if (hi < 0 || lo < 0) break;
1041 proxyGraphics.push_back(static_cast<char>((hi << 4) | lo));
1042 }
1043 }
1044 break;
1045 case 1000:
1046 case 1001:
1047 case 1002:
1048 case 1003:
1049 case 1004:
1050 case 1005:
1051 extData.push_back(std::make_shared<DRW_Variant>(code, reader->getString()));
1052 break;
1053 case 1010:
1054 case 1011:
1055 case 1012:
1056 case 1013:
1057 curr =std::make_shared<DRW_Variant>(code, DRW_Coord(reader->getDouble(), 0.0, 0.0));
1058 extData.push_back(curr);
1059 break;
1060 case 1020:
1061 case 1021:
1062 case 1022:
1063 case 1023:
1064 if (curr)
1065 curr->setCoordY(reader->getDouble());
1066 break;
1067 case 1030:
1068 case 1031:
1069 case 1032:
1070 case 1033:
1071 if (curr)
1072 curr->setCoordZ(reader->getDouble());
1073 //FIXME, why do we discard curr right after setting the its Z
1074// curr=NULL;
1075 break;
1076 case 1040:
1077 case 1041:
1078 case 1042:
1079 extData.push_back(std::make_shared<DRW_Variant>(code, reader->getDouble() ));
1080 break;
1081 case 1070:
1082 case 1071:
1083 extData.push_back(std::make_shared<DRW_Variant>(code, reader->getInt32() ));
1084 break;
1085 default:
1086 break;
1087 }
1088 return true;
1089}
1090
1091//parses dxf 102 groups to read entity
1092bool DRW_Entity::parseDxfGroups(int code, const std::unique_ptr<dxfReader>& reader){
1093 std::list<DRW_Variant> ls;
1094 DRW_Variant curr;
1095 std::string appName= reader->getString();
1096 bool complete = true;
1097 if (!appName.empty() && appName.at(0)== '{') {
1098 curr.addString(code, appName.substr(1));
1099 ls.push_back(curr);
1100 int depth = 1;
1101 int nextCode = 0;
1102 while (depth > 0 && reader->readRec(&nextCode)) {
1103 DRW_Variant value;
1104 if (nextCode == 102) {
1105 std::string marker = reader->getString();
1106 value.addString(nextCode, marker);
1107 if (!marker.empty() && marker.at(0) == '{')
1108 ++depth;
1109 else if (!marker.empty() && marker.at(0) == '}')
1110 --depth;
1111 } else if ((nextCode >= 320 && nextCode <= 369)
1112 || (nextCode >= 390 && nextCode <= 399)
1113 || nextCode == 480 || nextCode == 481
1114 || nextCode == 1005) {
1115 value.addString(nextCode, reader->getString());
1116 } else {
1117 switch (reader->type) {
1118 case dxfReader::STRING:
1119 case dxfReader::BINARY:
1120 value.addString(nextCode, reader->getString());
1121 break;
1122 case dxfReader::INT32:
1123 case dxfReader::BOOL:
1124 value.addInt(nextCode, reader->getInt32());
1125 break;
1126 case dxfReader::INT64:
1127 value.addInt64(nextCode, static_cast<std::int64_t>(reader->getInt64()));
1128 break;
1129 case dxfReader::DOUBLE:
1130 value.addDouble(nextCode, reader->getDouble());
1131 break;
1132 default:
1133 break;
1134 }
1135 }
1136 ls.push_back(value);
1137 }
1138 complete = depth == 0;
1139 }
1140
1141 appData.push_back(ls);
1142 return complete;
1143}
1144
1145bool DRW_Entity::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer* strBuf, std::uint32_t bs){
1146 objSize=0;
1147 DRW_DBG("\n***************************** parsing entity *********************************************\n")DRW_dbg::dbg("\n***************************** parsing entity *********************************************\n"
)
;
1148 oType = buf->getObjType(version);
1149 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);
1150
1151 if (version > DRW::AC1014 && version < DRW::AC1024) {//2000 & 2004
1152 objSize = buf->getRawLong32(); //RL 32bits object size in bits
1153 DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n");
1154 }
1155 if (version > DRW::AC1021) {//2010+
1156 std::uint32_t ms = buf->size();
1157 // Clamp: a corrupt bs > ms*8 would underflow objSize (unsigned) to a
1158 // huge value and drive strBuf->moveBitPos(objSize-1) past the buffer.
1159 objSize = (bs <= ms*8u) ? ms*8u - bs : 0u;
1160 DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n");
1161 }
1162
1163 if (strBuf != NULL__null && version > DRW::AC1018) {//2007+
1164 strBuf->moveBitPos(objSize-1);
1165 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");
1166 if (strBuf->getBit() == 1){
1167 DRW_DBG("DRW_TableEntry::parseDwg string bit is 1\n")DRW_dbg::dbg("DRW_TableEntry::parseDwg string bit is 1\n");
1168 strBuf->moveBitPos(-17);
1169 std::uint16_t strDataSize = strBuf->getRawShort16();
1170 DRW_DBG("\nDRW_TableEntry::parseDwg string strDataSize: ")DRW_dbg::dbg("\nDRW_TableEntry::parseDwg string strDataSize: "
)
; DRW_DBGH(strDataSize)DRW_dbg::dbgH(strDataSize); DRW_DBG("\n")DRW_dbg::dbg("\n");
1171 if ( (strDataSize& 0x8000) == 0x8000){
1172 DRW_DBG("\nDRW_TableEntry::parseDwg string 0x8000 bit is set")DRW_dbg::dbg("\nDRW_TableEntry::parseDwg string 0x8000 bit is set"
)
;
1173 strBuf->moveBitPos(-32);
1174 std::uint16_t hiSize = strBuf->getRawShort16();
1175 strDataSize = ((strDataSize&0x7fff) | (hiSize<<15));
1176 }
1177 strBuf->moveBitPos( -strDataSize -16); //-14
1178 DRW_DBG("strBuf start strDataSize pos 2007: ")DRW_dbg::dbg("strBuf start strDataSize 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");
1179 } else
1180 DRW_DBG("\nDRW_TableEntry::parseDwg string bit is 0")DRW_dbg::dbg("\nDRW_TableEntry::parseDwg string bit is 0");
1181 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");
1182 }
1183
1184 dwgHandle ho = buf->getHandle();
1185 handle = ho.ref;
1186 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);
1187 // ODA DWG spec §28 "Extended Entity Data". The outer loop yields one
1188 // BS-prefixed byte chunk per APPID-attached group; size==0 terminates.
1189 // Each chunk's payload is a sequence of (1-byte type code + value)
1190 // items; we walk it with a nested loop and push DRW_Variant entries
1191 // into @ref extData. Handle-typed items (type 3 layer-ref, type 5
1192 // entity-ref) and the per-chunk APPID handle are resolved post-hoc
1193 // in dwgReader::parseAttribs once the symbol tables are available.
1194 std::uint16_t extDataSize = buf->getBitShort(); //BS (unsigned: a >32767 chunk size must not go negative)
1195 DRW_DBG(" ext data size: ")DRW_dbg::dbg(" ext data size: "); DRW_DBG(extDataSize)DRW_dbg::dbg(extDataSize);
1196 while (extDataSize>0 && buf->isGood()) {
1197 dwgHandle ah = buf->getHandle();
1198 DRW_DBG("App Handle: ")DRW_dbg::dbg("App Handle: "); DRW_DBGHL(ah.code, ah.size, ah.ref)DRW_dbg::dbgHL(ah.code, ah.size, ah.ref);
1199 std::vector<std::uint8_t> tmpExtData(static_cast<std::size_t>(extDataSize));
1200 if (!buf->getBytes(tmpExtData.data(), extDataSize))
1201 return false;
1202 dwgBuffer tmpExtDataBuf(tmpExtData.data(), extDataSize, buf->decoder);
1203
1204 // Placeholder for the APPID name (DXF group 1001). Filled in by
1205 // parseAttribs from appIdmap; falls back to ACAD_<hex> if unknown.
1206 extData.push_back(std::make_shared<DRW_Variant>(1001, std::string{}));
1207 pendingAppIdResolutions.push_back({extData.size() - 1, ah.ref});
1208
1209 while (tmpExtDataBuf.numRemainingBytes() > 0 && tmpExtDataBuf.isGood()) {
1210 std::uint8_t dxfCode = tmpExtDataBuf.getRawChar8();
1211 DRW_DBG(" eed type: ")DRW_dbg::dbg(" eed type: "); DRW_DBG(dxfCode)DRW_dbg::dbg(dxfCode);
1212 switch (dxfCode){
1213 case 0: { //string
1214 std::string s;
1215 if (version > DRW::AC1018) { //R2007+
1216 if (tmpExtDataBuf.numRemainingBytes() < 2) break;
1217 std::uint16_t nChars = tmpExtDataBuf.getRawShort16();
1218 DRW_DBG(" EED string nChars: ")DRW_dbg::dbg(" EED string nChars: "); DRW_DBG(nChars)DRW_dbg::dbg(nChars);
1219 if (nChars > 0) {
1220 // R2007+ EED strings are UTF-16LE (nChars 16-bit code units).
1221 std::uint64_t byteLen = static_cast<std::uint64_t>(nChars) * 2;
1222 if ((std::uint64_t)tmpExtDataBuf.numRemainingBytes() < byteLen) break;
1223 std::vector<std::uint8_t> bytes(byteLen);
1224 tmpExtDataBuf.getBytes(bytes.data(), byteLen);
1225 for (std::uint16_t i = 0; i < nChars; ++i) {
1226 std::uint16_t c = static_cast<std::uint16_t>(bytes[2*i]) |
1227 (static_cast<std::uint16_t>(bytes[2*i+1]) << 8);
1228 if (c < 0x80) {
1229 s.push_back(static_cast<char>(c));
1230 } else if (c < 0x800) {
1231 s.push_back(static_cast<char>(0xC0 | (c >> 6)));
1232 s.push_back(static_cast<char>(0x80 | (c & 0x3F)));
1233 } else {
1234 s.push_back(static_cast<char>(0xE0 | (c >> 12)));
1235 s.push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3F)));
1236 s.push_back(static_cast<char>(0x80 | (c & 0x3F)));
1237 }
1238 }
1239 }
1240 } else { //R13–R2004: 1-byte len + 2-byte BE codepage hint + bytes (+NUL)
1241 if (tmpExtDataBuf.numRemainingBytes() < 3) break;
1242 std::uint8_t strLength = tmpExtDataBuf.getRawChar8();
1243 std::uint16_t cp = tmpExtDataBuf.getBERawShort16();
1244 if (strLength > 0 && tmpExtDataBuf.numRemainingBytes() >= strLength) {
1245 std::string raw(strLength, '\0');
1246 tmpExtDataBuf.getBytes(reinterpret_cast<std::uint8_t*>(&raw[0]), strLength);
1247 s = decodeEedString(cp, raw, tmpExtDataBuf.decoder);
1248 }
1249 //consume the optional trailing NUL terminator if present
1250 if (tmpExtDataBuf.numRemainingBytes() > 0) {
1251 tmpExtDataBuf.getRawChar8();
1252 }
1253 }
1254 extData.push_back(std::make_shared<DRW_Variant>(1000, s));
1255 break;
1256 }
1257 case 2: { //control character: 0 = '{', 1 = '}'
1258 if (tmpExtDataBuf.numRemainingBytes() < 1) break;
1259 std::uint8_t ctrl = tmpExtDataBuf.getRawChar8();
1260 extData.push_back(std::make_shared<DRW_Variant>(
1261 1002, std::string(ctrl == 0 ? "{" : "}")));
1262 break;
1263 }
1264 case 3: { //layer-table reference (8 raw BE bytes -> handle)
1265 if (tmpExtDataBuf.numRemainingBytes() < 8) break;
1266 std::uint8_t hb[8];
1267 tmpExtDataBuf.getBytes(hb, 8);
1268 std::uint64_t ref = 0;
1269 for (int i = 0; i < 8; ++i) {
1270 ref = (ref << 8) | hb[i];
1271 }
1272 // Placeholder layer-ref string; resolved post-hoc.
1273 extData.push_back(std::make_shared<DRW_Variant>(
1274 1003, std::string{}, /*isLayerRef=*/true));
1275 pendingLayerRefResolutions.push_back(
1276 {extData.size() - 1, static_cast<std::uint32_t>(ref)});
1277 break;
1278 }
1279 case 4: { //binary chunk: 1-byte length + bytes
1280 if (tmpExtDataBuf.numRemainingBytes() < 1) break;
1281 std::uint8_t binLen = tmpExtDataBuf.getRawChar8();
1282 std::vector<std::uint8_t> bytes(binLen);
1283 if (binLen > 0 && tmpExtDataBuf.numRemainingBytes() >= binLen) {
1284 tmpExtDataBuf.getBytes(bytes.data(), binLen);
1285 }
1286 extData.push_back(std::make_shared<DRW_Variant>(1004, std::move(bytes)));
1287 break;
1288 }
1289 case 5: { //entity-handle reference (8 raw BE bytes -> hex string)
1290 if (tmpExtDataBuf.numRemainingBytes() < 8) break;
1291 std::uint8_t hb[8];
1292 tmpExtDataBuf.getBytes(hb, 8);
1293 std::uint64_t ref = 0;
1294 for (int i = 0; i < 8; ++i) {
1295 ref = (ref << 8) | hb[i];
1296 }
1297 char tmp[24];
1298 std::snprintf(tmp, sizeof(tmp), "%llX",
1299 static_cast<unsigned long long>(ref));
1300 extData.push_back(std::make_shared<DRW_Variant>(1005, std::string{tmp}));
1301 break;
1302 }
1303 case 10: case 11: case 12: case 13: { //3-double point
1304 if (tmpExtDataBuf.numRemainingBytes() < 24) break;
1305 DRW_Coord c;
1306 c.x = tmpExtDataBuf.getRawDouble();
1307 c.y = tmpExtDataBuf.getRawDouble();
1308 c.z = tmpExtDataBuf.getRawDouble();
1309 extData.push_back(std::make_shared<DRW_Variant>(1000 + dxfCode, c));
1310 break;
1311 }
1312 case 40: case 41: case 42: { //real
1313 if (tmpExtDataBuf.numRemainingBytes() < 8) break;
1314 double d = tmpExtDataBuf.getRawDouble();
1315 extData.push_back(std::make_shared<DRW_Variant>(1000 + dxfCode, d));
1316 break;
1317 }
1318 case 70: { //int16
1319 if (tmpExtDataBuf.numRemainingBytes() < 2) break;
1320 std::int16_t i = static_cast<std::int16_t>(tmpExtDataBuf.getRawShort16());
1321 extData.push_back(std::make_shared<DRW_Variant>(1070, static_cast<std::int32_t>(i)));
1322 break;
1323 }
1324 case 71: { //int32
1325 if (tmpExtDataBuf.numRemainingBytes() < 4) break;
1326 std::int32_t i = static_cast<std::int32_t>(tmpExtDataBuf.getRawLong32());
1327 extData.push_back(std::make_shared<DRW_Variant>(1071, i));
1328 break;
1329 }
1330 default:
1331 DRW_DBG(" unknown EED type: ")DRW_dbg::dbg(" unknown EED type: "); DRW_DBG(dxfCode)DRW_dbg::dbg(dxfCode); DRW_DBG("\n")DRW_dbg::dbg("\n");
1332 // Unknown type — bail on this app's chunk; we cannot
1333 // know how many bytes the rest of the item occupies.
1334 tmpExtDataBuf.setPosition(tmpExtDataBuf.size());
1335 break;
1336 }
1337 }
1338 extDataSize = buf->getBitShort(); //BS
1339 DRW_DBG(" ext data size: ")DRW_dbg::dbg(" ext data size: "); DRW_DBG(extDataSize)DRW_dbg::dbg(extDataSize);
1340 } //end parsing extData (EED)
1341 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");
1342 std::uint8_t graphFlag = buf->getBit(); //B
1343 DRW_DBG(" graphFlag: ")DRW_dbg::dbg(" graphFlag: "); DRW_DBG(graphFlag)DRW_dbg::dbg(graphFlag); DRW_DBG("\n")DRW_dbg::dbg("\n");
1344 if (graphFlag) {
1345 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");
1346 const std::uint64_t graphDataSize = (version >= DRW::AC1024)
1347 ? buf->getBitLongLong()
1348 : buf->getRawLong32();
1349 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");
1350 const std::uint64_t maxMoveBytes = static_cast<std::uint64_t>(std::numeric_limits<std::int32_t>::max() / 8);
1351 if (graphDataSize > static_cast<std::uint64_t>(buf->numRemainingBytes())
1352 || graphDataSize > maxMoveBytes) {
1353 DRW_DBG("graphData size outside object body\n")DRW_dbg::dbg("graphData size outside object body\n");
1354 return false;
1355 }
1356 // Capture the proxy-graphics byte stream instead of skipping it. These
1357 // are cached drawable primitives (lines/arcs/polylines/text) that any
1358 // reader can render for proxy/custom entities (STDPART2D, AEC_*, tables)
1359 // — previously discarded via moveBitPos, leaving proxyGraphics empty.
1360 // dwgBuffer::getBytes is bit-aware (reconstructs each byte at a non-zero
1361 // bitPos), so it lands at the exact same position moveBitPos(8N) did.
1362 // (write-review #32 / read-coverage gap #1)
1363 if (graphDataSize > 0) {
1364 proxyGraphics.resize(graphDataSize);
1365 if (!buf->getBytes(reinterpret_cast<std::uint8_t*>(&proxyGraphics[0]),
1366 graphDataSize))
1367 return false;
1368 numProxyGraph = static_cast<int>(graphDataSize);
1369 }
1370 }
1371 if (version < DRW::AC1015) {//14-
1372 objSize = buf->getRawLong32(); //RL 32bits object size in bits
1373 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");
1374 }
1375
1376 std::uint8_t entmode = buf->get2Bits(); //BB
1377 if (entmode == 0)
1378 ownerHandle= true;
1379// entmode = 2;
1380 else if(entmode ==2)
1381 entmode = 0;
1382 space = (DRW::Space)entmode; //RLZ verify cast values
1383 DRW_DBG("entmode: ")DRW_dbg::dbg("entmode: "); DRW_DBG(entmode)DRW_dbg::dbg(entmode);
1384 numReactors = buf->getBitLong(); //BL per spec §20.4.1
1385 DRW_DBG(", numReactors: ")DRW_dbg::dbg(", numReactors: "); DRW_DBG(numReactors)DRW_dbg::dbg(numReactors);
1386
1387 if (version < DRW::AC1015) {//14-
1388 if(buf->getBit()) {//is bylayer line type
1389 lineType = "BYLAYER";
1390 ltFlags = 0;
1391 } else {
1392 lineType = "";
1393 ltFlags = 3;
1394 }
1395 DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str());
1396 DRW_DBG(" ltFlags: ")DRW_dbg::dbg(" ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags);
1397 }
1398 if (version > DRW::AC1015) {//2004+
1399 xDictFlag = buf->getBit();
1400 DRW_DBG(" xDictFlag: ")DRW_dbg::dbg(" xDictFlag: "); DRW_DBG(xDictFlag)DRW_dbg::dbg(xDictFlag); DRW_DBG("\n")DRW_dbg::dbg("\n");
1401 }
1402
1403 // libreDWG common_entity_data.spec — the bit at this stream position has two
1404 // disjoint meanings by version:
1405 // * R13..R2002 (version < AC1018): `nolinks` (B). 1 = no prev/next handles
1406 // in the handle section; 0 = read prev+next at parseDwgEntHandle.
1407 // * R2004..R2010 (AC1018..AC1024): NO bit in the stream — reader forces
1408 // haveNextLinks=1 to skip the prev/next handle reads.
1409 // * R2013+ (version > AC1024): `has_ds_data` (B). 1 = inline ACIS SAB
1410 // datastore present. Stored separately because it gates SAB handling,
1411 // not prev/next links (which are already version<AC1018 gated).
1412 // Total bit consumption is unchanged for every version.
1413 if (version < DRW::AC1018) {
1414 haveNextLinks = buf->getBit(); //nolinks //B
1415 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");
1416 } else {
1417 haveNextLinks = 1; //AC1018+: not in stream, force 1 (no prev/next)
1418 DRW_DBG(", haveNextLinks (forced): ")DRW_dbg::dbg(", haveNextLinks (forced): "); DRW_DBG(haveNextLinks)DRW_dbg::dbg(haveNextLinks); DRW_DBG("\n")DRW_dbg::dbg("\n");
1419 }
1420 if (version > DRW::AC1024) {
1421 hasDsData = buf->getBit(); //has_ds_data //B (R2013+)
1422 DRW_DBG(", hasDsData (R2013+): ")DRW_dbg::dbg(", hasDsData (R2013+): "); DRW_DBG(hasDsData)DRW_dbg::dbg(hasDsData); DRW_DBG("\n")DRW_dbg::dbg("\n");
1423 }
1424//ENC color
1425 color = buf->getEnColor(version); //BS or CMC //ok for R14 or negate
1426 // Capture the AcDbColor side-channel BEFORE any subsequent ENC read.
1427 // libreDWG common_entity_data.spec:454-459 — the corresponding handle
1428 // is consumed at the start of the handle stream in parseDwgEntHandle.
1429 hasAcDbColorH = buf->lastEnColorHadDbColorRef;
1430 // libreDWG common_entity_data.spec:432-453 — ENC alpha_raw (DXF code
1431 // 440) is encoded as (alpha_type<<24) | alpha. Stored verbatim; the
1432 // filter (RS_FilterDXFRW::setEntityAttributes) decodes alpha_type==3
1433 // into a per-entity pen alpha, otherwise inherits from layer/block.
1434 if (buf->lastEnColorAlphaRaw != 0) {
1435 transparency = static_cast<int>(buf->lastEnColorAlphaRaw);
1436 }
1437 // libreDWG common_entity_data.spec:468-475 — inline TV name/book name
1438 // (flags 0x41/0x42) override any dbColorMap-resolved name. Captured
1439 // immediately; entryParse will skip the override only if colorName is
1440 // already populated here.
1441 if (!buf->lastEnColorName.empty()) {
1442 colorName = buf->lastEnColorBookName.empty()
1443 ? buf->lastEnColorName
1444 : (buf->lastEnColorBookName + "$" + buf->lastEnColorName);
1445 }
1446 ltypeScale = buf->getBitDouble(); //BD
1447 DRW_DBG(" entity color: ")DRW_dbg::dbg(" entity color: "); DRW_DBG(color)DRW_dbg::dbg(color);
1448 DRW_DBG(" ltScale: ")DRW_dbg::dbg(" ltScale: "); DRW_DBG(ltypeScale)DRW_dbg::dbg(ltypeScale); DRW_DBG("\n")DRW_dbg::dbg("\n");
1449 if (version > DRW::AC1014) {//2000+ — §19.4.1: linetype-flags BB then plot-flags BB
1450 ltFlags = buf->get2Bits(); //BB
1451 if (ltFlags == 0) lineType = "BYLAYER";
1452 else if (ltFlags == 1) lineType = "BYBLOCK";
1453 else if (ltFlags == 2) lineType = "CONTINUOUS";
1454 else lineType = ""; //3 → handle at end
1455 DRW_DBG("ltFlags: ")DRW_dbg::dbg("ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags);
1456 DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str());
1457
1458 plotFlags = buf->get2Bits(); //BB
1459 DRW_DBG(", plotFlags: ")DRW_dbg::dbg(", plotFlags: "); DRW_DBG(plotFlags)DRW_dbg::dbg(plotFlags);
1460 }
1461 if (version > DRW::AC1018) {//2007+
1462 materialFlag = buf->get2Bits(); //BB
1463 DRW_DBG("materialFlag: ")DRW_dbg::dbg("materialFlag: "); DRW_DBG(materialFlag)DRW_dbg::dbg(materialFlag);
1464 shadowFlag = buf->getRawChar8(); //RC, low 2 bits is shadow mode 0..3
1465 DRW_DBG("shadowFlag: ")DRW_dbg::dbg("shadowFlag: "); DRW_DBG(shadowFlag)DRW_dbg::dbg(shadowFlag); DRW_DBG("\n")DRW_dbg::dbg("\n");
1466 shadow = static_cast<DRW::ShadowMode>(shadowFlag & 0x3);
1467 }
1468 if (version > DRW::AC1021) {//2010+ — §19.4.1: three single-bit flags
1469 // Ground-truth: libreDWG common_entity_data.spec lines 523-528
1470 // and ODA spec v5.4.1 §19.4.1 both define three FIELD_B (single bit)
1471 // flags here, one each for full/face/edge visual style. Total bit
1472 // consumption (3 bits) is identical to the historical BB+B shape;
1473 // only the semantics differ. The corresponding handles are read
1474 // conditionally in parseDwgEntHandle after the plotstyle handle.
1475 hasFullVisualStyle = buf->getBit(); //B
1476 hasFaceVisualStyle = buf->getBit(); //B
1477 hasEdgeVisualStyle = buf->getBit(); //B
1478 DRW_DBG("hasFull/Face/Edge VisualStyle: ")DRW_dbg::dbg("hasFull/Face/Edge VisualStyle: ");
1479 DRW_DBG(hasFullVisualStyle)DRW_dbg::dbg(hasFullVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" ");
1480 DRW_DBG(hasFaceVisualStyle)DRW_dbg::dbg(hasFaceVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" ");
1481 DRW_DBG(hasEdgeVisualStyle)DRW_dbg::dbg(hasEdgeVisualStyle); DRW_DBG("\n")DRW_dbg::dbg("\n");
1482 }
1483 std::int16_t invisibleFlag = buf->getBitShort(); //BS
1484 DRW_DBG(" invisibleFlag: ")DRW_dbg::dbg(" invisibleFlag: "); DRW_DBG(invisibleFlag)DRW_dbg::dbg(invisibleFlag);
1485 // DXF group 60: bit 0 = invisible (1) / visible (0). libreDWG
1486 // common_entity_data.spec masks bit 0 only (`invisible & 1`) and ignores
1487 // the higher bits, so use the same mask rather than `== 0`. Paired with
1488 // the encode emit below.
1489 visible = ((invisibleFlag & 1) == 0);
1490 if (version > DRW::AC1014) {//2000+
1491 lWeight = DRW_LW_Conv::dwgInt2lineWidth( buf->getRawChar8() ); //RC
1492 DRW_DBG(" lwFlag (lWeight): ")DRW_dbg::dbg(" lwFlag (lWeight): "); DRW_DBG(lWeight)DRW_dbg::dbg(lWeight); DRW_DBG("\n")DRW_dbg::dbg("\n");
1493 }
1494 //Only in blocks ????????
1495// if (version > DRW::AC1018) {//2007+
1496// std::uint8_t unk = buf->getBit();
1497// DRW_DBG("unknown bit: "); DRW_DBG(unk); DRW_DBG("\n");
1498// }
1499 return buf->isGood();
1500}
1501
1502bool DRW_Entity::parseDwgEntHandle(DRW::Version version, dwgBuffer *buf, bool resetHandleStream){
1503 if (resetHandleStream && version > DRW::AC1018) {//2007+ skip string area
1504 buf->setPosition(objSize >> 3);
1505 buf->setBitPos(objSize & 7);
1506 }
1507
1508 // libreDWG common_entity_data.spec:454-459: when ENC flag 0x40 is set,
1509 // an AcDbColor reference handle is the FIRST item in the handle stream
1510 // — read before owner / reactors / xdic / etc. Set in parseDwg via
1511 // dwgBuffer::lastEnColorHadDbColorRef. The dwgReader resolves this
1512 // handle against dbColorMap after parseDwg returns and patches
1513 // color24 + colorName onto the entity.
1514 if (hasAcDbColorH && version > DRW::AC1015 && buf->numRemainingBytes() >= 4) {
1515 dwgHandle dbcH = buf->getOffsetHandle(handle);
1516 acDbColorHandle = dbcH.ref;
1517 DRW_DBG(" AcDbColor Handle: ")DRW_dbg::dbg(" AcDbColor Handle: ");
1518 DRW_DBGHL(dbcH.code, dbcH.size, dbcH.ref)DRW_dbg::dbgHL(dbcH.code, dbcH.size, dbcH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1519 }
1520
1521 if(ownerHandle){//entity are in block or in a polyline
1522 dwgHandle ownerH = buf->getOffsetHandle(handle);
1523 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");
1524 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");
1525 parentHandle = ownerH.ref;
1526 DRW_DBG("Block (parent) Handle: ")DRW_dbg::dbg("Block (parent) Handle: "); DRW_DBGHL(ownerH.code, ownerH.size, parentHandle)DRW_dbg::dbgHL(ownerH.code, ownerH.size, parentHandle); DRW_DBG("\n")DRW_dbg::dbg("\n");
1527 } else
1528 DRW_DBG("NO Block (parent) Handle\n")DRW_dbg::dbg("NO Block (parent) Handle\n");
1529
1530 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");
1531 reactorHandles.clear();
1532 for (int i=0; i< numReactors;++i) {
1533 dwgHandle reactorsH = buf->getHandle();
1534 reactorHandles.push_back(reactorsH.ref); // 2a.2: persist reactors
1535 DRW_DBG(" reactorsH control Handle: ")DRW_dbg::dbg(" reactorsH control Handle: "); DRW_DBGHL(reactorsH.code, reactorsH.size, reactorsH.ref)DRW_dbg::dbgHL(reactorsH.code, reactorsH.size, reactorsH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1536 }
1537 if (xDictFlag !=1){//linetype in 2004 seems not have XDicObjH or NULL handle
1538 dwgHandle XDicObjH = buf->getHandle();
1539 xDictHandle = XDicObjH.ref; // 2a.2: persist xdict
1540 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");
1541 }
1542 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");
1543
1544 if (version < DRW::AC1015) {//R14-
1545 //layer handle
1546 layerH = buf->getOffsetHandle(handle);
1547 DRW_DBG(" layer Handle: ")DRW_dbg::dbg(" layer Handle: "); DRW_DBGHL(layerH.code, layerH.size, layerH.ref)DRW_dbg::dbgHL(layerH.code, layerH.size, layerH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1548 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");
1549 //lineType handle
1550 if(ltFlags == 3){
1551 lTypeH = buf->getOffsetHandle(handle);
1552 DRW_DBG("linetype Handle: ")DRW_dbg::dbg("linetype Handle: "); DRW_DBGHL(lTypeH.code, lTypeH.size, lTypeH.ref)DRW_dbg::dbgHL(lTypeH.code, lTypeH.size, lTypeH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1553 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");
1554 }
1555 }
1556 if (version < DRW::AC1018) {//2000+
1557 if (haveNextLinks == 0) {
1558 dwgHandle nextLinkH = buf->getOffsetHandle(handle);
1559 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");
1560 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");
1561 prevEntLink = nextLinkH.ref;
1562 nextLinkH = buf->getOffsetHandle(handle);
1563 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");
1564 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");
1565 nextEntLink = nextLinkH.ref;
1566 } else {
1567 nextEntLink = handle+1;
1568 prevEntLink = handle-1;
1569 }
1570 }
1571 if (version > DRW::AC1015) {//2004+
1572 //Parses Bookcolor handle
1573 }
1574 if (version > DRW::AC1014) {//2000+
1575 //layer handle
1576 layerH = buf->getOffsetHandle(handle);
1577 DRW_DBG(" layer Handle: ")DRW_dbg::dbg(" layer Handle: "); DRW_DBGHL(layerH.code, layerH.size, layerH.ref)DRW_dbg::dbgHL(layerH.code, layerH.size, layerH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1578 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");
1579 //lineType handle
1580 if(ltFlags == 3){
1581 lTypeH = buf->getOffsetHandle(handle);
1582 DRW_DBG("linetype Handle: ")DRW_dbg::dbg("linetype Handle: "); DRW_DBGHL(lTypeH.code, lTypeH.size, lTypeH.ref)DRW_dbg::dbgHL(lTypeH.code, lTypeH.size, lTypeH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1583 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");
1584 }
1585 }
1586 if (version > DRW::AC1014) {//2000+
1587 if (version > DRW::AC1018) {//2007+
1588 if (materialFlag == 3) {
1589 dwgHandle materialH = buf->getOffsetHandle(handle);
1590 material = materialH.ref;
1591 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");
1592 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");
1593 }
1594 if (shadowFlag == 3) {
1595 // AcDbShadow object handle (separate from entity shadow mode
1596 // populated from shadowFlag & 0x3 above). LibreCAD has no
1597 // shadow object consumer; leave discarding.
1598 dwgHandle shadowH = buf->getOffsetHandle(handle);
1599 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");
1600 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");
1601 }
1602 }
1603 if (plotFlags == 3) {
1604 dwgHandle plotStyleH = buf->getOffsetHandle(handle);
1605 plotStyle = static_cast<int>(plotStyleH.ref);
1606 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");
1607 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");
1608 }
1609 if (version > DRW::AC1021) {//2010+ — §19.4.2: visual-style handles
1610 // Ground-truth: libreDWG common_entity_handle_data.spec lines
1611 // 141-150 and ODA spec v5.4.1 §19.4.2. Order matches: full,
1612 // face, edge — each conditional on its single-bit flag from
1613 // §19.4.1 (set in parseDwg above). All three are hard pointers
1614 // (libreDWG FIELD_HANDLE code 5), matching the existing
1615 // material/shadow/plotstyle handles in this block.
1616 if (hasFullVisualStyle) {
1617 dwgHandle h = buf->getOffsetHandle(handle);
1618 fullVisualStyleHandle = h.ref;
1619 DRW_DBG(" full visual-style H: ")DRW_dbg::dbg(" full visual-style H: ");
1620 DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1621 }
1622 if (hasFaceVisualStyle) {
1623 dwgHandle h = buf->getOffsetHandle(handle);
1624 faceVisualStyleHandle = h.ref;
1625 DRW_DBG(" face visual-style H: ")DRW_dbg::dbg(" face visual-style H: ");
1626 DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1627 }
1628 if (hasEdgeVisualStyle) {
1629 dwgHandle h = buf->getOffsetHandle(handle);
1630 edgeVisualStyleHandle = h.ref;
1631 DRW_DBG(" edge visual-style H: ")DRW_dbg::dbg(" edge visual-style H: ");
1632 DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1633 }
1634 }
1635 }
1636 const int rb = buf->numRemainingBytes();
1637 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");
1638 if (rb > 4) { // 2-byte CRC + slack
1639 DRW_DBG("\n*** parseDwgEntHandle leftover ")DRW_dbg::dbg("\n*** parseDwgEntHandle leftover ");
1640 DRW_DBG(rb)DRW_dbg::dbg(rb);
1641 DRW_DBG(" bytes; entity handle ")DRW_dbg::dbg(" bytes; entity handle ");
1642 DRW_DBGH(handle)DRW_dbg::dbgH(handle);
1643 DRW_DBG(" oType ")DRW_dbg::dbg(" oType ");
1644 DRW_DBG(oType)DRW_dbg::dbg(oType);
1645 DRW_DBG(" — possible bit-stream misalignment ***\n")DRW_dbg::dbg(" — possible bit-stream misalignment ***\n");
1646 }
1647 return buf->isGood();
1648}
1649
1650bool DRW_Point::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
1651 switch (code) {
1652 case 10:
1653 basePoint.x = reader->getDouble();
1654 break;
1655 case 20:
1656 basePoint.y = reader->getDouble();
1657 break;
1658 case 30:
1659 basePoint.z = reader->getDouble();
1660 break;
1661 case 39:
1662 thickness = reader->getDouble();
1663 break;
1664 case 50:
1665 // DXF code 50 is in degrees; the field is radians (matching the DWG
1666 // path, drw_entities.cpp:1787). degrees -> radians is /ARAD (x pi/180);
1667 // the prior *ARAD only canceled with the writer's /ARAD on DXF->DXF and
1668 // corrupted the value for DXF->DWG. ARAD = 180/pi.
1669 xAxisAngle = reader->getDouble() / ARAD57.29577951308232; // DXF degrees -> radians
1670 break;
1671 case 210:
1672 haveExtrusion = true;
1673 extPoint.x = reader->getDouble();
1674 break;
1675 case 220:
1676 extPoint.y = reader->getDouble();
1677 break;
1678 case 230:
1679 extPoint.z = reader->getDouble();
1680 break;
1681 default:
1682 return DRW_Entity::parseCode(code, reader);
1683 }
1684
1685 return true;
1686}
1687
1688// ---------------------------------------------------------------------------
1689// Phase 4a (drafted 2026-05-15)
1690// ---------------------------------------------------------------------------
1691// `DRW_Entity::encodeDwgCommon` and `encodeDwgEntHandle` are R2000-only
1692// inverses of the corresponding parseDwg fragments above. The version
1693// conditionals collapse: all `version > AC1014` branches fire (R2000 is
1694// AC1015 > AC1014), all `version > AC1015` and `version > AC1018` and
1695// `version > AC1021` branches skip. Likewise `version < AC1015` skips.
1696//
1697// Discarded fields (Risk 4i):
1698// - graphFlag B + optional graphData — we always emit graphFlag=0.
1699// - haveNextLinks B — we emit 1 (no prev/next chain).
1700// - acDbColorH — only fires when ENC flag 0x40 set; R2000 entity
1701// encoders don't emit DBCOLOR refs yet.
1702//
1703// We always emit:
1704// - entmode = 2 (modelspace, no owner-handle in stream — caller can
1705// override before calling encodeDwgCommon if entity needs an owner).
1706// - numReactors = 0
1707// - ltFlags = 0 (BYLAYER), plotFlags = 0 (BYLAYER)
1708// - invisibleFlag = 0 (visible)
1709//
1710// Caller must:
1711// - Pre-populate `eType`, `handle`, `color`, `ltypeScale`, `lWeight`,
1712// `layerH.ref` (handle of the layer this entity belongs to).
1713// - The body emit between encodeDwgCommon and encodeDwgEntHandle is
1714// per-entity (3BD basePoint for Point, etc.).
1715
1716// Phase-2a kill switch for the full common-entity-header write contract
1717// (entity reactors/xdict/EED/visibility/entmode emission). Default ON. The
1718// emission is gated by DATA PRESENCE (empty reactorHandles/extData + visible
1719// == today's hardcoded zeros), so flipping this OFF restores the legacy
1720// byte-identical output as an emergency escape hatch. The per-field emission
1721// arms land in 2a.1..2a.5; this scaffolding commit changes no bytes.
1722#ifndef LIBDXFRW_FULL_COMMON_HEADER1
1723#define LIBDXFRW_FULL_COMMON_HEADER1 1
1724#endif
1725
1726bool DRW_Entity::encodeDwgCommon(DRW::Version version, dwgBufferW *buf,
1727 dwgBufferW *strBuf) {
1728 (void)strBuf; // common data contains no strings
1729 if (version != DRW::AC1015 && version != DRW::AC1018 &&
1730 version != DRW::AC1024 && version != DRW::AC1027 &&
1731 version != DRW::AC1032) return false;
1732
1733 // Object type: BS for AC1015/AC1018, OT for AC1024+.
1734 buf->putObjType(version, static_cast<std::uint16_t>(oType));
1735
1736 // objSize stub — back-patched for AC1015/AC1018 only. AC1024 derives
1737 // objSize from the body buffer size, so no RL is emitted.
1738 if (version < DRW::AC1024) {
1739 buf->putRawLong32(0);
1740 }
1741
1742 // Own handle: code 0 per spec §20.4.1.
1743 dwgHandle ownH;
1744 ownH.code = 0;
1745 ownH.ref = handle;
1746 ownH.size = 0;
1747 if (handle != 0) {
1748 std::uint32_t t = handle;
1749 while (t != 0) { t >>= 8; ++ownH.size; }
1750 }
1751 buf->putHandle(ownH);
1752
1753 // No EED yet.
1754 buf->putBitShort(0); // extDataSize=0
1755
1756 // No graphics data.
1757 buf->putBit(0); // graphFlag=0
1758
1759 const bool hasOwner = parentHandle != DRW::NoHandle;
1760
1761 // entmode: 0 = owner handle follows in the handle stream; 2 = modelspace,
1762 // no owner-handle in stream.
1763 buf->put2Bits(hasOwner ? 0 : 2);
1764
1765 // numReactors (BL per spec §20.4.1). 2a.2: emit the real count; empty
1766 // reactorHandles → 0 → byte-identical to legacy.
1767#if LIBDXFRW_FULL_COMMON_HEADER1
1768 buf->putBitLong(static_cast<std::int32_t>(reactorHandles.size()));
1769#else
1770 buf->putBitLong(0);
1771#endif
1772
1773 // R2004/R2010 (AC1018, AC1024): reader reads xDictFlag bit (version > AC1015)
1774 // then forces haveNextLinks=1 (no bit in stream). We always emit
1775 // xDictFlag=0 (xdic-present) so the reader reads exactly one xdic handle
1776 // in the handle section — we emit the real handle when xDictHandle!=0 and
1777 // a null handle otherwise. This keeps the empty case byte-identical to the
1778 // legacy path (bit 0 + null handle) while round-tripping a real xdict.
1779 // R2000 (AC1015): no xDictFlag bit; reader's xDictFlag stays 0 so it ALWAYS
1780 // reads an xdic handle — same emit rule applies.
1781 // R2013+ (AC1027+): reader reads xDictFlag then reads haveNextLinks (bit restored).
1782 if (version == DRW::AC1015) {
1783 buf->putBit(1); // nolinks=1 (R2000: no prev/next chain)
1784 } else {
1785 buf->putBit(0); // xDictFlag=0 (xdic present; real-or-null handle follows)
1786 if (version > DRW::AC1024) {
1787 // libreDWG common_entity_data.spec — R2013+ has_ds_data (B). libdxfrw
1788 // never inlines an ACIS SAB datastore, so emit hasDsData (default 0).
1789 // The old code emitted literal 1 (mislabeled haveNextLinks), falsely
1790 // advertising an SAB blob and risking misparse in strict readers.
1791 buf->putBit(hasDsData);
1792 }
1793 }
1794
1795 // ENC color (BS for R2000/R2004/R2010).
1796 buf->putEnColor(version, static_cast<std::uint16_t>(color));
1797
1798 // ltypeScale BD.
1799 buf->putBitDouble(ltypeScale);
1800
1801 // ltFlags BB (0 = BYLAYER), plotFlags BB (0 = BYLAYER).
1802 buf->put2Bits(0);
1803 buf->put2Bits(0);
1804
1805 // R2010 (AC1024): materialFlag BB + shadowFlag RC (version > AC1018).
1806 if (version > DRW::AC1018) {
1807 buf->put2Bits(0); // materialFlag BB = 0 (inherit)
1808 buf->putRawChar8(0); // shadowFlag RC = 0 (inherit)
1809 }
1810
1811 // R2010 (AC1024): three visual-style flag bits (version > AC1021).
1812 if (version > DRW::AC1021) {
1813 buf->putBit(0); // hasFullVisualStyle
1814 buf->putBit(0); // hasFaceVisualStyle
1815 buf->putBit(0); // hasEdgeVisualStyle
1816 }
1817
1818 // invisibleFlag BS (DXF 60). 2a.1: emit from `visible` (bit 0 = invisible)
1819 // instead of a hardcoded 0. visible==true → 0 → byte-identical to legacy.
1820#if LIBDXFRW_FULL_COMMON_HEADER1
1821 buf->putBitShort(visible ? 0 : 1);
1822#else
1823 buf->putBitShort(0);
1824#endif
1825
1826 // lWeight RC (0 = byLayer per DRW_LW_Conv).
1827 buf->putRawChar8(static_cast<std::uint8_t>(lWeight));
1828
1829 return true;
1830}
1831
1832bool DRW_Entity::encodeDwgEntHandle(DRW::Version version, dwgBufferW *buf,
1833 dwgBufferW *handleBuf) {
1834 if (version != DRW::AC1015 && version != DRW::AC1018 &&
1835 version != DRW::AC1024 && version != DRW::AC1027 &&
1836 version != DRW::AC1032) return false;
1837
1838 // For AC1024, handles are directed to handleBuf (the separate handle section);
1839 // for AC1015/AC1018, handles go into buf alongside the data.
1840 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
1841
1842 // Owner handle is present only when encodeDwgCommon emitted entmode=0.
1843 if (parentHandle != DRW::NoHandle) {
1844 dwgHandle owner;
1845 owner.code = 4; // soft pointer owner, read via getOffsetHandle()
1846 owner.ref = parentHandle;
1847 owner.size = 0;
1848 std::uint32_t t = parentHandle;
1849 while (t != 0) { t >>= 8; ++owner.size; }
1850 hb->putHandle(owner);
1851 }
1852
1853 // Reactor handles (2a.2): emitted before xdic, one per numReactors written
1854 // in the DATA section, as ABSOLUTE handles (reader uses getHandle()). Empty
1855 // reactorHandles → nothing emitted → byte-identical to legacy.
1856#if LIBDXFRW_FULL_COMMON_HEADER1
1857 for (std::uint32_t ref : reactorHandles) {
1858 dwgHandle rh;
1859 rh.code = 4; // soft pointer
1860 rh.ref = ref;
1861 rh.size = 0;
1862 if (ref != 0) { std::uint32_t t = ref; while (t != 0) { t >>= 8; ++rh.size; } }
1863 hb->putHandle(rh);
1864 }
1865#endif
1866
1867 // XDic handle — xDictFlag=0 in the DATA section means the reader reads one
1868 // XDicObj handle here: emit the real handle when xDictHandle!=0, else the
1869 // null handle (matching the legacy byte-for-byte for the empty case).
1870 dwgHandle xDic;
1871 xDic.code = 3;
1872#if LIBDXFRW_FULL_COMMON_HEADER1
1873 xDic.ref = xDictHandle;
1874 xDic.size = 0;
1875 if (xDictHandle != 0) {
1876 std::uint32_t t = xDictHandle; while (t != 0) { t >>= 8; ++xDic.size; }
1877 }
1878#else
1879 xDic.ref = 0;
1880 xDic.size = 0;
1881#endif
1882 hb->putHandle(xDic);
1883
1884 // Layer handle (R2000+ unconditional). Hard pointer.
1885 dwgHandle lH;
1886 lH.code = layerH.ref == 0 ? 0 : 5; // 5 = hard pointer for layer ref
1887 lH.ref = layerH.ref;
1888 lH.size = 0;
1889 if (lH.ref != 0) {
1890 std::uint32_t t = lH.ref;
1891 while (t != 0) { t >>= 8; ++lH.size; }
1892 }
1893 hb->putHandle(lH);
1894
1895 // ltFlags=0 → no separate lTypeH (BYLAYER).
1896 // plotFlags=0 → no plotStyleH (BYLAYER).
1897 // materialFlag=0 → no materialH (for AC1024).
1898 // visualStyle flags=0 → no visualStyleH (for AC1024).
1899
1900 return true;
1901}
1902
1903bool DRW_Point::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
1904 (void)bs; (void)strBuf;
1905 oType = 27; // POINT class id — see dwgreader.cpp:1111 dispatch
1906 if (!encodeDwgCommon(version, buf)) return false;
1907
1908 // Point body — mirror of DRW_Point::parseDwg below.
1909 buf->putBitDouble(basePoint.x);
1910 buf->putBitDouble(basePoint.y);
1911 buf->putBitDouble(basePoint.z);
1912 buf->putThickness(thickness, /*b_R2000_style=*/true);
1913 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
1914 buf->putBitDouble(xAxisAngle); // ODA §20.4.31 code 50
1915
1916 return encodeDwgEntHandle(version, buf, handleBuf);
1917}
1918
1919bool DRW_Point::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
1920 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
1921 if (!ret)
1922 return ret;
1923 DRW_DBG("\n***************************** parsing point *********************************************\n")DRW_dbg::dbg("\n***************************** parsing point *********************************************\n"
)
;
1924
1925 basePoint.x = buf->getBitDouble();
1926 basePoint.y = buf->getBitDouble();
1927 basePoint.z = buf->getBitDouble();
1928 DRW_DBG("point: ")DRW_dbg::dbg("point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
1929 thickness = buf->getThickness(version > DRW::AC1014);//BD
1930 DRW_DBG("\nthickness: ")DRW_dbg::dbg("\nthickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
1931 extPoint = buf->getExtrusion(version > DRW::AC1014);
1932 DRW_DBG(", Extrusion: ")DRW_dbg::dbg(", Extrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
1933
1934 xAxisAngle = buf->getBitDouble(); // ODA §20.4.31 code 50, stored in radians
1935 DRW_DBG("\n x_axis: ")DRW_dbg::dbg("\n x_axis: "); DRW_DBG(xAxisAngle)DRW_dbg::dbg(xAxisAngle); DRW_DBG("\n")DRW_dbg::dbg("\n");
1936 ret = DRW_Entity::parseDwgEntHandle(version, buf);
1937 if (!ret)
1938 return ret;
1939 // RS crc; //RS */
1940
1941 return buf->isGood();
1942}
1943
1944bool DRW_Line::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
1945 switch (code) {
1946 case 11:
1947 secPoint.x = reader->getDouble();
1948 break;
1949 case 21:
1950 secPoint.y = reader->getDouble();
1951 break;
1952 case 31:
1953 secPoint.z = reader->getDouble();
1954 break;
1955 default:
1956 return DRW_Point::parseCode(code, reader);
1957 }
1958
1959 return true;
1960}
1961
1962bool DRW_Line::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
1963 (void)bs; (void)strBuf;
1964 oType = 19; // LINE class id — see dwgreader.cpp:1105
1965 if (!encodeDwgCommon(version, buf)) return false;
1966
1967 // R2000+ Line body — zIsZero shortcut: if both z's are 0, omit the
1968 // z fields entirely. Reader reads `zIsZero` first, then RD x +
1969 // DD secX (default = x), RD y + DD secY (default = y), and
1970 // conditionally RD z + DD secZ. Our putDefaultDouble always emits
1971 // the full RD via code 0b11; reader's getDefaultDouble with code
1972 // 0b11 returns the raw double.
1973 bool zIsZero = (basePoint.z == 0.0 && secPoint.z == 0.0);
1974 buf->putBit(zIsZero ? 1 : 0);
1975 buf->putRawDouble(basePoint.x);
1976 buf->putDefaultDouble(basePoint.x, secPoint.x);
1977 buf->putRawDouble(basePoint.y);
1978 buf->putDefaultDouble(basePoint.y, secPoint.y);
1979 if (!zIsZero) {
1980 buf->putRawDouble(basePoint.z);
1981 buf->putDefaultDouble(basePoint.z, secPoint.z);
1982 }
1983 buf->putThickness(thickness, /*b_R2000_style=*/true);
1984 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
1985
1986 return encodeDwgEntHandle(version, buf, handleBuf);
1987}
1988
1989bool DRW_Circle::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
1990 (void)bs; (void)strBuf;
1991 oType = 18; // CIRCLE class id — see dwgreader.cpp:1099
1992 if (!encodeDwgCommon(version, buf)) return false;
1993
1994 // Circle body — mirror of DRW_Circle::parseDwg.
1995 buf->putBitDouble(basePoint.x);
1996 buf->putBitDouble(basePoint.y);
1997 buf->putBitDouble(basePoint.z);
1998 buf->putBitDouble(radious);
1999 buf->putThickness(thickness, /*b_R2000_style=*/true);
2000 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2001
2002 return encodeDwgEntHandle(version, buf, handleBuf);
2003}
2004
2005bool DRW_Ray::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2006 (void)bs; (void)strBuf;
2007 // Ray = 40, Xline = 41 — derive from runtime type so DRW_Xline can
2008 // share this encoder (it inherits from DRW_Ray).
2009 oType = (eType == DRW::XLINE) ? 41 : 40;
2010 if (!encodeDwgCommon(version, buf)) return false;
2011
2012 // 3 BD basePoint + 3 BD vector — same layout as parseDwg.
2013 buf->putBitDouble(basePoint.x);
2014 buf->putBitDouble(basePoint.y);
2015 buf->putBitDouble(basePoint.z);
2016 buf->putBitDouble(secPoint.x);
2017 buf->putBitDouble(secPoint.y);
2018 buf->putBitDouble(secPoint.z);
2019
2020 return encodeDwgEntHandle(version, buf, handleBuf);
2021}
2022
2023bool DRW_Trace::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2024 (void)bs; (void)strBuf;
2025 oType = 32; // TRACE = 32 — see dwgreader.cpp:1317
2026 if (!encodeDwgCommon(version, buf)) return false;
2027
2028 // Trace body — mirror of parseDwg. Note the unusual layout:
2029 // thickness FIRST, then elevation (basePoint.z) as BD, then 4
2030 // corners as 2RD (z values share basePoint.z).
2031 buf->putThickness(thickness, /*b_R2000_style=*/true);
2032 buf->putBitDouble(basePoint.z);
2033 buf->putRawDouble(basePoint.x);
2034 buf->putRawDouble(basePoint.y);
2035 buf->putRawDouble(secPoint.x);
2036 buf->putRawDouble(secPoint.y);
2037 buf->putRawDouble(thirdPoint.x);
2038 buf->putRawDouble(thirdPoint.y);
2039 buf->putRawDouble(fourPoint.x);
2040 buf->putRawDouble(fourPoint.y);
2041 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2042
2043 return encodeDwgEntHandle(version, buf, handleBuf);
2044}
2045
2046bool DRW_Spline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2047 (void)bs; (void)strBuf;
2048 oType = 36; // SPLINE class id — see dwgreader.cpp:1329
2049 if (!encodeDwgCommon(version, buf)) return false;
2050 encodeDwgSplineBody(version, buf);
2051 return encodeDwgEntHandle(version, buf, handleBuf);
2052}
2053
2054// Spline body encode: the scenario/degree/knots/ctrl/fit section, WITHOUT the
2055// leading encodeDwgCommon or the trailing encodeDwgEntHandle. Factored out so
2056// DRW_Helix::encodeDwg can reuse the identical payload (Phase 8a-1).
2057// Omits the DXF-only flag70/extrusion (210-230) which the DWG stream never
2058// carries here.
2059void DRW_Spline::encodeDwgSplineBody(DRW::Version version, dwgBufferW *buf) const {
2060 // Scenario:
2061 // 1 = control-point / rational / planar (uses knots + control + weights)
2062 // 2 = fit-point (uses fit points + tangents + tolerance)
2063 // When both lists are populated (e.g. DXF-sourced splines), prefer scenario 1
2064 // (ctrl + knots) and drop the fit list from the DWG stream — scenario 1 has no
2065 // fit-point section, so writing both would corrupt all subsequent entities.
2066 const bool hasFit = !fitlist.empty();
2067 const bool hasCtrl = !controllist.empty();
2068 std::int32_t scenario = (hasFit && !hasCtrl) ? 2 : 1;
2069 if (m_scenario == 1 && hasCtrl) {
2070 scenario = 1;
2071 } else if (m_scenario == 2 && hasFit) {
2072 scenario = 2;
2073 }
2074 buf->putBitLong(scenario);
2075 if (version > DRW::AC1024) {
2076 // splFlag1 bit 0: method = fit points; bit 2: closed;
2077 // bit 3: knotParam participates in R2013+ scenario selection.
2078 std::int32_t splFlag1 = m_splineFlags1;
2079 splFlag1 &= ~(kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter | kSplineFlagClosed);
2080 if (scenario == 2) {
2081 splFlag1 |= kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter;
2082 if (flags & 0x01) splFlag1 |= kSplineFlagClosed;
2083 } else {
2084 if (flags & 0x01) splFlag1 |= kSplineFlagClosed;
2085 }
2086 buf->putBitLong(splFlag1);
2087 std::int32_t knotParam = m_knotParam;
2088 if (scenario == 1) {
2089 knotParam = kSplineKnotParamCustom;
2090 } else if (knotParam == kSplineKnotParamCustom) {
2091 knotParam = 0;
2092 }
2093 buf->putBitLong(knotParam);
2094 }
2095 buf->putBitLong(static_cast<std::int32_t>(degree));
2096
2097 if (scenario == 2) {
2098 buf->putBitDouble(tolfit);
2099 buf->put3BitDouble(tgStart);
2100 buf->put3BitDouble(tgEnd);
2101 const std::int32_t nFit = static_cast<std::int32_t>(fitlist.size());
2102 buf->putBitLong(nFit);
2103 } else {
2104 // scenario == 1
2105 // Reader at parseDwg reads three flag bits in this order:
2106 // rational bit (flags bit 2 → 0x04)
2107 // closed bit (flags bit 0 → 0x01)
2108 // periodic bit (flags bit 1 → 0x02)
2109 const bool hasNonDefaultWeights = std::any_of(weightlist.begin(), weightlist.end(), differsFromUnitWeight);
2110 buf->putBit(((flags & 0x4) || hasNonDefaultWeights) ? 1 : 0); // rational
2111 buf->putBit((flags & 0x1) ? 1 : 0); // closed
2112 buf->putBit((flags & 0x2) ? 1 : 0); // periodic
2113 buf->putBitDouble(tolknot);
2114 buf->putBitDouble(tolcontrol);
2115 const std::int32_t nKnots = static_cast<std::int32_t>(knotslist.size());
2116 const std::int32_t nCtrl = static_cast<std::int32_t>(controllist.size());
2117 buf->putBitLong(nKnots);
2118 buf->putBitLong(nCtrl);
2119 // weight bit: caller populates weightlist when each control point
2120 // has a non-default weight (NURBS conics).
2121 bool hasWeights = !weightlist.empty();
2122 buf->putBit(hasWeights ? 1 : 0);
2123 }
2124
2125 // Data sections are scenario-gated to avoid stream corruption:
2126 // parseDwg reads knots+ctrl only for scenario 1, fit only for scenario 2.
2127 if (scenario == 1) {
2128 for (double k : knotslist) buf->putBitDouble(k);
2129 for (size_t i = 0; i < controllist.size(); ++i) {
2130 buf->put3BitDouble(*controllist[i]);
2131 if (!weightlist.empty()) {
2132 double w = (i < weightlist.size()) ? weightlist[i] : 1.0;
2133 buf->putBitDouble(w);
2134 }
2135 }
2136 } else {
2137 for (const auto& fp : fitlist) buf->put3BitDouble(*fp);
2138 }
2139}
2140
2141// DRW_Helix::encodeDwg — spline body (oType = HELIX class 503) + AcDbHelix
2142// trailer, then the common entity handle data. Trailer field order MUST match
2143// DRW_Helix::parseDwg (Phase 8a-1).
2144bool DRW_Helix::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2145 (void)bs; (void)strBuf;
2146 oType = kDwgClassNum; // HELIX custom class 503
2147 if (!encodeDwgCommon(version, buf)) return false;
2148 encodeDwgSplineBody(version, buf);
2149
2150 // AcDbHelix trailer (same order as parseDwg):
2151 buf->putBitLong(m_majorVersion);
2152 buf->putBitLong(m_maintVersion);
2153 buf->put3BitDouble(axisBasePt);
2154 buf->put3BitDouble(startPt);
2155 buf->put3BitDouble(axisVector);
2156 buf->putBitDouble(radius);
2157 buf->putBitDouble(turns);
2158 buf->putBitDouble(turnHeight);
2159 buf->putBit(handedness ? 1 : 0);
2160 buf->putRawChar8(static_cast<std::uint8_t>(constraintType));
2161
2162 return encodeDwgEntHandle(version, buf, handleBuf);
2163}
2164
2165bool DRW_MText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2166 (void)bs;
2167 oType = 44; // MTEXT class id — see dwgreader.cpp:1215
2168 if (!encodeDwgCommon(version, buf)) return false;
2169
2170 // R2000/R2004/R2010 MTEXT body — mirror of DRW_MText::parseDwg.
2171 buf->put3BitDouble(basePoint); // insertion
2172 buf->put3BitDouble(extPoint); // extrusion
2173 buf->put3BitDouble(secPoint); // X-axis dir
2174 buf->putBitDouble(widthscale); // rect width
2175 if (version > DRW::AC1018) {
2176 buf->putBitDouble(0.0); // rect height, R2007+
2177 }
2178 buf->putBitDouble(height); // text height
2179 buf->putBitShort(static_cast<std::uint16_t>(textgen)); // attachment
2180 buf->putBitShort(static_cast<std::uint16_t>(alignH)); // drawing dir
2181 buf->putBitDouble(0.0); // ext_ht (extents height; undocumented)
2182 buf->putBitDouble(0.0); // ext_wid (extents width; undocumented)
2183 // For AC1024: text goes to string buffer; for AC1015/AC1018: inline.
2184 (strBuf ? strBuf : buf)->putVariableText(version, text);
2185 // R2000+ extras:
2186 buf->putBitShort(linespacingStyle); // linespacing style BS 73
2187 buf->putBitDouble(interlin); // linespacing factor BD
2188 buf->putBit(0); // unknown bit
2189 if (version > DRW::AC1015) { // R2004+: background flags BL
2190 buf->putBitLong(m_backgroundFlags);
2191 if ((m_backgroundFlags & 0x01) || (version >= DRW::AC1032 && (m_backgroundFlags & 0x10))) {
2192 buf->putBitDouble(m_backgroundScale); // BitDouble (matches the read fix)
2193 buf->putCmColor(version, static_cast<std::uint16_t>(m_backgroundColor));
2194 buf->putBitLong(m_backgroundTransparency);
2195 }
2196 }
2197 if (version >= DRW::AC1032) {
2198 buf->putBit(m_r2018IsNotAnnotative ? 1 : 0);
2199 if (m_r2018IsNotAnnotative) {
2200 buf->putBitShort(m_r2018Version);
2201 buf->putBit(m_r2018DefaultFlag ? 1 : 0);
2202 buf->putBitLong(m_r2018Attachment);
2203 buf->put3BitDouble(m_r2018XAxisDir);
2204 buf->put3BitDouble(m_r2018InsertionPoint);
2205 buf->putBitDouble(m_r2018RectWidth);
2206 buf->putBitDouble(m_r2018RectHeight);
2207 buf->putBitDouble(m_r2018ExtentsHeight);
2208 buf->putBitDouble(m_r2018ExtentsWidth);
2209 buf->putBitShort(m_r2018ColumnType);
2210 if (m_r2018ColumnType != 0) {
2211 std::int32_t columnCount = m_r2018ColumnCount;
2212 if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2
2213 && !m_r2018ColumnHeights.empty()) {
2214 columnCount = static_cast<std::int32_t>(m_r2018ColumnHeights.size());
2215 }
2216 buf->putBitLong(columnCount);
2217 buf->putBitDouble(m_r2018ColumnWidth);
2218 buf->putBitDouble(m_r2018ColumnGutter);
2219 buf->putBit(m_r2018ColumnAutoHeight ? 1 : 0);
2220 buf->putBit(m_r2018ColumnFlowReversed ? 1 : 0);
2221 if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2) {
2222 for (std::int32_t i = 0; i < columnCount; ++i) {
2223 const double columnHeight = static_cast<size_t>(i) < m_r2018ColumnHeights.size()
2224 ? m_r2018ColumnHeights[static_cast<size_t>(i)]
2225 : 0.0;
2226 buf->putBitDouble(columnHeight);
2227 }
2228 }
2229 }
2230 }
2231 }
2232
2233 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
2234
2235 // styleH — hard pointer to STYLE table record (default STANDARD).
2236 dwgBufferW *hb = handleBuf ? handleBuf : buf;
2237 putHardPointerHandle(hb, (styleH.ref == 0) ? 0x13 : styleH.ref);
2238 if (version >= DRW::AC1032 && m_r2018IsNotAnnotative)
2239 putHardPointerHandle(hb, (m_r2018AppIdHandle == 0) ? 0x14 : m_r2018AppIdHandle);
2240 return true;
2241}
2242
2243bool DRW_Insert::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2244 (void)bs; (void)strBuf;
2245 // 2b.6: emit MINSERT (oType 8) when a column/row grid is present;
2246 // otherwise a plain INSERT (oType 7). The reader keys the grid block off
2247 // oType==8 (parseDwg :3189).
2248 oType = (colcount > 1 || rowcount > 1) ? 8 : 7;
2249 if (!encodeDwgCommon(version, buf)) return false;
2250
2251 // INSERT body — mirror of DRW_Insert::parseDwg for R2000.
2252 buf->putBitDouble(basePoint.x);
2253 buf->putBitDouble(basePoint.y);
2254 buf->putBitDouble(basePoint.z);
2255
2256 // dataFlags: pick the most compact form based on actual scales.
2257 // 3 → all scales default to 1.0 (no emit)
2258 // 2 → uniform scale (xscale RD only; yscale=zscale=xscale)
2259 // 1 → xscale defaults to 1, yscale/zscale as DD against xscale
2260 // 0 → xscale RD; yscale/zscale as DD against xscale
2261 if (xscale == 1.0 && yscale == 1.0 && zscale == 1.0) {
2262 buf->put2Bits(3);
2263 } else if (xscale == yscale && yscale == zscale) {
2264 buf->put2Bits(2);
2265 buf->putRawDouble(xscale);
2266 } else {
2267 // Use dataFlags=0 (general case): RD x + DD y + DD z.
2268 buf->put2Bits(0);
2269 buf->putRawDouble(xscale);
2270 buf->putDefaultDouble(xscale, yscale);
2271 buf->putDefaultDouble(xscale, zscale);
2272 }
2273
2274 buf->putBitDouble(angle); // radians
2275 buf->putExtrusion(extPoint, /*b_R2000_style=*/false);
2276 buf->putBit(0); // hasAttrib = 0 (no ATTRIBs)
2277 // hasAttrib==0 ⇒ the SINCE-R2004 num_owned BL is absent (parse :3184), so
2278 // the MINSERT grid (oType==8) follows the hasAttrib bit directly. Field
2279 // order mirrors parseDwg :3190-3193 (colcount BS, rowcount BS, colspace BD,
2280 // rowspace BD) and libreDWG dwg.spec num_cols/num_rows/col_spacing/row_spacing.
2281 if (oType == 8) { // MINSERT grid
2282 buf->putBitShort(static_cast<std::uint16_t>(colcount));
2283 buf->putBitShort(static_cast<std::uint16_t>(rowcount));
2284 buf->putBitDouble(colspace);
2285 buf->putBitDouble(rowspace);
2286 }
2287
2288 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
2289
2290 // BLOCK_RECORD hard pointer.
2291 dwgHandle bhH;
2292 bhH.code = (blockRecH.ref == 0) ? 0 : 5;
2293 bhH.ref = blockRecH.ref;
2294 bhH.size = 0;
2295 if (bhH.ref != 0) {
2296 std::uint32_t t = bhH.ref;
2297 while (t != 0) { t >>= 8; ++bhH.size; }
2298 }
2299 (handleBuf ? handleBuf : buf)->putHandle(bhH);
2300 return true;
2301}
2302
2303bool DRW_3Dface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2304 (void)bs; (void)strBuf;
2305 oType = 28; // 3DFACE class id — see dwgreader.cpp:1237
2306 if (!encodeDwgCommon(version, buf)) return false;
2307
2308 // R2000+ 3DFACE body — mirror of parseDwg's z_is_zero / has_no_flag
2309 // optimization. Reader checks `invisibleflag != NoEdge`; if NoEdge,
2310 // emit has_no_flag=1 to suppress the BS read.
2311 bool hasNoFlag = (invisibleflag == /*NoEdge*/0);
2312 bool zIsZero = (basePoint.z == 0.0);
2313 buf->putBit(hasNoFlag ? 1 : 0);
2314 buf->putBit(zIsZero ? 1 : 0);
2315 buf->putRawDouble(basePoint.x);
2316 buf->putRawDouble(basePoint.y);
2317 if (!zIsZero) buf->putRawDouble(basePoint.z);
2318 buf->putDefaultDouble(basePoint.x, secPoint.x);
2319 buf->putDefaultDouble(basePoint.y, secPoint.y);
2320 buf->putDefaultDouble(basePoint.z, secPoint.z);
2321 buf->putDefaultDouble(secPoint.x, thirdPoint.x);
2322 buf->putDefaultDouble(secPoint.y, thirdPoint.y);
2323 buf->putDefaultDouble(secPoint.z, thirdPoint.z);
2324 buf->putDefaultDouble(thirdPoint.x, fourPoint.x);
2325 buf->putDefaultDouble(thirdPoint.y, fourPoint.y);
2326 buf->putDefaultDouble(thirdPoint.z, fourPoint.z);
2327 if (!hasNoFlag) buf->putBitShort(static_cast<std::uint16_t>(invisibleflag));
2328
2329 return encodeDwgEntHandle(version, buf, handleBuf);
2330}
2331
2332bool DRW_Solid::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2333 (void)bs; (void)strBuf;
2334 oType = 31; // SOLID class id — see dwgreader.cpp:1305
2335 if (!encodeDwgCommon(version, buf)) return false;
2336
2337 // Same body layout as TRACE (4 corners + extrusion). Duplicated
2338 // here rather than delegating to DRW_Trace::encodeDwg because that
2339 // hardcodes oType=32.
2340 buf->putThickness(thickness, /*b_R2000_style=*/true);
2341 buf->putBitDouble(basePoint.z);
2342 buf->putRawDouble(basePoint.x);
2343 buf->putRawDouble(basePoint.y);
2344 buf->putRawDouble(secPoint.x);
2345 buf->putRawDouble(secPoint.y);
2346 buf->putRawDouble(thirdPoint.x);
2347 buf->putRawDouble(thirdPoint.y);
2348 buf->putRawDouble(fourPoint.x);
2349 buf->putRawDouble(fourPoint.y);
2350 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2351
2352 return encodeDwgEntHandle(version, buf, handleBuf);
2353}
2354
2355bool DRW_LWPolyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2356 (void)bs; (void)strBuf;
2357 oType = 77; // LWPOLYLINE class id — see dwgreader.cpp:1202
2358 if (!encodeDwgCommon(version, buf)) return false;
2359
2360 // DRW_LWPolyline::flags carries DXF-side bits (1=closed, 128=plinegen).
2361 // DWG-side flags are different: they signal which optional fields are
2362 // present. Per parseDwg, bit 9 (0x200) = closed, bit 8 (0x100) =
2363 // plinegen. Build the DWG flags from the DXF flags plus the data.
2364 std::uint16_t dwgFlags = 0;
2365 if (flags & 1) dwgFlags |= 0x200; // closed
2366 if (flags & 128) dwgFlags |= 0x100; // plinegen
2367 if (thickness != 0.0) dwgFlags |= 0x2;
2368 if (width != 0.0) dwgFlags |= 0x4;
2369 if (elevation != 0.0) dwgFlags |= 0x8;
2370 bool defaultExt = (extPoint.x == 0.0 && extPoint.y == 0.0 && extPoint.z == 1.0);
2371 if (!defaultExt) dwgFlags |= 0x1;
2372 // Detect per-vertex bulge / width data.
2373 bool anyBulge = false;
2374 bool anyWidth = false;
2375 bool anyVertexId = false;
2376 for (const auto& v : vertlist) {
2377 if (v && v->bulge != 0.0) anyBulge = true;
2378 if (v && (v->stawidth != 0.0 || v->endwidth != 0.0)) anyWidth = true;
2379 if (v && v->identifier != 0) anyVertexId = true;
2380 }
2381 if (anyBulge) dwgFlags |= 0x10;
2382 if (anyWidth) dwgFlags |= 0x20;
2383 if (version > DRW::AC1021 && anyVertexId) dwgFlags |= 0x400;
2384
2385 buf->putBitShort(dwgFlags);
2386 if (dwgFlags & 0x4) buf->putBitDouble(width);
2387 if (dwgFlags & 0x8) buf->putBitDouble(elevation);
2388 if (dwgFlags & 0x2) buf->putBitDouble(thickness);
2389 if (dwgFlags & 0x1) buf->putExtrusion(extPoint, /*b_R2000_style=*/false);
2390
2391 const std::int32_t numVerts = static_cast<std::int32_t>(vertlist.size());
2392 buf->putBitLong(numVerts);
2393 if (dwgFlags & 0x10) buf->putBitLong(numVerts); // bulgesnum
2394 if (version > DRW::AC1021 && (dwgFlags & 0x400)) {
2395 buf->putBitLong(numVerts); // vertexIdCount
2396 }
2397 if (dwgFlags & 0x20) buf->putBitLong(numVerts); // widthsnum
2398
2399 if (numVerts > 0) {
2400 // First vertex as 2RD. Subsequent vertices as 2DD relative to
2401 // the previous, with putDefaultDouble always emitting code 0b11
2402 // (full RD); the reader's getDefaultDouble returns the raw value.
2403 buf->putRawDouble(vertlist[0]->x);
2404 buf->putRawDouble(vertlist[0]->y);
2405 for (size_t i = 1; i < vertlist.size(); ++i) {
2406 buf->putDefaultDouble(vertlist[i-1]->x, vertlist[i]->x);
2407 buf->putDefaultDouble(vertlist[i-1]->y, vertlist[i]->y);
2408 }
2409 if (dwgFlags & 0x10) {
2410 for (const auto& v : vertlist)
2411 buf->putBitDouble(v->bulge);
2412 }
2413 if (version > DRW::AC1021 && (dwgFlags & 0x400)) {
2414 for (const auto& v : vertlist)
2415 buf->putBitLong(static_cast<std::int32_t>(v->identifier));
2416 }
2417 if (dwgFlags & 0x20) {
2418 for (const auto& v : vertlist) {
2419 buf->putBitDouble(v->stawidth);
2420 buf->putBitDouble(v->endwidth);
2421 }
2422 }
2423 }
2424
2425 return encodeDwgEntHandle(version, buf, handleBuf);
2426}
2427
2428bool DRW_Block::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2429 (void)bs;
2430 // BLOCK = 4, ENDBLK = 5 per DWG spec. isEnd controls which.
2431 oType = isEnd ? 5 : 4;
2432 if (!encodeDwgCommon(version, buf)) return false;
2433 if (!isEnd) {
2434 (strBuf ? strBuf : buf)->putVariableText(version, name);
2435 }
2436 if (version > DRW::AC1018) {
2437 buf->putBit(0); // unknown bit (R2007+: always 0 for our output)
2438 }
2439 return encodeDwgEntHandle(version, buf, handleBuf);
2440}
2441
2442bool DRW_Text::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2443 (void)bs;
2444 oType = 1; // TEXT class id — see dwgreader.cpp:1208
2445 if (!encodeDwgCommon(version, buf)) return false;
2446
2447 // R2000+ TEXT body — mirror of DRW_Text::parseDwg. We emit
2448 // data_flags=0 so the reader sees every optional field rather than
2449 // substituting defaults — keeps the encoder simple, costs ~30 bytes
2450 // per TEXT versus the most compressed form.
2451 buf->putRawChar8(0); // data_flags=0
2452 buf->putRawDouble(basePoint.z); // elevation RD
2453 buf->putRawDouble(basePoint.x); // insertion 2RD
2454 buf->putRawDouble(basePoint.y);
2455 buf->putDefaultDouble(basePoint.x, secPoint.x); // alignment 2DD
2456 buf->putDefaultDouble(basePoint.y, secPoint.y);
2457 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2458 buf->putThickness(thickness, /*b_R2000_style=*/true);
2459 buf->putRawDouble(oblique); // oblique angle
2460 // Angle: struct holds degrees; on-disk format is radians. Reader
2461 // does `angle *= ARAD` (180/π) after read. Inverse: divide here.
2462 buf->putRawDouble(angle / ARAD57.29577951308232);
2463 buf->putRawDouble(height); // text height
2464 buf->putRawDouble(widthscale); // width factor
2465 (strBuf ? strBuf : buf)->putVariableText(version, text); // text string
2466 buf->putBitShort(static_cast<std::uint16_t>(textgen));
2467 buf->putBitShort(static_cast<std::uint16_t>(alignH));
2468 buf->putBitShort(static_cast<std::uint16_t>(alignV));
2469
2470 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
2471
2472 // styleH — hard pointer to STYLE table record. Default points at
2473 // the STANDARD textstyle (handle 0x13) if caller hasn't set one.
2474 dwgHandle sH;
2475 std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref;
2476 sH.code = 5; // hard pointer
2477 sH.ref = sref;
2478 sH.size = 0;
2479 if (sref != 0) {
2480 std::uint32_t t = sref;
2481 while (t != 0) { t >>= 8; ++sH.size; }
2482 }
2483 (handleBuf ? handleBuf : buf)->putHandle(sH);
2484 return true;
2485}
2486
2487bool DRW_Ellipse::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2488 (void)bs; (void)strBuf;
2489 oType = 35; // ELLIPSE class id — see dwgreader.cpp:1117
2490 if (!encodeDwgCommon(version, buf)) return false;
2491
2492 // Ellipse body — mirror of DRW_Ellipse::parseDwg.
2493 buf->put3BitDouble(basePoint); // center
2494 buf->put3BitDouble(secPoint); // major axis vector
2495 buf->put3BitDouble(extPoint); // extrusion
2496 buf->putBitDouble(ratio); // minor/major ratio
2497 buf->putBitDouble(staparam); // start parameter
2498 buf->putBitDouble(endparam); // end parameter
2499
2500 return encodeDwgEntHandle(version, buf, handleBuf);
2501}
2502
2503bool DRW_Arc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2504 (void)bs; (void)strBuf;
2505 oType = 17; // ARC class id — see dwgreader.cpp:1093
2506 if (!encodeDwgCommon(version, buf)) return false;
2507
2508 // Arc body — Circle body + 2 BD angles.
2509 buf->putBitDouble(basePoint.x);
2510 buf->putBitDouble(basePoint.y);
2511 buf->putBitDouble(basePoint.z);
2512 buf->putBitDouble(radious);
2513 buf->putThickness(thickness, /*b_R2000_style=*/true);
2514 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2515 buf->putBitDouble(staangle);
2516 buf->putBitDouble(endangle);
2517
2518 return encodeDwgEntHandle(version, buf, handleBuf);
2519}
2520
2521bool DRW_Line::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2522 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2523 if (!ret)
2524 return ret;
2525 DRW_DBG("\n***************************** parsing line *********************************************\n")DRW_dbg::dbg("\n***************************** parsing line *********************************************\n"
)
;
2526
2527 if (version < DRW::AC1015) {//14-
2528 basePoint.x = buf->getBitDouble();
2529 basePoint.y = buf->getBitDouble();
2530 basePoint.z = buf->getBitDouble();
2531 secPoint.x = buf->getBitDouble();
2532 secPoint.y = buf->getBitDouble();
2533 secPoint.z = buf->getBitDouble();
2534 }
2535 if (version > DRW::AC1014) {//2000+
2536 bool zIsZero = buf->getBit(); //B
2537 basePoint.x = buf->getRawDouble();//RD
2538 secPoint.x = buf->getDefaultDouble(basePoint.x);//DD
2539 basePoint.y = buf->getRawDouble();//RD
2540 secPoint.y = buf->getDefaultDouble(basePoint.y);//DD
2541 if (!zIsZero) {
2542 basePoint.z = buf->getRawDouble();//RD
2543 secPoint.z = buf->getDefaultDouble(basePoint.z);//DD
2544 }
2545 }
2546 DRW_DBG("start point: ")DRW_dbg::dbg("start point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2547 DRW_DBG("\nend point: ")DRW_dbg::dbg("\nend point: "); DRW_DBGPT(secPoint.x, secPoint.y, secPoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, secPoint.z);
2548 thickness = buf->getThickness(version > DRW::AC1014);//BD
2549 DRW_DBG("\nthickness: ")DRW_dbg::dbg("\nthickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
2550 extPoint = buf->getExtrusion(version > DRW::AC1014);
2551 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");
2552 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2553 if (!ret)
2554 return ret;
2555// RS crc; //RS */
2556 return buf->isGood();
2557}
2558
2559bool DRW_Ray::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2560 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2561 if (!ret)
2562 return ret;
2563 DRW_DBG("\n***************************** parsing ray/xline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing ray/xline *********************************************\n"
)
;
2564 basePoint.x = buf->getBitDouble();
2565 basePoint.y = buf->getBitDouble();
2566 basePoint.z = buf->getBitDouble();
2567 secPoint.x = buf->getBitDouble();
2568 secPoint.y = buf->getBitDouble();
2569 secPoint.z = buf->getBitDouble();
2570 DRW_DBG("start point: ")DRW_dbg::dbg("start point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2571 DRW_DBG("\nvector: ")DRW_dbg::dbg("\nvector: "); DRW_DBGPT(secPoint.x, secPoint.y, secPoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, secPoint.z);
2572 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2573 if (!ret)
2574 return ret;
2575// RS crc; //RS */
2576 return buf->isGood();
2577}
2578
2579void DRW_Circle::applyExtrusion(){
2580 if (haveExtrusion) {
2581 //NOTE: Commenting these out causes the the arcs being tested to be located
2582 //on the other side of the y axis (all x dimensions are negated).
2583 calculateAxis(extPoint);
2584 extrudePoint(extPoint, &basePoint);
2585 }
2586}
2587
2588bool DRW_Circle::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2589 switch (code) {
2590 case 40:
2591 radious = reader->getDouble();
2592 break;
2593 default:
2594 return DRW_Point::parseCode(code, reader);
2595 }
2596
2597 return true;
2598}
2599
2600bool DRW_Circle::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2601 bool ret = DRW_Entity::parseDwg(version, buf, nullptr, bs);
2602 if (!ret)
2603 return ret;
2604 DRW_DBG("\n***************************** parsing circle *********************************************\n")DRW_dbg::dbg("\n***************************** parsing circle *********************************************\n"
)
;
2605
2606 basePoint.x = buf->getBitDouble();
2607 basePoint.y = buf->getBitDouble();
2608 basePoint.z = buf->getBitDouble();
2609 DRW_DBG("center: ")DRW_dbg::dbg("center: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2610 radious = buf->getBitDouble();
2611 DRW_DBG("\nradius: ")DRW_dbg::dbg("\nradius: "); DRW_DBG(radious)DRW_dbg::dbg(radious);
2612
2613 thickness = buf->getThickness(version > DRW::AC1014);
2614 DRW_DBG(" thickness: ")DRW_dbg::dbg(" thickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
2615 extPoint = buf->getExtrusion(version > DRW::AC1014);
2616 DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n");
2617
2618 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2619 if (!ret)
2620 return ret;
2621// RS crc; //RS */
2622 return buf->isGood();
2623}
2624
2625void DRW_Arc::applyExtrusion(){
2626 DRW_Circle::applyExtrusion();
2627
2628 if(haveExtrusion){
2629 // If the extrusion vector has a z value less than 0, the angles for the arc
2630 // have to be mirrored since DXF files use the right hand rule.
2631 // Note that the following code only handles the special case where there is a 2D
2632 // drawing with the z axis heading into the paper (or rather screen). An arbitrary
2633 // extrusion axis (with x and y values greater than 1/64) may still have issues.
2634 if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625 && extPoint.z < 0.0) {
2635 staangle=M_PI3.14159265358979323846-staangle;
2636 endangle=M_PI3.14159265358979323846-endangle;
2637
2638 double temp = staangle;
2639 staangle=endangle;
2640 endangle=temp;
2641 }
2642 }
2643}
2644
2645bool DRW_Arc::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2646 switch (code) {
2647 case 50:
2648 staangle = reader->getDouble()/ ARAD57.29577951308232;
2649 break;
2650 case 51:
2651 endangle = reader->getDouble()/ ARAD57.29577951308232;
2652 break;
2653 default:
2654 return DRW_Circle::parseCode(code, reader);
2655 }
2656
2657 return true;
2658}
2659
2660bool DRW_Arc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2661 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2662 if (!ret)
2663 return ret;
2664 DRW_DBG("\n***************************** parsing circle arc *********************************************\n")DRW_dbg::dbg("\n***************************** parsing circle arc *********************************************\n"
)
;
2665
2666 basePoint.x = buf->getBitDouble();
2667 basePoint.y = buf->getBitDouble();
2668 basePoint.z = buf->getBitDouble();
2669 DRW_DBG("center point: ")DRW_dbg::dbg("center point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2670
2671 radious = buf->getBitDouble();
2672 DRW_DBG("\nradius: ")DRW_dbg::dbg("\nradius: "); DRW_DBG(radious)DRW_dbg::dbg(radious);
2673 thickness = buf->getThickness(version > DRW::AC1014);
2674 DRW_DBG(" thickness: ")DRW_dbg::dbg(" thickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
2675 extPoint = buf->getExtrusion(version > DRW::AC1014);
2676 DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
2677 staangle = buf->getBitDouble();
2678 DRW_DBG("\nstart angle: ")DRW_dbg::dbg("\nstart angle: "); DRW_DBG(staangle)DRW_dbg::dbg(staangle);
2679 endangle = buf->getBitDouble();
2680 DRW_DBG(" end angle: ")DRW_dbg::dbg(" end angle: "); DRW_DBG(endangle)DRW_dbg::dbg(endangle); DRW_DBG("\n")DRW_dbg::dbg("\n");
2681 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2682 if (!ret)
2683 return ret;
2684 return buf->isGood();
2685}
2686
2687bool DRW_Ellipse::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2688 switch (code) {
2689 case 40:
2690 ratio = reader->getDouble();
2691 break;
2692 case 41:
2693 staparam = reader->getDouble();
2694 break;
2695 case 42:
2696 endparam = reader->getDouble();
2697 break;
2698 default:
2699 return DRW_Line::parseCode(code, reader);
2700 }
2701
2702 return true;
2703}
2704
2705void DRW_Ellipse::applyExtrusion(){
2706 if (haveExtrusion) {
2707 calculateAxis(extPoint);
2708 extrudePoint(extPoint, &secPoint);
2709 double intialparam = staparam;
2710 if (extPoint.z < 0.){
2711 staparam = M_PIx26.283185307179586 - endparam;
2712 endparam = M_PIx26.283185307179586 - intialparam;
2713 }
2714 }
2715}
2716
2717//if ratio > 1 minor axis are greather than major axis, correct it
2718void DRW_Ellipse::correctAxis(){
2719 bool complete = false;
2720 if (staparam == endparam) {
2721 staparam = 0.0;
2722 endparam = M_PIx26.283185307179586; //2*M_PI;
2723 complete = true;
2724 }
2725 if (ratio > 1){
2726 if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10)
2727 complete = true;
2728 double incX = secPoint.x;
2729 secPoint.x = -(secPoint.y * ratio);
2730 secPoint.y = incX*ratio;
2731 ratio = 1/ratio;
2732 if (!complete){
2733 if (staparam < M_PI_21.57079632679489661923)
2734 staparam += M_PI3.14159265358979323846 *2;
2735 if (endparam < M_PI_21.57079632679489661923)
2736 endparam += M_PI3.14159265358979323846 *2;
2737 endparam -= M_PI_21.57079632679489661923;
2738 staparam -= M_PI_21.57079632679489661923;
2739 }
2740 }
2741}
2742
2743bool DRW_Ellipse::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2744 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2745 if (!ret)
2746 return ret;
2747 DRW_DBG("\n***************************** parsing ellipse *********************************************\n")DRW_dbg::dbg("\n***************************** parsing ellipse *********************************************\n"
)
;
2748
2749 basePoint =buf->get3BitDouble();
2750 DRW_DBG("center: ")DRW_dbg::dbg("center: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2751 secPoint =buf->get3BitDouble();
2752 DRW_DBG(", axis: ")DRW_dbg::dbg(", axis: "); DRW_DBGPT(secPoint.x, secPoint.y, secPoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, secPoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n");
2753 extPoint =buf->get3BitDouble();
2754 DRW_DBG("Extrusion: ")DRW_dbg::dbg("Extrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
2755 ratio = buf->getBitDouble();//BD
2756 DRW_DBG("\nratio: ")DRW_dbg::dbg("\nratio: "); DRW_DBG(ratio)DRW_dbg::dbg(ratio);
2757 staparam = buf->getBitDouble();//BD
2758 DRW_DBG(" start param: ")DRW_dbg::dbg(" start param: "); DRW_DBG(staparam)DRW_dbg::dbg(staparam);
2759 endparam = buf->getBitDouble();//BD
2760 DRW_DBG(" end param: ")DRW_dbg::dbg(" end param: "); DRW_DBG(endparam)DRW_dbg::dbg(endparam); DRW_DBG("\n")DRW_dbg::dbg("\n");
2761
2762 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2763 if (!ret)
2764 return ret;
2765// RS crc; //RS */
2766 return buf->isGood();
2767}
2768
2769//parts are the number of vertex to split polyline, default 128
2770void DRW_Ellipse::toPolyline(DRW_Polyline *pol, int parts){
2771 double radMajor, radMinor, cosRot, sinRot, incAngle, curAngle;
2772 double cosCurr, sinCurr;
2773 radMajor = hypot(secPoint.x, secPoint.y);
2774 radMinor = radMajor*ratio;
2775 //calculate sin & cos of included angle
2776 incAngle = atan2(secPoint.y, secPoint.x);
2777 cosRot = cos(incAngle);
2778 sinRot = sin(incAngle);
2779 incAngle = M_PIx26.283185307179586 / parts;
2780 curAngle = staparam;
2781 int i = static_cast<int>(curAngle / incAngle);
2782 do {
2783 if (curAngle > endparam) {
2784 curAngle = endparam;
2785 i = parts+2;
2786 }
2787 cosCurr = cos(curAngle);
2788 sinCurr = sin(curAngle);
2789 double x = basePoint.x + (cosCurr*cosRot*radMajor) - (sinCurr*sinRot*radMinor);
2790 double y = basePoint.y + (cosCurr*sinRot*radMajor) + (sinCurr*cosRot*radMinor);
2791 pol->addVertex( DRW_Vertex(x, y, 0.0, 0.0));
2792 curAngle = (++i)*incAngle;
2793 } while (i<parts);
2794 if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10){
2795 pol->flags = 1;
2796 }
2797 pol->layer = this->layer;
2798 pol->lineType = this->lineType;
2799 pol->color = this->color;
2800 pol->lWeight = this->lWeight;
2801 pol->extPoint = this->extPoint;
2802}
2803
2804void DRW_Trace::applyExtrusion(){
2805 if (haveExtrusion) {
2806 calculateAxis(extPoint);
2807 extrudePoint(extPoint, &basePoint);
2808 extrudePoint(extPoint, &secPoint);
2809 extrudePoint(extPoint, &thirdPoint);
2810 extrudePoint(extPoint, &fourPoint);
2811 }
2812}
2813
2814bool DRW_Trace::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2815 switch (code) {
2816 case 12:
2817 thirdPoint.x = reader->getDouble();
2818 break;
2819 case 22:
2820 thirdPoint.y = reader->getDouble();
2821 break;
2822 case 32:
2823 thirdPoint.z = reader->getDouble();
2824 break;
2825 case 13:
2826 fourPoint.x = reader->getDouble();
2827 break;
2828 case 23:
2829 fourPoint.y = reader->getDouble();
2830 break;
2831 case 33:
2832 fourPoint.z = reader->getDouble();
2833 break;
2834 default:
2835 return DRW_Line::parseCode(code, reader);
2836 }
2837
2838 return true;
2839}
2840
2841bool DRW_Trace::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2842 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2843 if (!ret)
2844 return ret;
2845 DRW_DBG("\n***************************** parsing Trace *********************************************\n")DRW_dbg::dbg("\n***************************** parsing Trace *********************************************\n"
)
;
2846
2847 thickness = buf->getThickness(version>DRW::AC1014);
2848 basePoint.z = buf->getBitDouble();
2849 basePoint.x = buf->getRawDouble();
2850 basePoint.y = buf->getRawDouble();
2851 secPoint.x = buf->getRawDouble();
2852 secPoint.y = buf->getRawDouble();
2853 secPoint.z = basePoint.z;
2854 thirdPoint.x = buf->getRawDouble();
2855 thirdPoint.y = buf->getRawDouble();
2856 thirdPoint.z = basePoint.z;
2857 fourPoint.x = buf->getRawDouble();
2858 fourPoint.y = buf->getRawDouble();
2859 fourPoint.z = basePoint.z;
2860 extPoint = buf->getExtrusion(version>DRW::AC1014);
2861
2862 DRW_DBG(" - base ")DRW_dbg::dbg(" - base "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2863 DRW_DBG("\n - sec ")DRW_dbg::dbg("\n - sec "); DRW_DBGPT(secPoint.x, secPoint.y, secPoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, secPoint.z);
2864 DRW_DBG("\n - third ")DRW_dbg::dbg("\n - third "); DRW_DBGPT(thirdPoint.x, thirdPoint.y, thirdPoint.z)DRW_dbg::dbgPT(thirdPoint.x, thirdPoint.y, thirdPoint.z);
2865 DRW_DBG("\n - fourth ")DRW_dbg::dbg("\n - fourth "); DRW_DBGPT(fourPoint.x, fourPoint.y, fourPoint.z)DRW_dbg::dbgPT(fourPoint.x, fourPoint.y, fourPoint.z);
2866 DRW_DBG("\n - extrusion: ")DRW_dbg::dbg("\n - extrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
2867 DRW_DBG("\n - thickness: ")DRW_dbg::dbg("\n - thickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness); DRW_DBG("\n")DRW_dbg::dbg("\n");
2868
2869 /* Common Entity Handle Data */
2870 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2871 if (!ret)
2872 return ret;
2873
2874 /* CRC X --- */
2875 return buf->isGood();
2876}
2877
2878bool DRW_Solid::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
2879 DRW_DBG("\n***************************** parsing Solid *********************************************\n")DRW_dbg::dbg("\n***************************** parsing Solid *********************************************\n"
)
;
2880 return DRW_Trace::parseDwg(v, buf, bs);
2881}
2882
2883bool DRW_3Dface::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2884 switch (code) {
2885 case 70:
2886 invisibleflag = reader->getInt32();
2887 break;
2888 default:
2889 return DRW_Trace::parseCode(code, reader);
2890 }
2891
2892 return true;
2893}
2894
2895bool DRW_3Dface::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
2896 bool ret = DRW_Entity::parseDwg(v, buf, NULL__null, bs);
2897 if (!ret)
2898 return ret;
2899 DRW_DBG("\n***************************** parsing 3Dface *********************************************\n")DRW_dbg::dbg("\n***************************** parsing 3Dface *********************************************\n"
)
;
2900
2901 if ( v < DRW::AC1015 ) {// R13 & R14
2902 basePoint.x = buf->getBitDouble();
2903 basePoint.y = buf->getBitDouble();
2904 basePoint.z = buf->getBitDouble();
2905 secPoint.x = buf->getBitDouble();
2906 secPoint.y = buf->getBitDouble();
2907 secPoint.z = buf->getBitDouble();
2908 thirdPoint.x = buf->getBitDouble();
2909 thirdPoint.y = buf->getBitDouble();
2910 thirdPoint.z = buf->getBitDouble();
2911 fourPoint.x = buf->getBitDouble();
2912 fourPoint.y = buf->getBitDouble();
2913 fourPoint.z = buf->getBitDouble();
2914 invisibleflag = buf->getBitShort();
2915 } else { // 2000+
2916 bool has_no_flag = buf->getBit();
2917 bool z_is_zero = buf->getBit();
2918 basePoint.x = buf->getRawDouble();
2919 basePoint.y = buf->getRawDouble();
2920 basePoint.z = z_is_zero ? 0.0 : buf->getRawDouble();
2921 secPoint.x = buf->getDefaultDouble(basePoint.x);
2922 secPoint.y = buf->getDefaultDouble(basePoint.y);
2923 secPoint.z = buf->getDefaultDouble(basePoint.z);
2924 thirdPoint.x = buf->getDefaultDouble(secPoint.x);
2925 thirdPoint.y = buf->getDefaultDouble(secPoint.y);
2926 thirdPoint.z = buf->getDefaultDouble(secPoint.z);
2927 fourPoint.x = buf->getDefaultDouble(thirdPoint.x);
2928 fourPoint.y = buf->getDefaultDouble(thirdPoint.y);
2929 fourPoint.z = buf->getDefaultDouble(thirdPoint.z);
2930 invisibleflag = has_no_flag ? (int)NoEdge : buf->getBitShort();
2931 }
2932 drw_assert(invisibleflag>=NoEdge);
2933 drw_assert(invisibleflag<=AllEdges);
2934
2935 DRW_DBG(" - base ")DRW_dbg::dbg(" - base "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n");
2936 DRW_DBG(" - sec ")DRW_dbg::dbg(" - sec "); DRW_DBGPT(secPoint.x, secPoint.y, secPoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, secPoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n");
2937 DRW_DBG(" - third ")DRW_dbg::dbg(" - third "); DRW_DBGPT(thirdPoint.x, thirdPoint.y, thirdPoint.z)DRW_dbg::dbgPT(thirdPoint.x, thirdPoint.y, thirdPoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n");
2938 DRW_DBG(" - fourth ")DRW_dbg::dbg(" - fourth "); DRW_DBGPT(fourPoint.x, fourPoint.y, fourPoint.z)DRW_dbg::dbgPT(fourPoint.x, fourPoint.y, fourPoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n");
2939 DRW_DBG(" - Invisibility mask: ")DRW_dbg::dbg(" - Invisibility mask: "); DRW_DBG(invisibleflag)DRW_dbg::dbg(invisibleflag); DRW_DBG("\n")DRW_dbg::dbg("\n");
2940
2941 /* Common Entity Handle Data */
2942 ret = DRW_Entity::parseDwgEntHandle(v, buf);
2943 if (!ret)
2944 return ret;
2945 return buf->isGood();
2946}
2947
2948bool DRW_ModelerGeometry::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
2949 m_bodyBitSize = bs;
2950 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
2951 if (!ret)
2952 return ret;
2953 DRW_DBG("\n***************************** parsing modeler geometry ******************\n")DRW_dbg::dbg("\n***************************** parsing modeler geometry ******************\n"
)
;
2954
2955 m_isEmpty = buf->getBit() != 0;
2956 m_hasModelerData = !m_isEmpty;
2957 m_modelerDataUnknownBit = buf->getBit() != 0;
2958 if (m_hasModelerData)
2959 m_modelerVersion = buf->getBitShort();
2960
2961 ret = DRW_Entity::parseDwgEntHandle(v, buf);
2962 if (eType == DRW::E3DSOLID && v > DRW::AC1018 && buf->numRemainingBytes() > 2) {
2963 dwgHandle historyH = buf->getHandle();
2964 m_historyHandle = historyH.ref;
2965 DRW_DBG(" 3DSOLID history Handle: ")DRW_dbg::dbg(" 3DSOLID history Handle: ");
2966 DRW_DBGHL(historyH.code, historyH.size, historyH.ref)DRW_dbg::dbgHL(historyH.code, historyH.size, historyH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
2967 }
2968
2969 return ret;
2970}
2971
2972bool DRW_ModelerGeometry::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
2973 switch (code) {
2974 case 1:
2975 case 3:
2976 appendTextBytes(m_rawBytes, reader->getString());
2977 break;
2978 case 70:
2979 m_modelerVersion = static_cast<std::uint16_t>(reader->getInt32());
2980 break;
2981 case 350:
2982 case 360:
2983 m_historyHandle = static_cast<std::uint32_t>(reader->getHandleString());
2984 break;
2985 case 310:
2986 {
2987 std::vector<std::uint8_t> decoded;
2988 if (!decodeHexBytes(reader->getString(), decoded))
2989 return false;
2990 appendBytes(m_rawBytes, decoded);
2991 }
2992 break;
2993 default:
2994 return DRW_Entity::parseCode(code, reader);
2995 }
2996 return true;
2997}
2998
2999// DRW_Mesh::parseDwg — AcDbSubDMesh, field order per libreDWG dwg2.spec:2523
3000// (DWG bitstream order, NOT the DXF group-code order). R2010+ only in practice
3001// (the custom-class dispatch only fires when classesmap names "MESH").
3002bool DRW_Mesh::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3003 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
3004 if (!ret)
3005 return ret;
3006 DRW_DBG("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n")DRW_dbg::dbg("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n"
)
;
3007
3008 // Loose OOM/corruption guard: a count can't exceed the bits left in the
3009 // object (each item is >= 1 bit; crease/face values are bit-packed and may be
3010 // far below 1 byte each, so a per-byte bound would falsely reject valid data).
3011 auto sane = [&](std::int32_t n) {
3012 return n >= 0
3013 && static_cast<std::int64_t>(n)
3014 <= static_cast<std::int64_t>(buf->numRemainingBytes()) * 8 + 8;
3015 };
3016
3017 version = buf->getBitShort(); // BS dlevel (71)
3018 blendCrease = buf->getBit() != 0; // B is_watertight (72)
3019
3020 const std::int32_t nSubdiv = buf->getBitLong(); // BL num_subdiv_vertex (91)
3021 if (!sane(nSubdiv)) return false;
3022 subdivisionLevel = nSubdiv;
3023 subdivVertices.reserve(static_cast<size_t>(nSubdiv));
3024 for (std::int32_t i = 0; i < nSubdiv && buf->isGood(); ++i)
3025 subdivVertices.push_back(buf->get3BitDouble());
3026
3027 const std::int32_t nVert = buf->getBitLong(); // BL num_vertex (92)
3028 if (!sane(nVert)) return false;
3029 vertices.reserve(static_cast<size_t>(nVert));
3030 for (std::int32_t i = 0; i < nVert && buf->isGood(); ++i)
3031 vertices.push_back(buf->get3BitDouble());
3032
3033 // faces (93) is a FLAT BL stream of length num_faces; each face is
3034 // [count, idx0, idx1, ...]. num_faces is the stream length, not the polygon
3035 // count — group on the fly.
3036 std::int32_t remaining = buf->getBitLong(); // BL num_faces (93)
3037 if (!sane(remaining)) return false;
3038 while (remaining > 0 && buf->isGood()) {
3039 const std::int32_t cnt = buf->getBitLong();
3040 --remaining;
3041 if (cnt < 0 || cnt > remaining)
3042 break; // corrupt face run
3043 std::vector<std::int32_t> face;
3044 face.reserve(static_cast<size_t>(cnt));
3045 for (std::int32_t j = 0; j < cnt && buf->isGood(); ++j) {
3046 face.push_back(buf->getBitLong());
3047 --remaining;
3048 }
3049 faces.push_back(std::move(face));
3050 }
3051
3052 const std::int32_t nEdges = buf->getBitLong(); // BL num_edges (94)
3053 if (!sane(nEdges)) return false;
3054 edges.reserve(static_cast<size_t>(nEdges));
3055 for (std::int32_t i = 0; i < nEdges && buf->isGood(); ++i) {
3056 const std::int32_t from = buf->getBitLong();
3057 const std::int32_t to = buf->getBitLong();
3058 edges.emplace_back(from, to);
3059 }
3060
3061 const std::int32_t nCrease = buf->getBitLong(); // BL num_crease (95)
3062 if (!sane(nCrease)) return false;
3063 creases.reserve(static_cast<size_t>(nCrease));
3064 for (std::int32_t i = 0; i < nCrease && buf->isGood(); ++i)
3065 creases.push_back(buf->getBitDouble());
3066
3067 buf->getBit(); // unknown_b1
3068 buf->getBit(); // unknown_b2
3069
3070 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3071 return ret;
3072}
3073
3074// DRW_Mesh::parseCode — DXF read (codes 71/72/91/92/10·20·30/93/90/94/95/140).
3075// The 90 stream is shared by faces (after 93) and edges (after 94); m_dxfState
3076// sequences which one is being filled (mirrors DRW_Image::parseCode's stateful
3077// 91/14/24 WIPEOUT-vertex accumulation).
3078bool DRW_Mesh::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3079 switch (code) {
3080 case 71: version = reader->getInt32(); return true;
3081 case 72: blendCrease = reader->getInt32() != 0; return true;
3082 case 91: subdivisionLevel = reader->getInt32(); return true;
3083 case 92: /* base-vertex count */ vertices.reserve(reader->getInt32()); return true;
3084 case 10: vertices.emplace_back(); vertices.back().x = reader->getDouble(); return true;
3085 case 20: if (!vertices.empty()) vertices.back().y = reader->getDouble(); return true;
3086 case 30: if (!vertices.empty()) vertices.back().z = reader->getDouble(); return true;
3087 case 93: m_dxfState = 93; m_dxfPending = 0; return true; // start face stream
3088 case 94: m_dxfState = 94; m_dxfEdgeFrom = -1; (void)reader->getInt32(); return true; // edge count
3089 case 90: {
3090 const std::int32_t val = reader->getInt32();
3091 if (m_dxfState == 93) {
3092 // flat face stream: when no face is in progress, val is the next
3093 // face's vertex count; otherwise val is a vertex index.
3094 if (m_dxfPending == 0) {
3095 faces.emplace_back();
3096 m_dxfPending = (val > 0) ? val : 0;
3097 } else {
3098 if (!faces.empty()) faces.back().push_back(val);
3099 --m_dxfPending;
3100 }
3101 } else if (m_dxfState == 94) {
3102 if (m_dxfEdgeFrom < 0) m_dxfEdgeFrom = val;
3103 else { edges.emplace_back(m_dxfEdgeFrom, val); m_dxfEdgeFrom = -1; }
3104 }
3105 return true;
3106 }
3107 case 95: m_dxfState = 95; creases.reserve(static_cast<size_t>(std::max(0, reader->getInt32()))); return true;
3108 case 140: creases.push_back(reader->getDouble()); return true;
3109 default:
3110 return DRW_Entity::parseCode(code, reader);
3111 }
3112}
3113
3114bool DRW_Mesh::encodeDwg(DRW::Version dwgVersion, dwgBufferW *buf, std::uint32_t bs,
3115 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3116 (void)bs; (void)strBuf;
3117 oType = kDwgClassNum;
3118 if (!encodeDwgCommon(dwgVersion, buf)) return false;
3119
3120 buf->putBitShort(version);
3121 buf->putBit(blendCrease ? 1 : 0);
3122
3123 // DWG stores a subdiv-vertex vector in the slot that DXF exposes as group
3124 // 91 subdivision level. Preserve the vector exactly; DXF write keeps the
3125 // public subdivisionLevel field.
3126 buf->putBitLong(static_cast<std::int32_t>(subdivVertices.size()));
3127 for (const DRW_Coord& vertex : subdivVertices)
3128 buf->put3BitDouble(vertex);
3129
3130 buf->putBitLong(static_cast<std::int32_t>(vertices.size()));
3131 for (const DRW_Coord& vertex : vertices)
3132 buf->put3BitDouble(vertex);
3133
3134 std::int32_t faceStreamCount = 0;
3135 for (const auto& face : faces)
3136 faceStreamCount += static_cast<std::int32_t>(face.size() + 1);
3137 buf->putBitLong(faceStreamCount);
3138 for (const auto& face : faces) {
3139 buf->putBitLong(static_cast<std::int32_t>(face.size()));
3140 for (std::int32_t index : face)
3141 buf->putBitLong(index);
3142 }
3143
3144 buf->putBitLong(static_cast<std::int32_t>(edges.size()));
3145 for (const auto& edge : edges) {
3146 buf->putBitLong(edge.first);
3147 buf->putBitLong(edge.second);
3148 }
3149
3150 buf->putBitLong(static_cast<std::int32_t>(creases.size()));
3151 for (double crease : creases)
3152 buf->putBitDouble(crease);
3153
3154 buf->putBit(0);
3155 buf->putBit(0);
3156
3157 return encodeDwgEntHandle(dwgVersion, buf, handleBuf);
3158}
3159
3160bool DRW_Shape::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3161 m_bodyBitSize = bs;
3162 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
3163 if (!ret)
3164 return ret;
3165 DRW_DBG("\n***************************** parsing SHAPE *****************************\n")DRW_dbg::dbg("\n***************************** parsing SHAPE *****************************\n"
)
;
3166
3167 m_insertionPoint = buf->get3BitDouble();
3168 m_scale = buf->getBitDouble();
3169 m_rotation = buf->getBitDouble();
3170 m_widthFactor = buf->getBitDouble();
3171 m_oblique = buf->getBitDouble();
3172 m_thickness = buf->getBitDouble();
3173 m_shapeIndex = buf->getBitShort();
3174 m_extrusion = buf->get3BitDouble();
3175
3176 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3177 if (ret && buf->numRemainingBytes() > 2) {
3178 dwgHandle shapeFileH = buf->getHandle();
3179 m_shapeFileHandle = shapeFileH.ref;
3180 DRW_DBG(" SHAPEFILE Handle: ")DRW_dbg::dbg(" SHAPEFILE Handle: ");
3181 DRW_DBGHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref)DRW_dbg::dbgHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref
)
;
3182 DRW_DBG("\n")DRW_dbg::dbg("\n");
3183 }
3184 return ret && buf->isGood();
3185}
3186
3187// Phase 6.1: SHAPE encoder (fixed oType 33). Exact inverse of parseDwg above.
3188// Without this override a SHAPE would encode as a LINE (default DRW_Entity).
3189bool DRW_Shape::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
3190 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3191 (void)bs; (void)strBuf;
3192 oType = 33; // SHAPE class id — see dwgreader.cpp case 33
3193 if (!encodeDwgCommon(version, buf)) return false;
3194
3195 buf->put3BitDouble(m_insertionPoint);
3196 buf->putBitDouble(m_scale);
3197 buf->putBitDouble(m_rotation);
3198 buf->putBitDouble(m_widthFactor);
3199 buf->putBitDouble(m_oblique);
3200 buf->putBitDouble(m_thickness);
3201 buf->putBitShort(m_shapeIndex);
3202 buf->put3BitDouble(m_extrusion);
3203
3204 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
3205
3206 // Trailing SHAPEFILE style hard pointer (code 5), byte-count-sized.
3207 dwgHandle sH;
3208 sH.code = 5;
3209 sH.ref = m_shapeFileHandle;
3210 sH.size = 0;
3211 if (m_shapeFileHandle != 0) {
3212 std::uint32_t t = m_shapeFileHandle;
3213 while (t != 0) { t >>= 8; ++sH.size; }
3214 } else {
3215 sH.code = 0; // null handle
3216 }
3217 (handleBuf ? handleBuf : buf)->putHandle(sH);
3218 return true;
3219}
3220
3221bool DRW_Ole2Frame::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3222 m_bodyBitSize = bs;
3223 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
3224 if (!ret)
3225 return ret;
3226 DRW_DBG("\n***************************** parsing OLE2FRAME ************************\n")DRW_dbg::dbg("\n***************************** parsing OLE2FRAME ************************\n"
)
;
3227
3228 m_flags = buf->getBitShort();
3229 if (v > DRW::AC1014)
3230 m_mode = buf->getBitShort();
3231 m_declaredPayloadLength = buf->getBitLong();
3232 m_payloadStartBit = currentDwgBit(buf);
3233 const std::uint64_t currentBit = currentDwgBit(buf);
3234 const std::uint64_t bodyRemainingBits =
3235 (v > DRW::AC1018 && objSize > currentBit)
3236 ? objSize - currentBit
3237 : static_cast<std::uint64_t>(buf->numRemainingBytes()) * 8u;
3238 const std::uint32_t remainingBytes =
3239 static_cast<std::uint32_t>(std::min<std::uint64_t>(
3240 bodyRemainingBits / 8u,
3241 static_cast<std::uint64_t>(std::numeric_limits<std::uint32_t>::max())));
3242 if (m_declaredPayloadLength > kMaxOlePayloadBytes) {
3243 m_payloadTooLarge = true;
3244 return false;
3245 }
3246 if (m_declaredPayloadLength > remainingBytes) { // remainingBytes is already uint32
3247 m_payloadTruncated = true;
3248 m_payloadByteCount = remainingBytes;
3249 return false;
3250 }
3251
3252 m_payloadPresent = m_declaredPayloadLength > 0;
3253 m_payloadByteCount = m_declaredPayloadLength;
3254 // Phase 6.2: capture the opaque payload bytes (was skipped via moveBitPos)
3255 // so the OLE2FRAME encoder can re-emit them byte-for-byte.
3256 if (m_declaredPayloadLength > 0) {
3257 m_payloadBytes.resize(m_declaredPayloadLength);
3258 if (!buf->getBytes(m_payloadBytes.data(), m_declaredPayloadLength)) {
3259 m_payloadTruncated = true;
3260 m_payloadBytes.clear();
3261 return false;
3262 }
3263 }
3264
3265 if (v > DRW::AC1014 && buf->numRemainingBytes() > 0) {
3266 m_hasR2000TrailingByte = true;
3267 m_r2000TrailingByte = buf->getRawChar8();
3268 }
3269
3270 // Decode the frame rectangle (DXF 10/11) from the OLE header. AutoCAD/ODA do
3271 // NOT store pt1/pt2 as DWG fields; they live in the first ~0x80 bytes of the
3272 // payload as raw little-endian doubles. (libredwg's dwg_decode_ole2 is a stub
3273 // that hardcodes one sample file's corners.) Layout reverse-engineered and
3274 // validated on TS1 + Extruder2: byte 0x00 == 0x80 marker; upper-left @0x02,
3275 // lower-right @0x32, 3 doubles each. Guarded so a non-finite/short payload
3276 // simply leaves pt1/pt2 at the origin (payload still preserved).
3277 if (m_payloadBytes.size() >= 0x4a && m_payloadBytes[0] == 0x80) {
3278 auto rd = [&](std::size_t off) {
3279 double d = 0.0;
3280 std::memcpy(&d, m_payloadBytes.data() + off, sizeof(double));
3281 return d;
3282 };
3283 DRW_Coord ul(rd(0x02), rd(0x0a), rd(0x12));
3284 DRW_Coord lr(rd(0x32), rd(0x3a), rd(0x42));
3285 if (std::isfinite(ul.x) && std::isfinite(ul.y) && std::isfinite(ul.z)
3286 && std::isfinite(lr.x) && std::isfinite(lr.y) && std::isfinite(lr.z)) {
3287 m_pt1 = ul;
3288 m_pt2 = lr;
3289 }
3290 }
3291
3292 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3293 return ret && buf->isGood();
3294}
3295
3296// Phase 6.2: OLE2FRAME encoder (fixed oType 74). Inverse of parseDwg, emitting
3297// the captured opaque payload byte-for-byte. Without this override an OLE2FRAME
3298// would encode as a LINE.
3299bool DRW_Ole2Frame::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
3300 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3301 (void)bs; (void)strBuf;
3302 oType = 74; // OLE2FRAME class id — see dwgreader.cpp case 74
3303 if (!encodeDwgCommon(version, buf)) return false;
3304
3305 buf->putBitShort(m_flags);
3306 if (version > DRW::AC1014)
3307 buf->putBitShort(m_mode);
3308 // Emit the actual captured length so the reader's data_size matches the
3309 // bytes that follow (avoids a declared-vs-actual mismatch on re-read).
3310 const std::uint32_t payloadLen = static_cast<std::uint32_t>(m_payloadBytes.size());
3311 buf->putBitLong(static_cast<std::int32_t>(payloadLen));
3312 if (payloadLen > 0)
3313 buf->putBytes(m_payloadBytes.data(), m_payloadBytes.size());
3314 // R2000+ Unknown RC (ODA §20.4.88): emitted UNCONDITIONALLY for version >
3315 // AC1014. parseDwg reads it whenever bytes remain before the handle stream
3316 // (which is always — handle data always follows), so gating the write on
3317 // m_hasR2000TrailingByte desynced a directly-constructed OLE2FRAME (the
3318 // default false): the parser consumed the first handle byte as this RC and
3319 // shifted the entity handle stream. Default m_r2000TrailingByte is 0, so
3320 // constructed entities align and round-tripped ones keep the captured byte.
3321 if (version > DRW::AC1014)
3322 buf->putRawChar8(m_r2000TrailingByte);
3323
3324 return encodeDwgEntHandle(version, buf, handleBuf);
3325}
3326
3327bool DRW_Light::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3328 dwgBuffer sBuff = *buf;
3329 dwgBuffer *sBuf = v > DRW::AC1018 ? &sBuff : buf;
3330 bool ret = DRW_Entity::parseDwg(v, buf, sBuf, bs);
3331 if (!ret)
3332 return ret;
3333 DRW_DBG("\n***************************** parsing LIGHT *****************************\n")DRW_dbg::dbg("\n***************************** parsing LIGHT *****************************\n"
)
;
3334
3335 const std::uint64_t bodyDataEndBit = v > DRW::AC1018 ? currentDwgBit(sBuf) : 0;
3336 m_classVersion = static_cast<std::uint32_t>(buf->getBitLong());
3337 m_name = sBuf->getVariableText(v, false);
3338 m_type = static_cast<std::uint32_t>(buf->getBitLong());
3339 m_status = buf->getBit() != 0;
3340 m_color = buf->getCmColor(v);
3341 m_plotGlyph = buf->getBit() != 0;
3342 m_intensity = buf->getBitDouble();
3343 m_position = buf->get3BitDouble();
3344 m_target = buf->get3BitDouble();
3345 m_attenuationType = static_cast<std::uint32_t>(buf->getBitLong());
3346 m_useAttenuationLimits = buf->getBit() != 0;
3347 m_attenuationStartLimit = buf->getBitDouble();
3348 m_attenuationEndLimit = buf->getBitDouble();
3349 m_hotspotAngle = buf->getBitDouble();
3350 m_falloffAngle = buf->getBitDouble();
3351 m_castShadows = buf->getBit() != 0;
3352 m_shadowType = static_cast<std::uint32_t>(buf->getBitLong());
3353 m_shadowMapSize = buf->getBitShort();
3354 m_shadowMapSoftness = buf->getRawChar8();
3355
3356 if (v > DRW::AC1018 && currentDwgBit(buf) < bodyDataEndBit) {
3357 m_hasPhotometricData = buf->getBit() != 0;
3358 if (m_hasPhotometricData) {
3359 m_hasWebFile = buf->getBit() != 0;
3360 m_webFile = sBuf->getVariableText(v, false);
3361 m_physicalIntensityMethod = buf->getBitShort();
3362 m_physicalIntensity = buf->getBitDouble();
3363 m_illuminanceDistance = buf->getBitDouble();
3364 m_lampColorType = buf->getBitShort();
3365 m_lampColorTemperature = buf->getBitDouble();
3366 m_lampColorPreset = buf->getBitShort();
3367 m_webRotation = buf->get3BitDouble();
3368 m_extendedLightShape = buf->getBitShort();
3369 m_extendedLightLength = buf->getBitDouble();
3370 m_extendedLightWidth = buf->getBitDouble();
3371 m_extendedLightRadius = buf->getBitDouble();
3372 }
3373 }
3374
3375 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3376 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");
3377 return ret;
3378}
3379
3380bool DRW_Light::encodeDwg(DRW::Version v, dwgBufferW *buf, std::uint32_t bs,
3381 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3382 (void)bs;
3383 if (v < DRW::AC1021)
3384 return false;
3385
3386 oType = kDwgClassNum;
3387 if (!encodeDwgCommon(v, buf, strBuf))
3388 return false;
3389
3390 dwgBufferW *sb = strBuf ? strBuf : buf;
3391 buf->putBitLong(m_classVersion);
3392 sb->putVariableText(v, m_name);
3393 buf->putBitLong(m_type);
3394 buf->putBit(m_status ? 1 : 0);
3395 buf->putCmColor(v, static_cast<std::uint16_t>(m_color));
3396 buf->putBit(m_plotGlyph ? 1 : 0);
3397 buf->putBitDouble(m_intensity);
3398 buf->put3BitDouble(m_position);
3399 buf->put3BitDouble(m_target);
3400 buf->putBitLong(m_attenuationType);
3401 buf->putBit(m_useAttenuationLimits ? 1 : 0);
3402 buf->putBitDouble(m_attenuationStartLimit);
3403 buf->putBitDouble(m_attenuationEndLimit);
3404 buf->putBitDouble(m_hotspotAngle);
3405 buf->putBitDouble(m_falloffAngle);
3406 buf->putBit(m_castShadows ? 1 : 0);
3407 buf->putBitLong(m_shadowType);
3408 buf->putBitShort(m_shadowMapSize);
3409 buf->putRawChar8(m_shadowMapSoftness);
3410
3411 buf->putBit(m_hasPhotometricData ? 1 : 0);
3412 if (m_hasPhotometricData) {
3413 buf->putBit(m_hasWebFile ? 1 : 0);
3414 sb->putVariableText(v, m_webFile);
3415 buf->putBitShort(m_physicalIntensityMethod);
3416 buf->putBitDouble(m_physicalIntensity);
3417 buf->putBitDouble(m_illuminanceDistance);
3418 buf->putBitShort(m_lampColorType);
3419 buf->putBitDouble(m_lampColorTemperature);
3420 buf->putBitShort(m_lampColorPreset);
3421 buf->put3BitDouble(m_webRotation);
3422 buf->putBitShort(m_extendedLightShape);
3423 buf->putBitDouble(m_extendedLightLength);
3424 buf->putBitDouble(m_extendedLightWidth);
3425 buf->putBitDouble(m_extendedLightRadius);
3426 }
3427
3428 return encodeDwgEntHandle(v, buf, handleBuf);
3429}
3430
3431// DRW_Section::parseDwg — SECTIONOBJECT / AcDbSection, field order per
3432// libreDWG dwg2.spec DWG_ENTITY(SECTIONOBJECT): BL state, BL flags, T name,
3433// 3BD vert_dir, BD top/bottom height, BS indicator_alpha, CMTC indicator_color,
3434// BL num_verts + verts, BL num_blverts + blverts; then the common entity handle
3435// data followed by the section_settings hard reference (H 5, 360).
3436bool DRW_SectionObject::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3437 // R2007+ keeps text in a separate string stream; read scalars from buf
3438 // (data stream) and text from sBuf, exactly like DRW_Light.
3439 dwgBuffer sBuff = *buf;
3440 dwgBuffer *sBuf = v > DRW::AC1018 ? &sBuff : buf;
3441 bool ret = DRW_Entity::parseDwg(v, buf, sBuf, bs);
3442 if (!ret)
3443 return true; // graceful-degrade: keep the raw shelf
3444 DRW_DBG("\n***************************** parsing SECTIONOBJECT *********************\n")DRW_dbg::dbg("\n***************************** parsing SECTIONOBJECT *********************\n"
)
;
3445
3446 m_state = static_cast<std::uint32_t>(buf->getBitLong());
3447 m_flags = static_cast<std::uint32_t>(buf->getBitLong());
3448 m_name = sBuf->getVariableText(v, false);
3449 m_vertDir = buf->get3BitDouble();
3450 m_topHeight = buf->getBitDouble();
3451 m_bottomHeight = buf->getBitDouble();
3452 m_indicatorAlpha = buf->getBitShort();
3453 m_indicatorColor = buf->getCmColor(v);
3454
3455 // num_verts / num_blverts are bounded before looping — a corrupt count must
3456 // never drive an unbounded allocation, and a short read must never drop the
3457 // object (raw shelf is the round-trip floor).
3458 constexpr std::uint32_t kMaxSectionVerts = 1u << 20; // 1,048,576
3459 std::int32_t nv = buf->getBitLong();
3460 std::uint32_t numVerts = (nv > 0) ? static_cast<std::uint32_t>(nv) : 0u;
3461 if (numVerts > kMaxSectionVerts)
3462 numVerts = 0;
3463 m_verts.clear();
3464 m_verts.reserve(numVerts);
3465 for (std::uint32_t i = 0; i < numVerts && buf->isGood(); ++i)
3466 m_verts.push_back(buf->get3BitDouble());
3467
3468 std::int32_t nb = buf->getBitLong();
3469 std::uint32_t numBl = (nb > 0) ? static_cast<std::uint32_t>(nb) : 0u;
3470 if (numBl > kMaxSectionVerts)
3471 numBl = 0;
3472 m_blVerts.clear();
3473 m_blVerts.reserve(numBl);
3474 for (std::uint32_t i = 0; i < numBl && buf->isGood(); ++i)
3475 m_blVerts.push_back(buf->get3BitDouble());
3476
3477 // Handle stream: parseDwgEntHandle reads the common entity handles — it
3478 // resets buf to objSize for R2007+ and reads inline (after the exact body
3479 // above) for <=AC1018. The section_settings hard reference follows the
3480 // common handles, so read it from buf right after (guarded by remaining
3481 // bytes so a truncated object never over-reads).
3482 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3483 // The section_settings hard reference follows the common entity handles.
3484 // The R2007+ handle stream is small (a few bytes) so guard on any
3485 // remaining byte rather than the 4-byte common-object slack.
3486 if (ret && buf->isGood() && buf->numRemainingBytes() >= 1) {
3487 dwgHandle ssH = buf->getOffsetHandle(handle);
3488 m_sectionSettingsHandle = ssH.ref;
3489 DRW_DBG(" section_settings Handle: ")DRW_dbg::dbg(" section_settings Handle: ");
3490 DRW_DBGHL(ssH.code, ssH.size, ssH.ref)DRW_dbg::dbgHL(ssH.code, ssH.size, ssH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
3491 }
3492 DRW_DBG("SECTIONOBJECT name: ")DRW_dbg::dbg("SECTIONOBJECT name: "); DRW_DBG(m_name.c_str())DRW_dbg::dbg(m_name.c_str());
3493 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");
3494 return true; // graceful-degrade — always deliver typed add + raw shelf
3495}
3496
3497bool DRW_Tolerance::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3498 switch (code) {
3499 case 1:
3500 text = reader->getUtf8String();
3501 break;
3502 case 3:
3503 dimStyleName = reader->getUtf8String();
3504 break;
3505 case 10:
3506 insertionPoint.x = reader->getDouble();
3507 break;
3508 case 20:
3509 insertionPoint.y = reader->getDouble();
3510 break;
3511 case 30:
3512 insertionPoint.z = reader->getDouble();
3513 break;
3514 case 11:
3515 xAxisDirectionVector.x = reader->getDouble();
3516 break;
3517 case 21:
3518 xAxisDirectionVector.y = reader->getDouble();
3519 break;
3520 case 31:
3521 xAxisDirectionVector.z = reader->getDouble();
3522 break;
3523 case 210:
3524 extPoint.x = reader->getDouble();
3525 break;
3526 case 220:
3527 extPoint.y = reader->getDouble();
3528 break;
3529 case 230:
3530 extPoint.z = reader->getDouble();
3531 break;
3532 default:
3533 return DRW_Entity::parseCode(code, reader);
3534 }
3535 return true;
3536}
3537
3538bool DRW_Tolerance::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3539 dwgBuffer sBuff = *buf;
3540 dwgBuffer *sBuf = buf;
3541 if (v > DRW::AC1018)
3542 sBuf = &sBuff;
3543
3544 bool ret = DRW_Entity::parseDwg(v, buf, sBuf, bs);
3545 if (!ret)
3546 return ret;
3547
3548 DRW_DBG("\n***************************** parsing tolerance *********************************************\n")DRW_dbg::dbg("\n***************************** parsing tolerance *********************************************\n"
)
;
3549 if (v < DRW::AC1015) {
3550 DRW_DBG("unknown R13/R14 short: ")DRW_dbg::dbg("unknown R13/R14 short: "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort()); DRW_DBG("\n")DRW_dbg::dbg("\n");
3551 DRW_DBG("height at creation: ")DRW_dbg::dbg("height at creation: "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble()); DRW_DBG("\n")DRW_dbg::dbg("\n");
3552 DRW_DBG("dimgap/dimscale at creation: ")DRW_dbg::dbg("dimgap/dimscale at creation: "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble()); DRW_DBG("\n")DRW_dbg::dbg("\n");
3553 }
3554
3555 insertionPoint = buf->get3BitDouble();
3556 DRW_DBG("insertionPoint: ")DRW_dbg::dbg("insertionPoint: "); DRW_DBGPT(insertionPoint.x, insertionPoint.y, insertionPoint.z)DRW_dbg::dbgPT(insertionPoint.x, insertionPoint.y, insertionPoint
.z)
;
3557 xAxisDirectionVector = buf->get3BitDouble();
3558 DRW_DBG("\nxAxisDirectionVector: ")DRW_dbg::dbg("\nxAxisDirectionVector: ");
3559 DRW_DBGPT(xAxisDirectionVector.x, xAxisDirectionVector.y, xAxisDirectionVector.z)DRW_dbg::dbgPT(xAxisDirectionVector.x, xAxisDirectionVector.y
, xAxisDirectionVector.z)
;
3560 extPoint = buf->get3BitDouble();
3561 DRW_DBG("\nextPoint: ")DRW_dbg::dbg("\nextPoint: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
3562 text = sBuf->getVariableText(v, false);
3563 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");
3564
3565 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3566 if (!ret)
3567 return ret;
3568 dimStyleH = buf->getHandle();
3569 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: ");
3570 DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
3571 return buf->isGood();
3572}
3573
3574bool DRW_Tolerance::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
3575 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3576 (void)bs;
3577 oType = 46;
3578 if (!encodeDwgCommon(version, buf, strBuf))
3579 return false;
3580
3581 if (version < DRW::AC1015) {
3582 buf->putBitShort(0);
3583 buf->putBitDouble(0.0);
3584 buf->putBitDouble(0.0);
3585 }
3586
3587 buf->put3BitDouble(insertionPoint);
3588 buf->put3BitDouble(xAxisDirectionVector);
3589 buf->put3BitDouble(extPoint);
3590 (strBuf ? strBuf : buf)->putVariableText(version, text);
3591
3592 if (!encodeDwgEntHandle(version, buf, handleBuf))
3593 return false;
3594
3595 dwgBufferW *hb = handleBuf ? handleBuf : buf;
3596 putHardPointerHandle(hb, (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref);
3597 return true;
3598}
3599
3600bool DRW_Block::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3601 switch (code) {
3602 case 1:
3603 xrefPath = reader->getUtf8String();
3604 break;
3605 case 2:
3606 name = reader->getUtf8String();
3607 break;
3608 case 70:
3609 flags = reader->getInt32();
3610 break;
3611 default:
3612 return DRW_Point::parseCode(code, reader);
3613 }
3614
3615 return true;
3616}
3617
3618bool DRW_Block::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
3619 dwgBuffer sBuff = *buf;
3620 dwgBuffer *sBuf = buf;
3621 if (version > DRW::AC1018) {//2007+
3622 sBuf = &sBuff; //separate buffer for strings
3623 }
3624 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
3625 if (!ret)
3626 return ret;
3627 if (!isEnd){
3628 DRW_DBG("\n***************************** parsing block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing block *********************************************\n"
)
;
3629 name = sBuf->getVariableText(version, false);
3630 DRW_DBG("Block name: ")DRW_dbg::dbg("Block name: "); DRW_DBG(name.c_str())DRW_dbg::dbg(name.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n");
3631 } else {
3632 DRW_DBG("\n***************************** parsing end block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing end block *********************************************\n"
)
;
3633 }
3634 if (version > DRW::AC1018) {//2007+
3635 std::uint8_t unk = buf->getBit();
3636 DRW_DBG("unknown bit: ")DRW_dbg::dbg("unknown bit: "); DRW_DBG(unk)DRW_dbg::dbg(unk); DRW_DBG("\n")DRW_dbg::dbg("\n");
3637 }
3638// X handleAssoc; //X
3639 ret = DRW_Entity::parseDwgEntHandle(version, buf);
3640 if (!ret)
3641 return ret;
3642// RS crc; //RS */
3643 return buf->isGood();
3644}
3645
3646bool DRW_Insert::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3647 switch (code) {
3648 case 2:
3649 name = reader->getUtf8String();
3650 break;
3651 case 41:
3652 xscale = reader->getDouble();
3653 break;
3654 case 42:
3655 yscale = reader->getDouble();
3656 break;
3657 case 43:
3658 zscale = reader->getDouble();
3659 break;
3660 case 50:
3661 angle = reader->getDouble();
3662 angle = angle/ARAD57.29577951308232; //convert to radian
3663 break;
3664 case 70:
3665 colcount = reader->getInt32();
3666 break;
3667 case 71:
3668 rowcount = reader->getInt32();
3669 break;
3670 case 44:
3671 colspace = reader->getDouble();
3672 break;
3673 case 45:
3674 rowspace = reader->getDouble();
3675 break;
3676 default:
3677 return DRW_Point::parseCode(code, reader);
3678 }
3679
3680 return true;
3681}
3682
3683bool DRW_Table::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3684 auto ensureGrid = [this]() {
3685 if (m_dxfRowsExpected < 0 || m_dxfColumnsExpected < 0)
3686 return;
3687
3688 const std::uint32_t rows = static_cast<std::uint32_t>(m_dxfRowsExpected);
3689 const std::uint32_t columns = static_cast<std::uint32_t>(m_dxfColumnsExpected);
3690 if (rows > kMaxTableRows || columns > kMaxTableColumns
3691 || (columns != 0 && rows > kMaxTableCells / columns)) {
3692 return;
3693 }
3694
3695 if (m_content.m_columns.size() != columns) {
3696 m_content.m_columns.clear();
3697 m_content.m_columns.resize(columns);
3698 m_dxfColumnWidthsRead = 0;
3699 }
3700 if (m_content.m_rows.size() != rows) {
3701 m_content.m_rows.clear();
3702 m_content.m_rows.resize(rows);
3703 m_dxfRowHeightsRead = 0;
3704 }
3705 for (auto& row : m_content.m_rows)
3706 row.m_cells.resize(columns);
3707
3708 m_hasSemanticContent = true;
3709 m_semanticContentComplete = true;
3710 };
3711
3712 auto currentCell = [this]() -> DRW_TableCell* {
3713 if (m_dxfCurrentCell < 0 || m_content.m_columns.empty()
3714 || m_content.m_rows.empty()) {
3715 return nullptr;
3716 }
3717
3718 const std::size_t columns = m_content.m_columns.size();
3719 const std::size_t cell = static_cast<std::size_t>(m_dxfCurrentCell);
3720 const std::size_t row = cell / columns;
3721 const std::size_t column = cell % columns;
3722 if (row >= m_content.m_rows.size()
3723 || column >= m_content.m_rows[row].m_cells.size()) {
3724 return nullptr;
3725 }
3726 return &m_content.m_rows[row].m_cells[column];
3727 };
3728
3729 auto currentContent = [&currentCell]() -> DRW_TableCellContent* {
3730 DRW_TableCell *cell = currentCell();
3731 if (cell == nullptr)
3732 return nullptr;
3733 if (cell->m_contents.empty() || cell->m_contents.back().m_type != 1) {
3734 DRW_TableCellContent content;
3735 content.m_type = 1;
3736 cell->m_contents.push_back(content);
3737 }
3738 return &cell->m_contents.back();
3739 };
3740
3741 if (code == 100) {
3742 const std::string subclass = reader->getString();
3743 if (subclass == "AcDbBlockReference") {
3744 m_dxfSubclass = DxfSubclass::BlockReference;
3745 } else if (subclass == "AcDbTable") {
3746 m_dxfSubclass = DxfSubclass::Table;
3747 } else if (subclass == "AcDbEntity") {
3748 m_dxfSubclass = DxfSubclass::Entity;
3749 }
3750 return true;
3751 }
3752
3753 if (m_dxfSubclass != DxfSubclass::Table)
3754 return DRW_Insert::parseCode(code, reader);
3755
3756 switch (code) {
3757 case 342:
3758 m_tableStyleHandle = static_cast<std::uint32_t>(reader->getHandleString());
3759 m_content.m_tableStyleHandle = m_tableStyleHandle;
3760 break;
3761 case 343:
3762 reader->getHandleString();
3763 break;
3764 case 11:
3765 m_horizontalDirection.x = reader->getDouble();
3766 break;
3767 case 21:
3768 m_horizontalDirection.y = reader->getDouble();
3769 break;
3770 case 31:
3771 m_horizontalDirection.z = reader->getDouble();
3772 break;
3773 case 90:
3774 if (m_dxfInCellValue) {
3775 if (DRW_TableCellContent *content = currentContent())
3776 content->m_value.m_dataType = reader->getInt32();
3777 else
3778 reader->getInt32();
3779 } else {
3780 m_valueFlag = reader->getInt32();
3781 }
3782 break;
3783 case 91:
3784 if (m_dxfRowsExpected < 0 && !m_dxfInCellValue) {
3785 m_dxfRowsExpected = reader->getInt32();
3786 ensureGrid();
3787 } else {
3788 reader->getInt32();
3789 }
3790 break;
3791 case 92:
3792 if (m_dxfColumnsExpected < 0 && !m_dxfInCellValue) {
3793 m_dxfColumnsExpected = reader->getInt32();
3794 ensureGrid();
3795 } else {
3796 reader->getInt32();
3797 }
3798 break;
3799 case 93:
3800 case 94:
3801 case 95:
3802 case 96:
3803 case 172:
3804 case 173:
3805 case 174:
3806 case 175:
3807 case 176:
3808 case 178:
3809 reader->getInt32();
3810 break;
3811 case 141:
3812 ensureGrid();
3813 if (m_dxfRowHeightsRead < m_content.m_rows.size())
3814 m_content.m_rows[m_dxfRowHeightsRead++].m_height = reader->getDouble();
3815 else
3816 reader->getDouble();
3817 break;
3818 case 142:
3819 ensureGrid();
3820 if (m_dxfColumnWidthsRead < m_content.m_columns.size())
3821 m_content.m_columns[m_dxfColumnWidthsRead++].m_width = reader->getDouble();
3822 else
3823 reader->getDouble();
3824 break;
3825 case 145:
3826 reader->getDouble();
3827 break;
3828 case 171:
3829 ensureGrid();
3830 if (!m_content.m_rows.empty() && !m_content.m_columns.empty()
3831 && m_dxfNextCell < m_content.m_rows.size() * m_content.m_columns.size()) {
3832 m_dxfCurrentCell = static_cast<int>(m_dxfNextCell++);
3833 if (DRW_TableCell *cell = currentCell())
3834 cell->m_flags = reader->getInt32();
3835 else
3836 reader->getInt32();
3837 } else {
3838 m_dxfCurrentCell = -1;
3839 reader->getInt32();
3840 }
3841 m_dxfInCellValue = false;
3842 break;
3843 case 301:
3844 m_dxfInCellValue = reader->getString() == "CELL_VALUE";
3845 if (m_dxfInCellValue)
3846 currentContent();
3847 break;
3848 case 1:
3849 case 302: {
3850 const UTF8STRINGstd::string text = reader->getUtf8String();
3851 if (m_dxfInCellValue) {
3852 if (DRW_TableCellContent *content = currentContent()) {
3853 content->m_text = text;
3854 content->m_value.m_dataType = 4;
3855 content->m_value.m_value.addString(1, text);
3856 }
3857 }
3858 break;
3859 }
3860 case 300:
3861 if (m_dxfInCellValue) {
3862 if (DRW_TableCellContent *content = currentContent())
3863 content->m_value.m_valueString = reader->getUtf8String();
3864 else
3865 reader->getUtf8String();
3866 } else {
3867 reader->getUtf8String();
3868 }
3869 break;
3870 case 304:
3871 reader->getString();
3872 m_dxfInCellValue = false;
3873 break;
3874 default:
3875 return DRW_Entity::parseCode(code, reader);
3876 }
3877
3878 return true;
3879}
3880
3881bool DRW_Insert::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
3882 std::int32_t objCount = 0;
3883 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
3884 if (!ret)
3885 return ret;
3886 DRW_DBG("\n************************** parsing insert/minsert *****************************************\n")DRW_dbg::dbg("\n************************** parsing insert/minsert *****************************************\n"
)
;
3887 basePoint.x = buf->getBitDouble();
3888 basePoint.y = buf->getBitDouble();
3889 basePoint.z = buf->getBitDouble();
3890 DRW_DBG("insertion point: ")DRW_dbg::dbg("insertion 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");
3891 if (version < DRW::AC1015) {//14-
3892 xscale = buf->getBitDouble();
3893 yscale = buf->getBitDouble();
3894 zscale = buf->getBitDouble();
3895 } else {
3896 std::uint8_t dataFlags = buf->get2Bits();
3897 if (dataFlags == 3){
3898 //none default value 1,1,1
3899 } else if (dataFlags == 1){ //x default value 1, y & z can be x value
3900 yscale = buf->getDefaultDouble(xscale);
3901 zscale = buf->getDefaultDouble(xscale);
3902 } else if (dataFlags == 2){
3903 xscale = buf->getRawDouble();
3904 yscale = zscale = xscale;
3905 } else { //dataFlags == 0
3906 xscale = buf->getRawDouble();
3907 yscale = buf->getDefaultDouble(xscale);
3908 zscale = buf->getDefaultDouble(xscale);
3909 }
3910 }
3911 angle = buf->getBitDouble();
3912 DRW_DBG("scale : ")DRW_dbg::dbg("scale : "); DRW_DBGPT(xscale, yscale, zscale)DRW_dbg::dbgPT(xscale, yscale, zscale); DRW_DBG(", angle: ")DRW_dbg::dbg(", angle: "); DRW_DBG(angle)DRW_dbg::dbg(angle);
3913 extPoint = buf->getExtrusion(false); //3BD R14 style
3914 DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
3915
3916 bool hasAttrib = buf->getBit();
3917 DRW_DBG(" has Attrib: ")DRW_dbg::dbg(" has Attrib: "); DRW_DBG(hasAttrib)DRW_dbg::dbg(hasAttrib);
3918
3919 if (hasAttrib && version > DRW::AC1015) {//2004+
3920 objCount = buf->getBitLong();
3921 DRW_UNUSED(objCount)(void)objCount;
3922 DRW_DBG(" objCount: ")DRW_dbg::dbg(" objCount: "); DRW_DBG(objCount)DRW_dbg::dbg(objCount); DRW_DBG("\n")DRW_dbg::dbg("\n");
3923 }
3924 if (oType == 8) {//entity are minsert
3925 colcount = buf->getBitShort();
3926 rowcount = buf->getBitShort();
3927 colspace = buf->getBitDouble();
3928 rowspace = buf->getBitDouble();
3929 }
3930 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");
3931 ret = DRW_Entity::parseDwgEntHandle(version, buf);
3932 blockRecH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3933 DRW_DBG("BLOCK HEADER Handle: ")DRW_dbg::dbg("BLOCK HEADER Handle: "); DRW_DBGHL(blockRecH.code, blockRecH.size, blockRecH.ref)DRW_dbg::dbgHL(blockRecH.code, blockRecH.size, blockRecH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
3934 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");
3935
3936 /*attribs follows*/
3937 if (hasAttrib) {
3938 if (version < DRW::AC1018) {//2000-
3939 dwgHandle attH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3940 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");
3941 attribHandles.push_back(attH);
3942 attH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3943 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");
3944 attribHandles.push_back(attH);
3945 } else {
3946 for (std::int32_t i=0; i < objCount && buf->isGood(); ++i){
3947 dwgHandle attH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3948 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");
3949 attribHandles.push_back(attH);
3950 }
3951 }
3952 seqendH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3953 DRW_DBG("seqendH Handle: ")DRW_dbg::dbg("seqendH 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");
3954 }
3955 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");
3956
3957 if (!ret)
3958 return ret;
3959// RS crc; //RS */
3960 return buf->isGood();
3961}
3962
3963bool DRW_Table::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
3964 if (version < DRW::AC1015)
3965 return false;
3966
3967 dwgBuffer sBuff = *buf;
3968 sBuff.setVariableTextByteLength(true);
3969 dwgBuffer *sBuf = &sBuff;
3970 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
3971 if (!ret)
3972 return ret;
3973
3974 DRW_DBG("\n************************** parsing table *****************************************\n")DRW_dbg::dbg("\n************************** parsing table *****************************************\n"
)
;
3975 basePoint.x = buf->getBitDouble();
3976 basePoint.y = buf->getBitDouble();
3977 basePoint.z = buf->getBitDouble();
3978
3979 std::uint8_t dataFlags = buf->get2Bits();
3980 if (dataFlags == 3) {
3981 // default scale 1,1,1
3982 } else if (dataFlags == 1) {
3983 yscale = buf->getDefaultDouble(xscale);
3984 zscale = buf->getDefaultDouble(xscale);
3985 } else if (dataFlags == 2) {
3986 xscale = buf->getRawDouble();
3987 yscale = zscale = xscale;
3988 } else {
3989 xscale = buf->getRawDouble();
3990 yscale = buf->getDefaultDouble(xscale);
3991 zscale = buf->getDefaultDouble(xscale);
3992 }
3993
3994 angle = buf->getBitDouble();
3995 extPoint = buf->getExtrusion(false);
3996
3997 std::int32_t objCount = 0;
3998 bool hasAttrib = buf->getBit();
3999 if (hasAttrib && version > DRW::AC1015)
4000 objCount = buf->getBitLong();
4001
4002 dwgBuffer hBuff = *buf;
4003 if (version <= DRW::AC1018) {
4004 // R2000/R2004: parseDwgEntHandle only re-seeks to the handle stream
4005 // for version > AC1018 (2007+ string area). For the legacy versions
4006 // seek the snapshot to the handle-stream start (objSize is the
4007 // bit offset of the handle stream, RL field read in
4008 // DRW_Entity::parseDwg) or every handle below reads mid-DATA garbage.
4009 hBuff.setPosition(objSize >> 3);
4010 hBuff.setBitPos(objSize & 7);
4011 }
4012 ret = DRW_Entity::parseDwgEntHandle(version, &hBuff);
4013 blockRecH = hBuff.getHandle();
4014
4015 if (hasAttrib) {
4016 for (std::int32_t i = 0; i < objCount && hBuff.isGood(); ++i)
4017 attribHandles.push_back(hBuff.getHandle());
4018 seqendH = hBuff.getHandle();
4019 }
4020
4021 if (!ret)
4022 return ret;
4023
4024 if (version >= DRW::AC1024) {
4025 buf->getRawChar8();
4026 readTableHandle(&hBuff);
4027 buf->getBitLong();
4028 if (version >= DRW::AC1027)
4029 buf->getBitLong();
4030 else
4031 buf->getBit();
4032
4033 m_hasSemanticContent = true;
4034 m_semanticContentComplete = parseTableContent(version, buf, sBuf, &hBuff, m_content);
4035 if (m_content.m_tableStyleHandle != 0) {
4036 m_tableStyleHandle = m_content.m_tableStyleHandle;
4037 }
4038 if (!m_semanticContentComplete) {
4039 DRW_DBG("TABLECONTENT parse incomplete; anonymous block insert kept\n")DRW_dbg::dbg("TABLECONTENT parse incomplete; anonymous block insert kept\n"
)
;
4040 return true;
4041 }
4042
4043 buf->getBitShort();
4044 m_horizontalDirection = buf->get3BitDouble();
4045
4046 const std::uint64_t breakStartBit = currentDwgBit(buf);
4047 const bool hasBreakData = buf->getBitLong() != 0;
4048 if (hasBreakData) {
4049 buf->getBitLong();
4050 buf->getBitLong();
4051 buf->getBitDouble();
4052 buf->getBitLong();
4053 buf->getBitLong();
4054 const std::uint32_t manualPositions = buf->getBitLong();
4055 if (manualPositions > kMaxTableItems) {
4056 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4057 "table-break-data", breakStartBit, currentDwgBit(buf),
4058 version, manualPositions, false));
4059 return true;
4060 }
4061 for (std::uint32_t i = 0; i < manualPositions; ++i) {
4062 buf->get3BitDouble();
4063 buf->getBitDouble();
4064 buf->getBitLong();
4065 }
4066 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4067 "table-break-data", breakStartBit, currentDwgBit(buf),
4068 version, manualPositions, buf->isGood()));
4069 }
4070
4071 const std::uint64_t rowRangeStartBit = currentDwgBit(buf);
4072 const std::uint32_t rowRanges = buf->getBitLong();
4073 if (rowRanges <= kMaxTableItems) {
4074 for (std::uint32_t i = 0; i < rowRanges; ++i) {
4075 buf->get3BitDouble();
4076 buf->getBitLong();
4077 buf->getBitLong();
4078 }
4079 if (rowRanges != 0) {
4080 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4081 "table-row-ranges", rowRangeStartBit, currentDwgBit(buf),
4082 version, rowRanges, buf->isGood()));
4083 }
4084 } else {
4085 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4086 "table-row-ranges", rowRangeStartBit, currentDwgBit(buf),
4087 version, rowRanges, false));
4088 }
4089
4090 return true;
4091 }
4092
4093 m_valueFlag = buf->getBitShort();
4094 m_horizontalDirection = buf->get3BitDouble();
4095 const std::uint32_t columns = buf->getBitLong();
4096 const std::uint32_t rows = buf->getBitLong();
4097 if (columns > kMaxTableColumns || rows > kMaxTableRows
4098 || (columns != 0 && rows > kMaxTableCells / columns)) {
4099 return true;
4100 }
4101
4102 m_hasSemanticContent = true;
4103 m_semanticContentComplete = false;
4104 m_content.m_columns.clear();
4105 m_content.m_rows.clear();
4106 m_content.m_columns.reserve(columns);
4107 m_content.m_rows.reserve(rows);
4108 for (std::uint32_t i = 0; i < columns; ++i) {
4109 DRW_TableColumn column;
4110 column.m_width = buf->getBitDouble();
4111 m_content.m_columns.push_back(column);
4112 }
4113 for (std::uint32_t i = 0; i < rows; ++i) {
4114 DRW_TableRow row;
4115 row.m_height = buf->getBitDouble();
4116 row.m_cells.resize(columns);
4117 m_content.m_rows.push_back(row);
4118 }
4119 m_tableStyleHandle = readTableHandle(&hBuff);
4120 m_content.m_tableStyleHandle = m_tableStyleHandle;
4121 m_semanticContentComplete = true;
4122 // For <=AC1018 (R2000/R2004) there is no separate R2007+ string stream:
4123 // DRW_Entity::parseDwg only seeks sBuf when version > AC1018 (see the
4124 // `strBuf != NULL && version > DRW::AC1018` guard there), so legacy cell
4125 // text is inline in `buf`. Passing the stale sBuf copy here would read
4126 // text from the wrong position and desync `buf`. Pass nullptr so the
4127 // cell readers' `textBuf = strBuf ? strBuf : buf` falls back to the
4128 // inline `buf`. R2007 (AC1021) keeps the separate sBuf stream.
4129 dwgBuffer *cellStrBuf = (version > DRW::AC1018) ? sBuf : nullptr;
4130 for (std::uint32_t row = 0; row < rows && m_semanticContentComplete; ++row) {
4131 for (std::uint32_t column = 0; column < columns; ++column) {
4132 if (!parseR2007TableCell(version, buf, cellStrBuf, &hBuff,
4133 m_content.m_rows[row].m_cells[column],
4134 &m_content.m_subrecordRanges)) {
4135 m_semanticContentComplete = false;
4136 break;
4137 }
4138 }
4139 }
4140
4141 if (m_semanticContentComplete)
4142 m_semanticContentComplete = skipR2007TableOverrides(
4143 version, buf, cellStrBuf, &hBuff, &m_content.m_subrecordRanges);
4144 if (!m_semanticContentComplete)
4145 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"
)
;
4146
4147 return true;
4148}
4149
4150bool DRW_TableContentObject::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4151 if (version <= DRW::AC1018)
4152 return false;
4153
4154 dwgBuffer sBuff = *buf;
4155 sBuff.setVariableTextByteLength(true);
4156 dwgBuffer *sBuf = &sBuff;
4157 bool ret = DRW_TableEntry::parseDwg(version, buf, sBuf, bs);
4158 DRW_DBG("\n************************** parsing table content object ************************\n")DRW_dbg::dbg("\n************************** parsing table content object ************************\n"
)
;
4159 if (!ret)
4160 return ret;
4161
4162 dwgBuffer hBuff = *buf;
4163 seekTableObjectHandleStream(version, &hBuff, objSize);
4164 readTableObjectCommonHandles(&hBuff, handle, numReactors, xDictFlag, &parentHandle);
4165
4166 m_parseComplete = parseTableContent(version, buf, sBuf, &hBuff, m_content);
4167 if (!m_parseComplete)
4168 DRW_DBG("TABLECONTENT object parse incomplete\n")DRW_dbg::dbg("TABLECONTENT object parse incomplete\n");
4169 return true;
4170}
4171
4172void DRW_LWPolyline::applyExtrusion(){
4173 if (haveExtrusion) {
4174 calculateAxis(extPoint);
4175 for (unsigned int i=0; i<vertlist.size(); i++) {
4176 auto& vert = vertlist.at(i);
4177 DRW_Coord v(vert->x, vert->y, elevation);
4178 extrudePoint(extPoint, &v);
4179 vert->x = v.x;
4180 vert->y = v.y;
4181 }
4182 }
4183}
4184
4185bool DRW_LWPolyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4186 switch (code) {
4187 case 10: {
4188 vertex = std::make_shared<DRW_Vertex2D>();
4189 vertlist.push_back(vertex);
4190 vertex->x = reader->getDouble();
4191 break; }
4192 case 20:
4193 if(vertex)
4194 vertex->y = reader->getDouble();
4195 break;
4196 case 40:
4197 if(vertex)
4198 vertex->stawidth = reader->getDouble();
4199 break;
4200 case 41:
4201 if(vertex)
4202 vertex->endwidth = reader->getDouble();
4203 break;
4204 case 42:
4205 if(vertex)
4206 vertex->bulge = reader->getDouble();
4207 break;
4208 case 91:
4209 if (vertex)
4210 vertex->identifier = reader->getInt32();
4211 break;
4212 case 38:
4213 elevation = reader->getDouble();
4214 break;
4215 case 39:
4216 thickness = reader->getDouble();
4217 break;
4218 case 43:
4219 width = reader->getDouble();
4220 break;
4221 case 70:
4222 flags = reader->getInt32();
4223 break;
4224 case 90:
4225 vertexnum = reader->getInt32();
4226 return DRW::reserve( vertlist, vertexnum);
4227 case 210:
4228 haveExtrusion = true;
4229 extPoint.x = reader->getDouble();
4230 break;
4231 case 220:
4232 extPoint.y = reader->getDouble();
4233 break;
4234 case 230:
4235 extPoint.z = reader->getDouble();
4236 break;
4237 default:
4238 return DRW_Entity::parseCode(code, reader);
4239 }
4240
4241 return true;
4242}
4243
4244bool DRW_LWPolyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4245 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
4246 if (!ret)
4247 return ret;
4248 DRW_DBG("\n***************************** parsing LWPolyline *******************************************\n")DRW_dbg::dbg("\n***************************** parsing LWPolyline *******************************************\n"
)
;
4249
4250 flags = buf->getBitShort();
4251 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
4252 if (flags & 4)
4253 width = buf->getBitDouble();
4254 if (flags & 8)
4255 elevation = buf->getBitDouble();
4256 if (flags & 2)
4257 thickness = buf->getBitDouble();
4258 if (flags & 1)
4259 extPoint = buf->getExtrusion(false);
4260 vertexnum = buf->getBitLong();
4261 if (!isValidCount(vertexnum, kMaxLWPolylineVertices)) {
4262 return false;
4263 }
4264 if (!DRW::reserve( vertlist, vertexnum)) {
4265 return false;
4266 }
4267
4268 unsigned int bulgesnum = 0;
4269 if (flags & 16)
4270 bulgesnum = static_cast<unsigned int>(buf->getBitLong());
4271 int vertexIdCount = 0;
4272 if (version > DRW::AC1021) {//2010+
4273 if (flags & 1024)
4274 vertexIdCount = buf->getBitLong();
4275 }
4276 unsigned int widthsnum = 0;
4277 if (flags & 32)
4278 widthsnum = static_cast<unsigned int>(buf->getBitLong());
4279 if (bulgesnum > static_cast<unsigned int>(vertexnum) ||
4280 vertexIdCount < 0 || vertexIdCount > vertexnum ||
4281 widthsnum > static_cast<unsigned int>(vertexnum)) {
4282 return false;
4283 }
4284 DRW_DBG("\nvertex num: ")DRW_dbg::dbg("\nvertex num: "); DRW_DBG(vertexnum)DRW_dbg::dbg(vertexnum); DRW_DBG(" bulges num: ")DRW_dbg::dbg(" bulges num: "); DRW_DBG(bulgesnum)DRW_dbg::dbg(bulgesnum);
4285 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);
4286 // Translate DWG LWPLINE flag bits to DXF group 70 bits.
4287 // Per ODA spec 20.4.85 + libreDWG dwg.spec (DWG_ENTITY LWPOLYLINE):
4288 // DWG bit 9 (0x200, 512) -> DXF bit 0 (closed, value 1)
4289 // DWG bit 8 (0x100, 256) -> DXF bit 7 (plinegen, value 128)
4290 // All other DWG flag bits indicate which optional fields are present
4291 // and have no DXF equivalent in group 70.
4292 int dxfFlags = 0;
4293 if (flags & 512)
4294 dxfFlags |= 1;
4295 if (flags & 256)
4296 dxfFlags |= 128;
4297 flags = dxfFlags;
4298 DRW_DBG("end flags value: ")DRW_dbg::dbg("end flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
4299
4300 if (vertexnum > 0) { //verify if is lwpol without vertex (empty)
4301 // add vertexes
4302 vertex = std::make_shared<DRW_Vertex2D>();
4303 vertex->x = buf->getRawDouble();
4304 vertex->y = buf->getRawDouble();
4305 vertlist.push_back(vertex);
4306 auto pv = vertex;
4307 for (int i = 1; i< vertexnum; i++){
4308 vertex = std::make_shared<DRW_Vertex2D>();
4309 if (version < DRW::AC1015) {//14-
4310 vertex->x = buf->getRawDouble();
4311 vertex->y = buf->getRawDouble();
4312 } else {
4313// DRW_Vertex2D *pv = vertlist.back();
4314 vertex->x = buf->getDefaultDouble(pv->x);
4315 vertex->y = buf->getDefaultDouble(pv->y);
4316 }
4317 pv = vertex;
4318 vertlist.push_back(vertex);
4319 }
4320 //add bulges
4321 for (unsigned int i = 0; i < bulgesnum; i++){
4322 double bulge = buf->getBitDouble();
4323 if (vertlist.size()> i)
4324 vertlist.at(i)->bulge = bulge;
4325 }
4326 //add vertexId
4327 if (version > DRW::AC1021) {//2010+
4328 for (int i = 0; i < vertexIdCount; i++){
4329 std::int32_t vertexId = buf->getBitLong();
4330 if (static_cast<size_t>(i) < vertlist.size())
4331 vertlist.at(i)->identifier = vertexId;
4332 }
4333 }
4334 //add widths
4335 for (unsigned int i = 0; i < widthsnum; i++){
4336 double staW = buf->getBitDouble();
4337 double endW = buf->getBitDouble();
4338 if (i < vertlist.size()) {
4339 vertlist.at(i)->stawidth = staW;
4340 vertlist.at(i)->endwidth = endW;
4341 }
4342 }
4343 }
4344 if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug){
4345 DRW_DBG("\nVertex list: ")DRW_dbg::dbg("\nVertex list: ");
4346 for (auto& pv: vertlist) {
4347 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);
4348 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);
4349 DRW_DBG(" identifier: ")DRW_dbg::dbg(" identifier: "); DRW_DBG(pv->identifier)DRW_dbg::dbg(pv->identifier);
4350 }
4351 }
4352
4353 DRW_DBG("\n")DRW_dbg::dbg("\n");
4354 /* Common Entity Handle Data */
4355 ret = DRW_Entity::parseDwgEntHandle(version, buf);
4356 if (!ret)
4357 return ret;
4358 /* CRC X --- */
4359 return buf->isGood();
4360}
4361
4362
4363// ----------------------------------------------------------------------------
4364// DRW_MLine — multiline entity (ODA §19.4.78, fixed type 0x2F = 47).
4365// ----------------------------------------------------------------------------
4366
4367bool DRW_MLine::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4368 switch (code) {
4369 case 2:
4370 styleName = reader->getString();
4371 break;
4372 case 340:
4373 styleHandle = static_cast<std::uint32_t>(reader->getHandleString());
4374 break;
4375 case 40:
4376 scale = reader->getDouble();
4377 break;
4378 case 70:
4379 justification = static_cast<std::uint8_t>(reader->getInt32() & 0x3);
4380 break;
4381 case 71:
4382 openClosed = reader->getInt32();
4383 break;
4384 case 72:
4385 numVerts = static_cast<std::uint16_t>(reader->getInt32());
4386 break;
4387 case 73:
4388 numLines = static_cast<std::uint8_t>(reader->getInt32());
4389 break;
4390 case 10:
4391 basePoint.x = reader->getDouble();
4392 break;
4393 case 20:
4394 basePoint.y = reader->getDouble();
4395 break;
4396 case 30:
4397 basePoint.z = reader->getDouble();
4398 break;
4399 case 210:
4400 extPoint.x = reader->getDouble();
4401 break;
4402 case 220:
4403 extPoint.y = reader->getDouble();
4404 break;
4405 case 230:
4406 extPoint.z = reader->getDouble();
4407 break;
4408 // Per-vertex block: code 11 starts a new vertex; 12/13 follow.
4409 case 11:
4410 ++m_currentVertexIdx;
4411 m_currentElementIdx = 0;
4412 if (m_currentVertexIdx >= static_cast<int>(vertlist.size())) {
4413 vertlist.resize(m_currentVertexIdx + 1);
4414 }
4415 vertlist[m_currentVertexIdx].position.x = reader->getDouble();
4416 break;
4417 case 21:
4418 if (m_currentVertexIdx >= 0)
4419 vertlist[m_currentVertexIdx].position.y = reader->getDouble();
4420 break;
4421 case 31:
4422 if (m_currentVertexIdx >= 0)
4423 vertlist[m_currentVertexIdx].position.z = reader->getDouble();
4424 break;
4425 case 12:
4426 if (m_currentVertexIdx >= 0)
4427 vertlist[m_currentVertexIdx].vertexDir.x = reader->getDouble();
4428 break;
4429 case 22:
4430 if (m_currentVertexIdx >= 0)
4431 vertlist[m_currentVertexIdx].vertexDir.y = reader->getDouble();
4432 break;
4433 case 32:
4434 if (m_currentVertexIdx >= 0)
4435 vertlist[m_currentVertexIdx].vertexDir.z = reader->getDouble();
4436 break;
4437 case 13:
4438 if (m_currentVertexIdx >= 0)
4439 vertlist[m_currentVertexIdx].miterDir.x = reader->getDouble();
4440 break;
4441 case 23:
4442 if (m_currentVertexIdx >= 0)
4443 vertlist[m_currentVertexIdx].miterDir.y = reader->getDouble();
4444 break;
4445 case 33:
4446 if (m_currentVertexIdx >= 0)
4447 vertlist[m_currentVertexIdx].miterDir.z = reader->getDouble();
4448 break;
4449 // 74 = segment-param count for current element. Sets up the inner
4450 // vector and resets the running param count. 41 reads each param.
4451 // 75 = fill-param count; 42 reads each. After fills are consumed,
4452 // advance to the next element. AutoCAD emits 74/41*/75/42* per element.
4453 case 74:
4454 if (m_currentVertexIdx >= 0) {
4455 auto& v = vertlist[m_currentVertexIdx];
4456 if (static_cast<int>(v.segParms.size()) < numLines) {
4457 v.segParms.resize(numLines);
4458 v.areaFillParms.resize(numLines);
4459 }
4460 (void)reader->getInt32(); // expected count, used only as a marker
4461 m_currentSegFillCount = 0;
4462 }
4463 break;
4464 case 41:
4465 if (m_currentVertexIdx >= 0
4466 && m_currentElementIdx < static_cast<int>(vertlist[m_currentVertexIdx].segParms.size())) {
4467 vertlist[m_currentVertexIdx].segParms[m_currentElementIdx]
4468 .push_back(reader->getDouble());
4469 }
4470 break;
4471 case 75:
4472 if (m_currentVertexIdx >= 0) {
4473 m_currentSegFillCount = reader->getInt32();
4474 // After fills are emitted (or count==0 immediate), advance element.
4475 if (m_currentSegFillCount == 0
4476 && m_currentElementIdx + 1 < numLines) {
4477 ++m_currentElementIdx;
4478 }
4479 }
4480 break;
4481 case 42:
4482 if (m_currentVertexIdx >= 0
4483 && m_currentElementIdx < static_cast<int>(vertlist[m_currentVertexIdx].areaFillParms.size())) {
4484 vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx]
4485 .push_back(reader->getDouble());
4486 if (static_cast<int>(vertlist[m_currentVertexIdx]
4487 .areaFillParms[m_currentElementIdx].size())
4488 >= m_currentSegFillCount
4489 && m_currentElementIdx + 1 < numLines) {
4490 ++m_currentElementIdx;
4491 }
4492 }
4493 break;
4494 default:
4495 return DRW_Entity::parseCode(code, reader);
4496 }
4497 return true;
4498}
4499
4500bool DRW_MLine::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4501 if (!DRW_Entity::parseDwg(version, buf, nullptr, bs)) return false;
4502 DRW_DBG("\n***************************** parsing MLINE *********************\n")DRW_dbg::dbg("\n***************************** parsing MLINE *********************\n"
)
;
4503 // Per ODA §19.4.78 / libreDWG dwg_decode_MLINE:
4504 // BD scale, RC justification, 3BD basePoint, BE extrusion,
4505 // BS open/closed flag, RC num_lines, BS num_verts,
4506 // then per-vertex: 3BD pos, 3BD vdir, 3BD mdir,
4507 // per-line: BS num_segparms × BD parm, BS num_areafillparms × BD parm.
4508 scale = buf->getBitDouble();
4509 justification = buf->getRawChar8();
4510 basePoint = buf->get3BitDouble();
4511 extPoint = buf->getExtrusion(false);
4512 openClosed = buf->getBitShort();
4513 numLines = buf->getRawChar8();
4514 numVerts = buf->getBitShort();
4515 DRW_DBG(" mline scale: ")DRW_dbg::dbg(" mline scale: "); DRW_DBG(scale)DRW_dbg::dbg(scale);
4516 DRW_DBG(" just: ")DRW_dbg::dbg(" just: "); DRW_DBG(static_cast<int>(justification))DRW_dbg::dbg(static_cast<int>(justification));
4517 DRW_DBG(" openClosed: ")DRW_dbg::dbg(" openClosed: "); DRW_DBG(openClosed)DRW_dbg::dbg(openClosed);
4518 DRW_DBG(" lines: ")DRW_dbg::dbg(" lines: "); DRW_DBG(static_cast<int>(numLines))DRW_dbg::dbg(static_cast<int>(numLines));
4519 DRW_DBG(" verts: ")DRW_dbg::dbg(" verts: "); DRW_DBG(numVerts)DRW_dbg::dbg(numVerts); DRW_DBG("\n")DRW_dbg::dbg("\n");
4520 // Sanity: numLines / numVerts are RC and BS so already small types,
4521 // but guard against pathological values anyway.
4522 if (numLines > 100) return true;
4523 vertlist.reserve(numVerts);
4524 for (int vi = 0; vi < numVerts; ++vi) {
4525 DRW_MLineVertex vtx;
4526 vtx.position = buf->get3BitDouble();
4527 vtx.vertexDir = buf->get3BitDouble();
4528 vtx.miterDir = buf->get3BitDouble();
4529 vtx.segParms.resize(numLines);
4530 vtx.areaFillParms.resize(numLines);
4531 for (int li = 0; li < numLines; ++li) {
4532 std::uint16_t nSeg = buf->getBitShort();
4533 vtx.segParms[li].reserve(nSeg);
4534 for (int s = 0; s < nSeg; ++s) {
4535 vtx.segParms[li].push_back(buf->getBitDouble());
4536 }
4537 std::uint16_t nFill = buf->getBitShort();
4538 vtx.areaFillParms[li].reserve(nFill);
4539 for (int f = 0; f < nFill; ++f) {
4540 vtx.areaFillParms[li].push_back(buf->getBitDouble());
4541 }
4542 }
4543 vertlist.push_back(std::move(vtx));
4544 }
4545 if (!DRW_Entity::parseDwgEntHandle(version, buf)) return false;
4546 // MLINE has one extra handle in the handle stream after the standard
4547 // entity handles: the MLINESTYLE reference. Read if available — some
4548 // older files (R14) store the style name inline instead.
4549 if (version > DRW::AC1014 && buf->numRemainingBytes() > 0) {
4550 dwgHandle styleH = buf->getOffsetHandle(handle);
4551 styleHandle = styleH.ref;
4552 DRW_DBG(" MLINE style handle: ")DRW_dbg::dbg(" MLINE style handle: ");
4553 DRW_DBGHL(styleH.code, styleH.size, styleH.ref)DRW_dbg::dbgHL(styleH.code, styleH.size, styleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
4554 }
4555 return buf->isGood();
4556}
4557
4558
4559// ----------------------------------------------------------------------------
4560// DRW_Underlay — UNDERLAY entity (PDFUNDERLAY/DGNUNDERLAY/DWFUNDERLAY).
4561// libreDWG UNDERLAYREFERENCE.spec field order:
4562// extrusion (BE) -> position (3BD) -> angle (BD radians) -> scale (3BD)
4563// -> flags (RC) -> contrast (RC) -> fade (RC) -> num_clip (BL)
4564// -> clip_verts (2RD × num_clip).
4565// Handle stream after standard entity handles: definition_id (H).
4566// ----------------------------------------------------------------------------
4567
4568bool DRW_Underlay::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4569 switch (code) {
4570 case 340:
4571 definitionHandle = static_cast<std::uint32_t>(reader->getHandleString());
4572 break;
4573 case 10: position.x = reader->getDouble(); break;
4574 case 20: position.y = reader->getDouble(); break;
4575 case 30: position.z = reader->getDouble(); break;
4576 case 41: scale.x = reader->getDouble(); break;
4577 case 42: scale.y = reader->getDouble(); break;
4578 case 43: scale.z = reader->getDouble(); break;
4579 case 50: rotation = reader->getDouble(); break; // degrees in DXF
4580 case 210: extPoint.x = reader->getDouble(); break;
4581 case 220: extPoint.y = reader->getDouble(); break;
4582 case 230: extPoint.z = reader->getDouble(); break;
4583 case 280: flags = static_cast<std::uint8_t>(reader->getInt32() & 0xFF); break;
4584 case 281: contrast = static_cast<std::uint8_t>(reader->getInt32() & 0xFF); break;
4585 case 282: fade = static_cast<std::uint8_t>(reader->getInt32() & 0xFF); break;
4586 case 11: {
4587 ++m_currentClipVertexIdx;
4588 if (m_currentClipVertexIdx >= static_cast<int>(clipBoundary.size())) {
4589 clipBoundary.resize(m_currentClipVertexIdx + 1);
4590 }
4591 clipBoundary[m_currentClipVertexIdx].x = reader->getDouble();
4592 break;
4593 }
4594 case 21:
4595 if (m_currentClipVertexIdx >= 0
4596 && m_currentClipVertexIdx < static_cast<int>(clipBoundary.size())) {
4597 clipBoundary[m_currentClipVertexIdx].y = reader->getDouble();
4598 }
4599 break;
4600 default:
4601 return DRW_Entity::parseCode(code, reader);
4602 }
4603 return true;
4604}
4605
4606bool DRW_Underlay::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4607 if (!DRW_Entity::parseDwg(version, buf, nullptr, bs)) return false;
4608 DRW_DBG("\n***************************** parsing UNDERLAY ***************\n")DRW_dbg::dbg("\n***************************** parsing UNDERLAY ***************\n"
)
;
4609 extPoint = buf->getExtrusion(false);
4610 position = buf->get3BitDouble();
4611 rotation = buf->getBitDouble(); // angle (radians) BEFORE scale
4612 scale = buf->get3BitDouble();
4613 flags = buf->getRawChar8();
4614 contrast = buf->getRawChar8();
4615 fade = buf->getRawChar8();
4616 std::uint32_t nClip = buf->getBitLong();
4617 DRW_DBG(" UNDERLAY pos: ")DRW_dbg::dbg(" UNDERLAY pos: "); DRW_DBG(position.x)DRW_dbg::dbg(position.x); DRW_DBG(",")DRW_dbg::dbg(",");
4618 DRW_DBG(position.y)DRW_dbg::dbg(position.y); DRW_DBG(" rot: ")DRW_dbg::dbg(" rot: "); DRW_DBG(rotation)DRW_dbg::dbg(rotation);
4619 DRW_DBG(" flags: ")DRW_dbg::dbg(" flags: "); DRW_DBGH(flags)DRW_dbg::dbgH(flags);
4620 DRW_DBG(" nClip: ")DRW_dbg::dbg(" nClip: "); DRW_DBG(nClip)DRW_dbg::dbg(nClip); DRW_DBG("\n")DRW_dbg::dbg("\n");
4621 if (nClip > 100000) return true; // sanity
4622 clipBoundary.reserve(nClip);
4623 for (std::uint32_t i = 0; i < nClip; ++i) {
4624 DRW_Coord p;
4625 p.x = buf->getRawDouble();
4626 p.y = buf->getRawDouble();
4627 p.z = 0.0;
4628 clipBoundary.push_back(p);
4629 }
4630 if (!DRW_Entity::parseDwgEntHandle(version, buf)) return false;
4631 if (version > DRW::AC1014 && buf->numRemainingBytes() >= 2) {
4632 dwgHandle defH = buf->getOffsetHandle(handle);
4633 definitionHandle = defH.ref;
4634 DRW_DBG(" UNDERLAY definitionHandle: ")DRW_dbg::dbg(" UNDERLAY definitionHandle: ");
4635 DRW_DBGHL(defH.code, defH.size, defH.ref)DRW_dbg::dbgHL(defH.code, defH.size, defH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
4636 }
4637 return buf->isGood();
4638}
4639
4640bool DRW_Underlay::encodeDwg(DRW::Version version, dwgBufferW *buf,
4641 std::uint32_t bs, dwgBufferW *strBuf,
4642 dwgBufferW *handleBuf) {
4643 (void)bs; (void)strBuf;
4644 switch (kind) {
4645 case DGN:
4646 oType = kDwgClassNumDgn;
4647 break;
4648 case DWF:
4649 oType = kDwgClassNumDwf;
4650 break;
4651 case PDF:
4652 default:
4653 oType = kDwgClassNumPdf;
4654 break;
4655 }
4656 if (!encodeDwgCommon(version, buf))
4657 return false;
4658
4659 buf->putExtrusion(extPoint, false);
4660 buf->put3BitDouble(position);
4661 buf->putBitDouble(rotation);
4662 buf->put3BitDouble(scale);
4663 buf->putRawChar8(flags);
4664 buf->putRawChar8(contrast);
4665 buf->putRawChar8(fade);
4666 constexpr std::size_t kMaxClipVerts = 100000u;
4667 const std::size_t emitVerts = std::min(clipBoundary.size(), kMaxClipVerts);
4668 buf->putBitLong(static_cast<std::int32_t>(emitVerts));
4669 for (std::size_t i = 0; i < emitVerts; ++i) {
4670 buf->putRawDouble(clipBoundary[i].x);
4671 buf->putRawDouble(clipBoundary[i].y);
4672 }
4673
4674 if (!encodeDwgEntHandle(version, buf, handleBuf))
4675 return false;
4676 putNullableHardPointerHandle(handleBuf ? handleBuf : buf, definitionHandle);
4677 return true;
4678}
4679
4680
4681bool DRW_Text::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4682 switch (code) {
4683 case 40:
4684 height = reader->getDouble();
4685 break;
4686 case 41:
4687 widthscale = reader->getDouble();
4688 break;
4689 case 50:
4690 angle = reader->getDouble();
4691 break;
4692 case 51:
4693 oblique = reader->getDouble();
4694 break;
4695 case 71:
4696 textgen = reader->getInt32();
4697 break;
4698 case 72:
4699 alignH = (HAlign)reader->getInt32();
4700 break;
4701 case 73:
4702 alignV = (VAlign)reader->getInt32();
4703 break;
4704 case 1:
4705 text = reader->getUtf8String();
4706 break;
4707 case 7:
4708 style = reader->getUtf8String();
4709 break;
4710 default:
4711 return DRW_Line::parseCode(code, reader);
4712 }
4713
4714 return true;
4715}
4716
4717bool DRW_Text::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4718 dwgBuffer sBuff = *buf;
4719 dwgBuffer *sBuf = buf;
4720 if (version > DRW::AC1018) {//2007+
4721 sBuf = &sBuff; //separate buffer for strings
4722 }
4723 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
4724 if (!ret)
4725 return ret;
4726 DRW_DBG("\n***************************** parsing text *********************************************\n")DRW_dbg::dbg("\n***************************** parsing text *********************************************\n"
)
;
4727
4728 // DataFlags RC Used to determine presence of subsequent data, set to 0xFF for R14-
4729 std::uint8_t data_flags = 0x00;
4730 if (version > DRW::AC1014) {//2000+
4731 data_flags = buf->getRawChar8(); /* DataFlags RC Used to determine presence of subsequent data */
4732 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");
4733 if ( !(data_flags & 0x01) ) { /* Elevation RD --- present if !(DataFlags & 0x01) */
4734 basePoint.z = buf->getRawDouble();
4735 }
4736 } else {//14-
4737 basePoint.z = buf->getBitDouble(); /* Elevation BD --- */
4738 }
4739 basePoint.x = buf->getRawDouble(); /* Insertion pt 2RD 10 */
4740 basePoint.y = buf->getRawDouble();
4741 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");
4742 if (version > DRW::AC1014) {//2000+
4743 if ( !(data_flags & 0x02) ) { /* Alignment pt 2DD 11 present if !(DataFlags & 0x02), use 10 & 20 values for 2 default values.*/
4744 secPoint.x = buf->getDefaultDouble(basePoint.x);
4745 secPoint.y = buf->getDefaultDouble(basePoint.y);
4746 } else {
4747 secPoint = basePoint;
4748 }
4749 } else {//14-
4750 secPoint.x = buf->getRawDouble(); /* Alignment pt 2RD 11 */
4751 secPoint.y = buf->getRawDouble();
4752 }
4753 secPoint.z = basePoint.z;
4754 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");
4755 extPoint = buf->getExtrusion(version > DRW::AC1014);
4756 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");
4757 thickness = buf->getThickness(version > DRW::AC1014); /* Thickness BD 39 */
4758
4759 if (version > DRW::AC1014) {//2000+
4760 if ( !(data_flags & 0x04) ) { /* Oblique ang RD 51 present if !(DataFlags & 0x04) */
4761 oblique = buf->getRawDouble();
4762 }
4763 if ( !(data_flags & 0x08) ) { /* Rotation ang RD 50 present if !(DataFlags & 0x08) */
4764 angle = buf->getRawDouble();
4765 }
4766 height = buf->getRawDouble(); /* Height RD 40 */
4767 if ( !(data_flags & 0x10) ) { /* Width factor RD 41 present if !(DataFlags & 0x10) */
4768 widthscale = buf->getRawDouble();
4769 }
4770 } else {//14-
4771 oblique = buf->getBitDouble(); /* Oblique ang BD 51 */
4772 angle = buf->getBitDouble(); /* Rotation ang BD 50 */
4773 height = buf->getBitDouble(); /* Height BD 40 */
4774 widthscale = buf->getBitDouble(); /* Width factor BD 41 */
4775 }
4776 angle *= ARAD57.29577951308232;
4777 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: ");
4778 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");
4779 text = sBuf->getVariableText(version, false); /* Text value TV 1 */
4780 DRW_DBG("text string: ")DRW_dbg::dbg("text string: "); DRW_DBG(text.c_str())DRW_dbg::dbg(text.c_str());DRW_DBG("\n")DRW_dbg::dbg("\n");
4781 //textgen, alignH, alignV always present in R14-, data_flags set in initialisation
4782 if ( !(data_flags & 0x20) ) { /* Generation BS 71 present if !(DataFlags & 0x20) */
4783 textgen = buf->getBitShort();
4784 DRW_DBG("textgen: ")DRW_dbg::dbg("textgen: "); DRW_DBG(textgen)DRW_dbg::dbg(textgen);
4785 }
4786 if ( !(data_flags & 0x40) ) { /* Horiz align. BS 72 present if !(DataFlags & 0x40) */
4787 alignH = (HAlign)buf->getBitShort();
4788 DRW_DBG(", alignH: ")DRW_dbg::dbg(", alignH: "); DRW_DBG(alignH)DRW_dbg::dbg(alignH);
4789 }
4790 if ( !(data_flags & 0x80) ) { /* Vert align. BS 73 present if !(DataFlags & 0x80) */
4791 alignV = (VAlign)buf->getBitShort();
4792 DRW_DBG(", alignV: ")DRW_dbg::dbg(", alignV: "); DRW_DBG(alignV)DRW_dbg::dbg(alignV);
4793 }
4794 DRW_DBG("\n")DRW_dbg::dbg("\n");
4795
4796 /* Common Entity Handle Data */
4797 ret = DRW_Entity::parseDwgEntHandle(version, buf);
4798 if (!ret)
4799 return ret;
4800
4801 styleH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
4802 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");
4803
4804 /* CRC X --- */
4805 return buf->isGood();
4806}
4807
4808// ---------------------------------------------------------------------------
4809// RTEXT (RText, Express Tools) — read-only, mapped onto DRW_Text.
4810// ---------------------------------------------------------------------------
4811bool DRW_RText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4812 // RTEXT's DXF layout is a TEXT subset (1 text, 7 style, 10/20/30 insertion,
4813 // 40 height, 50 rotation deg, 210/220/230 extrusion) plus a flags long (70)
4814 // that plain TEXT does not carry.
4815 if (70 == code) {
4816 m_rTextFlags = reader->getInt32();
4817 return true;
4818 }
4819 return DRW_Text::parseCode(code, reader);
4820}
4821
4822bool DRW_RText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4823 dwgBuffer sBuff = *buf;
4824 dwgBuffer *sBuf = buf;
4825 if (version > DRW::AC1018) // 2007+ strings live in a separate stream
4826 sBuf = &sBuff;
4827 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
4828 if (!ret)
4829 return ret;
4830 DRW_DBG("\n***************************** parsing rtext ********************************************\n")DRW_dbg::dbg("\n***************************** parsing rtext ********************************************\n"
)
;
4831
4832 basePoint = buf->get3BitDouble(); // insertion 3BD
4833 secPoint = basePoint; // no separate alignment point
4834 extPoint = buf->get3BitDouble(); // extrusion 3BD
4835 angle = buf->getBitDouble() * ARAD57.29577951308232; // rotation BD (radians) -> degrees
4836 height = buf->getBitDouble(); // height BD
4837 m_rTextFlags = buf->getBitShort(); // flags BS
4838 text = sBuf->getVariableText(version, false); // TV (DIESEL or literal)
4839 DRW_DBG("rtext string: ")DRW_dbg::dbg("rtext string: "); DRW_DBG(text.c_str())DRW_dbg::dbg(text.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n");
4840
4841 ret = DRW_Entity::parseDwgEntHandle(version, buf);
4842 if (!ret)
4843 return ret;
4844 styleH = buf->getHandle(); // STYLE (hard pointer)
4845 return buf->isGood();
4846}
4847
4848// ---------------------------------------------------------------------------
4849// ARCALIGNEDTEXT (AcDbArcAlignedText, Express Tools) — read-only, mapped onto
4850// DRW_Text as a 2D approximation (text at the arc mid-point, tangent baseline).
4851// ---------------------------------------------------------------------------
4852bool DRW_RText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
4853 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
4854 (void)bs;
4855 oType = kDwgClassNum;
4856 if (!encodeDwgCommon(version, buf)) return false;
4857
4858 buf->put3BitDouble(basePoint);
4859 buf->put3BitDouble(extPoint);
4860 buf->putBitDouble(angle / ARAD57.29577951308232);
4861 buf->putBitDouble(height);
4862 buf->putBitShort(bitShortFromInt(m_rTextFlags));
4863 (strBuf ? strBuf : buf)->putVariableText(version, text);
4864
4865 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
4866 putHardPointerHandle(handleBuf ? handleBuf : buf,
4867 (styleH.ref == 0) ? 0x13 : styleH.ref);
4868 return true;
4869}
4870
4871void DRW_ArcAlignedText::applyArcApproximation(){
4872 const double mid = 0.5 * (m_startAngle + m_endAngle);
4873 basePoint.x = m_center.x + m_radius * std::cos(mid);
4874 basePoint.y = m_center.y + m_radius * std::sin(mid);
4875 basePoint.z = m_center.z;
4876 secPoint = basePoint;
4877 // Baseline tangent to the arc at the mid-point; angle stored in degrees to
4878 // match DRW_Text (which the DWG path fills via `angle *= ARAD`).
4879 angle = (mid + M_PI_21.57079632679489661923) * ARAD57.29577951308232;
4880 // Height from the text-size D2T string when parseable, else a fraction of
4881 // the radius so the approximation is at least visible.
4882 double h = 0.0;
4883 try { h = std::stod(m_textSize); } catch (...) { h = 0.0; }
4884 if (h > 0.0)
4885 height = h;
4886 else if (height <= 0.0)
4887 height = 0.1 * m_radius;
4888}
4889
4890// Format a D2T (double-to-text) field the way the ARCALIGNEDTEXT model stores
4891// it: the DWG body carries these as text ("2.5", "1", "0"), while the DXF path
4892// reads them as doubles (group codes 41-46 fall in the double range, so the
4893// reader populates doubleData and leaves strData stale — getString() is unsafe
4894// here). %g reproduces the same compact textual form.
4895static std::string arcAlignedD2T(double v){
4896 char buf[32];
4897 std::snprintf(buf, sizeof(buf), "%g", v);
4898 return std::string(buf);
4899}
4900
4901static std::string arcAlignedStringOrDefault(const UTF8STRINGstd::string& value,
4902 const std::string& fallback) {
4903 return value.empty() ? fallback : value;
4904}
4905
4906bool DRW_ArcAlignedText::encodeDwg(DRW::Version version, dwgBufferW *buf,
4907 std::uint32_t bs, dwgBufferW *strBuf,
4908 dwgBufferW *handleBuf) {
4909 (void)bs;
4910 oType = kDwgClassNum;
4911 if (!encodeDwgCommon(version, buf)) return false;
4912
4913 dwgBufferW *sb = strBuf ? strBuf : buf;
4914 sb->putVariableText(version, arcAlignedStringOrDefault(
4915 m_textSize, arcAlignedD2T(height > 0.0 ? height : 0.0)));
4916 sb->putVariableText(version, arcAlignedStringOrDefault(
4917 m_xScale, arcAlignedD2T(widthscale > 0.0 ? widthscale : 1.0)));
4918 sb->putVariableText(version, arcAlignedStringOrDefault(m_charSpacing, "1"));
4919 sb->putVariableText(version, style.empty() ? "Standard" : style);
4920 sb->putVariableText(version, m_fontName);
4921 sb->putVariableText(version, m_bigFontName);
4922 sb->putVariableText(version, text);
4923 sb->putVariableText(version, arcAlignedStringOrDefault(m_offsetFromArc, "0"));
4924 sb->putVariableText(version, arcAlignedStringOrDefault(m_rightOffset, "0"));
4925 sb->putVariableText(version, arcAlignedStringOrDefault(m_leftOffset, "0"));
4926
4927 buf->put3BitDouble(m_center);
4928 buf->putBitDouble(m_radius);
4929 buf->putBitDouble(m_startAngle);
4930 buf->putBitDouble(m_endAngle);
4931 buf->put3BitDouble(extPoint);
4932 buf->putBitLong(static_cast<std::int32_t>(m_rawColor));
4933 buf->putBitShort(bitShortFromInt(m_characterSet));
4934 buf->putBitShort(bitShortFromInt(m_pitchAndFamily));
4935 buf->putBitShort(bitShortFromInt(m_isShx));
4936 buf->putBitShort(bitShortFromInt(m_isBold));
4937 buf->putBitShort(bitShortFromInt(m_isItalic));
4938 buf->putBitShort(bitShortFromInt(m_isUnderlined));
4939 buf->putBitShort(bitShortFromInt(m_alignment));
4940 buf->putBitShort(bitShortFromInt(m_isReverse));
4941 buf->putBitShort(bitShortFromInt(m_wizardFlag));
4942 buf->putBitShort(bitShortFromInt(m_textPosition));
4943 buf->putBitShort(bitShortFromInt(m_textDirection));
4944
4945 if (version <= DRW::AC1018)
4946 putNullableHardPointerHandle(buf, m_arcHandle);
4947 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
4948 if (version > DRW::AC1018)
4949 putNullableHardPointerHandle(handleBuf ? handleBuf : buf, m_arcHandle);
4950 return true;
4951}
4952
4953bool DRW_ArcAlignedText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4954 // ARCALIGNEDTEXT repurposes several TEXT codes (2/10/40/41/50/51/70…), so it
4955 // must not delegate those to DRW_Text; unknown codes fall through to the
4956 // AcDbEntity common parser. Angles (50/51) are DXF degrees -> radians.
4957 switch (code) {
4958 case 1: text = reader->getUtf8String(); break;
4959 case 2: m_fontName = reader->getUtf8String(); break;
4960 case 3: m_bigFontName = reader->getUtf8String(); break;
4961 case 7: style = reader->getUtf8String(); break;
4962 case 10: m_center.x = reader->getDouble(); break;
4963 case 20: m_center.y = reader->getDouble(); break;
4964 case 30: m_center.z = reader->getDouble(); break;
4965 case 40: m_radius = reader->getDouble(); break;
4966 case 41: m_xScale = arcAlignedD2T(reader->getDouble()); break;
4967 case 42: m_textSize = arcAlignedD2T(reader->getDouble()); break;
4968 case 43: m_charSpacing = arcAlignedD2T(reader->getDouble()); break;
4969 case 44: m_offsetFromArc = arcAlignedD2T(reader->getDouble()); break;
4970 case 45: m_rightOffset = arcAlignedD2T(reader->getDouble()); break;
4971 case 46: m_leftOffset = arcAlignedD2T(reader->getDouble()); break;
4972 case 50: m_startAngle = reader->getDouble() / ARAD57.29577951308232; break;
4973 case 51: m_endAngle = reader->getDouble() / ARAD57.29577951308232; break;
4974 case 70: m_isReverse = reader->getInt32(); break;
4975 case 71: m_textDirection = reader->getInt32(); break;
4976 case 72: m_alignment = reader->getInt32(); break;
4977 case 73: m_textPosition = reader->getInt32(); break;
4978 case 74: m_isBold = reader->getInt32(); break;
4979 case 75: m_isItalic = reader->getInt32(); break;
4980 case 76: m_isUnderlined = reader->getInt32(); break;
4981 case 77: m_characterSet = reader->getInt32(); break;
4982 case 78: m_pitchAndFamily = reader->getInt32(); break;
4983 case 79: m_isShx = reader->getInt32(); break;
4984 case 90: m_rawColor = reader->getInt32(); break;
4985 case 210: extPoint.x = reader->getDouble(); break;
4986 case 220: extPoint.y = reader->getDouble(); break;
4987 case 230: extPoint.z = reader->getDouble(); break;
4988 case 280: m_wizardFlag = reader->getInt32(); break;
4989 default: return DRW_Entity::parseCode(code, reader);
4990 }
4991 return true;
4992}
4993
4994bool DRW_ArcAlignedText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4995 dwgBuffer sBuff = *buf;
4996 dwgBuffer *sBuf = buf;
4997 if (version > DRW::AC1018) // 2007+ strings live in a separate stream
4998 sBuf = &sBuff;
4999 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5000 if (!ret)
5001 return ret;
5002 DRW_DBG("\n***************************** parsing arcalignedtext **********************************\n")DRW_dbg::dbg("\n***************************** parsing arcalignedtext **********************************\n"
)
;
5003
5004 m_textSize = sBuf->getVariableText(version, false);
5005 m_xScale = sBuf->getVariableText(version, false);
5006 m_charSpacing = sBuf->getVariableText(version, false);
5007 style = sBuf->getVariableText(version, false);
5008 m_fontName = sBuf->getVariableText(version, false);
5009 m_bigFontName = sBuf->getVariableText(version, false);
5010 text = sBuf->getVariableText(version, false);
5011 m_offsetFromArc = sBuf->getVariableText(version, false);
5012 m_rightOffset = sBuf->getVariableText(version, false);
5013 m_leftOffset = sBuf->getVariableText(version, false);
5014 m_center = buf->get3BitDouble();
5015 m_radius = buf->getBitDouble();
5016 m_startAngle = buf->getBitDouble();
5017 m_endAngle = buf->getBitDouble();
5018 extPoint = buf->get3BitDouble();
5019 m_rawColor = buf->getBitLong();
5020 m_characterSet = buf->getBitShort();
5021 m_pitchAndFamily = buf->getBitShort();
5022 m_isShx = buf->getBitShort();
5023 m_isBold = buf->getBitShort();
5024 m_isItalic = buf->getBitShort();
5025 m_isUnderlined = buf->getBitShort();
5026 m_alignment = buf->getBitShort();
5027 m_isReverse = buf->getBitShort();
5028 m_wizardFlag = buf->getBitShort();
5029 m_textPosition = buf->getBitShort();
5030 m_textDirection = buf->getBitShort();
5031 DRW_DBG("arcalignedtext string: ")DRW_dbg::dbg("arcalignedtext string: "); DRW_DBG(text.c_str())DRW_dbg::dbg(text.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n");
5032
5033 // R2004- keeps the arc handle before the common handle stream; R2007+ after.
5034 if (version <= DRW::AC1018)
5035 m_arcHandle = (buf->numRemainingBytes() > 0) ? buf->getHandle().ref : 0;
5036
5037 ret = DRW_Entity::parseDwgEntHandle(version, buf);
5038 if (!ret)
5039 return ret;
5040 if (version > DRW::AC1018)
5041 m_arcHandle = (buf->numRemainingBytes() > 0) ? buf->getHandle().ref : 0;
5042
5043 applyArcApproximation();
5044 return buf->isGood();
5045}
5046
5047// Out-of-line special members: required because mtext is a unique_ptr<DRW_MText>
5048// declared with a forward-declared element type in the header.
5049DRW_Attrib::~DRW_Attrib() = default;
5050DRW_Attrib::DRW_Attrib(const DRW_Attrib& o)
5051 : DRW_Text(o), tag(o.tag), attribFlags(o.attribFlags),
5052 lockPosition(o.lockPosition), attVersion(o.attVersion),
5053 m_attributeType(o.m_attributeType),
5054 mtext(o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr) {}
5055DRW_Attrib& DRW_Attrib::operator=(const DRW_Attrib& o) {
5056 if (this != &o) {
5057 DRW_Text::operator=(o);
5058 tag = o.tag;
5059 attribFlags = o.attribFlags;
5060 lockPosition = o.lockPosition;
5061 attVersion = o.attVersion;
5062 m_attributeType = o.m_attributeType;
5063 mtext = o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr;
5064 }
5065 return *this;
5066}
5067DRW_Attrib::DRW_Attrib(DRW_Attrib&&) noexcept = default;
5068DRW_Attrib& DRW_Attrib::operator=(DRW_Attrib&&) noexcept = default;
5069
5070namespace {
5071struct EmbeddedMTextHandleInfo {
5072 bool m_ownerHandle = false;
5073 int m_numReactors = 0;
5074 std::uint8_t m_xDictFlag = 1;
5075 bool m_hasAcDbColorHandle = false;
5076 int m_ltFlags = 0;
5077 int m_plotFlags = 0;
5078 int m_materialFlag = 0;
5079 int m_shadowFlag = 0;
5080 bool m_hasFullVisualStyle = false;
5081 bool m_hasFaceVisualStyle = false;
5082 bool m_hasEdgeVisualStyle = false;
5083 bool m_hasStyleHandle = true;
5084 bool m_hasR2018AppIdHandle = false;
5085 bool m_hasAnnotativeAppHandle = false;
5086};
5087
5088static bool parseEmbeddedMTextEntityMode(DRW::Version version, dwgBuffer *buf,
5089 EmbeddedMTextHandleInfo& info) {
5090 std::uint8_t entmode = buf->get2Bits();
5091 info.m_ownerHandle = entmode == 0;
5092 info.m_numReactors = buf->getBitLong();
5093 if (version > DRW::AC1015) {
5094 info.m_xDictFlag = buf->getBit();
5095 }
5096 if (version > DRW::AC1024 || version < DRW::AC1018) {
5097 buf->getBit(); // nolinks / have-next-links
5098 }
5099 buf->getEnColor(version);
5100 info.m_hasAcDbColorHandle = buf->lastEnColorHadDbColorRef;
5101 buf->getBitDouble(); // linetype scale
5102 if (version > DRW::AC1014) {
5103 info.m_ltFlags = buf->get2Bits();
5104 info.m_plotFlags = buf->get2Bits();
5105 }
5106 if (version > DRW::AC1018) {
5107 info.m_materialFlag = buf->get2Bits();
5108 info.m_shadowFlag = buf->getRawChar8();
5109 }
5110 if (version > DRW::AC1021) {
5111 info.m_hasFullVisualStyle = buf->getBit() != 0;
5112 info.m_hasFaceVisualStyle = buf->getBit() != 0;
5113 info.m_hasEdgeVisualStyle = buf->getBit() != 0;
5114 }
5115 buf->getBitShort(); // invisibility
5116 if (version > DRW::AC1014) {
5117 buf->getRawChar8(); // lineweight
5118 }
5119 return buf->isGood();
5120}
5121
5122static bool parseEmbeddedMTextDwg(DRW::Version version, dwgBuffer *buf,
5123 dwgBuffer *sBuf, DRW_MText& mtext,
5124 EmbeddedMTextHandleInfo& info) {
5125 if (!parseEmbeddedMTextEntityMode(version, buf, info))
5126 return false;
5127
5128 mtext.basePoint = buf->get3BitDouble();
5129 mtext.extPoint = buf->get3BitDouble();
5130 mtext.secPoint = buf->get3BitDouble();
5131 mtext.angle = atan2(mtext.secPoint.y, mtext.secPoint.x) * ARAD57.29577951308232;
5132 mtext.widthscale = buf->getBitDouble();
5133 if (version > DRW::AC1018) {
5134 buf->getBitDouble(); // rect height
5135 }
5136 mtext.height = buf->getBitDouble();
5137 mtext.textgen = buf->getBitShort();
5138 mtext.alignH = static_cast<DRW_Text::HAlign>(buf->getBitShort());
5139 buf->getBitDouble(); // extents height
5140 buf->getBitDouble(); // extents width
5141 mtext.text = sBuf->getVariableText(version, false);
5142
5143 if (version > DRW::AC1014) {
5144 buf->getBitShort();
5145 mtext.interlin = buf->getBitDouble();
5146 buf->getBit();
5147 }
5148 if (version > DRW::AC1015) {
5149 mtext.m_backgroundFlags = buf->getBitLong();
5150 if ((mtext.m_backgroundFlags & 0x01)
5151 || (version >= DRW::AC1032 && (mtext.m_backgroundFlags & 0x10))) {
5152 mtext.m_backgroundScale = buf->getBitDouble(); // BitDouble, not BitLong
5153 mtext.m_backgroundColor = static_cast<int>(buf->getCmColor(version, nullptr, sBuf));
5154 mtext.m_backgroundTransparency = buf->getBitLong();
5155 }
5156 }
5157
5158 if (version >= DRW::AC1032) {
5159 mtext.m_r2018ColumnHeights.clear();
5160 mtext.m_r2018IsNotAnnotative = buf->getBit();
5161 if (mtext.m_r2018IsNotAnnotative) {
5162 mtext.m_r2018Version = buf->getBitShort();
5163 mtext.m_r2018DefaultFlag = buf->getBit();
5164 info.m_hasR2018AppIdHandle = true;
5165 mtext.m_r2018Attachment = buf->getBitLong();
5166 mtext.m_r2018XAxisDir = buf->get3BitDouble();
5167 mtext.m_r2018InsertionPoint = buf->get3BitDouble();
5168 mtext.m_r2018RectWidth = buf->getBitDouble();
5169 mtext.m_r2018RectHeight = buf->getBitDouble();
5170 mtext.m_r2018ExtentsHeight = buf->getBitDouble();
5171 mtext.m_r2018ExtentsWidth = buf->getBitDouble();
5172 mtext.m_r2018ColumnType = buf->getBitShort();
5173 if (mtext.m_r2018ColumnType != 0) {
5174 mtext.m_r2018ColumnCount = buf->getBitLong();
5175 mtext.m_r2018ColumnWidth = buf->getBitDouble();
5176 mtext.m_r2018ColumnGutter = buf->getBitDouble();
5177 mtext.m_r2018ColumnAutoHeight = buf->getBit();
5178 mtext.m_r2018ColumnFlowReversed = buf->getBit();
5179 if (!mtext.m_r2018ColumnAutoHeight && mtext.m_r2018ColumnType == 2
5180 && mtext.m_r2018ColumnCount > 0 && mtext.m_r2018ColumnCount < 10000) {
5181 mtext.m_r2018ColumnHeights.reserve(static_cast<size_t>(mtext.m_r2018ColumnCount));
5182 for (std::int32_t i = 0; i < mtext.m_r2018ColumnCount; ++i) {
5183 mtext.m_r2018ColumnHeights.push_back(buf->getBitDouble());
5184 }
5185 }
5186 }
5187 }
5188 }
5189
5190 const std::uint16_t annotativeSize = buf->getBitShort();
5191 if (annotativeSize > 0) {
5192 const int remaining = buf->numRemainingBytes();
5193 if (remaining < 0 || static_cast<std::uint64_t>(annotativeSize) > static_cast<std::uint64_t>(remaining))
5194 return false;
5195 std::vector<std::uint8_t> annotativeData(annotativeSize);
5196 buf->getBytes(annotativeData.data(), annotativeData.size());
5197 info.m_hasAnnotativeAppHandle = true;
5198 buf->getBitShort(); // unknown short, normally 0
5199 }
5200 return buf->isGood();
5201}
5202
5203static bool consumeEmbeddedMTextHandles(DRW::Version version, dwgBuffer *buf,
5204 std::uint32_t objSize,
5205 const EmbeddedMTextHandleInfo& info,
5206 DRW_MText *mtext) {
5207 if (version > DRW::AC1018) {
5208 buf->setPosition(objSize >> 3);
5209 buf->setBitPos(objSize & 7);
5210 }
5211 if (info.m_hasAcDbColorHandle) buf->getHandle();
5212 if (info.m_ownerHandle) buf->getHandle();
5213 for (int i = 0; i < info.m_numReactors; ++i) buf->getHandle();
5214 if (info.m_xDictFlag != 1) buf->getHandle();
5215 if (version > DRW::AC1014) {
5216 buf->getHandle(); // layer
5217 if (info.m_ltFlags == 3) buf->getHandle();
5218 }
5219 if (version > DRW::AC1018) {
5220 if (info.m_materialFlag == 3) buf->getHandle();
5221 if (info.m_shadowFlag == 3) buf->getHandle();
5222 }
5223 if (info.m_plotFlags == 3) buf->getHandle();
5224 if (version > DRW::AC1021) {
5225 if (info.m_hasFullVisualStyle) buf->getHandle();
5226 if (info.m_hasFaceVisualStyle) buf->getHandle();
5227 if (info.m_hasEdgeVisualStyle) buf->getHandle();
5228 }
5229 if (info.m_hasStyleHandle) {
5230 dwgHandle styleH = buf->getHandle();
5231 if (mtext) mtext->styleH = styleH;
5232 }
5233 if (info.m_hasR2018AppIdHandle) {
5234 dwgHandle appIdH = buf->getHandle();
5235 if (mtext) mtext->m_r2018AppIdHandle = appIdH.ref;
5236 }
5237 if (info.m_hasAnnotativeAppHandle) buf->getHandle();
5238 return buf->isGood();
5239}
5240
5241static bool encodeEmbeddedMTextEntityMode(DRW::Version version, dwgBufferW *buf,
5242 const DRW_MText& mtext) {
5243 if (version < DRW::AC1032)
5244 return false;
5245
5246 // Embedded MTEXT begins at AcDbEntity mode, not with an object type,
5247 // object size, own handle, EED, or graphics data.
5248 buf->put2Bits(2); // modelspace, no owner handle
5249 buf->putBitLong(0); // no reactors
5250 buf->putBit(1); // xDictFlag=1, no xdict handle
5251 buf->putBit(1); // no prev/next links
5252 buf->putEnColor(version, static_cast<std::uint16_t>(mtext.color));
5253 buf->putBitDouble(mtext.ltypeScale);
5254 buf->put2Bits(0); // linetype by layer
5255 buf->put2Bits(0); // plotstyle by layer
5256 buf->put2Bits(0); // material inherit
5257 buf->putRawChar8(0); // shadow flags
5258 buf->putBit(0); // no full visual style
5259 buf->putBit(0); // no face visual style
5260 buf->putBit(0); // no edge visual style
5261 buf->putBitShort(0); // visible
5262 buf->putRawChar8(static_cast<std::uint8_t>(mtext.lWeight));
5263 return true;
5264}
5265
5266static bool encodeEmbeddedMTextDwg(DRW::Version version, dwgBufferW *buf,
5267 dwgBufferW *strBuf, dwgBufferW *handleBuf,
5268 const DRW_MText& mtext) {
5269 if (!encodeEmbeddedMTextEntityMode(version, buf, mtext))
5270 return false;
5271
5272 buf->put3BitDouble(mtext.basePoint);
5273 buf->put3BitDouble(mtext.extPoint);
5274 buf->put3BitDouble(mtext.secPoint);
5275 buf->putBitDouble(mtext.widthscale);
5276 buf->putBitDouble(mtext.m_r2018RectHeight);
5277 buf->putBitDouble(mtext.height);
5278 buf->putBitShort(static_cast<std::uint16_t>(mtext.textgen));
5279 buf->putBitShort(static_cast<std::uint16_t>(mtext.alignH));
5280 buf->putBitDouble(mtext.m_r2018ExtentsHeight);
5281 buf->putBitDouble(mtext.m_r2018ExtentsWidth);
5282 (strBuf ? strBuf : buf)->putVariableText(version, mtext.text);
5283
5284 buf->putBitShort(0); // linespacing style
5285 buf->putBitDouble(mtext.interlin);
5286 buf->putBit(0);
5287 buf->putBitLong(mtext.m_backgroundFlags);
5288 if ((mtext.m_backgroundFlags & 0x01)
5289 || (mtext.m_backgroundFlags & 0x10)) {
5290 buf->putBitDouble(mtext.m_backgroundScale); // BitDouble, not BitLong
5291 buf->putCmColor(version, static_cast<std::uint16_t>(mtext.m_backgroundColor));
5292 buf->putBitLong(mtext.m_backgroundTransparency);
5293 }
5294
5295 buf->putBit(mtext.m_r2018IsNotAnnotative ? 1 : 0);
5296 if (mtext.m_r2018IsNotAnnotative) {
5297 buf->putBitShort(mtext.m_r2018Version);
5298 buf->putBit(mtext.m_r2018DefaultFlag ? 1 : 0);
5299 buf->putBitLong(mtext.m_r2018Attachment);
5300 buf->put3BitDouble(mtext.m_r2018XAxisDir);
5301 buf->put3BitDouble(mtext.m_r2018InsertionPoint);
5302 buf->putBitDouble(mtext.m_r2018RectWidth);
5303 buf->putBitDouble(mtext.m_r2018RectHeight);
5304 buf->putBitDouble(mtext.m_r2018ExtentsHeight);
5305 buf->putBitDouble(mtext.m_r2018ExtentsWidth);
5306 buf->putBitShort(mtext.m_r2018ColumnType);
5307 if (mtext.m_r2018ColumnType != 0) {
5308 std::int32_t columnCount = mtext.m_r2018ColumnCount;
5309 if (!mtext.m_r2018ColumnAutoHeight && mtext.m_r2018ColumnType == 2
5310 && !mtext.m_r2018ColumnHeights.empty()) {
5311 columnCount = static_cast<std::int32_t>(mtext.m_r2018ColumnHeights.size());
5312 }
5313 buf->putBitLong(columnCount);
5314 buf->putBitDouble(mtext.m_r2018ColumnWidth);
5315 buf->putBitDouble(mtext.m_r2018ColumnGutter);
5316 buf->putBit(mtext.m_r2018ColumnAutoHeight ? 1 : 0);
5317 buf->putBit(mtext.m_r2018ColumnFlowReversed ? 1 : 0);
5318 if (!mtext.m_r2018ColumnAutoHeight && mtext.m_r2018ColumnType == 2) {
5319 for (std::int32_t i = 0; i < columnCount; ++i) {
5320 const double columnHeight = static_cast<size_t>(i) < mtext.m_r2018ColumnHeights.size()
5321 ? mtext.m_r2018ColumnHeights[static_cast<size_t>(i)]
5322 : 0.0;
5323 buf->putBitDouble(columnHeight);
5324 }
5325 }
5326 }
5327 }
5328
5329 buf->putBitShort(0); // no annotative payload
5330
5331 dwgBufferW *hb = handleBuf ? handleBuf : buf;
5332 // Layer hard-pointer: consumeEmbeddedMTextHandles reads this UNCONDITIONALLY
5333 // for version > AC1014 (the entity-mode flags this encoder writes make every
5334 // other conditional embedded handle absent: no color/owner/reactor/xdict,
5335 // linetype/plotstyle/material/shadow all "by layer"). Omitting it made the
5336 // parser consume the style handle as the layer and the appId as the style,
5337 // then run into the PARENT ATTRIB/ATTDEF handle stream, shifting it. The
5338 // parser discards this value, so emit LAYER "0" (0x12) as the placeholder
5339 // (layerH is a protected DRW_Entity member, not reachable from this free
5340 // function; only the slot matters for handle-count alignment).
5341 putHardPointerHandle(hb, 0x12);
5342 putHardPointerHandle(hb, (mtext.styleH.ref == 0) ? 0x13 : mtext.styleH.ref);
5343 if (mtext.m_r2018IsNotAnnotative)
5344 putHardPointerHandle(hb, (mtext.m_r2018AppIdHandle == 0) ? 0x14 : mtext.m_r2018AppIdHandle);
5345 return true;
5346}
5347}
5348
5349bool DRW_Attrib::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5350 // Multi-line ATTRIB (R2018+, ODA spec §20.4.4): an embedded MTEXT object
5351 // is introduced by the DXF subclass marker `100 / Embedded Object` (NOT
5352 // `AcDbMText`). After the marker, the standard MTEXT group codes follow
5353 // (10/20/30 insertion, 11/21/31 X-axis, 40 height, 41 rect width, 71
5354 // attachment point, 72 drawing direction, 1 formatted text, etc.), then
5355 // the ATTRIB-specific tail (tag=2, prompt=3 for ATTDEF, flags=70,
5356 // lock-position=280) which we must NOT route into the embedded MText.
5357 if (code == 100) {
5358 const std::string sub = reader->getString();
5359 if (sub == "Embedded Object" && !mtext) {
5360 mtext = std::make_unique<DRW_MText>();
5361 if (attVersion == 0) attVersion = 1;
5362 }
5363 return true;
5364 }
5365 // Inside the embedded MText scope, route MTEXT-owned codes to mtext but
5366 // keep ATTRIB-specific tail codes for ATTRIB / ATTDEF handling below.
5367 if (mtext) {
5368 switch (code) {
5369 case 2: // tag (ATTRIB-specific; group 1 in MText is text body)
5370 case 3: // prompt (ATTDEF-specific)
5371 case 70: // ATTRIB flags
5372 case 280: // ATTRIB lock-position
5373 break; // fall through to ATTRIB handling below
5374 default:
5375 return mtext->parseCode(code, reader);
5376 }
5377 }
5378 switch (code) {
5379 case 2:
5380 tag = reader->getUtf8String();
5381 break;
5382 case 70:
5383 attribFlags = reader->getInt32();
5384 break;
5385 case 73:
5386 // AcDbAttribute code 73 = field length (obsolete); NOT the vertical
5387 // alignment from AcDbText (which is code 73 in TEXT but 74 in ATTRIB).
5388 m_fieldLength = reader->getInt32();
5389 break;
5390 case 74:
5391 // AcDbAttribute vertical alignment (code 74); TEXT uses code 73 for
5392 // this but ATTRIB moves it here to free code 73 for field length.
5393 alignV = (VAlign)reader->getInt32();
5394 break;
5395 case 280:
5396 // Lock position flag (R2010+ DXF group code)
5397 lockPosition = reader->getInt32() != 0;
5398 break;
5399 default:
5400 return DRW_Text::parseCode(code, reader);
5401 }
5402 return true;
5403}
5404
5405bool DRW_Attrib::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5406 dwgBuffer sBuff = *buf;
5407 dwgBuffer *sBuf = buf;
5408 if (version > DRW::AC1018) {//2007+
5409 sBuf = &sBuff; //separate buffer for strings
5410 }
5411 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5412 if (!ret)
5413 return ret;
5414 DRW_DBG("\n***************************** parsing attrib *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attrib *********************************************\n"
)
;
5415
5416 // Inline TEXT subtype data (mirrors DRW_Text::parseDwg layout, sans handles)
5417 std::uint8_t data_flags = 0x00;
5418 if (version > DRW::AC1014) {
5419 data_flags = buf->getRawChar8();
5420 if (!(data_flags & 0x01)) {
5421 basePoint.z = buf->getRawDouble();
5422 }
5423 } else {
5424 basePoint.z = buf->getBitDouble();
5425 }
5426 basePoint.x = buf->getRawDouble();
5427 basePoint.y = buf->getRawDouble();
5428 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");
5429 if (version > DRW::AC1014) {
5430 if (!(data_flags & 0x02)) {
5431 secPoint.x = buf->getDefaultDouble(basePoint.x);
5432 secPoint.y = buf->getDefaultDouble(basePoint.y);
5433 } else {
5434 secPoint = basePoint;
5435 }
5436 } else {
5437 secPoint.x = buf->getRawDouble();
5438 secPoint.y = buf->getRawDouble();
5439 }
5440 secPoint.z = basePoint.z;
5441 extPoint = buf->getExtrusion(version > DRW::AC1014);
5442 thickness = buf->getThickness(version > DRW::AC1014);
5443 if (version > DRW::AC1014) {
5444 if (!(data_flags & 0x04)) oblique = buf->getRawDouble();
5445 if (!(data_flags & 0x08)) angle = buf->getRawDouble();
5446 height = buf->getRawDouble();
5447 if (!(data_flags & 0x10)) widthscale = buf->getRawDouble();
5448 } else {
5449 oblique = buf->getBitDouble();
5450 angle = buf->getBitDouble();
5451 height = buf->getBitDouble();
5452 widthscale = buf->getBitDouble();
5453 }
5454 angle *= ARAD57.29577951308232;
5455 text = sBuf->getVariableText(version, false);
5456 DRW_DBG("text value: ")DRW_dbg::dbg("text value: "); DRW_DBG(text.c_str())DRW_dbg::dbg(text.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n");
5457 if (!(data_flags & 0x20)) textgen = buf->getBitShort();
5458 if (!(data_flags & 0x40)) alignH = (HAlign)buf->getBitShort();
5459 if (!(data_flags & 0x80)) alignV = (VAlign)buf->getBitShort();
5460
5461 // R2010+ ATTRIB version follows the common TEXT data. R2018 adds the
5462 // attribute type immediately after it.
5463 if (version >= DRW::AC1024) {
5464 attVersion = buf->getRawChar8();
5465 DRW_DBG("att version: ")DRW_dbg::dbg("att version: "); DRW_DBG(attVersion)DRW_dbg::dbg(attVersion); DRW_DBG("\n")DRW_dbg::dbg("\n");
5466 }
5467 if (version >= DRW::AC1032) {
5468 m_attributeType = buf->getRawChar8();
5469 DRW_DBG("attribute type: ")DRW_dbg::dbg("attribute type: "); DRW_DBG(m_attributeType)DRW_dbg::dbg(m_attributeType); DRW_DBG("\n")DRW_dbg::dbg("\n");
5470 }
5471
5472 bool hasEmbeddedMText = false;
5473 EmbeddedMTextHandleInfo embeddedMTextHandles;
5474 if (version >= DRW::AC1032 && m_attributeType != 0 && m_attributeType != 1) {
5475 mtext = std::make_unique<DRW_MText>();
5476 if (!parseEmbeddedMTextDwg(version, buf, sBuf, *mtext, embeddedMTextHandles)) {
5477 DRW_DBG("R2018 multi-line ATTRIB payload failed\n")DRW_dbg::dbg("R2018 multi-line ATTRIB payload failed\n");
5478 return false;
5479 }
5480 hasEmbeddedMText = true;
5481 }
5482
5483 // ATTRIB-specific fields
5484 tag = sBuf->getVariableText(version, false);
5485 DRW_DBG("attrib tag: ")DRW_dbg::dbg("attrib tag: "); DRW_DBG(tag.c_str())DRW_dbg::dbg(tag.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n");
5486
5487 m_fieldLength = buf->getBitShort(); /* Field length BS (obsolete, usually 0) */
5488
5489 attribFlags = buf->getRawChar8();
5490 DRW_DBG("attrib flags: ")DRW_dbg::dbg("attrib flags: "); DRW_DBG(attribFlags)DRW_dbg::dbg(attribFlags); DRW_DBG("\n")DRW_dbg::dbg("\n");
5491
5492 // lockPosition (DXF 280) appears since R2007 (AC1021) per ODA §20.4.x /
5493 // ACadSharp. Read gate lowered AC1024->AC1021 so R2007/8/9 imports keep
5494 // it. The encoder still emits it only at AC1024 (no AC1021 writer
5495 // exists), so this is read-only; parseDwgEntHandle repositions to objSize
5496 // for version>AC1018, absorbing the +1 bit without handle-stream drift.
5497 if (version >= DRW::AC1021) {
5498 lockPosition = buf->getBit();
5499 DRW_DBG("lock position: ")DRW_dbg::dbg("lock position: "); DRW_DBG(lockPosition)DRW_dbg::dbg(lockPosition); DRW_DBG("\n")DRW_dbg::dbg("\n");
5500 }
5501
5502 /* Common Entity Handle Data */
5503 if (hasEmbeddedMText
5504 && !consumeEmbeddedMTextHandles(version, buf, objSize, embeddedMTextHandles, mtext.get())) {
5505 return false;
5506 }
5507 ret = DRW_Entity::parseDwgEntHandle(version, buf, !hasEmbeddedMText);
5508 if (!ret)
5509 return ret;
5510
5511 styleH = buf->getHandle();
5512 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");
5513
5514 return buf->isGood();
5515}
5516
5517bool DRW_Attrib::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
5518 (void)bs;
5519 if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext))
5520 return false;
5521 const std::uint8_t attributeType = (m_attributeType == 0) ? 1 : m_attributeType;
5522 const bool hasEmbeddedMText = version >= DRW::AC1032 && attributeType != 1;
5523 if (hasEmbeddedMText && !mtext)
5524 return false;
5525
5526 oType = 2; // ATTRIB class id — see dwgreader.cpp:1148
5527 if (!encodeDwgCommon(version, buf)) return false;
5528
5529 // TEXT-body section — mirrors DRW_Attrib::parseDwg.
5530 // data_flags=0: emit every optional field unconditionally (same
5531 // strategy as DRW_Text::encodeDwg — simpler encoder, ~30 bytes larger).
5532 buf->putRawChar8(0); // data_flags=0
5533 buf->putRawDouble(basePoint.z); // elevation RD
5534 buf->putRawDouble(basePoint.x); // insertion 2RD
5535 buf->putRawDouble(basePoint.y);
5536 buf->putDefaultDouble(basePoint.x, secPoint.x); // alignment 2DD
5537 buf->putDefaultDouble(basePoint.y, secPoint.y);
5538 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
5539 buf->putThickness(thickness, /*b_R2000_style=*/true);
5540 buf->putRawDouble(oblique); // oblique angle RD
5541 buf->putRawDouble(angle / ARAD57.29577951308232); // angle in radians RD
5542 buf->putRawDouble(height); // text height RD
5543 buf->putRawDouble(widthscale); // width factor RD
5544 dwgBufferW *sb = strBuf ? strBuf : buf;
5545 sb->putVariableText(version, text); // text string TV
5546 buf->putBitShort(static_cast<std::uint16_t>(textgen)); // generation flags BS
5547 buf->putBitShort(static_cast<std::uint16_t>(alignH)); // horiz align BS
5548 buf->putBitShort(static_cast<std::uint16_t>(alignV)); // vert align BS
5549
5550 if (version >= DRW::AC1024) {
5551 buf->putRawChar8(hasEmbeddedMText && attVersion == 0 ? 1 : attVersion);
5552 }
5553 if (version >= DRW::AC1032) {
5554 buf->putRawChar8(attributeType);
5555 }
5556
5557 if (hasEmbeddedMText) {
5558 if (!encodeEmbeddedMTextDwg(version, buf, strBuf, handleBuf, *mtext))
5559 return false;
5560 }
5561
5562 // ATTRIB-specific tail
5563 sb->putVariableText(version, tag); // tag TV
5564 buf->putBitShort(static_cast<std::uint16_t>(m_fieldLength)); // fieldLen BS
5565 buf->putRawChar8(attribFlags); // flags RC
5566 if (version >= DRW::AC1024) {
5567 buf->putBit(lockPosition ? 1 : 0); // lock position B
5568 }
5569
5570 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
5571
5572 dwgHandle sH;
5573 std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref;
5574 sH.code = 5;
5575 sH.ref = sref;
5576 sH.size = 0;
5577 if (sref != 0) { std::uint32_t t = sref; while (t != 0) { t >>= 8; ++sH.size; } }
5578 (handleBuf ? handleBuf : buf)->putHandle(sH);
5579 return true;
5580}
5581
5582bool DRW_Attdef::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5583 switch (code) {
5584 case 3:
5585 prompt = reader->getUtf8String();
5586 break;
5587 default:
5588 return DRW_Attrib::parseCode(code, reader);
5589 }
5590 return true;
5591}
5592
5593bool DRW_Attdef::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5594 // ATTDEF mirrors ATTRIB layout but adds a prompt string after the tag.
5595 // Implementation duplicates ATTRIB::parseDwg in order to inject the
5596 // prompt read at the correct offset; refactor opportunity if a third
5597 // sibling appears.
5598 dwgBuffer sBuff = *buf;
5599 dwgBuffer *sBuf = buf;
5600 if (version > DRW::AC1018) {
5601 sBuf = &sBuff;
5602 }
5603 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5604 if (!ret)
5605 return ret;
5606 DRW_DBG("\n***************************** parsing attdef *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attdef *********************************************\n"
)
;
5607
5608 std::uint8_t data_flags = 0x00;
5609 if (version > DRW::AC1014) {
5610 data_flags = buf->getRawChar8();
5611 if (!(data_flags & 0x01)) basePoint.z = buf->getRawDouble();
5612 } else {
5613 basePoint.z = buf->getBitDouble();
5614 }
5615 basePoint.x = buf->getRawDouble();
5616 basePoint.y = buf->getRawDouble();
5617 if (version > DRW::AC1014) {
5618 if (!(data_flags & 0x02)) {
5619 secPoint.x = buf->getDefaultDouble(basePoint.x);
5620 secPoint.y = buf->getDefaultDouble(basePoint.y);
5621 } else {
5622 secPoint = basePoint;
5623 }
5624 } else {
5625 secPoint.x = buf->getRawDouble();
5626 secPoint.y = buf->getRawDouble();
5627 }
5628 secPoint.z = basePoint.z;
5629 extPoint = buf->getExtrusion(version > DRW::AC1014);
5630 thickness = buf->getThickness(version > DRW::AC1014);
5631 if (version > DRW::AC1014) {
5632 if (!(data_flags & 0x04)) oblique = buf->getRawDouble();
5633 if (!(data_flags & 0x08)) angle = buf->getRawDouble();
5634 height = buf->getRawDouble();
5635 if (!(data_flags & 0x10)) widthscale = buf->getRawDouble();
5636 } else {
5637 oblique = buf->getBitDouble();
5638 angle = buf->getBitDouble();
5639 height = buf->getBitDouble();
5640 widthscale = buf->getBitDouble();
5641 }
5642 angle *= ARAD57.29577951308232;
5643 text = sBuf->getVariableText(version, false);
5644 if (!(data_flags & 0x20)) textgen = buf->getBitShort();
5645 if (!(data_flags & 0x40)) alignH = (HAlign)buf->getBitShort();
5646 if (!(data_flags & 0x80)) alignV = (VAlign)buf->getBitShort();
5647
5648 if (version >= DRW::AC1024) {
5649 attVersion = buf->getRawChar8();
5650 }
5651 if (version >= DRW::AC1032) {
5652 m_attributeType = buf->getRawChar8();
5653 }
5654
5655 bool hasEmbeddedMText = false;
5656 EmbeddedMTextHandleInfo embeddedMTextHandles;
5657 if (version >= DRW::AC1032 && m_attributeType != 0 && m_attributeType != 1) {
5658 mtext = std::make_unique<DRW_MText>();
5659 if (!parseEmbeddedMTextDwg(version, buf, sBuf, *mtext, embeddedMTextHandles)) {
5660 DRW_DBG("R2018 multi-line ATTDEF payload failed\n")DRW_dbg::dbg("R2018 multi-line ATTDEF payload failed\n");
5661 return false;
5662 }
5663 hasEmbeddedMText = true;
5664 }
5665
5666 tag = sBuf->getVariableText(version, false);
5667 DRW_DBG("attdef tag: ")DRW_dbg::dbg("attdef tag: "); DRW_DBG(tag.c_str())DRW_dbg::dbg(tag.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n");
5668
5669 m_fieldLength = buf->getBitShort(); /* field length BS (obsolete, usually 0) */
5670
5671 attribFlags = buf->getRawChar8();
5672
5673 // lockPosition (DXF 280): read gate lowered AC1024->AC1021 to match
5674 // ATTRIB (R2007+). promptVersion/keep_duplicate RC below stays AC1024+.
5675 if (version >= DRW::AC1021) {
5676 lockPosition = buf->getBit();
5677 }
5678
5679 if (version >= DRW::AC1024) {
5680 const std::uint8_t promptVersion = buf->getRawChar8();
5681 DRW_UNUSED(promptVersion)(void)promptVersion;
5682 }
5683
5684 // ATTDEF prompt follows attrib body
5685 prompt = sBuf->getVariableText(version, false);
5686 DRW_DBG("attdef prompt: ")DRW_dbg::dbg("attdef prompt: "); DRW_DBG(prompt.c_str())DRW_dbg::dbg(prompt.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n");
5687
5688 if (hasEmbeddedMText
5689 && !consumeEmbeddedMTextHandles(version, buf, objSize, embeddedMTextHandles, mtext.get())) {
5690 return false;
5691 }
5692 ret = DRW_Entity::parseDwgEntHandle(version, buf, !hasEmbeddedMText);
5693 if (!ret)
5694 return ret;
5695
5696 styleH = buf->getHandle();
5697
5698 return buf->isGood();
5699}
5700
5701bool DRW_Attdef::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
5702 (void)bs;
5703 if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext))
5704 return false;
5705 const std::uint8_t attributeType = (m_attributeType == 0) ? 1 : m_attributeType;
5706 const bool hasEmbeddedMText = version >= DRW::AC1032 && attributeType != 1;
5707 if (hasEmbeddedMText && !mtext)
5708 return false;
5709
5710 oType = 3; // ATTDEF class id — see dwgreader.cpp:1185
5711 if (!encodeDwgCommon(version, buf)) return false;
5712
5713 // TEXT-body section — identical layout to DRW_Attrib::encodeDwg.
5714 buf->putRawChar8(0);
5715 buf->putRawDouble(basePoint.z);
5716 buf->putRawDouble(basePoint.x);
5717 buf->putRawDouble(basePoint.y);
5718 buf->putDefaultDouble(basePoint.x, secPoint.x);
5719 buf->putDefaultDouble(basePoint.y, secPoint.y);
5720 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
5721 buf->putThickness(thickness, /*b_R2000_style=*/true);
5722 buf->putRawDouble(oblique);
5723 buf->putRawDouble(angle / ARAD57.29577951308232);
5724 buf->putRawDouble(height);
5725 buf->putRawDouble(widthscale);
5726 dwgBufferW *sb = strBuf ? strBuf : buf;
5727 sb->putVariableText(version, text);
5728 buf->putBitShort(static_cast<std::uint16_t>(textgen));
5729 buf->putBitShort(static_cast<std::uint16_t>(alignH));
5730 buf->putBitShort(static_cast<std::uint16_t>(alignV));
5731
5732 if (version >= DRW::AC1024) {
5733 buf->putRawChar8(hasEmbeddedMText && attVersion == 0 ? 1 : attVersion);
5734 }
5735 if (version >= DRW::AC1032) {
5736 buf->putRawChar8(attributeType);
5737 }
5738
5739 if (hasEmbeddedMText) {
5740 if (!encodeEmbeddedMTextDwg(version, buf, strBuf, handleBuf, *mtext))
5741 return false;
5742 }
5743
5744 sb->putVariableText(version, tag);
5745 buf->putBitShort(static_cast<std::uint16_t>(m_fieldLength)); // fieldLen BS
5746 buf->putRawChar8(attribFlags);
5747 if (version >= DRW::AC1024) {
5748 buf->putBit(lockPosition ? 1 : 0);
5749 }
5750
5751 if (version >= DRW::AC1024) {
5752 buf->putRawChar8(attVersion);
5753 }
5754
5755 // ATTDEF adds prompt between flags and handle stream
5756 sb->putVariableText(version, prompt);
5757
5758 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
5759
5760 dwgHandle sH;
5761 std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref;
5762 sH.code = 5;
5763 sH.ref = sref;
5764 sH.size = 0;
5765 if (sref != 0) { std::uint32_t t = sref; while (t != 0) { t >>= 8; ++sH.size; } }
5766 (handleBuf ? handleBuf : buf)->putHandle(sH);
5767 return true;
5768}
5769
5770bool DRW_MText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5771 switch (code) {
5772 case 1:
5773 text += reader->getString();
5774 text = reader->toUtf8String(text);
5775 break;
5776 case 11:
5777 hasXAxisVec = true;
5778 return DRW_Text::parseCode(code, reader);
5779 case 3:
5780 text += reader->getString();
5781 break;
5782 case 44:
5783 interlin = reader->getDouble();
5784 break;
5785 case 50: // djm: per dxf docs, last of code 11 or code 50 prevails
5786 hasXAxisVec = false;
5787 angle = reader->getDouble();
5788 break;
5789 case 73:
5790 linespacingStyle = static_cast<std::uint16_t>(reader->getInt32());
5791 break;
5792 default:
5793 return DRW_Text::parseCode(code, reader);
5794 }
5795
5796 return true;
5797}
5798
5799bool DRW_MText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5800 dwgBuffer sBuff = *buf;
5801 dwgBuffer *sBuf = buf;
5802 if (version > DRW::AC1018) {//2007+
5803 sBuf = &sBuff; //separate buffer for strings
5804 }
5805 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5806 if (!ret)
5807 return ret;
5808 DRW_DBG("\n***************************** parsing mtext *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mtext *********************************************\n"
)
;
5809
5810 basePoint = buf->get3BitDouble(); /* Insertion pt 3BD 10 - First picked point. */
5811 DRW_DBG("Insertion: ")DRW_dbg::dbg("Insertion: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n");
5812 extPoint = buf->get3BitDouble(); /* Extrusion 3BD 210 Undocumented; */
5813 secPoint = buf->get3BitDouble(); /* X-axis dir 3BD 11 */
5814 hasXAxisVec = true;
5815 updateAngle();
5816 widthscale = buf->getBitDouble(); /* Rect width BD 41 */
5817 if (version > DRW::AC1018) {//2007+
5818 /* Rect height BD 46 Reference rectangle height. */
5819 /** @todo */buf->getBitDouble();
5820 }
5821 height = buf->getBitDouble();/* Text height BD 40 Undocumented */
5822 textgen = buf->getBitShort(); /* Attachment BS 71 Similar to justification; */
5823 /* Drawing dir BS 72 Left to right, etc.; see DXF doc. Reuse the
5824 * inherited alignH slot — for MTEXT this field carries the DXF group 72
5825 * "drawing direction" code (1=LtoR, 3=TtoB, 5=ByStyle), not the TEXT
5826 * horizontal-alignment values the HAlign enum was named for. The integer
5827 * round-trips cleanly; consumers compare against the raw integer. */
5828 alignH = static_cast<HAlign>(buf->getBitShort());
5829 /* Extents ht BD Undocumented and not present in DXF or entget */
5830 double ext_ht = buf->getBitDouble();
5831 DRW_UNUSED(ext_ht)(void)ext_ht;
5832 /* Extents wid BD Undocumented and not present in DXF or entget The extents
5833 rectangle, when rotated the same as the text, fits the actual text image on
5834 the screen (although we've seen it include an extra row of text in height). */
5835 double ext_wid = buf->getBitDouble();
5836 DRW_UNUSED(ext_wid)(void)ext_wid;
5837 /* Text TV 1 All text in one long string (without '\n's 3 for line wrapping).
5838 ACAD seems to add braces ({ }) and backslash-P's to indicate paragraphs
5839 based on the "\r\n"'s found in the imported file. But, all the text is in
5840 this one long string -- not broken into 1- and 3-groups as in DXF and
5841 entget. ACAD's entget breaks this string into 250-char pieces (not 255 as
5842 doc'd) – even if it's mid-word. The 1-group always gets the tag end;
5843 therefore, the 3's are always 250 chars long. */
5844 text = sBuf->getVariableText(version, false); /* Text value TV 1 */
5845 if (version > DRW::AC1014) {//2000+
5846 linespacingStyle = buf->getBitShort(); // ODA §20.4.46 code 73
5847 interlin = buf->getBitDouble();/* Linespacing Factor BD 44 */
5848 buf->getBit();/* Unknown bit B */
5849 }
5850 if (version > DRW::AC1015) {//2004+
5851 /* Background flags BL 0 = no background, 1 = background fill, 2 =background
5852 fill with drawing fill color. */
5853 m_backgroundFlags = buf->getBitLong();
5854 if ((m_backgroundFlags & 0x01) || (version >= DRW::AC1032 && (m_backgroundFlags & 0x10))) {
5855 /* Background-fill box scale, present if background flags & 1 (default
5856 1.5). It is a BitDouble, NOT a BitLong: reading it as BL consumes
5857 the wrong bit width and desyncs the stream so the following CMC
5858 fill-colour reads garbage and the entity body overruns (parse fails
5859 on every MTEXT with background fill, e.g. sample_AC1018). ACadSharp
5860 reads ReadBitDouble here. */
5861 m_backgroundScale = buf->getBitDouble();
5862 /* Background color CMC Present if background flags = 1 */
5863 m_backgroundColor = static_cast<int>(buf->getCmColor(version, nullptr, sBuf));
5864 /** @todo buf->getCMC */
5865 /* Background transparency BL Present if background flags = 1 */
5866 m_backgroundTransparency = buf->getBitLong();
5867 }
5868 }
5869
5870 bool hasR2018AppId = false;
5871 if (version >= DRW::AC1032) {
5872 m_r2018ColumnHeights.clear();
5873 m_r2018IsNotAnnotative = buf->getBit();
5874 if (m_r2018IsNotAnnotative) {
5875 m_r2018Version = buf->getBitShort();
5876 m_r2018DefaultFlag = buf->getBit();
5877 hasR2018AppId = true; // appid H follows in handle stream
5878 m_r2018Attachment = buf->getBitLong();
5879 m_r2018XAxisDir = buf->get3BitDouble();
5880 m_r2018InsertionPoint = buf->get3BitDouble();
5881 m_r2018RectWidth = buf->getBitDouble();
5882 m_r2018RectHeight = buf->getBitDouble();
5883 m_r2018ExtentsHeight = buf->getBitDouble();
5884 m_r2018ExtentsWidth = buf->getBitDouble();
5885 m_r2018ColumnType = buf->getBitShort();
5886 if (m_r2018ColumnType != 0) {
5887 m_r2018ColumnCount = buf->getBitLong();
5888 m_r2018ColumnWidth = buf->getBitDouble();
5889 m_r2018ColumnGutter = buf->getBitDouble();
5890 m_r2018ColumnAutoHeight = buf->getBit();
5891 m_r2018ColumnFlowReversed = buf->getBit();
5892 if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2 && m_r2018ColumnCount > 0
5893 && m_r2018ColumnCount < 10000) {
5894 m_r2018ColumnHeights.reserve(static_cast<size_t>(m_r2018ColumnCount));
5895 for (std::int32_t i = 0; i < m_r2018ColumnCount; ++i) {
5896 m_r2018ColumnHeights.push_back(buf->getBitDouble());
5897 }
5898 }
5899 }
5900 }
5901 }
5902
5903 /* Common Entity Handle Data */
5904 ret = DRW_Entity::parseDwgEntHandle(version, buf);
5905 if (!ret)
5906 return ret;
5907
5908 styleH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
5909 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(".");
5910 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");
5911 if (hasR2018AppId) {
5912 dwgHandle appIdH = buf->getHandle();
5913 m_r2018AppIdHandle = appIdH.ref;
5914 DRW_DBG("mtext R2018 appid Handle: ")DRW_dbg::dbg("mtext R2018 appid Handle: "); DRW_DBGHL(appIdH.code, appIdH.size, appIdH.ref)DRW_dbg::dbgHL(appIdH.code, appIdH.size, appIdH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
5915 }
5916
5917 /* CRC X --- */
5918 return buf->isGood();
5919}
5920
5921void DRW_MText::updateAngle() {
5922 if (hasXAxisVec) {
5923 angle = atan2(secPoint.y, secPoint.x) * ARAD57.29577951308232;
5924 }
5925}
5926
5927bool DRW_Polyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5928 switch (code) {
5929 case 70:
5930 flags = reader->getInt32();
5931 break;
5932 case 40:
5933 defstawidth = reader->getDouble();
5934 break;
5935 case 41:
5936 defendwidth = reader->getDouble();
5937 break;
5938 case 71:
5939 vertexcount = reader->getInt32();
5940 break;
5941 case 72:
5942 facecount = reader->getInt32();
5943 break;
5944 case 73:
5945 smoothM = reader->getInt32();
5946 break;
5947 case 74:
5948 smoothN = reader->getInt32();
5949 break;
5950 case 75:
5951 curvetype = reader->getInt32();
5952 break;
5953 default:
5954 return DRW_Point::parseCode(code, reader);
5955 }
5956
5957 return true;
5958}
5959
5960//0x0F polyline 2D bit 4(8) & 5(16) NOT set
5961//0x10 polyline 3D bit 4(8) set
5962//0x1D PFACE bit 5(16) set
5963bool DRW_Polyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5964 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
5965 if (!ret)
5966 return ret;
5967 DRW_DBG("\n***************************** parsing polyline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing polyline *********************************************\n"
)
;
5968
5969 std::int32_t ooCount = 0;
5970 if (oType == 0x0F) { //pline 2D
5971 flags = buf->getBitShort();
5972 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
5973 curvetype = buf->getBitShort();
5974 defstawidth = buf->getBitDouble();
5975 defendwidth = buf->getBitDouble();
5976 thickness = buf->getThickness(version > DRW::AC1014);
5977 basePoint = DRW_Coord(0,0,buf->getBitDouble());
5978 extPoint = buf->getExtrusion(version > DRW::AC1014);
5979 } else if (oType == 0x10) { //pline 3D
5980 std::uint8_t tmpFlag = buf->getRawChar8();
5981 DRW_DBG("flags 1 value: ")DRW_dbg::dbg("flags 1 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag);
5982 if (tmpFlag & 1)
5983 curvetype = 5; // quadratic B-spline
5984 else if (tmpFlag & 2)
5985 curvetype = 6; // cubic B-spline
5986 if (tmpFlag & 3)
5987 flags |= 4; // splined (bit 2); do NOT overwrite curvetype to 8
5988 tmpFlag = buf->getRawChar8();
5989 if (tmpFlag & 1)
5990 flags |= 1;
5991 flags |= 8; //indicate 3DPOL
5992 DRW_DBG("flags 2 value: ")DRW_dbg::dbg("flags 2 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag);
5993 } else if (oType == 0x1D) { //PFACE
5994 flags = 64;
5995 vertexcount = buf->getBitShort();
5996 DRW_DBG("vertex count: ")DRW_dbg::dbg("vertex count: "); DRW_DBG(vertexcount)DRW_dbg::dbg(vertexcount);
5997 facecount = buf->getBitShort();
5998 DRW_DBG("face count: ")DRW_dbg::dbg("face count: "); DRW_DBG(facecount)DRW_dbg::dbg(facecount);
5999 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6000 } else if (oType == 0x1E) { //POLYLINE_MESH per ODA spec sec 19.4.31
6001 flags = buf->getBitShort();
6002 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6003 flags |= 16; //bit 4 = 3D polygon mesh
6004 curvetype = buf->getBitShort();
6005 vertexcount = buf->getBitShort(); //M-count
6006 DRW_DBG(" M count: ")DRW_dbg::dbg(" M count: "); DRW_DBG(vertexcount)DRW_dbg::dbg(vertexcount);
6007 facecount = buf->getBitShort(); //N-count
6008 DRW_DBG(" N count: ")DRW_dbg::dbg(" N count: "); DRW_DBG(facecount)DRW_dbg::dbg(facecount);
6009 smoothM = buf->getBitShort(); //M smooth-surface density, DXF 73
6010 smoothN = buf->getBitShort(); //N smooth-surface density, DXF 74
6011 DRW_DBG(" M/N density: ")DRW_dbg::dbg(" M/N density: "); DRW_DBG(smoothM)DRW_dbg::dbg(smoothM); DRW_DBG("/")DRW_dbg::dbg("/"); DRW_DBG(smoothN)DRW_dbg::dbg(smoothN);
6012 }
6013 if (version > DRW::AC1015){ //2004+
6014 ooCount = buf->getBitLong();
6015 }
6016
6017 ret = DRW_Entity::parseDwgEntHandle(version, buf);
6018 if (!ret)
6019 return ret;
6020
6021 if (version < DRW::AC1018){ //2000-
6022 dwgHandle objectH = buf->getOffsetHandle(handle);
6023 firstEH = objectH.ref;
6024 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");
6025 objectH = buf->getOffsetHandle(handle);
6026 lastEH = objectH.ref;
6027 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");
6028 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");
6029 } else {
6030 for (std::int32_t i = 0; i < ooCount; ++i){
6031 dwgHandle objectH = buf->getOffsetHandle(handle);
6032 hadlesList.push_back (objectH.ref);
6033 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");
6034 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");
6035 }
6036 }
6037 seqEndH = buf->getOffsetHandle(handle);
6038 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");
6039 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");
6040
6041// RS crc; //RS */
6042 return buf->isGood();
6043}
6044
6045bool DRW_Vertex::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
6046 switch (code) {
6047 case 70:
6048 flags = reader->getInt32();
6049 break;
6050 case 40:
6051 stawidth = reader->getDouble();
6052 break;
6053 case 41:
6054 endwidth = reader->getDouble();
6055 break;
6056 case 42:
6057 bulge = reader->getDouble();
6058 break;
6059 case 50:
6060 tgdir = reader->getDouble();
6061 break;
6062 case 71:
6063 vindex1 = reader->getInt32();
6064 break;
6065 case 72:
6066 vindex2 = reader->getInt32();
6067 break;
6068 case 73:
6069 vindex3 = reader->getInt32();
6070 break;
6071 case 74:
6072 vindex4 = reader->getInt32();
6073 break;
6074 case 91:
6075 identifier = reader->getInt32();
6076 break;
6077 default:
6078 return DRW_Point::parseCode(code, reader);
6079 }
6080
6081 return true;
6082}
6083
6084//0x0A vertex 2D
6085//0x0B vertex 3D
6086//0x0C MESH
6087//0x0D PFACE
6088//0x0E PFACE FACE
6089bool DRW_Vertex::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs, double el){
6090 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
6091 if (!ret)
6092 return ret;
6093 DRW_DBG("\n***************************** parsing pline Vertex *********************************************\n")DRW_dbg::dbg("\n***************************** parsing pline Vertex *********************************************\n"
)
;
6094
6095 if (oType == 0x0A) { //pline 2D, needed example
6096 m_dwgSubtype = DwgSubtype::Vertex2D;
6097 flags = buf->getRawChar8(); //RLZ: EC unknown type
6098 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6099 basePoint = buf->get3BitDouble();
6100 basePoint.z = el;
6101 DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
6102 stawidth = buf->getBitDouble();
6103 if (stawidth < 0)
6104 endwidth = stawidth = fabs(stawidth);
6105 else
6106 endwidth = buf->getBitDouble();
6107 bulge = buf->getBitDouble();
6108 if (version > DRW::AC1021) { //2010+
6109 identifier = buf->getBitLong(); // ODA §20.4.11 code 91
6110 DRW_DBG("Vertex ID: ")DRW_dbg::dbg("Vertex ID: "); DRW_DBG(identifier)DRW_dbg::dbg(identifier);
6111 }
6112 tgdir = buf->getBitDouble();
6113 } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) { //PFACE
6114 if (oType == 0x0B)
6115 m_dwgSubtype = DwgSubtype::Vertex3D;
6116 else if (oType == 0x0C)
6117 m_dwgSubtype = DwgSubtype::Mesh;
6118 else
6119 m_dwgSubtype = DwgSubtype::Polyface;
6120 flags = buf->getRawChar8(); //RLZ: EC unknown type
6121 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6122 basePoint = buf->get3BitDouble();
6123 DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
6124 } else if (oType == 0x0E) { //PFACE FACE
6125 m_dwgSubtype = DwgSubtype::PolyfaceFace;
6126 auto signedIndex = [](int value) {
6127 return value > 32767 ? value - 65536 : value;
6128 };
6129 vindex1 = signedIndex(buf->getBitShort());
6130 vindex2 = signedIndex(buf->getBitShort());
6131 vindex3 = signedIndex(buf->getBitShort());
6132 vindex4 = signedIndex(buf->getBitShort());
6133 }
6134
6135 ret = DRW_Entity::parseDwgEntHandle(version, buf);
6136 if (!ret)
6137 return ret;
6138// RS crc; //RS */
6139 return buf->isGood();
6140}
6141
6142bool DRW_Hatch::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
6143 switch (code) {
6144 case 2:
6145 name = reader->getUtf8String();
6146 break;
6147 case 70:
6148 solid = reader->getInt32();
6149 break;
6150 case 71:
6151 associative = reader->getInt32();
6152 break;
6153 case 72: /*edge type*/
6154 if (ispol){ // polyline path: 72 is the has-bulge flag. Do NOT fold it
6155 // into pline->flags — bit 0 there is the *closed* flag (set by code
6156 // 73), and the per-vertex bulges arrive via code 42 regardless. Some
6157 // writers (e.g. ezdxf MPOLYGON) emit 73 before 72; the old code let
6158 // 72 clear the closed bit 73 had just set, leaving the boundary open
6159 // so RS_Hatch::validate() rejected the area.
6160 break;
6161 } else if (reader->getInt32() == 1){ //line
6162 addLine();
6163 } else if (reader->getInt32() == 2){ //arc
6164 addArc();
6165 } else if (reader->getInt32() == 3){ //elliptic arc
6166 addEllipse();
6167 } else if (reader->getInt32() == 4){ //spline
6168 addSpline();
6169 }
6170 break;
6171 case 10:
6172 // Spline edge: 10 is a control-point x-coord.
6173 if (spline) {
6174 spline->controllist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0));
6175 break;
6176 }
6177 if (pt) pt->basePoint.x = reader->getDouble();
6178 else if (pline) {
6179 plvert = pline->addVertex();
6180 plvert->x = reader->getDouble();
6181 } else {
6182 // After group 98 the boundary path is closed; seed-point
6183 // coords arrive as group-10/20 pairs.
6184 DRW_Coord seed;
6185 seed.x = reader->getDouble();
6186 seedPoints.push_back(seed);
6187 }
6188 break;
6189 case 20:
6190 if (spline && !spline->controllist.empty()) {
6191 spline->controllist.back()->y = reader->getDouble();
6192 break;
6193 }
6194 if (pt) pt->basePoint.y = reader->getDouble();
6195 else if (plvert) plvert ->y = reader->getDouble();
6196 else if (!seedPoints.empty())
6197 seedPoints.back().y = reader->getDouble();
6198 break;
6199 case 11:
6200 // Spline edge: 11 is a fit-point x-coord.
6201 if (spline) {
6202 spline->fitlist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0));
6203 break;
6204 }
6205 if (line) line->secPoint.x = reader->getDouble();
6206 else if (ellipse) ellipse->secPoint.x = reader->getDouble();
6207 break;
6208 case 21:
6209 if (spline && !spline->fitlist.empty()) {
6210 spline->fitlist.back()->y = reader->getDouble();
6211 break;
6212 }
6213 if (line) line->secPoint.y = reader->getDouble();
6214 else if (ellipse) ellipse->secPoint.y = reader->getDouble();
6215 break;
6216 case 12:
6217 if (spline) { spline->tgStart.x = reader->getDouble(); break; }
6218 break;
6219 case 22:
6220 if (spline) { spline->tgStart.y = reader->getDouble(); break; }
6221 break;
6222 case 13:
6223 if (spline) { spline->tgEnd.x = reader->getDouble(); break; }
6224 break;
6225 case 23:
6226 if (spline) { spline->tgEnd.y = reader->getDouble(); break; }
6227 break;
6228 case 40:
6229 // Spline edge: 40 is a knot value (occurs nknots times).
6230 if (spline) {
6231 spline->knotslist.push_back(reader->getDouble());
6232 break;
6233 }
6234 if (arc) arc->radious = reader->getDouble();
6235 else if (ellipse) ellipse->ratio = reader->getDouble();
6236 break;
6237 case 41:
6238 scale = reader->getDouble();
6239 break;
6240 case 42:
6241 // Spline edge: 42 is a per-control-point weight.
6242 if (spline) {
6243 spline->weightlist.push_back(reader->getDouble());
6244 break;
6245 }
6246 if (plvert) plvert ->bulge = reader->getDouble();
6247 break;
6248 case 50:
6249 if (arc) arc->staangle = reader->getDouble()/ARAD57.29577951308232;
6250 else if (ellipse) ellipse->staparam = reader->getDouble()/ARAD57.29577951308232;
6251 break;
6252 case 51:
6253 if (arc) arc->endangle = reader->getDouble()/ARAD57.29577951308232;
6254 else if (ellipse) ellipse->endparam = reader->getDouble()/ARAD57.29577951308232;
6255 break;
6256 case 47:
6257 pixelSize = reader->getDouble();
6258 break;
6259 case 52:
6260 angle = reader->getDouble();
6261 break;
6262 case 53: // pattern line angle — starts a new PatternLine record
6263 patternLines.push_back(PatternLine());
6264 patternLines.back().angle = reader->getDouble();
6265 break;
6266 case 43:
6267 if (!patternLines.empty()) patternLines.back().baseX = reader->getDouble();
6268 break;
6269 case 44:
6270 if (!patternLines.empty()) patternLines.back().baseY = reader->getDouble();
6271 break;
6272 case 45:
6273 if (!patternLines.empty()) patternLines.back().offsetX = reader->getDouble();
6274 break;
6275 case 46:
6276 if (!patternLines.empty()) patternLines.back().offsetY = reader->getDouble();
6277 break;
6278 case 79: // dash count — the 49s that follow will accumulate
6279 break;
6280 case 49:
6281 if (!patternLines.empty()) patternLines.back().dashList.push_back(reader->getDouble());
6282 break;
6283 case 73:
6284 // Spline edge: 73 is the rational flag (1 = rational).
6285 if (spline) {
6286 if (reader->getInt32()) spline->flags |= 0x4;
6287 break;
6288 }
6289 if (arc) arc->isccw = reader->getInt32();
6290 // polyline path: 73 is the is-closed flag -> set bit 0 only, leaving the
6291 // rest of pline->flags untouched (order-independent vs code 72).
6292 else if (pline) pline->flags = (pline->flags & ~1) | (reader->getInt32() ? 1 : 0);
6293 break;
6294 case 74:
6295 // Spline edge: 74 is the periodic flag (1 = periodic/closed).
6296 if (spline) {
6297 if (reader->getInt32()) spline->flags |= 0x2;
6298 }
6299 break;
6300 case 94:
6301 // Spline edge degree.
6302 if (spline) spline->degree = reader->getInt32();
6303 break;
6304 case 95:
6305 // Spline edge number of knots.
6306 if (spline) spline->nknots = reader->getInt32();
6307 break;
6308 case 96:
6309 // Spline edge number of control points.
6310 if (spline) spline->ncontrol = reader->getInt32();
6311 break;
6312 case 97:
6313 if (spline) {
6314 if (!m_splineNfitSet) {
6315 // First 97 in this spline edge = fit-point count (nfit).
6316 spline->nfit = reader->getInt32();
6317 if (spline->nfit == 0) {
6318 // No fit points or tangents follow; safe to clear spline
6319 // so the next code-97 (loop boundary count) is not
6320 // misinterpreted as another nfit.
6321 spline.reset();
6322 } else {
6323 m_splineNfitSet = true;
6324 }
6325 } else {
6326 // Second 97 while spline is active = loop boundary handle count.
6327 spline.reset();
6328 m_splineNfitSet = false;
6329 m_boundaryHandleCount = reader->getInt32();
6330 if (m_boundaryHandleCount > 0 && loop)
6331 DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount);
6332 }
6333 break;
6334 }
6335 // No active spline: this is the loop boundary handle count.
6336 m_splineNfitSet = false;
6337 m_boundaryHandleCount = reader->getInt32();
6338 if (m_boundaryHandleCount > 0 && loop)
6339 DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount);
6340 break;
6341 case 330:
6342 if (m_boundaryHandleCount > 0 && loop) {
6343 // getHandleString() converts the hex string to int for us.
6344 loop->m_boundaryHandles.push_back(
6345 static_cast<std::uint32_t>(reader->getHandleString()));
6346 --m_boundaryHandleCount;
6347 break;
6348 }
6349 return DRW_Point::parseCode(code, reader);
6350 case 75:
6351 hstyle = reader->getInt32();
6352 break;
6353 case 76:
6354 hpattern = reader->getInt32();
6355 break;
6356 case 77:
6357 doubleflag = reader->getInt32();
6358 break;
6359 case 78:
6360 deflines = reader->getInt32();
6361 break;
6362 case 91:
6363 loopsnum = reader->getInt32();
6364 return DRW::reserve( looplist, loopsnum);
6365 case 92:
6366 loop = std::make_shared<DRW_HatchLoop>(reader->getInt32());
6367 looplist.push_back(loop);
6368 if (reader->getInt32() & 2) {
6369 ispol = true;
6370 clearEntities();
6371 pline = std::make_shared<DRW_LWPolyline>();
6372 loop->objlist.push_back(pline);
6373 } else ispol = false;
6374 break;
6375 case 93:
6376 if (pline) pline->vertexnum = reader->getInt32();
6377 else if (loop) loop->numedges = reader->getInt32();//aqui reserve
6378 break;
6379 case 98: { // seed-point count; coords follow as group-10/20 pairs
6380 clearEntities();
6381 const int count = reader->getInt32();
6382 if (count > 0)
6383 DRW::reserve(seedPoints, count);
6384 break;
6385 }
6386 case 450:
6387 isGradient = reader->getInt32();
6388 break;
6389 case 451:
6390 gradReserved = reader->getInt32();
6391 break;
6392 case 452:
6393 singleColor = reader->getInt32();
6394 break;
6395 case 453: {
6396 const int n = reader->getInt32();
6397 if (n > 0)
6398 DRW::reserve(gradColors, n);
6399 break;
6400 }
6401 case 460:
6402 gradAngle = reader->getDouble();
6403 break;
6404 case 461:
6405 gradShift = reader->getDouble();
6406 break;
6407 case 462:
6408 gradTint = reader->getDouble();
6409 break;
6410 case 463: {
6411 DRW_Hatch::GradientStop stop;
6412 stop.value = reader->getDouble();
6413 gradColors.push_back(stop);
6414 break;
6415 }
6416 case 421:
6417 if (!gradColors.empty())
6418 gradColors.back().rgb = reader->getInt32();
6419 break;
6420 case 63:
6421 if (!gradColors.empty())
6422 gradColors.back().aciColor = reader->getInt32();
6423 else
6424 return DRW_Point::parseCode(code, reader);
6425 break;
6426 case 431:
6427 if (!gradColors.empty())
6428 gradColors.back().colorMethod = reader->getInt32();
6429 break;
6430 case 432:
6431 if (!gradColors.empty())
6432 gradColors.back().colorName = reader->getUtf8String();
6433 break;
6434 case 433:
6435 if (!gradColors.empty())
6436 gradColors.back().colorBookName = reader->getUtf8String();
6437 break;
6438 case 470:
6439 gradName = reader->getUtf8String();
6440 break;
6441 default:
6442 return DRW_Point::parseCode(code, reader);
6443 }
6444
6445 return true;
6446}
6447
6448bool DRW_MPolygon::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
6449 // MPOLYGON shares HATCH's boundary/pattern/gradient codes, so delegate those
6450 // to DRW_Hatch::parseCode. It adds a trailer that plain HATCH never emits:
6451 // 63 / 421 / 430 fill color (ACI / RGB / book-name) — the filled area's
6452 // color, which may differ from the boundary outline color;
6453 // 11 / 21 boundary x-direction vector (no render impact; left to
6454 // the base, which ignores it outside an edge context);
6455 // 99 count of degenerate boundary paths.
6456 // 63/421 are also gradient sub-codes in HATCH, so only claim them here when no
6457 // gradient is being accumulated (gradColors empty) — otherwise defer to base.
6458 switch (code) {
6459 case 63:
6460 if (gradColors.empty()) { fillColorAci = reader->getInt32(); return true; }
6461 break;
6462 case 421:
6463 if (gradColors.empty()) { fillColorRgb = reader->getInt32(); return true; }
6464 break;
6465 case 430:
6466 fillColorName = reader->getUtf8String();
6467 return true;
6468 case 99:
6469 degenerateLoops = reader->getInt32();
6470 return true;
6471 default:
6472 break;
6473 }
6474 return DRW_Hatch::parseCode(code, reader);
6475}
6476
6477// DRW_MPolygon::parseDwg — AcDbMPolygon DWG body.
6478// Layout mirrors HATCH except (per ACadSharp MPolygon / libreDWG dwg.spec):
6479// * a leading BS `style` (DXF group 75) precedes the gradient block, and
6480// * the trailer is a fill CMC + boundary x-direction (2RD) + degenerate-path
6481// count (BL) instead of HATCH's pixel-size + seed points.
6482// The gradient/elevation/extrusion/name/solid/associative prologue and the whole
6483// boundary-loop body are identical, so they reuse DRW_Hatch::parseDwgBoundaryData.
6484// DWG runtime coverage uses testdata/mpolygon_solid.dwg, ODA-synthesized from
6485// the ezdxf-verified inline DXF in mpolygon_tests.cpp and confirmed with the
6486// dwg-parser oracle.
6487bool DRW_MPolygon::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
6488 dwgBuffer sBuff = *buf;
6489 dwgBuffer *sBuf = buf;
6490 std::uint32_t totalBoundItems = 0;
6491 bool havePixelSize = false;
6492 if (version > DRW::AC1018) //2007+
6493 sBuf = &sBuff; //separate buffer for strings
6494 if (!DRW_Entity::parseDwg(version, buf, sBuf, bs))
6495 return false;
6496 DRW_DBG("\n***************************** parsing mpolygon *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mpolygon *********************************************\n"
)
;
6497
6498 // Leading BS style (group 75) — read once here and again after the loops
6499 // below (HATCH has only the latter); matches the reference parser, which
6500 // discards this first read.
6501 hstyle = buf->getBitShort();
6502
6503 if (version > DRW::AC1015) { //2004+ gradient (same layout as HATCH)
6504 isGradient = buf->getBitLong();
6505 gradReserved = buf->getBitLong();
6506 gradAngle = buf->getBitDouble();
6507 gradShift = buf->getBitDouble();
6508 singleColor = buf->getBitLong();
6509 gradTint = buf->getBitDouble();
6510 std::int32_t numCol = buf->getBitLong();
6511 if (numCol > 0)
6512 DRW::reserve(gradColors, numCol);
6513 for (std::int32_t i = 0 ; i < numCol; ++i){
6514 DRW_Hatch::GradientStop stop;
6515 stop.value = buf->getBitDouble();
6516 buf->getBitShort(); // unknown short
6517 stop.rgb = buf->getBitLong();
6518 buf->getRawChar8(); // ignored color byte
6519 gradColors.push_back(stop);
6520 }
6521 gradName = sBuf->getVariableText(version, false);
6522 }
6523 basePoint.z = buf->getBitDouble(); // elevation
6524 extPoint = buf->get3BitDouble();
6525 name = sBuf->getVariableText(version, false);
6526 solid = buf->getBit();
6527 associative = buf->getBit();
6528
6529 if (!parseDwgBoundaryData(version, buf, totalBoundItems, havePixelSize))
6530 return false;
6531
6532 hstyle = buf->getBitShort();
6533 hpattern = buf->getBitShort();
6534 if (!solid){
6535 angle = buf->getBitDouble();
6536 scale = buf->getBitDouble();
6537 doubleflag = buf->getBit();
6538 deflines = buf->getBitShort();
6539 for (std::int32_t i = 0 ; i < deflines; ++i){
6540 buf->getBitDouble(); // line angle
6541 buf->getBitDouble(); // base x
6542 buf->getBitDouble(); // base y
6543 buf->getBitDouble(); // offset x
6544 buf->getBitDouble(); // offset y
6545 std::uint16_t numDashL = buf->getBitShort();
6546 for (std::uint16_t d = 0 ; d < numDashL; ++d)
6547 buf->getBitDouble(); // dash length
6548 }
6549 }
6550
6551 // MPOLYGON trailer (differs from HATCH): fill CMC + x-direction + degenerate
6552 // path count. No pixel size / seed points here.
6553 std::int32_t rgb = -1;
6554 UTF8STRINGstd::string colName;
6555 fillColorAci = static_cast<int>(buf->getCmColor(version, &rgb, sBuf, &colName));
6556 fillColorRgb = rgb;
6557 fillColorName = colName;
6558 DRW_Coord xdir = buf->get2RawDouble();
6559 xDirX = xdir.x;
6560 xDirY = xdir.y;
6561 degenerateLoops = buf->getBitLong();
6562
6563 if (!DRW_Entity::parseDwgEntHandle(version, buf))
6564 return false;
6565 for (std::uint32_t i = 0 ; i < totalBoundItems; ++i)
6566 buf->getHandle(); // boundary-source handles
6567 return buf->isGood();
6568}
6569
6570// Shared DWG boundary-loop reader for HATCH and MPOLYGON (ODA §20.4.36).
6571// Reads the loop count and, per loop, the derived-boundary flag plus its edge
6572// list or polyline. Accumulates the running boundary-source-handle total and
6573// whether any loop is derived (needs a trailing pixel size). Extracted from
6574// DRW_Hatch::parseDwg so DRW_MPolygon::parseDwg reuses the identical body while
6575// supplying its own differing leading (BS style) and trailing (fill CMC +
6576// x-direction + degenerate count) field order.
6577bool DRW_MPolygon::encodeDwg(DRW::Version version, dwgBufferW *buf,
6578 std::uint32_t bs, dwgBufferW *strBuf,
6579 dwgBufferW *handleBuf) {
6580 (void)bs;
6581 oType = kDwgClassNum;
6582 if (!encodeDwgCommon(version, buf, strBuf))
6583 return false;
6584
6585 dwgBufferW *sb = strBuf ? strBuf : buf;
6586
6587 // AcDbMPolygon has a leading style field before the HATCH-like gradient
6588 // prologue. The same style is emitted again after the boundary data.
6589 buf->putBitShort(static_cast<std::uint16_t>(hstyle));
6590 encodeDwgGradientData(version, buf, sb);
6591
6592 buf->putBitDouble(basePoint.z);
6593 buf->put3BitDouble(extPoint);
6594 sb->putVariableText(version, name);
6595 buf->putBit(static_cast<std::uint8_t>(solid));
6596 buf->putBit(static_cast<std::uint8_t>(associative));
6597 if (!encodeDwgBoundaryData(version, buf)) return false;
6598
6599 buf->putBitShort(static_cast<std::uint16_t>(hstyle));
6600 buf->putBitShort(static_cast<std::uint16_t>(hpattern));
6601
6602 if (!solid) {
6603 buf->putBitDouble(angle);
6604 buf->putBitDouble(scale);
6605 buf->putBit(static_cast<std::uint8_t>(doubleflag));
6606 buf->putBitShort(static_cast<std::uint16_t>(patternLines.size()));
6607 for (const PatternLine& pl : patternLines) {
6608 buf->putBitDouble(pl.angle);
6609 buf->putBitDouble(pl.baseX);
6610 buf->putBitDouble(pl.baseY);
6611 buf->putBitDouble(pl.offsetX);
6612 buf->putBitDouble(pl.offsetY);
6613 buf->putBitShort(static_cast<std::uint16_t>(pl.dashList.size()));
6614 for (double dash : pl.dashList)
6615 buf->putBitDouble(dash);
6616 }
6617 }
6618
6619 buf->putCmColor(version,
6620 static_cast<std::uint16_t>(fillColorAci),
6621 fillColorRgb,
6622 fillColorName,
6623 {},
6624 sb);
6625 buf->put2RawDouble(DRW_Coord{xDirX, xDirY, 0.0});
6626 buf->putBitLong(degenerateLoops);
6627
6628 return encodeDwgEntHandle(version, buf, handleBuf);
6629}
6630
6631bool DRW_Hatch::parseDwgBoundaryData(DRW::Version version, dwgBuffer *buf,
6632 std::uint32_t &totalBoundItems, bool &havePixelSize) {
6633 loopsnum = buf->getBitLong();
6634 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);
6635 DRW_DBG(" loopsnum: ")DRW_dbg::dbg(" loopsnum: "); DRW_DBG(loopsnum)DRW_dbg::dbg(loopsnum); DRW_DBG("\n")DRW_dbg::dbg("\n");
6636
6637 //read loops
6638 for (std::int32_t i = 0 ; i < loopsnum; ++i){
6639 loop = std::make_shared<DRW_HatchLoop>(buf->getBitLong());
6640 havePixelSize = havePixelSize || ((loop->type & 4) != 0);
6641 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);
6642 if (!(loop->type & 2)){ //Not polyline
6643 std::int32_t numPathSeg = buf->getBitLong();
6644 DRW_DBG(" numPathSeg: ")DRW_dbg::dbg(" numPathSeg: "); DRW_DBG(numPathSeg)DRW_dbg::dbg(numPathSeg); DRW_DBG("\n")DRW_dbg::dbg("\n");
6645 for (std::int32_t j = 0; j<numPathSeg;++j){
6646 std::uint8_t typePath = buf->getRawChar8();
6647 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");
6648 if (typePath == 1){ //line
6649 addLine();
6650 line->basePoint = buf->get2RawDouble();
6651 line->secPoint = buf->get2RawDouble();
6652 } else if (typePath == 2){ //circle arc
6653 addArc();
6654 arc->basePoint = buf->get2RawDouble();
6655 arc->radious = buf->getBitDouble();
6656 arc->staangle = buf->getBitDouble();
6657 arc->endangle = buf->getBitDouble();
6658 arc->isccw = buf->getBit();
6659 } else if (typePath == 3){ //ellipse arc
6660 addEllipse();
6661 ellipse->basePoint = buf->get2RawDouble();
6662 ellipse->secPoint = buf->get2RawDouble();
6663 ellipse->ratio = buf->getBitDouble();
6664 ellipse->staparam = buf->getBitDouble();
6665 ellipse->endparam = buf->getBitDouble();
6666 ellipse->isccw = buf->getBit();
6667 } else if (typePath == 4){ //spline
6668 addSpline();
6669 spline->degree = buf->getBitLong();
6670 bool isRational = buf->getBit();
6671 spline->flags |= (isRational << 2); //rational
6672 spline->flags |= (buf->getBit() << 1); //periodic
6673 spline->nknots = buf->getBitLong();
6674 if (!DRW::reserve( spline->knotslist, spline->nknots)) {
6675 return false;
6676 }
6677 spline->ncontrol = buf->getBitLong();
6678 if (!DRW::reserve( spline->controllist, spline->ncontrol)) {
6679 return false;
6680 }
6681 for (std::int32_t j = 0; j < spline->nknots;++j){
6682 spline->knotslist.push_back (buf->getBitDouble());
6683 }
6684 for (std::int32_t j = 0; j < spline->ncontrol;++j){
6685 std::shared_ptr<DRW_Coord> crd = std::make_shared<DRW_Coord>(buf->get2RawDouble());
6686 if(isRational)
6687 crd->z = buf->getBitDouble(); //RLZ: investigate how store weight
6688 spline->controllist.push_back(crd);
6689 }
6690 if (version > DRW::AC1021) { //2010+
6691 spline->nfit = buf->getBitLong();
6692 // Fit points AND the start/end tangents are present only
6693 // when nfit > 0 (matches ACadSharp's `if (nfitPoints > 0)`).
6694 // Reading the two tangents unconditionally on an nfit==0
6695 // spline edge over-runs the entity body and fails the parse
6696 // (e.g. svg/export_sample.dwg: a degree-3 non-rational
6697 // spline boundary edge with 9 control points / 0 fit points).
6698 if (spline->nfit > 0) {
6699 if (!DRW::reserve( spline->fitlist, spline->nfit)) {
6700 return false;
6701 }
6702 for (std::int32_t j = 0; j < spline->nfit;++j){
6703 std::shared_ptr<DRW_Coord> crd = std::make_shared<DRW_Coord>(buf->get2RawDouble());
6704 spline->fitlist.push_back(crd);
6705 }
6706 spline->tgStart = buf->get2RawDouble();
6707 spline->tgEnd = buf->get2RawDouble();
6708 }
6709 }
6710 }
6711 }
6712 } else { //end not pline, start polyline
6713 pline = std::make_shared<DRW_LWPolyline>();
6714 bool asBulge = buf->getBit();
6715 pline->flags = buf->getBit();//closed bit
6716 std::int32_t numVert = buf->getBitLong();
6717 DRW_DBG(" asBulge: ")DRW_dbg::dbg(" asBulge: "); DRW_DBG(asBulge)DRW_dbg::dbg(asBulge); DRW_DBG(" closed: ")DRW_dbg::dbg(" closed: "); DRW_DBG(pline->flags)DRW_dbg::dbg(pline->flags);
6718 DRW_DBG(" numVert: ")DRW_dbg::dbg(" numVert: "); DRW_DBG(numVert)DRW_dbg::dbg(numVert); DRW_DBG("\n")DRW_dbg::dbg("\n");
6719 for (std::int32_t j = 0; j<numVert;++j){
6720 DRW_Vertex2D v;
6721 v.x = buf->getRawDouble();
6722 v.y = buf->getRawDouble();
6723 if (asBulge)
6724 v.bulge = buf->getBitDouble();
6725 pline->addVertex(v);
6726 }
6727 loop->objlist.push_back(pline);
6728 }//end polyline
6729 loop->update();
6730 looplist.push_back(loop);
6731 totalBoundItems += buf->getBitLong();
6732 DRW_DBG(" totalBoundItems: ")DRW_dbg::dbg(" totalBoundItems: "); DRW_DBG(totalBoundItems)DRW_dbg::dbg(totalBoundItems);
6733 } //end read loops
6734 return true;
6735}
6736
6737bool DRW_Hatch::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
6738 dwgBuffer sBuff = *buf;
6739 dwgBuffer *sBuf = buf;
6740 std::uint32_t totalBoundItems = 0;
6741 bool havePixelSize = false;
6742
6743 if (version > DRW::AC1018) {//2007+
6744 sBuf = &sBuff; //separate buffer for strings
6745 }
6746 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
6747 if (!ret)
6748 return ret;
6749 DRW_DBG("\n***************************** parsing hatch *********************************************\n")DRW_dbg::dbg("\n***************************** parsing hatch *********************************************\n"
)
;
6750
6751 //Gradient data, RLZ: is ok or if grad > 0 continue read ?
6752 if (version > DRW::AC1015) { //2004+
6753 isGradient = buf->getBitLong();
6754 DRW_DBG("is Gradient: ")DRW_dbg::dbg("is Gradient: "); DRW_DBG(isGradient)DRW_dbg::dbg(isGradient);
6755 gradReserved = buf->getBitLong();
6756 DRW_DBG(" reserved: ")DRW_dbg::dbg(" reserved: "); DRW_DBG(gradReserved)DRW_dbg::dbg(gradReserved);
6757 gradAngle = buf->getBitDouble();
6758 DRW_DBG(" Gradient angle: ")DRW_dbg::dbg(" Gradient angle: "); DRW_DBG(gradAngle)DRW_dbg::dbg(gradAngle);
6759 gradShift = buf->getBitDouble();
6760 DRW_DBG(" Gradient shift: ")DRW_dbg::dbg(" Gradient shift: "); DRW_DBG(gradShift)DRW_dbg::dbg(gradShift);
6761 singleColor = buf->getBitLong();
6762 DRW_DBG("\nsingle color Grad: ")DRW_dbg::dbg("\nsingle color Grad: "); DRW_DBG(singleColor)DRW_dbg::dbg(singleColor);
6763 gradTint = buf->getBitDouble();
6764 DRW_DBG(" Gradient tint: ")DRW_dbg::dbg(" Gradient tint: "); DRW_DBG(gradTint)DRW_dbg::dbg(gradTint);
6765 std::int32_t numCol = buf->getBitLong();
6766 DRW_DBG(" num colors: ")DRW_dbg::dbg(" num colors: "); DRW_DBG(numCol)DRW_dbg::dbg(numCol);
6767 if (numCol > 0)
6768 DRW::reserve(gradColors, numCol);
6769 for (std::int32_t i = 0 ; i < numCol; ++i){
6770 GradientStop stop;
6771 // First field is the stop position (per libreDWG: BD/unkDouble holds
6772 // the stop value in [0,1]); falls back to even spacing if missing.
6773 stop.value = buf->getBitDouble();
6774 DRW_DBG("\nstop value: ")DRW_dbg::dbg("\nstop value: "); DRW_DBG(stop.value)DRW_dbg::dbg(stop.value);
6775 std::uint16_t unkShort = buf->getBitShort();
6776 DRW_DBG(" unkShort: ")DRW_dbg::dbg(" unkShort: "); DRW_DBG(unkShort)DRW_dbg::dbg(unkShort);
6777 stop.rgb = buf->getBitLong();
6778 DRW_DBG(" rgb color: ")DRW_dbg::dbg(" rgb color: "); DRW_DBG(stop.rgb)DRW_dbg::dbg(stop.rgb);
6779 std::uint8_t ignCol = buf->getRawChar8();
6780 DRW_DBG(" ignored color: ")DRW_dbg::dbg(" ignored color: "); DRW_DBG(ignCol)DRW_dbg::dbg(ignCol);
6781 gradColors.push_back(stop);
6782 }
6783 gradName = sBuf->getVariableText(version, false);
6784 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");
6785 }
6786 basePoint.z = buf->getBitDouble();
6787 extPoint = buf->get3BitDouble();
6788 DRW_DBG("base point: ")DRW_dbg::dbg("base point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
6789 DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
6790 name = sBuf->getVariableText(version, false);
6791 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");
6792 solid = buf->getBit();
6793 associative = buf->getBit();
6794 if (!parseDwgBoundaryData(version, buf, totalBoundItems, havePixelSize))
6795 return false;
6796
6797 hstyle = buf->getBitShort();
6798 hpattern = buf->getBitShort();
6799 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);
6800 if (!solid){
6801 angle = buf->getBitDouble();
6802 scale = buf->getBitDouble();
6803 doubleflag = buf->getBit();
6804 deflines = buf->getBitShort();
6805 for (std::int32_t i = 0 ; i < deflines; ++i){
6806 DRW_Coord ptL, offL;
6807 double angleL = buf->getBitDouble();
6808 ptL.x = buf->getBitDouble();
6809 ptL.y = buf->getBitDouble();
6810 offL.x = buf->getBitDouble();
6811 offL.y = buf->getBitDouble();
6812 std::uint16_t numDashL = buf->getBitShort();
6813 DRW_DBG("\ndef line: ")DRW_dbg::dbg("\ndef line: "); DRW_DBG(angleL)DRW_dbg::dbg(angleL); DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(ptL.x)DRW_dbg::dbg(ptL.x); DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(ptL.y)DRW_dbg::dbg(ptL.y);
6814 DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(offL.x)DRW_dbg::dbg(offL.x); DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(offL.y)DRW_dbg::dbg(offL.y); DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(angleL)DRW_dbg::dbg(angleL);
6815 for (std::uint16_t i = 0 ; i < numDashL; ++i){
6816 double lengthL = buf->getBitDouble();
6817 DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(lengthL)DRW_dbg::dbg(lengthL);
6818 }
6819 }//end deflines
6820 } //end not solid
6821
6822 if (havePixelSize){
6823 double pixsize = buf->getBitDouble();
6824 DRW_DBG("\npixel size: ")DRW_dbg::dbg("\npixel size: "); DRW_DBG(pixsize)DRW_dbg::dbg(pixsize);
6825 }
6826 std::int32_t numSeedPoints = buf->getBitLong();
6827 DRW_DBG("\nnum Seed Points ")DRW_dbg::dbg("\nnum Seed Points "); DRW_DBG(numSeedPoints)DRW_dbg::dbg(numSeedPoints);
6828 if (numSeedPoints > 0)
6829 DRW::reserve(seedPoints, numSeedPoints);
6830 for (std::int32_t i = 0 ; i < numSeedPoints; ++i){
6831 DRW_Coord seedPt;
6832 seedPt.x = buf->getRawDouble();
6833 seedPt.y = buf->getRawDouble();
6834 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);
6835 seedPoints.push_back(seedPt);
6836 }
6837
6838 DRW_DBG("\n")DRW_dbg::dbg("\n");
6839 ret = DRW_Entity::parseDwgEntHandle(version, buf);
6840 if (!ret)
6841 return ret;
6842 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");
6843
6844 for (std::uint32_t i = 0 ; i < totalBoundItems; ++i){
6845 dwgHandle biH = buf->getHandle();
6846 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);
6847 }
6848 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");
6849// RS crc; //RS */
6850 return buf->isGood();
6851}
6852
6853void DRW_Hatch::encodeDwgGradientData(DRW::Version version, dwgBufferW *buf,
6854 dwgBufferW *strBuf) const {
6855 if (version <= DRW::AC1015)
7
Assuming 'version' is > AC1015
6856 return;
6857
6858 dwgBufferW *sb = strBuf ? strBuf : buf;
8
Taking false branch
9
Assuming 'strBuf' is null
10
'?' condition is false
6859 buf->putBitLong(isGradient);
11
Called C++ object pointer is null
6860 buf->putBitLong(gradReserved);
6861 buf->putBitDouble(gradAngle);
6862 buf->putBitDouble(gradShift);
6863 buf->putBitLong(singleColor);
6864 buf->putBitDouble(gradTint);
6865 buf->putBitLong(static_cast<std::int32_t>(gradColors.size()));
6866 for (const GradientStop& stop : gradColors) {
6867 buf->putBitDouble(stop.value);
6868 buf->putBitShort(static_cast<std::uint16_t>(stop.aciColor));
6869 buf->putBitLong(static_cast<std::uint32_t>(stop.rgb));
6870 buf->putRawChar8(0);
6871 }
6872 sb->putVariableText(version, gradName);
6873}
6874
6875bool DRW_Hatch::encodeDwgBoundaryData(DRW::Version version, dwgBufferW *buf) const {
6876 buf->putBitLong(static_cast<std::int32_t>(looplist.size()));
6877
6878 for (const auto& lp : looplist) {
6879 // Strip bit 4 (pixel-size flag): DRW_Hatch has no storage for the
6880 // associated pixelSize BD, so a reader would desync if the flag were
6881 // set and we then omitted the field.
6882 buf->putBitLong(lp->type & ~4);
6883
6884 if (!(lp->type & 2)) {
6885 buf->putBitLong(static_cast<std::int32_t>(lp->objlist.size()));
6886 for (const auto& seg : lp->objlist) {
6887 if (const auto* ln = dynamic_cast<const DRW_Line*>(seg.get())) {
6888 buf->putRawChar8(1); // line
6889 buf->put2RawDouble(ln->basePoint);
6890 buf->put2RawDouble(ln->secPoint);
6891 } else if (const auto* arc = dynamic_cast<const DRW_Arc*>(seg.get())) {
6892 buf->putRawChar8(2); // circular arc
6893 buf->put2RawDouble(arc->basePoint);
6894 buf->putBitDouble(arc->radious);
6895 buf->putBitDouble(arc->staangle);
6896 buf->putBitDouble(arc->endangle);
6897 buf->putBit(static_cast<std::uint8_t>(arc->isccw));
6898 } else if (const auto* el = dynamic_cast<const DRW_Ellipse*>(seg.get())) {
6899 buf->putRawChar8(3); // ellipse arc
6900 buf->put2RawDouble(el->basePoint);
6901 buf->put2RawDouble(el->secPoint);
6902 buf->putBitDouble(el->ratio);
6903 buf->putBitDouble(el->staparam);
6904 buf->putBitDouble(el->endparam);
6905 buf->putBit(static_cast<std::uint8_t>(el->isccw));
6906 } else if (const auto* sp = dynamic_cast<const DRW_Spline*>(seg.get())) {
6907 buf->putRawChar8(4); // spline
6908 buf->putBitLong(sp->degree);
6909 bool isRational = (sp->flags & 4) != 0;
6910 bool isPeriodic = (sp->flags & 2) != 0;
6911 buf->putBit(static_cast<std::uint8_t>(isRational));
6912 buf->putBit(static_cast<std::uint8_t>(isPeriodic));
6913 buf->putBitLong(static_cast<std::int32_t>(sp->knotslist.size()));
6914 buf->putBitLong(static_cast<std::int32_t>(sp->controllist.size()));
6915 for (double k : sp->knotslist)
6916 buf->putBitDouble(k);
6917 for (const auto& cp : sp->controllist) {
6918 DRW_Coord c2{cp->x, cp->y, 0.0};
6919 buf->put2RawDouble(c2);
6920 if (isRational)
6921 buf->putBitDouble(cp->z);
6922 }
6923 if (version > DRW::AC1021) {
6924 buf->putBitLong(static_cast<std::int32_t>(sp->fitlist.size()));
6925 for (const auto& fp : sp->fitlist) {
6926 DRW_Coord f2{fp->x, fp->y, 0.0};
6927 buf->put2RawDouble(f2);
6928 }
6929 buf->put2RawDouble(sp->tgStart);
6930 buf->put2RawDouble(sp->tgEnd);
6931 }
6932 } else {
6933 return false;
6934 }
6935 }
6936 } else {
6937 const DRW_LWPolyline* pl = nullptr;
6938 if (!lp->objlist.empty())
6939 pl = dynamic_cast<const DRW_LWPolyline*>(lp->objlist[0].get());
6940 if (!pl)
6941 return false;
6942
6943 bool asBulge = false;
6944 for (const auto& v : pl->vertlist)
6945 if (v->bulge != 0.0) { asBulge = true; break; }
6946
6947 buf->putBit(static_cast<std::uint8_t>(asBulge));
6948 buf->putBit(static_cast<std::uint8_t>(pl->flags & 1));
6949 buf->putBitLong(static_cast<std::int32_t>(pl->vertlist.size()));
6950 for (const auto& v : pl->vertlist) {
6951 buf->putRawDouble(v->x);
6952 buf->putRawDouble(v->y);
6953 if (asBulge)
6954 buf->putBitDouble(v->bulge);
6955 }
6956 }
6957
6958 buf->putBitLong(0); // numBoundHandles for this loop (0 = non-associative)
6959 }
6960
6961 return true;
6962}
6963
6964bool DRW_Hatch::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
6965 (void)bs;
6966 oType = 78; // HATCH class id — see dwgreader.cpp:1380
6967 if (!encodeDwgCommon(version, buf)) return false;
1
Assuming the condition is false
6968
6969 dwgBufferW *sb = strBuf ? strBuf : buf;
2
Taking false branch
3
Assuming 'strBuf' is null
4
'?' condition is false
6970 encodeDwgGradientData(version, buf, sb);
5
Passing 'sb' via 2nd parameter 'buf'
6
Calling 'DRW_Hatch::encodeDwgGradientData'
6971
6972 buf->putBitDouble(basePoint.z); // BD: elevation
6973 buf->put3BitDouble(extPoint); // 3BD: extrusion (NOT BE-style for HATCH)
6974 sb->putVariableText(version, name); // TV: hatch pattern name
6975 buf->putBit(static_cast<std::uint8_t>(solid));
6976 buf->putBit(static_cast<std::uint8_t>(associative));
6977 if (!encodeDwgBoundaryData(version, buf)) return false;
6978
6979 buf->putBitShort(static_cast<std::uint16_t>(hstyle));
6980 buf->putBitShort(static_cast<std::uint16_t>(hpattern));
6981
6982 if (!solid) {
6983 buf->putBitDouble(angle);
6984 buf->putBitDouble(scale);
6985 buf->putBit(static_cast<std::uint8_t>(doubleflag));
6986 // Pattern definition lines: the parseDwg reads them but DRW_Hatch
6987 // has no storage for per-line data, so emit 0 here.
6988 buf->putBitShort(0); // deflines = 0
6989 }
6990
6991 // pixelSize BD omitted: bit 4 is stripped from every emitted loop type
6992 // above (DRW_Hatch has no pixelSize storage), so havePixelSize is always
6993 // false on the read side and parseDwg never expects this field.
6994
6995 buf->putBitLong(static_cast<std::int32_t>(seedPoints.size()));
6996 for (const auto& sp : seedPoints) {
6997 buf->putRawDouble(sp.x);
6998 buf->putRawDouble(sp.y);
6999 }
7000
7001 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
7002 return true;
7003}
7004
7005bool DRW_Spline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7006 switch (code) {
7007 case 210:
7008 normalVec.x = reader->getDouble();
7009 break;
7010 case 220:
7011 normalVec.y = reader->getDouble();
7012 break;
7013 case 230:
7014 normalVec.z = reader->getDouble();
7015 break;
7016 case 12:
7017 tgStart.x = reader->getDouble();
7018 break;
7019 case 22:
7020 tgStart.y = reader->getDouble();
7021 break;
7022 case 32:
7023 tgStart.z = reader->getDouble();
7024 break;
7025 case 13:
7026 tgEnd.x = reader->getDouble();
7027 break;
7028 case 23:
7029 tgEnd.y = reader->getDouble();
7030 break;
7031 case 33:
7032 tgEnd.z = reader->getDouble();
7033 break;
7034 case 70:
7035 flags = reader->getInt32();
7036 break;
7037 case 71:
7038 degree = reader->getInt32();
7039 break;
7040 case 72:
7041 nknots = reader->getInt32();
7042 break;
7043 case 73:
7044 ncontrol = reader->getInt32();
7045 break;
7046 case 74:
7047 nfit = reader->getInt32();
7048 break;
7049 case 42:
7050 tolknot = reader->getDouble();
7051 break;
7052 case 43:
7053 tolcontrol = reader->getDouble();
7054 break;
7055 case 44:
7056 tolfit = reader->getDouble();
7057 break;
7058 case 10: {
7059 controlpoint = std::make_shared<DRW_Coord>();
7060 controllist.push_back(controlpoint);
7061 controlpoint->x = reader->getDouble();
7062 break; }
7063 case 20:
7064 if(controlpoint)
7065 controlpoint->y = reader->getDouble();
7066 break;
7067 case 30:
7068 if(controlpoint)
7069 controlpoint->z = reader->getDouble();
7070 break;
7071 case 11: {
7072 fitpoint = std::make_shared<DRW_Coord>();
7073 fitlist.push_back(fitpoint);
7074 fitpoint->x = reader->getDouble();
7075 break; }
7076 case 21:
7077 if(fitpoint)
7078 fitpoint->y = reader->getDouble();
7079 break;
7080 case 31:
7081 if(fitpoint)
7082 fitpoint->z = reader->getDouble();
7083 break;
7084 case 40:
7085 knotslist.push_back(reader->getDouble());
7086 break;
7087 case 41:
7088 weightlist.push_back(reader->getDouble());
7089 break;
7090 default:
7091 return DRW_Entity::parseCode(code, reader);
7092 }
7093
7094 return true;
7095}
7096
7097bool DRW_Helix::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7098 if (code == 100) {
7099 const std::string subclass = reader->getString();
7100 m_parsingHelixSubclass = (subclass == "AcDbHelix");
7101 return true;
7102 }
7103
7104 if (!m_parsingHelixSubclass)
7105 return DRW_Spline::parseCode(code, reader);
7106
7107 switch (code) {
7108 case 90:
7109 m_majorVersion = reader->getInt32();
7110 break;
7111 case 91:
7112 m_maintVersion = reader->getInt32();
7113 break;
7114 case 10:
7115 axisBasePt.x = reader->getDouble();
7116 break;
7117 case 20:
7118 axisBasePt.y = reader->getDouble();
7119 break;
7120 case 30:
7121 axisBasePt.z = reader->getDouble();
7122 break;
7123 case 11:
7124 startPt.x = reader->getDouble();
7125 break;
7126 case 21:
7127 startPt.y = reader->getDouble();
7128 break;
7129 case 31:
7130 startPt.z = reader->getDouble();
7131 break;
7132 case 12:
7133 axisVector.x = reader->getDouble();
7134 break;
7135 case 22:
7136 axisVector.y = reader->getDouble();
7137 break;
7138 case 32:
7139 axisVector.z = reader->getDouble();
7140 break;
7141 case 40:
7142 radius = reader->getDouble();
7143 break;
7144 case 41:
7145 turns = reader->getDouble();
7146 break;
7147 case 42:
7148 turnHeight = reader->getDouble();
7149 break;
7150 case 290:
7151 handedness = reader->getInt32() != 0;
7152 break;
7153 case 280:
7154 constraintType = static_cast<std::uint8_t>(reader->getInt32() & 0xff);
7155 break;
7156 default:
7157 return DRW_Entity::parseCode(code, reader);
7158 }
7159
7160 return true;
7161}
7162
7163bool DRW_Spline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
7164 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
7165 if (!ret)
7166 return ret;
7167 if (!parseDwgSplineBody(version, buf))
7168 return false;
7169 /* Common Entity Handle Data */
7170 ret = DRW_Entity::parseDwgEntHandle(version, buf);
7171 if (!ret)
7172 return ret;
7173// RS crc; //RS */
7174 return buf->isGood();
7175}
7176
7177// Spline body decode: the scenario/degree/knots/ctrl/fit section, WITHOUT
7178// the leading DRW_Entity::parseDwg(common) or the trailing parseDwgEntHandle.
7179// Factored out so DRW_Helix can reuse the identical spline payload before its
7180// AcDbHelix trailer (Phase 8a-1).
7181bool DRW_Spline::parseDwgSplineBody(DRW::Version version, dwgBuffer *buf){
7182 DRW_DBG("\n***************************** parsing spline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing spline *********************************************\n"
)
;
7183 std::uint8_t weight = 0; // RLZ ??? flags, weight, code 70, bit 4 (16)
7184
7185 std::int32_t scenario = buf->getBitLong();
7186 m_scenario = scenario;
7187 DRW_DBG("scenario: ")DRW_dbg::dbg("scenario: "); DRW_DBG(scenario)DRW_dbg::dbg(scenario);
7188 if (version > DRW::AC1024) {
7189 std::int32_t splFlag1 = buf->getBitLong();
7190 m_splineFlags1 = splFlag1;
7191 std::int32_t knotParam = buf->getBitLong();
7192 m_knotParam = knotParam;
7193 if (knotParam == kSplineKnotParamCustom || !(splFlag1 & kSplineFlagUseKnotParameter)) {
7194 scenario = 1;
7195 } else if (splFlag1 & kSplineFlagMethodFitPoints) {
7196 scenario = 2;
7197 }
7198 m_scenario = scenario;
7199 DRW_DBG(" 2013 splFlag1: ")DRW_dbg::dbg(" 2013 splFlag1: "); DRW_DBG(splFlag1)DRW_dbg::dbg(splFlag1);
7200 DRW_DBG(" 2013 knotParam: ")DRW_dbg::dbg(" 2013 knotParam: "); DRW_DBG(knotParam)DRW_dbg::dbg(knotParam);
7201// DRW_DBG("unk bit: "); DRW_DBG(buf->getBit());
7202 }
7203 degree = buf->getBitLong(); //RLZ: code 71, verify with dxf
7204 DRW_DBG(" degree: ")DRW_dbg::dbg(" degree: "); DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("\n")DRW_dbg::dbg("\n");
7205 if (!isValidSplineDegree(degree)) {
7206 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");
7207 return false;
7208 }
7209 if (scenario == 2) {
7210 flags = 8;//scenario 2 = not rational & planar
7211 if (m_splineFlags1 & kSplineFlagClosed)
7212 flags |= 1;
7213 tolfit = buf->getBitDouble();//BD
7214 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);
7215 tgStart =buf->get3BitDouble();
7216 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);
7217 tgEnd =buf->get3BitDouble();
7218 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);
7219 nfit = buf->getBitLong();
7220 if (!isValidFitSplineLayout(degree, nfit)) {
7221 DRW_DBG("\ndwg Spline, invalid fit layout degree/count: ")DRW_dbg::dbg("\ndwg Spline, invalid fit layout degree/count: "
)
;
7222 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");
7223 return false;
7224 }
7225 DRW_DBG("\nnumber of fit points: ")DRW_dbg::dbg("\nnumber of fit points: "); DRW_DBG(nfit)DRW_dbg::dbg(nfit);
7226 } else if (scenario == 1) {
7227 flags = 8;//scenario 1 = rational & planar
7228 flags |= buf->getBit() << 2; //flags, rational, code 70, bit 2 (4)
7229 flags |= buf->getBit(); //flags, closed, code 70, bit 0 (1)
7230 flags |= buf->getBit() << 1; //flags, periodic, code 70, bit 1 (2)
7231 tolknot = buf->getBitDouble();
7232 tolcontrol = buf->getBitDouble();
7233 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);
7234 DRW_DBG(" control point tolerance: ")DRW_dbg::dbg(" control point tolerance: "); DRW_DBG(tolcontrol)DRW_dbg::dbg(tolcontrol);
7235 nknots = buf->getBitLong();
7236 ncontrol = buf->getBitLong();
7237 if (!isValidControlSplineLayout(degree, nknots, ncontrol)) {
7238 DRW_DBG("\ndwg Spline, invalid control layout degree/knots/control: ")DRW_dbg::dbg("\ndwg Spline, invalid control layout degree/knots/control: "
)
;
7239 DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("/")DRW_dbg::dbg("/"); DRW_DBG(nknots)DRW_dbg::dbg(nknots); DRW_DBG("/")DRW_dbg::dbg("/");
7240 DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG("\n")DRW_dbg::dbg("\n");
7241 return false;
7242 }
7243 weight = buf->getBit(); // flags bit 4: weights present (code 70)
7244 if (weight) flags |= 0x10;
7245 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: ");
7246 DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG(" weight bit: ")DRW_dbg::dbg(" weight bit: "); DRW_DBG(weight)DRW_dbg::dbg(weight);
7247 } else {
7248 DRW_DBG("\ndwg Spline, unknown scenario ")DRW_dbg::dbg("\ndwg Spline, unknown scenario "); DRW_DBG(scenario)DRW_dbg::dbg(scenario);
7249 DRW_DBG(" (expected 1 or 2)\n")DRW_dbg::dbg(" (expected 1 or 2)\n");
7250 return false; //RLZ: from doc only 1 or 2 are ok ?
7251 }
7252
7253 if (!DRW::reserve( knotslist, nknots)) {
7254 return false;
7255 }
7256 for (std::int32_t i= 0; i<nknots; ++i){
7257 knotslist.push_back (buf->getBitDouble());
7258 }
7259 if (!DRW::reserve( controllist, ncontrol)) {
7260 return false;
7261 }
7262 if (weight && !DRW::reserve(weightlist, ncontrol)) {
7263 return false;
7264 }
7265 for (std::int32_t i= 0; i<ncontrol; ++i){
7266 controllist.push_back(std::make_shared<DRW_Coord>(buf->get3BitDouble()));
7267 if (weight) {
7268 //per-control-point weight; required for hyperbola/parabola
7269 //conic detection in consumers (e.g. LibreCAD addSpline)
7270 double w = buf->getBitDouble(); //RLZ Warning: D (BD or RD)
7271 weightlist.push_back(w);
7272 DRW_DBG("\n w: ")DRW_dbg::dbg("\n w: "); DRW_DBG(w)DRW_dbg::dbg(w);
7273 }
7274 }
7275 if (!DRW::reserve( fitlist, nfit)) {
7276 return false;
7277 }
7278 for (std::int32_t i= 0; i<nfit; ++i)
7279 fitlist.push_back(std::make_shared<DRW_Coord>(buf->get3BitDouble()));
7280
7281 if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug) {
7282 DRW_DBG("\nknots list: ")DRW_dbg::dbg("\nknots list: ");
7283 for (auto const& v: knotslist) {
7284 DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBG(v)DRW_dbg::dbg(v);
7285 }
7286 DRW_DBG("\ncontrol point list: ")DRW_dbg::dbg("\ncontrol point list: ");
7287 for (auto const& v: controllist) {
7288 DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z);
7289 }
7290 DRW_DBG("\nfit point list: ")DRW_dbg::dbg("\nfit point list: ");
7291 for (auto const& v: fitlist) {
7292 DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z);
7293 }
7294 }
7295
7296 return buf->isGood();
7297}
7298
7299// AcDbHelix trailer order (libreDWG dwg2.spec:2493-2503):
7300// major_version BL, maint_version BL, axis_base_pt 3BD, start_pt 3BD,
7301// axis_vector 3BD, radius BD, turns BD, turn_height BD, handedness B,
7302// constraint_type RC.
7303bool DRW_Helix::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
7304 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
7305 if (!ret)
7306 return ret;
7307 DRW_DBG("\n***************************** parsing helix *********************************************\n")DRW_dbg::dbg("\n***************************** parsing helix *********************************************\n"
)
;
7308 if (!parseDwgSplineBody(version, buf))
7309 return false;
7310
7311 // AcDbHelix trailer (see field order above).
7312 m_majorVersion = buf->getBitLong();
7313 m_maintVersion = buf->getBitLong();
7314 axisBasePt = buf->get3BitDouble();
7315 startPt = buf->get3BitDouble();
7316 axisVector = buf->get3BitDouble();
7317 radius = buf->getBitDouble();
7318 turns = buf->getBitDouble();
7319 turnHeight = buf->getBitDouble();
7320 handedness = buf->getBit() != 0;
7321 constraintType = buf->getRawChar8();
7322 DRW_DBG("\nhelix radius: ")DRW_dbg::dbg("\nhelix radius: "); DRW_DBG(radius)DRW_dbg::dbg(radius); DRW_DBG(" turns: ")DRW_dbg::dbg(" turns: "); DRW_DBG(turns)DRW_dbg::dbg(turns);
7323
7324 /* Common Entity Handle Data */
7325 ret = DRW_Entity::parseDwgEntHandle(version, buf);
7326 if (!ret)
7327 return ret;
7328// RS crc; //RS */
7329 return buf->isGood();
7330}
7331
7332bool DRW_Image::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7333 switch (code) {
7334 case 12:
7335 vVector.x = reader->getDouble();
7336 break;
7337 case 22:
7338 vVector.y = reader->getDouble();
7339 break;
7340 case 32:
7341 vVector.z = reader->getDouble();
7342 break;
7343 case 13:
7344 sizeu = reader->getDouble();
7345 break;
7346 case 23:
7347 sizev = reader->getDouble();
7348 break;
7349 case 340:
7350 ref = reader->getHandleString();
7351 break;
7352 case 280:
7353 clip = reader->getInt32();
7354 break;
7355 case 281:
7356 brightness = reader->getInt32();
7357 break;
7358 case 282:
7359 contrast = reader->getInt32();
7360 break;
7361 case 283:
7362 fade = reader->getInt32();
7363 break;
7364 case 71:
7365 m_clipBoundaryType = reader->getInt32();
7366 break;
7367 case 91:
7368 // WIPEOUT: number of polygon vertices. We don't pre-size — the count
7369 // is informational and the 14/24 pairs follow in order.
7370 clipPath.clear();
7371 clipPath.reserve(static_cast<size_t>(reader->getInt32()));
7372 break;
7373 case 14:
7374 // WIPEOUT polygon vertex x — start a new vertex. Group 24 (y) follows.
7375 clipPath.emplace_back(reader->getDouble(), 0.0);
7376 break;
7377 case 24:
7378 // WIPEOUT polygon vertex y — complete the most recently started vertex.
7379 if (!clipPath.empty()) {
7380 clipPath.back().y = reader->getDouble();
7381 }
7382 break;
7383 case 290:
7384 // R2010+ Clip mode (IMAGE/WIPEOUT, ODA spec §20.4.80):
7385 // 0 = mask outside the polygon, 1 = mask inside.
7386 clipMode = reader->getBool();
7387 break;
7388 default:
7389 return DRW_Line::parseCode(code, reader);
7390 }
7391
7392 return true;
7393}
7394
7395bool DRW_Image::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
7396 dwgBuffer sBuff = *buf;
7397 dwgBuffer *sBuf = buf;
7398 if (version > DRW::AC1018) {//2007+
7399 sBuf = &sBuff; //separate buffer for strings
7400 }
7401 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
7402 if (!ret)
7403 return ret;
7404 DRW_DBG("\n***************************** parsing image *********************************************\n")DRW_dbg::dbg("\n***************************** parsing image *********************************************\n"
)
;
7405
7406 std::int32_t classVersion = buf->getBitLong();
7407 DRW_DBG("class Version: ")DRW_dbg::dbg("class Version: "); DRW_DBG(classVersion)DRW_dbg::dbg(classVersion);
7408 basePoint = buf->get3BitDouble();
7409 DRW_DBG("\nbase point: ")DRW_dbg::dbg("\nbase point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
7410 secPoint = buf->get3BitDouble();
7411 DRW_DBG("\nU vector: ")DRW_dbg::dbg("\nU vector: "); DRW_DBGPT(secPoint.x, secPoint.y, secPoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, secPoint.z);
7412 vVector = buf->get3BitDouble();
7413 DRW_DBG("\nV vector: ")DRW_dbg::dbg("\nV vector: "); DRW_DBGPT(vVector.x, vVector.y, vVector.z)DRW_dbg::dbgPT(vVector.x, vVector.y, vVector.z);
7414 sizeu = buf->getRawDouble();
7415 sizev = buf->getRawDouble();
7416 DRW_DBG("\nsize U: ")DRW_dbg::dbg("\nsize U: "); DRW_DBG(sizeu)DRW_dbg::dbg(sizeu); DRW_DBG("\nsize V: ")DRW_dbg::dbg("\nsize V: "); DRW_DBG(sizev)DRW_dbg::dbg(sizev);
7417 m_displayProps = buf->getBitShort();
7418 DRW_DBG("\ndisplay props: ")DRW_dbg::dbg("\ndisplay props: "); DRW_DBG(m_displayProps)DRW_dbg::dbg(m_displayProps);
7419 clip = buf->getBit();
7420 brightness = buf->getRawChar8();
7421 contrast = buf->getRawChar8();
7422 fade = buf->getRawChar8();
7423 if (version > DRW::AC1021){ //2010+
7424 clipMode = buf->getBit() != 0; // ODA §20.4.80: Clip mode B (R2010+)
7425 }
7426 m_clipBoundaryType = buf->getBitShort();
7427 clipPath.clear();
7428 if (m_clipBoundaryType == 0) {
7429 // No clip boundary payload.
7430 } else if (m_clipBoundaryType == 1){
7431 // rectangular clip: lower-left and upper-right corners; expand to a
7432 // 4-vertex polygon so downstream consumers can treat both kinds uniformly.
7433 DRW_Coord ll = buf->get2RawDouble();
7434 DRW_Coord ur = buf->get2RawDouble();
7435 clipPath.push_back(ll);
7436 clipPath.push_back(DRW_Coord(ur.x, ll.y, 0.0));
7437 clipPath.push_back(ur);
7438 clipPath.push_back(DRW_Coord(ll.x, ur.y, 0.0));
7439 } else if (m_clipBoundaryType == 2) {
7440 std::int32_t numVerts = buf->getBitLong();
7441 if (numVerts < 0 || numVerts > 100000)
7442 return false;
7443 clipPath.reserve(numVerts);
7444 for (int i= 0; i< numVerts;++i)
7445 clipPath.push_back(buf->get2RawDouble());
7446 } else {
7447 DRW_DBG("unsupported image clip type: ")DRW_dbg::dbg("unsupported image clip type: "); DRW_DBG(m_clipBoundaryType)DRW_dbg::dbg(m_clipBoundaryType); DRW_DBG("\n")DRW_dbg::dbg("\n");
7448 return false;
7449 }
7450
7451 ret = DRW_Entity::parseDwgEntHandle(version, buf);
7452 if (!ret)
7453 return ret;
7454 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");
7455
7456 dwgHandle biH = buf->getHandle();
7457 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);
7458 ref = biH.ref;
7459 biH = buf->getHandle();
7460 DRW_DBG("ImageDefReactor Handle: ")DRW_dbg::dbg("ImageDefReactor Handle: "); DRW_DBGHL(biH.code, biH.size, biH.ref)DRW_dbg::dbgHL(biH.code, biH.size, biH.ref);
7461 m_imageDefReactorHandle = biH.ref;
7462 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");
7463// RS crc; //RS */
7464 return buf->isGood();
7465}
7466
7467// DRW_Image::encodeDwg — inverse of DRW_Image::parseDwg above (libreDWG
7468// dwg.spec:5533-5563). Body field order: BL class_version (0), 3 x 3BD
7469// (base/uvec/vvec), 2 x RD (sizeu/sizev), BS display_props, B clip,
7470// 3 x RC (brightness/contrast/fade), [R2010+ B clip_mode], BS
7471// clip_boundary_type + verts. Both handles (imagedef code 5 + reactor
7472// code 3) are emitted UNCONDITIONALLY at the END of the handle stream,
7473// matching parseDwg's order — NOT the spec's interleaved mid-stream slots.
7474bool DRW_Image::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7475 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7476 (void)bs; (void)strBuf;
7477 oType = 101; // IMAGE class id — see dwgreader.cpp case 101
7478 if (!encodeDwgCommon(version, buf)) return false;
7479
7480 buf->putBitLong(0); // class_version (reader discards; ODA emits 0)
7481 buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z);
7482 buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z); // uvec
7483 buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z);
7484 buf->putRawDouble(sizeu);
7485 buf->putRawDouble(sizev);
7486 buf->putBitShort(static_cast<std::uint16_t>(m_displayProps));
7487 buf->putBit(static_cast<std::uint8_t>(clip & 1));
7488 buf->putRawChar8(static_cast<std::uint8_t>(brightness));
7489 buf->putRawChar8(static_cast<std::uint8_t>(contrast));
7490 buf->putRawChar8(static_cast<std::uint8_t>(fade));
7491 if (version > DRW::AC1021) { // 2010+ clip mode
7492 buf->putBit(clipMode ? 1 : 0);
7493 }
7494 if (clipPath.empty()) {
7495 buf->putBitShort(0); // clip_boundary_type 0 = none
7496 } else {
7497 // Always emit polygon type 2 — reader expands a stored rect (type 1)
7498 // into a 4-vertex polygon, so re-emit it as a polygon, never type 1.
7499 buf->putBitShort(2);
7500 // Clamp to the count parseDwg accepts (it rejects clipType==2 with
7501 // numVerts > 100000, dropping the entity on re-read). The DXF parseCode
7502 // path (code 91) has no such bound, so a DXF-sourced clip can exceed it;
7503 // cap on encode and emit exactly that many vertices. Compute the min on
7504 // size_t (NOT a pre-cast int32) so an enormous size cannot wrap negative.
7505 constexpr std::size_t kMaxClipVerts = 100000u;
7506 const std::size_t emitVerts = std::min(clipPath.size(), kMaxClipVerts);
7507 if (clipPath.size() > kMaxClipVerts) {
7508 DRW_DBG("IMAGE clip vertices truncated to 100000 (was ")DRW_dbg::dbg("IMAGE clip vertices truncated to 100000 (was ");
7509 DRW_DBG(static_cast<int>(clipPath.size()))DRW_dbg::dbg(static_cast<int>(clipPath.size())); DRW_DBG(")\n")DRW_dbg::dbg(")\n");
7510 }
7511 buf->putBitLong(static_cast<std::int32_t>(emitVerts));
7512 for (std::size_t i = 0; i < emitVerts; ++i)
7513 buf->put2RawDouble(clipPath[i]);
7514 }
7515
7516 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
7517
7518 // Emit both trailing handles UNCONDITIONALLY in parseDwg order:
7519 // imagedef (hard pointer, code 5) then imagedefreactor (hard owner, code 3).
7520 dwgBufferW *hb = handleBuf ? handleBuf : buf;
7521 auto makeHandle = [](std::uint8_t code, std::uint32_t r) {
7522 dwgHandle h;
7523 h.code = (r == 0) ? 0 : code;
7524 h.ref = r;
7525 h.size = 0;
7526 if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } }
7527 return h;
7528 };
7529 hb->putHandle(makeHandle(5, ref)); // imagedef (340)
7530 hb->putHandle(makeHandle(3, m_imageDefReactorHandle)); // imagedefreactor (360)
7531 return true;
7532}
7533
7534bool DRW_Wipeout::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7535 return DRW_Image::parseCode(code, reader);
7536}
7537
7538bool DRW_Wipeout::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7539 return DRW_Image::parseDwg(version, buf, bs);
7540}
7541
7542bool DRW_Wipeout::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7543 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7544 (void)bs; (void)strBuf;
7545 oType = 1109;
7546 if (!encodeDwgCommon(version, buf)) return false;
7547
7548 buf->putBitLong(0);
7549 buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z);
7550 buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z);
7551 buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z);
7552 buf->putRawDouble(sizeu);
7553 buf->putRawDouble(sizev);
7554 buf->putBitShort(static_cast<std::uint16_t>(m_displayProps));
7555 buf->putBit(static_cast<std::uint8_t>(clip & 1));
7556 buf->putRawChar8(static_cast<std::uint8_t>(brightness));
7557 buf->putRawChar8(static_cast<std::uint8_t>(contrast));
7558 buf->putRawChar8(static_cast<std::uint8_t>(fade));
7559 if (version > DRW::AC1021) {
7560 buf->putBit(clipMode ? 1 : 0);
7561 }
7562 if (clipPath.empty()) {
7563 buf->putBitShort(0);
7564 } else {
7565 buf->putBitShort(2);
7566 constexpr std::size_t kMaxClipVerts = 100000u;
7567 const std::size_t emitVerts = std::min(clipPath.size(), kMaxClipVerts);
7568 if (clipPath.size() > kMaxClipVerts) {
7569 DRW_DBG("WIPEOUT clip vertices truncated to 100000 (was ")DRW_dbg::dbg("WIPEOUT clip vertices truncated to 100000 (was "
)
;
7570 DRW_DBG(static_cast<int>(clipPath.size()))DRW_dbg::dbg(static_cast<int>(clipPath.size())); DRW_DBG(")\n")DRW_dbg::dbg(")\n");
7571 }
7572 buf->putBitLong(static_cast<std::int32_t>(emitVerts));
7573 for (std::size_t i = 0; i < emitVerts; ++i)
7574 buf->put2RawDouble(clipPath[i]);
7575 }
7576
7577 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
7578
7579 dwgBufferW *hb = handleBuf ? handleBuf : buf;
7580 auto makeHandle = [](std::uint8_t code, std::uint32_t r) {
7581 dwgHandle h;
7582 h.code = (r == 0) ? 0 : code;
7583 h.ref = r;
7584 h.size = 0;
7585 if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } }
7586 return h;
7587 };
7588 hb->putHandle(makeHandle(5, ref));
7589 hb->putHandle(makeHandle(3, m_imageDefReactorHandle));
7590 return true;
7591}
7592
7593bool DRW_PointCloud::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7594 switch (code) {
7595 case 90: classVersion = reader->getInt32(); break;
7596 case 10: origin.x = reader->getDouble(); break;
7597 case 20: origin.y = reader->getDouble(); break;
7598 case 30: origin.z = reader->getDouble(); break;
7599 case 1: savedFilename = reader->getUtf8String(); break;
7600 case 91: sourceFileCount = reader->getInt32(); break;
7601 case 101:
7602 sourceFiles.clear();
7603 sourceFiles.reserve(static_cast<size_t>(sourceFileCount));
7604 break;
7605 case 300:
7606 if (sourceFiles.size() < static_cast<size_t>(sourceFileCount)) {
7607 sourceFiles.push_back(reader->getUtf8String());
7608 }
7609 break;
7610 case 11: extentsMin.x = reader->getDouble(); break;
7611 case 21: extentsMin.y = reader->getDouble(); break;
7612 case 31: extentsMin.z = reader->getDouble(); break;
7613 case 12: extentsMax.x = reader->getDouble(); break;
7614 case 22: extentsMax.y = reader->getDouble(); break;
7615 case 32: extentsMax.z = reader->getDouble(); break;
7616 case 92: pointCount = reader->getInt64(); break;
7617 case 2: ucsName = reader->getUtf8String(); break;
7618 case 13: ucsOrigin.x = reader->getDouble(); break;
7619 case 23: ucsOrigin.y = reader->getDouble(); break;
7620 case 33: ucsOrigin.z = reader->getDouble(); break;
7621 case 14: ucsXDirection.x = reader->getDouble(); break;
7622 case 24: ucsXDirection.y = reader->getDouble(); break;
7623 case 34: ucsXDirection.z = reader->getDouble(); break;
7624 case 15: ucsYDirection.x = reader->getDouble(); break;
7625 case 25: ucsYDirection.y = reader->getDouble(); break;
7626 case 35: ucsYDirection.z = reader->getDouble(); break;
7627 case 16: ucsZDirection.x = reader->getDouble(); break;
7628 case 26: ucsZDirection.y = reader->getDouble(); break;
7629 case 36: ucsZDirection.z = reader->getDouble(); break;
7630 case 340: definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7631 case 360: reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7632 case 290: showIntensity = reader->getBool(); break;
7633 case 280: intensityScheme = reader->getInt32(); break;
7634 case 441: intensityStyle.minIntensity = reader->getDouble(); break;
7635 case 442: intensityStyle.maxIntensity = reader->getDouble(); break;
7636 case 443: intensityStyle.lowThreshold = reader->getDouble(); break;
7637 case 444: intensityStyle.highThreshold = reader->getDouble(); break;
7638 case 291: showClipping = reader->getBool(); break;
7639 case 93: clippingCount = reader->getInt32(); break;
7640 default:
7641 return DRW_Entity::parseCode(code, reader);
7642 }
7643 return true;
7644}
7645
7646bool DRW_PointCloud::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7647 return DRW_Entity::parseDwg(version, buf, nullptr, bs);
7648}
7649
7650bool DRW_PointCloud::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7651 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7652 (void)bs; (void)strBuf; (void)handleBuf;
7653 oType = 1157;
7654 return encodeDwgCommon(version, buf);
7655}
7656
7657bool DRW_PointCloudEx::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7658 switch (code) {
7659 case 90: classVersion = reader->getInt32(); break;
7660 case 11: extentsMin.x = reader->getDouble(); break;
7661 case 21: extentsMin.y = reader->getDouble(); break;
7662 case 31: extentsMin.z = reader->getDouble(); break;
7663 case 12: extentsMax.x = reader->getDouble(); break;
7664 case 22: extentsMax.y = reader->getDouble(); break;
7665 case 32: extentsMax.z = reader->getDouble(); break;
7666 case 13: ucsOrigin.x = reader->getDouble(); break;
7667 case 23: ucsOrigin.y = reader->getDouble(); break;
7668 case 33: ucsOrigin.z = reader->getDouble(); break;
7669 case 14: ucsXDirection.x = reader->getDouble(); break;
7670 case 24: ucsXDirection.y = reader->getDouble(); break;
7671 case 34: ucsXDirection.z = reader->getDouble(); break;
7672 case 15: ucsYDirection.x = reader->getDouble(); break;
7673 case 25: ucsYDirection.y = reader->getDouble(); break;
7674 case 35: ucsYDirection.z = reader->getDouble(); break;
7675 case 16: ucsZDirection.x = reader->getDouble(); break;
7676 case 26: ucsZDirection.y = reader->getDouble(); break;
7677 case 36: ucsZDirection.z = reader->getDouble(); break;
7678 case 290: isLocked = reader->getBool(); break;
7679 case 340: definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7680 case 360: reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7681 case 1: name = reader->getUtf8String(); break;
7682 case 291: showIntensity = reader->getBool(); break;
7683 case 292: showCropping = reader->getBool(); break;
7684 case 91: croppingCount = reader->getInt32(); break;
7685 case 92: unknownInt0 = reader->getInt32(); break;
7686 case 93: unknownInt1 = reader->getInt32(); break;
7687 case 280: stylizationType = reader->getInt32(); break;
7688 case 300: intensityColorScheme = reader->getUtf8String(); break;
7689 case 301: currentColorScheme = reader->getUtf8String(); break;
7690 case 302: classificationColorScheme = reader->getUtf8String(); break;
7691 case 440: elevationMin = reader->getDouble(); break;
7692 case 441: elevationMax = reader->getDouble(); break;
7693 case 442: intensityMin = reader->getDouble(); break;
7694 case 443: intensityMax = reader->getDouble(); break;
7695 case 281: intensityOutOfRangeBehavior = reader->getInt32(); break;
7696 case 282: elevationOutOfRangeBehavior = reader->getInt32(); break;
7697 case 293: elevationApplyToFixedRange = reader->getBool(); break;
7698 case 294: intensityAsGradient = reader->getBool(); break;
7699 case 295: elevationAsGradient = reader->getBool(); break;
7700 default:
7701 return DRW_Entity::parseCode(code, reader);
7702 }
7703 return true;
7704}
7705
7706bool DRW_PointCloudEx::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7707 return DRW_Entity::parseDwg(version, buf, nullptr, bs);
7708}
7709
7710bool DRW_PointCloudEx::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7711 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7712 (void)bs; (void)strBuf; (void)handleBuf;
7713 oType = 1158;
7714 return encodeDwgCommon(version, buf);
7715}
7716
7717bool DRW_Surface::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7718 switch (code) {
7719 case 70:
7720 modelerFormatVersion = reader->getInt32();
7721 break;
7722 case 71:
7723 uIsolines = reader->getInt32();
7724 break;
7725 case 72:
7726 vIsolines = reader->getInt32();
7727 break;
7728 case 310:
7729 {
7730 std::vector<std::uint8_t> decoded;
7731 if (!decodeHexBytes(reader->getString(), decoded))
7732 return false;
7733 appendBytes(rawAcisData, decoded);
7734 }
7735 break;
7736 default:
7737 return DRW_Entity::parseCode(code, reader);
7738 }
7739 return true;
7740}
7741
7742bool DRW_Surface::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7743 return DRW_Entity::parseDwg(version, buf, nullptr, bs);
7744}
7745
7746bool DRW_Surface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7747 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7748 (void)bs; (void)strBuf; (void)handleBuf;
7749 return encodeDwgCommon(version, buf);
7750}
7751
7752bool DRW_Dimension::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7753 switch (code) {
7754 case 1:
7755 text = reader->getUtf8String();
7756 break;
7757 case 2:
7758 name = reader->getString();
7759 break;
7760 case 3:
7761 style = reader->getUtf8String();
7762 break;
7763 case 70:
7764 type = reader->getInt32();
7765 break;
7766 case 71:
7767 align = reader->getInt32();
7768 break;
7769 case 72:
7770 linesty = reader->getInt32();
7771 break;
7772 case 10:
7773 defPoint.x = reader->getDouble();
7774 break;
7775 case 20:
7776 defPoint.y = reader->getDouble();
7777 break;
7778 case 30:
7779 defPoint.z = reader->getDouble();
7780 break;
7781 case 11:
7782 textPoint.x = reader->getDouble();
7783 break;
7784 case 21:
7785 textPoint.y = reader->getDouble();
7786 break;
7787 case 31:
7788 textPoint.z = reader->getDouble();
7789 break;
7790 case 12:
7791 clonePoint.x = reader->getDouble();
7792 break;
7793 case 22:
7794 clonePoint.y = reader->getDouble();
7795 break;
7796 case 32:
7797 clonePoint.z = reader->getDouble();
7798 break;
7799 case 13:
7800 def1.x = reader->getDouble();
7801 break;
7802 case 23:
7803 def1.y = reader->getDouble();
7804 break;
7805 case 33:
7806 def1.z = reader->getDouble();
7807 break;
7808 case 14:
7809 def2.x = reader->getDouble();
7810 break;
7811 case 24:
7812 def2.y = reader->getDouble();
7813 break;
7814 case 34:
7815 def2.z = reader->getDouble();
7816 break;
7817 case 15:
7818 circlePoint.x = reader->getDouble();
7819 break;
7820 case 25:
7821 circlePoint.y = reader->getDouble();
7822 break;
7823 case 35:
7824 circlePoint.z = reader->getDouble();
7825 break;
7826 case 16:
7827 arcPoint.x = reader->getDouble();
7828 break;
7829 case 26:
7830 arcPoint.y = reader->getDouble();
7831 break;
7832 case 36:
7833 arcPoint.z = reader->getDouble();
7834 break;
7835 case 41:
7836 linefactor = reader->getDouble();
7837 break;
7838 case 53:
7839 rot = reader->getDouble();
7840 break;
7841 case 50:
7842 angle = reader->getDouble();
7843 break;
7844 case 52:
7845 oblique = reader->getDouble();
7846 break;
7847 case 40:
7848 length = reader->getDouble();
7849 break;
7850 case 51:
7851 hdir = reader->getDouble();
7852 break;
7853 case 42:
7854 measureValue = reader->getDouble();
7855 break;
7856 case 74:
7857 flipArrow1 = reader->getInt32() != 0;
7858 break;
7859 case 75:
7860 flipArrow2 = reader->getInt32() != 0;
7861 break;
7862 case 76:
7863 genTol = reader->getInt32() != 0;
7864 break;
7865 case 77:
7866 limGen = reader->getInt32() != 0;
7867 break;
7868 case 43:
7869 tolPlus = reader->getDouble();
7870 break;
7871 case 44:
7872 tolMinus = reader->getDouble();
7873 break;
7874 case 45:
7875 tolScale = reader->getDouble();
7876 break;
7877 case 78:
7878 tolDecimals = reader->getInt32();
7879 break;
7880 case 79:
7881 tolAlign = reader->getInt32();
7882 break;
7883 case 80:
7884 tolZero = reader->getInt32();
7885 break;
7886 case 81:
7887 altTolDecimals = reader->getInt32();
7888 break;
7889 case 82:
7890 altZero = reader->getInt32();
7891 break;
7892 case 83:
7893 altTolZero = reader->getInt32();
7894 break;
7895 case 84:
7896 textMove = reader->getInt32();
7897 break;
7898 default:
7899 return DRW_Entity::parseCode(code, reader);
7900 }
7901
7902 return true;
7903}
7904
7905bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs)
7906{
7907 DRW_UNUSED( version)(void)version;
7908 DRW_UNUSED( buf)(void)buf;
7909 DRW_UNUSED( bs)(void)bs;
7910
7911 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"
)
;
7912
7913 return false;
7914}
7915
7916bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, std::uint32_t bs /*= 0*/) {
7917 dwgBuffer sBuff = *buf;
7918 sBuf = buf;
7919 if (version > DRW::AC1018) {//2007+
7920 sBuf = &sBuff; //separate buffer for strings
7921 }
7922
7923 if (!DRW_Entity::parseDwg( version, buf, sBuf, bs)) {
7924 return false;
7925 }
7926
7927 DRW_DBG("\n***************************** parsing dimension *********************************************")DRW_dbg::dbg("\n***************************** parsing dimension *********************************************"
)
;
7928 if (version > DRW::AC1021) { //2010+
7929 std::uint8_t dimVersion = buf->getRawChar8();
7930 DRW_DBG("\ndimVersion: ")DRW_dbg::dbg("\ndimVersion: "); DRW_DBG(dimVersion)DRW_dbg::dbg(dimVersion);
7931 }
7932 // ODA §20.4.22: Extrusion is plain 3BD (NOT BE) — confirmed by libreDWG dwg_spec_shared.h
7933 extPoint = buf->get3BitDouble();
7934 DRW_DBG("\nextPoint: ")DRW_dbg::dbg("\nextPoint: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
7935 textPoint.x = buf->getRawDouble();
7936 textPoint.y = buf->getRawDouble();
7937 textPoint.z = buf->getBitDouble();
7938 DRW_DBG("\ntextPoint: ")DRW_dbg::dbg("\ntextPoint: "); DRW_DBGPT(textPoint.x, textPoint.y, textPoint.z)DRW_dbg::dbgPT(textPoint.x, textPoint.y, textPoint.z);
7939 type = buf->getRawChar8();
7940 DRW_DBG("\ntype (70) read: ")DRW_dbg::dbg("\ntype (70) read: "); DRW_DBG(type)DRW_dbg::dbg(type);
7941 type = (type & 1) ? type & 0x7F : type | 0x80; //set bit 7
7942 type = (type & 2) ? type | 0x20 : type & 0xDF; //set bit 5
7943 DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(type)DRW_dbg::dbg(type);
7944 //clear last 3 bits to set integer dim type
7945 type &= 0xF8;
7946 text = sBuf->getVariableText(version, false);
7947 DRW_DBG("\nforced dim text: ")DRW_dbg::dbg("\nforced dim text: "); DRW_DBG(text.c_str())DRW_dbg::dbg(text.c_str());
7948 rot = buf->getBitDouble();
7949 hdir = buf->getBitDouble();
7950 DRW_Coord inspoint = buf->get3BitDouble();
7951 DRW_DBG("\ninspoint: ")DRW_dbg::dbg("\ninspoint: "); DRW_DBGPT(inspoint.x, inspoint.y, inspoint.z)DRW_dbg::dbgPT(inspoint.x, inspoint.y, inspoint.z);
7952 double insRot_code54 = buf->getBitDouble(); //RLZ: unknown, investigate
7953 DRW_DBG(" insRot_code54: ")DRW_dbg::dbg(" insRot_code54: "); DRW_DBG(insRot_code54)DRW_dbg::dbg(insRot_code54);
7954 if (version > DRW::AC1014) { //2000+
7955 align = buf->getBitShort();
7956 linesty = buf->getBitShort();
7957 linefactor = buf->getBitDouble();
7958 measureValue = buf->getBitDouble();
7959 DRW_DBG("\n actMeas_code42: ")DRW_dbg::dbg("\n actMeas_code42: "); DRW_DBG(measureValue)DRW_dbg::dbg(measureValue);
7960 if (version > DRW::AC1018) { //2007+
7961 bool unk = buf->getBit();
7962 flipArrow1 = buf->getBit();
7963 flipArrow2 = buf->getBit();
7964 DRW_DBG("\n2007, unk, flip1, flip2: ")DRW_dbg::dbg("\n2007, unk, flip1, flip2: "); DRW_DBG(unk)DRW_dbg::dbg(unk); DRW_DBG(flipArrow1)DRW_dbg::dbg(flipArrow1); DRW_DBG(flipArrow2)DRW_dbg::dbg(flipArrow2);
7965 }
7966 }
7967 clonePoint.x = buf->getRawDouble();
7968 clonePoint.y = buf->getRawDouble();
7969 DRW_DBG("\nclonePoint: ")DRW_dbg::dbg("\nclonePoint: "); DRW_DBGPT(clonePoint.x, clonePoint.y, clonePoint.z)DRW_dbg::dbgPT(clonePoint.x, clonePoint.y, clonePoint.z);
7970
7971 return buf->isGood();
7972}
7973
7974bool DRW_DimAligned::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
7975 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
7976 return false;
7977 }
7978
7979 if (oType == 0x15)
7980 DRW_DBG("\n***************************** parsing dim linear *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim linear *********************************************\n"
)
;
7981 else
7982 DRW_DBG("\n***************************** parsing dim aligned *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim aligned *********************************************\n"
)
;
7983 DRW_Coord pt = buf->get3BitDouble();
7984 setPt3(pt); //def1
7985 DRW_DBG("def1: ")DRW_dbg::dbg("def1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
7986 pt = buf->get3BitDouble();
7987 setPt4(pt);
7988 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
7989 pt = buf->get3BitDouble();
7990 setDefPoint(pt);
7991 DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
7992 setOb52(buf->getBitDouble() * ARAD57.29577951308232); // radians → degrees
7993 if (oType == 0x15)
7994 setAn50(buf->getBitDouble() * ARAD57.29577951308232);
7995 else
7996 type |= 1;
7997 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");
7998
7999 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8000 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n"
)
;
8001 return false;
8002 }
8003 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");
8004 dimStyleH = buf->getHandle();
8005 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8006 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8007 DRW_DBG("anon block Handle: ")DRW_dbg::dbg("anon block Handle: "); DRW_DBGHL(blockH.code, blockH.size, blockH.ref)DRW_dbg::dbgHL(blockH.code, blockH.size, blockH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8008 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");
8009
8010 // RS crc; //RS */
8011 return buf->isGood();
8012 }
8013
8014bool DRW_DimRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8015 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8016 return false;
8017 }
8018
8019 DRW_DBG("\n***************************** parsing dim radial *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim radial *********************************************\n"
)
;
8020 DRW_Coord pt = buf->get3BitDouble();
8021 setDefPoint(pt); //code 10
8022 DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8023 pt = buf->get3BitDouble();
8024 setPt5(pt); //center pt code 15
8025 DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8026 setRa40(buf->getBitDouble()); //leader length code 40
8027 DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40());
8028 type |= 4;
8029 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");
8030
8031 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8032 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n"
)
;
8033 return false;
8034 }
8035 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");
8036 dimStyleH = buf->getHandle();
8037 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8038 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8039 DRW_DBG("anon block Handle: ")DRW_dbg::dbg("anon block Handle: "); DRW_DBGHL(blockH.code, blockH.size, blockH.ref)DRW_dbg::dbgHL(blockH.code, blockH.size, blockH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8040 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");
8041
8042 // RS crc; //RS */
8043 return buf->isGood();
8044}
8045
8046// DRW_DimLargeRadial (AcDbRadialDimensionLarge, LARGE_RADIAL_DIMENSION).
8047// DXF group-code parser: the AcDbRadialDimensionLarge subclass overloads codes
8048// 13/14/15/40 (chord / override center / jog point / jog angle), so gate them on
8049// the subclass marker (like DRW_DimArc). The chord point is stored as the radial
8050// diameter point so the existing addDimRadial consumer renders center→chord.
8051bool DRW_DimLargeRadial::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
8052 if (code == 100) {
8053 std::string s = reader->getString();
8054 if (s == "AcDbRadialDimensionLarge") {
8055 m_largeRadialSubclassSeen = true;
8056 return true;
8057 }
8058 return DRW_Dimension::parseCode(code, reader);
8059 }
8060 if (m_largeRadialSubclassSeen) {
8061 DRW_Coord chord;
8062 switch (code) {
8063 case 13: chord = getPt5(); chord.x = reader->getDouble(); setPt5(chord); return true;
8064 case 23: chord = getPt5(); chord.y = reader->getDouble(); setPt5(chord); return true;
8065 case 33: chord = getPt5(); chord.z = reader->getDouble(); setPt5(chord); return true;
8066 case 14: overrideCenterPoint.x = reader->getDouble(); return true;
8067 case 24: overrideCenterPoint.y = reader->getDouble(); return true;
8068 case 34: overrideCenterPoint.z = reader->getDouble(); return true;
8069 case 15: jogPoint.x = reader->getDouble(); return true;
8070 case 25: jogPoint.y = reader->getDouble(); return true;
8071 case 35: jogPoint.z = reader->getDouble(); return true;
8072 case 40: jogAngle = reader->getDouble(); return true;
8073 default: break;
8074 }
8075 }
8076 return DRW_Dimension::parseCode(code, reader);
8077}
8078
8079// DRW_DimLargeRadial DWG body: five subclass reads then the dim-style and
8080// anon-block handles. The three subclass points are ordered
8081// definition point, JOG point, jog angle, CHORD point, OVERRIDDEN center
8082// so that the decoded fields match the DXF group codes (chord=13, override=14,
8083// jog=15) and libdxfrw's own DXF parseCode. The read-only reference parser
8084// (parseLargeRadialDimension) labels the 2nd/4th/5th reads chord/override/jog,
8085// i.e. a cyclic rotation of the point roles; that is inconsistent with the DXF
8086// semantics and with an ODA File Converter DXF↔DWG round-trip (which preserves
8087// codes 13/14/15 exactly). Verified by large_radial_dim_dwg_tests.cpp against
8088// an ODA-synthesized fixture, cross-checked with the dwg-parser's DXF read.
8089// Only the field labels change vs. the reference parser — the read sizes/order
8090// (3BD, 3BD, BD, 3BD, 3BD) are identical, so buffer alignment is unchanged.
8091bool DRW_DimLargeRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8092 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8093 return false;
8094 }
8095 setDefPoint(buf->get3BitDouble()); // definition point (code 10)
8096 jogPoint = buf->get3BitDouble(); // jog vertex (code 15)
8097 jogAngle = buf->getBitDouble(); // jog transverse angle (code 40)
8098 setPt5(buf->get3BitDouble()); // chord point → radial diameter point (code 13)
8099 overrideCenterPoint = buf->get3BitDouble(); // overridden center (code 14)
8100 type |= 4; // radial dimension type bit
8101 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8102 return false;
8103 }
8104 dimStyleH = buf->getHandle();
8105 blockH = buf->getHandle();
8106 return buf->isGood();
8107}
8108
8109bool DRW_DimDiametric::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8110 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8111 return false;
8112 }
8113
8114 DRW_DBG("\n***************************** parsing dim diametric *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim diametric *********************************************\n"
)
;
8115 DRW_Coord pt = buf->get3BitDouble();
8116 setPt5(pt); //center pt code 15
8117 DRW_DBG("center point: ")DRW_dbg::dbg("center point: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8118 pt = buf->get3BitDouble();
8119 setDefPoint(pt); //code 10
8120 DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8121 setRa40(buf->getBitDouble()); //leader length code 40
8122 DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40());
8123 type |= 3;
8124 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");
8125
8126 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8127 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n"
)
;
8128 return false;
8129 }
8130 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");
8131 dimStyleH = buf->getHandle();
8132 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8133 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8134 DRW_DBG("anon block Handle: ")DRW_dbg::dbg("anon block Handle: "); DRW_DBGHL(blockH.code, blockH.size, blockH.ref)DRW_dbg::dbgHL(blockH.code, blockH.size, blockH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8135 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");
8136
8137 // RS crc; //RS */
8138 return buf->isGood();
8139}
8140
8141bool DRW_DimAngular::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8142 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8143 return false;
8144 }
8145
8146 DRW_DBG("\n***************************** parsing dim angular *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular *********************************************\n"
)
;
8147 DRW_Coord pt;
8148 pt.x = buf->getRawDouble();
8149 pt.y = buf->getRawDouble();
8150 setPt6(pt); //code 16
8151 DRW_DBG("arc Point: ")DRW_dbg::dbg("arc Point: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8152 pt = buf->get3BitDouble();
8153 setPt3(pt); //def1 code 13
8154 DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8155 pt = buf->get3BitDouble();
8156 setPt4(pt); //def2 code 14
8157 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8158 pt = buf->get3BitDouble();
8159 setPt5(pt); //center pt code 15
8160 DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8161 pt = buf->get3BitDouble();
8162 setDefPoint(pt); //code 10
8163 DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8164 type |= 0x02;
8165 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");
8166
8167 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8168 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n"
)
;
8169 return false;
8170 }
8171 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");
8172 dimStyleH = buf->getHandle();
8173 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8174 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8175 DRW_DBG("anon block Handle: ")DRW_dbg::dbg("anon block Handle: "); DRW_DBGHL(blockH.code, blockH.size, blockH.ref)DRW_dbg::dbgHL(blockH.code, blockH.size, blockH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8176 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");
8177
8178 // RS crc; //RS */
8179 return buf->isGood();
8180}
8181
8182bool DRW_DimAngular3p::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8183 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8184 return false;
8185 }
8186
8187 DRW_DBG("\n***************************** parsing dim angular3p *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular3p *********************************************\n"
)
;
8188 DRW_Coord pt = buf->get3BitDouble();
8189 setDefPoint(pt); //code 10
8190 DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8191 pt = buf->get3BitDouble();
8192 setPt3(pt); //def1 code 13
8193 DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8194 pt = buf->get3BitDouble();
8195 setPt4(pt); //def2 code 14
8196 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8197 pt = buf->get3BitDouble();
8198 setPt5(pt); //center pt code 15
8199 DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8200 type |= 0x05;
8201 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");
8202
8203 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8204 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n"
)
;
8205 return false;
8206 }
8207 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");
8208 dimStyleH = buf->getHandle();
8209 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8210 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8211 DRW_DBG("anon block Handle: ")DRW_dbg::dbg("anon block Handle: "); DRW_DBGHL(blockH.code, blockH.size, blockH.ref)DRW_dbg::dbgHL(blockH.code, blockH.size, blockH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8212 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");
8213
8214 // RS crc; //RS */
8215 return buf->isGood();
8216}
8217
8218bool DRW_DimOrdinate::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8219 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8220 return false;
8221 }
8222
8223 DRW_DBG("\n***************************** parsing dim ordinate *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim ordinate *********************************************\n"
)
;
8224 DRW_Coord pt = buf->get3BitDouble();
8225 setDefPoint(pt);
8226 DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8227 pt = buf->get3BitDouble();
8228 setPt3(pt); //def1
8229 DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8230 pt = buf->get3BitDouble();
8231 setPt4(pt);
8232 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8233 std::uint8_t type2 = buf->getRawChar8();//RLZ: correct this
8234 DRW_DBG("type2 (70) read: ")DRW_dbg::dbg("type2 (70) read: "); DRW_DBG(type2)DRW_dbg::dbg(type2);
8235 // 0B.1: x-vs-y ordinate flag is DXF group-70 bit 6 (0x40), matching the
8236 // filter (rs_filterdxfrw.cpp `type & 64`) and the DWG parseCode path.
8237 // (Previously set bit 7/0x80, which the filter never checks.) The clear
8238 // mask 0xBF already clears 0x40. The DIMENSION base type byte (bit 7) is
8239 // a separate field — see :6141/:6409/:6660, NOT touched here.
8240 type = (type2 & 1) ? type | 0x40 : type & 0xBF; //set bit 6 (0x40)
8241 DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(type)DRW_dbg::dbg(type);
8242 type |= 6;
8243 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");
8244
8245 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8246 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n"
)
;
8247 return false;
8248 }
8249 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");
8250 dimStyleH = buf->getHandle();
8251 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8252 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8253 DRW_DBG("anon block Handle: ")DRW_dbg::dbg("anon block Handle: "); DRW_DBGHL(blockH.code, blockH.size, blockH.ref)DRW_dbg::dbgHL(blockH.code, blockH.size, blockH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8254 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");
8255
8256 // RS crc; //RS */
8257 return buf->isGood();
8258}
8259
8260// ----------------------------------------------------------------------------
8261// DRW_Dimension shared base encoder (R2000 / AC1015)
8262// ----------------------------------------------------------------------------
8263bool DRW_Dimension::encodeDwgDimBase(DRW::Version version, dwgBufferW *buf,
8264 dwgBufferW *strBuf) const {
8265 // ODA §20.4.22: version RC present for R2010+ (mirrors parseDwg read at version > AC1021)
8266 if (version > DRW::AC1021)
8267 buf->putRawChar8(0);
8268 // R2007+: the dim text below is routed to strBuf (the separate string
8269 // stream) via the (strBuf ? strBuf : buf) selector in putVariableText.
8270 buf->put3BitDouble(extPoint); // 3BD per ODA §20.4.22 (NOT BE, NO padding bits)
8271 buf->putRawDouble(textPoint.x);
8272 buf->putRawDouble(textPoint.y);
8273 buf->putBitDouble(textPoint.z);
8274 // Reverse the parseDwg type-byte transformation:
8275 // parseDwg bit0=0 → type bit7 set; bit0=1 → type bit7 clear
8276 // parseDwg bit1=1 → type bit5 set; bit1=0 → type bit5 clear
8277 std::uint8_t rawByte = static_cast<std::uint8_t>(
8278 ((type & 0x80) ? 0 : 1) | ((type & 0x20) ? 2 : 0));
8279 buf->putRawChar8(rawByte);
8280 (strBuf ? strBuf : buf)->putVariableText(version, text);
8281 buf->putBitDouble(rot);
8282 buf->putBitDouble(hdir);
8283 // ins_scale (3BD) of the dimension's anonymous block — not stored by the
8284 // reader, but ODA/libreDWG default it to (1,1,1) (dwg.spec FIELD_3BD_1), not
8285 // (0,0,0). A zero scale is degenerate for ODA consumers. (write-review #46)
8286 const DRW_Coord insScale{1.0, 1.0, 1.0};
8287 buf->put3BitDouble(insScale);
8288 buf->putBitDouble(0.0); // ins_rotation (code 54) — default 0, not stored
8289 // R2000 (version > AC1014): alignment, spacing, line factor, measure
8290 buf->putBitShort(static_cast<std::uint16_t>(align));
8291 buf->putBitShort(static_cast<std::uint16_t>(linesty));
8292 buf->putBitDouble(linefactor);
8293 buf->putBitDouble(measureValue);
8294 if (version > DRW::AC1018) {
8295 buf->putBit(0); // unknown R2007+ bit
8296 buf->putBit(flipArrow1 ? 1 : 0);
8297 buf->putBit(flipArrow2 ? 1 : 0);
8298 }
8299 buf->putRawDouble(clonePoint.x);
8300 buf->putRawDouble(clonePoint.y);
8301 return true;
8302}
8303
8304// Helper: emit dimStyleH (defaults to STANDARD=0x15) and blockH.
8305static void putDimHandles(dwgBufferW *buf, const dwgHandle& dimStyleH, const dwgHandle& blockH,
8306 dwgBufferW *hBuf = nullptr) {
8307 dwgBufferW *hb = hBuf ? hBuf : buf;
8308 dwgHandle dsH;
8309 dsH.code = 5;
8310 dsH.ref = (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref;
8311 dsH.size = 0;
8312 if (dsH.ref != 0) { std::uint32_t t = dsH.ref; while (t != 0) { t >>= 8; ++dsH.size; } }
8313 hb->putHandle(dsH);
8314
8315 dwgHandle bhH;
8316 bhH.code = (blockH.ref == 0) ? 0 : 5;
8317 bhH.ref = blockH.ref;
8318 bhH.size = 0;
8319 if (bhH.ref != 0) { std::uint32_t t = bhH.ref; while (t != 0) { t >>= 8; ++bhH.size; } }
8320 hb->putHandle(bhH);
8321}
8322
8323// ----------------------------------------------------------------------------
8324// DRW_DimAligned::encodeDwg (oType=22)
8325// ----------------------------------------------------------------------------
8326bool DRW_DimAligned::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8327 (void)bs;
8328 oType = 22;
8329 if (!encodeDwgCommon(version, buf)) return false;
8330 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8331 buf->put3BitDouble(getPt3()); // def1
8332 buf->put3BitDouble(getPt4()); // def2
8333 buf->put3BitDouble(getDefPoint()); // defPoint
8334 buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians
8335 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8336 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8337 return true;
8338}
8339
8340// ----------------------------------------------------------------------------
8341// DRW_DimLinear::encodeDwg (oType=21)
8342// ----------------------------------------------------------------------------
8343bool DRW_DimLinear::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8344 (void)bs;
8345 oType = 21;
8346 if (!encodeDwgCommon(version, buf)) return false;
8347 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8348 buf->put3BitDouble(getPt3()); // def1
8349 buf->put3BitDouble(getPt4()); // def2
8350 buf->put3BitDouble(getDefPoint()); // defPoint
8351 buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians
8352 buf->putBitDouble(getAn50() / ARAD57.29577951308232); // rotation angle: degrees → radians
8353 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8354 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8355 return true;
8356}
8357
8358// ----------------------------------------------------------------------------
8359// DRW_DimRadial::encodeDwg (oType=25)
8360// ----------------------------------------------------------------------------
8361bool DRW_DimRadial::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8362 (void)bs;
8363 oType = 25;
8364 if (!encodeDwgCommon(version, buf)) return false;
8365 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8366 buf->put3BitDouble(getDefPoint()); // center point (code 10)
8367 buf->put3BitDouble(getPt5()); // diameter point (code 15)
8368 buf->putBitDouble(getRa40()); // leader length (code 40)
8369 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8370 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8371 return true;
8372}
8373
8374// ----------------------------------------------------------------------------
8375// DRW_DimLargeRadial::encodeDwg (oType=519, custom AcDbRadialDimensionLarge)
8376// ----------------------------------------------------------------------------
8377bool DRW_DimLargeRadial::encodeDwg(DRW::Version version, dwgBufferW *buf,
8378 std::uint32_t bs, dwgBufferW *strBuf,
8379 dwgBufferW *handleBuf) {
8380 (void)bs;
8381 oType = kDwgClassNum;
8382 if (!encodeDwgCommon(version, buf)) return false;
8383 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8384 buf->put3BitDouble(getCenterPoint()); // definition point (code 10)
8385 buf->put3BitDouble(jogPoint); // jog vertex (code 15)
8386 buf->putBitDouble(jogAngle); // jog transverse angle (code 40)
8387 buf->put3BitDouble(getChordPoint()); // chord point (code 13)
8388 buf->put3BitDouble(overrideCenterPoint); // overridden center (code 14)
8389 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8390 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8391 return true;
8392}
8393
8394// ----------------------------------------------------------------------------
8395// DRW_DimDiametric::encodeDwg (oType=26)
8396// ----------------------------------------------------------------------------
8397bool DRW_DimDiametric::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8398 (void)bs;
8399 oType = 26;
8400 if (!encodeDwgCommon(version, buf)) return false;
8401 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8402 buf->put3BitDouble(getPt5()); // first diameter point (code 15) — matches parseDwg order
8403 buf->put3BitDouble(getDefPoint()); // opposite point (code 10)
8404 buf->putBitDouble(getRa40()); // leader length (code 40)
8405 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8406 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8407 return true;
8408}
8409
8410// ----------------------------------------------------------------------------
8411// DRW_DimAngular::encodeDwg (oType=24, 2-line angular)
8412// ----------------------------------------------------------------------------
8413bool DRW_DimAngular::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8414 (void)bs;
8415 oType = 24;
8416 if (!encodeDwgCommon(version, buf)) return false;
8417 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8418 // arcPoint is 2RD (not 3BD) in parseDwg — only x and y
8419 buf->putRawDouble(getPt6().x);
8420 buf->putRawDouble(getPt6().y);
8421 buf->put3BitDouble(getPt3()); // def1 (line 1 start)
8422 buf->put3BitDouble(getPt4()); // def2 (line 1 end)
8423 buf->put3BitDouble(getPt5()); // circlePoint (center)
8424 buf->put3BitDouble(getDefPoint()); // defPoint
8425 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8426 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8427 return true;
8428}
8429
8430// ----------------------------------------------------------------------------
8431// DRW_DimAngular3p::encodeDwg (oType=23, 3-point angular)
8432// ----------------------------------------------------------------------------
8433bool DRW_DimAngular3p::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8434 (void)bs;
8435 oType = 23;
8436 if (!encodeDwgCommon(version, buf)) return false;
8437 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8438 buf->put3BitDouble(getDefPoint()); // defPoint (code 10)
8439 buf->put3BitDouble(getPt3()); // def1 (code 13)
8440 buf->put3BitDouble(getPt4()); // def2 (code 14)
8441 buf->put3BitDouble(getPt5()); // circlePoint / vertex (code 15)
8442 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8443 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8444 return true;
8445}
8446
8447// ----------------------------------------------------------------------------
8448// DRW_DimArc::parseCode (DXF group-code parser)
8449// ----------------------------------------------------------------------------
8450bool DRW_DimArc::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
8451 if (code == 100) {
8452 std::string s = reader->getString();
8453 if (s == "AcDbArcDimension") {
8454 m_arcSubclassSeen = true;
8455 return true;
8456 }
8457 // Fall through for AcDbEntity / AcDbDimension so base classes see them
8458 return DRW_Dimension::parseCode(code, reader);
8459 }
8460 if (m_arcSubclassSeen) {
8461 switch (code) {
8462 case 40: arcStartAngle = reader->getDouble(); return true;
8463 case 41: arcEndAngle = reader->getDouble(); return true;
8464 case 70: arcSymbol = reader->getInt32(); return true;
8465 case 71: isPartial = reader->getInt32() != 0; return true;
8466 }
8467 }
8468 switch (code) {
8469 case 17: leaderPt2.x = reader->getDouble(); return true;
8470 case 27: leaderPt2.y = reader->getDouble(); return true;
8471 case 37: leaderPt2.z = reader->getDouble(); return true;
8472 }
8473 return DRW_Dimension::parseCode(code, reader);
8474}
8475
8476// ----------------------------------------------------------------------------
8477// DRW_DimArc::parseDwg (ODA DWG spec §20.4.19)
8478// ----------------------------------------------------------------------------
8479bool DRW_DimArc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
8480 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) return false;
8481 setDefPoint(buf->get3BitDouble()); // arc dim-line arc point (code 10)
8482 setPt3(buf->get3BitDouble()); // extension line 1 (code 13)
8483 setPt4(buf->get3BitDouble()); // extension line 2 (code 14)
8484 setPt5(buf->get3BitDouble()); // arc center (code 15)
8485 isPartial = buf->getBit() != 0;
8486 arcStartAngle = buf->getBitDouble();
8487 arcEndAngle = buf->getBitDouble();
8488 hasLeader = buf->getBit() != 0;
8489 // ODA §20.4.19: leader points are UNCONDITIONAL — always present in the stream
8490 setPt6(buf->get3BitDouble()); // leader point 1 (code 16)
8491 leaderPt2 = buf->get3BitDouble(); // leader point 2 (code 17)
8492 if (!DRW_Entity::parseDwgEntHandle(version, buf)) return false;
8493 dimStyleH = buf->getHandle();
8494 blockH = buf->getHandle();
8495 return buf->isGood();
8496}
8497
8498// ----------------------------------------------------------------------------
8499// DRW_DimArc::encodeDwg (oType=500 — dynamic class, classNum from writeDwgClasses)
8500// ----------------------------------------------------------------------------
8501bool DRW_DimArc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
8502 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8503 (void)bs;
8504 oType = DRW_DimArc::kDwgClassNum; // assigned in writeDwgClasses; reader resolves via classesmap
8505 if (!encodeDwgCommon(version, buf)) return false;
8506 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8507 buf->put3BitDouble(getDefPoint()); // arc dim-line arc point (code 10)
8508 buf->put3BitDouble(getPt3()); // extension line 1 (code 13)
8509 buf->put3BitDouble(getPt4()); // extension line 2 (code 14)
8510 buf->put3BitDouble(getPt5()); // arc center (code 15)
8511 buf->putBit(isPartial ? 1 : 0);
8512 buf->putBitDouble(arcStartAngle);
8513 buf->putBitDouble(arcEndAngle);
8514 buf->putBit(hasLeader ? 1 : 0);
8515 // ODA §20.4.19: leader points are UNCONDITIONAL — always written; default to ext-line pts
8516 DRW_Coord lp1 = hasLeader ? getPt6() : getPt3();
8517 DRW_Coord lp2 = hasLeader ? leaderPt2 : getPt4();
8518 buf->put3BitDouble(lp1); // leader point 1 (code 16)
8519 buf->put3BitDouble(lp2); // leader point 2 (code 17)
8520 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8521 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8522 return true;
8523}
8524
8525// ----------------------------------------------------------------------------
8526// DRW_DimOrdinate::encodeDwg (oType=20)
8527// ----------------------------------------------------------------------------
8528bool DRW_DimOrdinate::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8529 (void)bs;
8530 oType = 20;
8531 if (!encodeDwgCommon(version, buf)) return false;
8532 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8533 buf->put3BitDouble(getDefPoint()); // origin/definition point (code 10)
8534 buf->put3BitDouble(getPt3()); // feature location point (code 13)
8535 buf->put3BitDouble(getPt4()); // leader end point (code 14)
8536 // type2 byte encodes the x-vs-y ordinate flag (bit 6 / 0x40 of type, per
8537 // 0B.1) — keeps the DWG byte round-trip self-consistent with the parse
8538 // side while making the filter's `type & 64` check fire.
8539 std::uint8_t type2byte = (type & 0x40) ? 1 : 0;
8540 buf->putRawChar8(type2byte);
8541 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8542 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8543 return true;
8544}
8545
8546bool DRW_Leader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
8547 switch (code) {
8548 case 3:
8549 style = reader->getUtf8String();
8550 break;
8551 case 71:
8552 arrow = reader->getInt32();
8553 break;
8554 case 72:
8555 leadertype = reader->getInt32();
8556 break;
8557 case 73:
8558 flag = reader->getInt32();
8559 break;
8560 case 74:
8561 hookline = reader->getInt32();
8562 break;
8563 case 75:
8564 hookflag = reader->getInt32();
8565 break;
8566 case 76:
8567 vertnum = reader->getInt32();
8568 break;
8569 case 77:
8570 coloruse = reader->getInt32();
8571 break;
8572 case 40:
8573 textheight = reader->getDouble();
8574 break;
8575 case 41:
8576 textwidth = reader->getDouble();
8577 break;
8578 case 10:
8579 vertexpoint= std::make_shared<DRW_Coord>();
8580 vertexlist.push_back(vertexpoint);
8581 vertexpoint->x = reader->getDouble();
8582 break;
8583 case 20:
8584 if(vertexpoint)
8585 vertexpoint->y = reader->getDouble();
8586 break;
8587 case 30:
8588 if(vertexpoint)
8589 vertexpoint->z = reader->getDouble();
8590 break;
8591 case 340:
8592 annotHandle = reader->getHandleString();
8593 break;
8594 case 210:
8595 extrusionPoint.x = reader->getDouble();
8596 break;
8597 case 220:
8598 extrusionPoint.y = reader->getDouble();
8599 break;
8600 case 230:
8601 extrusionPoint.z = reader->getDouble();
8602 break;
8603 case 211:
8604 horizdir.x = reader->getDouble();
8605 break;
8606 case 221:
8607 horizdir.y = reader->getDouble();
8608 break;
8609 case 231:
8610 horizdir.z = reader->getDouble();
8611 break;
8612 case 212:
8613 offsetblock.x = reader->getDouble();
8614 break;
8615 case 222:
8616 offsetblock.y = reader->getDouble();
8617 break;
8618 case 232:
8619 offsetblock.z = reader->getDouble();
8620 break;
8621 case 213:
8622 offsettext.x = reader->getDouble();
8623 break;
8624 case 223:
8625 offsettext.y = reader->getDouble();
8626 break;
8627 case 233:
8628 offsettext.z = reader->getDouble();
8629 break;
8630 default:
8631 return DRW_Entity::parseCode(code, reader);
8632 }
8633
8634 return true;
8635}
8636
8637bool DRW_Leader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8638 dwgBuffer sBuff = *buf;
8639 dwgBuffer *sBuf = buf;
8640 if (version > DRW::AC1018) {//2007+
8641 sBuf = &sBuff; //separate buffer for strings
8642 }
8643 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
8644 if (!ret)
8645 return ret;
8646 DRW_DBG("\n***************************** parsing leader *********************************************\n")DRW_dbg::dbg("\n***************************** parsing leader *********************************************\n"
)
;
8647 DRW_DBG("unknown bit ")DRW_dbg::dbg("unknown bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8648 DRW_DBG(" annot type ")DRW_dbg::dbg(" annot type "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8649 leadertype = buf->getBitShort();
8650 DRW_DBG(" Path type ")DRW_dbg::dbg(" Path type "); DRW_DBG(leadertype)DRW_dbg::dbg(leadertype);
8651 std::int32_t nPt = buf->getBitLong();
8652 DRW_DBG(" Num pts ")DRW_dbg::dbg(" Num pts "); DRW_DBG(nPt)DRW_dbg::dbg(nPt);
8653
8654 // add vertexes
8655 for (int i = 0; i< nPt; i++){
8656 DRW_Coord vertex = buf->get3BitDouble();
8657 vertexlist.push_back(std::make_shared<DRW_Coord>(vertex));
8658 DRW_DBG("\nvertex ")DRW_dbg::dbg("\nvertex "); DRW_DBGPT(vertex.x, vertex.y, vertex.z)DRW_dbg::dbgPT(vertex.x, vertex.y, vertex.z);
8659 }
8660 DRW_Coord Endptproj = buf->get3BitDouble();
8661 DRW_DBG("\nEndptproj ")DRW_dbg::dbg("\nEndptproj "); DRW_DBGPT(Endptproj.x, Endptproj.y, Endptproj.z)DRW_dbg::dbgPT(Endptproj.x, Endptproj.y, Endptproj.z);
8662 // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — confirmed by libreDWG dwg.spec:3439
8663 extrusionPoint = buf->get3BitDouble();
8664 DRW_DBG("\nextrusionPoint ")DRW_dbg::dbg("\nextrusionPoint "); DRW_DBGPT(extrusionPoint.x, extrusionPoint.y, extrusionPoint.z)DRW_dbg::dbgPT(extrusionPoint.x, extrusionPoint.y, extrusionPoint
.z)
;
8665 horizdir = buf->get3BitDouble();
8666 DRW_DBG("\nhorizdir ")DRW_dbg::dbg("\nhorizdir "); DRW_DBGPT(horizdir.x, horizdir.y, horizdir.z)DRW_dbg::dbgPT(horizdir.x, horizdir.y, horizdir.z);
8667 offsetblock = buf->get3BitDouble();
8668 DRW_DBG("\noffsetblock ")DRW_dbg::dbg("\noffsetblock "); DRW_DBGPT(offsetblock.x, offsetblock.y, offsetblock.z)DRW_dbg::dbgPT(offsetblock.x, offsetblock.y, offsetblock.z);
8669 if (version > DRW::AC1012) { //R14+
8670 DRW_Coord unk = buf->get3BitDouble();
8671 DRW_DBG("\nunknown ")DRW_dbg::dbg("\nunknown "); DRW_DBGPT(unk.x, unk.y, unk.z)DRW_dbg::dbgPT(unk.x, unk.y, unk.z);
8672 }
8673 if (version < DRW::AC1015) { //R14 -
8674 DRW_DBG("\ndimgap ")DRW_dbg::dbg("\ndimgap "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble());
8675 }
8676 if (version < DRW::AC1024) { //2010-
8677 textheight = buf->getBitDouble();
8678 textwidth = buf->getBitDouble();
8679 DRW_DBG("\ntextheight ")DRW_dbg::dbg("\ntextheight "); DRW_DBG(textheight)DRW_dbg::dbg(textheight); DRW_DBG(" textwidth ")DRW_dbg::dbg(" textwidth "); DRW_DBG(textwidth)DRW_dbg::dbg(textwidth);
8680 }
8681 hookline = buf->getBit();
8682 arrow = buf->getBit();
8683 DRW_DBG(" hookline ")DRW_dbg::dbg(" hookline "); DRW_DBG(hookline)DRW_dbg::dbg(hookline); DRW_DBG(" arrow flag ")DRW_dbg::dbg(" arrow flag "); DRW_DBG(arrow)DRW_dbg::dbg(arrow);
8684
8685 if (version < DRW::AC1015) { //R14 -
8686 DRW_DBG("\nArrow head type ")DRW_dbg::dbg("\nArrow head type "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8687 DRW_DBG("dimasz ")DRW_dbg::dbg("dimasz "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble());
8688 DRW_DBG("\nunk bit ")DRW_dbg::dbg("\nunk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8689 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8690 DRW_DBG(" unk short ")DRW_dbg::dbg(" unk short "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8691 DRW_DBG(" byBlock color ")DRW_dbg::dbg(" byBlock color "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8692 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8693 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8694 } else { //R2000+
8695 DRW_DBG("\nunk short ")DRW_dbg::dbg("\nunk short "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8696 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8697 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8698 }
8699 DRW_DBG("\n")DRW_dbg::dbg("\n");
8700 ret = DRW_Entity::parseDwgEntHandle(version, buf);
8701 if (!ret)
8702 return ret;
8703 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");
8704 AnnotH = buf->getHandle();
8705 annotHandle = AnnotH.ref;
8706 DRW_DBG("annot block Handle: ")DRW_dbg::dbg("annot block Handle: "); DRW_DBGHL(AnnotH.code, AnnotH.size, dimStyleH.ref)DRW_dbg::dbgHL(AnnotH.code, AnnotH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8707 dimStyleH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8708 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
8709 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");
8710// RS crc; //RS */
8711 return buf->isGood();
8712}
8713
8714// DXF CONTEXT_DATA{} nested-block state machine (§20.4.86). The nested blocks
8715// open with 300 "CONTEXT_DATA{" / 302 "LEADER{" / 304 "LEADER_LINE{" and close
8716// with the distinct codes 301 / 303 / 305, so the open block is tracked with a
8717// single state int (no stack needed). The numeric group codes are overloaded
8718// by block — e.g. 40 is the overall scale in CONTEXT, the landing distance in
8719// LEADER and the arrow size in LEADER_LINE; 10/20/30 are the content base point,
8720// the connection point and a polyline vertex respectively — so they are routed
8721// per state into `context`. Returns true when the code belongs to the context
8722// block (consumed); false at entity level so parseCode handles it.
8723bool DRW_MLeader::parseDxfContextCode(int code, const std::unique_ptr<dxfReader>& reader){
8724 switch (code) { // block open/close markers
8725 case 300: m_dxfCtxState = 1; return true; // "CONTEXT_DATA{"
8726 case 301: m_dxfCtxState = 0; return true; // "}" end context
8727 case 302: context.roots.emplace_back(); m_dxfCtxState = 2; return true; // "LEADER{"
8728 case 303: m_dxfCtxState = m_dxfCtxState ? 1 : 0; return true; // "}" end leader
8729 case 304:
8730 if (reader->getString() == "LEADER_LINE{") {
8731 if (!context.roots.empty())
8732 context.roots.back().leaderLines.emplace_back();
8733 m_dxfCtxState = 3;
8734 return true;
8735 }
8736 if (m_dxfCtxState == 1) { context.textLabel = reader->getUtf8String(); return true; }
8737 return false; // not in context: defer (unused)
8738 case 305: m_dxfCtxState = 2; return true; // "}" end leader line
8739 default: break;
8740 }
8741
8742 if (m_dxfCtxState == 0)
8743 return false; // entity level — parseCode handles it
8744
8745 if (m_dxfCtxState == 3) { // LEADER_LINE{}: a polyline + overrides
8746 DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back();
8747 DRW_MLeaderLeaderLine* line =
8748 (root && !root->leaderLines.empty()) ? &root->leaderLines.back() : nullptr;
8749 if (line) switch (code) {
8750 case 10: line->points.emplace_back(reader->getDouble(), 0.0, 0.0); return true;
8751 case 20: if (!line->points.empty()) line->points.back().y = reader->getDouble(); return true;
8752 case 30: if (!line->points.empty()) line->points.back().z = reader->getDouble(); return true;
8753 case 40: line->arrowSize = reader->getDouble(); return true;
8754 case 90: line->segmentIndex = reader->getInt32(); return true;
8755 case 91: line->leaderLineIndex = reader->getInt32(); return true;
8756 case 92: line->color = reader->getInt32(); return true;
8757 case 93: line->overrideFlags = reader->getInt32(); return true;
8758 case 170: line->leaderType = reader->getInt32(); return true;
8759 case 171: line->lineWeight = reader->getInt32(); return true;
8760 default: break;
8761 }
8762 return true; // swallow other line codes
8763 }
8764
8765 if (m_dxfCtxState == 2) { // LEADER{}: one root attachment
8766 DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back();
8767 if (root) switch (code) {
8768 case 290: root->isContentValid = (reader->getInt32() != 0); return true;
8769 case 291: root->unknown291 = (reader->getInt32() != 0); return true;
8770 case 10: root->connectionPoint.x = reader->getDouble(); return true;
8771 case 20: root->connectionPoint.y = reader->getDouble(); return true;
8772 case 30: root->connectionPoint.z = reader->getDouble(); return true;
8773 case 11: root->direction.x = reader->getDouble(); return true;
8774 case 21: root->direction.y = reader->getDouble(); return true;
8775 case 31: root->direction.z = reader->getDouble(); return true;
8776 case 90: root->leaderIndex = reader->getInt32(); return true;
8777 case 40: root->landingDistance = reader->getDouble(); return true;
8778 case 271: root->attachmentDirection = reader->getInt32(); return true;
8779 default: break;
8780 }
8781 return true; // swallow other leader codes
8782 }
8783
8784 switch (code) { // m_dxfCtxState == 1: CONTEXT_DATA{}
8785 case 40: context.overallScale = reader->getDouble(); return true;
8786 case 10: context.contentBasePoint.x = reader->getDouble(); return true;
8787 case 20: context.contentBasePoint.y = reader->getDouble(); return true;
8788 case 30: context.contentBasePoint.z = reader->getDouble(); return true;
8789 case 41: context.textHeight = reader->getDouble(); return true;
8790 case 140: context.arrowHeadSize = reader->getDouble(); return true;
8791 case 145: context.landingGap = reader->getDouble(); return true;
8792 case 174: context.styleLeftAttach = reader->getInt32(); return true;
8793 case 175: context.styleRightAttach = reader->getInt32(); return true;
8794 case 176: context.textAlignType = reader->getInt32(); return true;
8795 case 177: context.attachmentType = reader->getInt32(); return true;
8796 case 290: context.hasTextContents = (reader->getInt32() != 0); return true;
8797 /* text-content branch */
8798 case 11: context.textNormal.x = reader->getDouble(); return true;
8799 case 21: context.textNormal.y = reader->getDouble(); return true;
8800 case 31: context.textNormal.z = reader->getDouble(); return true;
8801 case 12: context.textLocation.x = reader->getDouble(); return true;
8802 case 22: context.textLocation.y = reader->getDouble(); return true;
8803 case 32: context.textLocation.z = reader->getDouble(); return true;
8804 case 13: context.textDirection.x = reader->getDouble(); return true;
8805 case 23: context.textDirection.y = reader->getDouble(); return true;
8806 case 33: context.textDirection.z = reader->getDouble(); return true;
8807 case 42: context.textRotation = reader->getDouble(); return true;
8808 case 43: context.boundaryWidth = reader->getDouble(); return true;
8809 case 44: context.boundaryHeight = reader->getDouble(); return true;
8810 case 45: context.lineSpacingFactor = reader->getDouble(); return true;
8811 case 170: context.lineSpacingStyle = reader->getInt32(); return true;
8812 case 90: context.textColor = reader->getInt32(); return true;
8813 case 171: context.alignment = reader->getInt32(); return true;
8814 case 172: context.flowDirection = reader->getInt32(); return true;
8815 case 91: context.bgFillColor = reader->getInt32(); return true;
8816 case 141: context.bgScaleFactor = reader->getDouble(); return true;
8817 case 92: context.bgTransparency = reader->getInt32(); return true;
8818 case 291: context.bgFillEnabled = (reader->getInt32() != 0); return true;
8819 case 292: context.bgMaskFillOn = (reader->getInt32() != 0); return true;
8820 case 173: context.columnType = reader->getInt32(); return true;
8821 case 293: context.textHeightAuto = (reader->getInt32() != 0); return true;
8822 case 142: context.columnWidth = reader->getDouble(); return true;
8823 case 143: context.columnGutter = reader->getDouble(); return true;
8824 case 294: context.columnFlowReversed = (reader->getInt32() != 0); return true;
8825 case 144: context.columnSizes.push_back(reader->getDouble()); return true;
8826 case 295: context.wordBreak = (reader->getInt32() != 0); return true;
8827 /* block-content branch */
8828 case 296: context.hasContentsBlock = (reader->getInt32() != 0); return true;
8829 case 14: context.blockNormal.x = reader->getDouble(); return true;
8830 case 24: context.blockNormal.y = reader->getDouble(); return true;
8831 case 34: context.blockNormal.z = reader->getDouble(); return true;
8832 case 15: context.blockLocation.x = reader->getDouble(); return true;
8833 case 25: context.blockLocation.y = reader->getDouble(); return true;
8834 case 35: context.blockLocation.z = reader->getDouble(); return true;
8835 case 16: context.blockScale.x = reader->getDouble(); return true;
8836 case 26: context.blockScale.y = reader->getDouble(); return true;
8837 case 36: context.blockScale.z = reader->getDouble(); return true;
8838 case 46: context.blockRotation = reader->getDouble(); return true;
8839 case 93: context.blockColor = reader->getInt32(); return true;
8840 /* common tail */
8841 case 110: context.basePoint.x = reader->getDouble(); return true;
8842 case 120: context.basePoint.y = reader->getDouble(); return true;
8843 case 130: context.basePoint.z = reader->getDouble(); return true;
8844 case 111: context.baseDirection.x = reader->getDouble(); return true;
8845 case 121: context.baseDirection.y = reader->getDouble(); return true;
8846 case 131: context.baseDirection.z = reader->getDouble(); return true;
8847 case 112: context.baseVertical.x = reader->getDouble(); return true;
8848 case 122: context.baseVertical.y = reader->getDouble(); return true;
8849 case 132: context.baseVertical.z = reader->getDouble(); return true;
8850 case 297: context.isNormalReversed = (reader->getInt32() != 0); return true;
8851 case 272: context.styleBottomAttach = reader->getInt32(); return true;
8852 case 273: context.styleTopAttach = reader->getInt32(); return true;
8853 default: return true; // swallow any other context code
8854 }
8855}
8856
8857bool DRW_MLeader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
8858 // The embedded CONTEXT_DATA{} block (§20.4.86) is routed by the nested-block
8859 // state machine; the remaining (entity-level) fields are read below and
8860 // mirror the DWG body parser.
8861 if (parseDxfContextCode(code, reader))
8862 return true;
8863 switch (code) {
8864 case 170: leaderType = reader->getInt32(); break;
8865 case 171: leaderLineWeight = reader->getInt32(); break;
8866 case 172: styleContentType = reader->getInt32(); break;
8867 case 173: styleLeftAttach = reader->getInt32(); break;
8868 case 95: styleRightAttach = reader->getInt32(); break;
8869 case 174: styleTextAngleType = reader->getInt32(); break;
8870 case 175: unknown175 = reader->getInt32(); break;
8871 case 176: styleAttachmentType = reader->getInt32(); break;
8872 case 178: ipeAlign = reader->getInt32(); break;
8873 case 179: justification = reader->getInt32(); break;
8874 case 271: attachmentDirection = reader->getInt32(); break;
8875 case 272: styleBottomAttach = reader->getInt32(); break;
8876 case 273: styleTopAttach = reader->getInt32(); break;
8877 case 90: overrideFlags = reader->getInt32(); break;
8878 case 91: leaderColor = reader->getInt32(); break;
8879 case 92: styleTextColor = reader->getInt32(); break;
8880 case 93: styleBlockColor = reader->getInt32(); break;
8881 case 41: landingDistance = reader->getDouble(); break;
8882 case 42: defaultArrowHeadSize = reader->getDouble(); break;
8883 case 43: styleBlockRotation = reader->getDouble(); break;
8884 case 45: scaleFactor = reader->getDouble(); break;
8885 case 290: landingEnabled = (reader->getInt32() != 0); break;
8886 case 291: doglegEnabled = (reader->getInt32() != 0); break;
8887 case 292: styleTextFrameEnabled = (reader->getInt32() != 0); break;
8888 case 293: isAnnotative = (reader->getInt32() != 0); break;
8889 case 294: isTextDirectionNegative = (reader->getInt32() != 0); break;
8890 case 295: leaderExtendedToText = (reader->getInt32() != 0); break;
8891 default:
8892 return DRW_Entity::parseCode(code, reader);
8893 }
8894 return true;
8895}
8896
8897// Helper: parse one AcDbMLeaderObjectContextData::LeaderRoot entry (§20.4.86).
8898//
8899// Each root has: connection point + direction, optional break pairs, leader
8900// index, landing distance, then a count-and-list of leader lines. Lines
8901// themselves carry: point list, break-info pairs, and (R2010+) per-line
8902// style overrides. The handles inside (line-type / arrow per leader line)
8903// are deferred to the entity-level handle stream and not stored here.
8904static bool parseMLeaderRoot(DRW::Version version, dwgBuffer *buf,
8905 DRW_MLeaderRoot& root) {
8906 // Layout per libreDWG dwg2.spec:1316-1366 (Dwg_LEADER_Node + Dwg_LEADER_Line).
8907 // The two 3BD coords at the head of the node are conditional on the
8908 // preceding B flags; reading them unconditionally drifts the bit stream
8909 // when either flag is 0.
8910 bool hasLastPt = buf->getBit(); // 290 has_lastleaderlinepoint
8911 bool hasDogleg = buf->getBit(); // 291 has_dogleg
8912 root.isContentValid = hasLastPt;
8913 root.unknown291 = hasDogleg;
8914 if (hasLastPt) root.connectionPoint = buf->get3BitDouble();
8915 if (hasDogleg) root.direction = buf->get3BitDouble();
8916
8917 std::int32_t nBreaks = buf->getBitLong();
8918 if (nBreaks < 0 || nBreaks > 5000) return false; // libreDWG MAX_LEADER_NUMBER
8919 root.breaks.reserve(static_cast<size_t>(nBreaks));
8920 for (std::int32_t i = 0; i < nBreaks; ++i) {
8921 DRW_Coord a = buf->get3BitDouble();
8922 DRW_Coord b = buf->get3BitDouble();
8923 root.breaks.emplace_back(a, b);
8924 }
8925
8926 root.leaderIndex = buf->getBitLong(); // 90 branch_index
8927 root.landingDistance = buf->getBitDouble(); // 40 dogleg_length
8928
8929 std::int32_t nLines = buf->getBitLong();
8930 if (nLines < 0 || nLines > 5000) return false;
8931 root.leaderLines.reserve(static_cast<size_t>(nLines));
8932 for (std::int32_t i = 0; i < nLines; ++i) {
8933 DRW_MLeaderLeaderLine line;
8934 // Per libreDWG: BL num_points, points, BL num_breaks, breaks, BL line_index.
8935 // The previous 5-BL layout (brkInfoCount + segmentIndex + nPairs +
8936 // pairs + leaderLineIndex) inserted two spurious BL reads, drifting
8937 // every subsequent entity-level field (overallScale, contentType, …).
8938 std::int32_t nPts = buf->getBitLong();
8939 if (nPts < 0 || nPts > 5000) return false;
8940 line.points.reserve(static_cast<size_t>(nPts));
8941 for (std::int32_t j = 0; j < nPts; ++j) {
8942 line.points.push_back(buf->get3BitDouble());
8943 }
8944 std::int32_t nLineBreaks = buf->getBitLong();
8945 if (nLineBreaks < 0 || nLineBreaks > 5000) return false;
8946 for (std::int32_t j = 0; j < nLineBreaks; ++j) {
8947 DRW_Coord a = buf->get3BitDouble();
8948 DRW_Coord b = buf->get3BitDouble();
8949 line.breaks.emplace_back(a, b);
8950 }
8951 line.leaderLineIndex = buf->getBitLong(); // 91 line_index
8952
8953 // R2010+ per-line override block. The spec marks this block "R2010"
8954 // (§20.4.86 page 215); the override flags BL 93 says which fields
8955 // were overridden. The handle fields (340 line-type, 341 arrow) are
8956 // deferred to the trailing handle stream.
8957 if (version >= DRW::AC1024) {
8958 line.leaderType = buf->getBitShort();
8959 line.color = buf->getCmColor(version);
8960 // line type handle 340 — read from handles section later
8961 line.lineWeight = buf->getBitLong();
8962 line.arrowSize = buf->getBitDouble();
8963 // arrow handle 341 — handles section
8964 line.overrideFlags = buf->getBitLong();
8965 }
8966 root.leaderLines.push_back(std::move(line));
8967 }
8968
8969 if (version >= DRW::AC1024) {
8970 root.attachmentDirection = buf->getBitShort();
8971 }
8972
8973 return buf->isGood();
8974}
8975
8976// Helper: parse the AcDbMLeaderObjectContextData (§20.4.86) payload, the
8977// large embedded block at the start of the MLEADER body that carries the
8978// leader geometry plus either text or block content.
8979static bool parseMLeaderAnnotContext(DRW::Version version, dwgBuffer *buf,
8980 dwgBuffer *sBuf,
8981 DRW_MLeaderAnnotContext& ctx) {
8982 // NOTE: when AcDbMLeaderObjectContextData is embedded INSIDE the MLEADER
8983 // entity body (rather than serialized as a standalone object), the
8984 // AcDbObjectContextData base preamble (BS version, B has-file-ext-dict,
8985 // B default-flag) does NOT appear in the bit stream — those fields are
8986 // standalone-object metadata. The embedded AnnotContext starts directly
8987 // with the leader-roots count. AcDbAnnotScaleObjectContextData's scale
8988 // handle is deferred to the trailing handle stream.
8989
8990 // Number of leader roots.
8991 std::int32_t nRoots = buf->getBitLong();
8992 if (nRoots == 0) {
8993 bool rootCountBits[7] = {};
8994 for (bool& rootCountBit : rootCountBits)
8995 rootCountBit = buf->getBit() != 0;
8996 nRoots = rootCountBits[5] ? 2 : 1;
8997 }
8998 if (nRoots < 0 || nRoots > 1000000) return false;
8999 ctx.roots.clear();
9000 ctx.roots.reserve(static_cast<size_t>(nRoots));
9001 for (std::int32_t i = 0; i < nRoots; ++i) {
9002 DRW_MLeaderRoot root;
9003 if (!parseMLeaderRoot(version, buf, root)) return false;
9004 ctx.roots.push_back(std::move(root));
9005 }
9006
9007 // Common content fields.
9008 ctx.overallScale = buf->getBitDouble();
9009 ctx.contentBasePoint = buf->get3BitDouble();
9010 ctx.textHeight = buf->getBitDouble();
9011 ctx.arrowHeadSize = buf->getBitDouble();
9012 ctx.landingGap = buf->getBitDouble();
9013 ctx.styleLeftAttach = buf->getBitShort();
9014 ctx.styleRightAttach = buf->getBitShort();
9015 ctx.textAlignType = buf->getBitShort();
9016 ctx.attachmentType = buf->getBitShort();
9017 ctx.hasTextContents = buf->getBit();
9018
9019 if (ctx.hasTextContents) {
9020 ctx.textLabel = sBuf->getVariableText(version, false);
9021 ctx.textNormal = buf->get3BitDouble();
9022 // text style handle 340 — handles section
9023 ctx.textLocation = buf->get3BitDouble();
9024 ctx.textDirection = buf->get3BitDouble();
9025 ctx.textRotation = buf->getBitDouble();
9026 ctx.boundaryWidth = buf->getBitDouble();
9027 ctx.boundaryHeight = buf->getBitDouble();
9028 ctx.lineSpacingFactor = buf->getBitDouble();
9029 ctx.lineSpacingStyle = buf->getBitShort();
9030 ctx.textColor = buf->getCmColor(version);
9031 ctx.alignment = buf->getBitShort();
9032 ctx.flowDirection = buf->getBitShort();
9033 ctx.bgFillColor = buf->getCmColor(version);
9034 ctx.bgScaleFactor = buf->getBitDouble();
9035 ctx.bgTransparency = buf->getBitLong();
9036 ctx.bgFillEnabled = buf->getBit();
9037 ctx.bgMaskFillOn = buf->getBit();
9038 ctx.columnType = buf->getBitShort();
9039 ctx.textHeightAuto = buf->getBit();
9040 ctx.columnWidth = buf->getBitDouble();
9041 ctx.columnGutter = buf->getBitDouble();
9042 ctx.columnFlowReversed = buf->getBit();
9043 std::int32_t nColSizes = buf->getBitLong();
9044 if (nColSizes < 0 || nColSizes > 1000000) return false;
9045 ctx.columnSizes.reserve(static_cast<size_t>(nColSizes));
9046 for (std::int32_t i = 0; i < nColSizes; ++i) {
9047 ctx.columnSizes.push_back(buf->getBitDouble());
9048 }
9049 ctx.wordBreak = buf->getBit();
9050 buf->getBit(); // unknown trailing bit
9051 } else {
9052 ctx.hasContentsBlock = buf->getBit();
9053 if (ctx.hasContentsBlock) {
9054 // BlockTableRecord handle 341 — deferred
9055 ctx.blockNormal = buf->get3BitDouble();
9056 ctx.blockLocation = buf->get3BitDouble();
9057 ctx.blockScale = buf->get3BitDouble();
9058 ctx.blockRotation = buf->getBitDouble();
9059 ctx.blockColor = buf->getCmColor(version);
9060 for (size_t i = 0; i < 16; ++i) {
9061 ctx.blockTransform[i] = buf->getBitDouble();
9062 }
9063 }
9064 }
9065
9066 // Common tail.
9067 ctx.basePoint = buf->get3BitDouble();
9068 ctx.baseDirection = buf->get3BitDouble();
9069 ctx.baseVertical = buf->get3BitDouble();
9070 ctx.isNormalReversed = buf->getBit();
9071
9072 if (version >= DRW::AC1024) {
9073 ctx.styleTopAttach = buf->getBitShort();
9074 ctx.styleBottomAttach = buf->getBitShort();
9075 }
9076
9077 return buf->isGood();
9078}
9079
9080static bool encodeMLeaderRoot(DRW::Version version, dwgBufferW *buf,
9081 const DRW_MLeaderRoot& root) {
9082 if (root.breaks.size() > 5000 || root.leaderLines.size() > 5000)
9083 return false;
9084
9085 buf->putBit(root.isContentValid ? 1 : 0);
9086 buf->putBit(root.unknown291 ? 1 : 0);
9087 if (root.isContentValid)
9088 buf->put3BitDouble(root.connectionPoint);
9089 if (root.unknown291)
9090 buf->put3BitDouble(root.direction);
9091
9092 buf->putBitLong(static_cast<std::int32_t>(root.breaks.size()));
9093 for (const auto& brk : root.breaks) {
9094 buf->put3BitDouble(brk.first);
9095 buf->put3BitDouble(brk.second);
9096 }
9097
9098 buf->putBitLong(root.leaderIndex);
9099 buf->putBitDouble(root.landingDistance);
9100
9101 buf->putBitLong(static_cast<std::int32_t>(root.leaderLines.size()));
9102 for (const DRW_MLeaderLeaderLine& line : root.leaderLines) {
9103 if (line.points.size() > 5000 || line.breaks.size() > 5000)
9104 return false;
9105 buf->putBitLong(static_cast<std::int32_t>(line.points.size()));
9106 for (const DRW_Coord& point : line.points)
9107 buf->put3BitDouble(point);
9108
9109 buf->putBitLong(static_cast<std::int32_t>(line.breaks.size()));
9110 for (const auto& brk : line.breaks) {
9111 buf->put3BitDouble(brk.first);
9112 buf->put3BitDouble(brk.second);
9113 }
9114 buf->putBitLong(line.leaderLineIndex);
9115
9116 if (version >= DRW::AC1024) {
9117 buf->putBitShort(line.leaderType);
9118 buf->putCmColor(version, static_cast<std::uint16_t>(line.color));
9119 buf->putBitLong(line.lineWeight);
9120 buf->putBitDouble(line.arrowSize);
9121 buf->putBitLong(line.overrideFlags);
9122 }
9123 }
9124
9125 if (version >= DRW::AC1024)
9126 buf->putBitShort(root.attachmentDirection);
9127
9128 return true;
9129}
9130
9131static bool encodeMLeaderAnnotContext(DRW::Version version, dwgBufferW *buf,
9132 dwgBufferW *strBuf,
9133 const DRW_MLeaderAnnotContext& ctx) {
9134 if (ctx.roots.size() > 1000000 || ctx.columnSizes.size() > 1000000)
9135 return false;
9136 if (ctx.hasContentsBlock)
9137 return false;
9138
9139 buf->putBitLong(static_cast<std::int32_t>(ctx.roots.size()));
9140 for (const DRW_MLeaderRoot& root : ctx.roots) {
9141 if (!encodeMLeaderRoot(version, buf, root))
9142 return false;
9143 }
9144
9145 buf->putBitDouble(ctx.overallScale);
9146 buf->put3BitDouble(ctx.contentBasePoint);
9147 buf->putBitDouble(ctx.textHeight);
9148 buf->putBitDouble(ctx.arrowHeadSize);
9149 buf->putBitDouble(ctx.landingGap);
9150 buf->putBitShort(ctx.styleLeftAttach);
9151 buf->putBitShort(ctx.styleRightAttach);
9152 buf->putBitShort(ctx.textAlignType);
9153 buf->putBitShort(ctx.attachmentType);
9154 buf->putBit(ctx.hasTextContents ? 1 : 0);
9155
9156 if (ctx.hasTextContents) {
9157 (strBuf ? strBuf : buf)->putVariableText(version, ctx.textLabel);
9158 buf->put3BitDouble(ctx.textNormal);
9159 buf->put3BitDouble(ctx.textLocation);
9160 buf->put3BitDouble(ctx.textDirection);
9161 buf->putBitDouble(ctx.textRotation);
9162 buf->putBitDouble(ctx.boundaryWidth);
9163 buf->putBitDouble(ctx.boundaryHeight);
9164 buf->putBitDouble(ctx.lineSpacingFactor);
9165 buf->putBitShort(ctx.lineSpacingStyle);
9166 buf->putCmColor(version, static_cast<std::uint16_t>(ctx.textColor));
9167 buf->putBitShort(ctx.alignment);
9168 buf->putBitShort(ctx.flowDirection);
9169 buf->putCmColor(version, static_cast<std::uint16_t>(ctx.bgFillColor));
9170 buf->putBitDouble(ctx.bgScaleFactor);
9171 buf->putBitLong(ctx.bgTransparency);
9172 buf->putBit(ctx.bgFillEnabled ? 1 : 0);
9173 buf->putBit(ctx.bgMaskFillOn ? 1 : 0);
9174 buf->putBitShort(ctx.columnType);
9175 buf->putBit(ctx.textHeightAuto ? 1 : 0);
9176 buf->putBitDouble(ctx.columnWidth);
9177 buf->putBitDouble(ctx.columnGutter);
9178 buf->putBit(ctx.columnFlowReversed ? 1 : 0);
9179 buf->putBitLong(static_cast<std::int32_t>(ctx.columnSizes.size()));
9180 for (double columnSize : ctx.columnSizes)
9181 buf->putBitDouble(columnSize);
9182 buf->putBit(ctx.wordBreak ? 1 : 0);
9183 buf->putBit(0);
9184 } else {
9185 buf->putBit(0); // hasContentsBlock
9186 }
9187
9188 buf->put3BitDouble(ctx.basePoint);
9189 buf->put3BitDouble(ctx.baseDirection);
9190 buf->put3BitDouble(ctx.baseVertical);
9191 buf->putBit(ctx.isNormalReversed ? 1 : 0);
9192
9193 if (version >= DRW::AC1024) {
9194 buf->putBitShort(ctx.styleTopAttach);
9195 buf->putBitShort(ctx.styleBottomAttach);
9196 }
9197
9198 return true;
9199}
9200
9201bool DRW_MLeader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
9202 dwgBuffer sBuff = *buf;
9203 dwgBuffer *sBuf = buf;
9204 if (version > DRW::AC1018) { // 2007+
9205 sBuf = &sBuff;
9206 }
9207 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
9208 if (!ret) return ret;
9209 DRW_DBG("\n***************************** parsing MLEADER ***************\n")DRW_dbg::dbg("\n***************************** parsing MLEADER ***************\n"
)
;
9210
9211 // R2010b+ class version (BS, default 2; <=R2004 was 1). libreDWG
9212 // dwg2.spec:1303-1306. Absent in R2007 streams; reading it would drift.
9213 if (version >= DRW::AC1024) {
9214 classVersion = buf->getBitShort();
9215 if (classVersion > 10) {
9216 DRW_DBG("\nMLEADER: implausible classVersion=")DRW_dbg::dbg("\nMLEADER: implausible classVersion=");
9217 DRW_DBG(static_cast<int>(classVersion))DRW_dbg::dbg(static_cast<int>(classVersion));
9218 DRW_DBG(", aborting body\n")DRW_dbg::dbg(", aborting body\n");
9219 return true;
9220 }
9221 }
9222
9223 // Phase 4 — embedded AcDbMLeaderObjectContextData / MLeaderAnnotContext.
9224 // Body misalignment is local to this entity's buffer (each entity gets a
9225 // fresh buffer from the object map), so on a partial-parse failure we
9226 // keep whatever was captured and return true. This preserves the
9227 // entity-stream-continues invariant established in Phase 2.
9228 if (!parseMLeaderAnnotContext(version, buf, sBuf, context)) {
9229 DRW_DBG("\nMLEADER: AnnotContext parse drift — partial fields kept\n")DRW_dbg::dbg("\nMLEADER: AnnotContext parse drift — partial fields kept\n"
)
;
9230 return true;
9231 }
9232
9233 // Phase 3 — entity-level fields per §20.4.48 (after the AnnotContext).
9234 // Many handle slots are deferred to the trailing handle stream and not
9235 // stored here yet (resolution comes in Phase 7).
9236 overrideFlags = buf->getBitLong();
9237 leaderType = buf->getBitShort();
9238 leaderColor = buf->getCmColor(version);
9239 // leader line type handle 341 — handle stream
9240 leaderLineWeight = buf->getBitLong();
9241 landingEnabled = buf->getBit();
9242 doglegEnabled = buf->getBit();
9243 landingDistance = buf->getBitDouble();
9244 // arrow head handle 342 — handle stream
9245 defaultArrowHeadSize = buf->getBitDouble();
9246 styleContentType = buf->getBitShort();
9247 // text style handle 343 — handle stream
9248 styleLeftAttach = buf->getBitShort();
9249 styleRightAttach = buf->getBitShort();
9250 styleTextAngleType = buf->getBitShort();
9251 unknown175 = buf->getBitShort();
9252 styleTextColor = buf->getCmColor(version);
9253 styleTextFrameEnabled = buf->getBit();
9254 // style block handle 344 — handle stream (optional)
9255 styleBlockColor = buf->getCmColor(version);
9256 styleBlockScale = buf->get3BitDouble();
9257 styleBlockRotation = buf->getBitDouble();
9258 styleAttachmentType = buf->getBitShort();
9259 isAnnotative = buf->getBit();
9260
9261 // R2007 arrays (pre-R2010 only): per spec §20.4.48. Bounds-check the
9262 // counts; a misaligned bit stream would produce huge nonsense values.
9263 // On a sanity-check trip, abort the rest of the body parse but keep
9264 // the entity (per Phase 4 contract above).
9265 if (version < DRW::AC1024) {
9266 std::int32_t nArrows = buf->getBitLong();
9267 if (nArrows < 0 || nArrows > 1000000) return true;
9268 arrowHeads.reserve(static_cast<size_t>(nArrows));
9269 for (std::int32_t i = 0; i < nArrows; ++i) {
9270 ArrowHeadEntry e;
9271 e.isDefault = buf->getBit();
9272 arrowHeads.push_back(e);
9273 }
9274 std::int32_t nLabels = buf->getBitLong();
9275 if (nLabels < 0 || nLabels > 1000000) return true;
9276 blockLabels.reserve(static_cast<size_t>(nLabels));
9277 for (std::int32_t i = 0; i < nLabels; ++i) {
9278 BlockLabelEntry e;
9279 e.labelText = sBuf->getVariableText(version, false);
9280 e.uiIndex = buf->getBitShort();
9281 e.width = buf->getBitDouble();
9282 blockLabels.push_back(std::move(e));
9283 }
9284 }
9285
9286 isTextDirectionNegative = buf->getBit();
9287 ipeAlign = buf->getBitShort();
9288 justification = buf->getBitShort();
9289 scaleFactor = buf->getBitDouble();
9290
9291 if (version >= DRW::AC1024) { // R2010+
9292 attachmentDirection = buf->getBitShort();
9293 styleTopAttach = buf->getBitShort();
9294 styleBottomAttach = buf->getBitShort();
9295 }
9296 if (version >= DRW::AC1027) { // R2013+
9297 leaderExtendedToText = buf->getBit();
9298 }
9299
9300 // Common entity handles first (owner/reactors/xdic/layer/ltype/...) —
9301 // entity-specific handles follow in declared order from libreDWG
9302 // dwg2.spec:1386-1453. Read order in the trailing handle stream:
9303 // 1. AnnotContext content handle (text_style 340 if hasTextContents,
9304 // else block_table 341 if hasContentsBlock).
9305 // 2. (R2010b+ only) per-leader-line ltype + arrow handles, in the
9306 // same iteration order as the body block.
9307 // 3. mleaderstyle (340), line_ltype (341), arrow_handle (342),
9308 // text_style (343), block_style (344) entity-level handles.
9309 // 4. (R14-R2007 only) per-arrowhead + per-blocklabel handles.
9310 ret = DRW_Entity::parseDwgEntHandle(version, buf);
9311 if (!ret) {
9312 DRW_DBG("\nMLEADER: parseDwgEntHandle hiccup — body fields kept\n")DRW_dbg::dbg("\nMLEADER: parseDwgEntHandle hiccup — body fields kept\n"
)
;
9313 return true;
9314 }
9315
9316 auto safeHandle = [&](dwgHandle& slot, const char* tag) {
9317 if (buf->numRemainingBytes() < 1) return false;
9318 slot = buf->getHandle();
9319 DRW_DBG(" ")DRW_dbg::dbg(" "); DRW_DBG(tag)DRW_dbg::dbg(tag); DRW_DBG(": ")DRW_dbg::dbg(": ");
9320 DRW_DBGHL(slot.code, slot.size, slot.ref)DRW_dbg::dbgHL(slot.code, slot.size, slot.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9321 return buf->isGood();
9322 };
9323
9324 // 1. AnnotContext content handle.
9325 if (context.hasTextContents) {
9326 if (!safeHandle(context.textStyleHandle, "ctx.text_style")) return true;
9327 } else if (context.hasContentsBlock) {
9328 if (!safeHandle(context.blockTableRecordHandle, "ctx.block_table")) return true;
9329 }
9330
9331 // 2. R2010b+ per-line handles, in body iteration order.
9332 if (version >= DRW::AC1024) {
9333 for (auto& root : context.roots) {
9334 for (auto& line : root.leaderLines) {
9335 if (!safeHandle(line.lineTypeHandle, "line.ltype")) return true;
9336 if (!safeHandle(line.arrowHandle, "line.arrow")) return true;
9337 }
9338 }
9339 }
9340
9341 // 3. Entity-level handles.
9342 if (!safeHandle(styleHandle, "mleaderstyle")) return true;
9343 if (!safeHandle(leaderLineTypeHandle, "line_ltype")) return true;
9344 if (!safeHandle(arrowHeadHandle, "arrow_handle")) return true;
9345 if (!safeHandle(styleTextStyleHandle, "text_style")) return true;
9346 if (!safeHandle(styleBlockHandle, "block_style")) return true;
9347
9348 // 4. R14-R2007 per-arrowhead + per-blocklabel handles (counts came
9349 // from the body-side arrays read earlier).
9350 if (version < DRW::AC1024) {
9351 for (auto& a : arrowHeads)
9352 if (!safeHandle(a.handle, "arrowheads.handle")) return true;
9353 for (auto& bl : blockLabels)
9354 if (!safeHandle(bl.attDefHandle, "blocklabels.attdef")) return true;
9355 }
9356
9357 const int rb = buf->numRemainingBytes();
9358 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");
9359 if (rb > 4) {
9360 DRW_DBG("MLEADER: handle-stream tail ")DRW_dbg::dbg("MLEADER: handle-stream tail "); DRW_DBG(rb)DRW_dbg::dbg(rb);
9361 DRW_DBG(" bytes unconsumed (handle ")DRW_dbg::dbg(" bytes unconsumed (handle ");
9362 DRW_DBGH(handle)DRW_dbg::dbgH(handle); DRW_DBG(") — review tail handle list\n")DRW_dbg::dbg(") — review tail handle list\n");
9363 }
9364
9365 return true;
9366}
9367
9368bool DRW_MLeader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9369 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9370 (void)bs;
9371 if (version < DRW::AC1024)
9372 return false;
9373
9374 oType = kDwgClassNum;
9375 if (!encodeDwgCommon(version, buf, strBuf))
9376 return false;
9377
9378 buf->putBitShort(classVersion == 0 ? 2 : classVersion);
9379 if (!encodeMLeaderAnnotContext(version, buf, strBuf, context))
9380 return false;
9381
9382 buf->putBitLong(overrideFlags);
9383 buf->putBitShort(leaderType);
9384 buf->putCmColor(version, static_cast<std::uint16_t>(leaderColor));
9385 buf->putBitLong(leaderLineWeight);
9386 buf->putBit(landingEnabled ? 1 : 0);
9387 buf->putBit(doglegEnabled ? 1 : 0);
9388 buf->putBitDouble(landingDistance);
9389 buf->putBitDouble(defaultArrowHeadSize);
9390 buf->putBitShort(styleContentType);
9391 buf->putBitShort(styleLeftAttach);
9392 buf->putBitShort(styleRightAttach);
9393 buf->putBitShort(styleTextAngleType);
9394 buf->putBitShort(unknown175);
9395 buf->putCmColor(version, static_cast<std::uint16_t>(styleTextColor));
9396 buf->putBit(styleTextFrameEnabled ? 1 : 0);
9397 buf->putCmColor(version, static_cast<std::uint16_t>(styleBlockColor));
9398 buf->put3BitDouble(styleBlockScale);
9399 buf->putBitDouble(styleBlockRotation);
9400 buf->putBitShort(styleAttachmentType);
9401 buf->putBit(isAnnotative ? 1 : 0);
9402 buf->putBit(isTextDirectionNegative ? 1 : 0);
9403 buf->putBitShort(ipeAlign);
9404 buf->putBitShort(justification);
9405 buf->putBitDouble(scaleFactor);
9406
9407 buf->putBitShort(attachmentDirection);
9408 buf->putBitShort(styleTopAttach);
9409 buf->putBitShort(styleBottomAttach);
9410 if (version >= DRW::AC1027)
9411 buf->putBit(leaderExtendedToText ? 1 : 0);
9412
9413 if (!encodeDwgEntHandle(version, buf, handleBuf))
9414 return false;
9415
9416 dwgBufferW *hb = handleBuf ? handleBuf : buf;
9417 if (context.hasTextContents) {
9418 putHardPointerHandle(hb, context.textStyleHandle.ref);
9419 } else if (context.hasContentsBlock) {
9420 putHardPointerHandle(hb, context.blockTableRecordHandle.ref);
9421 }
9422
9423 for (const DRW_MLeaderRoot& root : context.roots) {
9424 for (const DRW_MLeaderLeaderLine& line : root.leaderLines) {
9425 putHardPointerHandle(hb, line.lineTypeHandle.ref);
9426 putHardPointerHandle(hb, line.arrowHandle.ref);
9427 }
9428 }
9429
9430 putHardPointerHandle(hb, styleHandle.ref);
9431 putHardPointerHandle(hb, leaderLineTypeHandle.ref);
9432 putHardPointerHandle(hb, arrowHeadHandle.ref);
9433 putHardPointerHandle(hb, styleTextStyleHandle.ref);
9434 putHardPointerHandle(hb, styleBlockHandle.ref);
9435
9436 return true;
9437}
9438
9439bool DRW_Viewport::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
9440 switch (code) {
9441 case 40:
9442 pswidth = reader->getDouble();
9443 break;
9444 case 41:
9445 psheight = reader->getDouble();
9446 break;
9447 case 68:
9448 vpstatus = reader->getInt32();
9449 break;
9450 case 69:
9451 vpID = reader->getInt32();
9452 break;
9453 case 12:
9454 centerPX = reader->getDouble();
9455 break;
9456 case 22:
9457 centerPY = reader->getDouble();
9458 break;
9459 case 15:
9460 gridSpX = reader->getDouble();
9461 break;
9462 case 25:
9463 gridSpY = reader->getDouble();
9464 break;
9465 case 46:
9466 circleZoom = reader->getDouble();
9467 break;
9468 case 72:
9469 majorGridLines = reader->getInt32();
9470 break;
9471 case 90:
9472 statusFlags = reader->getInt32();
9473 break;
9474 case 1:
9475 styleSheet = reader->getUtf8String();
9476 break;
9477 case 281:
9478 renderMode = reader->getInt32();
9479 break;
9480 case 71:
9481 ucsAtOrigin = reader->getInt32() != 0;
9482 break;
9483 case 74:
9484 ucsPerViewport = reader->getInt32() != 0;
9485 break;
9486 case 110:
9487 ucsOrigin.x = reader->getDouble();
9488 break;
9489 case 120:
9490 ucsOrigin.y = reader->getDouble();
9491 break;
9492 case 130:
9493 ucsOrigin.z = reader->getDouble();
9494 break;
9495 case 111:
9496 ucsXAxis.x = reader->getDouble();
9497 break;
9498 case 121:
9499 ucsXAxis.y = reader->getDouble();
9500 break;
9501 case 131:
9502 ucsXAxis.z = reader->getDouble();
9503 break;
9504 case 112:
9505 ucsYAxis.x = reader->getDouble();
9506 break;
9507 case 122:
9508 ucsYAxis.y = reader->getDouble();
9509 break;
9510 case 132:
9511 ucsYAxis.z = reader->getDouble();
9512 break;
9513 case 146:
9514 ucsElevation = reader->getDouble();
9515 break;
9516 case 76:
9517 ucsOrthographicType = reader->getInt32();
9518 break;
9519 case 148:
9520 shadePlotMode = reader->getInt32();
9521 break;
9522 case 292:
9523 useDefaultLighting = reader->getInt32() != 0;
9524 break;
9525 case 282:
9526 defaultLightingType = reader->getInt32();
9527 break;
9528 case 451:
9529 brightness = reader->getDouble();
9530 break;
9531 case 452:
9532 contrast = reader->getDouble();
9533 break;
9534 case 421:
9535 ambientColorRgb = reader->getInt32();
9536 break;
9537 case 431:
9538 ambientColorMethod = reader->getInt32();
9539 break;
9540 case 331:
9541 vpHeaderHandle = static_cast<std::uint32_t>(reader->getHandleString());
9542 break;
9543 case 340:
9544 clipBoundaryHandle = static_cast<std::uint32_t>(reader->getHandleString());
9545 break;
9546 case 345:
9547 namedUcsHandle = static_cast<std::uint32_t>(reader->getHandleString());
9548 break;
9549 case 346:
9550 baseUcsHandle = static_cast<std::uint32_t>(reader->getHandleString());
9551 break;
9552 case 347:
9553 backgroundHandle = static_cast<std::uint32_t>(reader->getHandleString());
9554 break;
9555 case 348:
9556 visualStyleHandle = static_cast<std::uint32_t>(reader->getHandleString());
9557 break;
9558 case 349:
9559 shadePlotHandle = static_cast<std::uint32_t>(reader->getHandleString());
9560 break;
9561 default:
9562 return DRW_Point::parseCode(code, reader);
9563 }
9564
9565 return true;
9566}
9567//ex 22 dec 34
9568bool DRW_Viewport::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
9569 dwgBuffer sBuff = *buf;
9570 dwgBuffer *sBuf = buf;
9571 if (version > DRW::AC1018) {//2007+
9572 sBuf = &sBuff; //separate buffer for strings
9573 }
9574 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
9575 if (!ret)
9576 return ret;
9577 DRW_DBG("\n***************************** parsing viewport *****************************************\n")DRW_dbg::dbg("\n***************************** parsing viewport *****************************************\n"
)
;
9578 basePoint.x = buf->getBitDouble();
9579 basePoint.y = buf->getBitDouble();
9580 basePoint.z = buf->getBitDouble();
9581 DRW_DBG("center ")DRW_dbg::dbg("center "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
9582 pswidth = buf->getBitDouble();
9583 psheight = buf->getBitDouble();
9584 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");
9585 //RLZ TODO: complete in dxf
9586 if (version > DRW::AC1014) {//2000+
9587 viewTarget.x = buf->getBitDouble();
9588 viewTarget.y = buf->getBitDouble();
9589 viewTarget.z = buf->getBitDouble();
9590 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);
9591 viewDir.x = buf->getBitDouble();
9592 viewDir.y = buf->getBitDouble();
9593 viewDir.z = buf->getBitDouble();
9594 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);
9595 twistAngle = buf->getBitDouble();
9596 DRW_DBG("\nView twist Angle: ")DRW_dbg::dbg("\nView twist Angle: "); DRW_DBG(twistAngle)DRW_dbg::dbg(twistAngle);
9597 viewHeight = buf->getBitDouble();
9598 DRW_DBG("\nview Height: ")DRW_dbg::dbg("\nview Height: "); DRW_DBG(viewHeight)DRW_dbg::dbg(viewHeight);
9599 viewLength = buf->getBitDouble();
9600 DRW_DBG(" Lens Length: ")DRW_dbg::dbg(" Lens Length: "); DRW_DBG(viewLength)DRW_dbg::dbg(viewLength);
9601 frontClip = buf->getBitDouble();
9602 DRW_DBG("\nfront Clip Z: ")DRW_dbg::dbg("\nfront Clip Z: "); DRW_DBG(frontClip)DRW_dbg::dbg(frontClip);
9603 backClip = buf->getBitDouble();
9604 DRW_DBG(" back Clip Z: ")DRW_dbg::dbg(" back Clip Z: "); DRW_DBG(backClip)DRW_dbg::dbg(backClip);
9605 snapAngle = buf->getBitDouble();
9606 DRW_DBG("\n snap Angle: ")DRW_dbg::dbg("\n snap Angle: "); DRW_DBG(snapAngle)DRW_dbg::dbg(snapAngle);
9607 centerPX = buf->getRawDouble();
9608 centerPY = buf->getRawDouble();
9609 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);
9610 snapPX = buf->getRawDouble();
9611 snapPY = buf->getRawDouble();
9612 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);
9613 snapSpPX = buf->getRawDouble();
9614 snapSpPY = buf->getRawDouble();
9615 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);
9616 //RLZ: need to complete
9617 DRW_DBG("\nGrid spacing X: ")DRW_dbg::dbg("\nGrid spacing X: "); DRW_DBG(buf->getRawDouble())DRW_dbg::dbg(buf->getRawDouble()); DRW_DBG(", Y: ")DRW_dbg::dbg(", Y: "); DRW_DBG(buf->getRawDouble())DRW_dbg::dbg(buf->getRawDouble());DRW_DBG("\n")DRW_dbg::dbg("\n");
9618 DRW_DBG("Circle zoom?: ")DRW_dbg::dbg("Circle zoom?: "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9619 }
9620 if (version > DRW::AC1018) {//2007+
9621 DRW_DBG("Grid major?: ")DRW_dbg::dbg("Grid major?: "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9622 }
9623 if (version > DRW::AC1014) {//2000+
9624 frozenLyCount = buf->getBitLong();
9625 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");
9626 DRW_DBG("Status Flags?: ")DRW_dbg::dbg("Status Flags?: "); DRW_DBG(buf->getBitLong())DRW_dbg::dbg(buf->getBitLong()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9627 //RLZ: Warning needed separate string buffer
9628 DRW_DBG("Style sheet?: ")DRW_dbg::dbg("Style sheet?: "); DRW_DBG(sBuf->getVariableText(version, false))DRW_dbg::dbg(sBuf->getVariableText(version, false)); DRW_DBG("\n")DRW_dbg::dbg("\n");
9629 DRW_DBG("Render mode?: ")DRW_dbg::dbg("Render mode?: "); DRW_DBG(buf->getRawChar8())DRW_dbg::dbg(buf->getRawChar8()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9630 DRW_DBG("UCS OMore...: ")DRW_dbg::dbg("UCS OMore...: "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9631 DRW_DBG("UCS VMore...: ")DRW_dbg::dbg("UCS VMore...: "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9632 DRW_DBG("UCS OMore...: ")DRW_dbg::dbg("UCS OMore...: "); DRW_DBGPT(buf->getBitDouble(), buf->getBitDouble(), buf->getBitDouble())DRW_dbg::dbgPT(buf->getBitDouble(), buf->getBitDouble()
, buf->getBitDouble())
; DRW_DBG("\n")DRW_dbg::dbg("\n");
9633 DRW_DBG("ucs XAMore...: ")DRW_dbg::dbg("ucs XAMore...: "); DRW_DBGPT(buf->getBitDouble(), buf->getBitDouble(), buf->getBitDouble())DRW_dbg::dbgPT(buf->getBitDouble(), buf->getBitDouble()
, buf->getBitDouble())
; DRW_DBG("\n")DRW_dbg::dbg("\n");
9634 DRW_DBG("UCS YMore....: ")DRW_dbg::dbg("UCS YMore....: "); DRW_DBGPT(buf->getBitDouble(), buf->getBitDouble(), buf->getBitDouble())DRW_dbg::dbgPT(buf->getBitDouble(), buf->getBitDouble()
, buf->getBitDouble())
; DRW_DBG("\n")DRW_dbg::dbg("\n");
9635 DRW_DBG("UCS EMore...: ")DRW_dbg::dbg("UCS EMore...: "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9636 DRW_DBG("UCS OVMore...: ")DRW_dbg::dbg("UCS OVMore...: "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9637 }
9638 if (version > DRW::AC1015) {//2004+
9639 DRW_DBG("ShadePlot Mode...: ")DRW_dbg::dbg("ShadePlot Mode...: "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9640 }
9641 if (version > DRW::AC1018) {//2007+
9642 DRW_DBG("Use def Light...: ")DRW_dbg::dbg("Use def Light...: "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9643 DRW_DBG("Def light type?: ")DRW_dbg::dbg("Def light type?: "); DRW_DBG(buf->getRawChar8())DRW_dbg::dbg(buf->getRawChar8()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9644 DRW_DBG("Brightness: ")DRW_dbg::dbg("Brightness: "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9645 DRW_DBG("Contrast: ")DRW_dbg::dbg("Contrast: "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9646 // ODA §20.4.38: ambient color is CMC, not ENC — confirmed by libreDWG dwg.spec:2512
9647 DRW_DBG("Ambient CMC: ")DRW_dbg::dbg("Ambient CMC: "); DRW_DBG(buf->getCmColor(version, nullptr, sBuf))DRW_dbg::dbg(buf->getCmColor(version, nullptr, sBuf)); DRW_DBG("\n")DRW_dbg::dbg("\n");
9648 }
9649 ret = DRW_Entity::parseDwgEntHandle(version, buf);
9650
9651 dwgHandle someHdl;
9652 if (version < DRW::AC1015) {//R13 & R14 only
9653 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");
9654 someHdl = buf->getHandle();
9655 DRW_DBG("ViewPort ent header: ")DRW_dbg::dbg("ViewPort ent header: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9656 }
9657 if (version > DRW::AC1014) {//2000+
9658 for (std::uint32_t i=0; i < frozenLyCount && buf->isGood(); ++i){
9659 someHdl = buf->getHandle();
9660 DRW_DBG("Frozen layer handle ")DRW_dbg::dbg("Frozen layer handle "); DRW_DBG(i)DRW_dbg::dbg(i); DRW_DBG(": ")DRW_dbg::dbg(": "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9661 }
9662 someHdl = buf->getHandle();
9663 DRW_DBG("Clip bpundary handle: ")DRW_dbg::dbg("Clip bpundary handle: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9664 if (version == DRW::AC1015) {//2000 only
9665 someHdl = buf->getHandle();
9666 DRW_DBG("ViewPort ent header: ")DRW_dbg::dbg("ViewPort ent header: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9667 }
9668 someHdl = buf->getHandle();
9669 DRW_DBG("Named ucs handle: ")DRW_dbg::dbg("Named ucs handle: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9670 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");
9671 someHdl = buf->getHandle();
9672 DRW_DBG("base ucs handle: ")DRW_dbg::dbg("base ucs handle: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9673 }
9674 if (version > DRW::AC1018) {//2007+
9675 someHdl = buf->getHandle();
9676 DRW_DBG("background handle: ")DRW_dbg::dbg("background handle: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9677 someHdl = buf->getHandle();
9678 DRW_DBG("visual style handle: ")DRW_dbg::dbg("visual style handle: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9679 someHdl = buf->getHandle();
9680 DRW_DBG("shadeplot ID handle: ")DRW_dbg::dbg("shadeplot ID handle: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9681 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");
9682 someHdl = buf->getHandle();
9683 m_sunHandle = someHdl.ref;
9684 DRW_DBG("SUN handle: ")DRW_dbg::dbg("SUN handle: "); DRW_DBGHL(someHdl.code, someHdl.size, someHdl.ref)DRW_dbg::dbgHL(someHdl.code, someHdl.size, someHdl.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9685 }
9686 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");
9687
9688 if (!ret)
9689 return ret;
9690 return buf->isGood();
9691}
9692
9693// ---------------------------------------------------------------------------
9694// Write helpers shared by the new encoders below.
9695// ---------------------------------------------------------------------------
9696
9697namespace {
9698// Write an absolute hard-pointer handle (code=5, ref=ref) or null handle
9699// (code=3, ref=0) depending on whether ref is non-zero.
9700static void putAbsHandle(dwgBufferW *hb, std::uint32_t ref) {
9701 dwgHandle h;
9702 h.code = (ref != 0) ? 5 : 3;
9703 h.ref = ref;
9704 h.size = 0;
9705 if (h.ref != 0) {
9706 std::uint32_t t = h.ref;
9707 while (t != 0) { t >>= 8; ++h.size; }
9708 }
9709 hb->putHandle(h);
9710}
9711} // namespace
9712
9713// ---------------------------------------------------------------------------
9714// DRW_MLine::encodeDwg — OT=47 (AC1015/AC1018/AC1024)
9715// ---------------------------------------------------------------------------
9716
9717bool DRW_MLine::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9718 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9719 (void)bs; (void)strBuf;
9720 oType = 47;
9721 if (!encodeDwgCommon(version, buf)) return false;
9722
9723 buf->putBitDouble(scale);
9724 buf->putRawChar8(justification);
9725 buf->put3BitDouble(basePoint);
9726 buf->putExtrusion(extPoint, false); // false = pre-2000 style (getExtrusion(false) in parser)
9727 buf->putBitShort(static_cast<std::uint16_t>(openClosed));
9728 buf->putRawChar8(numLines);
9729 buf->putBitShort(numVerts);
9730
9731 for (const auto& vtx : vertlist) {
9732 buf->put3BitDouble(vtx.position);
9733 buf->put3BitDouble(vtx.vertexDir);
9734 buf->put3BitDouble(vtx.miterDir);
9735 for (int li = 0; li < static_cast<int>(numLines); ++li) {
9736 const auto& segs = (li < static_cast<int>(vtx.segParms.size()))
9737 ? vtx.segParms[li] : std::vector<double>{};
9738 const auto& fills = (li < static_cast<int>(vtx.areaFillParms.size()))
9739 ? vtx.areaFillParms[li] : std::vector<double>{};
9740 buf->putBitShort(static_cast<std::uint16_t>(segs.size()));
9741 for (double s : segs) buf->putBitDouble(s);
9742 buf->putBitShort(static_cast<std::uint16_t>(fills.size()));
9743 for (double f : fills) buf->putBitDouble(f);
9744 }
9745 }
9746
9747 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
9748
9749 // MLINE style handle — extra handle after standard entity handles.
9750 if (version > DRW::AC1014) {
9751 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
9752 putAbsHandle(hb, styleHandle);
9753 }
9754 return true;
9755}
9756
9757// ---------------------------------------------------------------------------
9758// DRW_Vertex::encodeDwg — OT varies by flags
9759// ---------------------------------------------------------------------------
9760
9761bool DRW_Vertex::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9762 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9763 (void)bs; (void)strBuf;
9764 switch (m_dwgSubtype) {
9765 case DwgSubtype::Vertex2D: oType = 0x0A; break;
9766 case DwgSubtype::Vertex3D: oType = 0x0B; break;
9767 case DwgSubtype::Mesh: oType = 0x0C; break;
9768 case DwgSubtype::Polyface: oType = 0x0D; break;
9769 case DwgSubtype::PolyfaceFace: oType = 0x0E; break;
9770 case DwgSubtype::Auto:
9771 if ((flags & 64) != 0)
9772 oType = 0x0D; // VERTEX_PFACE coordinate vertex
9773 else if ((flags & 128) != 0)
9774 oType = 0x0E; // VERTEX_PFACE_FACE
9775 else if ((flags & 16) != 0)
9776 oType = 0x0C; // VERTEX_MESH
9777 else if ((flags & 32) != 0 || (flags & 8) != 0)
9778 oType = 0x0B; // VERTEX_3D
9779 else
9780 oType = 0x0A; // VERTEX_2D
9781 break;
9782 }
9783
9784 if (!encodeDwgCommon(version, buf)) return false;
9785
9786 if (oType == 0x0A) {
9787 buf->putRawChar8(static_cast<std::uint8_t>(flags));
9788 buf->put3BitDouble(basePoint);
9789 buf->putBitDouble(stawidth);
9790 buf->putBitDouble(endwidth);
9791 buf->putBitDouble(bulge);
9792 if (version > DRW::AC1021)
9793 buf->putBitLong(static_cast<std::int32_t>(identifier));
9794 buf->putBitDouble(tgdir);
9795 } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) {
9796 buf->putRawChar8(static_cast<std::uint8_t>(flags));
9797 buf->put3BitDouble(basePoint);
9798 } else { // 0x0E pface face
9799 buf->putBitShort(static_cast<std::uint16_t>(vindex1));
9800 buf->putBitShort(static_cast<std::uint16_t>(vindex2));
9801 buf->putBitShort(static_cast<std::uint16_t>(vindex3));
9802 buf->putBitShort(static_cast<std::uint16_t>(vindex4));
9803 }
9804
9805 return encodeDwgEntHandle(version, buf, handleBuf);
9806}
9807
9808bool DRW_SeqEnd::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
9809 if (!DRW_Entity::parseDwg(version, buf, nullptr, bs))
9810 return false;
9811 return DRW_Entity::parseDwgEntHandle(version, buf);
9812}
9813
9814bool DRW_SeqEnd::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9815 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9816 (void)bs; (void)strBuf;
9817 oType = 0x06;
9818 if (!encodeDwgCommon(version, buf))
9819 return false;
9820 return encodeDwgEntHandle(version, buf, handleBuf);
9821}
9822
9823// ---------------------------------------------------------------------------
9824// DRW_Polyline::encodeDwg — OT varies by flags; vertex handles emitted here.
9825// ---------------------------------------------------------------------------
9826
9827bool DRW_Polyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9828 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9829 (void)bs; (void)strBuf;
9830 // Determine object type from stored flags (mirror of parseDwg dispatch).
9831 if (flags & 64) oType = 0x1D; // POLYLINE_PFACE
9832 else if (flags & 16) oType = 0x1E; // POLYLINE_MESH
9833 else if (flags & 8) oType = 0x10; // POLYLINE_3D
9834 else oType = 0x0F; // POLYLINE_2D
9835
9836 if (!encodeDwgCommon(version, buf)) return false;
9837
9838 if (oType == 0x0F) {
9839 buf->putBitShort(static_cast<std::uint16_t>(flags));
9840 buf->putBitShort(static_cast<std::uint16_t>(curvetype));
9841 buf->putBitDouble(defstawidth);
9842 buf->putBitDouble(defendwidth);
9843 buf->putThickness(thickness, version > DRW::AC1014);
9844 buf->putBitDouble(basePoint.z);
9845 buf->putExtrusion(extPoint, version > DRW::AC1014);
9846 } else if (oType == 0x10) {
9847 // curvetype → 2 RC flag bytes (mirror of parser decode)
9848 std::uint8_t rc1 = 0;
9849 if (curvetype == 5) rc1 = 1;
9850 else if (curvetype == 6) rc1 = 2;
9851 else if (curvetype == 8) rc1 = 3;
9852 buf->putRawChar8(rc1);
9853 buf->putRawChar8(static_cast<std::uint8_t>(flags & 1)); // bit 0 = closed
9854 } else if (oType == 0x1D) {
9855 buf->putBitShort(static_cast<std::uint16_t>(vertexcount));
9856 buf->putBitShort(static_cast<std::uint16_t>(facecount));
9857 } else { // 0x1E MESH
9858 buf->putBitShort(static_cast<std::uint16_t>(flags & ~16)); // strip reader-added bit 4
9859 buf->putBitShort(static_cast<std::uint16_t>(curvetype));
9860 buf->putBitShort(static_cast<std::uint16_t>(vertexcount)); // M count
9861 buf->putBitShort(static_cast<std::uint16_t>(facecount)); // N count
9862 buf->putBitShort(static_cast<std::uint16_t>(smoothM)); // mDensity, DXF 73
9863 buf->putBitShort(static_cast<std::uint16_t>(smoothN)); // nDensity, DXF 74
9864 }
9865
9866 // AC2004+ (>AC1015): emit vertex count before the handle section.
9867 std::int32_t ooCount = static_cast<std::int32_t>(vertlist.size());
9868 if (version > DRW::AC1015)
9869 buf->putBitLong(ooCount);
9870
9871 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
9872
9873 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
9874
9875 if (version < DRW::AC1018) {
9876 // R2000-: first/last vertex handles (absolute hard pointers).
9877 putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.front()->handle);
9878 putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.back()->handle);
9879 } else {
9880 // R2004+: one handle per vertex.
9881 for (const auto& v : vertlist)
9882 putAbsHandle(hb, v ? v->handle : 0u);
9883 }
9884 putAbsHandle(hb, seqEndH.ref);
9885
9886 return true;
9887}
9888
9889// ---------------------------------------------------------------------------
9890// DRW_Leader::encodeDwg — OT=45 (AC1015/AC1018/AC1024)
9891// ---------------------------------------------------------------------------
9892
9893bool DRW_Leader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9894 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9895 (void)bs; (void)strBuf;
9896 oType = 45;
9897 if (!encodeDwgCommon(version, buf)) return false;
9898
9899 buf->putBit(0); // unknown bit
9900 buf->putBitShort(0); // annotType (ignored on read)
9901 buf->putBitShort(static_cast<std::int16_t>(leadertype)); // pathType (DXF code 72)
9902 buf->putBitLong(static_cast<std::int32_t>(vertexlist.size()));
9903 for (const auto& vp : vertexlist)
9904 buf->put3BitDouble(*vp);
9905 buf->put3BitDouble(DRW_Coord(0, 0, 0)); // Endptproj (ignored on read)
9906 // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — matches parseDwg.
9907 buf->put3BitDouble(extrusionPoint);
9908
9909 buf->put3BitDouble(horizdir);
9910 buf->put3BitDouble(offsetblock);
9911
9912 if (version > DRW::AC1012)
9913 buf->put3BitDouble(DRW_Coord(0, 0, 0)); // unknown coord
9914
9915 if (version < DRW::AC1015)
9916 buf->putBitDouble(0.0); // dimgap (pre-R2000)
9917
9918 if (version < DRW::AC1024) {
9919 buf->putBitDouble(textheight);
9920 buf->putBitDouble(textwidth);
9921 }
9922
9923 buf->putBit(static_cast<std::uint8_t>(hookline));
9924 buf->putBit(static_cast<std::uint8_t>(arrow));
9925
9926 if (version < DRW::AC1015) {
9927 buf->putBitShort(0); // arrowHeadType
9928 buf->putBitDouble(0.0); // dimasz
9929 buf->putBit(0); // unk
9930 buf->putBit(0); // unk
9931 buf->putBitShort(0); // unk short
9932 buf->putBitShort(0); // byBlock color
9933 buf->putBit(0); // unk
9934 buf->putBit(0); // unk
9935 } else {
9936 buf->putBitShort(0); // unk short (R2000+)
9937 buf->putBit(0); // unk
9938 buf->putBit(0); // unk
9939 }
9940
9941 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
9942
9943 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
9944 putAbsHandle(hb, 0); // AnnotH — null (no annotation entity)
9945 putAbsHandle(hb, 0x15); // dimStyleH — hard ptr to STANDARD (handle 0x15)
9946
9947 return true;
9948}
9949
9950// ---------------------------------------------------------------------------
9951// DRW_Viewport::encodeDwg — OT=34 (AC1015/AC1018/AC1024)
9952// ---------------------------------------------------------------------------
9953
9954bool DRW_Viewport::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9955 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9956 (void)bs;
9957 oType = 34;
9958 // Use strBuf for TV strings in AC1024; for AC1015/AC1018 strings go inline.
9959 dwgBufferW *sb = (strBuf && version > DRW::AC1018) ? strBuf : buf;
9960 if (!encodeDwgCommon(version, buf)) return false;
9961
9962 buf->putBitDouble(basePoint.x);
9963 buf->putBitDouble(basePoint.y);
9964 buf->putBitDouble(basePoint.z);
9965 buf->putBitDouble(pswidth);
9966 buf->putBitDouble(psheight);
9967
9968 if (version > DRW::AC1014) {
9969 buf->putBitDouble(viewTarget.x);
9970 buf->putBitDouble(viewTarget.y);
9971 buf->putBitDouble(viewTarget.z);
9972 buf->putBitDouble(viewDir.x);
9973 buf->putBitDouble(viewDir.y);
9974 buf->putBitDouble(viewDir.z);
9975 buf->putBitDouble(twistAngle);
9976 buf->putBitDouble(viewHeight);
9977 buf->putBitDouble(viewLength); // lens length
9978 buf->putBitDouble(frontClip);
9979 buf->putBitDouble(backClip);
9980 buf->putBitDouble(snapAngle);
9981 buf->putRawDouble(centerPX);
9982 buf->putRawDouble(centerPY);
9983 buf->putRawDouble(snapPX);
9984 buf->putRawDouble(snapPY);
9985 buf->putRawDouble(snapSpPX);
9986 buf->putRawDouble(snapSpPY);
9987 buf->putRawDouble(0.0); // gridSpacingX
9988 buf->putRawDouble(0.0); // gridSpacingY
9989 buf->putBitShort(0); // circleZoom
9990 }
9991
9992 if (version > DRW::AC1018)
9993 buf->putBitShort(0); // gridMajor (AC2007+)
9994
9995 if (version > DRW::AC1014) {
9996 buf->putBitLong(0); // frozenLyCount
9997 buf->putBitLong(0); // statusFlags
9998 sb->putVariableText(version, ""); // styleSheet TV
9999 buf->putRawChar8(0); // renderMode
10000 buf->putBit(0); // ucsPerVP
10001 buf->putBit(0); // ucs flag
10002 // UCS origin / X-axis / Y-axis (3×3BD), elevation, ortho type
10003 for (int i = 0; i < 9; ++i) buf->putBitDouble(0.0);
10004 buf->putBitDouble(0.0); // ucsElev
10005 buf->putBitShort(0); // ucsOrthoType
10006 }
10007
10008 if (version > DRW::AC1015)
10009 buf->putBitShort(0); // shadePlotMode (AC2004+)
10010
10011 if (version > DRW::AC1018) {
10012 buf->putBit(0); // useDefLight
10013 buf->putRawChar8(0); // defLightType
10014 buf->putBitDouble(0.0); // brightness
10015 buf->putBitDouble(0.0); // contrast
10016 buf->putCmColor(version, 256); // ambientColor CMC (ByLayer) per ODA §20.4.38
10017 }
10018
10019 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
10020
10021 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
10022
10023 if (version < DRW::AC1015) {
10024 putAbsHandle(hb, 0); // viewport entity header (pre-2000)
10025 }
10026 if (version > DRW::AC1014) {
10027 // frozenLyCount=0, so no frozen layer handles.
10028 putAbsHandle(hb, 0); // clip boundary (null)
10029 if (version == DRW::AC1015)
10030 putAbsHandle(hb, 0); // viewport entity header (R2000 only)
10031 putAbsHandle(hb, 0); // namedUCS (null)
10032 putAbsHandle(hb, 0); // baseUCS (null)
10033 }
10034 if (version > DRW::AC1018) {
10035 putAbsHandle(hb, 0); // background (null)
10036 putAbsHandle(hb, 0); // visualStyle (null)
10037 putAbsHandle(hb, 0); // shadeplotID (null)
10038 putAbsHandle(hb, 0); // sun (null)
10039 }
10040
10041 return true;
10042}