Bug Summary

File:libraries/libdxfrw/src/drw_entities.cpp
Warning:line 6908, 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-08-04-154929-5069-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 <cctype>
17#include <cmath>
18#include <cstdio>
19#include <cstdlib>
20#include <cstring>
21#include <limits>
22#include <vector>
23#include "drw_entities.h"
24#include "intern/dxfreader.h"
25#include "intern/dwgbuffer.h"
26#include "intern/dwgbufferw.h"
27#include "intern/drw_textcodec.h"
28#include "intern/drw_dbg.h"
29#include "intern/drw_reserve.h"
30#include "intern/dwgreader.h"
31
32namespace {
33
34constexpr std::uint32_t kMaxTableRows = 10000;
35constexpr std::uint32_t kMaxTableColumns = 1000;
36constexpr std::uint32_t kMaxTableCells = 200000;
37constexpr std::uint32_t kMaxTableItems = 100000;
38constexpr std::uint32_t kMaxTableStringBytes = 16 * 1024 * 1024;
39constexpr std::int32_t kMaxLWPolylineVertices = 1000000;
40constexpr std::int32_t kMaxSplineItems = 1000000;
41constexpr std::int32_t kMaxSplineDegree = 1024;
42
43constexpr std::int32_t kSplineFlagMethodFitPoints = 1;
44constexpr std::int32_t kSplineFlagClosed = 4;
45constexpr std::int32_t kSplineFlagUseKnotParameter = 8;
46constexpr std::int32_t kSplineKnotParamCustom = 15;
47
48bool isValidCount(std::int32_t count, std::int32_t maxCount) {
49 return count >= 0 && count <= maxCount;
50}
51
52int hexNibble(char c) {
53 if (c >= '0' && c <= '9')
54 return c - '0';
55 if (c >= 'A' && c <= 'F')
56 return c - 'A' + 10;
57 if (c >= 'a' && c <= 'f')
58 return c - 'a' + 10;
59 return -1;
60}
61
62bool decodeHexBytes(const std::string& hex, std::vector<std::uint8_t>& out) {
63 if ((hex.size() % 2) != 0)
64 return false;
65
66 std::vector<std::uint8_t> decoded;
67 decoded.reserve(hex.size() / 2);
68 for (std::size_t i = 0; i < hex.size(); i += 2) {
69 const int hi = hexNibble(hex[i]);
70 const int lo = hexNibble(hex[i + 1]);
71 if (hi < 0 || lo < 0)
72 return false;
73 decoded.push_back(static_cast<std::uint8_t>((hi << 4) | lo));
74 }
75
76 out = std::move(decoded);
77 return true;
78}
79
80void appendBytes(std::vector<std::uint8_t>& out,
81 const std::vector<std::uint8_t>& bytes) {
82 out.insert(out.end(), bytes.begin(), bytes.end());
83}
84
85void appendTextBytes(std::vector<std::uint8_t>& out, const std::string& text) {
86 out.insert(out.end(), text.begin(), text.end());
87}
88
89std::uint64_t currentDwgBit(const dwgBuffer *buf) {
90 return buf->getPosition() * 8 + buf->getBitPos();
91}
92
93DRW_DwgSubrecordRange makeDwgSubrecordRange(const char *name, std::uint64_t startBit,
94 std::uint64_t endBit, DRW::Version version,
95 std::uint32_t count, bool parseComplete) {
96 DRW_DwgSubrecordRange range;
97 range.m_name = name;
98 range.m_startBit = startBit;
99 range.m_bitSize = endBit >= startBit ? endBit - startBit : 0;
100 range.m_version = version;
101 range.m_count = count;
102 range.m_parseComplete = parseComplete;
103 return range;
104}
105
106bool isValidSplineDegree(int degree) {
107 return degree >= 1 && degree <= kMaxSplineDegree;
108}
109
110bool isValidControlSplineLayout(int degree, std::int32_t knotCount, std::int32_t controlCount) {
111 if (!isValidSplineDegree(degree) || !isValidCount(knotCount, kMaxSplineItems) ||
112 !isValidCount(controlCount, kMaxSplineItems)) {
113 return false;
114 }
115
116 if (controlCount < degree + 1) {
117 return false;
118 }
119
120 const std::int64_t expectedKnots = static_cast<std::int64_t>(controlCount) + degree + 1;
121 return expectedKnots <= kMaxSplineItems && knotCount == expectedKnots;
122}
123
124bool isValidFitSplineLayout(int degree, std::int32_t fitCount) {
125 return isValidSplineDegree(degree) && isValidCount(fitCount, kMaxSplineItems) &&
126 fitCount >= 2;
127}
128
129bool differsFromUnitWeight(double weight) {
130 return std::fabs(weight - 1.0) > 1e-12;
131}
132
133void putHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) {
134 dwgHandle h;
135 h.code = 5;
136 h.ref = ref;
137 h.size = 0;
138 if (ref != 0) {
139 std::uint32_t t = ref;
140 while (t != 0) {
141 t >>= 8;
142 ++h.size;
143 }
144 }
145 buf->putHandle(h);
146}
147
148void putNullableHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) {
149 dwgHandle h;
150 h.code = ref == 0 ? 0 : 5;
151 h.ref = ref;
152 h.size = 0;
153 if (ref != 0) {
154 std::uint32_t t = ref;
155 while (t != 0) {
156 t >>= 8;
157 ++h.size;
158 }
159 }
160 buf->putHandle(h);
161}
162
163std::uint16_t bitShortFromInt(int value) {
164 if (value < 0)
165 return 0;
166 if (value > 0xffff)
167 return 0xffff;
168 return static_cast<std::uint16_t>(value);
169}
170
171std::uint32_t readTableHandle(dwgBuffer *hdlBuf) {
172 if (hdlBuf == nullptr || !hdlBuf->isGood())
173 return 0;
174 dwgHandle h = hdlBuf->getHandle();
175 return h.ref;
176}
177
178void seekTableObjectHandleStream(DRW::Version version, dwgBuffer *buf, std::uint32_t objSize) {
179 if (version > DRW::AC1018) {
180 buf->setPosition(objSize >> 3);
181 buf->setBitPos(objSize & 7);
182 }
183}
184
185void readTableObjectCommonHandles(dwgBuffer *buf, std::uint32_t baseHandle,
186 std::int32_t numReactors, std::uint8_t xDictFlag,
187 int *parentHandle) {
188 dwgHandle parentH = buf->getOffsetHandle(baseHandle);
189 if (parentHandle)
190 *parentHandle = parentH.ref;
191 for (int i = 0; i < numReactors; ++i)
192 buf->getOffsetHandle(baseHandle);
193 if (xDictFlag != 1)
194 buf->getOffsetHandle(baseHandle);
195}
196
197bool readTableValueBytes(dwgBuffer *buf, std::vector<std::uint8_t>& raw, const char *label) {
198 const std::uint32_t byteCount = buf->getBitLong();
199 if (byteCount > kMaxTableStringBytes) {
200 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");
201 return false;
202 }
203 raw.resize(byteCount);
204 const bool good = byteCount == 0 || buf->getBytes(raw.data(), raw.size());
205 if (!good) {
206 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);
207 DRW_DBG(" remaining: ")DRW_dbg::dbg(" remaining: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n");
208 }
209 return good;
210}
211
212UTF8STRINGstd::string decodeTableValueText(DRW::Version version, dwgBuffer *buf, const std::vector<std::uint8_t>& raw) {
213 if (raw.empty())
214 return UTF8STRINGstd::string();
215 std::string s(reinterpret_cast<const char*>(raw.data()), raw.size());
216 if (version > DRW::AC1018 && s.size() >= 2 && s[s.size() - 1] == '\0'
217 && s[s.size() - 2] == '\0') {
218 s.resize(s.size() - 2);
219 } else {
220 while (!s.empty() && s.back() == '\0')
221 s.pop_back();
222 }
223 if (buf->decoder)
224 s = buf->decoder->toUtf8(s);
225 return s;
226}
227
228UTF8STRINGstd::string readTableText(DRW::Version version, dwgBuffer *buf) {
229 if (!buf)
230 return UTF8STRINGstd::string();
231 if (version <= DRW::AC1018)
232 return buf->getVariableText(version, false);
233
234 const std::uint32_t byteLen = buf->getBitShort();
235 if (byteLen == 0)
236 return UTF8STRINGstd::string();
237 if (byteLen > kMaxTableStringBytes) {
238 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");
239 return UTF8STRINGstd::string();
240 }
241
242 std::vector<std::uint8_t> raw(static_cast<size_t>(byteLen) + 2, 0);
243 if (!buf->getBytes(raw.data(), byteLen))
244 return UTF8STRINGstd::string();
245
246 std::string s(reinterpret_cast<const char*>(raw.data()), byteLen);
247 if (buf->decoder)
248 s = buf->decoder->toUtf8(s);
249 return s;
250}
251
252bool readTableValuePoint(dwgBuffer *buf, DRW_CadValue& value, int dimensions) {
253 value.m_dataSize = static_cast<std::uint32_t>(buf->getBitLong());
254 const std::uint32_t expectedSize = static_cast<std::uint32_t>(dimensions) * 8;
255 if (value.m_dataSize > kMaxTableStringBytes)
256 return false;
257 if (value.m_dataSize < expectedSize) {
258 value.m_rawData.resize(value.m_dataSize);
259 if (value.m_dataSize > 0 && !buf->getBytes(value.m_rawData.data(), value.m_rawData.size()))
260 return false;
261 value.m_value.addBinary(310, value.m_rawData);
262 return true;
263 }
264
265 DRW_Coord c;
266 c.x = buf->getRawDouble();
267 c.y = buf->getRawDouble();
268 c.z = dimensions == 3 ? buf->getRawDouble() : 0.0;
269 value.m_value.addCoord(11, c);
270
271 const std::uint32_t extraBytes = value.m_dataSize - expectedSize;
272 value.m_rawData.resize(extraBytes);
273 return extraBytes == 0 || buf->getBytes(value.m_rawData.data(), value.m_rawData.size());
274}
275
276bool readTableCadValue(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
277 dwgBuffer *hdlBuf, DRW_CadValue& value) {
278 if (version > DRW::AC1018)
279 value.m_formatFlags = buf->getBitLong();
280
281 value.m_dataType = buf->getBitLong();
282 const bool emptyR2007Value = version > DRW::AC1018 && (value.m_formatFlags & 3);
283 if (!emptyR2007Value) {
284 switch (value.m_dataType) {
285 case 0:
286 case 1:
287 value.m_value.addInt(91, buf->getBitLong());
288 break;
289 case 2:
290 value.m_value.addDouble(140, buf->getBitDouble());
291 break;
292 case 4:
293 case 512:
294 if (!readTableValueBytes(buf, value.m_rawData, "TABLE value byte payload"))
295 return false;
296 value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size());
297 value.m_value.addString(1, decodeTableValueText(version, buf, value.m_rawData));
298 break;
299 case 8: {
300 if (!readTableValueBytes(buf, value.m_rawData, "TABLE value date payload"))
301 return false;
302 value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size());
303 value.m_value.addBinary(310, value.m_rawData);
304 break;
305 }
306 case 16:
307 if (!readTableValuePoint(buf, value, 2))
308 return false;
309 break;
310 case 32:
311 if (!readTableValuePoint(buf, value, 3))
312 return false;
313 break;
314 case 64:
315 value.m_handle = readTableHandle(hdlBuf);
316 value.m_value.addInt(330, static_cast<std::uint32_t>(value.m_handle));
317 break;
318 case 128:
319 case 256:
320 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");
321 return false;
322 default:
323 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");
324 return false;
325 }
326 }
327
328 if (version > DRW::AC1018) {
329 dwgBuffer *textBuf = strBuf ? strBuf : buf;
330 value.m_unitType = buf->getBitLong();
331 value.m_formatString = readTableText(version, textBuf);
332 value.m_valueString = readTableText(version, textBuf);
333 }
334
335 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
336 if (!good) {
337 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);
338 DRW_DBG(" type: ")DRW_dbg::dbg(" type: "); DRW_DBG(value.m_dataType)DRW_dbg::dbg(value.m_dataType);
339 DRW_DBG(" unit: ")DRW_dbg::dbg(" unit: "); DRW_DBG(value.m_unitType)DRW_dbg::dbg(value.m_unitType);
340 DRW_DBG(" bufGood: ")DRW_dbg::dbg(" bufGood: "); DRW_DBG(buf->isGood() ? 1 : 0)DRW_dbg::dbg(buf->isGood() ? 1 : 0);
341 DRW_DBG(" strGood: ")DRW_dbg::dbg(" strGood: "); DRW_DBG((!strBuf || strBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!strBuf || strBuf->isGood()) ? 1 : 0);
342 DRW_DBG(" hdlGood: ")DRW_dbg::dbg(" hdlGood: "); DRW_DBG((!hdlBuf || hdlBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!hdlBuf || hdlBuf->isGood()) ? 1 : 0);
343 DRW_DBG(" bufPos: ")DRW_dbg::dbg(" bufPos: "); DRW_DBG(buf->getPosition())DRW_dbg::dbg(buf->getPosition());
344 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);
345 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);
346 DRW_DBG("\n")DRW_dbg::dbg("\n");
347 }
348 return good;
349}
350
351bool skipTableCustomData(DRW::Version version, dwgBuffer *buf,
352 dwgBuffer *strBuf, dwgBuffer *hdlBuf) {
353 dwgBuffer *textBuf = strBuf ? strBuf : buf;
354 UTF8STRINGstd::string key = readTableText(version, textBuf);
355 if (strBuf && !strBuf->isGood()) {
356 DRW_DBG("TABLE custom data key string read failed\n")DRW_dbg::dbg("TABLE custom data key string read failed\n");
357 return false;
358 }
359 DRW_CadValue value;
360 const bool good = readTableCadValue(version, buf, strBuf, hdlBuf, value);
361 if (!good) {
362 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");
363 }
364 return good;
365}
366
367void readTableCmColor(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf) {
368 dwgBuffer *textBuf = strBuf ? strBuf : buf;
369 if (version < DRW::AC1018) {
370 buf->getSBitShort();
371 return;
372 }
373
374 buf->getBitShort();
375 const std::uint32_t rgb = buf->getBitLong();
376 const std::uint8_t colorFlags = buf->getRawChar8();
377 DRW_DBG("\ntype COLOR: ")DRW_dbg::dbg("\ntype COLOR: "); DRW_DBGH(rgb >> 24)DRW_dbg::dbgH(rgb >> 24);
378 DRW_DBG("\nRGB COLOR: ")DRW_dbg::dbg("\nRGB COLOR: "); DRW_DBGH(rgb)DRW_dbg::dbgH(rgb);
379 DRW_DBG("\nbyte COLOR: ")DRW_dbg::dbg("\nbyte COLOR: "); DRW_DBGH(colorFlags)DRW_dbg::dbgH(colorFlags);
380 if (colorFlags & 1)
381 readTableText(version, textBuf);
382 if (colorFlags & 2)
383 readTableText(version, textBuf);
384}
385
386bool skipR2007TableCellOverrides(DRW::Version version, dwgBuffer *buf,
387 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
388 DRW_TableCell& cell,
389 std::vector<DRW_DwgSubrecordRange> *ranges) {
390 const std::uint64_t startBit = currentDwgBit(buf);
391 cell.m_overrideFlags = static_cast<std::uint32_t>(buf->getBitLong());
392 cell.m_virtualEdgeFlags = buf->getRawChar8();
393
394 if (cell.m_overrideFlags & 0x00001)
395 buf->getRawShort16();
396 if (cell.m_overrideFlags & 0x00002)
397 buf->getBit();
398 if (cell.m_overrideFlags & 0x00004)
399 readTableCmColor(version, buf, strBuf);
400 if (cell.m_overrideFlags & 0x00008)
401 readTableCmColor(version, buf, strBuf);
402 if (cell.m_overrideFlags & 0x00010)
403 cell.m_textStyleOverrideHandle = readTableHandle(hdlBuf);
404 if (cell.m_overrideFlags & 0x00020)
405 buf->getBitDouble();
406 if (cell.m_overrideFlags & 0x00040)
407 readTableCmColor(version, buf, strBuf);
408 if (cell.m_overrideFlags & 0x00400)
409 buf->getBitShort();
410 if (cell.m_overrideFlags & 0x04000)
411 buf->getBitShort();
412 if (cell.m_overrideFlags & 0x00080)
413 readTableCmColor(version, buf, strBuf);
414 if (cell.m_overrideFlags & 0x00800)
415 buf->getBitShort();
416 if (cell.m_overrideFlags & 0x08000)
417 buf->getBitShort();
418 if (cell.m_overrideFlags & 0x00100)
419 readTableCmColor(version, buf, strBuf);
420 if (cell.m_overrideFlags & 0x01000)
421 buf->getBitShort();
422 if (cell.m_overrideFlags & 0x10000)
423 buf->getBitShort();
424 if (cell.m_overrideFlags & 0x00200)
425 readTableCmColor(version, buf, strBuf);
426 if (cell.m_overrideFlags & 0x02000)
427 buf->getBitShort();
428 if (cell.m_overrideFlags & 0x20000)
429 buf->getBitShort();
430
431 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
432 if (ranges != nullptr) {
433 ranges->push_back(makeDwgSubrecordRange(
434 "r2007-table-cell-overrides", startBit, currentDwgBit(buf),
435 version, cell.m_overrideFlags, good));
436 }
437 return good;
438}
439
440bool parseR2007TableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
441 dwgBuffer *hdlBuf, DRW_TableCell& cell,
442 std::vector<DRW_DwgSubrecordRange> *ranges) {
443 dwgBuffer *textBuf = strBuf ? strBuf : buf;
444 cell.m_type = buf->getBitShort();
445 cell.m_edgeFlags = buf->getRawChar8();
446 cell.m_isMerged = buf->getBit() != 0;
447 cell.m_autoFit = buf->getBit() != 0;
448 cell.m_mergedWidth = buf->getBitLong();
449 cell.m_mergedHeight = buf->getBitLong();
450 cell.m_rotation = buf->getBitDouble();
451 cell.m_valueHandle = readTableHandle(hdlBuf);
452
453 if (cell.m_type == 1) {
454 cell.m_textStyleHandle = cell.m_valueHandle;
455 if (cell.m_textStyleHandle == 0 && version < DRW::AC1021) {
456 DRW_TableCellContent content;
457 content.m_type = 1;
458 content.m_text = readTableText(version, textBuf);
459 content.m_value.m_dataType = 4;
460 content.m_value.m_value.addString(1, content.m_text);
461 cell.m_contents.push_back(content);
462 }
463 } else if (cell.m_type == 2) {
464 cell.m_blockHandle = cell.m_valueHandle;
465 cell.m_blockScale = buf->getBitDouble();
466 if (buf->getBit() != 0) {
467 const std::uint16_t numAttributes = buf->getBitShort();
468 cell.m_attributes.reserve(numAttributes);
469 for (std::uint16_t i = 0; i < numAttributes; ++i) {
470 DRW_TableCellAttribute attribute;
471 attribute.m_attdefHandle = readTableHandle(hdlBuf);
472 attribute.m_index = buf->getBitShort();
473 attribute.m_text = readTableText(version, textBuf);
474 cell.m_attributes.push_back(attribute);
475 }
476 }
477
478 DRW_TableCellContent content;
479 content.m_type = 4;
480 content.m_handle = cell.m_blockHandle;
481 cell.m_contents.push_back(content);
482 }
483
484 if (buf->getBit() != 0
485 && !skipR2007TableCellOverrides(version, buf, strBuf, hdlBuf, cell, ranges))
486 return false;
487
488 if (version > DRW::AC1018) {
489 buf->getBitLong();
490 DRW_TableCellContent content;
491 content.m_type = 1;
492 if (!readTableCadValue(version, buf, strBuf, hdlBuf, content.m_value))
493 return false;
494 if (content.m_value.m_value.type() == DRW_Variant::STRING)
495 content.m_text = content.m_value.m_value.c_str();
496 else if (!content.m_value.m_valueString.empty())
497 content.m_text = content.m_value.m_valueString;
498 cell.m_contents.push_back(content);
499 }
500
501 return buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
502}
503
504bool skipR2007TableOverrides(DRW::Version version, dwgBuffer *buf,
505 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
506 std::vector<DRW_DwgSubrecordRange> *ranges = nullptr) {
507 const std::uint64_t startBit = currentDwgBit(buf);
508 std::uint32_t maskCount = 0;
509 if (buf->getBit() != 0) {
510 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
511 ++maskCount;
512 if (flags & 0x000001)
513 buf->getBit();
514 if (flags & 0x000004)
515 buf->getBitShort();
516 if (flags & 0x000008)
517 buf->getBitDouble();
518 if (flags & 0x000010)
519 buf->getBitDouble();
520 if (flags & 0x000020)
521 readTableCmColor(version, buf, strBuf);
522 if (flags & 0x000040)
523 readTableCmColor(version, buf, strBuf);
524 if (flags & 0x000080)
525 readTableCmColor(version, buf, strBuf);
526 if (flags & 0x000100)
527 buf->getBit();
528 if (flags & 0x000200)
529 buf->getBit();
530 if (flags & 0x000400)
531 buf->getBit();
532 if (flags & 0x000800)
533 readTableCmColor(version, buf, strBuf);
534 if (flags & 0x001000)
535 readTableCmColor(version, buf, strBuf);
536 if (flags & 0x002000)
537 readTableCmColor(version, buf, strBuf);
538 if (flags & 0x004000)
539 buf->getBitShort();
540 if (flags & 0x008000)
541 buf->getBitShort();
542 if (flags & 0x010000)
543 buf->getBitShort();
544 if (flags & 0x020000)
545 readTableHandle(hdlBuf);
546 if (flags & 0x040000)
547 readTableHandle(hdlBuf);
548 if (flags & 0x080000)
549 readTableHandle(hdlBuf);
550 if (flags & 0x100000)
551 buf->getBitDouble();
552 if (flags & 0x200000)
553 buf->getBitDouble();
554 if (flags & 0x400000)
555 buf->getBitDouble();
556 }
557
558 if (buf->getBit() != 0) {
559 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
560 ++maskCount;
561 for (int i = 0; i < 18; ++i) {
562 if (flags & (1u << i))
563 readTableCmColor(version, buf, strBuf);
564 }
565 }
566
567 if (buf->getBit() != 0) {
568 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
569 ++maskCount;
570 for (int i = 0; i < 18; ++i) {
571 if (flags & (1u << i))
572 buf->getBitShort();
573 }
574 }
575
576 if (buf->getBit() != 0) {
577 const std::uint32_t flags = static_cast<std::uint32_t>(buf->getBitLong());
578 ++maskCount;
579 for (int i = 0; i < 18; ++i) {
580 if (flags & (1u << i))
581 buf->getBitShort();
582 }
583 }
584
585 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
586 if (ranges != nullptr && (maskCount != 0 || currentDwgBit(buf) != startBit)) {
587 ranges->push_back(makeDwgSubrecordRange(
588 "r2007-table-overrides", startBit, currentDwgBit(buf),
589 version, maskCount, good));
590 }
591 return good;
592}
593
594bool skipTableContentFormat(DRW::Version version, dwgBuffer *buf,
595 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
596 std::vector<DRW_DwgSubrecordRange> *ranges = nullptr) {
597 const std::uint64_t startBit = currentDwgBit(buf);
598 dwgBuffer *textBuf = strBuf ? strBuf : buf;
599 buf->getBitLong(); // property override flags
600 buf->getBitLong(); // property flags
601 buf->getBitLong(); // value data type
602 buf->getBitLong(); // value unit type
603 readTableText(version, textBuf);
604 buf->getBitDouble(); // rotation
605 buf->getBitDouble(); // block scale
606 buf->getBitLong(); // alignment
607 std::int32_t rgb = -1;
608 UTF8STRINGstd::string name;
609 UTF8STRINGstd::string book;
610 buf->getCmColor(version, &rgb, textBuf, &name, &book);
611 readTableHandle(hdlBuf); // text style
612 buf->getBitDouble(); // text height
613 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
614 if (ranges != nullptr) {
615 ranges->push_back(makeDwgSubrecordRange(
616 "table-content-format", startBit, currentDwgBit(buf),
617 version, 1, good));
618 }
619 return good;
620}
621
622bool skipTableCellStyle(DRW::Version version, dwgBuffer *buf,
623 dwgBuffer *strBuf, dwgBuffer *hdlBuf,
624 std::vector<DRW_DwgSubrecordRange> *ranges = nullptr) {
625 const std::uint64_t startBit = currentDwgBit(buf);
626 buf->getBitLong(); // style type
627 const bool hasData = buf->getBitShort() != 0;
628 if (!hasData) {
629 if (ranges != nullptr) {
630 ranges->push_back(makeDwgSubrecordRange(
631 "table-cell-style", startBit, currentDwgBit(buf),
632 version, 0, buf->isGood()));
633 }
634 return buf->isGood();
635 }
636
637 buf->getBitLong(); // property override flags
638 buf->getBitLong(); // merge flags
639 std::int32_t rgb = -1;
640 UTF8STRINGstd::string name;
641 UTF8STRINGstd::string book;
642 dwgBuffer *textBuf = strBuf ? strBuf : buf;
643 buf->getCmColor(version, &rgb, textBuf, &name, &book);
644 buf->getBitLong(); // content layout
645 if (!skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges))
646 return false;
647
648 const std::uint16_t marginFlags = buf->getBitShort();
649 if (marginFlags != 0) {
650 for (int i = 0; i < 6; ++i)
651 buf->getBitDouble();
652 }
653
654 const std::uint32_t borders = buf->getBitLong();
655 if (borders > 6) {
656 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");
657 return false;
658 }
659 for (std::uint32_t i = 0; i < borders; ++i) {
660 const std::uint32_t edgeFlags = buf->getBitLong();
661 if (edgeFlags == 0)
662 continue;
663 buf->getBitLong(); // border overrides
664 buf->getBitLong(); // border type
665 buf->getCmColor(version, &rgb, textBuf, &name, &book);
666 buf->getBitLong(); // line weight
667 readTableHandle(hdlBuf); // linetype
668 buf->getBitLong(); // visible/invisible
669 buf->getBitDouble(); // double line spacing
670 }
671
672 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
673 if (ranges != nullptr) {
674 ranges->push_back(makeDwgSubrecordRange(
675 "table-cell-style", startBit, currentDwgBit(buf),
676 version, borders, good));
677 }
678 return good;
679}
680
681bool parseTableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
682 dwgBuffer *hdlBuf, DRW_TableCell& cell,
683 std::vector<DRW_DwgSubrecordRange> *ranges) {
684 dwgBuffer *textBuf = strBuf ? strBuf : buf;
685 cell.m_flags = buf->getBitLong();
686 cell.m_toolTip = readTableText(version, textBuf);
687 if (strBuf && !strBuf->isGood()) {
688 DRW_DBG("TABLE cell tooltip string read failed\n")DRW_dbg::dbg("TABLE cell tooltip string read failed\n");
689 return false;
690 }
691 buf->getBitLong(); // custom data
692
693 const std::uint32_t customItems = buf->getBitLong();
694 if (customItems > kMaxTableItems) {
695 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");
696 return false;
697 }
698 for (std::uint32_t i = 0; i < customItems; ++i) {
699 if (!skipTableCustomData(version, buf, strBuf, hdlBuf)) {
700 DRW_DBG("TABLE cell custom data parse incomplete\n")DRW_dbg::dbg("TABLE cell custom data parse incomplete\n");
701 return false;
702 }
703 }
704
705 if (buf->getBitLong() != 0) {
706 readTableHandle(hdlBuf);
707 buf->getBitLong();
708 buf->getBitLong();
709 buf->getBitLong();
710 }
711
712 const std::uint32_t contentCount = buf->getBitLong();
713 if (contentCount > kMaxTableItems) {
714 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");
715 return false;
716 }
717 cell.m_contents.reserve(contentCount);
718 for (std::uint32_t i = 0; i < contentCount; ++i) {
719 DRW_TableCellContent content;
720 content.m_type = buf->getBitLong();
721 if (content.m_type == 1) {
722 if (!readTableCadValue(version, buf, strBuf, hdlBuf, content.m_value)) {
723 DRW_DBG("TABLE cell value parse incomplete\n")DRW_dbg::dbg("TABLE cell value parse incomplete\n");
724 return false;
725 }
726 if (content.m_value.m_value.type() == DRW_Variant::STRING)
727 content.m_text = content.m_value.m_value.c_str();
728 else if (!content.m_value.m_valueString.empty())
729 content.m_text = content.m_value.m_valueString;
730 } else if (content.m_type == 2 || content.m_type == 4) {
731 content.m_handle = readTableHandle(hdlBuf);
732 }
733
734 const std::uint32_t numAttrs = buf->getBitLong();
735 if (numAttrs > kMaxTableItems) {
736 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");
737 return false;
738 }
739 for (std::uint32_t attr = 0; attr < numAttrs; ++attr) {
740 readTableHandle(hdlBuf);
741 readTableText(version, textBuf);
742 buf->getBitLong();
743 }
744
745 const bool hasContentFormat = buf->getBitShort() != 0;
746 if (hasContentFormat
747 && !skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges)) {
748 DRW_DBG("TABLE cell content format parse incomplete\n")DRW_dbg::dbg("TABLE cell content format parse incomplete\n");
749 return false;
750 }
751 cell.m_contents.push_back(content);
752 }
753
754 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, ranges)) {
755 DRW_DBG("TABLE cell style override parse incomplete\n")DRW_dbg::dbg("TABLE cell style override parse incomplete\n");
756 return false;
757 }
758
759 cell.m_styleId = buf->getBitLong();
760 const std::uint64_t geometryStartBit = currentDwgBit(buf);
761 const std::uint32_t hasGeometry = buf->getBitLong();
762 if (hasGeometry != 0) {
763 buf->getBitLong(); // unknown AC1027+ geometry marker
764 cell.m_width = buf->getBitDouble();
765 cell.m_height = buf->getBitDouble();
766 cell.m_geometryFlags = buf->getBitLong();
767 cell.m_geometryHandle = readTableHandle(hdlBuf);
768 if (cell.m_geometryFlags != 0) {
769 cell.m_geometryTopLeft = buf->get3BitDouble();
770 cell.m_geometryCenter = buf->get3BitDouble();
771 cell.m_contentWidth = buf->getBitDouble();
772 cell.m_contentHeight = buf->getBitDouble();
773 cell.m_geometryWidth = buf->getBitDouble();
774 cell.m_geometryHeight = buf->getBitDouble();
775 cell.m_geometryRecordFlags = buf->getBitLong();
776 }
777 if (ranges != nullptr) {
778 const bool geometryGood = buf->isGood() && (!hdlBuf || hdlBuf->isGood());
779 ranges->push_back(makeDwgSubrecordRange(
780 "table-cell-geometry-tail", geometryStartBit, currentDwgBit(buf),
781 version, cell.m_geometryFlags, geometryGood));
782 }
783 }
784
785 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
786 if (!good)
787 DRW_DBG("TABLE cell stream ended unexpectedly\n")DRW_dbg::dbg("TABLE cell stream ended unexpectedly\n");
788 return good;
789}
790
791bool parseTableContent(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf,
792 dwgBuffer *hdlBuf, DRW_TableContent& content) {
793 dwgBuffer *textBuf = strBuf ? strBuf : buf;
794 content.m_name = readTableText(version, textBuf);
795 content.m_description = readTableText(version, textBuf);
796
797 const std::uint32_t columns = buf->getBitLong();
798 if (columns > kMaxTableColumns) {
799 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");
800 return false;
801 }
802 content.m_columns.clear();
803 content.m_columns.reserve(columns);
804 for (std::uint32_t col = 0; col < columns; ++col) {
805 DRW_TableColumn column;
806 column.m_name = readTableText(version, textBuf);
807 buf->getBitLong(); // custom data
808 const std::uint32_t customItems = buf->getBitLong();
809 if (customItems > kMaxTableItems) {
810 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");
811 return false;
812 }
813 for (std::uint32_t i = 0; i < customItems; ++i) {
814 if (!skipTableCustomData(version, buf, strBuf, hdlBuf)) {
815 DRW_DBG("TABLECONTENT column custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column custom data parse incomplete\n"
)
;
816 return false;
817 }
818 }
819 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf,
820 &content.m_subrecordRanges)) {
821 DRW_DBG("TABLECONTENT column cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column cell style parse incomplete\n"
)
;
822 return false;
823 }
824 buf->getBitLong(); // style id
825 column.m_width = buf->getBitDouble();
826 content.m_columns.push_back(column);
827 }
828
829 const std::uint32_t rows = buf->getBitLong();
830 if (rows > kMaxTableRows || (columns != 0 && rows > kMaxTableCells / columns)) {
831 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");
832 return false;
833 }
834 content.m_rows.clear();
835 content.m_rows.reserve(rows);
836 for (std::uint32_t rowIndex = 0; rowIndex < rows; ++rowIndex) {
837 DRW_TableRow row;
838 const std::uint32_t cells = buf->getBitLong();
839 if (cells > kMaxTableColumns || cells > kMaxTableItems) {
840 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");
841 return false;
842 }
843 row.m_cells.reserve(cells);
844 for (std::uint32_t cellIndex = 0; cellIndex < cells; ++cellIndex) {
845 DRW_TableCell cell;
846 if (!parseTableCell(version, buf, strBuf, hdlBuf, cell,
847 &content.m_subrecordRanges)) {
848 DRW_DBG("TABLECONTENT cell parse incomplete at row ")DRW_dbg::dbg("TABLECONTENT cell parse incomplete at row "); DRW_DBG(rowIndex)DRW_dbg::dbg(rowIndex);
849 DRW_DBG(" cell ")DRW_dbg::dbg(" cell "); DRW_DBG(cellIndex)DRW_dbg::dbg(cellIndex); DRW_DBG("\n")DRW_dbg::dbg("\n");
850 return false;
851 }
852 row.m_cells.push_back(cell);
853 }
854
855 buf->getBitLong(); // custom data
856 const std::uint32_t customItems = buf->getBitLong();
857 if (customItems > kMaxTableItems) {
858 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");
859 return false;
860 }
861 for (std::uint32_t i = 0; i < customItems; ++i) {
862 if (!skipTableCustomData(version, buf, strBuf, hdlBuf)) {
863 DRW_DBG("TABLECONTENT row custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row custom data parse incomplete\n"
)
;
864 return false;
865 }
866 }
867 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf,
868 &content.m_subrecordRanges)) {
869 DRW_DBG("TABLECONTENT row cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row cell style parse incomplete\n"
)
;
870 return false;
871 }
872 buf->getBitLong(); // style id
873 row.m_height = buf->getBitDouble();
874 content.m_rows.push_back(row);
875 }
876
877 const std::uint32_t fieldRefs = buf->getBitLong();
878 if (fieldRefs > kMaxTableItems) {
879 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");
880 return false;
881 }
882 content.m_fieldHandles.clear();
883 content.m_fieldHandles.reserve(fieldRefs);
884 for (std::uint32_t i = 0; i < fieldRefs; ++i) {
885 const std::uint32_t ref = readTableHandle(hdlBuf);
886 if (ref != 0)
887 content.m_fieldHandles.push_back(ref);
888 }
889
890 if (!skipTableCellStyle(version, buf, strBuf, hdlBuf,
891 &content.m_subrecordRanges)) {
892 DRW_DBG("TABLECONTENT table cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT table cell style parse incomplete\n"
)
;
893 return false;
894 }
895
896 const std::uint32_t mergedRanges = buf->getBitLong();
897 if (mergedRanges > kMaxTableItems) {
898 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");
899 return false;
900 }
901 content.m_mergedRanges.clear();
902 content.m_mergedRanges.reserve(mergedRanges);
903 for (std::uint32_t i = 0; i < mergedRanges; ++i) {
904 DRW_TableMergedRange range;
905 range.m_topRow = buf->getBitLong();
906 range.m_leftColumn = buf->getBitLong();
907 range.m_bottomRow = buf->getBitLong();
908 range.m_rightColumn = buf->getBitLong();
909 content.m_mergedRanges.push_back(range);
910 }
911
912 content.m_tableStyleHandle = readTableHandle(hdlBuf);
913 const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood());
914 if (!good)
915 DRW_DBG("TABLECONTENT stream ended unexpectedly\n")DRW_dbg::dbg("TABLECONTENT stream ended unexpectedly\n");
916 return good;
917}
918
919} // namespace
920
921//! Calculate arbitrary axis
922/*!
923* Calculate arbitrary axis for apply extrusions
924* @author Rallaz
925*/
926void DRW_Entity::calculateAxis(DRW_Coord extPoint){
927 //Follow the arbitrary DXF definitions for extrusion axes.
928 if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625) {
929 //If we get here, implement Ax = Wy x N where Wy is [0,1,0] per the DXF spec.
930 //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
931 //Factoring in the fixed values for Wy gives N.z,0,-N.x
932 extAxisX.x = extPoint.z;
933 extAxisX.y = 0;
934 extAxisX.z = -extPoint.x;
935 } else {
936 //Otherwise, implement Ax = Wz x N where Wz is [0,0,1] per the DXF spec.
937 //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
938 //Factoring in the fixed values for Wz gives -N.y,N.x,0.
939 extAxisX.x = -extPoint.y;
940 extAxisX.y = extPoint.x;
941 extAxisX.z = 0;
942 }
943
944 extAxisX.unitize();
945
946 //Ay = N x Ax
947 extAxisY.x = (extPoint.y * extAxisX.z) - (extAxisX.y * extPoint.z);
948 extAxisY.y = (extPoint.z * extAxisX.x) - (extAxisX.z * extPoint.x);
949 extAxisY.z = (extPoint.x * extAxisX.y) - (extAxisX.x * extPoint.y);
950
951 extAxisY.unitize();
952}
953
954//! Extrude a point using arbitrary axis
955/*!
956* apply extrusion in a point using arbitrary axis (previous calculated)
957* @author Rallaz
958*/
959void DRW_Entity::extrudePoint(DRW_Coord extPoint, DRW_Coord *point){
960 double px, py, pz;
961 px = (extAxisX.x*point->x)+(extAxisY.x*point->y)+(extPoint.x*point->z);
962 py = (extAxisX.y*point->x)+(extAxisY.y*point->y)+(extPoint.y*point->z);
963 pz = (extAxisX.z*point->x)+(extAxisY.z*point->y)+(extPoint.z*point->z);
964
965 point->x = px;
966 point->y = py;
967 point->z = pz;
968}
969
970bool DRW_Entity::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
971 switch (code) {
972 case DRW::dxfCode::HANDLE:
973 handle = reader->getHandleString();
974 break;
975 case DRW::dxfCode::OWNER_HANDLE:
976 parentHandle = reader->getHandleString();
977 break;
978 case DRW::dxfCode::LAYER:
979 layer = reader->getUtf8String();
980 break;
981 case 6:
982 lineType = reader->getUtf8String();
983 break;
984 case DRW::dxfCode::COLOR:
985 color = reader->getInt32();
986 break;
987 case DRW::dxfCode::LINEWEIGHT:
988 lWeight = DRW_LW_Conv::dxfInt2lineWidth(reader->getInt32());
989 break;
990 case 48:
991 ltypeScale = reader->getDouble();
992 break;
993 case DRW::dxfCode::INVISIBLE:
994 visible = (reader->getInt32() & 1) == 0;
995 break;
996 case 420:
997 color24 = reader->getInt32();
998 break;
999 case 430:
1000 colorName = reader->getString();
1001 break;
1002 case 67:
1003 space = static_cast<DRW::Space>(reader->getInt32());
1004 break;
1005 case 102:
1006 return parseDxfGroups(code, reader);
1007 case 284:
1008 shadow = static_cast<DRW::ShadowMode>(reader->getInt32() & 0x3);
1009 break;
1010 case 347:
1011 material = static_cast<std::uint32_t>(reader->getHandleString());
1012 break;
1013 case DRW::dxfCode::PLOTSTYLE:
1014 plotStyle = reader->getHandleString();
1015 break;
1016 case 440:
1017 transparency = reader->getInt32();
1018 break;
1019 case 92:
1020 case 160:
1021 // Proxy entity graphics byte count (ODA §20.4.95): 92 for R13–R2007,
1022 // 160 for R2010+. Introduces the 310 hex chunks below; gating the 310
1023 // capture on this keeps unrelated binary-310 streams out of the proxy
1024 // buffer. (Entities that repurpose 92 — e.g. MESH — handle it in their
1025 // own parseCode and never reach here.)
1026 numProxyGraph = reader->getInt32();
1027 break;
1028 case 310:
1029 if (numProxyGraph != 0) {
1030 // Proxy graphics binary, hex-encoded across many ≤254-char chunks.
1031 const std::string& hex = reader->getString();
1032 proxyGraphics.reserve(proxyGraphics.size() + hex.size() / 2);
1033 auto hexVal = [](char c) -> int {
1034 if (c >= '0' && c <= '9') return c - '0';
1035 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
1036 if (c >= 'A' && c <= 'F') return c - 'A' + 10;
1037 return -1;
1038 };
1039 for (std::size_t i = 0; i + 1 < hex.size(); i += 2) {
1040 int hi = hexVal(hex[i]), lo = hexVal(hex[i + 1]);
1041 if (hi < 0 || lo < 0) break;
1042 proxyGraphics.push_back(static_cast<char>((hi << 4) | lo));
1043 }
1044 }
1045 break;
1046 case 1000:
1047 case 1001:
1048 case 1002:
1049 case 1003:
1050 case 1004:
1051 case 1005:
1052 extData.push_back(std::make_shared<DRW_Variant>(code, reader->getString()));
1053 break;
1054 case 1010:
1055 case 1011:
1056 case 1012:
1057 case 1013:
1058 curr =std::make_shared<DRW_Variant>(code, DRW_Coord(reader->getDouble(), 0.0, 0.0));
1059 extData.push_back(curr);
1060 break;
1061 case 1020:
1062 case 1021:
1063 case 1022:
1064 case 1023:
1065 if (curr)
1066 curr->setCoordY(reader->getDouble());
1067 break;
1068 case 1030:
1069 case 1031:
1070 case 1032:
1071 case 1033:
1072 if (curr)
1073 curr->setCoordZ(reader->getDouble());
1074 //FIXME, why do we discard curr right after setting the its Z
1075// curr=NULL;
1076 break;
1077 case 1040:
1078 case 1041:
1079 case 1042:
1080 extData.push_back(std::make_shared<DRW_Variant>(code, reader->getDouble() ));
1081 break;
1082 case 1070:
1083 case 1071:
1084 extData.push_back(std::make_shared<DRW_Variant>(code, reader->getInt32() ));
1085 break;
1086 default:
1087 break;
1088 }
1089 return true;
1090}
1091
1092//parses dxf 102 groups to read entity
1093bool DRW_Entity::parseDxfGroups(int code, const std::unique_ptr<dxfReader>& reader){
1094 std::list<DRW_Variant> ls;
1095 DRW_Variant curr;
1096 std::string appName= reader->getString();
1097 bool complete = true;
1098 if (!appName.empty() && appName.at(0)== '{') {
1099 curr.addString(code, appName.substr(1));
1100 ls.push_back(curr);
1101 int depth = 1;
1102 int nextCode = 0;
1103 while (depth > 0 && reader->readRec(&nextCode)) {
1104 DRW_Variant value;
1105 if (nextCode == 102) {
1106 std::string marker = reader->getString();
1107 value.addString(nextCode, marker);
1108 if (!marker.empty() && marker.at(0) == '{')
1109 ++depth;
1110 else if (!marker.empty() && marker.at(0) == '}')
1111 --depth;
1112 } else if ((nextCode >= 320 && nextCode <= 369)
1113 || (nextCode >= 390 && nextCode <= 399)
1114 || nextCode == 480 || nextCode == 481
1115 || nextCode == 1005) {
1116 value.addString(nextCode, reader->getString());
1117 } else {
1118 switch (reader->type) {
1119 case dxfReader::STRING:
1120 case dxfReader::BINARY:
1121 value.addString(nextCode, reader->getString());
1122 break;
1123 case dxfReader::INT32:
1124 case dxfReader::BOOL:
1125 value.addInt(nextCode, reader->getInt32());
1126 break;
1127 case dxfReader::INT64:
1128 value.addInt64(nextCode, static_cast<std::int64_t>(reader->getInt64()));
1129 break;
1130 case dxfReader::DOUBLE:
1131 value.addDouble(nextCode, reader->getDouble());
1132 break;
1133 default:
1134 break;
1135 }
1136 }
1137 ls.push_back(value);
1138 }
1139 complete = depth == 0;
1140 }
1141
1142 appData.push_back(ls);
1143 return complete;
1144}
1145
1146bool DRW_Entity::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer* strBuf, std::uint32_t bs){
1147 objSize=0;
1148 DRW_DBG("\n***************************** parsing entity *********************************************\n")DRW_dbg::dbg("\n***************************** parsing entity *********************************************\n"
)
;
1149 oType = buf->getObjType(version);
1150 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);
1151
1152 if (version > DRW::AC1014 && version < DRW::AC1024) {//2000 & 2004
1153 objSize = buf->getRawLong32(); //RL 32bits object size in bits
1154 DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n");
1155 }
1156 if (version > DRW::AC1021) {//2010+
1157 std::uint32_t ms = buf->size();
1158 // Clamp: a corrupt bs > ms*8 would underflow objSize (unsigned) to a
1159 // huge value and drive strBuf->moveBitPos(objSize-1) past the buffer.
1160 objSize = (bs <= ms*8u) ? ms*8u - bs : 0u;
1161 DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n");
1162 }
1163
1164 if (strBuf != NULL__null && version > DRW::AC1018) {//2007+
1165 strBuf->moveBitPos(objSize-1);
1166 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");
1167 if (strBuf->getBit() == 1){
1168 DRW_DBG("DRW_TableEntry::parseDwg string bit is 1\n")DRW_dbg::dbg("DRW_TableEntry::parseDwg string bit is 1\n");
1169 strBuf->moveBitPos(-17);
1170 std::uint16_t strDataSize = strBuf->getRawShort16();
1171 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");
1172 if ( (strDataSize& 0x8000) == 0x8000){
1173 DRW_DBG("\nDRW_TableEntry::parseDwg string 0x8000 bit is set")DRW_dbg::dbg("\nDRW_TableEntry::parseDwg string 0x8000 bit is set"
)
;
1174 strBuf->moveBitPos(-32);
1175 std::uint16_t hiSize = strBuf->getRawShort16();
1176 strDataSize = ((strDataSize&0x7fff) | (hiSize<<15));
1177 }
1178 strBuf->moveBitPos( -strDataSize -16); //-14
1179 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");
1180 } else
1181 DRW_DBG("\nDRW_TableEntry::parseDwg string bit is 0")DRW_dbg::dbg("\nDRW_TableEntry::parseDwg string bit is 0");
1182 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");
1183 }
1184
1185 dwgHandle ho = buf->getHandle();
1186 handle = ho.ref;
1187 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);
1188 // ODA DWG spec §28 "Extended Entity Data". The outer loop yields one
1189 // BS-prefixed byte chunk per APPID-attached group; size==0 terminates.
1190 // Each chunk's payload is a sequence of (1-byte type code + value)
1191 // items; we walk it with a nested loop and push DRW_Variant entries
1192 // into @ref extData. Handle-typed items (type 3 layer-ref, type 5
1193 // entity-ref) and the per-chunk APPID handle are resolved post-hoc
1194 // in dwgReader::parseAttribs once the symbol tables are available.
1195 std::uint16_t extDataSize = buf->getBitShort(); //BS (unsigned: a >32767 chunk size must not go negative)
1196 DRW_DBG(" ext data size: ")DRW_dbg::dbg(" ext data size: "); DRW_DBG(extDataSize)DRW_dbg::dbg(extDataSize);
1197 while (extDataSize>0 && buf->isGood()) {
1198 dwgHandle ah = buf->getHandle();
1199 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);
1200 std::vector<std::uint8_t> tmpExtData(static_cast<std::size_t>(extDataSize));
1201 if (!buf->getBytes(tmpExtData.data(), extDataSize))
1202 return false;
1203 dwgBuffer tmpExtDataBuf(tmpExtData.data(), extDataSize, buf->decoder);
1204
1205 // Placeholder for the APPID name (DXF group 1001). Filled in by
1206 // parseAttribs from appIdmap; falls back to ACAD_<hex> if unknown.
1207 extData.push_back(std::make_shared<DRW_Variant>(1001, std::string{}));
1208 pendingAppIdResolutions.push_back({extData.size() - 1, ah.ref});
1209
1210 while (tmpExtDataBuf.numRemainingBytes() > 0 && tmpExtDataBuf.isGood()) {
1211 std::uint8_t dxfCode = tmpExtDataBuf.getRawChar8();
1212 DRW_DBG(" eed type: ")DRW_dbg::dbg(" eed type: "); DRW_DBG(dxfCode)DRW_dbg::dbg(dxfCode);
1213 switch (dxfCode){
1214 case 0: { //string
1215 std::string s;
1216 if (version > DRW::AC1018) { //R2007+
1217 if (tmpExtDataBuf.numRemainingBytes() < 2) break;
1218 std::uint16_t nChars = tmpExtDataBuf.getRawShort16();
1219 DRW_DBG(" EED string nChars: ")DRW_dbg::dbg(" EED string nChars: "); DRW_DBG(nChars)DRW_dbg::dbg(nChars);
1220 if (nChars > 0) {
1221 // R2007+ EED strings are UTF-16LE (nChars 16-bit code units).
1222 std::uint64_t byteLen = static_cast<std::uint64_t>(nChars) * 2;
1223 if ((std::uint64_t)tmpExtDataBuf.numRemainingBytes() < byteLen) break;
1224 std::vector<std::uint8_t> bytes(byteLen);
1225 tmpExtDataBuf.getBytes(bytes.data(), byteLen);
1226 for (std::uint16_t i = 0; i < nChars; ++i) {
1227 std::uint16_t c = static_cast<std::uint16_t>(bytes[2*i]) |
1228 (static_cast<std::uint16_t>(bytes[2*i+1]) << 8);
1229 if (c < 0x80) {
1230 s.push_back(static_cast<char>(c));
1231 } else if (c < 0x800) {
1232 s.push_back(static_cast<char>(0xC0 | (c >> 6)));
1233 s.push_back(static_cast<char>(0x80 | (c & 0x3F)));
1234 } else {
1235 s.push_back(static_cast<char>(0xE0 | (c >> 12)));
1236 s.push_back(static_cast<char>(0x80 | ((c >> 6) & 0x3F)));
1237 s.push_back(static_cast<char>(0x80 | (c & 0x3F)));
1238 }
1239 }
1240 }
1241 } else { //R13–R2004: 1-byte len + 2-byte BE codepage hint + bytes (+NUL)
1242 if (tmpExtDataBuf.numRemainingBytes() < 3) break;
1243 std::uint8_t strLength = tmpExtDataBuf.getRawChar8();
1244 std::uint16_t cp = tmpExtDataBuf.getBERawShort16();
1245 if (strLength > 0 && tmpExtDataBuf.numRemainingBytes() >= strLength) {
1246 std::string raw(strLength, '\0');
1247 tmpExtDataBuf.getBytes(reinterpret_cast<std::uint8_t*>(&raw[0]), strLength);
1248 s = decodeEedString(cp, raw, tmpExtDataBuf.decoder);
1249 }
1250 //consume the optional trailing NUL terminator if present
1251 if (tmpExtDataBuf.numRemainingBytes() > 0) {
1252 tmpExtDataBuf.getRawChar8();
1253 }
1254 }
1255 extData.push_back(std::make_shared<DRW_Variant>(1000, s));
1256 break;
1257 }
1258 case 2: { //control character: 0 = '{', 1 = '}'
1259 if (tmpExtDataBuf.numRemainingBytes() < 1) break;
1260 std::uint8_t ctrl = tmpExtDataBuf.getRawChar8();
1261 extData.push_back(std::make_shared<DRW_Variant>(
1262 1002, std::string(ctrl == 0 ? "{" : "}")));
1263 break;
1264 }
1265 case 3: { //layer-table reference (8 raw BE bytes -> handle)
1266 if (tmpExtDataBuf.numRemainingBytes() < 8) break;
1267 std::uint8_t hb[8];
1268 tmpExtDataBuf.getBytes(hb, 8);
1269 std::uint64_t ref = 0;
1270 for (int i = 0; i < 8; ++i) {
1271 ref = (ref << 8) | hb[i];
1272 }
1273 // Placeholder layer-ref string; resolved post-hoc.
1274 extData.push_back(std::make_shared<DRW_Variant>(
1275 1003, std::string{}, /*isLayerRef=*/true));
1276 pendingLayerRefResolutions.push_back(
1277 {extData.size() - 1, static_cast<std::uint32_t>(ref)});
1278 break;
1279 }
1280 case 4: { //binary chunk: 1-byte length + bytes
1281 if (tmpExtDataBuf.numRemainingBytes() < 1) break;
1282 std::uint8_t binLen = tmpExtDataBuf.getRawChar8();
1283 std::vector<std::uint8_t> bytes(binLen);
1284 if (binLen > 0 && tmpExtDataBuf.numRemainingBytes() >= binLen) {
1285 tmpExtDataBuf.getBytes(bytes.data(), binLen);
1286 }
1287 extData.push_back(std::make_shared<DRW_Variant>(1004, std::move(bytes)));
1288 break;
1289 }
1290 case 5: { //entity-handle reference (8 raw BE bytes -> hex string)
1291 if (tmpExtDataBuf.numRemainingBytes() < 8) break;
1292 std::uint8_t hb[8];
1293 tmpExtDataBuf.getBytes(hb, 8);
1294 std::uint64_t ref = 0;
1295 for (int i = 0; i < 8; ++i) {
1296 ref = (ref << 8) | hb[i];
1297 }
1298 char tmp[24];
1299 std::snprintf(tmp, sizeof(tmp), "%llX",
1300 static_cast<unsigned long long>(ref));
1301 extData.push_back(std::make_shared<DRW_Variant>(1005, std::string{tmp}));
1302 break;
1303 }
1304 case 10: case 11: case 12: case 13: { //3-double point
1305 if (tmpExtDataBuf.numRemainingBytes() < 24) break;
1306 DRW_Coord c;
1307 c.x = tmpExtDataBuf.getRawDouble();
1308 c.y = tmpExtDataBuf.getRawDouble();
1309 c.z = tmpExtDataBuf.getRawDouble();
1310 extData.push_back(std::make_shared<DRW_Variant>(1000 + dxfCode, c));
1311 break;
1312 }
1313 case 40: case 41: case 42: { //real
1314 if (tmpExtDataBuf.numRemainingBytes() < 8) break;
1315 double d = tmpExtDataBuf.getRawDouble();
1316 extData.push_back(std::make_shared<DRW_Variant>(1000 + dxfCode, d));
1317 break;
1318 }
1319 case 70: { //int16
1320 if (tmpExtDataBuf.numRemainingBytes() < 2) break;
1321 std::int16_t i = static_cast<std::int16_t>(tmpExtDataBuf.getRawShort16());
1322 extData.push_back(std::make_shared<DRW_Variant>(1070, static_cast<std::int32_t>(i)));
1323 break;
1324 }
1325 case 71: { //int32
1326 if (tmpExtDataBuf.numRemainingBytes() < 4) break;
1327 std::int32_t i = static_cast<std::int32_t>(tmpExtDataBuf.getRawLong32());
1328 extData.push_back(std::make_shared<DRW_Variant>(1071, i));
1329 break;
1330 }
1331 default:
1332 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");
1333 // Unknown type — bail on this app's chunk; we cannot
1334 // know how many bytes the rest of the item occupies.
1335 tmpExtDataBuf.setPosition(tmpExtDataBuf.size());
1336 break;
1337 }
1338 }
1339 extDataSize = buf->getBitShort(); //BS
1340 DRW_DBG(" ext data size: ")DRW_dbg::dbg(" ext data size: "); DRW_DBG(extDataSize)DRW_dbg::dbg(extDataSize);
1341 } //end parsing extData (EED)
1342 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");
1343 std::uint8_t graphFlag = buf->getBit(); //B
1344 DRW_DBG(" graphFlag: ")DRW_dbg::dbg(" graphFlag: "); DRW_DBG(graphFlag)DRW_dbg::dbg(graphFlag); DRW_DBG("\n")DRW_dbg::dbg("\n");
1345 if (graphFlag) {
1346 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");
1347 const std::uint64_t graphDataSize = (version >= DRW::AC1024)
1348 ? buf->getBitLongLong()
1349 : buf->getRawLong32();
1350 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");
1351 const std::uint64_t maxMoveBytes = static_cast<std::uint64_t>(std::numeric_limits<std::int32_t>::max() / 8);
1352 if (graphDataSize > static_cast<std::uint64_t>(buf->numRemainingBytes())
1353 || graphDataSize > maxMoveBytes) {
1354 DRW_DBG("graphData size outside object body\n")DRW_dbg::dbg("graphData size outside object body\n");
1355 return false;
1356 }
1357 // Capture the proxy-graphics byte stream instead of skipping it. These
1358 // are cached drawable primitives (lines/arcs/polylines/text) that any
1359 // reader can render for proxy/custom entities (STDPART2D, AEC_*, tables)
1360 // — previously discarded via moveBitPos, leaving proxyGraphics empty.
1361 // dwgBuffer::getBytes is bit-aware (reconstructs each byte at a non-zero
1362 // bitPos), so it lands at the exact same position moveBitPos(8N) did.
1363 // (write-review #32 / read-coverage gap #1)
1364 if (graphDataSize > 0) {
1365 proxyGraphics.resize(graphDataSize);
1366 if (!buf->getBytes(reinterpret_cast<std::uint8_t*>(&proxyGraphics[0]),
1367 graphDataSize))
1368 return false;
1369 numProxyGraph = static_cast<int>(graphDataSize);
1370 }
1371 }
1372 if (version < DRW::AC1015) {//14-
1373 objSize = buf->getRawLong32(); //RL 32bits object size in bits
1374 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");
1375 }
1376
1377 std::uint8_t entmode = buf->get2Bits(); //BB
1378 if (entmode == 0)
1379 ownerHandle= true;
1380 // entmode = 2;
1381 else if(entmode ==2)
1382 entmode = 0;
1383 space = (DRW::Space)entmode; //RLZ verify cast values
1384 DRW_DBG("entmode: ")DRW_dbg::dbg("entmode: "); DRW_DBG(entmode)DRW_dbg::dbg(entmode);
1385 numReactors = buf->getBitLong(); //BL per spec §20.4.1
1386 DRW_DBG(", numReactors: ")DRW_dbg::dbg(", numReactors: "); DRW_DBG(numReactors)DRW_dbg::dbg(numReactors);
1387
1388 if (version < DRW::AC1015) {//14-
1389 if(buf->getBit()) {//is bylayer line type
1390 lineType = "BYLAYER";
1391 ltFlags = 0;
1392 } else {
1393 lineType = "";
1394 ltFlags = 3;
1395 }
1396 DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str());
1397 DRW_DBG(" ltFlags: ")DRW_dbg::dbg(" ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags);
1398 }
1399 if (version > DRW::AC1015) {//2004+
1400 xDictFlag = buf->getBit();
1401 DRW_DBG(" xDictFlag: ")DRW_dbg::dbg(" xDictFlag: "); DRW_DBG(xDictFlag)DRW_dbg::dbg(xDictFlag); DRW_DBG("\n")DRW_dbg::dbg("\n");
1402 }
1403
1404 // libreDWG common_entity_data.spec — the bit at this stream position has two
1405 // disjoint meanings by version:
1406 // * R13..R2002 (version < AC1018): `nolinks` (B). 1 = no prev/next handles
1407 // in the handle section; 0 = read prev+next at parseDwgEntHandle.
1408 // * R2004..R2010 (AC1018..AC1024): NO bit in the stream — reader forces
1409 // haveNextLinks=1 to skip the prev/next handle reads.
1410 // * R2013+ (version > AC1024): `has_ds_data` (B). 1 = inline ACIS SAB
1411 // datastore present. Stored separately because it gates SAB handling,
1412 // not prev/next links (which are already version<AC1018 gated).
1413 // Total bit consumption is unchanged for every version.
1414 if (version < DRW::AC1018) {
1415 haveNextLinks = buf->getBit(); //nolinks //B
1416 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");
1417 } else {
1418 haveNextLinks = 1; //AC1018+: not in stream, force 1 (no prev/next)
1419 DRW_DBG(", haveNextLinks (forced): ")DRW_dbg::dbg(", haveNextLinks (forced): "); DRW_DBG(haveNextLinks)DRW_dbg::dbg(haveNextLinks); DRW_DBG("\n")DRW_dbg::dbg("\n");
1420 }
1421 if (version > DRW::AC1024) {
1422 hasDsData = buf->getBit(); //has_ds_data //B (R2013+)
1423 DRW_DBG(", hasDsData (R2013+): ")DRW_dbg::dbg(", hasDsData (R2013+): "); DRW_DBG(hasDsData)DRW_dbg::dbg(hasDsData); DRW_DBG("\n")DRW_dbg::dbg("\n");
1424 }
1425//ENC color
1426 color = buf->getEnColor(version); //BS or CMC //ok for R14 or negate
1427 // Capture the AcDbColor side-channel BEFORE any subsequent ENC read.
1428 // libreDWG common_entity_data.spec:454-459 — the corresponding handle
1429 // is consumed at the start of the handle stream in parseDwgEntHandle.
1430 hasAcDbColorH = buf->lastEnColorHadDbColorRef;
1431 // libreDWG common_entity_data.spec:432-453 — ENC alpha_raw (DXF code
1432 // 440) is encoded as (alpha_type<<24) | alpha. Stored verbatim; the
1433 // filter (RS_FilterDXFRW::setEntityAttributes) decodes alpha_type==3
1434 // into a per-entity pen alpha, otherwise inherits from layer/block.
1435 if (buf->lastEnColorAlphaRaw != 0) {
1436 transparency = static_cast<int>(buf->lastEnColorAlphaRaw);
1437 }
1438 // libreDWG common_entity_data.spec:468-475 — inline TV name/book name
1439 // (flags 0x41/0x42) override any dbColorMap-resolved name. Captured
1440 // immediately; entryParse will skip the override only if colorName is
1441 // already populated here.
1442 if (!buf->lastEnColorName.empty()) {
1443 colorName = buf->lastEnColorBookName.empty()
1444 ? buf->lastEnColorName
1445 : (buf->lastEnColorBookName + "$" + buf->lastEnColorName);
1446 }
1447 ltypeScale = buf->getBitDouble(); //BD
1448 DRW_DBG(" entity color: ")DRW_dbg::dbg(" entity color: "); DRW_DBG(color)DRW_dbg::dbg(color);
1449 DRW_DBG(" ltScale: ")DRW_dbg::dbg(" ltScale: "); DRW_DBG(ltypeScale)DRW_dbg::dbg(ltypeScale); DRW_DBG("\n")DRW_dbg::dbg("\n");
1450 if (version > DRW::AC1014) {//2000+ — §19.4.1: linetype-flags BB then plot-flags BB
1451 ltFlags = buf->get2Bits(); //BB
1452 if (ltFlags == 0) lineType = "BYLAYER";
1453 else if (ltFlags == 1) lineType = "BYBLOCK";
1454 else if (ltFlags == 2) lineType = "CONTINUOUS";
1455 else lineType = ""; //3 → handle at end
1456 DRW_DBG("ltFlags: ")DRW_dbg::dbg("ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags);
1457 DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str());
1458
1459 plotFlags = buf->get2Bits(); //BB
1460 DRW_DBG(", plotFlags: ")DRW_dbg::dbg(", plotFlags: "); DRW_DBG(plotFlags)DRW_dbg::dbg(plotFlags);
1461 }
1462 if (version > DRW::AC1018) {//2007+
1463 materialFlag = buf->get2Bits(); //BB
1464 DRW_DBG("materialFlag: ")DRW_dbg::dbg("materialFlag: "); DRW_DBG(materialFlag)DRW_dbg::dbg(materialFlag);
1465 shadowFlag = buf->getRawChar8(); //RC, low 2 bits is shadow mode 0..3
1466 DRW_DBG("shadowFlag: ")DRW_dbg::dbg("shadowFlag: "); DRW_DBG(shadowFlag)DRW_dbg::dbg(shadowFlag); DRW_DBG("\n")DRW_dbg::dbg("\n");
1467 shadow = static_cast<DRW::ShadowMode>(shadowFlag & 0x3);
1468 }
1469 if (version > DRW::AC1021) {//2010+ — §19.4.1: three single-bit flags
1470 // Ground-truth: libreDWG common_entity_data.spec lines 523-528
1471 // and ODA spec v5.4.1 §19.4.1 both define three FIELD_B (single bit)
1472 // flags here, one each for full/face/edge visual style. Total bit
1473 // consumption (3 bits) is identical to the historical BB+B shape;
1474 // only the semantics differ. The corresponding handles are read
1475 // conditionally in parseDwgEntHandle after the plotstyle handle.
1476 hasFullVisualStyle = buf->getBit(); //B
1477 hasFaceVisualStyle = buf->getBit(); //B
1478 hasEdgeVisualStyle = buf->getBit(); //B
1479 DRW_DBG("hasFull/Face/Edge VisualStyle: ")DRW_dbg::dbg("hasFull/Face/Edge VisualStyle: ");
1480 DRW_DBG(hasFullVisualStyle)DRW_dbg::dbg(hasFullVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" ");
1481 DRW_DBG(hasFaceVisualStyle)DRW_dbg::dbg(hasFaceVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" ");
1482 DRW_DBG(hasEdgeVisualStyle)DRW_dbg::dbg(hasEdgeVisualStyle); DRW_DBG("\n")DRW_dbg::dbg("\n");
1483 }
1484 std::int16_t invisibleFlag = buf->getBitShort(); //BS
1485 DRW_DBG(" invisibleFlag: ")DRW_dbg::dbg(" invisibleFlag: "); DRW_DBG(invisibleFlag)DRW_dbg::dbg(invisibleFlag);
1486 // DXF group 60: bit 0 = invisible (1) / visible (0). libreDWG
1487 // common_entity_data.spec masks bit 0 only (`invisible & 1`) and ignores
1488 // the higher bits, so use the same mask rather than `== 0`. Paired with
1489 // the encode emit below.
1490 visible = ((invisibleFlag & 1) == 0);
1491 if (version > DRW::AC1014) {//2000+
1492 lWeight = DRW_LW_Conv::dwgInt2lineWidth( buf->getRawChar8() ); //RC
1493 DRW_DBG(" lwFlag (lWeight): ")DRW_dbg::dbg(" lwFlag (lWeight): "); DRW_DBG(lWeight)DRW_dbg::dbg(lWeight); DRW_DBG("\n")DRW_dbg::dbg("\n");
1494 }
1495 //Only in blocks ????????
1496// if (version > DRW::AC1018) {//2007+
1497// std::uint8_t unk = buf->getBit();
1498// DRW_DBG("unknown bit: "); DRW_DBG(unk); DRW_DBG("\n");
1499// }
1500 return buf->isGood();
1501}
1502
1503bool DRW_Entity::parseDwgEntHandle(DRW::Version version, dwgBuffer *buf, bool resetHandleStream){
1504 if (resetHandleStream && version > DRW::AC1018) {//2007+ skip string area
1505 buf->setPosition(objSize >> 3);
1506 buf->setBitPos(objSize & 7);
1507 }
1508
1509 // libreDWG common_entity_data.spec:454-459: when ENC flag 0x40 is set,
1510 // an AcDbColor reference handle is the FIRST item in the handle stream
1511 // — read before owner / reactors / xdic / etc. Set in parseDwg via
1512 // dwgBuffer::lastEnColorHadDbColorRef. The dwgReader resolves this
1513 // handle against dbColorMap after parseDwg returns and patches
1514 // color24 + colorName onto the entity.
1515 if (hasAcDbColorH && version > DRW::AC1015 && buf->numRemainingBytes() >= 4) {
1516 dwgHandle dbcH = buf->getOffsetHandle(handle);
1517 acDbColorHandle = dbcH.ref;
1518 DRW_DBG(" AcDbColor Handle: ")DRW_dbg::dbg(" AcDbColor Handle: ");
1519 DRW_DBGHL(dbcH.code, dbcH.size, dbcH.ref)DRW_dbg::dbgHL(dbcH.code, dbcH.size, dbcH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1520 }
1521
1522 if(ownerHandle){//entity are in block or in a polyline
1523 dwgHandle ownerH = buf->getOffsetHandle(handle);
1524 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");
1525 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");
1526 parentHandle = ownerH.ref;
1527 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");
1528 } else
1529 DRW_DBG("NO Block (parent) Handle\n")DRW_dbg::dbg("NO Block (parent) Handle\n");
1530
1531 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");
1532 reactorHandles.clear();
1533 for (int i=0; i< numReactors;++i) {
1534 dwgHandle reactorsH = buf->getHandle();
1535 reactorHandles.push_back(reactorsH.ref); // 2a.2: persist reactors
1536 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");
1537 }
1538 if (xDictFlag !=1){//linetype in 2004 seems not have XDicObjH or NULL handle
1539 dwgHandle XDicObjH = buf->getHandle();
1540 xDictHandle = XDicObjH.ref; // 2a.2: persist xdict
1541 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");
1542 }
1543 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");
1544
1545 if (version < DRW::AC1015) {//R14-
1546 //layer handle
1547 layerH = buf->getOffsetHandle(handle);
1548 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");
1549 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");
1550 //lineType handle
1551 if(ltFlags == 3){
1552 lTypeH = buf->getOffsetHandle(handle);
1553 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");
1554 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");
1555 }
1556 }
1557 if (version < DRW::AC1018) {//2000+
1558 if (haveNextLinks == 0) {
1559 dwgHandle nextLinkH = buf->getOffsetHandle(handle);
1560 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");
1561 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");
1562 prevEntLink = nextLinkH.ref;
1563 nextLinkH = buf->getOffsetHandle(handle);
1564 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");
1565 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");
1566 nextEntLink = nextLinkH.ref;
1567 } else {
1568 nextEntLink = handle+1;
1569 prevEntLink = handle-1;
1570 }
1571 }
1572 if (version > DRW::AC1015) {//2004+
1573 //Parses Bookcolor handle
1574 }
1575 if (version > DRW::AC1014) {//2000+
1576 //layer handle
1577 layerH = buf->getOffsetHandle(handle);
1578 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");
1579 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");
1580 //lineType handle
1581 if(ltFlags == 3){
1582 lTypeH = buf->getOffsetHandle(handle);
1583 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");
1584 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");
1585 }
1586 }
1587 if (version > DRW::AC1014) {//2000+
1588 if (version > DRW::AC1018) {//2007+
1589 if (materialFlag == 3) {
1590 dwgHandle materialH = buf->getOffsetHandle(handle);
1591 material = materialH.ref;
1592 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");
1593 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");
1594 }
1595 if (shadowFlag == 3) {
1596 // AcDbShadow object handle (separate from entity shadow mode
1597 // populated from shadowFlag & 0x3 above). LibreCAD has no
1598 // shadow object consumer; leave discarding.
1599 dwgHandle shadowH = buf->getOffsetHandle(handle);
1600 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");
1601 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");
1602 }
1603 }
1604 if (plotFlags == 3) {
1605 dwgHandle plotStyleH = buf->getOffsetHandle(handle);
1606 plotStyle = static_cast<int>(plotStyleH.ref);
1607 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");
1608 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");
1609 }
1610 if (version > DRW::AC1021) {//2010+ — §19.4.2: visual-style handles
1611 // Ground-truth: libreDWG common_entity_handle_data.spec lines
1612 // 141-150 and ODA spec v5.4.1 §19.4.2. Order matches: full,
1613 // face, edge — each conditional on its single-bit flag from
1614 // §19.4.1 (set in parseDwg above). All three are hard pointers
1615 // (libreDWG FIELD_HANDLE code 5), matching the existing
1616 // material/shadow/plotstyle handles in this block.
1617 if (hasFullVisualStyle) {
1618 dwgHandle h = buf->getOffsetHandle(handle);
1619 fullVisualStyleHandle = h.ref;
1620 DRW_DBG(" full visual-style H: ")DRW_dbg::dbg(" full visual-style H: ");
1621 DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1622 }
1623 if (hasFaceVisualStyle) {
1624 dwgHandle h = buf->getOffsetHandle(handle);
1625 faceVisualStyleHandle = h.ref;
1626 DRW_DBG(" face visual-style H: ")DRW_dbg::dbg(" face visual-style H: ");
1627 DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1628 }
1629 if (hasEdgeVisualStyle) {
1630 dwgHandle h = buf->getOffsetHandle(handle);
1631 edgeVisualStyleHandle = h.ref;
1632 DRW_DBG(" edge visual-style H: ")DRW_dbg::dbg(" edge visual-style H: ");
1633 DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
1634 }
1635 }
1636 }
1637 const int rb = buf->numRemainingBytes();
1638 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");
1639 if (rb > 4) { // 2-byte CRC + slack
1640 DRW_DBG("\n*** parseDwgEntHandle leftover ")DRW_dbg::dbg("\n*** parseDwgEntHandle leftover ");
1641 DRW_DBG(rb)DRW_dbg::dbg(rb);
1642 DRW_DBG(" bytes; entity handle ")DRW_dbg::dbg(" bytes; entity handle ");
1643 DRW_DBGH(handle)DRW_dbg::dbgH(handle);
1644 DRW_DBG(" oType ")DRW_dbg::dbg(" oType ");
1645 DRW_DBG(oType)DRW_dbg::dbg(oType);
1646 DRW_DBG(" — possible bit-stream misalignment ***\n")DRW_dbg::dbg(" — possible bit-stream misalignment ***\n");
1647 }
1648 return buf->isGood();
1649}
1650
1651bool DRW_Point::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
1652 switch (code) {
1653 case 10:
1654 basePoint.x = reader->getDouble();
1655 break;
1656 case 20:
1657 basePoint.y = reader->getDouble();
1658 break;
1659 case 30:
1660 basePoint.z = reader->getDouble();
1661 break;
1662 case 39:
1663 thickness = reader->getDouble();
1664 break;
1665 case 50:
1666 // DXF code 50 is in degrees; the field is radians (matching the DWG
1667 // path, drw_entities.cpp:1787). degrees -> radians is /ARAD (x pi/180);
1668 // the prior *ARAD only canceled with the writer's /ARAD on DXF->DXF and
1669 // corrupted the value for DXF->DWG. ARAD = 180/pi.
1670 xAxisAngle = reader->getDouble() / ARAD57.29577951308232; // DXF degrees -> radians
1671 break;
1672 case 210:
1673 haveExtrusion = true;
1674 extPoint.x = reader->getDouble();
1675 break;
1676 case 220:
1677 extPoint.y = reader->getDouble();
1678 break;
1679 case 230:
1680 extPoint.z = reader->getDouble();
1681 break;
1682 default:
1683 return DRW_Entity::parseCode(code, reader);
1684 }
1685
1686 return true;
1687}
1688
1689// ---------------------------------------------------------------------------
1690// Phase 4a (drafted 2026-05-15)
1691// ---------------------------------------------------------------------------
1692// `DRW_Entity::encodeDwgCommon` and `encodeDwgEntHandle` are R2000-only
1693// inverses of the corresponding parseDwg fragments above. The version
1694// conditionals collapse: all `version > AC1014` branches fire (R2000 is
1695// AC1015 > AC1014), all `version > AC1015` and `version > AC1018` and
1696// `version > AC1021` branches skip. Likewise `version < AC1015` skips.
1697//
1698// Discarded fields (Risk 4i):
1699// - graphFlag B + optional graphData — we always emit graphFlag=0.
1700// - haveNextLinks B — we emit 1 (no prev/next chain).
1701// - acDbColorH — only fires when ENC flag 0x40 set; R2000 entity
1702// encoders don't emit DBCOLOR refs yet.
1703//
1704// We always emit:
1705// - entmode = 2 (modelspace, no owner-handle in stream — caller can
1706// override before calling encodeDwgCommon if entity needs an owner).
1707// - numReactors = 0
1708// - ltFlags = 0 (BYLAYER), plotFlags = 0 (BYLAYER)
1709// - invisibleFlag = 0 (visible)
1710//
1711// Caller must:
1712// - Pre-populate `eType`, `handle`, `color`, `ltypeScale`, `lWeight`,
1713// `layerH.ref` (handle of the layer this entity belongs to).
1714// - The body emit between encodeDwgCommon and encodeDwgEntHandle is
1715// per-entity (3BD basePoint for Point, etc.).
1716
1717// Phase-2a kill switch for the full common-entity-header write contract
1718// (entity reactors/xdict/EED/visibility/entmode emission). Default ON. The
1719// emission is gated by DATA PRESENCE (empty reactorHandles/extData + visible
1720// == today's hardcoded zeros), so flipping this OFF restores the legacy
1721// byte-identical output as an emergency escape hatch. The per-field emission
1722// arms land in 2a.1..2a.5; this scaffolding commit changes no bytes.
1723#ifndef LIBDXFRW_FULL_COMMON_HEADER1
1724#define LIBDXFRW_FULL_COMMON_HEADER1 1
1725#endif
1726
1727bool DRW_Entity::encodeDwgCommon(DRW::Version version, dwgBufferW *buf,
1728 dwgBufferW *strBuf) {
1729 (void)strBuf; // common data contains no strings
1730 if (version != DRW::AC1015 && version != DRW::AC1018 &&
1731 version != DRW::AC1024 && version != DRW::AC1027 &&
1732 version != DRW::AC1032) return false;
1733
1734 // Object type: BS for AC1015/AC1018, OT for AC1024+.
1735 buf->putObjType(version, static_cast<std::uint16_t>(oType));
1736
1737 // objSize stub — back-patched for AC1015/AC1018 only. AC1024 derives
1738 // objSize from the body buffer size, so no RL is emitted.
1739 if (version < DRW::AC1024) {
1740 buf->putRawLong32(0);
1741 }
1742
1743 // Own handle: code 0 per spec §20.4.1.
1744 dwgHandle ownH;
1745 ownH.code = 0;
1746 ownH.ref = handle;
1747 ownH.size = 0;
1748 if (handle != 0) {
1749 std::uint32_t t = handle;
1750 while (t != 0) { t >>= 8; ++ownH.size; }
1751 }
1752 buf->putHandle(ownH);
1753
1754 // No EED yet.
1755 buf->putBitShort(0); // extDataSize=0
1756
1757 // No graphics data.
1758 buf->putBit(0); // graphFlag=0
1759
1760 const bool hasOwner = parentHandle != DRW::NoHandle;
1761
1762 // entmode BB (ODA §20.4.1 / Open Design FE):
1763 // 0 = owner handle follows in the handle stream
1764 // 1 = paperspace entity without owner-relative handle
1765 // 2 = modelspace entity without owner-relative handle
1766 // Prefer owner when present; otherwise honor DRW_Entity::space.
1767 std::uint8_t entmode = 2;
1768 if (hasOwner)
1769 entmode = 0;
1770 else if (space == DRW::PaperSpace)
1771 entmode = 1;
1772 buf->put2Bits(entmode);
1773
1774 // numReactors (BL per spec §20.4.1). 2a.2: emit the real count; empty
1775 // reactorHandles → 0 → byte-identical to legacy.
1776#if LIBDXFRW_FULL_COMMON_HEADER1
1777 buf->putBitLong(static_cast<std::int32_t>(reactorHandles.size()));
1778#else
1779 buf->putBitLong(0);
1780#endif
1781
1782 // R2004/R2010 (AC1018, AC1024): reader reads xDictFlag bit (version > AC1015)
1783 // then forces haveNextLinks=1 (no bit in stream). We always emit
1784 // xDictFlag=0 (xdic-present) so the reader reads exactly one xdic handle
1785 // in the handle section — we emit the real handle when xDictHandle!=0 and
1786 // a null handle otherwise. This keeps the empty case byte-identical to the
1787 // legacy path (bit 0 + null handle) while round-tripping a real xdict.
1788 // R2000 (AC1015): no xDictFlag bit; reader's xDictFlag stays 0 so it ALWAYS
1789 // reads an xdic handle — same emit rule applies.
1790 // R2013+ (AC1027+): reader reads xDictFlag then reads haveNextLinks (bit restored).
1791 if (version == DRW::AC1015) {
1792 buf->putBit(1); // nolinks=1 (R2000: no prev/next chain)
1793 } else {
1794 buf->putBit(0); // xDictFlag=0 (xdic present; real-or-null handle follows)
1795 if (version > DRW::AC1024) {
1796 // libreDWG common_entity_data.spec — R2013+ has_ds_data (B). libdxfrw
1797 // never inlines an ACIS SAB datastore, so emit hasDsData (default 0).
1798 // The old code emitted literal 1 (mislabeled haveNextLinks), falsely
1799 // advertising an SAB blob and risking misparse in strict readers.
1800 buf->putBit(hasDsData);
1801 }
1802 }
1803
1804 // ENC color (BS for R2000/R2004/R2010).
1805 buf->putEnColor(version, static_cast<std::uint16_t>(color));
1806
1807 // ltypeScale BD.
1808 buf->putBitDouble(ltypeScale);
1809
1810 // ltFlags BB: 0=BYLAYER, 1=BYBLOCK, 2=CONTINUOUS, 3=lTypeH present.
1811 // Prefer an already-set ltFlags; otherwise derive from lineType / lTypeH.
1812 {
1813 auto upper = [](std::string s) {
1814 for (char& c : s)
1815 c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
1816 return s;
1817 };
1818 std::uint8_t flags = ltFlags;
1819 if (flags > 3)
1820 flags = 0;
1821 if (flags == 0 && lTypeH.ref != 0)
1822 flags = 3;
1823 if (flags == 0) {
1824 const std::string lt = upper(lineType);
1825 if (lt.empty() || lt == "BYLAYER")
1826 flags = 0;
1827 else if (lt == "BYBLOCK")
1828 flags = 1;
1829 else if (lt == "CONTINUOUS")
1830 flags = 2;
1831 else
1832 flags = 3; // named linetype — handle required
1833 }
1834 ltFlags = flags;
1835 }
1836 buf->put2Bits(ltFlags);
1837 // plotFlags BB: keep BYLAYER (0) this pass unless already set to 3.
1838 buf->put2Bits(plotFlags & 0x3);
1839
1840 // R2010 (AC1024): materialFlag BB + shadowFlag RC (version > AC1018).
1841 if (version > DRW::AC1018) {
1842 buf->put2Bits(0); // materialFlag BB = 0 (inherit)
1843 buf->putRawChar8(0); // shadowFlag RC = 0 (inherit)
1844 }
1845
1846 // R2010 (AC1024): three visual-style flag bits (version > AC1021).
1847 if (version > DRW::AC1021) {
1848 buf->putBit(0); // hasFullVisualStyle
1849 buf->putBit(0); // hasFaceVisualStyle
1850 buf->putBit(0); // hasEdgeVisualStyle
1851 }
1852
1853 // invisibleFlag BS (DXF 60). 2a.1: emit from `visible` (bit 0 = invisible)
1854 // instead of a hardcoded 0. visible==true → 0 → byte-identical to legacy.
1855#if LIBDXFRW_FULL_COMMON_HEADER1
1856 buf->putBitShort(visible ? 0 : 1);
1857#else
1858 buf->putBitShort(0);
1859#endif
1860
1861 // lWeight RC (0 = byLayer per DRW_LW_Conv).
1862 buf->putRawChar8(static_cast<std::uint8_t>(lWeight));
1863
1864 return true;
1865}
1866
1867bool DRW_Entity::encodeDwgEntHandle(DRW::Version version, dwgBufferW *buf,
1868 dwgBufferW *handleBuf) {
1869 if (version != DRW::AC1015 && version != DRW::AC1018 &&
1870 version != DRW::AC1024 && version != DRW::AC1027 &&
1871 version != DRW::AC1032) return false;
1872
1873 // For AC1024, handles are directed to handleBuf (the separate handle section);
1874 // for AC1015/AC1018, handles go into buf alongside the data.
1875 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
1876
1877 // Owner handle is present only when encodeDwgCommon emitted entmode=0.
1878 if (parentHandle != DRW::NoHandle) {
1879 dwgHandle owner;
1880 owner.code = 4; // soft pointer owner, read via getOffsetHandle()
1881 owner.ref = parentHandle;
1882 owner.size = 0;
1883 std::uint32_t t = parentHandle;
1884 while (t != 0) { t >>= 8; ++owner.size; }
1885 hb->putHandle(owner);
1886 }
1887
1888 // Reactor handles (2a.2): emitted before xdic, one per numReactors written
1889 // in the DATA section, as ABSOLUTE handles (reader uses getHandle()). Empty
1890 // reactorHandles → nothing emitted → byte-identical to legacy.
1891#if LIBDXFRW_FULL_COMMON_HEADER1
1892 for (std::uint32_t ref : reactorHandles) {
1893 dwgHandle rh;
1894 rh.code = 4; // soft pointer
1895 rh.ref = ref;
1896 rh.size = 0;
1897 if (ref != 0) { std::uint32_t t = ref; while (t != 0) { t >>= 8; ++rh.size; } }
1898 hb->putHandle(rh);
1899 }
1900#endif
1901
1902 // XDic handle — xDictFlag=0 in the DATA section means the reader reads one
1903 // XDicObj handle here: emit the real handle when xDictHandle!=0, else the
1904 // null handle (matching the legacy byte-for-byte for the empty case).
1905 dwgHandle xDic;
1906 xDic.code = 3;
1907#if LIBDXFRW_FULL_COMMON_HEADER1
1908 xDic.ref = xDictHandle;
1909 xDic.size = 0;
1910 if (xDictHandle != 0) {
1911 std::uint32_t t = xDictHandle; while (t != 0) { t >>= 8; ++xDic.size; }
1912 }
1913#else
1914 xDic.ref = 0;
1915 xDic.size = 0;
1916#endif
1917 hb->putHandle(xDic);
1918
1919 // Layer handle (R2000+ unconditional). Hard pointer.
1920 dwgHandle lH;
1921 lH.code = layerH.ref == 0 ? 0 : 5; // 5 = hard pointer for layer ref
1922 lH.ref = layerH.ref;
1923 lH.size = 0;
1924 if (lH.ref != 0) {
1925 std::uint32_t t = lH.ref;
1926 while (t != 0) { t >>= 8; ++lH.size; }
1927 }
1928 hb->putHandle(lH);
1929
1930 // ltFlags=3 → lTypeH (hard pointer, code 5) present; else omit.
1931 if (ltFlags == 3) {
1932 dwgHandle ltH;
1933 ltH.code = lTypeH.ref == 0 ? 0 : 5;
1934 ltH.ref = lTypeH.ref;
1935 ltH.size = 0;
1936 if (ltH.ref != 0) {
1937 std::uint32_t t = ltH.ref;
1938 while (t != 0) { t >>= 8; ++ltH.size; }
1939 }
1940 hb->putHandle(ltH);
1941 }
1942 // plotFlags remain 0 this pass → no plot-style handle.
1943 // materialFlag / visualStyle flags remain 0 → no extra handles.
1944
1945 return true;
1946}
1947
1948bool DRW_Point::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
1949 (void)bs; (void)strBuf;
1950 oType = 27; // POINT class id — see dwgreader.cpp:1111 dispatch
1951 if (!encodeDwgCommon(version, buf)) return false;
1952
1953 // Point body — mirror of DRW_Point::parseDwg below.
1954 buf->putBitDouble(basePoint.x);
1955 buf->putBitDouble(basePoint.y);
1956 buf->putBitDouble(basePoint.z);
1957 buf->putThickness(thickness, /*b_R2000_style=*/true);
1958 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
1959 buf->putBitDouble(xAxisAngle); // ODA §20.4.31 code 50
1960
1961 return encodeDwgEntHandle(version, buf, handleBuf);
1962}
1963
1964bool DRW_Point::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
1965 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
1966 if (!ret)
1967 return ret;
1968 DRW_DBG("\n***************************** parsing point *********************************************\n")DRW_dbg::dbg("\n***************************** parsing point *********************************************\n"
)
;
1969
1970 basePoint.x = buf->getBitDouble();
1971 basePoint.y = buf->getBitDouble();
1972 basePoint.z = buf->getBitDouble();
1973 DRW_DBG("point: ")DRW_dbg::dbg("point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
1974 thickness = buf->getThickness(version > DRW::AC1014);//BD
1975 DRW_DBG("\nthickness: ")DRW_dbg::dbg("\nthickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
1976 extPoint = buf->getExtrusion(version > DRW::AC1014);
1977 DRW_DBG(", Extrusion: ")DRW_dbg::dbg(", Extrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
1978
1979 xAxisAngle = buf->getBitDouble(); // ODA §20.4.31 code 50, stored in radians
1980 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");
1981 ret = DRW_Entity::parseDwgEntHandle(version, buf);
1982 if (!ret)
1983 return ret;
1984 // RS crc; //RS */
1985
1986 return buf->isGood();
1987}
1988
1989bool DRW_Line::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
1990 switch (code) {
1991 case 11:
1992 secPoint.x = reader->getDouble();
1993 break;
1994 case 21:
1995 secPoint.y = reader->getDouble();
1996 break;
1997 case 31:
1998 secPoint.z = reader->getDouble();
1999 break;
2000 default:
2001 return DRW_Point::parseCode(code, reader);
2002 }
2003
2004 return true;
2005}
2006
2007bool DRW_Line::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2008 (void)bs; (void)strBuf;
2009 oType = 19; // LINE class id — see dwgreader.cpp:1105
2010 if (!encodeDwgCommon(version, buf)) return false;
2011
2012 // R2000+ Line body — zIsZero shortcut: if both z's are 0, omit the
2013 // z fields entirely. Reader reads `zIsZero` first, then RD x +
2014 // DD secX (default = x), RD y + DD secY (default = y), and
2015 // conditionally RD z + DD secZ. Our putDefaultDouble always emits
2016 // the full RD via code 0b11; reader's getDefaultDouble with code
2017 // 0b11 returns the raw double.
2018 bool zIsZero = (basePoint.z == 0.0 && secPoint.z == 0.0);
2019 buf->putBit(zIsZero ? 1 : 0);
2020 buf->putRawDouble(basePoint.x);
2021 buf->putDefaultDouble(basePoint.x, secPoint.x);
2022 buf->putRawDouble(basePoint.y);
2023 buf->putDefaultDouble(basePoint.y, secPoint.y);
2024 if (!zIsZero) {
2025 buf->putRawDouble(basePoint.z);
2026 buf->putDefaultDouble(basePoint.z, secPoint.z);
2027 }
2028 buf->putThickness(thickness, /*b_R2000_style=*/true);
2029 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2030
2031 return encodeDwgEntHandle(version, buf, handleBuf);
2032}
2033
2034bool DRW_Circle::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2035 (void)bs; (void)strBuf;
2036 oType = 18; // CIRCLE class id — see dwgreader.cpp:1099
2037 if (!encodeDwgCommon(version, buf)) return false;
2038
2039 // Circle body — mirror of DRW_Circle::parseDwg.
2040 buf->putBitDouble(basePoint.x);
2041 buf->putBitDouble(basePoint.y);
2042 buf->putBitDouble(basePoint.z);
2043 buf->putBitDouble(radious);
2044 buf->putThickness(thickness, /*b_R2000_style=*/true);
2045 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2046
2047 return encodeDwgEntHandle(version, buf, handleBuf);
2048}
2049
2050bool DRW_Ray::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2051 (void)bs; (void)strBuf;
2052 // Ray = 40, Xline = 41 — derive from runtime type so DRW_Xline can
2053 // share this encoder (it inherits from DRW_Ray).
2054 oType = (eType == DRW::XLINE) ? 41 : 40;
2055 if (!encodeDwgCommon(version, buf)) return false;
2056
2057 // 3 BD basePoint + 3 BD vector — same layout as parseDwg.
2058 buf->putBitDouble(basePoint.x);
2059 buf->putBitDouble(basePoint.y);
2060 buf->putBitDouble(basePoint.z);
2061 buf->putBitDouble(secPoint.x);
2062 buf->putBitDouble(secPoint.y);
2063 buf->putBitDouble(secPoint.z);
2064
2065 return encodeDwgEntHandle(version, buf, handleBuf);
2066}
2067
2068bool DRW_Trace::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2069 (void)bs; (void)strBuf;
2070 oType = 32; // TRACE = 32 — see dwgreader.cpp:1317
2071 if (!encodeDwgCommon(version, buf)) return false;
2072
2073 // Trace body — mirror of parseDwg. Note the unusual layout:
2074 // thickness FIRST, then elevation (basePoint.z) as BD, then 4
2075 // corners as 2RD (z values share basePoint.z).
2076 buf->putThickness(thickness, /*b_R2000_style=*/true);
2077 buf->putBitDouble(basePoint.z);
2078 buf->putRawDouble(basePoint.x);
2079 buf->putRawDouble(basePoint.y);
2080 buf->putRawDouble(secPoint.x);
2081 buf->putRawDouble(secPoint.y);
2082 buf->putRawDouble(thirdPoint.x);
2083 buf->putRawDouble(thirdPoint.y);
2084 buf->putRawDouble(fourPoint.x);
2085 buf->putRawDouble(fourPoint.y);
2086 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2087
2088 return encodeDwgEntHandle(version, buf, handleBuf);
2089}
2090
2091bool DRW_Spline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2092 (void)bs; (void)strBuf;
2093 oType = 36; // SPLINE class id — see dwgreader.cpp:1329
2094 if (!encodeDwgCommon(version, buf)) return false;
2095 encodeDwgSplineBody(version, buf);
2096 return encodeDwgEntHandle(version, buf, handleBuf);
2097}
2098
2099// Spline body encode: the scenario/degree/knots/ctrl/fit section, WITHOUT the
2100// leading encodeDwgCommon or the trailing encodeDwgEntHandle. Factored out so
2101// DRW_Helix::encodeDwg can reuse the identical payload (Phase 8a-1).
2102// Omits the DXF-only flag70/extrusion (210-230) which the DWG stream never
2103// carries here.
2104void DRW_Spline::encodeDwgSplineBody(DRW::Version version, dwgBufferW *buf) const {
2105 // Scenario:
2106 // 1 = control-point / rational / planar (uses knots + control + weights)
2107 // 2 = fit-point (uses fit points + tangents + tolerance)
2108 // When both lists are populated (e.g. DXF-sourced splines), prefer scenario 1
2109 // (ctrl + knots) and drop the fit list from the DWG stream — scenario 1 has no
2110 // fit-point section, so writing both would corrupt all subsequent entities.
2111 const bool hasFit = !fitlist.empty();
2112 const bool hasCtrl = !controllist.empty();
2113 std::int32_t scenario = (hasFit && !hasCtrl) ? 2 : 1;
2114 if (m_scenario == 1 && hasCtrl) {
2115 scenario = 1;
2116 } else if (m_scenario == 2 && hasFit) {
2117 scenario = 2;
2118 }
2119 buf->putBitLong(scenario);
2120 if (version > DRW::AC1024) {
2121 // splFlag1 bit 0: method = fit points; bit 2: closed;
2122 // bit 3: knotParam participates in R2013+ scenario selection.
2123 std::int32_t splFlag1 = m_splineFlags1;
2124 splFlag1 &= ~(kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter | kSplineFlagClosed);
2125 if (scenario == 2) {
2126 splFlag1 |= kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter;
2127 if (flags & 0x01) splFlag1 |= kSplineFlagClosed;
2128 } else {
2129 if (flags & 0x01) splFlag1 |= kSplineFlagClosed;
2130 }
2131 buf->putBitLong(splFlag1);
2132 std::int32_t knotParam = m_knotParam;
2133 if (scenario == 1) {
2134 knotParam = kSplineKnotParamCustom;
2135 } else if (knotParam == kSplineKnotParamCustom) {
2136 knotParam = 0;
2137 }
2138 buf->putBitLong(knotParam);
2139 }
2140 buf->putBitLong(static_cast<std::int32_t>(degree));
2141
2142 if (scenario == 2) {
2143 buf->putBitDouble(tolfit);
2144 buf->put3BitDouble(tgStart);
2145 buf->put3BitDouble(tgEnd);
2146 const std::int32_t nFit = static_cast<std::int32_t>(fitlist.size());
2147 buf->putBitLong(nFit);
2148 } else {
2149 // scenario == 1
2150 // Reader at parseDwg reads three flag bits in this order:
2151 // rational bit (flags bit 2 → 0x04)
2152 // closed bit (flags bit 0 → 0x01)
2153 // periodic bit (flags bit 1 → 0x02)
2154 const bool hasNonDefaultWeights = std::any_of(weightlist.begin(), weightlist.end(), differsFromUnitWeight);
2155 buf->putBit(((flags & 0x4) || hasNonDefaultWeights) ? 1 : 0); // rational
2156 buf->putBit((flags & 0x1) ? 1 : 0); // closed
2157 buf->putBit((flags & 0x2) ? 1 : 0); // periodic
2158 buf->putBitDouble(tolknot);
2159 buf->putBitDouble(tolcontrol);
2160 const std::int32_t nKnots = static_cast<std::int32_t>(knotslist.size());
2161 const std::int32_t nCtrl = static_cast<std::int32_t>(controllist.size());
2162 buf->putBitLong(nKnots);
2163 buf->putBitLong(nCtrl);
2164 // weight bit: caller populates weightlist when each control point
2165 // has a non-default weight (NURBS conics).
2166 bool hasWeights = !weightlist.empty();
2167 buf->putBit(hasWeights ? 1 : 0);
2168 }
2169
2170 // Data sections are scenario-gated to avoid stream corruption:
2171 // parseDwg reads knots+ctrl only for scenario 1, fit only for scenario 2.
2172 if (scenario == 1) {
2173 for (double k : knotslist) buf->putBitDouble(k);
2174 for (size_t i = 0; i < controllist.size(); ++i) {
2175 buf->put3BitDouble(*controllist[i]);
2176 if (!weightlist.empty()) {
2177 double w = (i < weightlist.size()) ? weightlist[i] : 1.0;
2178 buf->putBitDouble(w);
2179 }
2180 }
2181 } else {
2182 for (const auto& fp : fitlist) buf->put3BitDouble(*fp);
2183 }
2184}
2185
2186// DRW_Helix::encodeDwg — spline body (oType = HELIX class 503) + AcDbHelix
2187// trailer, then the common entity handle data. Trailer field order MUST match
2188// DRW_Helix::parseDwg (Phase 8a-1).
2189bool DRW_Helix::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2190 (void)bs; (void)strBuf;
2191 oType = kDwgClassNum; // HELIX custom class 503
2192 if (!encodeDwgCommon(version, buf)) return false;
2193 encodeDwgSplineBody(version, buf);
2194
2195 // AcDbHelix trailer (same order as parseDwg):
2196 buf->putBitLong(m_majorVersion);
2197 buf->putBitLong(m_maintVersion);
2198 buf->put3BitDouble(axisBasePt);
2199 buf->put3BitDouble(startPt);
2200 buf->put3BitDouble(axisVector);
2201 buf->putBitDouble(radius);
2202 buf->putBitDouble(turns);
2203 buf->putBitDouble(turnHeight);
2204 buf->putBit(handedness ? 1 : 0);
2205 buf->putRawChar8(static_cast<std::uint8_t>(constraintType));
2206
2207 return encodeDwgEntHandle(version, buf, handleBuf);
2208}
2209
2210bool DRW_MText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2211 (void)bs;
2212 oType = 44; // MTEXT class id — see dwgreader.cpp:1215
2213 if (!encodeDwgCommon(version, buf)) return false;
2214
2215 // R2000/R2004/R2010 MTEXT body — mirror of DRW_MText::parseDwg.
2216 buf->put3BitDouble(basePoint); // insertion
2217 buf->put3BitDouble(extPoint); // extrusion
2218 buf->put3BitDouble(secPoint); // X-axis dir
2219 buf->putBitDouble(widthscale); // rect width
2220 if (version > DRW::AC1018) {
2221 buf->putBitDouble(0.0); // rect height, R2007+
2222 }
2223 buf->putBitDouble(height); // text height
2224 buf->putBitShort(static_cast<std::uint16_t>(textgen)); // attachment
2225 buf->putBitShort(static_cast<std::uint16_t>(alignH)); // drawing dir
2226 buf->putBitDouble(0.0); // ext_ht (extents height; undocumented)
2227 buf->putBitDouble(0.0); // ext_wid (extents width; undocumented)
2228 // For AC1024: text goes to string buffer; for AC1015/AC1018: inline.
2229 (strBuf ? strBuf : buf)->putVariableText(version, text);
2230 // R2000+ extras:
2231 buf->putBitShort(linespacingStyle); // linespacing style BS 73
2232 buf->putBitDouble(interlin); // linespacing factor BD
2233 buf->putBit(0); // unknown bit
2234 if (version > DRW::AC1015) { // R2004+: background flags BL
2235 buf->putBitLong(m_backgroundFlags);
2236 if ((m_backgroundFlags & 0x01) || (version >= DRW::AC1032 && (m_backgroundFlags & 0x10))) {
2237 buf->putBitDouble(m_backgroundScale); // BitDouble (matches the read fix)
2238 buf->putCmColor(version, static_cast<std::uint16_t>(m_backgroundColor));
2239 buf->putBitLong(m_backgroundTransparency);
2240 }
2241 }
2242 if (version >= DRW::AC1032) {
2243 buf->putBit(m_r2018IsNotAnnotative ? 1 : 0);
2244 if (m_r2018IsNotAnnotative) {
2245 buf->putBitShort(m_r2018Version);
2246 buf->putBit(m_r2018DefaultFlag ? 1 : 0);
2247 buf->putBitLong(m_r2018Attachment);
2248 buf->put3BitDouble(m_r2018XAxisDir);
2249 buf->put3BitDouble(m_r2018InsertionPoint);
2250 buf->putBitDouble(m_r2018RectWidth);
2251 buf->putBitDouble(m_r2018RectHeight);
2252 buf->putBitDouble(m_r2018ExtentsHeight);
2253 buf->putBitDouble(m_r2018ExtentsWidth);
2254 buf->putBitShort(m_r2018ColumnType);
2255 if (m_r2018ColumnType != 0) {
2256 std::int32_t columnCount = m_r2018ColumnCount;
2257 if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2
2258 && !m_r2018ColumnHeights.empty()) {
2259 columnCount = static_cast<std::int32_t>(m_r2018ColumnHeights.size());
2260 }
2261 buf->putBitLong(columnCount);
2262 buf->putBitDouble(m_r2018ColumnWidth);
2263 buf->putBitDouble(m_r2018ColumnGutter);
2264 buf->putBit(m_r2018ColumnAutoHeight ? 1 : 0);
2265 buf->putBit(m_r2018ColumnFlowReversed ? 1 : 0);
2266 if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2) {
2267 for (std::int32_t i = 0; i < columnCount; ++i) {
2268 const double columnHeight = static_cast<size_t>(i) < m_r2018ColumnHeights.size()
2269 ? m_r2018ColumnHeights[static_cast<size_t>(i)]
2270 : 0.0;
2271 buf->putBitDouble(columnHeight);
2272 }
2273 }
2274 }
2275 }
2276 }
2277
2278 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
2279
2280 // styleH — hard pointer to STYLE table record (default STANDARD).
2281 dwgBufferW *hb = handleBuf ? handleBuf : buf;
2282 putHardPointerHandle(hb, (styleH.ref == 0) ? 0x13 : styleH.ref);
2283 if (version >= DRW::AC1032 && m_r2018IsNotAnnotative)
2284 putHardPointerHandle(hb, (m_r2018AppIdHandle == 0) ? 0x14 : m_r2018AppIdHandle);
2285 return true;
2286}
2287
2288bool DRW_Insert::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2289 (void)bs; (void)strBuf;
2290 // 2b.6: emit MINSERT (oType 8) when a column/row grid is present;
2291 // otherwise a plain INSERT (oType 7). The reader keys the grid block off
2292 // oType==8 (parseDwg :3189).
2293 oType = isMInsert() ? 8 : 7;
2294 if (!encodeDwgCommon(version, buf)) return false;
2295
2296 // INSERT body — mirror of DRW_Insert::parseDwg for R2000.
2297 buf->putBitDouble(basePoint.x);
2298 buf->putBitDouble(basePoint.y);
2299 buf->putBitDouble(basePoint.z);
2300
2301 // dataFlags: pick the most compact form based on actual scales.
2302 // 3 → all scales default to 1.0 (no emit)
2303 // 2 → uniform scale (xscale RD only; yscale=zscale=xscale)
2304 // 1 → xscale defaults to 1, yscale/zscale as DD against xscale
2305 // 0 → xscale RD; yscale/zscale as DD against xscale
2306 if (xscale == 1.0 && yscale == 1.0 && zscale == 1.0) {
2307 buf->put2Bits(3);
2308 } else if (xscale == yscale && yscale == zscale) {
2309 buf->put2Bits(2);
2310 buf->putRawDouble(xscale);
2311 } else {
2312 // Use dataFlags=0 (general case): RD x + DD y + DD z.
2313 buf->put2Bits(0);
2314 buf->putRawDouble(xscale);
2315 buf->putDefaultDouble(xscale, yscale);
2316 buf->putDefaultDouble(xscale, zscale);
2317 }
2318
2319 buf->putBitDouble(angle); // radians
2320 buf->putExtrusion(extPoint, /*b_R2000_style=*/false);
2321 buf->putBit(0); // hasAttrib = 0 (no ATTRIBs)
2322 // hasAttrib==0 ⇒ the SINCE-R2004 num_owned BL is absent (parse :3184), so
2323 // the MINSERT grid (oType==8) follows the hasAttrib bit directly. Field
2324 // order mirrors parseDwg :3190-3193 (colcount BS, rowcount BS, colspace BD,
2325 // rowspace BD) and libreDWG dwg.spec num_cols/num_rows/col_spacing/row_spacing.
2326 if (oType == 8) { // MINSERT grid
2327 buf->putBitShort(static_cast<std::uint16_t>(colcount));
2328 buf->putBitShort(static_cast<std::uint16_t>(rowcount));
2329 buf->putBitDouble(colspace);
2330 buf->putBitDouble(rowspace);
2331 }
2332
2333 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
2334
2335 // BLOCK_RECORD hard pointer.
2336 dwgHandle bhH;
2337 bhH.code = (blockRecH.ref == 0) ? 0 : 5;
2338 bhH.ref = blockRecH.ref;
2339 bhH.size = 0;
2340 if (bhH.ref != 0) {
2341 std::uint32_t t = bhH.ref;
2342 while (t != 0) { t >>= 8; ++bhH.size; }
2343 }
2344 (handleBuf ? handleBuf : buf)->putHandle(bhH);
2345 return true;
2346}
2347
2348bool DRW_3Dface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2349 (void)bs; (void)strBuf;
2350 oType = 28; // 3DFACE class id — see dwgreader.cpp:1237
2351 if (!encodeDwgCommon(version, buf)) return false;
2352
2353 // R2000+ 3DFACE body — mirror of parseDwg's z_is_zero / has_no_flag
2354 // optimization. Reader checks `invisibleflag != NoEdge`; if NoEdge,
2355 // emit has_no_flag=1 to suppress the BS read.
2356 bool hasNoFlag = (invisibleflag == /*NoEdge*/0);
2357 bool zIsZero = (basePoint.z == 0.0);
2358 buf->putBit(hasNoFlag ? 1 : 0);
2359 buf->putBit(zIsZero ? 1 : 0);
2360 buf->putRawDouble(basePoint.x);
2361 buf->putRawDouble(basePoint.y);
2362 if (!zIsZero) buf->putRawDouble(basePoint.z);
2363 buf->putDefaultDouble(basePoint.x, secPoint.x);
2364 buf->putDefaultDouble(basePoint.y, secPoint.y);
2365 buf->putDefaultDouble(basePoint.z, secPoint.z);
2366 buf->putDefaultDouble(secPoint.x, thirdPoint.x);
2367 buf->putDefaultDouble(secPoint.y, thirdPoint.y);
2368 buf->putDefaultDouble(secPoint.z, thirdPoint.z);
2369 buf->putDefaultDouble(thirdPoint.x, fourPoint.x);
2370 buf->putDefaultDouble(thirdPoint.y, fourPoint.y);
2371 buf->putDefaultDouble(thirdPoint.z, fourPoint.z);
2372 if (!hasNoFlag) buf->putBitShort(static_cast<std::uint16_t>(invisibleflag));
2373
2374 return encodeDwgEntHandle(version, buf, handleBuf);
2375}
2376
2377bool DRW_Solid::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2378 (void)bs; (void)strBuf;
2379 oType = 31; // SOLID class id — see dwgreader.cpp:1305
2380 if (!encodeDwgCommon(version, buf)) return false;
2381
2382 // Same body layout as TRACE (4 corners + extrusion). Duplicated
2383 // here rather than delegating to DRW_Trace::encodeDwg because that
2384 // hardcodes oType=32.
2385 buf->putThickness(thickness, /*b_R2000_style=*/true);
2386 buf->putBitDouble(basePoint.z);
2387 buf->putRawDouble(basePoint.x);
2388 buf->putRawDouble(basePoint.y);
2389 buf->putRawDouble(secPoint.x);
2390 buf->putRawDouble(secPoint.y);
2391 buf->putRawDouble(thirdPoint.x);
2392 buf->putRawDouble(thirdPoint.y);
2393 buf->putRawDouble(fourPoint.x);
2394 buf->putRawDouble(fourPoint.y);
2395 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2396
2397 return encodeDwgEntHandle(version, buf, handleBuf);
2398}
2399
2400bool DRW_LWPolyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2401 (void)bs; (void)strBuf;
2402 oType = 77; // LWPOLYLINE class id — see dwgreader.cpp:1202
2403 if (!encodeDwgCommon(version, buf)) return false;
2404
2405 // DRW_LWPolyline::flags carries DXF-side bits (1=closed, 128=plinegen).
2406 // DWG-side flags are different: they signal which optional fields are
2407 // present. Per parseDwg, bit 9 (0x200) = closed, bit 8 (0x100) =
2408 // plinegen. Build the DWG flags from the DXF flags plus the data.
2409 std::uint16_t dwgFlags = 0;
2410 if (flags & 1) dwgFlags |= 0x200; // closed
2411 if (flags & 128) dwgFlags |= 0x100; // plinegen
2412 if (thickness != 0.0) dwgFlags |= 0x2;
2413 if (width != 0.0) dwgFlags |= 0x4;
2414 if (elevation != 0.0) dwgFlags |= 0x8;
2415 bool defaultExt = (extPoint.x == 0.0 && extPoint.y == 0.0 && extPoint.z == 1.0);
2416 if (!defaultExt) dwgFlags |= 0x1;
2417 // Detect per-vertex bulge / width data.
2418 bool anyBulge = false;
2419 bool anyWidth = false;
2420 bool anyVertexId = false;
2421 for (const auto& v : vertlist) {
2422 if (v && v->bulge != 0.0) anyBulge = true;
2423 if (v && (v->stawidth != 0.0 || v->endwidth != 0.0)) anyWidth = true;
2424 if (v && v->identifier != 0) anyVertexId = true;
2425 }
2426 if (anyBulge) dwgFlags |= 0x10;
2427 if (anyWidth) dwgFlags |= 0x20;
2428 if (version > DRW::AC1021 && anyVertexId) dwgFlags |= 0x400;
2429
2430 buf->putBitShort(dwgFlags);
2431 if (dwgFlags & 0x4) buf->putBitDouble(width);
2432 if (dwgFlags & 0x8) buf->putBitDouble(elevation);
2433 if (dwgFlags & 0x2) buf->putBitDouble(thickness);
2434 if (dwgFlags & 0x1) buf->putExtrusion(extPoint, /*b_R2000_style=*/false);
2435
2436 const std::int32_t numVerts = static_cast<std::int32_t>(vertlist.size());
2437 buf->putBitLong(numVerts);
2438 if (dwgFlags & 0x10) buf->putBitLong(numVerts); // bulgesnum
2439 if (version > DRW::AC1021 && (dwgFlags & 0x400)) {
2440 buf->putBitLong(numVerts); // vertexIdCount
2441 }
2442 if (dwgFlags & 0x20) buf->putBitLong(numVerts); // widthsnum
2443
2444 if (numVerts > 0) {
2445 // First vertex as 2RD. Subsequent vertices as 2DD relative to
2446 // the previous, with putDefaultDouble always emitting code 0b11
2447 // (full RD); the reader's getDefaultDouble returns the raw value.
2448 buf->putRawDouble(vertlist[0]->x);
2449 buf->putRawDouble(vertlist[0]->y);
2450 for (size_t i = 1; i < vertlist.size(); ++i) {
2451 buf->putDefaultDouble(vertlist[i-1]->x, vertlist[i]->x);
2452 buf->putDefaultDouble(vertlist[i-1]->y, vertlist[i]->y);
2453 }
2454 if (dwgFlags & 0x10) {
2455 for (const auto& v : vertlist)
2456 buf->putBitDouble(v->bulge);
2457 }
2458 if (version > DRW::AC1021 && (dwgFlags & 0x400)) {
2459 for (const auto& v : vertlist)
2460 buf->putBitLong(static_cast<std::int32_t>(v->identifier));
2461 }
2462 if (dwgFlags & 0x20) {
2463 for (const auto& v : vertlist) {
2464 buf->putBitDouble(v->stawidth);
2465 buf->putBitDouble(v->endwidth);
2466 }
2467 }
2468 }
2469
2470 return encodeDwgEntHandle(version, buf, handleBuf);
2471}
2472
2473bool DRW_Block::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2474 (void)bs;
2475 // BLOCK = 4, ENDBLK = 5 per DWG spec. isEnd controls which.
2476 oType = isEnd ? 5 : 4;
2477 if (!encodeDwgCommon(version, buf)) return false;
2478 if (!isEnd) {
2479 (strBuf ? strBuf : buf)->putVariableText(version, name);
2480 }
2481 if (version > DRW::AC1018) {
2482 buf->putBit(0); // unknown bit (R2007+: always 0 for our output)
2483 }
2484 return encodeDwgEntHandle(version, buf, handleBuf);
2485}
2486
2487bool DRW_Text::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2488 (void)bs;
2489 oType = 1; // TEXT class id — see dwgreader.cpp:1208
2490 if (!encodeDwgCommon(version, buf)) return false;
2491
2492 // R2000+ TEXT body — mirror of DRW_Text::parseDwg. We emit
2493 // data_flags=0 so the reader sees every optional field rather than
2494 // substituting defaults — keeps the encoder simple, costs ~30 bytes
2495 // per TEXT versus the most compressed form.
2496 buf->putRawChar8(0); // data_flags=0
2497 buf->putRawDouble(basePoint.z); // elevation RD
2498 buf->putRawDouble(basePoint.x); // insertion 2RD
2499 buf->putRawDouble(basePoint.y);
2500 buf->putDefaultDouble(basePoint.x, secPoint.x); // alignment 2DD
2501 buf->putDefaultDouble(basePoint.y, secPoint.y);
2502 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2503 buf->putThickness(thickness, /*b_R2000_style=*/true);
2504 buf->putRawDouble(oblique); // oblique angle
2505 // Angle: struct holds degrees; on-disk format is radians. Reader
2506 // does `angle *= ARAD` (180/π) after read. Inverse: divide here.
2507 buf->putRawDouble(angle / ARAD57.29577951308232);
2508 buf->putRawDouble(height); // text height
2509 buf->putRawDouble(widthscale); // width factor
2510 (strBuf ? strBuf : buf)->putVariableText(version, text); // text string
2511 buf->putBitShort(static_cast<std::uint16_t>(textgen));
2512 buf->putBitShort(static_cast<std::uint16_t>(alignH));
2513 buf->putBitShort(static_cast<std::uint16_t>(alignV));
2514
2515 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
2516
2517 // styleH — hard pointer to STYLE table record. Default points at
2518 // the STANDARD textstyle (handle 0x13) if caller hasn't set one.
2519 dwgHandle sH;
2520 std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref;
2521 sH.code = 5; // hard pointer
2522 sH.ref = sref;
2523 sH.size = 0;
2524 if (sref != 0) {
2525 std::uint32_t t = sref;
2526 while (t != 0) { t >>= 8; ++sH.size; }
2527 }
2528 (handleBuf ? handleBuf : buf)->putHandle(sH);
2529 return true;
2530}
2531
2532bool DRW_Ellipse::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2533 (void)bs; (void)strBuf;
2534 oType = 35; // ELLIPSE class id — see dwgreader.cpp:1117
2535 if (!encodeDwgCommon(version, buf)) return false;
2536
2537 // Ellipse body — mirror of DRW_Ellipse::parseDwg.
2538 buf->put3BitDouble(basePoint); // center
2539 buf->put3BitDouble(secPoint); // major axis vector
2540 buf->put3BitDouble(extPoint); // extrusion
2541 buf->putBitDouble(ratio); // minor/major ratio
2542 buf->putBitDouble(staparam); // start parameter
2543 buf->putBitDouble(endparam); // end parameter
2544
2545 return encodeDwgEntHandle(version, buf, handleBuf);
2546}
2547
2548bool DRW_Arc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
2549 (void)bs; (void)strBuf;
2550 oType = 17; // ARC class id — see dwgreader.cpp:1093
2551 if (!encodeDwgCommon(version, buf)) return false;
2552
2553 // Arc body — Circle body + 2 BD angles.
2554 buf->putBitDouble(basePoint.x);
2555 buf->putBitDouble(basePoint.y);
2556 buf->putBitDouble(basePoint.z);
2557 buf->putBitDouble(radious);
2558 buf->putThickness(thickness, /*b_R2000_style=*/true);
2559 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
2560 buf->putBitDouble(staangle);
2561 buf->putBitDouble(endangle);
2562
2563 return encodeDwgEntHandle(version, buf, handleBuf);
2564}
2565
2566bool DRW_Line::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2567 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2568 if (!ret)
2569 return ret;
2570 DRW_DBG("\n***************************** parsing line *********************************************\n")DRW_dbg::dbg("\n***************************** parsing line *********************************************\n"
)
;
2571
2572 if (version < DRW::AC1015) {//14-
2573 basePoint.x = buf->getBitDouble();
2574 basePoint.y = buf->getBitDouble();
2575 basePoint.z = buf->getBitDouble();
2576 secPoint.x = buf->getBitDouble();
2577 secPoint.y = buf->getBitDouble();
2578 secPoint.z = buf->getBitDouble();
2579 }
2580 if (version > DRW::AC1014) {//2000+
2581 bool zIsZero = buf->getBit(); //B
2582 basePoint.x = buf->getRawDouble();//RD
2583 secPoint.x = buf->getDefaultDouble(basePoint.x);//DD
2584 basePoint.y = buf->getRawDouble();//RD
2585 secPoint.y = buf->getDefaultDouble(basePoint.y);//DD
2586 if (!zIsZero) {
2587 basePoint.z = buf->getRawDouble();//RD
2588 secPoint.z = buf->getDefaultDouble(basePoint.z);//DD
2589 }
2590 }
2591 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);
2592 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);
2593 thickness = buf->getThickness(version > DRW::AC1014);//BD
2594 DRW_DBG("\nthickness: ")DRW_dbg::dbg("\nthickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
2595 extPoint = buf->getExtrusion(version > DRW::AC1014);
2596 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");
2597 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2598 if (!ret)
2599 return ret;
2600 // RS crc; //RS */
2601 return buf->isGood();
2602}
2603
2604bool DRW_Ray::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2605 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2606 if (!ret)
2607 return ret;
2608 DRW_DBG("\n***************************** parsing ray/xline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing ray/xline *********************************************\n"
)
;
2609 basePoint.x = buf->getBitDouble();
2610 basePoint.y = buf->getBitDouble();
2611 basePoint.z = buf->getBitDouble();
2612 secPoint.x = buf->getBitDouble();
2613 secPoint.y = buf->getBitDouble();
2614 secPoint.z = buf->getBitDouble();
2615 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);
2616 DRW_DBG("\nvector: ")DRW_dbg::dbg("\nvector: "); DRW_DBGPT(secPoint.x, secPoint.y, secPoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, secPoint.z);
2617 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2618 if (!ret)
2619 return ret;
2620 // RS crc; //RS */
2621 return buf->isGood();
2622}
2623
2624void DRW_Circle::applyExtrusion(){
2625 if (haveExtrusion) {
2626 //NOTE: Commenting these out causes the the arcs being tested to be located
2627 //on the other side of the y axis (all x dimensions are negated).
2628 calculateAxis(extPoint);
2629 extrudePoint(extPoint, &basePoint);
2630 }
2631}
2632
2633bool DRW_Circle::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2634 switch (code) {
2635 case 40:
2636 radious = reader->getDouble();
2637 break;
2638 default:
2639 return DRW_Point::parseCode(code, reader);
2640 }
2641
2642 return true;
2643}
2644
2645bool DRW_Circle::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2646 bool ret = DRW_Entity::parseDwg(version, buf, nullptr, bs);
2647 if (!ret)
2648 return ret;
2649 DRW_DBG("\n***************************** parsing circle *********************************************\n")DRW_dbg::dbg("\n***************************** parsing circle *********************************************\n"
)
;
2650
2651 basePoint.x = buf->getBitDouble();
2652 basePoint.y = buf->getBitDouble();
2653 basePoint.z = buf->getBitDouble();
2654 DRW_DBG("center: ")DRW_dbg::dbg("center: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2655 radious = buf->getBitDouble();
2656 DRW_DBG("\nradius: ")DRW_dbg::dbg("\nradius: "); DRW_DBG(radious)DRW_dbg::dbg(radious);
2657
2658 thickness = buf->getThickness(version > DRW::AC1014);
2659 DRW_DBG(" thickness: ")DRW_dbg::dbg(" thickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
2660 extPoint = buf->getExtrusion(version > DRW::AC1014);
2661 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");
2662
2663 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2664 if (!ret)
2665 return ret;
2666 // RS crc; //RS */
2667 return buf->isGood();
2668}
2669
2670void DRW_Arc::applyExtrusion(){
2671 DRW_Circle::applyExtrusion();
2672
2673 if(haveExtrusion){
2674 // If the extrusion vector has a z value less than 0, the angles for the arc
2675 // have to be mirrored since DXF files use the right hand rule.
2676 // Note that the following code only handles the special case where there is a 2D
2677 // drawing with the z axis heading into the paper (or rather screen). An arbitrary
2678 // extrusion axis (with x and y values greater than 1/64) may still have issues.
2679 if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625 && extPoint.z < 0.0) {
2680 staangle=M_PI3.14159265358979323846-staangle;
2681 endangle=M_PI3.14159265358979323846-endangle;
2682
2683 double temp = staangle;
2684 staangle=endangle;
2685 endangle=temp;
2686 }
2687 }
2688}
2689
2690bool DRW_Arc::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2691 switch (code) {
2692 case 50:
2693 staangle = reader->getDouble()/ ARAD57.29577951308232;
2694 break;
2695 case 51:
2696 endangle = reader->getDouble()/ ARAD57.29577951308232;
2697 break;
2698 default:
2699 return DRW_Circle::parseCode(code, reader);
2700 }
2701
2702 return true;
2703}
2704
2705bool DRW_Arc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2706 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2707 if (!ret)
2708 return ret;
2709 DRW_DBG("\n***************************** parsing circle arc *********************************************\n")DRW_dbg::dbg("\n***************************** parsing circle arc *********************************************\n"
)
;
2710
2711 basePoint.x = buf->getBitDouble();
2712 basePoint.y = buf->getBitDouble();
2713 basePoint.z = buf->getBitDouble();
2714 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);
2715
2716 radious = buf->getBitDouble();
2717 DRW_DBG("\nradius: ")DRW_dbg::dbg("\nradius: "); DRW_DBG(radious)DRW_dbg::dbg(radious);
2718 thickness = buf->getThickness(version > DRW::AC1014);
2719 DRW_DBG(" thickness: ")DRW_dbg::dbg(" thickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness);
2720 extPoint = buf->getExtrusion(version > DRW::AC1014);
2721 DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
2722 staangle = buf->getBitDouble();
2723 DRW_DBG("\nstart angle: ")DRW_dbg::dbg("\nstart angle: "); DRW_DBG(staangle)DRW_dbg::dbg(staangle);
2724 endangle = buf->getBitDouble();
2725 DRW_DBG(" end angle: ")DRW_dbg::dbg(" end angle: "); DRW_DBG(endangle)DRW_dbg::dbg(endangle); DRW_DBG("\n")DRW_dbg::dbg("\n");
2726 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2727 if (!ret)
2728 return ret;
2729 return buf->isGood();
2730}
2731
2732bool DRW_Ellipse::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2733 switch (code) {
2734 case 40:
2735 ratio = reader->getDouble();
2736 break;
2737 case 41:
2738 staparam = reader->getDouble();
2739 break;
2740 case 42:
2741 endparam = reader->getDouble();
2742 break;
2743 default:
2744 return DRW_Line::parseCode(code, reader);
2745 }
2746
2747 return true;
2748}
2749
2750void DRW_Ellipse::applyExtrusion(){
2751 if (haveExtrusion) {
2752 calculateAxis(extPoint);
2753 extrudePoint(extPoint, &basePoint);
2754 extrudePoint(extPoint, &secPoint);
2755 double intialparam = staparam;
2756 if (extPoint.z < 0.){
2757 staparam = M_PIx26.283185307179586 - endparam;
2758 endparam = M_PIx26.283185307179586 - intialparam;
2759 }
2760 }
2761}
2762
2763//if ratio > 1 minor axis are greather than major axis, correct it
2764void DRW_Ellipse::correctAxis(){
2765 bool complete = false;
2766 if (staparam == endparam) {
2767 staparam = 0.0;
2768 endparam = M_PIx26.283185307179586; //2*M_PI;
2769 complete = true;
2770 }
2771 if (ratio > 1){
2772 if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10)
2773 complete = true;
2774 double incX = secPoint.x;
2775 secPoint.x = -(secPoint.y * ratio);
2776 secPoint.y = incX*ratio;
2777 ratio = 1/ratio;
2778 if (!complete){
2779 if (staparam < M_PI_21.57079632679489661923)
2780 staparam += M_PI3.14159265358979323846 *2;
2781 if (endparam < M_PI_21.57079632679489661923)
2782 endparam += M_PI3.14159265358979323846 *2;
2783 endparam -= M_PI_21.57079632679489661923;
2784 staparam -= M_PI_21.57079632679489661923;
2785 }
2786 }
2787}
2788
2789bool DRW_Ellipse::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2790 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2791 if (!ret)
2792 return ret;
2793 DRW_DBG("\n***************************** parsing ellipse *********************************************\n")DRW_dbg::dbg("\n***************************** parsing ellipse *********************************************\n"
)
;
2794
2795 basePoint =buf->get3BitDouble();
2796 DRW_DBG("center: ")DRW_dbg::dbg("center: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2797 secPoint =buf->get3BitDouble();
2798 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");
2799 extPoint =buf->get3BitDouble();
2800 DRW_DBG("Extrusion: ")DRW_dbg::dbg("Extrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
2801 ratio = buf->getBitDouble();//BD
2802 DRW_DBG("\nratio: ")DRW_dbg::dbg("\nratio: "); DRW_DBG(ratio)DRW_dbg::dbg(ratio);
2803 staparam = buf->getBitDouble();//BD
2804 DRW_DBG(" start param: ")DRW_dbg::dbg(" start param: "); DRW_DBG(staparam)DRW_dbg::dbg(staparam);
2805 endparam = buf->getBitDouble();//BD
2806 DRW_DBG(" end param: ")DRW_dbg::dbg(" end param: "); DRW_DBG(endparam)DRW_dbg::dbg(endparam); DRW_DBG("\n")DRW_dbg::dbg("\n");
2807
2808 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2809 if (!ret)
2810 return ret;
2811 // RS crc; //RS */
2812 return buf->isGood();
2813}
2814
2815//parts are the number of vertex to split polyline, default 128
2816void DRW_Ellipse::toPolyline(DRW_Polyline *pol, int parts){
2817 double radMajor, radMinor, cosRot, sinRot, incAngle, curAngle;
2818 double cosCurr, sinCurr;
2819 radMajor = hypot(secPoint.x, secPoint.y);
2820 radMinor = radMajor*ratio;
2821 //calculate sin & cos of included angle
2822 incAngle = atan2(secPoint.y, secPoint.x);
2823 cosRot = cos(incAngle);
2824 sinRot = sin(incAngle);
2825 incAngle = M_PIx26.283185307179586 / parts;
2826 curAngle = staparam;
2827 int i = static_cast<int>(curAngle / incAngle);
2828 do {
2829 if (curAngle > endparam) {
2830 curAngle = endparam;
2831 i = parts+2;
2832 }
2833 cosCurr = cos(curAngle);
2834 sinCurr = sin(curAngle);
2835 double x = basePoint.x + (cosCurr*cosRot*radMajor) - (sinCurr*sinRot*radMinor);
2836 double y = basePoint.y + (cosCurr*sinRot*radMajor) + (sinCurr*cosRot*radMinor);
2837 pol->addVertex( DRW_Vertex(x, y, 0.0, 0.0));
2838 curAngle = (++i)*incAngle;
2839 } while (i<parts);
2840 if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10){
2841 pol->flags = 1;
2842 }
2843 pol->layer = this->layer;
2844 pol->lineType = this->lineType;
2845 pol->color = this->color;
2846 pol->lWeight = this->lWeight;
2847 pol->extPoint = this->extPoint;
2848}
2849
2850void DRW_Trace::applyExtrusion(){
2851 if (haveExtrusion) {
2852 calculateAxis(extPoint);
2853 extrudePoint(extPoint, &basePoint);
2854 extrudePoint(extPoint, &secPoint);
2855 extrudePoint(extPoint, &thirdPoint);
2856 extrudePoint(extPoint, &fourPoint);
2857 }
2858}
2859
2860bool DRW_Trace::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2861 switch (code) {
2862 case 12:
2863 thirdPoint.x = reader->getDouble();
2864 break;
2865 case 22:
2866 thirdPoint.y = reader->getDouble();
2867 break;
2868 case 32:
2869 thirdPoint.z = reader->getDouble();
2870 break;
2871 case 13:
2872 fourPoint.x = reader->getDouble();
2873 break;
2874 case 23:
2875 fourPoint.y = reader->getDouble();
2876 break;
2877 case 33:
2878 fourPoint.z = reader->getDouble();
2879 break;
2880 default:
2881 return DRW_Line::parseCode(code, reader);
2882 }
2883
2884 return true;
2885}
2886
2887bool DRW_Trace::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
2888 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
2889 if (!ret)
2890 return ret;
2891 DRW_DBG("\n***************************** parsing Trace *********************************************\n")DRW_dbg::dbg("\n***************************** parsing Trace *********************************************\n"
)
;
2892
2893 thickness = buf->getThickness(version>DRW::AC1014);
2894 basePoint.z = buf->getBitDouble();
2895 basePoint.x = buf->getRawDouble();
2896 basePoint.y = buf->getRawDouble();
2897 secPoint.x = buf->getRawDouble();
2898 secPoint.y = buf->getRawDouble();
2899 secPoint.z = basePoint.z;
2900 thirdPoint.x = buf->getRawDouble();
2901 thirdPoint.y = buf->getRawDouble();
2902 thirdPoint.z = basePoint.z;
2903 fourPoint.x = buf->getRawDouble();
2904 fourPoint.y = buf->getRawDouble();
2905 fourPoint.z = basePoint.z;
2906 extPoint = buf->getExtrusion(version>DRW::AC1014);
2907
2908 DRW_DBG(" - base ")DRW_dbg::dbg(" - base "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
2909 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);
2910 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);
2911 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);
2912 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);
2913 DRW_DBG("\n - thickness: ")DRW_dbg::dbg("\n - thickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness); DRW_DBG("\n")DRW_dbg::dbg("\n");
2914
2915 /* Common Entity Handle Data */
2916 ret = DRW_Entity::parseDwgEntHandle(version, buf);
2917 if (!ret)
2918 return ret;
2919
2920 /* CRC X --- */
2921 return buf->isGood();
2922}
2923
2924bool DRW_Solid::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
2925 DRW_DBG("\n***************************** parsing Solid *********************************************\n")DRW_dbg::dbg("\n***************************** parsing Solid *********************************************\n"
)
;
2926 return DRW_Trace::parseDwg(v, buf, bs);
2927}
2928
2929bool DRW_3Dface::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
2930 switch (code) {
2931 case 70:
2932 invisibleflag = reader->getInt32();
2933 break;
2934 default:
2935 return DRW_Trace::parseCode(code, reader);
2936 }
2937
2938 return true;
2939}
2940
2941bool DRW_3Dface::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
2942 bool ret = DRW_Entity::parseDwg(v, buf, NULL__null, bs);
2943 if (!ret)
2944 return ret;
2945 DRW_DBG("\n***************************** parsing 3Dface *********************************************\n")DRW_dbg::dbg("\n***************************** parsing 3Dface *********************************************\n"
)
;
2946
2947 if ( v < DRW::AC1015 ) {// R13 & R14
2948 basePoint.x = buf->getBitDouble();
2949 basePoint.y = buf->getBitDouble();
2950 basePoint.z = buf->getBitDouble();
2951 secPoint.x = buf->getBitDouble();
2952 secPoint.y = buf->getBitDouble();
2953 secPoint.z = buf->getBitDouble();
2954 thirdPoint.x = buf->getBitDouble();
2955 thirdPoint.y = buf->getBitDouble();
2956 thirdPoint.z = buf->getBitDouble();
2957 fourPoint.x = buf->getBitDouble();
2958 fourPoint.y = buf->getBitDouble();
2959 fourPoint.z = buf->getBitDouble();
2960 invisibleflag = buf->getBitShort();
2961 } else { // 2000+
2962 bool has_no_flag = buf->getBit();
2963 bool z_is_zero = buf->getBit();
2964 basePoint.x = buf->getRawDouble();
2965 basePoint.y = buf->getRawDouble();
2966 basePoint.z = z_is_zero ? 0.0 : buf->getRawDouble();
2967 secPoint.x = buf->getDefaultDouble(basePoint.x);
2968 secPoint.y = buf->getDefaultDouble(basePoint.y);
2969 secPoint.z = buf->getDefaultDouble(basePoint.z);
2970 thirdPoint.x = buf->getDefaultDouble(secPoint.x);
2971 thirdPoint.y = buf->getDefaultDouble(secPoint.y);
2972 thirdPoint.z = buf->getDefaultDouble(secPoint.z);
2973 fourPoint.x = buf->getDefaultDouble(thirdPoint.x);
2974 fourPoint.y = buf->getDefaultDouble(thirdPoint.y);
2975 fourPoint.z = buf->getDefaultDouble(thirdPoint.z);
2976 invisibleflag = has_no_flag ? (int)NoEdge : buf->getBitShort();
2977 }
2978 drw_assert(invisibleflag>=NoEdge);
2979 drw_assert(invisibleflag<=AllEdges);
2980
2981 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");
2982 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");
2983 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");
2984 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");
2985 DRW_DBG(" - Invisibility mask: ")DRW_dbg::dbg(" - Invisibility mask: "); DRW_DBG(invisibleflag)DRW_dbg::dbg(invisibleflag); DRW_DBG("\n")DRW_dbg::dbg("\n");
2986
2987 /* Common Entity Handle Data */
2988 ret = DRW_Entity::parseDwgEntHandle(v, buf);
2989 if (!ret)
2990 return ret;
2991 return buf->isGood();
2992}
2993
2994bool DRW_ModelerGeometry::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
2995 m_bodyBitSize = bs;
2996 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
2997 if (!ret)
2998 return ret;
2999 DRW_DBG("\n***************************** parsing modeler geometry ******************\n")DRW_dbg::dbg("\n***************************** parsing modeler geometry ******************\n"
)
;
3000
3001 m_isEmpty = buf->getBit() != 0;
3002 m_hasModelerData = !m_isEmpty;
3003 m_modelerDataUnknownBit = buf->getBit() != 0;
3004 if (m_hasModelerData)
3005 m_modelerVersion = buf->getBitShort();
3006
3007 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3008 if (eType == DRW::E3DSOLID && v > DRW::AC1018 && buf->numRemainingBytes() > 2) {
3009 dwgHandle historyH = buf->getHandle();
3010 m_historyHandle = historyH.ref;
3011 DRW_DBG(" 3DSOLID history Handle: ")DRW_dbg::dbg(" 3DSOLID history Handle: ");
3012 DRW_DBGHL(historyH.code, historyH.size, historyH.ref)DRW_dbg::dbgHL(historyH.code, historyH.size, historyH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
3013 }
3014
3015 return ret;
3016}
3017
3018bool DRW_ModelerGeometry::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
3019 switch (code) {
3020 case 1:
3021 case 3:
3022 appendTextBytes(m_rawBytes, reader->getString());
3023 break;
3024 case 70:
3025 m_modelerVersion = static_cast<std::uint16_t>(reader->getInt32());
3026 break;
3027 case 350:
3028 case 360:
3029 m_historyHandle = static_cast<std::uint32_t>(reader->getHandleString());
3030 break;
3031 case 310:
3032 {
3033 std::vector<std::uint8_t> decoded;
3034 if (!decodeHexBytes(reader->getString(), decoded))
3035 return false;
3036 appendBytes(m_rawBytes, decoded);
3037 }
3038 break;
3039 default:
3040 return DRW_Entity::parseCode(code, reader);
3041 }
3042 return true;
3043}
3044
3045// DRW_Mesh::parseDwg — AcDbSubDMesh, field order per libreDWG dwg2.spec:2523
3046// (DWG bitstream order, NOT the DXF group-code order). R2010+ only in practice
3047// (the custom-class dispatch only fires when classesmap names "MESH").
3048bool DRW_Mesh::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3049 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
3050 if (!ret)
3051 return ret;
3052 DRW_DBG("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n")DRW_dbg::dbg("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n"
)
;
3053
3054 // Loose OOM/corruption guard: a count can't exceed the bits left in the
3055 // object (each item is >= 1 bit; crease/face values are bit-packed and may be
3056 // far below 1 byte each, so a per-byte bound would falsely reject valid data).
3057 auto sane = [&](std::int32_t n) {
3058 return n >= 0
3059 && static_cast<std::int64_t>(n)
3060 <= static_cast<std::int64_t>(buf->numRemainingBytes()) * 8 + 8;
3061 };
3062
3063 version = buf->getBitShort(); // BS dlevel (71)
3064 blendCrease = buf->getBit() != 0; // B is_watertight (72)
3065
3066 const std::int32_t nSubdiv = buf->getBitLong(); // BL num_subdiv_vertex (91)
3067 if (!sane(nSubdiv)) return false;
3068 subdivisionLevel = nSubdiv;
3069 subdivVertices.reserve(static_cast<size_t>(nSubdiv));
3070 for (std::int32_t i = 0; i < nSubdiv && buf->isGood(); ++i)
3071 subdivVertices.push_back(buf->get3BitDouble());
3072
3073 const std::int32_t nVert = buf->getBitLong(); // BL num_vertex (92)
3074 if (!sane(nVert)) return false;
3075 vertices.reserve(static_cast<size_t>(nVert));
3076 for (std::int32_t i = 0; i < nVert && buf->isGood(); ++i)
3077 vertices.push_back(buf->get3BitDouble());
3078
3079 // faces (93) is a FLAT BL stream of length num_faces; each face is
3080 // [count, idx0, idx1, ...]. num_faces is the stream length, not the polygon
3081 // count — group on the fly.
3082 std::int32_t remaining = buf->getBitLong(); // BL num_faces (93)
3083 if (!sane(remaining)) return false;
3084 while (remaining > 0 && buf->isGood()) {
3085 const std::int32_t cnt = buf->getBitLong();
3086 --remaining;
3087 if (cnt < 0 || cnt > remaining)
3088 break; // corrupt face run
3089 std::vector<std::int32_t> face;
3090 face.reserve(static_cast<size_t>(cnt));
3091 for (std::int32_t j = 0; j < cnt && buf->isGood(); ++j) {
3092 face.push_back(buf->getBitLong());
3093 --remaining;
3094 }
3095 faces.push_back(std::move(face));
3096 }
3097
3098 const std::int32_t nEdges = buf->getBitLong(); // BL num_edges (94)
3099 if (!sane(nEdges)) return false;
3100 edges.reserve(static_cast<size_t>(nEdges));
3101 for (std::int32_t i = 0; i < nEdges && buf->isGood(); ++i) {
3102 const std::int32_t from = buf->getBitLong();
3103 const std::int32_t to = buf->getBitLong();
3104 edges.emplace_back(from, to);
3105 }
3106
3107 const std::int32_t nCrease = buf->getBitLong(); // BL num_crease (95)
3108 if (!sane(nCrease)) return false;
3109 creases.reserve(static_cast<size_t>(nCrease));
3110 for (std::int32_t i = 0; i < nCrease && buf->isGood(); ++i)
3111 creases.push_back(buf->getBitDouble());
3112
3113 buf->getBit(); // unknown_b1
3114 buf->getBit(); // unknown_b2
3115
3116 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3117 return ret;
3118}
3119
3120// DRW_Mesh::parseCode — DXF read (codes 71/72/91/92/10·20·30/93/90/94/95/140).
3121// The 90 stream is shared by faces (after 93) and edges (after 94); m_dxfState
3122// sequences which one is being filled (mirrors DRW_Image::parseCode's stateful
3123// 91/14/24 WIPEOUT-vertex accumulation).
3124bool DRW_Mesh::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3125 switch (code) {
3126 case 71: version = reader->getInt32(); return true;
3127 case 72: blendCrease = reader->getInt32() != 0; return true;
3128 case 91: subdivisionLevel = reader->getInt32(); return true;
3129 case 92: /* base-vertex count */ vertices.reserve(reader->getInt32()); return true;
3130 case 10: vertices.emplace_back(); vertices.back().x = reader->getDouble(); return true;
3131 case 20: if (!vertices.empty()) vertices.back().y = reader->getDouble(); return true;
3132 case 30: if (!vertices.empty()) vertices.back().z = reader->getDouble(); return true;
3133 case 93: m_dxfState = 93; m_dxfPending = 0; return true; // start face stream
3134 case 94: m_dxfState = 94; m_dxfEdgeFrom = -1; (void)reader->getInt32(); return true; // edge count
3135 case 90: {
3136 const std::int32_t val = reader->getInt32();
3137 if (m_dxfState == 93) {
3138 // flat face stream: when no face is in progress, val is the next
3139 // face's vertex count; otherwise val is a vertex index.
3140 if (m_dxfPending == 0) {
3141 faces.emplace_back();
3142 m_dxfPending = (val > 0) ? val : 0;
3143 } else {
3144 if (!faces.empty()) faces.back().push_back(val);
3145 --m_dxfPending;
3146 }
3147 } else if (m_dxfState == 94) {
3148 if (m_dxfEdgeFrom < 0) m_dxfEdgeFrom = val;
3149 else { edges.emplace_back(m_dxfEdgeFrom, val); m_dxfEdgeFrom = -1; }
3150 }
3151 return true;
3152 }
3153 case 95: m_dxfState = 95; creases.reserve(static_cast<size_t>(std::max(0, reader->getInt32()))); return true;
3154 case 140: creases.push_back(reader->getDouble()); return true;
3155 default:
3156 return DRW_Entity::parseCode(code, reader);
3157 }
3158}
3159
3160bool DRW_Mesh::encodeDwg(DRW::Version dwgVersion, dwgBufferW *buf, std::uint32_t bs,
3161 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3162 (void)bs; (void)strBuf;
3163 oType = kDwgClassNum;
3164 if (!encodeDwgCommon(dwgVersion, buf)) return false;
3165
3166 buf->putBitShort(version);
3167 buf->putBit(blendCrease ? 1 : 0);
3168
3169 // DWG stores a subdiv-vertex vector in the slot that DXF exposes as group
3170 // 91 subdivision level. Preserve the vector exactly; DXF write keeps the
3171 // public subdivisionLevel field.
3172 buf->putBitLong(static_cast<std::int32_t>(subdivVertices.size()));
3173 for (const DRW_Coord& vertex : subdivVertices)
3174 buf->put3BitDouble(vertex);
3175
3176 buf->putBitLong(static_cast<std::int32_t>(vertices.size()));
3177 for (const DRW_Coord& vertex : vertices)
3178 buf->put3BitDouble(vertex);
3179
3180 std::int32_t faceStreamCount = 0;
3181 for (const auto& face : faces)
3182 faceStreamCount += static_cast<std::int32_t>(face.size() + 1);
3183 buf->putBitLong(faceStreamCount);
3184 for (const auto& face : faces) {
3185 buf->putBitLong(static_cast<std::int32_t>(face.size()));
3186 for (std::int32_t index : face)
3187 buf->putBitLong(index);
3188 }
3189
3190 buf->putBitLong(static_cast<std::int32_t>(edges.size()));
3191 for (const auto& edge : edges) {
3192 buf->putBitLong(edge.first);
3193 buf->putBitLong(edge.second);
3194 }
3195
3196 buf->putBitLong(static_cast<std::int32_t>(creases.size()));
3197 for (double crease : creases)
3198 buf->putBitDouble(crease);
3199
3200 buf->putBit(0);
3201 buf->putBit(0);
3202
3203 return encodeDwgEntHandle(dwgVersion, buf, handleBuf);
3204}
3205
3206bool DRW_Shape::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3207 m_bodyBitSize = bs;
3208 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
3209 if (!ret)
3210 return ret;
3211 DRW_DBG("\n***************************** parsing SHAPE *****************************\n")DRW_dbg::dbg("\n***************************** parsing SHAPE *****************************\n"
)
;
3212
3213 m_insertionPoint = buf->get3BitDouble();
3214 m_scale = buf->getBitDouble();
3215 m_rotation = buf->getBitDouble();
3216 m_widthFactor = buf->getBitDouble();
3217 m_oblique = buf->getBitDouble();
3218 m_thickness = buf->getBitDouble();
3219 m_shapeIndex = buf->getBitShort();
3220 m_extrusion = buf->get3BitDouble();
3221
3222 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3223 if (ret && buf->numRemainingBytes() > 2) {
3224 dwgHandle shapeFileH = buf->getHandle();
3225 m_shapeFileHandle = shapeFileH.ref;
3226 DRW_DBG(" SHAPEFILE Handle: ")DRW_dbg::dbg(" SHAPEFILE Handle: ");
3227 DRW_DBGHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref)DRW_dbg::dbgHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref
)
;
3228 DRW_DBG("\n")DRW_dbg::dbg("\n");
3229 }
3230 return ret && buf->isGood();
3231}
3232
3233// Phase 6.1: SHAPE encoder (fixed oType 33). Exact inverse of parseDwg above.
3234// Without this override a SHAPE would encode as a LINE (default DRW_Entity).
3235bool DRW_Shape::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
3236 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3237 (void)bs; (void)strBuf;
3238 oType = 33; // SHAPE class id — see dwgreader.cpp case 33
3239 if (!encodeDwgCommon(version, buf)) return false;
3240
3241 buf->put3BitDouble(m_insertionPoint);
3242 buf->putBitDouble(m_scale);
3243 buf->putBitDouble(m_rotation);
3244 buf->putBitDouble(m_widthFactor);
3245 buf->putBitDouble(m_oblique);
3246 buf->putBitDouble(m_thickness);
3247 buf->putBitShort(m_shapeIndex);
3248 buf->put3BitDouble(m_extrusion);
3249
3250 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
3251
3252 // Trailing SHAPEFILE style hard pointer (code 5), byte-count-sized.
3253 dwgHandle sH;
3254 sH.code = 5;
3255 sH.ref = m_shapeFileHandle;
3256 sH.size = 0;
3257 if (m_shapeFileHandle != 0) {
3258 std::uint32_t t = m_shapeFileHandle;
3259 while (t != 0) { t >>= 8; ++sH.size; }
3260 } else {
3261 sH.code = 0; // null handle
3262 }
3263 (handleBuf ? handleBuf : buf)->putHandle(sH);
3264 return true;
3265}
3266
3267bool DRW_Ole2Frame::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3268 m_bodyBitSize = bs;
3269 bool ret = DRW_Entity::parseDwg(v, buf, nullptr, bs);
3270 if (!ret)
3271 return ret;
3272 DRW_DBG("\n***************************** parsing OLE2FRAME ************************\n")DRW_dbg::dbg("\n***************************** parsing OLE2FRAME ************************\n"
)
;
3273
3274 m_flags = buf->getBitShort();
3275 if (v > DRW::AC1014)
3276 m_mode = buf->getBitShort();
3277 m_declaredPayloadLength = buf->getBitLong();
3278 m_payloadStartBit = currentDwgBit(buf);
3279 const std::uint64_t currentBit = currentDwgBit(buf);
3280 const std::uint64_t bodyRemainingBits =
3281 (v > DRW::AC1018 && objSize > currentBit)
3282 ? objSize - currentBit
3283 : static_cast<std::uint64_t>(buf->numRemainingBytes()) * 8u;
3284 const std::uint32_t remainingBytes =
3285 static_cast<std::uint32_t>(std::min<std::uint64_t>(
3286 bodyRemainingBits / 8u,
3287 static_cast<std::uint64_t>(std::numeric_limits<std::uint32_t>::max())));
3288 if (m_declaredPayloadLength > kMaxOlePayloadBytes) {
3289 m_payloadTooLarge = true;
3290 return false;
3291 }
3292 if (m_declaredPayloadLength > remainingBytes) { // remainingBytes is already uint32
3293 m_payloadTruncated = true;
3294 m_payloadByteCount = remainingBytes;
3295 return false;
3296 }
3297
3298 m_payloadPresent = m_declaredPayloadLength > 0;
3299 m_payloadByteCount = m_declaredPayloadLength;
3300 // Phase 6.2: capture the opaque payload bytes (was skipped via moveBitPos)
3301 // so the OLE2FRAME encoder can re-emit them byte-for-byte.
3302 if (m_declaredPayloadLength > 0) {
3303 m_payloadBytes.resize(m_declaredPayloadLength);
3304 if (!buf->getBytes(m_payloadBytes.data(), m_declaredPayloadLength)) {
3305 m_payloadTruncated = true;
3306 m_payloadBytes.clear();
3307 return false;
3308 }
3309 }
3310
3311 if (v > DRW::AC1014 && buf->numRemainingBytes() > 0) {
3312 m_hasR2000TrailingByte = true;
3313 m_r2000TrailingByte = buf->getRawChar8();
3314 }
3315
3316 // Decode the frame rectangle (DXF 10/11) from the OLE header. AutoCAD/ODA do
3317 // NOT store pt1/pt2 as DWG fields; they live in the first ~0x80 bytes of the
3318 // payload as raw little-endian doubles. (libredwg's dwg_decode_ole2 is a stub
3319 // that hardcodes one sample file's corners.) Layout reverse-engineered and
3320 // validated on TS1 + Extruder2: byte 0x00 == 0x80 marker; upper-left @0x02,
3321 // lower-right @0x32, 3 doubles each. Guarded so a non-finite/short payload
3322 // simply leaves pt1/pt2 at the origin (payload still preserved).
3323 if (m_payloadBytes.size() >= 0x4a && m_payloadBytes[0] == 0x80) {
3324 auto rd = [&](std::size_t off) {
3325 double d = 0.0;
3326 std::memcpy(&d, m_payloadBytes.data() + off, sizeof(double));
3327 return d;
3328 };
3329 DRW_Coord ul(rd(0x02), rd(0x0a), rd(0x12));
3330 DRW_Coord lr(rd(0x32), rd(0x3a), rd(0x42));
3331 if (std::isfinite(ul.x) && std::isfinite(ul.y) && std::isfinite(ul.z)
3332 && std::isfinite(lr.x) && std::isfinite(lr.y) && std::isfinite(lr.z)) {
3333 m_pt1 = ul;
3334 m_pt2 = lr;
3335 }
3336 }
3337
3338 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3339 return ret && buf->isGood();
3340}
3341
3342// Phase 6.2: OLE2FRAME encoder (fixed oType 74). Inverse of parseDwg, emitting
3343// the captured opaque payload byte-for-byte. Without this override an OLE2FRAME
3344// would encode as a LINE.
3345bool DRW_Ole2Frame::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
3346 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3347 (void)bs; (void)strBuf;
3348 oType = 74; // OLE2FRAME class id — see dwgreader.cpp case 74
3349 if (!encodeDwgCommon(version, buf)) return false;
3350
3351 buf->putBitShort(m_flags);
3352 if (version > DRW::AC1014)
3353 buf->putBitShort(m_mode);
3354 // Emit the actual captured length so the reader's data_size matches the
3355 // bytes that follow (avoids a declared-vs-actual mismatch on re-read).
3356 const std::uint32_t payloadLen = static_cast<std::uint32_t>(m_payloadBytes.size());
3357 buf->putBitLong(static_cast<std::int32_t>(payloadLen));
3358 if (payloadLen > 0)
3359 buf->putBytes(m_payloadBytes.data(), m_payloadBytes.size());
3360 // R2000+ Unknown RC (ODA §20.4.88): emitted UNCONDITIONALLY for version >
3361 // AC1014. parseDwg reads it whenever bytes remain before the handle stream
3362 // (which is always — handle data always follows), so gating the write on
3363 // m_hasR2000TrailingByte desynced a directly-constructed OLE2FRAME (the
3364 // default false): the parser consumed the first handle byte as this RC and
3365 // shifted the entity handle stream. Default m_r2000TrailingByte is 0, so
3366 // constructed entities align and round-tripped ones keep the captured byte.
3367 if (version > DRW::AC1014)
3368 buf->putRawChar8(m_r2000TrailingByte);
3369
3370 return encodeDwgEntHandle(version, buf, handleBuf);
3371}
3372
3373bool DRW_Light::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3374 dwgBuffer sBuff = *buf;
3375 dwgBuffer *sBuf = v > DRW::AC1018 ? &sBuff : buf;
3376 bool ret = DRW_Entity::parseDwg(v, buf, sBuf, bs);
3377 if (!ret)
3378 return ret;
3379 DRW_DBG("\n***************************** parsing LIGHT *****************************\n")DRW_dbg::dbg("\n***************************** parsing LIGHT *****************************\n"
)
;
3380
3381 const std::uint64_t bodyDataEndBit = v > DRW::AC1018 ? currentDwgBit(sBuf) : 0;
3382 m_classVersion = static_cast<std::uint32_t>(buf->getBitLong());
3383 m_name = sBuf->getVariableText(v, false);
3384 m_type = static_cast<std::uint32_t>(buf->getBitLong());
3385 m_status = buf->getBit() != 0;
3386 m_color = buf->getCmColor(v);
3387 m_plotGlyph = buf->getBit() != 0;
3388 m_intensity = buf->getBitDouble();
3389 m_position = buf->get3BitDouble();
3390 m_target = buf->get3BitDouble();
3391 m_attenuationType = static_cast<std::uint32_t>(buf->getBitLong());
3392 m_useAttenuationLimits = buf->getBit() != 0;
3393 m_attenuationStartLimit = buf->getBitDouble();
3394 m_attenuationEndLimit = buf->getBitDouble();
3395 m_hotspotAngle = buf->getBitDouble();
3396 m_falloffAngle = buf->getBitDouble();
3397 m_castShadows = buf->getBit() != 0;
3398 m_shadowType = static_cast<std::uint32_t>(buf->getBitLong());
3399 m_shadowMapSize = buf->getBitShort();
3400 m_shadowMapSoftness = buf->getRawChar8();
3401
3402 if (v > DRW::AC1018 && currentDwgBit(buf) < bodyDataEndBit) {
3403 m_hasPhotometricData = buf->getBit() != 0;
3404 if (m_hasPhotometricData) {
3405 m_hasWebFile = buf->getBit() != 0;
3406 m_webFile = sBuf->getVariableText(v, false);
3407 m_physicalIntensityMethod = buf->getBitShort();
3408 m_physicalIntensity = buf->getBitDouble();
3409 m_illuminanceDistance = buf->getBitDouble();
3410 m_lampColorType = buf->getBitShort();
3411 m_lampColorTemperature = buf->getBitDouble();
3412 m_lampColorPreset = buf->getBitShort();
3413 m_webRotation = buf->get3BitDouble();
3414 m_extendedLightShape = buf->getBitShort();
3415 m_extendedLightLength = buf->getBitDouble();
3416 m_extendedLightWidth = buf->getBitDouble();
3417 m_extendedLightRadius = buf->getBitDouble();
3418 }
3419 }
3420
3421 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3422 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");
3423 return ret;
3424}
3425
3426bool DRW_Light::encodeDwg(DRW::Version v, dwgBufferW *buf, std::uint32_t bs,
3427 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3428 (void)bs;
3429 if (v < DRW::AC1021)
3430 return false;
3431
3432 oType = kDwgClassNum;
3433 if (!encodeDwgCommon(v, buf, strBuf))
3434 return false;
3435
3436 dwgBufferW *sb = strBuf ? strBuf : buf;
3437 buf->putBitLong(m_classVersion);
3438 sb->putVariableText(v, m_name);
3439 buf->putBitLong(m_type);
3440 buf->putBit(m_status ? 1 : 0);
3441 buf->putCmColor(v, static_cast<std::uint16_t>(m_color));
3442 buf->putBit(m_plotGlyph ? 1 : 0);
3443 buf->putBitDouble(m_intensity);
3444 buf->put3BitDouble(m_position);
3445 buf->put3BitDouble(m_target);
3446 buf->putBitLong(m_attenuationType);
3447 buf->putBit(m_useAttenuationLimits ? 1 : 0);
3448 buf->putBitDouble(m_attenuationStartLimit);
3449 buf->putBitDouble(m_attenuationEndLimit);
3450 buf->putBitDouble(m_hotspotAngle);
3451 buf->putBitDouble(m_falloffAngle);
3452 buf->putBit(m_castShadows ? 1 : 0);
3453 buf->putBitLong(m_shadowType);
3454 buf->putBitShort(m_shadowMapSize);
3455 buf->putRawChar8(m_shadowMapSoftness);
3456
3457 buf->putBit(m_hasPhotometricData ? 1 : 0);
3458 if (m_hasPhotometricData) {
3459 buf->putBit(m_hasWebFile ? 1 : 0);
3460 sb->putVariableText(v, m_webFile);
3461 buf->putBitShort(m_physicalIntensityMethod);
3462 buf->putBitDouble(m_physicalIntensity);
3463 buf->putBitDouble(m_illuminanceDistance);
3464 buf->putBitShort(m_lampColorType);
3465 buf->putBitDouble(m_lampColorTemperature);
3466 buf->putBitShort(m_lampColorPreset);
3467 buf->put3BitDouble(m_webRotation);
3468 buf->putBitShort(m_extendedLightShape);
3469 buf->putBitDouble(m_extendedLightLength);
3470 buf->putBitDouble(m_extendedLightWidth);
3471 buf->putBitDouble(m_extendedLightRadius);
3472 }
3473
3474 return encodeDwgEntHandle(v, buf, handleBuf);
3475}
3476
3477// DRW_Section::parseDwg — SECTIONOBJECT / AcDbSection, field order per
3478// libreDWG dwg2.spec DWG_ENTITY(SECTIONOBJECT): BL state, BL flags, T name,
3479// 3BD vert_dir, BD top/bottom height, BS indicator_alpha, CMTC indicator_color,
3480// BL num_verts + verts, BL num_blverts + blverts; then the common entity handle
3481// data followed by the section_settings hard reference (H 5, 360).
3482bool DRW_SectionObject::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3483 // R2007+ keeps text in a separate string stream; read scalars from buf
3484 // (data stream) and text from sBuf, exactly like DRW_Light.
3485 dwgBuffer sBuff = *buf;
3486 dwgBuffer *sBuf = v > DRW::AC1018 ? &sBuff : buf;
3487 bool ret = DRW_Entity::parseDwg(v, buf, sBuf, bs);
3488 if (!ret)
3489 return true; // graceful-degrade: keep the raw shelf
3490 DRW_DBG("\n***************************** parsing SECTIONOBJECT *********************\n")DRW_dbg::dbg("\n***************************** parsing SECTIONOBJECT *********************\n"
)
;
3491
3492 m_state = static_cast<std::uint32_t>(buf->getBitLong());
3493 m_flags = static_cast<std::uint32_t>(buf->getBitLong());
3494 m_name = sBuf->getVariableText(v, false);
3495 m_vertDir = buf->get3BitDouble();
3496 m_topHeight = buf->getBitDouble();
3497 m_bottomHeight = buf->getBitDouble();
3498 m_indicatorAlpha = buf->getBitShort();
3499 m_indicatorColor = buf->getCmColor(v);
3500
3501 // num_verts / num_blverts are bounded before looping — a corrupt count must
3502 // never drive an unbounded allocation, and a short read must never drop the
3503 // object (raw shelf is the round-trip floor).
3504 constexpr std::uint32_t kMaxSectionVerts = 1u << 20; // 1,048,576
3505 std::int32_t nv = buf->getBitLong();
3506 std::uint32_t numVerts = (nv > 0) ? static_cast<std::uint32_t>(nv) : 0u;
3507 if (numVerts > kMaxSectionVerts)
3508 numVerts = 0;
3509 m_verts.clear();
3510 m_verts.reserve(numVerts);
3511 for (std::uint32_t i = 0; i < numVerts && buf->isGood(); ++i)
3512 m_verts.push_back(buf->get3BitDouble());
3513
3514 std::int32_t nb = buf->getBitLong();
3515 std::uint32_t numBl = (nb > 0) ? static_cast<std::uint32_t>(nb) : 0u;
3516 if (numBl > kMaxSectionVerts)
3517 numBl = 0;
3518 m_blVerts.clear();
3519 m_blVerts.reserve(numBl);
3520 for (std::uint32_t i = 0; i < numBl && buf->isGood(); ++i)
3521 m_blVerts.push_back(buf->get3BitDouble());
3522
3523 // Handle stream: parseDwgEntHandle reads the common entity handles — it
3524 // resets buf to objSize for R2007+ and reads inline (after the exact body
3525 // above) for <=AC1018. The section_settings hard reference follows the
3526 // common handles, so read it from buf right after (guarded by remaining
3527 // bytes so a truncated object never over-reads).
3528 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3529 // The section_settings hard reference follows the common entity handles.
3530 // The R2007+ handle stream is small (a few bytes) so guard on any
3531 // remaining byte rather than the 4-byte common-object slack.
3532 if (ret && buf->isGood() && buf->numRemainingBytes() >= 1) {
3533 dwgHandle ssH = buf->getOffsetHandle(handle);
3534 m_sectionSettingsHandle = ssH.ref;
3535 DRW_DBG(" section_settings Handle: ")DRW_dbg::dbg(" section_settings Handle: ");
3536 DRW_DBGHL(ssH.code, ssH.size, ssH.ref)DRW_dbg::dbgHL(ssH.code, ssH.size, ssH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
3537 }
3538 DRW_DBG("SECTIONOBJECT name: ")DRW_dbg::dbg("SECTIONOBJECT name: "); DRW_DBG(m_name.c_str())DRW_dbg::dbg(m_name.c_str());
3539 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");
3540 return true; // graceful-degrade — always deliver typed add + raw shelf
3541}
3542
3543bool DRW_Tolerance::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3544 switch (code) {
3545 case 1:
3546 text = reader->getUtf8String();
3547 break;
3548 case 3:
3549 dimStyleName = reader->getUtf8String();
3550 break;
3551 case 10:
3552 insertionPoint.x = reader->getDouble();
3553 break;
3554 case 20:
3555 insertionPoint.y = reader->getDouble();
3556 break;
3557 case 30:
3558 insertionPoint.z = reader->getDouble();
3559 break;
3560 case 11:
3561 xAxisDirectionVector.x = reader->getDouble();
3562 break;
3563 case 21:
3564 xAxisDirectionVector.y = reader->getDouble();
3565 break;
3566 case 31:
3567 xAxisDirectionVector.z = reader->getDouble();
3568 break;
3569 case 210:
3570 extPoint.x = reader->getDouble();
3571 break;
3572 case 220:
3573 extPoint.y = reader->getDouble();
3574 break;
3575 case 230:
3576 extPoint.z = reader->getDouble();
3577 break;
3578 default:
3579 return DRW_Entity::parseCode(code, reader);
3580 }
3581 return true;
3582}
3583
3584bool DRW_Tolerance::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){
3585 dwgBuffer sBuff = *buf;
3586 dwgBuffer *sBuf = buf;
3587 if (v > DRW::AC1018)
3588 sBuf = &sBuff;
3589
3590 bool ret = DRW_Entity::parseDwg(v, buf, sBuf, bs);
3591 if (!ret)
3592 return ret;
3593
3594 DRW_DBG("\n***************************** parsing tolerance *********************************************\n")DRW_dbg::dbg("\n***************************** parsing tolerance *********************************************\n"
)
;
3595 if (v < DRW::AC1015) {
3596 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");
3597 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");
3598 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");
3599 }
3600
3601 insertionPoint = buf->get3BitDouble();
3602 DRW_DBG("insertionPoint: ")DRW_dbg::dbg("insertionPoint: "); DRW_DBGPT(insertionPoint.x, insertionPoint.y, insertionPoint.z)DRW_dbg::dbgPT(insertionPoint.x, insertionPoint.y, insertionPoint
.z)
;
3603 xAxisDirectionVector = buf->get3BitDouble();
3604 DRW_DBG("\nxAxisDirectionVector: ")DRW_dbg::dbg("\nxAxisDirectionVector: ");
3605 DRW_DBGPT(xAxisDirectionVector.x, xAxisDirectionVector.y, xAxisDirectionVector.z)DRW_dbg::dbgPT(xAxisDirectionVector.x, xAxisDirectionVector.y
, xAxisDirectionVector.z)
;
3606 extPoint = buf->get3BitDouble();
3607 DRW_DBG("\nextPoint: ")DRW_dbg::dbg("\nextPoint: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
3608 text = sBuf->getVariableText(v, false);
3609 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");
3610
3611 ret = DRW_Entity::parseDwgEntHandle(v, buf);
3612 if (!ret)
3613 return ret;
3614 dimStyleH = buf->getHandle();
3615 DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: ");
3616 DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
3617 return buf->isGood();
3618}
3619
3620bool DRW_Tolerance::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
3621 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
3622 (void)bs;
3623 oType = 46;
3624 if (!encodeDwgCommon(version, buf, strBuf))
3625 return false;
3626
3627 if (version < DRW::AC1015) {
3628 buf->putBitShort(0);
3629 buf->putBitDouble(0.0);
3630 buf->putBitDouble(0.0);
3631 }
3632
3633 buf->put3BitDouble(insertionPoint);
3634 buf->put3BitDouble(xAxisDirectionVector);
3635 buf->put3BitDouble(extPoint);
3636 (strBuf ? strBuf : buf)->putVariableText(version, text);
3637
3638 if (!encodeDwgEntHandle(version, buf, handleBuf))
3639 return false;
3640
3641 dwgBufferW *hb = handleBuf ? handleBuf : buf;
3642 putHardPointerHandle(hb, (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref);
3643 return true;
3644}
3645
3646
3647bool DRW_Block::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3648 switch (code) {
3649 case 1:
3650 xrefPath = reader->getUtf8String();
3651 break;
3652 case 2:
3653 name = reader->getUtf8String();
3654 break;
3655 case 70:
3656 flags = reader->getInt32();
3657 break;
3658 default:
3659 return DRW_Point::parseCode(code, reader);
3660 }
3661
3662 return true;
3663}
3664
3665bool DRW_Block::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
3666 dwgBuffer sBuff = *buf;
3667 dwgBuffer *sBuf = buf;
3668 if (version > DRW::AC1018) {//2007+
3669 sBuf = &sBuff; //separate buffer for strings
3670 }
3671 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
3672 if (!ret)
3673 return ret;
3674 if (!isEnd){
3675 DRW_DBG("\n***************************** parsing block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing block *********************************************\n"
)
;
3676 name = sBuf->getVariableText(version, false);
3677 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");
3678 } else {
3679 DRW_DBG("\n***************************** parsing end block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing end block *********************************************\n"
)
;
3680 }
3681 if (version > DRW::AC1018) {//2007+
3682 std::uint8_t unk = buf->getBit();
3683 DRW_DBG("unknown bit: ")DRW_dbg::dbg("unknown bit: "); DRW_DBG(unk)DRW_dbg::dbg(unk); DRW_DBG("\n")DRW_dbg::dbg("\n");
3684 }
3685// X handleAssoc; //X
3686 ret = DRW_Entity::parseDwgEntHandle(version, buf);
3687 if (!ret)
3688 return ret;
3689 // RS crc; //RS */
3690 return buf->isGood();
3691}
3692
3693bool DRW_Insert::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3694 switch (code) {
3695 case 2:
3696 name = reader->getUtf8String();
3697 break;
3698 case 41:
3699 xscale = reader->getDouble();
3700 break;
3701 case 42:
3702 yscale = reader->getDouble();
3703 break;
3704 case 43:
3705 zscale = reader->getDouble();
3706 break;
3707 case 50:
3708 angle = reader->getDouble();
3709 angle = angle/ARAD57.29577951308232; //convert to radian
3710 break;
3711 case 70:
3712 colcount = reader->getInt32();
3713 break;
3714 case 71:
3715 rowcount = reader->getInt32();
3716 break;
3717 case 44:
3718 colspace = reader->getDouble();
3719 break;
3720 case 45:
3721 rowspace = reader->getDouble();
3722 break;
3723 default:
3724 return DRW_Point::parseCode(code, reader);
3725 }
3726
3727 return true;
3728}
3729
3730bool DRW_Table::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
3731 auto ensureGrid = [this]() {
3732 if (m_dxfRowsExpected < 0 || m_dxfColumnsExpected < 0)
3733 return;
3734
3735 const std::uint32_t rows = static_cast<std::uint32_t>(m_dxfRowsExpected);
3736 const std::uint32_t columns = static_cast<std::uint32_t>(m_dxfColumnsExpected);
3737 if (rows > kMaxTableRows || columns > kMaxTableColumns
3738 || (columns != 0 && rows > kMaxTableCells / columns)) {
3739 return;
3740 }
3741
3742 if (m_content.m_columns.size() != columns) {
3743 m_content.m_columns.clear();
3744 m_content.m_columns.resize(columns);
3745 m_dxfColumnWidthsRead = 0;
3746 }
3747 if (m_content.m_rows.size() != rows) {
3748 m_content.m_rows.clear();
3749 m_content.m_rows.resize(rows);
3750 m_dxfRowHeightsRead = 0;
3751 }
3752 for (auto& row : m_content.m_rows)
3753 row.m_cells.resize(columns);
3754
3755 m_hasSemanticContent = true;
3756 m_semanticContentComplete = true;
3757 };
3758
3759 auto currentCell = [this]() -> DRW_TableCell* {
3760 if (m_dxfCurrentCell < 0 || m_content.m_columns.empty()
3761 || m_content.m_rows.empty()) {
3762 return nullptr;
3763 }
3764
3765 const std::size_t columns = m_content.m_columns.size();
3766 const std::size_t cell = static_cast<std::size_t>(m_dxfCurrentCell);
3767 const std::size_t row = cell / columns;
3768 const std::size_t column = cell % columns;
3769 if (row >= m_content.m_rows.size()
3770 || column >= m_content.m_rows[row].m_cells.size()) {
3771 return nullptr;
3772 }
3773 return &m_content.m_rows[row].m_cells[column];
3774 };
3775
3776 auto currentContent = [&currentCell]() -> DRW_TableCellContent* {
3777 DRW_TableCell *cell = currentCell();
3778 if (cell == nullptr)
3779 return nullptr;
3780 if (cell->m_contents.empty() || cell->m_contents.back().m_type != 1) {
3781 DRW_TableCellContent content;
3782 content.m_type = 1;
3783 cell->m_contents.push_back(content);
3784 }
3785 return &cell->m_contents.back();
3786 };
3787
3788 if (code == 100) {
3789 const std::string subclass = reader->getString();
3790 if (subclass == "AcDbBlockReference") {
3791 m_dxfSubclass = DxfSubclass::BlockReference;
3792 } else if (subclass == "AcDbTable") {
3793 m_dxfSubclass = DxfSubclass::Table;
3794 } else if (subclass == "AcDbEntity") {
3795 m_dxfSubclass = DxfSubclass::Entity;
3796 }
3797 return true;
3798 }
3799
3800 if (m_dxfSubclass != DxfSubclass::Table)
3801 return DRW_Insert::parseCode(code, reader);
3802
3803 switch (code) {
3804 case 342:
3805 m_tableStyleHandle = static_cast<std::uint32_t>(reader->getHandleString());
3806 m_content.m_tableStyleHandle = m_tableStyleHandle;
3807 break;
3808 case 343:
3809 reader->getHandleString();
3810 break;
3811 case 11:
3812 m_horizontalDirection.x = reader->getDouble();
3813 break;
3814 case 21:
3815 m_horizontalDirection.y = reader->getDouble();
3816 break;
3817 case 31:
3818 m_horizontalDirection.z = reader->getDouble();
3819 break;
3820 case 90:
3821 if (m_dxfInCellValue) {
3822 if (DRW_TableCellContent *content = currentContent())
3823 content->m_value.m_dataType = reader->getInt32();
3824 else
3825 reader->getInt32();
3826 } else {
3827 m_valueFlag = reader->getInt32();
3828 }
3829 break;
3830 case 91:
3831 if (m_dxfRowsExpected < 0 && !m_dxfInCellValue) {
3832 m_dxfRowsExpected = reader->getInt32();
3833 ensureGrid();
3834 } else {
3835 reader->getInt32();
3836 }
3837 break;
3838 case 92:
3839 if (m_dxfColumnsExpected < 0 && !m_dxfInCellValue) {
3840 m_dxfColumnsExpected = reader->getInt32();
3841 ensureGrid();
3842 } else {
3843 reader->getInt32();
3844 }
3845 break;
3846 case 93:
3847 case 94:
3848 case 95:
3849 case 96:
3850 case 172:
3851 case 173:
3852 case 174:
3853 case 175:
3854 case 176:
3855 case 178:
3856 reader->getInt32();
3857 break;
3858 case 141:
3859 ensureGrid();
3860 if (m_dxfRowHeightsRead < m_content.m_rows.size())
3861 m_content.m_rows[m_dxfRowHeightsRead++].m_height = reader->getDouble();
3862 else
3863 reader->getDouble();
3864 break;
3865 case 142:
3866 ensureGrid();
3867 if (m_dxfColumnWidthsRead < m_content.m_columns.size())
3868 m_content.m_columns[m_dxfColumnWidthsRead++].m_width = reader->getDouble();
3869 else
3870 reader->getDouble();
3871 break;
3872 case 145:
3873 reader->getDouble();
3874 break;
3875 case 171:
3876 ensureGrid();
3877 if (!m_content.m_rows.empty() && !m_content.m_columns.empty()
3878 && m_dxfNextCell < m_content.m_rows.size() * m_content.m_columns.size()) {
3879 m_dxfCurrentCell = static_cast<int>(m_dxfNextCell++);
3880 if (DRW_TableCell *cell = currentCell())
3881 cell->m_flags = reader->getInt32();
3882 else
3883 reader->getInt32();
3884 } else {
3885 m_dxfCurrentCell = -1;
3886 reader->getInt32();
3887 }
3888 m_dxfInCellValue = false;
3889 break;
3890 case 301:
3891 m_dxfInCellValue = reader->getString() == "CELL_VALUE";
3892 if (m_dxfInCellValue)
3893 currentContent();
3894 break;
3895 case 1:
3896 case 302: {
3897 const UTF8STRINGstd::string text = reader->getUtf8String();
3898 if (m_dxfInCellValue) {
3899 if (DRW_TableCellContent *content = currentContent()) {
3900 content->m_text = text;
3901 content->m_value.m_dataType = 4;
3902 content->m_value.m_value.addString(1, text);
3903 }
3904 }
3905 break;
3906 }
3907 case 300:
3908 if (m_dxfInCellValue) {
3909 if (DRW_TableCellContent *content = currentContent())
3910 content->m_value.m_valueString = reader->getUtf8String();
3911 else
3912 reader->getUtf8String();
3913 } else {
3914 reader->getUtf8String();
3915 }
3916 break;
3917 case 304:
3918 reader->getString();
3919 m_dxfInCellValue = false;
3920 break;
3921 default:
3922 return DRW_Entity::parseCode(code, reader);
3923 }
3924
3925 return true;
3926}
3927
3928bool DRW_Insert::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
3929 std::int32_t objCount = 0;
3930 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
3931 if (!ret)
3932 return ret;
3933 DRW_DBG("\n************************** parsing insert/minsert *****************************************\n")DRW_dbg::dbg("\n************************** parsing insert/minsert *****************************************\n"
)
;
3934 basePoint.x = buf->getBitDouble();
3935 basePoint.y = buf->getBitDouble();
3936 basePoint.z = buf->getBitDouble();
3937 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");
3938 if (version < DRW::AC1015) {//14-
3939 xscale = buf->getBitDouble();
3940 yscale = buf->getBitDouble();
3941 zscale = buf->getBitDouble();
3942 } else {
3943 std::uint8_t dataFlags = buf->get2Bits();
3944 if (dataFlags == 3){
3945 //none default value 1,1,1
3946 } else if (dataFlags == 1){ //x default value 1, y & z can be x value
3947 yscale = buf->getDefaultDouble(xscale);
3948 zscale = buf->getDefaultDouble(xscale);
3949 } else if (dataFlags == 2){
3950 xscale = buf->getRawDouble();
3951 yscale = zscale = xscale;
3952 } else { //dataFlags == 0
3953 xscale = buf->getRawDouble();
3954 yscale = buf->getDefaultDouble(xscale);
3955 zscale = buf->getDefaultDouble(xscale);
3956 }
3957 }
3958 angle = buf->getBitDouble();
3959 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);
3960 extPoint = buf->getExtrusion(false); //3BD R14 style
3961 DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
3962
3963 bool hasAttrib = buf->getBit();
3964 DRW_DBG(" has Attrib: ")DRW_dbg::dbg(" has Attrib: "); DRW_DBG(hasAttrib)DRW_dbg::dbg(hasAttrib);
3965
3966 if (hasAttrib && version > DRW::AC1015) {//2004+
3967 objCount = buf->getBitLong();
3968 DRW_UNUSED(objCount)(void)objCount;
3969 DRW_DBG(" objCount: ")DRW_dbg::dbg(" objCount: "); DRW_DBG(objCount)DRW_dbg::dbg(objCount); DRW_DBG("\n")DRW_dbg::dbg("\n");
3970 }
3971 if (oType == 8) {//entity are minsert
3972 colcount = buf->getBitShort();
3973 rowcount = buf->getBitShort();
3974 colspace = buf->getBitDouble();
3975 rowspace = buf->getBitDouble();
3976 }
3977 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");
3978 ret = DRW_Entity::parseDwgEntHandle(version, buf);
3979 blockRecH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3980 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");
3981 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");
3982
3983 /*attribs follows*/
3984 if (hasAttrib) {
3985 if (version < DRW::AC1018) {//2000-
3986 dwgHandle attH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3987 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");
3988 attribHandles.push_back(attH);
3989 attH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3990 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");
3991 attribHandles.push_back(attH);
3992 } else {
3993 for (std::int32_t i=0; i < objCount && buf->isGood(); ++i){
3994 dwgHandle attH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
3995 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");
3996 attribHandles.push_back(attH);
3997 }
3998 }
3999 seqendH = buf->getHandle(); /* H 2 BLOCK HEADER (hard pointer) */
4000 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");
4001 }
4002 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");
4003
4004 if (!ret)
4005 return ret;
4006 // RS crc; //RS */
4007 return buf->isGood();
4008}
4009
4010bool DRW_Table::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4011 if (version < DRW::AC1015)
4012 return false;
4013
4014 dwgBuffer sBuff = *buf;
4015 sBuff.setVariableTextByteLength(true);
4016 dwgBuffer *sBuf = &sBuff;
4017 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
4018 if (!ret)
4019 return ret;
4020
4021 DRW_DBG("\n************************** parsing table *****************************************\n")DRW_dbg::dbg("\n************************** parsing table *****************************************\n"
)
;
4022 basePoint.x = buf->getBitDouble();
4023 basePoint.y = buf->getBitDouble();
4024 basePoint.z = buf->getBitDouble();
4025
4026 std::uint8_t dataFlags = buf->get2Bits();
4027 if (dataFlags == 3) {
4028 // default scale 1,1,1
4029 } else if (dataFlags == 1) {
4030 yscale = buf->getDefaultDouble(xscale);
4031 zscale = buf->getDefaultDouble(xscale);
4032 } else if (dataFlags == 2) {
4033 xscale = buf->getRawDouble();
4034 yscale = zscale = xscale;
4035 } else {
4036 xscale = buf->getRawDouble();
4037 yscale = buf->getDefaultDouble(xscale);
4038 zscale = buf->getDefaultDouble(xscale);
4039 }
4040
4041 angle = buf->getBitDouble();
4042 extPoint = buf->getExtrusion(false);
4043
4044 std::int32_t objCount = 0;
4045 bool hasAttrib = buf->getBit();
4046 if (hasAttrib && version > DRW::AC1015)
4047 objCount = buf->getBitLong();
4048
4049 dwgBuffer hBuff = *buf;
4050 if (version <= DRW::AC1018) {
4051 // R2000/R2004: parseDwgEntHandle only re-seeks to the handle stream
4052 // for version > AC1018 (2007+ string area). For the legacy versions
4053 // seek the snapshot to the handle-stream start (objSize is the
4054 // bit offset of the handle stream, RL field read in
4055 // DRW_Entity::parseDwg) or every handle below reads mid-DATA garbage.
4056 hBuff.setPosition(objSize >> 3);
4057 hBuff.setBitPos(objSize & 7);
4058 }
4059 ret = DRW_Entity::parseDwgEntHandle(version, &hBuff);
4060 blockRecH = hBuff.getHandle();
4061
4062 if (hasAttrib) {
4063 for (std::int32_t i = 0; i < objCount && hBuff.isGood(); ++i)
4064 attribHandles.push_back(hBuff.getHandle());
4065 seqendH = hBuff.getHandle();
4066 }
4067
4068 if (!ret)
4069 return ret;
4070
4071 if (version >= DRW::AC1024) {
4072 buf->getRawChar8();
4073 readTableHandle(&hBuff);
4074 buf->getBitLong();
4075 if (version >= DRW::AC1027)
4076 buf->getBitLong();
4077 else
4078 buf->getBit();
4079
4080 m_hasSemanticContent = true;
4081 m_semanticContentComplete = parseTableContent(version, buf, sBuf, &hBuff, m_content);
4082 if (m_content.m_tableStyleHandle != 0) {
4083 m_tableStyleHandle = m_content.m_tableStyleHandle;
4084 }
4085 if (!m_semanticContentComplete) {
4086 DRW_DBG("TABLECONTENT parse incomplete; anonymous block insert kept\n")DRW_dbg::dbg("TABLECONTENT parse incomplete; anonymous block insert kept\n"
)
;
4087 return true;
4088 }
4089
4090 buf->getBitShort();
4091 m_horizontalDirection = buf->get3BitDouble();
4092
4093 const std::uint64_t breakStartBit = currentDwgBit(buf);
4094 const bool hasBreakData = buf->getBitLong() != 0;
4095 if (hasBreakData) {
4096 buf->getBitLong();
4097 buf->getBitLong();
4098 buf->getBitDouble();
4099 buf->getBitLong();
4100 buf->getBitLong();
4101 const std::uint32_t manualPositions = buf->getBitLong();
4102 if (manualPositions > kMaxTableItems) {
4103 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4104 "table-break-data", breakStartBit, currentDwgBit(buf),
4105 version, manualPositions, false));
4106 return true;
4107 }
4108 for (std::uint32_t i = 0; i < manualPositions; ++i) {
4109 buf->get3BitDouble();
4110 buf->getBitDouble();
4111 buf->getBitLong();
4112 }
4113 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4114 "table-break-data", breakStartBit, currentDwgBit(buf),
4115 version, manualPositions, buf->isGood()));
4116 }
4117
4118 const std::uint64_t rowRangeStartBit = currentDwgBit(buf);
4119 const std::uint32_t rowRanges = buf->getBitLong();
4120 if (rowRanges <= kMaxTableItems) {
4121 for (std::uint32_t i = 0; i < rowRanges; ++i) {
4122 buf->get3BitDouble();
4123 buf->getBitLong();
4124 buf->getBitLong();
4125 }
4126 if (rowRanges != 0) {
4127 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4128 "table-row-ranges", rowRangeStartBit, currentDwgBit(buf),
4129 version, rowRanges, buf->isGood()));
4130 }
4131 } else {
4132 m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange(
4133 "table-row-ranges", rowRangeStartBit, currentDwgBit(buf),
4134 version, rowRanges, false));
4135 }
4136
4137 return true;
4138 }
4139
4140 m_valueFlag = buf->getBitShort();
4141 m_horizontalDirection = buf->get3BitDouble();
4142 const std::uint32_t columns = buf->getBitLong();
4143 const std::uint32_t rows = buf->getBitLong();
4144 if (columns > kMaxTableColumns || rows > kMaxTableRows
4145 || (columns != 0 && rows > kMaxTableCells / columns)) {
4146 return true;
4147 }
4148
4149 m_hasSemanticContent = true;
4150 m_semanticContentComplete = false;
4151 m_content.m_columns.clear();
4152 m_content.m_rows.clear();
4153 m_content.m_columns.reserve(columns);
4154 m_content.m_rows.reserve(rows);
4155 for (std::uint32_t i = 0; i < columns; ++i) {
4156 DRW_TableColumn column;
4157 column.m_width = buf->getBitDouble();
4158 m_content.m_columns.push_back(column);
4159 }
4160 for (std::uint32_t i = 0; i < rows; ++i) {
4161 DRW_TableRow row;
4162 row.m_height = buf->getBitDouble();
4163 row.m_cells.resize(columns);
4164 m_content.m_rows.push_back(row);
4165 }
4166 m_tableStyleHandle = readTableHandle(&hBuff);
4167 m_content.m_tableStyleHandle = m_tableStyleHandle;
4168 m_semanticContentComplete = true;
4169 // For <=AC1018 (R2000/R2004) there is no separate R2007+ string stream:
4170 // DRW_Entity::parseDwg only seeks sBuf when version > AC1018 (see the
4171 // `strBuf != NULL && version > DRW::AC1018` guard there), so legacy cell
4172 // text is inline in `buf`. Passing the stale sBuf copy here would read
4173 // text from the wrong position and desync `buf`. Pass nullptr so the
4174 // cell readers' `textBuf = strBuf ? strBuf : buf` falls back to the
4175 // inline `buf`. R2007 (AC1021) keeps the separate sBuf stream.
4176 dwgBuffer *cellStrBuf = (version > DRW::AC1018) ? sBuf : nullptr;
4177 for (std::uint32_t row = 0; row < rows && m_semanticContentComplete; ++row) {
4178 for (std::uint32_t column = 0; column < columns; ++column) {
4179 if (!parseR2007TableCell(version, buf, cellStrBuf, &hBuff,
4180 m_content.m_rows[row].m_cells[column],
4181 &m_content.m_subrecordRanges)) {
4182 m_semanticContentComplete = false;
4183 break;
4184 }
4185 }
4186 }
4187
4188 if (m_semanticContentComplete)
4189 m_semanticContentComplete = skipR2007TableOverrides(
4190 version, buf, cellStrBuf, &hBuff, &m_content.m_subrecordRanges);
4191 if (!m_semanticContentComplete)
4192 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"
)
;
4193
4194 return true;
4195}
4196
4197bool DRW_TableContentObject::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4198 if (version <= DRW::AC1018)
4199 return false;
4200
4201 dwgBuffer sBuff = *buf;
4202 sBuff.setVariableTextByteLength(true);
4203 dwgBuffer *sBuf = &sBuff;
4204 bool ret = DRW_TableEntry::parseDwg(version, buf, sBuf, bs);
4205 DRW_DBG("\n************************** parsing table content object ************************\n")DRW_dbg::dbg("\n************************** parsing table content object ************************\n"
)
;
4206 if (!ret)
4207 return ret;
4208
4209 dwgBuffer hBuff = *buf;
4210 seekTableObjectHandleStream(version, &hBuff, objSize);
4211 readTableObjectCommonHandles(&hBuff, handle, numReactors, xDictFlag, &parentHandle);
4212
4213 m_parseComplete = parseTableContent(version, buf, sBuf, &hBuff, m_content);
4214 if (!m_parseComplete)
4215 DRW_DBG("TABLECONTENT object parse incomplete\n")DRW_dbg::dbg("TABLECONTENT object parse incomplete\n");
4216 return true;
4217}
4218
4219void DRW_LWPolyline::applyExtrusion(){
4220 if (haveExtrusion) {
4221 calculateAxis(extPoint);
4222 for (unsigned int i=0; i<vertlist.size(); i++) {
4223 auto& vert = vertlist.at(i);
4224 DRW_Coord v(vert->x, vert->y, elevation);
4225 extrudePoint(extPoint, &v);
4226 vert->x = v.x;
4227 vert->y = v.y;
4228 }
4229 }
4230}
4231
4232bool DRW_LWPolyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4233 switch (code) {
4234 case 10: {
4235 vertex = std::make_shared<DRW_Vertex2D>();
4236 vertlist.push_back(vertex);
4237 vertex->x = reader->getDouble();
4238 break; }
4239 case 20:
4240 if(vertex)
4241 vertex->y = reader->getDouble();
4242 break;
4243 case 40:
4244 if(vertex)
4245 vertex->stawidth = reader->getDouble();
4246 break;
4247 case 41:
4248 if(vertex)
4249 vertex->endwidth = reader->getDouble();
4250 break;
4251 case 42:
4252 if(vertex)
4253 vertex->bulge = reader->getDouble();
4254 break;
4255 case 91:
4256 if (vertex)
4257 vertex->identifier = reader->getInt32();
4258 break;
4259 case 38:
4260 elevation = reader->getDouble();
4261 break;
4262 case 39:
4263 thickness = reader->getDouble();
4264 break;
4265 case 43:
4266 width = reader->getDouble();
4267 break;
4268 case 70:
4269 flags = reader->getInt32();
4270 break;
4271 case 90:
4272 vertexnum = reader->getInt32();
4273 return DRW::reserve( vertlist, vertexnum);
4274 case 210:
4275 haveExtrusion = true;
4276 extPoint.x = reader->getDouble();
4277 break;
4278 case 220:
4279 extPoint.y = reader->getDouble();
4280 break;
4281 case 230:
4282 extPoint.z = reader->getDouble();
4283 break;
4284 default:
4285 return DRW_Entity::parseCode(code, reader);
4286 }
4287
4288 return true;
4289}
4290
4291bool DRW_LWPolyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4292 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
4293 if (!ret)
4294 return ret;
4295 DRW_DBG("\n***************************** parsing LWPolyline *******************************************\n")DRW_dbg::dbg("\n***************************** parsing LWPolyline *******************************************\n"
)
;
4296
4297 flags = buf->getBitShort();
4298 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
4299 if (flags & 4)
4300 width = buf->getBitDouble();
4301 if (flags & 8)
4302 elevation = buf->getBitDouble();
4303 if (flags & 2)
4304 thickness = buf->getBitDouble();
4305 if (flags & 1)
4306 extPoint = buf->getExtrusion(false);
4307 vertexnum = buf->getBitLong();
4308 if (!isValidCount(vertexnum, kMaxLWPolylineVertices)) {
4309 return false;
4310 }
4311 if (!DRW::reserve( vertlist, vertexnum)) {
4312 return false;
4313 }
4314
4315 unsigned int bulgesnum = 0;
4316 if (flags & 16)
4317 bulgesnum = static_cast<unsigned int>(buf->getBitLong());
4318 int vertexIdCount = 0;
4319 if (version > DRW::AC1021) {//2010+
4320 if (flags & 1024)
4321 vertexIdCount = buf->getBitLong();
4322 }
4323 unsigned int widthsnum = 0;
4324 if (flags & 32)
4325 widthsnum = static_cast<unsigned int>(buf->getBitLong());
4326 if (bulgesnum > static_cast<unsigned int>(vertexnum) ||
4327 vertexIdCount < 0 || vertexIdCount > vertexnum ||
4328 widthsnum > static_cast<unsigned int>(vertexnum)) {
4329 return false;
4330 }
4331 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);
4332 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);
4333 // Translate DWG LWPLINE flag bits to DXF group 70 bits.
4334 // Per ODA spec 20.4.85 + libreDWG dwg.spec (DWG_ENTITY LWPOLYLINE):
4335 // DWG bit 9 (0x200, 512) -> DXF bit 0 (closed, value 1)
4336 // DWG bit 8 (0x100, 256) -> DXF bit 7 (plinegen, value 128)
4337 // All other DWG flag bits indicate which optional fields are present
4338 // and have no DXF equivalent in group 70.
4339 int dxfFlags = 0;
4340 if (flags & 512)
4341 dxfFlags |= 1;
4342 if (flags & 256)
4343 dxfFlags |= 128;
4344 flags = dxfFlags;
4345 DRW_DBG("end flags value: ")DRW_dbg::dbg("end flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
4346
4347 if (vertexnum > 0) { //verify if is lwpol without vertex (empty)
4348 // add vertexes
4349 vertex = std::make_shared<DRW_Vertex2D>();
4350 vertex->x = buf->getRawDouble();
4351 vertex->y = buf->getRawDouble();
4352 vertlist.push_back(vertex);
4353 auto pv = vertex;
4354 for (int i = 1; i< vertexnum; i++){
4355 vertex = std::make_shared<DRW_Vertex2D>();
4356 if (version < DRW::AC1015) {//14-
4357 vertex->x = buf->getRawDouble();
4358 vertex->y = buf->getRawDouble();
4359 } else {
4360// DRW_Vertex2D *pv = vertlist.back();
4361 vertex->x = buf->getDefaultDouble(pv->x);
4362 vertex->y = buf->getDefaultDouble(pv->y);
4363 }
4364 pv = vertex;
4365 vertlist.push_back(vertex);
4366 }
4367 //add bulges
4368 for (unsigned int i = 0; i < bulgesnum; i++){
4369 double bulge = buf->getBitDouble();
4370 if (vertlist.size()> i)
4371 vertlist.at(i)->bulge = bulge;
4372 }
4373 //add vertexId
4374 if (version > DRW::AC1021) {//2010+
4375 for (int i = 0; i < vertexIdCount; i++){
4376 std::int32_t vertexId = buf->getBitLong();
4377 if (static_cast<size_t>(i) < vertlist.size())
4378 vertlist.at(i)->identifier = vertexId;
4379 }
4380 }
4381 //add widths
4382 for (unsigned int i = 0; i < widthsnum; i++){
4383 double staW = buf->getBitDouble();
4384 double endW = buf->getBitDouble();
4385 if (i < vertlist.size()) {
4386 vertlist.at(i)->stawidth = staW;
4387 vertlist.at(i)->endwidth = endW;
4388 }
4389 }
4390 }
4391 if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug){
4392 DRW_DBG("\nVertex list: ")DRW_dbg::dbg("\nVertex list: ");
4393 for (auto& pv: vertlist) {
4394 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);
4395 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);
4396 DRW_DBG(" identifier: ")DRW_dbg::dbg(" identifier: "); DRW_DBG(pv->identifier)DRW_dbg::dbg(pv->identifier);
4397 }
4398 }
4399
4400 DRW_DBG("\n")DRW_dbg::dbg("\n");
4401 /* Common Entity Handle Data */
4402 ret = DRW_Entity::parseDwgEntHandle(version, buf);
4403 if (!ret)
4404 return ret;
4405 /* CRC X --- */
4406 return buf->isGood();
4407}
4408
4409
4410// ----------------------------------------------------------------------------
4411// DRW_MLine — multiline entity (ODA §19.4.78, fixed type 0x2F = 47).
4412// ----------------------------------------------------------------------------
4413
4414bool DRW_MLine::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4415 switch (code) {
4416 case 2:
4417 styleName = reader->getString();
4418 break;
4419 case 340:
4420 styleHandle = static_cast<std::uint32_t>(reader->getHandleString());
4421 break;
4422 case 40:
4423 scale = reader->getDouble();
4424 break;
4425 case 70:
4426 justification = static_cast<std::uint8_t>(reader->getInt32() & 0x3);
4427 break;
4428 case 71:
4429 openClosed = reader->getInt32();
4430 break;
4431 case 72:
4432 numVerts = static_cast<std::uint16_t>(reader->getInt32());
4433 break;
4434 case 73:
4435 numLines = static_cast<std::uint8_t>(reader->getInt32());
4436 break;
4437 case 10:
4438 basePoint.x = reader->getDouble();
4439 break;
4440 case 20:
4441 basePoint.y = reader->getDouble();
4442 break;
4443 case 30:
4444 basePoint.z = reader->getDouble();
4445 break;
4446 case 210:
4447 extPoint.x = reader->getDouble();
4448 break;
4449 case 220:
4450 extPoint.y = reader->getDouble();
4451 break;
4452 case 230:
4453 extPoint.z = reader->getDouble();
4454 break;
4455 // Per-vertex block: code 11 starts a new vertex; 12/13 follow.
4456 case 11:
4457 ++m_currentVertexIdx;
4458 m_currentElementIdx = 0;
4459 if (m_currentVertexIdx >= static_cast<int>(vertlist.size())) {
4460 vertlist.resize(m_currentVertexIdx + 1);
4461 }
4462 vertlist[m_currentVertexIdx].position.x = reader->getDouble();
4463 break;
4464 case 21:
4465 if (m_currentVertexIdx >= 0)
4466 vertlist[m_currentVertexIdx].position.y = reader->getDouble();
4467 break;
4468 case 31:
4469 if (m_currentVertexIdx >= 0)
4470 vertlist[m_currentVertexIdx].position.z = reader->getDouble();
4471 break;
4472 case 12:
4473 if (m_currentVertexIdx >= 0)
4474 vertlist[m_currentVertexIdx].vertexDir.x = reader->getDouble();
4475 break;
4476 case 22:
4477 if (m_currentVertexIdx >= 0)
4478 vertlist[m_currentVertexIdx].vertexDir.y = reader->getDouble();
4479 break;
4480 case 32:
4481 if (m_currentVertexIdx >= 0)
4482 vertlist[m_currentVertexIdx].vertexDir.z = reader->getDouble();
4483 break;
4484 case 13:
4485 if (m_currentVertexIdx >= 0)
4486 vertlist[m_currentVertexIdx].miterDir.x = reader->getDouble();
4487 break;
4488 case 23:
4489 if (m_currentVertexIdx >= 0)
4490 vertlist[m_currentVertexIdx].miterDir.y = reader->getDouble();
4491 break;
4492 case 33:
4493 if (m_currentVertexIdx >= 0)
4494 vertlist[m_currentVertexIdx].miterDir.z = reader->getDouble();
4495 break;
4496 // 74 = segment-param count for current element. Sets up the inner
4497 // vector and resets the running param count. 41 reads each param.
4498 // 75 = fill-param count; 42 reads each. After fills are consumed,
4499 // advance to the next element. AutoCAD emits 74/41*/75/42* per element.
4500 case 74:
4501 if (m_currentVertexIdx >= 0) {
4502 auto& v = vertlist[m_currentVertexIdx];
4503 if (static_cast<int>(v.segParms.size()) < numLines) {
4504 v.segParms.resize(numLines);
4505 v.areaFillParms.resize(numLines);
4506 }
4507 (void)reader->getInt32(); // expected count, used only as a marker
4508 m_currentSegFillCount = 0;
4509 }
4510 break;
4511 case 41:
4512 if (m_currentVertexIdx >= 0
4513 && m_currentElementIdx < static_cast<int>(vertlist[m_currentVertexIdx].segParms.size())) {
4514 vertlist[m_currentVertexIdx].segParms[m_currentElementIdx]
4515 .push_back(reader->getDouble());
4516 }
4517 break;
4518 case 75:
4519 if (m_currentVertexIdx >= 0) {
4520 m_currentSegFillCount = reader->getInt32();
4521 // After fills are emitted (or count==0 immediate), advance element.
4522 if (m_currentSegFillCount == 0
4523 && m_currentElementIdx + 1 < numLines) {
4524 ++m_currentElementIdx;
4525 }
4526 }
4527 break;
4528 case 42:
4529 if (m_currentVertexIdx >= 0
4530 && m_currentElementIdx < static_cast<int>(vertlist[m_currentVertexIdx].areaFillParms.size())) {
4531 vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx]
4532 .push_back(reader->getDouble());
4533 if (static_cast<int>(vertlist[m_currentVertexIdx]
4534 .areaFillParms[m_currentElementIdx].size())
4535 >= m_currentSegFillCount
4536 && m_currentElementIdx + 1 < numLines) {
4537 ++m_currentElementIdx;
4538 }
4539 }
4540 break;
4541 default:
4542 return DRW_Entity::parseCode(code, reader);
4543 }
4544 return true;
4545}
4546
4547bool DRW_MLine::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4548 if (!DRW_Entity::parseDwg(version, buf, nullptr, bs)) return false;
4549 DRW_DBG("\n***************************** parsing MLINE *********************\n")DRW_dbg::dbg("\n***************************** parsing MLINE *********************\n"
)
;
4550 // Per ODA §19.4.78 / libreDWG dwg_decode_MLINE:
4551 // BD scale, RC justification, 3BD basePoint, BE extrusion,
4552 // BS open/closed flag, RC num_lines, BS num_verts,
4553 // then per-vertex: 3BD pos, 3BD vdir, 3BD mdir,
4554 // per-line: BS num_segparms × BD parm, BS num_areafillparms × BD parm.
4555 scale = buf->getBitDouble();
4556 justification = buf->getRawChar8();
4557 basePoint = buf->get3BitDouble();
4558 extPoint = buf->getExtrusion(false);
4559 openClosed = buf->getBitShort();
4560 numLines = buf->getRawChar8();
4561 numVerts = buf->getBitShort();
4562 DRW_DBG(" mline scale: ")DRW_dbg::dbg(" mline scale: "); DRW_DBG(scale)DRW_dbg::dbg(scale);
4563 DRW_DBG(" just: ")DRW_dbg::dbg(" just: "); DRW_DBG(static_cast<int>(justification))DRW_dbg::dbg(static_cast<int>(justification));
4564 DRW_DBG(" openClosed: ")DRW_dbg::dbg(" openClosed: "); DRW_DBG(openClosed)DRW_dbg::dbg(openClosed);
4565 DRW_DBG(" lines: ")DRW_dbg::dbg(" lines: "); DRW_DBG(static_cast<int>(numLines))DRW_dbg::dbg(static_cast<int>(numLines));
4566 DRW_DBG(" verts: ")DRW_dbg::dbg(" verts: "); DRW_DBG(numVerts)DRW_dbg::dbg(numVerts); DRW_DBG("\n")DRW_dbg::dbg("\n");
4567 // Sanity: numLines / numVerts are RC and BS so already small types,
4568 // but guard against pathological values anyway.
4569 if (numLines > 100) return true;
4570 vertlist.reserve(numVerts);
4571 for (int vi = 0; vi < numVerts; ++vi) {
4572 DRW_MLineVertex vtx;
4573 vtx.position = buf->get3BitDouble();
4574 vtx.vertexDir = buf->get3BitDouble();
4575 vtx.miterDir = buf->get3BitDouble();
4576 vtx.segParms.resize(numLines);
4577 vtx.areaFillParms.resize(numLines);
4578 for (int li = 0; li < numLines; ++li) {
4579 std::uint16_t nSeg = buf->getBitShort();
4580 vtx.segParms[li].reserve(nSeg);
4581 for (int s = 0; s < nSeg; ++s) {
4582 vtx.segParms[li].push_back(buf->getBitDouble());
4583 }
4584 std::uint16_t nFill = buf->getBitShort();
4585 vtx.areaFillParms[li].reserve(nFill);
4586 for (int f = 0; f < nFill; ++f) {
4587 vtx.areaFillParms[li].push_back(buf->getBitDouble());
4588 }
4589 }
4590 vertlist.push_back(std::move(vtx));
4591 }
4592 if (!DRW_Entity::parseDwgEntHandle(version, buf)) return false;
4593 // MLINE has one extra handle in the handle stream after the standard
4594 // entity handles: the MLINESTYLE reference. Read if available — some
4595 // older files (R14) store the style name inline instead.
4596 if (version > DRW::AC1014 && buf->numRemainingBytes() > 0) {
4597 dwgHandle styleH = buf->getOffsetHandle(handle);
4598 styleHandle = styleH.ref;
4599 DRW_DBG(" MLINE style handle: ")DRW_dbg::dbg(" MLINE style handle: ");
4600 DRW_DBGHL(styleH.code, styleH.size, styleH.ref)DRW_dbg::dbgHL(styleH.code, styleH.size, styleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
4601 }
4602 return buf->isGood();
4603}
4604
4605
4606// ----------------------------------------------------------------------------
4607// DRW_Underlay — UNDERLAY entity (PDFUNDERLAY/DGNUNDERLAY/DWFUNDERLAY).
4608// libreDWG UNDERLAYREFERENCE.spec field order:
4609// extrusion (BE) -> position (3BD) -> angle (BD radians) -> scale (3BD)
4610// -> flags (RC) -> contrast (RC) -> fade (RC) -> num_clip (BL)
4611// -> clip_verts (2RD × num_clip).
4612// Handle stream after standard entity handles: definition_id (H).
4613// ----------------------------------------------------------------------------
4614
4615bool DRW_Underlay::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4616 switch (code) {
4617 case 340:
4618 definitionHandle = static_cast<std::uint32_t>(reader->getHandleString());
4619 break;
4620 case 10: position.x = reader->getDouble(); break;
4621 case 20: position.y = reader->getDouble(); break;
4622 case 30: position.z = reader->getDouble(); break;
4623 case 41: scale.x = reader->getDouble(); break;
4624 case 42: scale.y = reader->getDouble(); break;
4625 case 43: scale.z = reader->getDouble(); break;
4626 case 50: rotation = reader->getDouble(); break; // degrees in DXF
4627 case 210: extPoint.x = reader->getDouble(); break;
4628 case 220: extPoint.y = reader->getDouble(); break;
4629 case 230: extPoint.z = reader->getDouble(); break;
4630 case 280: flags = static_cast<std::uint8_t>(reader->getInt32() & 0xFF); break;
4631 case 281: contrast = static_cast<std::uint8_t>(reader->getInt32() & 0xFF); break;
4632 case 282: fade = static_cast<std::uint8_t>(reader->getInt32() & 0xFF); break;
4633 case 11: {
4634 ++m_currentClipVertexIdx;
4635 if (m_currentClipVertexIdx >= static_cast<int>(clipBoundary.size())) {
4636 clipBoundary.resize(m_currentClipVertexIdx + 1);
4637 }
4638 clipBoundary[m_currentClipVertexIdx].x = reader->getDouble();
4639 break;
4640 }
4641 case 21:
4642 if (m_currentClipVertexIdx >= 0
4643 && m_currentClipVertexIdx < static_cast<int>(clipBoundary.size())) {
4644 clipBoundary[m_currentClipVertexIdx].y = reader->getDouble();
4645 }
4646 break;
4647 default:
4648 return DRW_Entity::parseCode(code, reader);
4649 }
4650 return true;
4651}
4652
4653bool DRW_Underlay::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4654 if (!DRW_Entity::parseDwg(version, buf, nullptr, bs)) return false;
4655 DRW_DBG("\n***************************** parsing UNDERLAY ***************\n")DRW_dbg::dbg("\n***************************** parsing UNDERLAY ***************\n"
)
;
4656 extPoint = buf->getExtrusion(false);
4657 position = buf->get3BitDouble();
4658 rotation = buf->getBitDouble(); // angle (radians) BEFORE scale
4659 scale = buf->get3BitDouble();
4660 flags = buf->getRawChar8();
4661 contrast = buf->getRawChar8();
4662 fade = buf->getRawChar8();
4663 std::uint32_t nClip = buf->getBitLong();
4664 DRW_DBG(" UNDERLAY pos: ")DRW_dbg::dbg(" UNDERLAY pos: "); DRW_DBG(position.x)DRW_dbg::dbg(position.x); DRW_DBG(",")DRW_dbg::dbg(",");
4665 DRW_DBG(position.y)DRW_dbg::dbg(position.y); DRW_DBG(" rot: ")DRW_dbg::dbg(" rot: "); DRW_DBG(rotation)DRW_dbg::dbg(rotation);
4666 DRW_DBG(" flags: ")DRW_dbg::dbg(" flags: "); DRW_DBGH(flags)DRW_dbg::dbgH(flags);
4667 DRW_DBG(" nClip: ")DRW_dbg::dbg(" nClip: "); DRW_DBG(nClip)DRW_dbg::dbg(nClip); DRW_DBG("\n")DRW_dbg::dbg("\n");
4668 if (nClip > 100000) return true; // sanity
4669 clipBoundary.reserve(nClip);
4670 for (std::uint32_t i = 0; i < nClip; ++i) {
4671 DRW_Coord p;
4672 p.x = buf->getRawDouble();
4673 p.y = buf->getRawDouble();
4674 p.z = 0.0;
4675 clipBoundary.push_back(p);
4676 }
4677 if (!DRW_Entity::parseDwgEntHandle(version, buf)) return false;
4678 if (version > DRW::AC1014 && buf->numRemainingBytes() >= 2) {
4679 dwgHandle defH = buf->getOffsetHandle(handle);
4680 definitionHandle = defH.ref;
4681 DRW_DBG(" UNDERLAY definitionHandle: ")DRW_dbg::dbg(" UNDERLAY definitionHandle: ");
4682 DRW_DBGHL(defH.code, defH.size, defH.ref)DRW_dbg::dbgHL(defH.code, defH.size, defH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
4683 }
4684 return buf->isGood();
4685}
4686
4687bool DRW_Underlay::encodeDwg(DRW::Version version, dwgBufferW *buf,
4688 std::uint32_t bs, dwgBufferW *strBuf,
4689 dwgBufferW *handleBuf) {
4690 (void)bs; (void)strBuf;
4691 switch (kind) {
4692 case DGN:
4693 oType = kDwgClassNumDgn;
4694 break;
4695 case DWF:
4696 oType = kDwgClassNumDwf;
4697 break;
4698 case PDF:
4699 default:
4700 oType = kDwgClassNumPdf;
4701 break;
4702 }
4703 if (!encodeDwgCommon(version, buf))
4704 return false;
4705
4706 buf->putExtrusion(extPoint, false);
4707 buf->put3BitDouble(position);
4708 buf->putBitDouble(rotation);
4709 buf->put3BitDouble(scale);
4710 buf->putRawChar8(flags);
4711 buf->putRawChar8(contrast);
4712 buf->putRawChar8(fade);
4713 constexpr std::size_t kMaxClipVerts = 100000u;
4714 const std::size_t emitVerts = std::min(clipBoundary.size(), kMaxClipVerts);
4715 buf->putBitLong(static_cast<std::int32_t>(emitVerts));
4716 for (std::size_t i = 0; i < emitVerts; ++i) {
4717 buf->putRawDouble(clipBoundary[i].x);
4718 buf->putRawDouble(clipBoundary[i].y);
4719 }
4720
4721 if (!encodeDwgEntHandle(version, buf, handleBuf))
4722 return false;
4723 putNullableHardPointerHandle(handleBuf ? handleBuf : buf, definitionHandle);
4724 return true;
4725}
4726
4727
4728bool DRW_Text::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4729 switch (code) {
4730 case 40:
4731 height = reader->getDouble();
4732 break;
4733 case 41:
4734 widthscale = reader->getDouble();
4735 break;
4736 case 50:
4737 angle = reader->getDouble();
4738 break;
4739 case 51:
4740 oblique = reader->getDouble();
4741 break;
4742 case 71:
4743 textgen = reader->getInt32();
4744 break;
4745 case 72:
4746 alignH = (HAlign)reader->getInt32();
4747 break;
4748 case 73:
4749 alignV = (VAlign)reader->getInt32();
4750 break;
4751 case 1:
4752 text = reader->getUtf8String();
4753 break;
4754 case 7:
4755 style = reader->getUtf8String();
4756 break;
4757 default:
4758 return DRW_Line::parseCode(code, reader);
4759 }
4760
4761 return true;
4762}
4763
4764bool DRW_Text::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4765 dwgBuffer sBuff = *buf;
4766 dwgBuffer *sBuf = buf;
4767 if (version > DRW::AC1018) {//2007+
4768 sBuf = &sBuff; //separate buffer for strings
4769 }
4770 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
4771 if (!ret)
4772 return ret;
4773 DRW_DBG("\n***************************** parsing text *********************************************\n")DRW_dbg::dbg("\n***************************** parsing text *********************************************\n"
)
;
4774
4775 // DataFlags RC Used to determine presence of subsequent data, set to 0xFF for R14-
4776 std::uint8_t data_flags = 0x00;
4777 if (version > DRW::AC1014) {//2000+
4778 data_flags = buf->getRawChar8(); /* DataFlags RC Used to determine presence of subsequent data */
4779 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");
4780 if ( !(data_flags & 0x01) ) { /* Elevation RD --- present if !(DataFlags & 0x01) */
4781 basePoint.z = buf->getRawDouble();
4782 }
4783 } else {//14-
4784 basePoint.z = buf->getBitDouble(); /* Elevation BD --- */
4785 }
4786 basePoint.x = buf->getRawDouble(); /* Insertion pt 2RD 10 */
4787 basePoint.y = buf->getRawDouble();
4788 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");
4789 if (version > DRW::AC1014) {//2000+
4790 if ( !(data_flags & 0x02) ) { /* Alignment pt 2DD 11 present if !(DataFlags & 0x02), use 10 & 20 values for 2 default values.*/
4791 secPoint.x = buf->getDefaultDouble(basePoint.x);
4792 secPoint.y = buf->getDefaultDouble(basePoint.y);
4793 } else {
4794 secPoint = basePoint;
4795 }
4796 } else {//14-
4797 secPoint.x = buf->getRawDouble(); /* Alignment pt 2RD 11 */
4798 secPoint.y = buf->getRawDouble();
4799 }
4800 secPoint.z = basePoint.z;
4801 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");
4802 extPoint = buf->getExtrusion(version > DRW::AC1014);
4803 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");
4804 thickness = buf->getThickness(version > DRW::AC1014); /* Thickness BD 39 */
4805
4806 if (version > DRW::AC1014) {//2000+
4807 if ( !(data_flags & 0x04) ) { /* Oblique ang RD 51 present if !(DataFlags & 0x04) */
4808 oblique = buf->getRawDouble();
4809 }
4810 if ( !(data_flags & 0x08) ) { /* Rotation ang RD 50 present if !(DataFlags & 0x08) */
4811 angle = buf->getRawDouble();
4812 }
4813 height = buf->getRawDouble(); /* Height RD 40 */
4814 if ( !(data_flags & 0x10) ) { /* Width factor RD 41 present if !(DataFlags & 0x10) */
4815 widthscale = buf->getRawDouble();
4816 }
4817 } else {//14-
4818 oblique = buf->getBitDouble(); /* Oblique ang BD 51 */
4819 angle = buf->getBitDouble(); /* Rotation ang BD 50 */
4820 height = buf->getBitDouble(); /* Height BD 40 */
4821 widthscale = buf->getBitDouble(); /* Width factor BD 41 */
4822 }
4823 angle *= ARAD57.29577951308232;
4824 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: ");
4825 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");
4826 text = sBuf->getVariableText(version, false); /* Text value TV 1 */
4827 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");
4828 //textgen, alignH, alignV always present in R14-, data_flags set in initialisation
4829 if ( !(data_flags & 0x20) ) { /* Generation BS 71 present if !(DataFlags & 0x20) */
4830 textgen = buf->getBitShort();
4831 DRW_DBG("textgen: ")DRW_dbg::dbg("textgen: "); DRW_DBG(textgen)DRW_dbg::dbg(textgen);
4832 }
4833 if ( !(data_flags & 0x40) ) { /* Horiz align. BS 72 present if !(DataFlags & 0x40) */
4834 alignH = (HAlign)buf->getBitShort();
4835 DRW_DBG(", alignH: ")DRW_dbg::dbg(", alignH: "); DRW_DBG(alignH)DRW_dbg::dbg(alignH);
4836 }
4837 if ( !(data_flags & 0x80) ) { /* Vert align. BS 73 present if !(DataFlags & 0x80) */
4838 alignV = (VAlign)buf->getBitShort();
4839 DRW_DBG(", alignV: ")DRW_dbg::dbg(", alignV: "); DRW_DBG(alignV)DRW_dbg::dbg(alignV);
4840 }
4841 DRW_DBG("\n")DRW_dbg::dbg("\n");
4842
4843 /* Common Entity Handle Data */
4844 ret = DRW_Entity::parseDwgEntHandle(version, buf);
4845 if (!ret)
4846 return ret;
4847
4848 styleH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
4849 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");
4850
4851 /* CRC X --- */
4852 return buf->isGood();
4853}
4854
4855// ---------------------------------------------------------------------------
4856// RTEXT (RText, Express Tools) — read-only, mapped onto DRW_Text.
4857// ---------------------------------------------------------------------------
4858bool DRW_RText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
4859 // RTEXT's DXF layout is a TEXT subset (1 text, 7 style, 10/20/30 insertion,
4860 // 40 height, 50 rotation deg, 210/220/230 extrusion) plus a flags long (70)
4861 // that plain TEXT does not carry.
4862 if (70 == code) {
4863 m_rTextFlags = reader->getInt32();
4864 return true;
4865 }
4866 return DRW_Text::parseCode(code, reader);
4867}
4868
4869bool DRW_RText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
4870 dwgBuffer sBuff = *buf;
4871 dwgBuffer *sBuf = buf;
4872 if (version > DRW::AC1018) // 2007+ strings live in a separate stream
4873 sBuf = &sBuff;
4874 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
4875 if (!ret)
4876 return ret;
4877 DRW_DBG("\n***************************** parsing rtext ********************************************\n")DRW_dbg::dbg("\n***************************** parsing rtext ********************************************\n"
)
;
4878
4879 basePoint = buf->get3BitDouble(); // insertion 3BD
4880 secPoint = basePoint; // no separate alignment point
4881 extPoint = buf->get3BitDouble(); // extrusion 3BD
4882 angle = buf->getBitDouble() * ARAD57.29577951308232; // rotation BD (radians) -> degrees
4883 height = buf->getBitDouble(); // height BD
4884 m_rTextFlags = buf->getBitShort(); // flags BS
4885 text = sBuf->getVariableText(version, false); // TV (DIESEL or literal)
4886 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");
4887
4888 ret = DRW_Entity::parseDwgEntHandle(version, buf);
4889 if (!ret)
4890 return ret;
4891 styleH = buf->getHandle(); // STYLE (hard pointer)
4892 return buf->isGood();
4893}
4894
4895// ---------------------------------------------------------------------------
4896// ARCALIGNEDTEXT (AcDbArcAlignedText, Express Tools) — read-only, mapped onto
4897// DRW_Text as a 2D approximation (text at the arc mid-point, tangent baseline).
4898// ---------------------------------------------------------------------------
4899bool DRW_RText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
4900 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
4901 (void)bs;
4902 oType = kDwgClassNum;
4903 if (!encodeDwgCommon(version, buf)) return false;
4904
4905 buf->put3BitDouble(basePoint);
4906 buf->put3BitDouble(extPoint);
4907 buf->putBitDouble(angle / ARAD57.29577951308232);
4908 buf->putBitDouble(height);
4909 buf->putBitShort(bitShortFromInt(m_rTextFlags));
4910 (strBuf ? strBuf : buf)->putVariableText(version, text);
4911
4912 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
4913 putHardPointerHandle(handleBuf ? handleBuf : buf,
4914 (styleH.ref == 0) ? 0x13 : styleH.ref);
4915 return true;
4916}
4917
4918void DRW_ArcAlignedText::applyArcApproximation(){
4919 const double mid = 0.5 * (m_startAngle + m_endAngle);
4920 basePoint.x = m_center.x + m_radius * std::cos(mid);
4921 basePoint.y = m_center.y + m_radius * std::sin(mid);
4922 basePoint.z = m_center.z;
4923 secPoint = basePoint;
4924 // Baseline tangent to the arc at the mid-point; angle stored in degrees to
4925 // match DRW_Text (which the DWG path fills via `angle *= ARAD`).
4926 angle = (mid + M_PI_21.57079632679489661923) * ARAD57.29577951308232;
4927 // Height from the text-size D2T string when parseable, else a fraction of
4928 // the radius so the approximation is at least visible.
4929 double h = 0.0;
4930 try { h = std::stod(m_textSize); } catch (...) { h = 0.0; }
4931 if (h > 0.0)
4932 height = h;
4933 else if (height <= 0.0)
4934 height = 0.1 * m_radius;
4935}
4936
4937// Format a D2T (double-to-text) field the way the ARCALIGNEDTEXT model stores
4938// it: the DWG body carries these as text ("2.5", "1", "0"), while the DXF path
4939// reads them as doubles (group codes 41-46 fall in the double range, so the
4940// reader populates doubleData and leaves strData stale — getString() is unsafe
4941// here). %g reproduces the same compact textual form.
4942static std::string arcAlignedD2T(double v){
4943 char buf[32];
4944 std::snprintf(buf, sizeof(buf), "%g", v);
4945 return std::string(buf);
4946}
4947
4948static std::string arcAlignedStringOrDefault(const UTF8STRINGstd::string& value,
4949 const std::string& fallback) {
4950 return value.empty() ? fallback : value;
4951}
4952
4953bool DRW_ArcAlignedText::encodeDwg(DRW::Version version, dwgBufferW *buf,
4954 std::uint32_t bs, dwgBufferW *strBuf,
4955 dwgBufferW *handleBuf) {
4956 (void)bs;
4957 oType = kDwgClassNum;
4958 if (!encodeDwgCommon(version, buf)) return false;
4959
4960 dwgBufferW *sb = strBuf ? strBuf : buf;
4961 sb->putVariableText(version, arcAlignedStringOrDefault(
4962 m_textSize, arcAlignedD2T(height > 0.0 ? height : 0.0)));
4963 sb->putVariableText(version, arcAlignedStringOrDefault(
4964 m_xScale, arcAlignedD2T(widthscale > 0.0 ? widthscale : 1.0)));
4965 sb->putVariableText(version, arcAlignedStringOrDefault(m_charSpacing, "1"));
4966 sb->putVariableText(version, style.empty() ? "Standard" : style);
4967 sb->putVariableText(version, m_fontName);
4968 sb->putVariableText(version, m_bigFontName);
4969 sb->putVariableText(version, text);
4970 sb->putVariableText(version, arcAlignedStringOrDefault(m_offsetFromArc, "0"));
4971 sb->putVariableText(version, arcAlignedStringOrDefault(m_rightOffset, "0"));
4972 sb->putVariableText(version, arcAlignedStringOrDefault(m_leftOffset, "0"));
4973
4974 buf->put3BitDouble(m_center);
4975 buf->putBitDouble(m_radius);
4976 buf->putBitDouble(m_startAngle);
4977 buf->putBitDouble(m_endAngle);
4978 buf->put3BitDouble(extPoint);
4979 buf->putBitLong(static_cast<std::int32_t>(m_rawColor));
4980 buf->putBitShort(bitShortFromInt(m_characterSet));
4981 buf->putBitShort(bitShortFromInt(m_pitchAndFamily));
4982 buf->putBitShort(bitShortFromInt(m_isShx));
4983 buf->putBitShort(bitShortFromInt(m_isBold));
4984 buf->putBitShort(bitShortFromInt(m_isItalic));
4985 buf->putBitShort(bitShortFromInt(m_isUnderlined));
4986 buf->putBitShort(bitShortFromInt(m_alignment));
4987 buf->putBitShort(bitShortFromInt(m_isReverse));
4988 buf->putBitShort(bitShortFromInt(m_wizardFlag));
4989 buf->putBitShort(bitShortFromInt(m_textPosition));
4990 buf->putBitShort(bitShortFromInt(m_textDirection));
4991
4992 if (version <= DRW::AC1018)
4993 putNullableHardPointerHandle(buf, m_arcHandle);
4994 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
4995 if (version > DRW::AC1018)
4996 putNullableHardPointerHandle(handleBuf ? handleBuf : buf, m_arcHandle);
4997 return true;
4998}
4999
5000bool DRW_ArcAlignedText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5001 // ARCALIGNEDTEXT repurposes several TEXT codes (2/10/40/41/50/51/70…), so it
5002 // must not delegate those to DRW_Text; unknown codes fall through to the
5003 // AcDbEntity common parser. Angles (50/51) are DXF degrees -> radians.
5004 switch (code) {
5005 case 1: text = reader->getUtf8String(); break;
5006 case 2: m_fontName = reader->getUtf8String(); break;
5007 case 3: m_bigFontName = reader->getUtf8String(); break;
5008 case 7: style = reader->getUtf8String(); break;
5009 case 10: m_center.x = reader->getDouble(); break;
5010 case 20: m_center.y = reader->getDouble(); break;
5011 case 30: m_center.z = reader->getDouble(); break;
5012 case 40: m_radius = reader->getDouble(); break;
5013 case 41: m_xScale = arcAlignedD2T(reader->getDouble()); break;
5014 case 42: m_textSize = arcAlignedD2T(reader->getDouble()); break;
5015 case 43: m_charSpacing = arcAlignedD2T(reader->getDouble()); break;
5016 case 44: m_offsetFromArc = arcAlignedD2T(reader->getDouble()); break;
5017 case 45: m_rightOffset = arcAlignedD2T(reader->getDouble()); break;
5018 case 46: m_leftOffset = arcAlignedD2T(reader->getDouble()); break;
5019 case 50: m_startAngle = reader->getDouble() / ARAD57.29577951308232; break;
5020 case 51: m_endAngle = reader->getDouble() / ARAD57.29577951308232; break;
5021 case 70: m_isReverse = reader->getInt32(); break;
5022 case 71: m_textDirection = reader->getInt32(); break;
5023 case 72: m_alignment = reader->getInt32(); break;
5024 case 73: m_textPosition = reader->getInt32(); break;
5025 case 74: m_isBold = reader->getInt32(); break;
5026 case 75: m_isItalic = reader->getInt32(); break;
5027 case 76: m_isUnderlined = reader->getInt32(); break;
5028 case 77: m_characterSet = reader->getInt32(); break;
5029 case 78: m_pitchAndFamily = reader->getInt32(); break;
5030 case 79: m_isShx = reader->getInt32(); break;
5031 case 90: m_rawColor = reader->getInt32(); break;
5032 case 210: extPoint.x = reader->getDouble(); break;
5033 case 220: extPoint.y = reader->getDouble(); break;
5034 case 230: extPoint.z = reader->getDouble(); break;
5035 case 280: m_wizardFlag = reader->getInt32(); break;
5036 default: return DRW_Entity::parseCode(code, reader);
5037 }
5038 return true;
5039}
5040
5041bool DRW_ArcAlignedText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5042 dwgBuffer sBuff = *buf;
5043 dwgBuffer *sBuf = buf;
5044 if (version > DRW::AC1018) // 2007+ strings live in a separate stream
5045 sBuf = &sBuff;
5046 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5047 if (!ret)
5048 return ret;
5049 DRW_DBG("\n***************************** parsing arcalignedtext **********************************\n")DRW_dbg::dbg("\n***************************** parsing arcalignedtext **********************************\n"
)
;
5050
5051 m_textSize = sBuf->getVariableText(version, false);
5052 m_xScale = sBuf->getVariableText(version, false);
5053 m_charSpacing = sBuf->getVariableText(version, false);
5054 style = sBuf->getVariableText(version, false);
5055 m_fontName = sBuf->getVariableText(version, false);
5056 m_bigFontName = sBuf->getVariableText(version, false);
5057 text = sBuf->getVariableText(version, false);
5058 m_offsetFromArc = sBuf->getVariableText(version, false);
5059 m_rightOffset = sBuf->getVariableText(version, false);
5060 m_leftOffset = sBuf->getVariableText(version, false);
5061 m_center = buf->get3BitDouble();
5062 m_radius = buf->getBitDouble();
5063 m_startAngle = buf->getBitDouble();
5064 m_endAngle = buf->getBitDouble();
5065 extPoint = buf->get3BitDouble();
5066 m_rawColor = buf->getBitLong();
5067 m_characterSet = buf->getBitShort();
5068 m_pitchAndFamily = buf->getBitShort();
5069 m_isShx = buf->getBitShort();
5070 m_isBold = buf->getBitShort();
5071 m_isItalic = buf->getBitShort();
5072 m_isUnderlined = buf->getBitShort();
5073 m_alignment = buf->getBitShort();
5074 m_isReverse = buf->getBitShort();
5075 m_wizardFlag = buf->getBitShort();
5076 m_textPosition = buf->getBitShort();
5077 m_textDirection = buf->getBitShort();
5078 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");
5079
5080 // R2004- keeps the arc handle before the common handle stream; R2007+ after.
5081 if (version <= DRW::AC1018)
5082 m_arcHandle = (buf->numRemainingBytes() > 0) ? buf->getHandle().ref : 0;
5083
5084 ret = DRW_Entity::parseDwgEntHandle(version, buf);
5085 if (!ret)
5086 return ret;
5087 if (version > DRW::AC1018)
5088 m_arcHandle = (buf->numRemainingBytes() > 0) ? buf->getHandle().ref : 0;
5089
5090 applyArcApproximation();
5091 return buf->isGood();
5092}
5093
5094// Out-of-line special members: required because mtext is a unique_ptr<DRW_MText>
5095// declared with a forward-declared element type in the header.
5096DRW_Attrib::~DRW_Attrib() = default;
5097DRW_Attrib::DRW_Attrib(const DRW_Attrib& o)
5098 : DRW_Text(o), tag(o.tag), attribFlags(o.attribFlags),
5099 m_fieldLength(o.m_fieldLength),
5100 lockPosition(o.lockPosition), attVersion(o.attVersion),
5101 m_attributeType(o.m_attributeType),
5102 mtext(o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr) {}
5103DRW_Attrib& DRW_Attrib::operator=(const DRW_Attrib& o) {
5104 if (this != &o) {
5105 DRW_Text::operator=(o);
5106 tag = o.tag;
5107 attribFlags = o.attribFlags;
5108 m_fieldLength = o.m_fieldLength;
5109 lockPosition = o.lockPosition;
5110 attVersion = o.attVersion;
5111 m_attributeType = o.m_attributeType;
5112 mtext = o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr;
5113 }
5114 return *this;
5115}
5116DRW_Attrib::DRW_Attrib(DRW_Attrib&&) noexcept = default;
5117DRW_Attrib& DRW_Attrib::operator=(DRW_Attrib&&) noexcept = default;
5118
5119namespace {
5120struct EmbeddedMTextHandleInfo {
5121 bool m_ownerHandle = false;
5122 int m_numReactors = 0;
5123 std::uint8_t m_xDictFlag = 1;
5124 bool m_hasAcDbColorHandle = false;
5125 int m_ltFlags = 0;
5126 int m_plotFlags = 0;
5127 int m_materialFlag = 0;
5128 int m_shadowFlag = 0;
5129 bool m_hasFullVisualStyle = false;
5130 bool m_hasFaceVisualStyle = false;
5131 bool m_hasEdgeVisualStyle = false;
5132 bool m_hasStyleHandle = true;
5133 bool m_hasR2018AppIdHandle = false;
5134 bool m_hasAnnotativeAppHandle = false;
5135};
5136
5137static bool parseEmbeddedMTextEntityMode(DRW::Version version, dwgBuffer *buf,
5138 EmbeddedMTextHandleInfo& info) {
5139 std::uint8_t entmode = buf->get2Bits();
5140 info.m_ownerHandle = entmode == 0;
5141 info.m_numReactors = buf->getBitLong();
5142 if (version > DRW::AC1015) {
5143 info.m_xDictFlag = buf->getBit();
5144 }
5145 if (version > DRW::AC1024 || version < DRW::AC1018) {
5146 buf->getBit(); // nolinks / have-next-links
5147 }
5148 buf->getEnColor(version);
5149 info.m_hasAcDbColorHandle = buf->lastEnColorHadDbColorRef;
5150 buf->getBitDouble(); // linetype scale
5151 if (version > DRW::AC1014) {
5152 info.m_ltFlags = buf->get2Bits();
5153 info.m_plotFlags = buf->get2Bits();
5154 }
5155 if (version > DRW::AC1018) {
5156 info.m_materialFlag = buf->get2Bits();
5157 info.m_shadowFlag = buf->getRawChar8();
5158 }
5159 if (version > DRW::AC1021) {
5160 info.m_hasFullVisualStyle = buf->getBit() != 0;
5161 info.m_hasFaceVisualStyle = buf->getBit() != 0;
5162 info.m_hasEdgeVisualStyle = buf->getBit() != 0;
5163 }
5164 buf->getBitShort(); // invisibility
5165 if (version > DRW::AC1014) {
5166 buf->getRawChar8(); // lineweight
5167 }
5168 return buf->isGood();
5169}
5170
5171static bool parseEmbeddedMTextDwg(DRW::Version version, dwgBuffer *buf,
5172 dwgBuffer *sBuf, DRW_MText& mtext,
5173 EmbeddedMTextHandleInfo& info) {
5174 if (!parseEmbeddedMTextEntityMode(version, buf, info))
5175 return false;
5176
5177 mtext.basePoint = buf->get3BitDouble();
5178 mtext.extPoint = buf->get3BitDouble();
5179 mtext.secPoint = buf->get3BitDouble();
5180 mtext.angle = atan2(mtext.secPoint.y, mtext.secPoint.x) * ARAD57.29577951308232;
5181 mtext.widthscale = buf->getBitDouble();
5182 if (version > DRW::AC1018) {
5183 buf->getBitDouble(); // rect height
5184 }
5185 mtext.height = buf->getBitDouble();
5186 mtext.textgen = buf->getBitShort();
5187 mtext.alignH = static_cast<DRW_Text::HAlign>(buf->getBitShort());
5188 buf->getBitDouble(); // extents height
5189 buf->getBitDouble(); // extents width
5190 mtext.text = sBuf->getVariableText(version, false);
5191
5192 if (version > DRW::AC1014) {
5193 buf->getBitShort();
5194 mtext.interlin = buf->getBitDouble();
5195 buf->getBit();
5196 }
5197 if (version > DRW::AC1015) {
5198 mtext.m_backgroundFlags = buf->getBitLong();
5199 if ((mtext.m_backgroundFlags & 0x01)
5200 || (version >= DRW::AC1032 && (mtext.m_backgroundFlags & 0x10))) {
5201 mtext.m_backgroundScale = buf->getBitDouble(); // BitDouble, not BitLong
5202 mtext.m_backgroundColor = static_cast<int>(buf->getCmColor(version, nullptr, sBuf));
5203 mtext.m_backgroundTransparency = buf->getBitLong();
5204 }
5205 }
5206
5207 if (version >= DRW::AC1032) {
5208 mtext.m_r2018ColumnHeights.clear();
5209 mtext.m_r2018IsNotAnnotative = buf->getBit();
5210 if (mtext.m_r2018IsNotAnnotative) {
5211 mtext.m_r2018Version = buf->getBitShort();
5212 mtext.m_r2018DefaultFlag = buf->getBit();
5213 info.m_hasR2018AppIdHandle = true;
5214 mtext.m_r2018Attachment = buf->getBitLong();
5215 mtext.m_r2018XAxisDir = buf->get3BitDouble();
5216 mtext.m_r2018InsertionPoint = buf->get3BitDouble();
5217 mtext.m_r2018RectWidth = buf->getBitDouble();
5218 mtext.m_r2018RectHeight = buf->getBitDouble();
5219 mtext.m_r2018ExtentsHeight = buf->getBitDouble();
5220 mtext.m_r2018ExtentsWidth = buf->getBitDouble();
5221 mtext.m_r2018ColumnType = buf->getBitShort();
5222 if (mtext.m_r2018ColumnType != 0) {
5223 mtext.m_r2018ColumnCount = buf->getBitLong();
5224 mtext.m_r2018ColumnWidth = buf->getBitDouble();
5225 mtext.m_r2018ColumnGutter = buf->getBitDouble();
5226 mtext.m_r2018ColumnAutoHeight = buf->getBit();
5227 mtext.m_r2018ColumnFlowReversed = buf->getBit();
5228 if (!mtext.m_r2018ColumnAutoHeight && mtext.m_r2018ColumnType == 2
5229 && mtext.m_r2018ColumnCount > 0 && mtext.m_r2018ColumnCount < 10000) {
5230 mtext.m_r2018ColumnHeights.reserve(static_cast<size_t>(mtext.m_r2018ColumnCount));
5231 for (std::int32_t i = 0; i < mtext.m_r2018ColumnCount; ++i) {
5232 mtext.m_r2018ColumnHeights.push_back(buf->getBitDouble());
5233 }
5234 }
5235 }
5236 }
5237 }
5238
5239 const std::uint16_t annotativeSize = buf->getBitShort();
5240 if (annotativeSize > 0) {
5241 const int remaining = buf->numRemainingBytes();
5242 if (remaining < 0 || static_cast<std::uint64_t>(annotativeSize) > static_cast<std::uint64_t>(remaining))
5243 return false;
5244 std::vector<std::uint8_t> annotativeData(annotativeSize);
5245 buf->getBytes(annotativeData.data(), annotativeData.size());
5246 info.m_hasAnnotativeAppHandle = true;
5247 buf->getBitShort(); // unknown short, normally 0
5248 }
5249 return buf->isGood();
5250}
5251
5252static bool consumeEmbeddedMTextHandles(DRW::Version version, dwgBuffer *buf,
5253 std::uint32_t objSize,
5254 const EmbeddedMTextHandleInfo& info,
5255 DRW_MText *mtext) {
5256 if (version > DRW::AC1018) {
5257 buf->setPosition(objSize >> 3);
5258 buf->setBitPos(objSize & 7);
5259 }
5260 if (info.m_hasAcDbColorHandle) buf->getHandle();
5261 if (info.m_ownerHandle) buf->getHandle();
5262 for (int i = 0; i < info.m_numReactors; ++i) buf->getHandle();
5263 if (info.m_xDictFlag != 1) buf->getHandle();
5264 if (version > DRW::AC1014) {
5265 buf->getHandle(); // layer
5266 if (info.m_ltFlags == 3) buf->getHandle();
5267 }
5268 if (version > DRW::AC1018) {
5269 if (info.m_materialFlag == 3) buf->getHandle();
5270 if (info.m_shadowFlag == 3) buf->getHandle();
5271 }
5272 if (info.m_plotFlags == 3) buf->getHandle();
5273 if (version > DRW::AC1021) {
5274 if (info.m_hasFullVisualStyle) buf->getHandle();
5275 if (info.m_hasFaceVisualStyle) buf->getHandle();
5276 if (info.m_hasEdgeVisualStyle) buf->getHandle();
5277 }
5278 if (info.m_hasStyleHandle) {
5279 dwgHandle styleH = buf->getHandle();
5280 if (mtext) mtext->styleH = styleH;
5281 }
5282 if (info.m_hasR2018AppIdHandle) {
5283 dwgHandle appIdH = buf->getHandle();
5284 if (mtext) mtext->m_r2018AppIdHandle = appIdH.ref;
5285 }
5286 if (info.m_hasAnnotativeAppHandle) buf->getHandle();
5287 return buf->isGood();
5288}
5289
5290static bool encodeEmbeddedMTextEntityMode(DRW::Version version, dwgBufferW *buf,
5291 const DRW_MText& mtext) {
5292 if (version < DRW::AC1032)
5293 return false;
5294
5295 // Embedded MTEXT begins at AcDbEntity mode, not with an object type,
5296 // object size, own handle, EED, or graphics data.
5297 buf->put2Bits(2); // modelspace, no owner handle
5298 buf->putBitLong(0); // no reactors
5299 buf->putBit(1); // xDictFlag=1, no xdict handle
5300 buf->putBit(1); // no prev/next links
5301 buf->putEnColor(version, static_cast<std::uint16_t>(mtext.color));
5302 buf->putBitDouble(mtext.ltypeScale);
5303 buf->put2Bits(0); // linetype by layer
5304 buf->put2Bits(0); // plotstyle by layer
5305 buf->put2Bits(0); // material inherit
5306 buf->putRawChar8(0); // shadow flags
5307 buf->putBit(0); // no full visual style
5308 buf->putBit(0); // no face visual style
5309 buf->putBit(0); // no edge visual style
5310 buf->putBitShort(0); // visible
5311 buf->putRawChar8(static_cast<std::uint8_t>(mtext.lWeight));
5312 return true;
5313}
5314
5315static bool encodeEmbeddedMTextDwg(DRW::Version version, dwgBufferW *buf,
5316 dwgBufferW *strBuf, dwgBufferW *handleBuf,
5317 const DRW_MText& mtext) {
5318 if (!encodeEmbeddedMTextEntityMode(version, buf, mtext))
5319 return false;
5320
5321 buf->put3BitDouble(mtext.basePoint);
5322 buf->put3BitDouble(mtext.extPoint);
5323 buf->put3BitDouble(mtext.secPoint);
5324 buf->putBitDouble(mtext.widthscale);
5325 buf->putBitDouble(mtext.m_r2018RectHeight);
5326 buf->putBitDouble(mtext.height);
5327 buf->putBitShort(static_cast<std::uint16_t>(mtext.textgen));
5328 buf->putBitShort(static_cast<std::uint16_t>(mtext.alignH));
5329 buf->putBitDouble(mtext.m_r2018ExtentsHeight);
5330 buf->putBitDouble(mtext.m_r2018ExtentsWidth);
5331 (strBuf ? strBuf : buf)->putVariableText(version, mtext.text);
5332
5333 buf->putBitShort(0); // linespacing style
5334 buf->putBitDouble(mtext.interlin);
5335 buf->putBit(0);
5336 buf->putBitLong(mtext.m_backgroundFlags);
5337 if ((mtext.m_backgroundFlags & 0x01)
5338 || (mtext.m_backgroundFlags & 0x10)) {
5339 buf->putBitDouble(mtext.m_backgroundScale); // BitDouble, not BitLong
5340 buf->putCmColor(version, static_cast<std::uint16_t>(mtext.m_backgroundColor));
5341 buf->putBitLong(mtext.m_backgroundTransparency);
5342 }
5343
5344 buf->putBit(mtext.m_r2018IsNotAnnotative ? 1 : 0);
5345 if (mtext.m_r2018IsNotAnnotative) {
5346 buf->putBitShort(mtext.m_r2018Version);
5347 buf->putBit(mtext.m_r2018DefaultFlag ? 1 : 0);
5348 buf->putBitLong(mtext.m_r2018Attachment);
5349 buf->put3BitDouble(mtext.m_r2018XAxisDir);
5350 buf->put3BitDouble(mtext.m_r2018InsertionPoint);
5351 buf->putBitDouble(mtext.m_r2018RectWidth);
5352 buf->putBitDouble(mtext.m_r2018RectHeight);
5353 buf->putBitDouble(mtext.m_r2018ExtentsHeight);
5354 buf->putBitDouble(mtext.m_r2018ExtentsWidth);
5355 buf->putBitShort(mtext.m_r2018ColumnType);
5356 if (mtext.m_r2018ColumnType != 0) {
5357 std::int32_t columnCount = mtext.m_r2018ColumnCount;
5358 if (!mtext.m_r2018ColumnAutoHeight && mtext.m_r2018ColumnType == 2
5359 && !mtext.m_r2018ColumnHeights.empty()) {
5360 columnCount = static_cast<std::int32_t>(mtext.m_r2018ColumnHeights.size());
5361 }
5362 buf->putBitLong(columnCount);
5363 buf->putBitDouble(mtext.m_r2018ColumnWidth);
5364 buf->putBitDouble(mtext.m_r2018ColumnGutter);
5365 buf->putBit(mtext.m_r2018ColumnAutoHeight ? 1 : 0);
5366 buf->putBit(mtext.m_r2018ColumnFlowReversed ? 1 : 0);
5367 if (!mtext.m_r2018ColumnAutoHeight && mtext.m_r2018ColumnType == 2) {
5368 for (std::int32_t i = 0; i < columnCount; ++i) {
5369 const double columnHeight = static_cast<size_t>(i) < mtext.m_r2018ColumnHeights.size()
5370 ? mtext.m_r2018ColumnHeights[static_cast<size_t>(i)]
5371 : 0.0;
5372 buf->putBitDouble(columnHeight);
5373 }
5374 }
5375 }
5376 }
5377
5378 buf->putBitShort(0); // no annotative payload
5379
5380 dwgBufferW *hb = handleBuf ? handleBuf : buf;
5381 // Layer hard-pointer: consumeEmbeddedMTextHandles reads this UNCONDITIONALLY
5382 // for version > AC1014 (the entity-mode flags this encoder writes make every
5383 // other conditional embedded handle absent: no color/owner/reactor/xdict,
5384 // linetype/plotstyle/material/shadow all "by layer"). Omitting it made the
5385 // parser consume the style handle as the layer and the appId as the style,
5386 // then run into the PARENT ATTRIB/ATTDEF handle stream, shifting it. The
5387 // parser discards this value, so emit LAYER "0" (0x12) as the placeholder
5388 // (layerH is a protected DRW_Entity member, not reachable from this free
5389 // function; only the slot matters for handle-count alignment).
5390 putHardPointerHandle(hb, 0x12);
5391 putHardPointerHandle(hb, (mtext.styleH.ref == 0) ? 0x13 : mtext.styleH.ref);
5392 if (mtext.m_r2018IsNotAnnotative)
5393 putHardPointerHandle(hb, (mtext.m_r2018AppIdHandle == 0) ? 0x14 : mtext.m_r2018AppIdHandle);
5394 return true;
5395}
5396}
5397
5398bool DRW_Attrib::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5399 // Multi-line ATTRIB (R2018+, ODA spec §20.4.4): an embedded MTEXT object
5400 // is introduced by the DXF subclass marker `100 / Embedded Object` (NOT
5401 // `AcDbMText`). After the marker, the standard MTEXT group codes follow
5402 // (10/20/30 insertion, 11/21/31 X-axis, 40 height, 41 rect width, 71
5403 // attachment point, 72 drawing direction, 1 formatted text, etc.), then
5404 // the ATTRIB-specific tail (tag=2, prompt=3 for ATTDEF, flags=70,
5405 // lock-position=280) which we must NOT route into the embedded MText.
5406 if (code == 100) {
5407 const std::string sub = reader->getString();
5408 if (sub == "Embedded Object" && !mtext) {
5409 mtext = std::make_unique<DRW_MText>();
5410 if (attVersion == 0) attVersion = 1;
5411 }
5412 return true;
5413 }
5414 // Inside the embedded MText scope, route MTEXT-owned codes to mtext but
5415 // keep ATTRIB-specific tail codes for ATTRIB / ATTDEF handling below.
5416 if (mtext) {
5417 switch (code) {
5418 case 2: // tag (ATTRIB-specific; group 1 in MText is text body)
5419 case 3: // prompt (ATTDEF-specific)
5420 case 70: // ATTRIB flags
5421 case 280: // ATTRIB lock-position
5422 break; // fall through to ATTRIB handling below
5423 default:
5424 return mtext->parseCode(code, reader);
5425 }
5426 }
5427 switch (code) {
5428 case 2:
5429 tag = reader->getUtf8String();
5430 break;
5431 case 70:
5432 attribFlags = reader->getInt32();
5433 break;
5434 case 73:
5435 // AcDbAttribute code 73 = field length (obsolete); NOT the vertical
5436 // alignment from AcDbText (which is code 73 in TEXT but 74 in ATTRIB).
5437 m_fieldLength = reader->getInt32();
5438 break;
5439 case 74:
5440 // AcDbAttribute vertical alignment (code 74); TEXT uses code 73 for
5441 // this but ATTRIB moves it here to free code 73 for field length.
5442 alignV = (VAlign)reader->getInt32();
5443 break;
5444 case 280:
5445 // Lock position flag (R2010+ DXF group code)
5446 lockPosition = reader->getInt32() != 0;
5447 break;
5448 default:
5449 return DRW_Text::parseCode(code, reader);
5450 }
5451 return true;
5452}
5453
5454bool DRW_Attrib::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5455 dwgBuffer sBuff = *buf;
5456 dwgBuffer *sBuf = buf;
5457 if (version > DRW::AC1018) {//2007+
5458 sBuf = &sBuff; //separate buffer for strings
5459 }
5460 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5461 if (!ret)
5462 return ret;
5463 DRW_DBG("\n***************************** parsing attrib *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attrib *********************************************\n"
)
;
5464
5465 // Inline TEXT subtype data (mirrors DRW_Text::parseDwg layout, sans handles)
5466 std::uint8_t data_flags = 0x00;
5467 if (version > DRW::AC1014) {
5468 data_flags = buf->getRawChar8();
5469 if (!(data_flags & 0x01)) {
5470 basePoint.z = buf->getRawDouble();
5471 }
5472 } else {
5473 basePoint.z = buf->getBitDouble();
5474 }
5475 basePoint.x = buf->getRawDouble();
5476 basePoint.y = buf->getRawDouble();
5477 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");
5478 if (version > DRW::AC1014) {
5479 if (!(data_flags & 0x02)) {
5480 secPoint.x = buf->getDefaultDouble(basePoint.x);
5481 secPoint.y = buf->getDefaultDouble(basePoint.y);
5482 } else {
5483 secPoint = basePoint;
5484 }
5485 } else {
5486 secPoint.x = buf->getRawDouble();
5487 secPoint.y = buf->getRawDouble();
5488 }
5489 secPoint.z = basePoint.z;
5490 extPoint = buf->getExtrusion(version > DRW::AC1014);
5491 thickness = buf->getThickness(version > DRW::AC1014);
5492 if (version > DRW::AC1014) {
5493 if (!(data_flags & 0x04)) oblique = buf->getRawDouble();
5494 if (!(data_flags & 0x08)) angle = buf->getRawDouble();
5495 height = buf->getRawDouble();
5496 if (!(data_flags & 0x10)) widthscale = buf->getRawDouble();
5497 } else {
5498 oblique = buf->getBitDouble();
5499 angle = buf->getBitDouble();
5500 height = buf->getBitDouble();
5501 widthscale = buf->getBitDouble();
5502 }
5503 angle *= ARAD57.29577951308232;
5504 text = sBuf->getVariableText(version, false);
5505 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");
5506 if (!(data_flags & 0x20)) textgen = buf->getBitShort();
5507 if (!(data_flags & 0x40)) alignH = (HAlign)buf->getBitShort();
5508 if (!(data_flags & 0x80)) alignV = (VAlign)buf->getBitShort();
5509
5510 // R2010+ ATTRIB version follows the common TEXT data. R2018 adds the
5511 // attribute type immediately after it.
5512 if (version >= DRW::AC1024) {
5513 attVersion = buf->getRawChar8();
5514 DRW_DBG("att version: ")DRW_dbg::dbg("att version: "); DRW_DBG(attVersion)DRW_dbg::dbg(attVersion); DRW_DBG("\n")DRW_dbg::dbg("\n");
5515 }
5516 if (version >= DRW::AC1032) {
5517 m_attributeType = buf->getRawChar8();
5518 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");
5519 }
5520
5521 bool hasEmbeddedMText = false;
5522 EmbeddedMTextHandleInfo embeddedMTextHandles;
5523 if (version >= DRW::AC1032 && m_attributeType != 0 && m_attributeType != 1) {
5524 mtext = std::make_unique<DRW_MText>();
5525 if (!parseEmbeddedMTextDwg(version, buf, sBuf, *mtext, embeddedMTextHandles)) {
5526 DRW_DBG("R2018 multi-line ATTRIB payload failed\n")DRW_dbg::dbg("R2018 multi-line ATTRIB payload failed\n");
5527 return false;
5528 }
5529 hasEmbeddedMText = true;
5530 }
5531
5532 // ATTRIB-specific fields
5533 tag = sBuf->getVariableText(version, false);
5534 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");
5535
5536 m_fieldLength = buf->getBitShort(); /* Field length BS (obsolete, usually 0) */
5537
5538 attribFlags = buf->getRawChar8();
5539 DRW_DBG("attrib flags: ")DRW_dbg::dbg("attrib flags: "); DRW_DBG(attribFlags)DRW_dbg::dbg(attribFlags); DRW_DBG("\n")DRW_dbg::dbg("\n");
5540
5541 // lockPosition (DXF 280) appears since R2007 (AC1021) per ODA §20.4.x /
5542 // ACadSharp. Read gate lowered AC1024->AC1021 so R2007/8/9 imports keep
5543 // it. The encoder still emits it only at AC1024 (no AC1021 writer
5544 // exists), so this is read-only; parseDwgEntHandle repositions to objSize
5545 // for version>AC1018, absorbing the +1 bit without handle-stream drift.
5546 if (version >= DRW::AC1021) {
5547 lockPosition = buf->getBit();
5548 DRW_DBG("lock position: ")DRW_dbg::dbg("lock position: "); DRW_DBG(lockPosition)DRW_dbg::dbg(lockPosition); DRW_DBG("\n")DRW_dbg::dbg("\n");
5549 }
5550
5551 /* Common Entity Handle Data */
5552 if (hasEmbeddedMText
5553 && !consumeEmbeddedMTextHandles(version, buf, objSize, embeddedMTextHandles, mtext.get())) {
5554 return false;
5555 }
5556 ret = DRW_Entity::parseDwgEntHandle(version, buf, !hasEmbeddedMText);
5557 if (!ret)
5558 return ret;
5559
5560 styleH = buf->getHandle();
5561 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");
5562
5563 return buf->isGood();
5564}
5565
5566bool DRW_Attrib::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
5567 (void)bs;
5568 if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext))
5569 return false;
5570 const std::uint8_t attributeType = (m_attributeType == 0) ? 1 : m_attributeType;
5571 const bool hasEmbeddedMText = version >= DRW::AC1032 && attributeType != 1;
5572 if (hasEmbeddedMText && !mtext)
5573 return false;
5574
5575 oType = 2; // ATTRIB class id — see dwgreader.cpp:1148
5576 if (!encodeDwgCommon(version, buf)) return false;
5577
5578 // TEXT-body section — mirrors DRW_Attrib::parseDwg.
5579 // data_flags=0: emit every optional field unconditionally (same
5580 // strategy as DRW_Text::encodeDwg — simpler encoder, ~30 bytes larger).
5581 buf->putRawChar8(0); // data_flags=0
5582 buf->putRawDouble(basePoint.z); // elevation RD
5583 buf->putRawDouble(basePoint.x); // insertion 2RD
5584 buf->putRawDouble(basePoint.y);
5585 buf->putDefaultDouble(basePoint.x, secPoint.x); // alignment 2DD
5586 buf->putDefaultDouble(basePoint.y, secPoint.y);
5587 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
5588 buf->putThickness(thickness, /*b_R2000_style=*/true);
5589 buf->putRawDouble(oblique); // oblique angle RD
5590 buf->putRawDouble(angle / ARAD57.29577951308232); // angle in radians RD
5591 buf->putRawDouble(height); // text height RD
5592 buf->putRawDouble(widthscale); // width factor RD
5593 dwgBufferW *sb = strBuf ? strBuf : buf;
5594 sb->putVariableText(version, text); // text string TV
5595 buf->putBitShort(static_cast<std::uint16_t>(textgen)); // generation flags BS
5596 buf->putBitShort(static_cast<std::uint16_t>(alignH)); // horiz align BS
5597 buf->putBitShort(static_cast<std::uint16_t>(alignV)); // vert align BS
5598
5599 if (version >= DRW::AC1024) {
5600 buf->putRawChar8(hasEmbeddedMText && attVersion == 0 ? 1 : attVersion);
5601 }
5602 if (version >= DRW::AC1032) {
5603 buf->putRawChar8(attributeType);
5604 }
5605
5606 if (hasEmbeddedMText) {
5607 if (!encodeEmbeddedMTextDwg(version, buf, strBuf, handleBuf, *mtext))
5608 return false;
5609 }
5610
5611 // ATTRIB-specific tail
5612 sb->putVariableText(version, tag); // tag TV
5613 buf->putBitShort(static_cast<std::uint16_t>(m_fieldLength)); // fieldLen BS
5614 buf->putRawChar8(attribFlags); // flags RC
5615 if (version >= DRW::AC1024) {
5616 buf->putBit(lockPosition ? 1 : 0); // lock position B
5617 }
5618
5619 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
5620
5621 dwgHandle sH;
5622 std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref;
5623 sH.code = 5;
5624 sH.ref = sref;
5625 sH.size = 0;
5626 if (sref != 0) { std::uint32_t t = sref; while (t != 0) { t >>= 8; ++sH.size; } }
5627 (handleBuf ? handleBuf : buf)->putHandle(sH);
5628 return true;
5629}
5630
5631bool DRW_Attdef::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5632 switch (code) {
5633 case 3:
5634 prompt = reader->getUtf8String();
5635 break;
5636 default:
5637 return DRW_Attrib::parseCode(code, reader);
5638 }
5639 return true;
5640}
5641
5642bool DRW_Attdef::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5643 // ATTDEF mirrors ATTRIB layout but adds a prompt string after the tag.
5644 // Implementation duplicates ATTRIB::parseDwg in order to inject the
5645 // prompt read at the correct offset; refactor opportunity if a third
5646 // sibling appears.
5647 dwgBuffer sBuff = *buf;
5648 dwgBuffer *sBuf = buf;
5649 if (version > DRW::AC1018) {
5650 sBuf = &sBuff;
5651 }
5652 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5653 if (!ret)
5654 return ret;
5655 DRW_DBG("\n***************************** parsing attdef *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attdef *********************************************\n"
)
;
5656
5657 std::uint8_t data_flags = 0x00;
5658 if (version > DRW::AC1014) {
5659 data_flags = buf->getRawChar8();
5660 if (!(data_flags & 0x01)) basePoint.z = buf->getRawDouble();
5661 } else {
5662 basePoint.z = buf->getBitDouble();
5663 }
5664 basePoint.x = buf->getRawDouble();
5665 basePoint.y = buf->getRawDouble();
5666 if (version > DRW::AC1014) {
5667 if (!(data_flags & 0x02)) {
5668 secPoint.x = buf->getDefaultDouble(basePoint.x);
5669 secPoint.y = buf->getDefaultDouble(basePoint.y);
5670 } else {
5671 secPoint = basePoint;
5672 }
5673 } else {
5674 secPoint.x = buf->getRawDouble();
5675 secPoint.y = buf->getRawDouble();
5676 }
5677 secPoint.z = basePoint.z;
5678 extPoint = buf->getExtrusion(version > DRW::AC1014);
5679 thickness = buf->getThickness(version > DRW::AC1014);
5680 if (version > DRW::AC1014) {
5681 if (!(data_flags & 0x04)) oblique = buf->getRawDouble();
5682 if (!(data_flags & 0x08)) angle = buf->getRawDouble();
5683 height = buf->getRawDouble();
5684 if (!(data_flags & 0x10)) widthscale = buf->getRawDouble();
5685 } else {
5686 oblique = buf->getBitDouble();
5687 angle = buf->getBitDouble();
5688 height = buf->getBitDouble();
5689 widthscale = buf->getBitDouble();
5690 }
5691 angle *= ARAD57.29577951308232;
5692 text = sBuf->getVariableText(version, false);
5693 if (!(data_flags & 0x20)) textgen = buf->getBitShort();
5694 if (!(data_flags & 0x40)) alignH = (HAlign)buf->getBitShort();
5695 if (!(data_flags & 0x80)) alignV = (VAlign)buf->getBitShort();
5696
5697 if (version >= DRW::AC1024) {
5698 attVersion = buf->getRawChar8();
5699 }
5700 if (version >= DRW::AC1032) {
5701 m_attributeType = buf->getRawChar8();
5702 }
5703
5704 bool hasEmbeddedMText = false;
5705 EmbeddedMTextHandleInfo embeddedMTextHandles;
5706 if (version >= DRW::AC1032 && m_attributeType != 0 && m_attributeType != 1) {
5707 mtext = std::make_unique<DRW_MText>();
5708 if (!parseEmbeddedMTextDwg(version, buf, sBuf, *mtext, embeddedMTextHandles)) {
5709 DRW_DBG("R2018 multi-line ATTDEF payload failed\n")DRW_dbg::dbg("R2018 multi-line ATTDEF payload failed\n");
5710 return false;
5711 }
5712 hasEmbeddedMText = true;
5713 }
5714
5715 tag = sBuf->getVariableText(version, false);
5716 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");
5717
5718 m_fieldLength = buf->getBitShort(); /* field length BS (obsolete, usually 0) */
5719
5720 attribFlags = buf->getRawChar8();
5721
5722 // lockPosition (DXF 280): read gate lowered AC1024->AC1021 to match
5723 // ATTRIB (R2007+). promptVersion/keep_duplicate RC below stays AC1024+.
5724 if (version >= DRW::AC1021) {
5725 lockPosition = buf->getBit();
5726 }
5727
5728 if (version >= DRW::AC1024) {
5729 const std::uint8_t promptVersion = buf->getRawChar8();
5730 DRW_UNUSED(promptVersion)(void)promptVersion;
5731 }
5732
5733 // ATTDEF prompt follows attrib body
5734 prompt = sBuf->getVariableText(version, false);
5735 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");
5736
5737 if (hasEmbeddedMText
5738 && !consumeEmbeddedMTextHandles(version, buf, objSize, embeddedMTextHandles, mtext.get())) {
5739 return false;
5740 }
5741 ret = DRW_Entity::parseDwgEntHandle(version, buf, !hasEmbeddedMText);
5742 if (!ret)
5743 return ret;
5744
5745 styleH = buf->getHandle();
5746
5747 return buf->isGood();
5748}
5749
5750bool DRW_Attdef::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
5751 (void)bs;
5752 if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext))
5753 return false;
5754 const std::uint8_t attributeType = (m_attributeType == 0) ? 1 : m_attributeType;
5755 const bool hasEmbeddedMText = version >= DRW::AC1032 && attributeType != 1;
5756 if (hasEmbeddedMText && !mtext)
5757 return false;
5758
5759 oType = 3; // ATTDEF class id — see dwgreader.cpp:1185
5760 if (!encodeDwgCommon(version, buf)) return false;
5761
5762 // TEXT-body section — identical layout to DRW_Attrib::encodeDwg.
5763 buf->putRawChar8(0);
5764 buf->putRawDouble(basePoint.z);
5765 buf->putRawDouble(basePoint.x);
5766 buf->putRawDouble(basePoint.y);
5767 buf->putDefaultDouble(basePoint.x, secPoint.x);
5768 buf->putDefaultDouble(basePoint.y, secPoint.y);
5769 buf->putExtrusion(extPoint, /*b_R2000_style=*/true);
5770 buf->putThickness(thickness, /*b_R2000_style=*/true);
5771 buf->putRawDouble(oblique);
5772 buf->putRawDouble(angle / ARAD57.29577951308232);
5773 buf->putRawDouble(height);
5774 buf->putRawDouble(widthscale);
5775 dwgBufferW *sb = strBuf ? strBuf : buf;
5776 sb->putVariableText(version, text);
5777 buf->putBitShort(static_cast<std::uint16_t>(textgen));
5778 buf->putBitShort(static_cast<std::uint16_t>(alignH));
5779 buf->putBitShort(static_cast<std::uint16_t>(alignV));
5780
5781 if (version >= DRW::AC1024) {
5782 buf->putRawChar8(hasEmbeddedMText && attVersion == 0 ? 1 : attVersion);
5783 }
5784 if (version >= DRW::AC1032) {
5785 buf->putRawChar8(attributeType);
5786 }
5787
5788 if (hasEmbeddedMText) {
5789 if (!encodeEmbeddedMTextDwg(version, buf, strBuf, handleBuf, *mtext))
5790 return false;
5791 }
5792
5793 sb->putVariableText(version, tag);
5794 buf->putBitShort(static_cast<std::uint16_t>(m_fieldLength)); // fieldLen BS
5795 buf->putRawChar8(attribFlags);
5796 if (version >= DRW::AC1024) {
5797 buf->putBit(lockPosition ? 1 : 0);
5798 }
5799
5800 if (version >= DRW::AC1024) {
5801 buf->putRawChar8(attVersion);
5802 }
5803
5804 // ATTDEF adds prompt between flags and handle stream
5805 sb->putVariableText(version, prompt);
5806
5807 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
5808
5809 dwgHandle sH;
5810 std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref;
5811 sH.code = 5;
5812 sH.ref = sref;
5813 sH.size = 0;
5814 if (sref != 0) { std::uint32_t t = sref; while (t != 0) { t >>= 8; ++sH.size; } }
5815 (handleBuf ? handleBuf : buf)->putHandle(sH);
5816 return true;
5817}
5818
5819bool DRW_MText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5820 switch (code) {
5821 case 1:
5822 text += reader->getString();
5823 text = reader->toUtf8String(text);
5824 break;
5825 case 11:
5826 hasXAxisVec = true;
5827 return DRW_Text::parseCode(code, reader);
5828 case 3:
5829 text += reader->getString();
5830 break;
5831 case 44:
5832 interlin = reader->getDouble();
5833 break;
5834 case 50: // djm: per dxf docs, last of code 11 or code 50 prevails
5835 hasXAxisVec = false;
5836 angle = reader->getDouble();
5837 break;
5838 case 73:
5839 linespacingStyle = static_cast<std::uint16_t>(reader->getInt32());
5840 break;
5841 default:
5842 return DRW_Text::parseCode(code, reader);
5843 }
5844
5845 return true;
5846}
5847
5848bool DRW_MText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
5849 dwgBuffer sBuff = *buf;
5850 dwgBuffer *sBuf = buf;
5851 if (version > DRW::AC1018) {//2007+
5852 sBuf = &sBuff; //separate buffer for strings
5853 }
5854 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
5855 if (!ret)
5856 return ret;
5857 DRW_DBG("\n***************************** parsing mtext *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mtext *********************************************\n"
)
;
5858
5859 basePoint = buf->get3BitDouble(); /* Insertion pt 3BD 10 - First picked point. */
5860 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");
5861 extPoint = buf->get3BitDouble(); /* Extrusion 3BD 210 Undocumented; */
5862 secPoint = buf->get3BitDouble(); /* X-axis dir 3BD 11 */
5863 hasXAxisVec = true;
5864 updateAngle();
5865 widthscale = buf->getBitDouble(); /* Rect width BD 41 */
5866 if (version > DRW::AC1018) {//2007+
5867 /* Rect height BD 46 Reference rectangle height. */
5868 /** @todo */buf->getBitDouble();
5869 }
5870 height = buf->getBitDouble();/* Text height BD 40 Undocumented */
5871 textgen = buf->getBitShort(); /* Attachment BS 71 Similar to justification; */
5872 /* Drawing dir BS 72 Left to right, etc.; see DXF doc. Reuse the
5873 * inherited alignH slot — for MTEXT this field carries the DXF group 72
5874 * "drawing direction" code (1=LtoR, 3=TtoB, 5=ByStyle), not the TEXT
5875 * horizontal-alignment values the HAlign enum was named for. The integer
5876 * round-trips cleanly; consumers compare against the raw integer. */
5877 alignH = static_cast<HAlign>(buf->getBitShort());
5878 /* Extents ht BD Undocumented and not present in DXF or entget */
5879 double ext_ht = buf->getBitDouble();
5880 DRW_UNUSED(ext_ht)(void)ext_ht;
5881 /* Extents wid BD Undocumented and not present in DXF or entget The extents
5882 rectangle, when rotated the same as the text, fits the actual text image on
5883 the screen (although we've seen it include an extra row of text in height). */
5884 double ext_wid = buf->getBitDouble();
5885 DRW_UNUSED(ext_wid)(void)ext_wid;
5886 /* Text TV 1 All text in one long string (without '\n's 3 for line wrapping).
5887 ACAD seems to add braces ({ }) and backslash-P's to indicate paragraphs
5888 based on the "\r\n"'s found in the imported file. But, all the text is in
5889 this one long string -- not broken into 1- and 3-groups as in DXF and
5890 entget. ACAD's entget breaks this string into 250-char pieces (not 255 as
5891 doc'd) – even if it's mid-word. The 1-group always gets the tag end;
5892 therefore, the 3's are always 250 chars long. */
5893 text = sBuf->getVariableText(version, false); /* Text value TV 1 */
5894 if (version > DRW::AC1014) {//2000+
5895 linespacingStyle = buf->getBitShort(); // ODA §20.4.46 code 73
5896 interlin = buf->getBitDouble();/* Linespacing Factor BD 44 */
5897 buf->getBit();/* Unknown bit B */
5898 }
5899 if (version > DRW::AC1015) {//2004+
5900 /* Background flags BL 0 = no background, 1 = background fill, 2 =background
5901 fill with drawing fill color. */
5902 m_backgroundFlags = buf->getBitLong();
5903 if ((m_backgroundFlags & 0x01) || (version >= DRW::AC1032 && (m_backgroundFlags & 0x10))) {
5904 /* Background-fill box scale, present if background flags & 1 (default
5905 1.5). It is a BitDouble, NOT a BitLong: reading it as BL consumes
5906 the wrong bit width and desyncs the stream so the following CMC
5907 fill-colour reads garbage and the entity body overruns (parse fails
5908 on every MTEXT with background fill, e.g. sample_AC1018). ACadSharp
5909 reads ReadBitDouble here. */
5910 m_backgroundScale = buf->getBitDouble();
5911 /* Background color CMC Present if background flags = 1 */
5912 m_backgroundColor = static_cast<int>(buf->getCmColor(version, nullptr, sBuf));
5913 /** @todo buf->getCMC */
5914 /* Background transparency BL Present if background flags = 1 */
5915 m_backgroundTransparency = buf->getBitLong();
5916 }
5917 }
5918
5919 bool hasR2018AppId = false;
5920 if (version >= DRW::AC1032) {
5921 m_r2018ColumnHeights.clear();
5922 m_r2018IsNotAnnotative = buf->getBit();
5923 if (m_r2018IsNotAnnotative) {
5924 m_r2018Version = buf->getBitShort();
5925 m_r2018DefaultFlag = buf->getBit();
5926 hasR2018AppId = true; // appid H follows in handle stream
5927 m_r2018Attachment = buf->getBitLong();
5928 m_r2018XAxisDir = buf->get3BitDouble();
5929 m_r2018InsertionPoint = buf->get3BitDouble();
5930 m_r2018RectWidth = buf->getBitDouble();
5931 m_r2018RectHeight = buf->getBitDouble();
5932 m_r2018ExtentsHeight = buf->getBitDouble();
5933 m_r2018ExtentsWidth = buf->getBitDouble();
5934 m_r2018ColumnType = buf->getBitShort();
5935 if (m_r2018ColumnType != 0) {
5936 m_r2018ColumnCount = buf->getBitLong();
5937 m_r2018ColumnWidth = buf->getBitDouble();
5938 m_r2018ColumnGutter = buf->getBitDouble();
5939 m_r2018ColumnAutoHeight = buf->getBit();
5940 m_r2018ColumnFlowReversed = buf->getBit();
5941 if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2 && m_r2018ColumnCount > 0
5942 && m_r2018ColumnCount < 10000) {
5943 m_r2018ColumnHeights.reserve(static_cast<size_t>(m_r2018ColumnCount));
5944 for (std::int32_t i = 0; i < m_r2018ColumnCount; ++i) {
5945 m_r2018ColumnHeights.push_back(buf->getBitDouble());
5946 }
5947 }
5948 }
5949 }
5950 }
5951
5952 /* Common Entity Handle Data */
5953 ret = DRW_Entity::parseDwgEntHandle(version, buf);
5954 if (!ret)
5955 return ret;
5956
5957 styleH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
5958 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(".");
5959 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");
5960 if (hasR2018AppId) {
5961 dwgHandle appIdH = buf->getHandle();
5962 m_r2018AppIdHandle = appIdH.ref;
5963 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");
5964 }
5965
5966 /* CRC X --- */
5967 return buf->isGood();
5968}
5969
5970void DRW_MText::updateAngle() {
5971 if (hasXAxisVec) {
5972 angle = atan2(secPoint.y, secPoint.x) * ARAD57.29577951308232;
5973 }
5974}
5975
5976bool DRW_Polyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
5977 switch (code) {
5978 case 70:
5979 flags = reader->getInt32();
5980 break;
5981 case 40:
5982 defstawidth = reader->getDouble();
5983 break;
5984 case 41:
5985 defendwidth = reader->getDouble();
5986 break;
5987 case 71:
5988 vertexcount = reader->getInt32();
5989 break;
5990 case 72:
5991 facecount = reader->getInt32();
5992 break;
5993 case 73:
5994 smoothM = reader->getInt32();
5995 break;
5996 case 74:
5997 smoothN = reader->getInt32();
5998 break;
5999 case 75:
6000 curvetype = reader->getInt32();
6001 break;
6002 default:
6003 return DRW_Point::parseCode(code, reader);
6004 }
6005
6006 return true;
6007}
6008
6009//0x0F polyline 2D bit 4(8) & 5(16) NOT set
6010//0x10 polyline 3D bit 4(8) set
6011//0x1D PFACE bit 5(16) set
6012bool DRW_Polyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
6013 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
6014 if (!ret)
6015 return ret;
6016 DRW_DBG("\n***************************** parsing polyline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing polyline *********************************************\n"
)
;
6017
6018 std::int32_t ooCount = 0;
6019 if (oType == 0x0F) { //pline 2D
6020 flags = buf->getBitShort();
6021 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6022 curvetype = buf->getBitShort();
6023 defstawidth = buf->getBitDouble();
6024 defendwidth = buf->getBitDouble();
6025 thickness = buf->getThickness(version > DRW::AC1014);
6026 basePoint = DRW_Coord(0,0,buf->getBitDouble());
6027 extPoint = buf->getExtrusion(version > DRW::AC1014);
6028 } else if (oType == 0x10) { //pline 3D
6029 std::uint8_t tmpFlag = buf->getRawChar8();
6030 DRW_DBG("flags 1 value: ")DRW_dbg::dbg("flags 1 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag);
6031 if (tmpFlag & 1)
6032 curvetype = 5; // quadratic B-spline
6033 else if (tmpFlag & 2)
6034 curvetype = 6; // cubic B-spline
6035 if (tmpFlag & 3)
6036 flags |= 4; // splined (bit 2); do NOT overwrite curvetype to 8
6037 tmpFlag = buf->getRawChar8();
6038 if (tmpFlag & 1)
6039 flags |= 1;
6040 flags |= 8; //indicate 3DPOL
6041 DRW_DBG("flags 2 value: ")DRW_dbg::dbg("flags 2 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag);
6042 } else if (oType == 0x1D) { //PFACE
6043 flags = 64;
6044 vertexcount = buf->getBitShort();
6045 DRW_DBG("vertex count: ")DRW_dbg::dbg("vertex count: "); DRW_DBG(vertexcount)DRW_dbg::dbg(vertexcount);
6046 facecount = buf->getBitShort();
6047 DRW_DBG("face count: ")DRW_dbg::dbg("face count: "); DRW_DBG(facecount)DRW_dbg::dbg(facecount);
6048 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6049 } else if (oType == 0x1E) { //POLYLINE_MESH per ODA spec sec 19.4.31
6050 flags = buf->getBitShort();
6051 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6052 flags |= 16; //bit 4 = 3D polygon mesh
6053 curvetype = buf->getBitShort();
6054 vertexcount = buf->getBitShort(); //M-count
6055 DRW_DBG(" M count: ")DRW_dbg::dbg(" M count: "); DRW_DBG(vertexcount)DRW_dbg::dbg(vertexcount);
6056 facecount = buf->getBitShort(); //N-count
6057 DRW_DBG(" N count: ")DRW_dbg::dbg(" N count: "); DRW_DBG(facecount)DRW_dbg::dbg(facecount);
6058 smoothM = buf->getBitShort(); //M smooth-surface density, DXF 73
6059 smoothN = buf->getBitShort(); //N smooth-surface density, DXF 74
6060 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);
6061 }
6062 if (version > DRW::AC1015){ //2004+
6063 ooCount = buf->getBitLong();
6064 }
6065
6066 ret = DRW_Entity::parseDwgEntHandle(version, buf);
6067 if (!ret)
6068 return ret;
6069
6070 if (version < DRW::AC1018){ //2000-
6071 dwgHandle objectH = buf->getOffsetHandle(handle);
6072 firstEH = objectH.ref;
6073 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");
6074 objectH = buf->getOffsetHandle(handle);
6075 lastEH = objectH.ref;
6076 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");
6077 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");
6078 } else {
6079 for (std::int32_t i = 0; i < ooCount; ++i){
6080 dwgHandle objectH = buf->getOffsetHandle(handle);
6081 hadlesList.push_back (objectH.ref);
6082 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");
6083 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");
6084 }
6085 }
6086 seqEndH = buf->getOffsetHandle(handle);
6087 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");
6088 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");
6089
6090// RS crc; //RS */
6091 return buf->isGood();
6092}
6093
6094bool DRW_Vertex::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
6095 switch (code) {
6096 case 70:
6097 flags = reader->getInt32();
6098 break;
6099 case 40:
6100 stawidth = reader->getDouble();
6101 break;
6102 case 41:
6103 endwidth = reader->getDouble();
6104 break;
6105 case 42:
6106 bulge = reader->getDouble();
6107 break;
6108 case 50:
6109 tgdir = reader->getDouble();
6110 break;
6111 case 71:
6112 vindex1 = reader->getInt32();
6113 break;
6114 case 72:
6115 vindex2 = reader->getInt32();
6116 break;
6117 case 73:
6118 vindex3 = reader->getInt32();
6119 break;
6120 case 74:
6121 vindex4 = reader->getInt32();
6122 break;
6123 case 91:
6124 identifier = reader->getInt32();
6125 break;
6126 default:
6127 return DRW_Point::parseCode(code, reader);
6128 }
6129
6130 return true;
6131}
6132
6133//0x0A vertex 2D
6134//0x0B vertex 3D
6135//0x0C MESH
6136//0x0D PFACE
6137//0x0E PFACE FACE
6138bool DRW_Vertex::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs, double el){
6139 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
6140 if (!ret)
6141 return ret;
6142 DRW_DBG("\n***************************** parsing pline Vertex *********************************************\n")DRW_dbg::dbg("\n***************************** parsing pline Vertex *********************************************\n"
)
;
6143
6144 if (oType == 0x0A) { //pline 2D, needed example
6145 m_dwgSubtype = DwgSubtype::Vertex2D;
6146 flags = buf->getRawChar8(); //RLZ: EC unknown type
6147 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6148 basePoint = buf->get3BitDouble();
6149 basePoint.z = el;
6150 DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
6151 stawidth = buf->getBitDouble();
6152 if (stawidth < 0)
6153 endwidth = stawidth = fabs(stawidth);
6154 else
6155 endwidth = buf->getBitDouble();
6156 bulge = buf->getBitDouble();
6157 if (version > DRW::AC1021) { //2010+
6158 identifier = buf->getBitLong(); // ODA §20.4.11 code 91
6159 DRW_DBG("Vertex ID: ")DRW_dbg::dbg("Vertex ID: "); DRW_DBG(identifier)DRW_dbg::dbg(identifier);
6160 }
6161 tgdir = buf->getBitDouble();
6162 } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) { //PFACE
6163 if (oType == 0x0B)
6164 m_dwgSubtype = DwgSubtype::Vertex3D;
6165 else if (oType == 0x0C)
6166 m_dwgSubtype = DwgSubtype::Mesh;
6167 else
6168 m_dwgSubtype = DwgSubtype::Polyface;
6169 flags = buf->getRawChar8(); //RLZ: EC unknown type
6170 DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags);
6171 basePoint = buf->get3BitDouble();
6172 DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
6173 } else if (oType == 0x0E) { //PFACE FACE
6174 m_dwgSubtype = DwgSubtype::PolyfaceFace;
6175 auto signedIndex = [](int value) {
6176 return value > 32767 ? value - 65536 : value;
6177 };
6178 vindex1 = signedIndex(buf->getBitShort());
6179 vindex2 = signedIndex(buf->getBitShort());
6180 vindex3 = signedIndex(buf->getBitShort());
6181 vindex4 = signedIndex(buf->getBitShort());
6182 }
6183
6184 ret = DRW_Entity::parseDwgEntHandle(version, buf);
6185 if (!ret)
6186 return ret;
6187 // RS crc; //RS */
6188 return buf->isGood();
6189}
6190
6191bool DRW_Hatch::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
6192 switch (code) {
6193 case 2:
6194 name = reader->getUtf8String();
6195 break;
6196 case 70:
6197 solid = reader->getInt32();
6198 break;
6199 case 71:
6200 associative = reader->getInt32();
6201 break;
6202 case 72: /*edge type*/
6203 if (ispol){ // polyline path: 72 is the has-bulge flag. Do NOT fold it
6204 // into pline->flags — bit 0 there is the *closed* flag (set by code
6205 // 73), and the per-vertex bulges arrive via code 42 regardless. Some
6206 // writers (e.g. ezdxf MPOLYGON) emit 73 before 72; the old code let
6207 // 72 clear the closed bit 73 had just set, leaving the boundary open
6208 // so RS_Hatch::validate() rejected the area.
6209 break;
6210 } else if (reader->getInt32() == 1){ //line
6211 addLine();
6212 } else if (reader->getInt32() == 2){ //arc
6213 addArc();
6214 } else if (reader->getInt32() == 3){ //elliptic arc
6215 addEllipse();
6216 } else if (reader->getInt32() == 4){ //spline
6217 addSpline();
6218 }
6219 break;
6220 case 10:
6221 // Spline edge: 10 is a control-point x-coord.
6222 if (spline) {
6223 spline->controllist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0));
6224 break;
6225 }
6226 if (pt) pt->basePoint.x = reader->getDouble();
6227 else if (pline) {
6228 plvert = pline->addVertex();
6229 plvert->x = reader->getDouble();
6230 } else {
6231 // After group 98 the boundary path is closed; seed-point
6232 // coords arrive as group-10/20 pairs.
6233 DRW_Coord seed;
6234 seed.x = reader->getDouble();
6235 seedPoints.push_back(seed);
6236 }
6237 break;
6238 case 20:
6239 if (spline && !spline->controllist.empty()) {
6240 spline->controllist.back()->y = reader->getDouble();
6241 break;
6242 }
6243 if (pt) pt->basePoint.y = reader->getDouble();
6244 else if (plvert) plvert ->y = reader->getDouble();
6245 else if (!seedPoints.empty())
6246 seedPoints.back().y = reader->getDouble();
6247 break;
6248 case 11:
6249 // Spline edge: 11 is a fit-point x-coord.
6250 if (spline) {
6251 spline->fitlist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0));
6252 break;
6253 }
6254 if (line) line->secPoint.x = reader->getDouble();
6255 else if (ellipse) ellipse->secPoint.x = reader->getDouble();
6256 break;
6257 case 21:
6258 if (spline && !spline->fitlist.empty()) {
6259 spline->fitlist.back()->y = reader->getDouble();
6260 break;
6261 }
6262 if (line) line->secPoint.y = reader->getDouble();
6263 else if (ellipse) ellipse->secPoint.y = reader->getDouble();
6264 break;
6265 case 12:
6266 if (spline) { spline->tgStart.x = reader->getDouble(); break; }
6267 break;
6268 case 22:
6269 if (spline) { spline->tgStart.y = reader->getDouble(); break; }
6270 break;
6271 case 13:
6272 if (spline) { spline->tgEnd.x = reader->getDouble(); break; }
6273 break;
6274 case 23:
6275 if (spline) { spline->tgEnd.y = reader->getDouble(); break; }
6276 break;
6277 case 40:
6278 // Spline edge: 40 is a knot value (occurs nknots times).
6279 if (spline) {
6280 spline->knotslist.push_back(reader->getDouble());
6281 break;
6282 }
6283 if (arc) arc->radious = reader->getDouble();
6284 else if (ellipse) ellipse->ratio = reader->getDouble();
6285 break;
6286 case 41:
6287 scale = reader->getDouble();
6288 break;
6289 case 42:
6290 // Spline edge: 42 is a per-control-point weight.
6291 if (spline) {
6292 spline->weightlist.push_back(reader->getDouble());
6293 break;
6294 }
6295 if (plvert) plvert ->bulge = reader->getDouble();
6296 break;
6297 case 50:
6298 if (arc) arc->staangle = reader->getDouble()/ARAD57.29577951308232;
6299 else if (ellipse) ellipse->staparam = reader->getDouble()/ARAD57.29577951308232;
6300 break;
6301 case 51:
6302 if (arc) arc->endangle = reader->getDouble()/ARAD57.29577951308232;
6303 else if (ellipse) ellipse->endparam = reader->getDouble()/ARAD57.29577951308232;
6304 break;
6305 case 47:
6306 pixelSize = reader->getDouble();
6307 break;
6308 case 52:
6309 angle = reader->getDouble();
6310 break;
6311 case 53: // pattern line angle — starts a new PatternLine record
6312 patternLines.push_back(PatternLine());
6313 patternLines.back().angle = reader->getDouble();
6314 break;
6315 case 43:
6316 if (!patternLines.empty()) patternLines.back().baseX = reader->getDouble();
6317 break;
6318 case 44:
6319 if (!patternLines.empty()) patternLines.back().baseY = reader->getDouble();
6320 break;
6321 case 45:
6322 if (!patternLines.empty()) patternLines.back().offsetX = reader->getDouble();
6323 break;
6324 case 46:
6325 if (!patternLines.empty()) patternLines.back().offsetY = reader->getDouble();
6326 break;
6327 case 79: // dash count — the 49s that follow will accumulate
6328 break;
6329 case 49:
6330 if (!patternLines.empty()) patternLines.back().dashList.push_back(reader->getDouble());
6331 break;
6332 case 73:
6333 // Spline edge: 73 is the rational flag (1 = rational).
6334 if (spline) {
6335 if (reader->getInt32()) spline->flags |= 0x4;
6336 break;
6337 }
6338 if (arc) arc->isccw = reader->getInt32();
6339 // polyline path: 73 is the is-closed flag -> set bit 0 only, leaving the
6340 // rest of pline->flags untouched (order-independent vs code 72).
6341 else if (pline) pline->flags = (pline->flags & ~1) | (reader->getInt32() ? 1 : 0);
6342 break;
6343 case 74:
6344 // Spline edge: 74 is the periodic flag (1 = periodic/closed).
6345 if (spline) {
6346 if (reader->getInt32()) spline->flags |= 0x2;
6347 }
6348 break;
6349 case 94:
6350 // Spline edge degree.
6351 if (spline) spline->degree = reader->getInt32();
6352 break;
6353 case 95:
6354 // Spline edge number of knots.
6355 if (spline) spline->nknots = reader->getInt32();
6356 break;
6357 case 96:
6358 // Spline edge number of control points.
6359 if (spline) spline->ncontrol = reader->getInt32();
6360 break;
6361 case 97:
6362 if (spline) {
6363 if (!m_splineNfitSet) {
6364 // First 97 in this spline edge = fit-point count (nfit).
6365 spline->nfit = reader->getInt32();
6366 if (spline->nfit == 0) {
6367 // No fit points or tangents follow; safe to clear spline
6368 // so the next code-97 (loop boundary count) is not
6369 // misinterpreted as another nfit.
6370 spline.reset();
6371 } else {
6372 m_splineNfitSet = true;
6373 }
6374 } else {
6375 // Second 97 while spline is active = loop boundary handle count.
6376 spline.reset();
6377 m_splineNfitSet = false;
6378 m_boundaryHandleCount = reader->getInt32();
6379 if (m_boundaryHandleCount > 0 && loop)
6380 DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount);
6381 }
6382 break;
6383 }
6384 // No active spline: this is the loop boundary handle count.
6385 m_splineNfitSet = false;
6386 m_boundaryHandleCount = reader->getInt32();
6387 if (m_boundaryHandleCount > 0 && loop)
6388 DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount);
6389 break;
6390 case 330:
6391 if (m_boundaryHandleCount > 0 && loop) {
6392 // getHandleString() converts the hex string to int for us.
6393 loop->m_boundaryHandles.push_back(
6394 static_cast<std::uint32_t>(reader->getHandleString()));
6395 --m_boundaryHandleCount;
6396 break;
6397 }
6398 return DRW_Point::parseCode(code, reader);
6399 case 75:
6400 hstyle = reader->getInt32();
6401 break;
6402 case 76:
6403 hpattern = reader->getInt32();
6404 break;
6405 case 77:
6406 doubleflag = reader->getInt32();
6407 break;
6408 case 78:
6409 deflines = reader->getInt32();
6410 break;
6411 case 91:
6412 loopsnum = reader->getInt32();
6413 return DRW::reserve( looplist, loopsnum);
6414 case 92:
6415 loop = std::make_shared<DRW_HatchLoop>(reader->getInt32());
6416 looplist.push_back(loop);
6417 if (reader->getInt32() & 2) {
6418 ispol = true;
6419 clearEntities();
6420 pline = std::make_shared<DRW_LWPolyline>();
6421 loop->objlist.push_back(pline);
6422 } else ispol = false;
6423 break;
6424 case 93:
6425 if (pline) pline->vertexnum = reader->getInt32();
6426 else if (loop) loop->numedges = reader->getInt32();//aqui reserve
6427 break;
6428 case 98: { // seed-point count; coords follow as group-10/20 pairs
6429 clearEntities();
6430 const int count = reader->getInt32();
6431 if (count > 0)
6432 DRW::reserve(seedPoints, count);
6433 break;
6434 }
6435 case 450:
6436 isGradient = reader->getInt32();
6437 break;
6438 case 451:
6439 gradReserved = reader->getInt32();
6440 break;
6441 case 452:
6442 singleColor = reader->getInt32();
6443 break;
6444 case 453: {
6445 const int n = reader->getInt32();
6446 if (n > 0)
6447 DRW::reserve(gradColors, n);
6448 break;
6449 }
6450 case 460:
6451 gradAngle = reader->getDouble();
6452 break;
6453 case 461:
6454 gradShift = reader->getDouble();
6455 break;
6456 case 462:
6457 gradTint = reader->getDouble();
6458 break;
6459 case 463: {
6460 DRW_Hatch::GradientStop stop;
6461 stop.value = reader->getDouble();
6462 gradColors.push_back(stop);
6463 break;
6464 }
6465 case 421:
6466 if (!gradColors.empty())
6467 gradColors.back().rgb = reader->getInt32();
6468 break;
6469 case 63:
6470 if (!gradColors.empty())
6471 gradColors.back().aciColor = reader->getInt32();
6472 else
6473 return DRW_Point::parseCode(code, reader);
6474 break;
6475 case 431:
6476 if (!gradColors.empty())
6477 gradColors.back().colorMethod = reader->getInt32();
6478 break;
6479 case 432:
6480 if (!gradColors.empty())
6481 gradColors.back().colorName = reader->getUtf8String();
6482 break;
6483 case 433:
6484 if (!gradColors.empty())
6485 gradColors.back().colorBookName = reader->getUtf8String();
6486 break;
6487 case 470:
6488 gradName = reader->getUtf8String();
6489 break;
6490 default:
6491 return DRW_Point::parseCode(code, reader);
6492 }
6493
6494 return true;
6495}
6496
6497bool DRW_MPolygon::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
6498 // MPOLYGON shares HATCH's boundary/pattern/gradient codes, so delegate those
6499 // to DRW_Hatch::parseCode. It adds a trailer that plain HATCH never emits:
6500 // 63 / 421 / 430 fill color (ACI / RGB / book-name) — the filled area's
6501 // color, which may differ from the boundary outline color;
6502 // 11 / 21 boundary x-direction vector (no render impact; left to
6503 // the base, which ignores it outside an edge context);
6504 // 99 count of degenerate boundary paths.
6505 // 63/421 are also gradient sub-codes in HATCH, so only claim them here when no
6506 // gradient is being accumulated (gradColors empty) — otherwise defer to base.
6507 switch (code) {
6508 case 63:
6509 if (gradColors.empty()) { fillColorAci = reader->getInt32(); return true; }
6510 break;
6511 case 421:
6512 if (gradColors.empty()) { fillColorRgb = reader->getInt32(); return true; }
6513 break;
6514 case 430:
6515 fillColorName = reader->getUtf8String();
6516 return true;
6517 case 99:
6518 degenerateLoops = reader->getInt32();
6519 return true;
6520 default:
6521 break;
6522 }
6523 return DRW_Hatch::parseCode(code, reader);
6524}
6525
6526// DRW_MPolygon::parseDwg — AcDbMPolygon DWG body.
6527// Layout mirrors HATCH except (per ACadSharp MPolygon / libreDWG dwg.spec):
6528// * a leading BS `style` (DXF group 75) precedes the gradient block, and
6529// * the trailer is a fill CMC + boundary x-direction (2RD) + degenerate-path
6530// count (BL) instead of HATCH's pixel-size + seed points.
6531// The gradient/elevation/extrusion/name/solid/associative prologue and the whole
6532// boundary-loop body are identical, so they reuse DRW_Hatch::parseDwgBoundaryData.
6533// DWG runtime coverage uses testdata/mpolygon_solid.dwg, ODA-synthesized from
6534// the ezdxf-verified inline DXF in mpolygon_tests.cpp and confirmed with the
6535// dwg-parser oracle.
6536bool DRW_MPolygon::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
6537 dwgBuffer sBuff = *buf;
6538 dwgBuffer *sBuf = buf;
6539 std::uint32_t totalBoundItems = 0;
6540 bool havePixelSize = false;
6541 if (version > DRW::AC1018) //2007+
6542 sBuf = &sBuff; //separate buffer for strings
6543 if (!DRW_Entity::parseDwg(version, buf, sBuf, bs))
6544 return false;
6545 DRW_DBG("\n***************************** parsing mpolygon *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mpolygon *********************************************\n"
)
;
6546
6547 // Leading BS style (group 75) — read once here and again after the loops
6548 // below (HATCH has only the latter); matches the reference parser, which
6549 // discards this first read.
6550 hstyle = buf->getBitShort();
6551
6552 if (version > DRW::AC1015) { //2004+ gradient (same layout as HATCH)
6553 isGradient = buf->getBitLong();
6554 gradReserved = buf->getBitLong();
6555 gradAngle = buf->getBitDouble();
6556 gradShift = buf->getBitDouble();
6557 singleColor = buf->getBitLong();
6558 gradTint = buf->getBitDouble();
6559 std::int32_t numCol = buf->getBitLong();
6560 if (numCol > 0)
6561 DRW::reserve(gradColors, numCol);
6562 for (std::int32_t i = 0 ; i < numCol; ++i){
6563 DRW_Hatch::GradientStop stop;
6564 stop.value = buf->getBitDouble();
6565 buf->getBitShort(); // unknown short
6566 stop.rgb = buf->getBitLong();
6567 buf->getRawChar8(); // ignored color byte
6568 gradColors.push_back(stop);
6569 }
6570 gradName = sBuf->getVariableText(version, false);
6571 }
6572 basePoint.z = buf->getBitDouble(); // elevation
6573 extPoint = buf->get3BitDouble();
6574 name = sBuf->getVariableText(version, false);
6575 solid = buf->getBit();
6576 associative = buf->getBit();
6577
6578 if (!parseDwgBoundaryData(version, buf, totalBoundItems, havePixelSize))
6579 return false;
6580
6581 hstyle = buf->getBitShort();
6582 hpattern = buf->getBitShort();
6583 if (!solid){
6584 angle = buf->getBitDouble();
6585 scale = buf->getBitDouble();
6586 doubleflag = buf->getBit();
6587 deflines = buf->getBitShort();
6588 for (std::int32_t i = 0 ; i < deflines; ++i){
6589 buf->getBitDouble(); // line angle
6590 buf->getBitDouble(); // base x
6591 buf->getBitDouble(); // base y
6592 buf->getBitDouble(); // offset x
6593 buf->getBitDouble(); // offset y
6594 std::uint16_t numDashL = buf->getBitShort();
6595 for (std::uint16_t d = 0 ; d < numDashL; ++d)
6596 buf->getBitDouble(); // dash length
6597 }
6598 }
6599
6600 // MPOLYGON trailer (differs from HATCH): fill CMC + x-direction + degenerate
6601 // path count. No pixel size / seed points here.
6602 std::int32_t rgb = -1;
6603 UTF8STRINGstd::string colName;
6604 fillColorAci = static_cast<int>(buf->getCmColor(version, &rgb, sBuf, &colName));
6605 fillColorRgb = rgb;
6606 fillColorName = colName;
6607 DRW_Coord xdir = buf->get2RawDouble();
6608 xDirX = xdir.x;
6609 xDirY = xdir.y;
6610 degenerateLoops = buf->getBitLong();
6611
6612 if (!DRW_Entity::parseDwgEntHandle(version, buf))
6613 return false;
6614 for (std::uint32_t i = 0 ; i < totalBoundItems; ++i)
6615 buf->getHandle(); // boundary-source handles
6616 return buf->isGood();
6617}
6618
6619// Shared DWG boundary-loop reader for HATCH and MPOLYGON (ODA §20.4.36).
6620// Reads the loop count and, per loop, the derived-boundary flag plus its edge
6621// list or polyline. Accumulates the running boundary-source-handle total and
6622// whether any loop is derived (needs a trailing pixel size). Extracted from
6623// DRW_Hatch::parseDwg so DRW_MPolygon::parseDwg reuses the identical body while
6624// supplying its own differing leading (BS style) and trailing (fill CMC +
6625// x-direction + degenerate count) field order.
6626bool DRW_MPolygon::encodeDwg(DRW::Version version, dwgBufferW *buf,
6627 std::uint32_t bs, dwgBufferW *strBuf,
6628 dwgBufferW *handleBuf) {
6629 (void)bs;
6630 oType = kDwgClassNum;
6631 if (!encodeDwgCommon(version, buf, strBuf))
6632 return false;
6633
6634 dwgBufferW *sb = strBuf ? strBuf : buf;
6635
6636 // AcDbMPolygon has a leading style field before the HATCH-like gradient
6637 // prologue. The same style is emitted again after the boundary data.
6638 buf->putBitShort(static_cast<std::uint16_t>(hstyle));
6639 encodeDwgGradientData(version, buf, sb);
6640
6641 buf->putBitDouble(basePoint.z);
6642 buf->put3BitDouble(extPoint);
6643 sb->putVariableText(version, name);
6644 buf->putBit(static_cast<std::uint8_t>(solid));
6645 buf->putBit(static_cast<std::uint8_t>(associative));
6646 if (!encodeDwgBoundaryData(version, buf)) return false;
6647
6648 buf->putBitShort(static_cast<std::uint16_t>(hstyle));
6649 buf->putBitShort(static_cast<std::uint16_t>(hpattern));
6650
6651 if (!solid) {
6652 buf->putBitDouble(angle);
6653 buf->putBitDouble(scale);
6654 buf->putBit(static_cast<std::uint8_t>(doubleflag));
6655 buf->putBitShort(static_cast<std::uint16_t>(patternLines.size()));
6656 for (const PatternLine& pl : patternLines) {
6657 buf->putBitDouble(pl.angle);
6658 buf->putBitDouble(pl.baseX);
6659 buf->putBitDouble(pl.baseY);
6660 buf->putBitDouble(pl.offsetX);
6661 buf->putBitDouble(pl.offsetY);
6662 buf->putBitShort(static_cast<std::uint16_t>(pl.dashList.size()));
6663 for (double dash : pl.dashList)
6664 buf->putBitDouble(dash);
6665 }
6666 }
6667
6668 buf->putCmColor(version,
6669 static_cast<std::uint16_t>(fillColorAci),
6670 fillColorRgb,
6671 fillColorName,
6672 {},
6673 sb);
6674 buf->put2RawDouble(DRW_Coord{xDirX, xDirY, 0.0});
6675 buf->putBitLong(degenerateLoops);
6676
6677 return encodeDwgEntHandle(version, buf, handleBuf);
6678}
6679
6680bool DRW_Hatch::parseDwgBoundaryData(DRW::Version version, dwgBuffer *buf,
6681 std::uint32_t &totalBoundItems, bool &havePixelSize) {
6682 loopsnum = buf->getBitLong();
6683 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);
6684 DRW_DBG(" loopsnum: ")DRW_dbg::dbg(" loopsnum: "); DRW_DBG(loopsnum)DRW_dbg::dbg(loopsnum); DRW_DBG("\n")DRW_dbg::dbg("\n");
6685
6686 //read loops
6687 for (std::int32_t i = 0 ; i < loopsnum; ++i){
6688 loop = std::make_shared<DRW_HatchLoop>(buf->getBitLong());
6689 havePixelSize = havePixelSize || ((loop->type & 4) != 0);
6690 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);
6691 if (!(loop->type & 2)){ //Not polyline
6692 std::int32_t numPathSeg = buf->getBitLong();
6693 DRW_DBG(" numPathSeg: ")DRW_dbg::dbg(" numPathSeg: "); DRW_DBG(numPathSeg)DRW_dbg::dbg(numPathSeg); DRW_DBG("\n")DRW_dbg::dbg("\n");
6694 for (std::int32_t j = 0; j<numPathSeg;++j){
6695 std::uint8_t typePath = buf->getRawChar8();
6696 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");
6697 if (typePath == 1){ //line
6698 addLine();
6699 line->basePoint = buf->get2RawDouble();
6700 line->secPoint = buf->get2RawDouble();
6701 } else if (typePath == 2){ //circle arc
6702 addArc();
6703 arc->basePoint = buf->get2RawDouble();
6704 arc->radious = buf->getBitDouble();
6705 arc->staangle = buf->getBitDouble();
6706 arc->endangle = buf->getBitDouble();
6707 arc->isccw = buf->getBit();
6708 } else if (typePath == 3){ //ellipse arc
6709 addEllipse();
6710 ellipse->basePoint = buf->get2RawDouble();
6711 ellipse->secPoint = buf->get2RawDouble();
6712 ellipse->ratio = buf->getBitDouble();
6713 ellipse->staparam = buf->getBitDouble();
6714 ellipse->endparam = buf->getBitDouble();
6715 ellipse->isccw = buf->getBit();
6716 } else if (typePath == 4){ //spline
6717 addSpline();
6718 spline->degree = buf->getBitLong();
6719 bool isRational = buf->getBit();
6720 spline->flags |= (isRational << 2); //rational
6721 spline->flags |= (buf->getBit() << 1); //periodic
6722 spline->nknots = buf->getBitLong();
6723 if (!DRW::reserve( spline->knotslist, spline->nknots)) {
6724 return false;
6725 }
6726 spline->ncontrol = buf->getBitLong();
6727 if (!DRW::reserve( spline->controllist, spline->ncontrol)) {
6728 return false;
6729 }
6730 for (std::int32_t j = 0; j < spline->nknots;++j){
6731 spline->knotslist.push_back (buf->getBitDouble());
6732 }
6733 for (std::int32_t j = 0; j < spline->ncontrol;++j){
6734 std::shared_ptr<DRW_Coord> crd = std::make_shared<DRW_Coord>(buf->get2RawDouble());
6735 if(isRational)
6736 crd->z = buf->getBitDouble(); //RLZ: investigate how store weight
6737 spline->controllist.push_back(crd);
6738 }
6739 if (version > DRW::AC1021) { //2010+
6740 spline->nfit = buf->getBitLong();
6741 // Fit points AND the start/end tangents are present only
6742 // when nfit > 0 (matches ACadSharp's `if (nfitPoints > 0)`).
6743 // Reading the two tangents unconditionally on an nfit==0
6744 // spline edge over-runs the entity body and fails the parse
6745 // (e.g. svg/export_sample.dwg: a degree-3 non-rational
6746 // spline boundary edge with 9 control points / 0 fit points).
6747 if (spline->nfit > 0) {
6748 if (!DRW::reserve( spline->fitlist, spline->nfit)) {
6749 return false;
6750 }
6751 for (std::int32_t j = 0; j < spline->nfit;++j){
6752 std::shared_ptr<DRW_Coord> crd = std::make_shared<DRW_Coord>(buf->get2RawDouble());
6753 spline->fitlist.push_back(crd);
6754 }
6755 spline->tgStart = buf->get2RawDouble();
6756 spline->tgEnd = buf->get2RawDouble();
6757 }
6758 }
6759 }
6760 }
6761 } else { //end not pline, start polyline
6762 pline = std::make_shared<DRW_LWPolyline>();
6763 bool asBulge = buf->getBit();
6764 pline->flags = buf->getBit();//closed bit
6765 std::int32_t numVert = buf->getBitLong();
6766 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);
6767 DRW_DBG(" numVert: ")DRW_dbg::dbg(" numVert: "); DRW_DBG(numVert)DRW_dbg::dbg(numVert); DRW_DBG("\n")DRW_dbg::dbg("\n");
6768 for (std::int32_t j = 0; j<numVert;++j){
6769 DRW_Vertex2D v;
6770 v.x = buf->getRawDouble();
6771 v.y = buf->getRawDouble();
6772 if (asBulge)
6773 v.bulge = buf->getBitDouble();
6774 pline->addVertex(v);
6775 }
6776 loop->objlist.push_back(pline);
6777 }//end polyline
6778 loop->update();
6779 looplist.push_back(loop);
6780 totalBoundItems += buf->getBitLong();
6781 DRW_DBG(" totalBoundItems: ")DRW_dbg::dbg(" totalBoundItems: "); DRW_DBG(totalBoundItems)DRW_dbg::dbg(totalBoundItems);
6782 } //end read loops
6783 return true;
6784}
6785
6786bool DRW_Hatch::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
6787 dwgBuffer sBuff = *buf;
6788 dwgBuffer *sBuf = buf;
6789 std::uint32_t totalBoundItems = 0;
6790 bool havePixelSize = false;
6791
6792 if (version > DRW::AC1018) {//2007+
6793 sBuf = &sBuff; //separate buffer for strings
6794 }
6795 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
6796 if (!ret)
6797 return ret;
6798 DRW_DBG("\n***************************** parsing hatch *********************************************\n")DRW_dbg::dbg("\n***************************** parsing hatch *********************************************\n"
)
;
6799
6800 //Gradient data, RLZ: is ok or if grad > 0 continue read ?
6801 if (version > DRW::AC1015) { //2004+
6802 isGradient = buf->getBitLong();
6803 DRW_DBG("is Gradient: ")DRW_dbg::dbg("is Gradient: "); DRW_DBG(isGradient)DRW_dbg::dbg(isGradient);
6804 gradReserved = buf->getBitLong();
6805 DRW_DBG(" reserved: ")DRW_dbg::dbg(" reserved: "); DRW_DBG(gradReserved)DRW_dbg::dbg(gradReserved);
6806 gradAngle = buf->getBitDouble();
6807 DRW_DBG(" Gradient angle: ")DRW_dbg::dbg(" Gradient angle: "); DRW_DBG(gradAngle)DRW_dbg::dbg(gradAngle);
6808 gradShift = buf->getBitDouble();
6809 DRW_DBG(" Gradient shift: ")DRW_dbg::dbg(" Gradient shift: "); DRW_DBG(gradShift)DRW_dbg::dbg(gradShift);
6810 singleColor = buf->getBitLong();
6811 DRW_DBG("\nsingle color Grad: ")DRW_dbg::dbg("\nsingle color Grad: "); DRW_DBG(singleColor)DRW_dbg::dbg(singleColor);
6812 gradTint = buf->getBitDouble();
6813 DRW_DBG(" Gradient tint: ")DRW_dbg::dbg(" Gradient tint: "); DRW_DBG(gradTint)DRW_dbg::dbg(gradTint);
6814 std::int32_t numCol = buf->getBitLong();
6815 DRW_DBG(" num colors: ")DRW_dbg::dbg(" num colors: "); DRW_DBG(numCol)DRW_dbg::dbg(numCol);
6816 if (numCol > 0)
6817 DRW::reserve(gradColors, numCol);
6818 for (std::int32_t i = 0 ; i < numCol; ++i){
6819 GradientStop stop;
6820 // First field is the stop position (per libreDWG: BD/unkDouble holds
6821 // the stop value in [0,1]); falls back to even spacing if missing.
6822 stop.value = buf->getBitDouble();
6823 DRW_DBG("\nstop value: ")DRW_dbg::dbg("\nstop value: "); DRW_DBG(stop.value)DRW_dbg::dbg(stop.value);
6824 std::uint16_t unkShort = buf->getBitShort();
6825 DRW_DBG(" unkShort: ")DRW_dbg::dbg(" unkShort: "); DRW_DBG(unkShort)DRW_dbg::dbg(unkShort);
6826 stop.rgb = buf->getBitLong();
6827 DRW_DBG(" rgb color: ")DRW_dbg::dbg(" rgb color: "); DRW_DBG(stop.rgb)DRW_dbg::dbg(stop.rgb);
6828 std::uint8_t ignCol = buf->getRawChar8();
6829 DRW_DBG(" ignored color: ")DRW_dbg::dbg(" ignored color: "); DRW_DBG(ignCol)DRW_dbg::dbg(ignCol);
6830 gradColors.push_back(stop);
6831 }
6832 gradName = sBuf->getVariableText(version, false);
6833 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");
6834 }
6835 basePoint.z = buf->getBitDouble();
6836 extPoint = buf->get3BitDouble();
6837 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);
6838 DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
6839 name = sBuf->getVariableText(version, false);
6840 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");
6841 solid = buf->getBit();
6842 associative = buf->getBit();
6843 if (!parseDwgBoundaryData(version, buf, totalBoundItems, havePixelSize))
6844 return false;
6845
6846 hstyle = buf->getBitShort();
6847 hpattern = buf->getBitShort();
6848 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);
6849 if (!solid){
6850 angle = buf->getBitDouble();
6851 scale = buf->getBitDouble();
6852 doubleflag = buf->getBit();
6853 deflines = buf->getBitShort();
6854 for (std::int32_t i = 0 ; i < deflines; ++i){
6855 DRW_Coord ptL, offL;
6856 double angleL = buf->getBitDouble();
6857 ptL.x = buf->getBitDouble();
6858 ptL.y = buf->getBitDouble();
6859 offL.x = buf->getBitDouble();
6860 offL.y = buf->getBitDouble();
6861 std::uint16_t numDashL = buf->getBitShort();
6862 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);
6863 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);
6864 for (std::uint16_t i = 0 ; i < numDashL; ++i){
6865 double lengthL = buf->getBitDouble();
6866 DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(lengthL)DRW_dbg::dbg(lengthL);
6867 }
6868 }//end deflines
6869 } //end not solid
6870
6871 if (havePixelSize){
6872 double pixsize = buf->getBitDouble();
6873 DRW_DBG("\npixel size: ")DRW_dbg::dbg("\npixel size: "); DRW_DBG(pixsize)DRW_dbg::dbg(pixsize);
6874 }
6875 std::int32_t numSeedPoints = buf->getBitLong();
6876 DRW_DBG("\nnum Seed Points ")DRW_dbg::dbg("\nnum Seed Points "); DRW_DBG(numSeedPoints)DRW_dbg::dbg(numSeedPoints);
6877 if (numSeedPoints > 0)
6878 DRW::reserve(seedPoints, numSeedPoints);
6879 for (std::int32_t i = 0 ; i < numSeedPoints; ++i){
6880 DRW_Coord seedPt;
6881 seedPt.x = buf->getRawDouble();
6882 seedPt.y = buf->getRawDouble();
6883 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);
6884 seedPoints.push_back(seedPt);
6885 }
6886
6887 DRW_DBG("\n")DRW_dbg::dbg("\n");
6888 ret = DRW_Entity::parseDwgEntHandle(version, buf);
6889 if (!ret)
6890 return ret;
6891 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");
6892
6893 for (std::uint32_t i = 0 ; i < totalBoundItems; ++i){
6894 dwgHandle biH = buf->getHandle();
6895 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);
6896 }
6897 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");
6898// RS crc; //RS */
6899 return buf->isGood();
6900}
6901
6902void DRW_Hatch::encodeDwgGradientData(DRW::Version version, dwgBufferW *buf,
6903 dwgBufferW *strBuf) const {
6904 if (version <= DRW::AC1015)
7
Assuming 'version' is > AC1015
6905 return;
6906
6907 dwgBufferW *sb = strBuf ? strBuf : buf;
8
Taking false branch
9
Assuming 'strBuf' is null
10
'?' condition is false
6908 buf->putBitLong(isGradient);
11
Called C++ object pointer is null
6909 buf->putBitLong(gradReserved);
6910 buf->putBitDouble(gradAngle);
6911 buf->putBitDouble(gradShift);
6912 buf->putBitLong(singleColor);
6913 buf->putBitDouble(gradTint);
6914 buf->putBitLong(static_cast<std::int32_t>(gradColors.size()));
6915 for (const GradientStop& stop : gradColors) {
6916 buf->putBitDouble(stop.value);
6917 buf->putBitShort(static_cast<std::uint16_t>(stop.aciColor));
6918 buf->putBitLong(static_cast<std::uint32_t>(stop.rgb));
6919 buf->putRawChar8(0);
6920 }
6921 sb->putVariableText(version, gradName);
6922}
6923
6924bool DRW_Hatch::encodeDwgBoundaryData(DRW::Version version, dwgBufferW *buf) const {
6925 buf->putBitLong(static_cast<std::int32_t>(looplist.size()));
6926
6927 for (const auto& lp : looplist) {
6928 // Strip bit 4 (pixel-size flag): DRW_Hatch has no storage for the
6929 // associated pixelSize BD, so a reader would desync if the flag were
6930 // set and we then omitted the field.
6931 buf->putBitLong(lp->type & ~4);
6932
6933 if (!(lp->type & 2)) {
6934 buf->putBitLong(static_cast<std::int32_t>(lp->objlist.size()));
6935 for (const auto& seg : lp->objlist) {
6936 if (const auto* ln = dynamic_cast<const DRW_Line*>(seg.get())) {
6937 buf->putRawChar8(1); // line
6938 buf->put2RawDouble(ln->basePoint);
6939 buf->put2RawDouble(ln->secPoint);
6940 } else if (const auto* arc = dynamic_cast<const DRW_Arc*>(seg.get())) {
6941 buf->putRawChar8(2); // circular arc
6942 buf->put2RawDouble(arc->basePoint);
6943 buf->putBitDouble(arc->radious);
6944 buf->putBitDouble(arc->staangle);
6945 buf->putBitDouble(arc->endangle);
6946 buf->putBit(static_cast<std::uint8_t>(arc->isccw));
6947 } else if (const auto* el = dynamic_cast<const DRW_Ellipse*>(seg.get())) {
6948 buf->putRawChar8(3); // ellipse arc
6949 buf->put2RawDouble(el->basePoint);
6950 buf->put2RawDouble(el->secPoint);
6951 buf->putBitDouble(el->ratio);
6952 buf->putBitDouble(el->staparam);
6953 buf->putBitDouble(el->endparam);
6954 buf->putBit(static_cast<std::uint8_t>(el->isccw));
6955 } else if (const auto* sp = dynamic_cast<const DRW_Spline*>(seg.get())) {
6956 buf->putRawChar8(4); // spline
6957 buf->putBitLong(sp->degree);
6958 bool isRational = (sp->flags & 4) != 0;
6959 bool isPeriodic = (sp->flags & 2) != 0;
6960 buf->putBit(static_cast<std::uint8_t>(isRational));
6961 buf->putBit(static_cast<std::uint8_t>(isPeriodic));
6962 buf->putBitLong(static_cast<std::int32_t>(sp->knotslist.size()));
6963 buf->putBitLong(static_cast<std::int32_t>(sp->controllist.size()));
6964 for (double k : sp->knotslist)
6965 buf->putBitDouble(k);
6966 for (const auto& cp : sp->controllist) {
6967 DRW_Coord c2{cp->x, cp->y, 0.0};
6968 buf->put2RawDouble(c2);
6969 if (isRational)
6970 buf->putBitDouble(cp->z);
6971 }
6972 if (version > DRW::AC1021) {
6973 buf->putBitLong(static_cast<std::int32_t>(sp->fitlist.size()));
6974 for (const auto& fp : sp->fitlist) {
6975 DRW_Coord f2{fp->x, fp->y, 0.0};
6976 buf->put2RawDouble(f2);
6977 }
6978 buf->put2RawDouble(sp->tgStart);
6979 buf->put2RawDouble(sp->tgEnd);
6980 }
6981 } else {
6982 return false;
6983 }
6984 }
6985 } else {
6986 const DRW_LWPolyline* pl = nullptr;
6987 if (!lp->objlist.empty())
6988 pl = dynamic_cast<const DRW_LWPolyline*>(lp->objlist[0].get());
6989 if (!pl)
6990 return false;
6991
6992 bool asBulge = false;
6993 for (const auto& v : pl->vertlist)
6994 if (v->bulge != 0.0) { asBulge = true; break; }
6995
6996 buf->putBit(static_cast<std::uint8_t>(asBulge));
6997 buf->putBit(static_cast<std::uint8_t>(pl->flags & 1));
6998 buf->putBitLong(static_cast<std::int32_t>(pl->vertlist.size()));
6999 for (const auto& v : pl->vertlist) {
7000 buf->putRawDouble(v->x);
7001 buf->putRawDouble(v->y);
7002 if (asBulge)
7003 buf->putBitDouble(v->bulge);
7004 }
7005 }
7006
7007 buf->putBitLong(0); // numBoundHandles for this loop (0 = non-associative)
7008 }
7009
7010 return true;
7011}
7012
7013bool DRW_Hatch::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7014 (void)bs;
7015 oType = 78; // HATCH class id — see dwgreader.cpp:1380
7016 if (!encodeDwgCommon(version, buf)) return false;
1
Assuming the condition is false
7017
7018 dwgBufferW *sb = strBuf ? strBuf : buf;
2
Taking false branch
3
Assuming 'strBuf' is null
4
'?' condition is false
7019 encodeDwgGradientData(version, buf, sb);
5
Passing 'sb' via 2nd parameter 'buf'
6
Calling 'DRW_Hatch::encodeDwgGradientData'
7020
7021 buf->putBitDouble(basePoint.z); // BD: elevation
7022 buf->put3BitDouble(extPoint); // 3BD: extrusion (NOT BE-style for HATCH)
7023 sb->putVariableText(version, name); // TV: hatch pattern name
7024 buf->putBit(static_cast<std::uint8_t>(solid));
7025 buf->putBit(static_cast<std::uint8_t>(associative));
7026 if (!encodeDwgBoundaryData(version, buf)) return false;
7027
7028 buf->putBitShort(static_cast<std::uint16_t>(hstyle));
7029 buf->putBitShort(static_cast<std::uint16_t>(hpattern));
7030
7031 if (!solid) {
7032 buf->putBitDouble(angle);
7033 buf->putBitDouble(scale);
7034 buf->putBit(static_cast<std::uint8_t>(doubleflag));
7035 // Pattern definition lines: the parseDwg reads them but DRW_Hatch
7036 // has no storage for per-line data, so emit 0 here.
7037 buf->putBitShort(0); // deflines = 0
7038 }
7039
7040 // pixelSize BD omitted: bit 4 is stripped from every emitted loop type
7041 // above (DRW_Hatch has no pixelSize storage), so havePixelSize is always
7042 // false on the read side and parseDwg never expects this field.
7043
7044 buf->putBitLong(static_cast<std::int32_t>(seedPoints.size()));
7045 for (const auto& sp : seedPoints) {
7046 buf->putRawDouble(sp.x);
7047 buf->putRawDouble(sp.y);
7048 }
7049
7050 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
7051 return true;
7052}
7053
7054bool DRW_Spline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7055 switch (code) {
7056 case 210:
7057 normalVec.x = reader->getDouble();
7058 break;
7059 case 220:
7060 normalVec.y = reader->getDouble();
7061 break;
7062 case 230:
7063 normalVec.z = reader->getDouble();
7064 break;
7065 case 12:
7066 tgStart.x = reader->getDouble();
7067 break;
7068 case 22:
7069 tgStart.y = reader->getDouble();
7070 break;
7071 case 32:
7072 tgStart.z = reader->getDouble();
7073 break;
7074 case 13:
7075 tgEnd.x = reader->getDouble();
7076 break;
7077 case 23:
7078 tgEnd.y = reader->getDouble();
7079 break;
7080 case 33:
7081 tgEnd.z = reader->getDouble();
7082 break;
7083 case 70:
7084 flags = reader->getInt32();
7085 break;
7086 case 71:
7087 degree = reader->getInt32();
7088 break;
7089 case 72:
7090 nknots = reader->getInt32();
7091 break;
7092 case 73:
7093 ncontrol = reader->getInt32();
7094 break;
7095 case 74:
7096 nfit = reader->getInt32();
7097 break;
7098 case 42:
7099 tolknot = reader->getDouble();
7100 break;
7101 case 43:
7102 tolcontrol = reader->getDouble();
7103 break;
7104 case 44:
7105 tolfit = reader->getDouble();
7106 break;
7107 case 10: {
7108 controlpoint = std::make_shared<DRW_Coord>();
7109 controllist.push_back(controlpoint);
7110 controlpoint->x = reader->getDouble();
7111 break; }
7112 case 20:
7113 if(controlpoint)
7114 controlpoint->y = reader->getDouble();
7115 break;
7116 case 30:
7117 if(controlpoint)
7118 controlpoint->z = reader->getDouble();
7119 break;
7120 case 11: {
7121 fitpoint = std::make_shared<DRW_Coord>();
7122 fitlist.push_back(fitpoint);
7123 fitpoint->x = reader->getDouble();
7124 break; }
7125 case 21:
7126 if(fitpoint)
7127 fitpoint->y = reader->getDouble();
7128 break;
7129 case 31:
7130 if(fitpoint)
7131 fitpoint->z = reader->getDouble();
7132 break;
7133 case 40:
7134 knotslist.push_back(reader->getDouble());
7135 break;
7136 case 41:
7137 weightlist.push_back(reader->getDouble());
7138 break;
7139 default:
7140 return DRW_Entity::parseCode(code, reader);
7141 }
7142
7143 return true;
7144}
7145
7146bool DRW_Helix::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7147 if (code == 100) {
7148 const std::string subclass = reader->getString();
7149 m_parsingHelixSubclass = (subclass == "AcDbHelix");
7150 return true;
7151 }
7152
7153 if (!m_parsingHelixSubclass)
7154 return DRW_Spline::parseCode(code, reader);
7155
7156 switch (code) {
7157 case 90:
7158 m_majorVersion = reader->getInt32();
7159 break;
7160 case 91:
7161 m_maintVersion = reader->getInt32();
7162 break;
7163 case 10:
7164 axisBasePt.x = reader->getDouble();
7165 break;
7166 case 20:
7167 axisBasePt.y = reader->getDouble();
7168 break;
7169 case 30:
7170 axisBasePt.z = reader->getDouble();
7171 break;
7172 case 11:
7173 startPt.x = reader->getDouble();
7174 break;
7175 case 21:
7176 startPt.y = reader->getDouble();
7177 break;
7178 case 31:
7179 startPt.z = reader->getDouble();
7180 break;
7181 case 12:
7182 axisVector.x = reader->getDouble();
7183 break;
7184 case 22:
7185 axisVector.y = reader->getDouble();
7186 break;
7187 case 32:
7188 axisVector.z = reader->getDouble();
7189 break;
7190 case 40:
7191 radius = reader->getDouble();
7192 break;
7193 case 41:
7194 turns = reader->getDouble();
7195 break;
7196 case 42:
7197 turnHeight = reader->getDouble();
7198 break;
7199 case 290:
7200 handedness = reader->getInt32() != 0;
7201 break;
7202 case 280:
7203 constraintType = static_cast<std::uint8_t>(reader->getInt32() & 0xff);
7204 break;
7205 default:
7206 return DRW_Entity::parseCode(code, reader);
7207 }
7208
7209 return true;
7210}
7211
7212bool DRW_Spline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
7213 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
7214 if (!ret)
7215 return ret;
7216 if (!parseDwgSplineBody(version, buf))
7217 return false;
7218 /* Common Entity Handle Data */
7219 ret = DRW_Entity::parseDwgEntHandle(version, buf);
7220 if (!ret)
7221 return ret;
7222// RS crc; //RS */
7223 return buf->isGood();
7224}
7225
7226// Spline body decode: the scenario/degree/knots/ctrl/fit section, WITHOUT
7227// the leading DRW_Entity::parseDwg(common) or the trailing parseDwgEntHandle.
7228// Factored out so DRW_Helix can reuse the identical spline payload before its
7229// AcDbHelix trailer (Phase 8a-1).
7230bool DRW_Spline::parseDwgSplineBody(DRW::Version version, dwgBuffer *buf){
7231 DRW_DBG("\n***************************** parsing spline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing spline *********************************************\n"
)
;
7232 std::uint8_t weight = 0; // RLZ ??? flags, weight, code 70, bit 4 (16)
7233
7234 std::int32_t scenario = buf->getBitLong();
7235 m_scenario = scenario;
7236 DRW_DBG("scenario: ")DRW_dbg::dbg("scenario: "); DRW_DBG(scenario)DRW_dbg::dbg(scenario);
7237 if (version > DRW::AC1024) {
7238 std::int32_t splFlag1 = buf->getBitLong();
7239 m_splineFlags1 = splFlag1;
7240 std::int32_t knotParam = buf->getBitLong();
7241 m_knotParam = knotParam;
7242 if (knotParam == kSplineKnotParamCustom || !(splFlag1 & kSplineFlagUseKnotParameter)) {
7243 scenario = 1;
7244 } else if (splFlag1 & kSplineFlagMethodFitPoints) {
7245 scenario = 2;
7246 }
7247 m_scenario = scenario;
7248 DRW_DBG(" 2013 splFlag1: ")DRW_dbg::dbg(" 2013 splFlag1: "); DRW_DBG(splFlag1)DRW_dbg::dbg(splFlag1);
7249 DRW_DBG(" 2013 knotParam: ")DRW_dbg::dbg(" 2013 knotParam: "); DRW_DBG(knotParam)DRW_dbg::dbg(knotParam);
7250// DRW_DBG("unk bit: "); DRW_DBG(buf->getBit());
7251 }
7252 degree = buf->getBitLong(); //RLZ: code 71, verify with dxf
7253 DRW_DBG(" degree: ")DRW_dbg::dbg(" degree: "); DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("\n")DRW_dbg::dbg("\n");
7254 if (!isValidSplineDegree(degree)) {
7255 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");
7256 return false;
7257 }
7258 if (scenario == 2) {
7259 flags = 8;//scenario 2 = not rational & planar
7260 if (m_splineFlags1 & kSplineFlagClosed)
7261 flags |= 1;
7262 tolfit = buf->getBitDouble();//BD
7263 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);
7264 tgStart =buf->get3BitDouble();
7265 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);
7266 tgEnd =buf->get3BitDouble();
7267 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);
7268 nfit = buf->getBitLong();
7269 if (!isValidFitSplineLayout(degree, nfit)) {
7270 DRW_DBG("\ndwg Spline, invalid fit layout degree/count: ")DRW_dbg::dbg("\ndwg Spline, invalid fit layout degree/count: "
)
;
7271 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");
7272 return false;
7273 }
7274 DRW_DBG("\nnumber of fit points: ")DRW_dbg::dbg("\nnumber of fit points: "); DRW_DBG(nfit)DRW_dbg::dbg(nfit);
7275 } else if (scenario == 1) {
7276 flags = 8;//scenario 1 = rational & planar
7277 flags |= buf->getBit() << 2; //flags, rational, code 70, bit 2 (4)
7278 flags |= buf->getBit(); //flags, closed, code 70, bit 0 (1)
7279 flags |= buf->getBit() << 1; //flags, periodic, code 70, bit 1 (2)
7280 tolknot = buf->getBitDouble();
7281 tolcontrol = buf->getBitDouble();
7282 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);
7283 DRW_DBG(" control point tolerance: ")DRW_dbg::dbg(" control point tolerance: "); DRW_DBG(tolcontrol)DRW_dbg::dbg(tolcontrol);
7284 nknots = buf->getBitLong();
7285 ncontrol = buf->getBitLong();
7286 if (!isValidControlSplineLayout(degree, nknots, ncontrol)) {
7287 DRW_DBG("\ndwg Spline, invalid control layout degree/knots/control: ")DRW_dbg::dbg("\ndwg Spline, invalid control layout degree/knots/control: "
)
;
7288 DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("/")DRW_dbg::dbg("/"); DRW_DBG(nknots)DRW_dbg::dbg(nknots); DRW_DBG("/")DRW_dbg::dbg("/");
7289 DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG("\n")DRW_dbg::dbg("\n");
7290 return false;
7291 }
7292 weight = buf->getBit(); // flags bit 4: weights present (code 70)
7293 if (weight) flags |= 0x10;
7294 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: ");
7295 DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG(" weight bit: ")DRW_dbg::dbg(" weight bit: "); DRW_DBG(weight)DRW_dbg::dbg(weight);
7296 } else {
7297 DRW_DBG("\ndwg Spline, unknown scenario ")DRW_dbg::dbg("\ndwg Spline, unknown scenario "); DRW_DBG(scenario)DRW_dbg::dbg(scenario);
7298 DRW_DBG(" (expected 1 or 2)\n")DRW_dbg::dbg(" (expected 1 or 2)\n");
7299 return false; //RLZ: from doc only 1 or 2 are ok ?
7300 }
7301
7302 if (!DRW::reserve( knotslist, nknots)) {
7303 return false;
7304 }
7305 for (std::int32_t i= 0; i<nknots; ++i){
7306 knotslist.push_back (buf->getBitDouble());
7307 }
7308 if (!DRW::reserve( controllist, ncontrol)) {
7309 return false;
7310 }
7311 if (weight && !DRW::reserve(weightlist, ncontrol)) {
7312 return false;
7313 }
7314 for (std::int32_t i= 0; i<ncontrol; ++i){
7315 controllist.push_back(std::make_shared<DRW_Coord>(buf->get3BitDouble()));
7316 if (weight) {
7317 //per-control-point weight; required for hyperbola/parabola
7318 //conic detection in consumers (e.g. LibreCAD addSpline)
7319 double w = buf->getBitDouble(); //RLZ Warning: D (BD or RD)
7320 weightlist.push_back(w);
7321 DRW_DBG("\n w: ")DRW_dbg::dbg("\n w: "); DRW_DBG(w)DRW_dbg::dbg(w);
7322 }
7323 }
7324 if (!DRW::reserve( fitlist, nfit)) {
7325 return false;
7326 }
7327 for (std::int32_t i= 0; i<nfit; ++i)
7328 fitlist.push_back(std::make_shared<DRW_Coord>(buf->get3BitDouble()));
7329
7330 if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug) {
7331 DRW_DBG("\nknots list: ")DRW_dbg::dbg("\nknots list: ");
7332 for (auto const& v: knotslist) {
7333 DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBG(v)DRW_dbg::dbg(v);
7334 }
7335 DRW_DBG("\ncontrol point list: ")DRW_dbg::dbg("\ncontrol point list: ");
7336 for (auto const& v: controllist) {
7337 DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z);
7338 }
7339 DRW_DBG("\nfit point list: ")DRW_dbg::dbg("\nfit point list: ");
7340 for (auto const& v: fitlist) {
7341 DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z);
7342 }
7343 }
7344
7345 return buf->isGood();
7346}
7347
7348// AcDbHelix trailer order (libreDWG dwg2.spec:2493-2503):
7349// major_version BL, maint_version BL, axis_base_pt 3BD, start_pt 3BD,
7350// axis_vector 3BD, radius BD, turns BD, turn_height BD, handedness B,
7351// constraint_type RC.
7352bool DRW_Helix::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
7353 bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs);
7354 if (!ret)
7355 return ret;
7356 DRW_DBG("\n***************************** parsing helix *********************************************\n")DRW_dbg::dbg("\n***************************** parsing helix *********************************************\n"
)
;
7357 if (!parseDwgSplineBody(version, buf))
7358 return false;
7359
7360 // AcDbHelix trailer (see field order above).
7361 m_majorVersion = buf->getBitLong();
7362 m_maintVersion = buf->getBitLong();
7363 axisBasePt = buf->get3BitDouble();
7364 startPt = buf->get3BitDouble();
7365 axisVector = buf->get3BitDouble();
7366 radius = buf->getBitDouble();
7367 turns = buf->getBitDouble();
7368 turnHeight = buf->getBitDouble();
7369 handedness = buf->getBit() != 0;
7370 constraintType = buf->getRawChar8();
7371 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);
7372
7373 /* Common Entity Handle Data */
7374 ret = DRW_Entity::parseDwgEntHandle(version, buf);
7375 if (!ret)
7376 return ret;
7377 // RS crc; //RS */
7378 return buf->isGood();
7379}
7380
7381bool DRW_Image::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7382 switch (code) {
7383 case 12:
7384 vVector.x = reader->getDouble();
7385 break;
7386 case 22:
7387 vVector.y = reader->getDouble();
7388 break;
7389 case 32:
7390 vVector.z = reader->getDouble();
7391 break;
7392 case 13:
7393 sizeu = reader->getDouble();
7394 break;
7395 case 23:
7396 sizev = reader->getDouble();
7397 break;
7398 case 70:
7399 m_displayProps = reader->getInt32();
7400 break;
7401 case 340:
7402 ref = reader->getHandleString();
7403 break;
7404 case 360:
7405 m_imageDefReactorHandle = reader->getHandleString();
7406 break;
7407 case 280:
7408 clip = reader->getInt32();
7409 break;
7410 case 281:
7411 brightness = reader->getInt32();
7412 break;
7413 case 282:
7414 contrast = reader->getInt32();
7415 break;
7416 case 283:
7417 fade = reader->getInt32();
7418 break;
7419 case 71:
7420 m_clipBoundaryType = reader->getInt32();
7421 break;
7422 case 91:
7423 // The declared count is a structural invariant: reject negative or
7424 // implausibly large values before reserve() can allocate unboundedly.
7425 {
7426 constexpr std::int32_t kMaxClipVertices = 100000;
7427 const std::int32_t count = reader->getInt32();
7428 if (count < 0 || count > kMaxClipVertices)
7429 return false;
7430 clipPath.clear();
7431 clipPath.reserve(static_cast<size_t>(count));
7432 m_declaredClipVertexCount = count;
7433 m_clipPathHasOpenVertex = false;
7434 }
7435 break;
7436 case 14:
7437 // WIPEOUT polygon vertex x — start a new vertex. Group 24 (y) follows.
7438 if (m_clipPathHasOpenVertex)
7439 return false;
7440 clipPath.emplace_back(reader->getDouble(), 0.0);
7441 m_clipPathHasOpenVertex = true;
7442 break;
7443 case 24:
7444 // WIPEOUT polygon vertex y — complete the most recently started vertex.
7445 if (!m_clipPathHasOpenVertex || clipPath.empty())
7446 return false;
7447 clipPath.back().y = reader->getDouble();
7448 m_clipPathHasOpenVertex = false;
7449 break;
7450 case 290:
7451 // R2010+ Clip mode (IMAGE/WIPEOUT, ODA spec §20.4.80):
7452 // 0 = mask outside the polygon, 1 = mask inside.
7453 clipMode = reader->getBool();
7454 break;
7455 default:
7456 return DRW_Line::parseCode(code, reader);
7457 }
7458
7459 return true;
7460}
7461
7462bool DRW_Image::hasValidClipBoundary() const {
7463 if (m_clipPathHasOpenVertex
7464 || (m_declaredClipVertexCount >= 0
7465 && static_cast<std::size_t>(m_declaredClipVertexCount) != clipPath.size())) {
7466 return false;
7467 }
7468 switch (m_clipBoundaryType) {
7469 case 0:
7470 return clipPath.empty();
7471 case 1:
7472 return clipPath.size() == 2;
7473 case 2:
7474 return clipPath.size() >= 3;
7475 default:
7476 return false;
7477 }
7478}
7479
7480bool DRW_Image::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
7481 dwgBuffer sBuff = *buf;
7482 dwgBuffer *sBuf = buf;
7483 if (version > DRW::AC1018) {//2007+
7484 sBuf = &sBuff; //separate buffer for strings
7485 }
7486 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
7487 if (!ret)
7488 return ret;
7489 DRW_DBG("\n***************************** parsing image *********************************************\n")DRW_dbg::dbg("\n***************************** parsing image *********************************************\n"
)
;
7490
7491 std::int32_t classVersion = buf->getBitLong();
7492 DRW_DBG("class Version: ")DRW_dbg::dbg("class Version: "); DRW_DBG(classVersion)DRW_dbg::dbg(classVersion);
7493 basePoint = buf->get3BitDouble();
7494 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);
7495 secPoint = buf->get3BitDouble();
7496 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);
7497 vVector = buf->get3BitDouble();
7498 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);
7499 sizeu = buf->getRawDouble();
7500 sizev = buf->getRawDouble();
7501 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);
7502 m_displayProps = buf->getBitShort();
7503 DRW_DBG("\ndisplay props: ")DRW_dbg::dbg("\ndisplay props: "); DRW_DBG(m_displayProps)DRW_dbg::dbg(m_displayProps);
7504 clip = buf->getBit();
7505 brightness = buf->getRawChar8();
7506 contrast = buf->getRawChar8();
7507 fade = buf->getRawChar8();
7508 if (version > DRW::AC1021){ //2010+
7509 clipMode = buf->getBit() != 0; // ODA §20.4.80: Clip mode B (R2010+)
7510 }
7511 m_clipBoundaryType = buf->getBitShort();
7512 clipPath.clear();
7513 if (m_clipBoundaryType == 0) {
7514 // No clip boundary payload.
7515 } else if (m_clipBoundaryType == 1){
7516 // Rectangles are encoded as exactly two opposite corners. Keep that
7517 // canonical payload intact; rendering expands it independently.
7518 DRW_Coord ll = buf->get2RawDouble();
7519 DRW_Coord ur = buf->get2RawDouble();
7520 clipPath.push_back(ll);
7521 clipPath.push_back(ur);
7522 m_declaredClipVertexCount = 2;
7523 } else if (m_clipBoundaryType == 2) {
7524 std::int32_t numVerts = buf->getBitLong();
7525 if (numVerts < 0 || numVerts > 100000)
7526 return false;
7527 clipPath.reserve(numVerts);
7528 for (int i= 0; i< numVerts;++i)
7529 clipPath.push_back(buf->get2RawDouble());
7530 m_declaredClipVertexCount = numVerts;
7531 } else {
7532 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");
7533 return false;
7534 }
7535
7536 ret = DRW_Entity::parseDwgEntHandle(version, buf);
7537 if (!ret)
7538 return ret;
7539 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");
7540
7541 dwgHandle biH = buf->getHandle();
7542 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);
7543 ref = biH.ref;
7544 biH = buf->getHandle();
7545 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);
7546 m_imageDefReactorHandle = biH.ref;
7547 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");
7548// RS crc; //RS */
7549 return buf->isGood();
7550}
7551
7552// DRW_Image::encodeDwg — inverse of DRW_Image::parseDwg above (libreDWG
7553// dwg.spec:5533-5563). Body field order: BL class_version (0), 3 x 3BD
7554// (base/uvec/vvec), 2 x RD (sizeu/sizev), BS display_props, B clip,
7555// 3 x RC (brightness/contrast/fade), [R2010+ B clip_mode], BS
7556// clip_boundary_type + verts. Both handles (imagedef code 5 + reactor
7557// code 3) are emitted UNCONDITIONALLY at the END of the handle stream,
7558// matching parseDwg's order — NOT the spec's interleaved mid-stream slots.
7559bool DRW_Image::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7560 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7561 (void)bs; (void)strBuf;
7562 constexpr std::size_t kMaxClipVerts = 100000u;
7563 if (clipPath.size() > kMaxClipVerts) {
7564 DRW_DBG("IMAGE clip vertices exceed DWG limit\n")DRW_dbg::dbg("IMAGE clip vertices exceed DWG limit\n");
7565 return false;
7566 }
7567 // Callers sometimes populate clipPath without setting m_clipBoundaryType
7568 // (DXF import historically stored only the vertices). Infer a coherent type
7569 // so encode does not reject a well-formed polygon/rectangle path.
7570 if (m_clipBoundaryType == 0 && !clipPath.empty()) {
7571 if (clipPath.size() == 2)
7572 m_clipBoundaryType = 1;
7573 else if (clipPath.size() >= 3)
7574 m_clipBoundaryType = 2;
7575 }
7576 oType = 101; // IMAGE class id — see dwgreader.cpp case 101
7577 if (!encodeDwgCommon(version, buf)) return false;
7578
7579 buf->putBitLong(0); // class_version (reader discards; ODA emits 0)
7580 buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z);
7581 buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z); // uvec
7582 buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z);
7583 buf->putRawDouble(sizeu);
7584 buf->putRawDouble(sizev);
7585 buf->putBitShort(static_cast<std::uint16_t>(m_displayProps));
7586 buf->putBit(static_cast<std::uint8_t>(clip & 1));
7587 buf->putRawChar8(static_cast<std::uint8_t>(brightness));
7588 buf->putRawChar8(static_cast<std::uint8_t>(contrast));
7589 buf->putRawChar8(static_cast<std::uint8_t>(fade));
7590 if (version > DRW::AC1021) { // 2010+ clip mode
7591 buf->putBit(clipMode ? 1 : 0);
7592 }
7593 if (!hasValidClipBoundary()) {
7594 DRW_DBG("IMAGE has invalid clip boundary\n")DRW_dbg::dbg("IMAGE has invalid clip boundary\n");
7595 return false;
7596 }
7597 if (m_clipBoundaryType == 0) {
7598 buf->putBitShort(0); // clip_boundary_type 0 = none
7599 } else if (m_clipBoundaryType == 1) {
7600 buf->putBitShort(1);
7601 buf->put2RawDouble(clipPath[0]);
7602 buf->put2RawDouble(clipPath[1]);
7603 } else {
7604 buf->putBitShort(2);
7605 buf->putBitLong(static_cast<std::int32_t>(clipPath.size()));
7606 for (std::size_t i = 0; i < clipPath.size(); ++i)
7607 buf->put2RawDouble(clipPath[i]);
7608 }
7609
7610 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
7611
7612 // Emit both trailing handles UNCONDITIONALLY in parseDwg order:
7613 // imagedef (hard pointer, code 5) then imagedefreactor (hard owner, code 3).
7614 dwgBufferW *hb = handleBuf ? handleBuf : buf;
7615 auto makeHandle = [](std::uint8_t code, std::uint32_t r) {
7616 dwgHandle h;
7617 h.code = (r == 0) ? 0 : code;
7618 h.ref = r;
7619 h.size = 0;
7620 if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } }
7621 return h;
7622 };
7623 hb->putHandle(makeHandle(5, ref)); // imagedef (340)
7624 hb->putHandle(makeHandle(3, m_imageDefReactorHandle)); // imagedefreactor (360)
7625 return true;
7626}
7627
7628bool DRW_Wipeout::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7629 return DRW_Image::parseCode(code, reader);
7630}
7631
7632bool DRW_Wipeout::hasValidBoundary() const {
7633 return m_clipBoundaryType != 0 && hasValidClipBoundary();
7634}
7635
7636bool DRW_Wipeout::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7637 return DRW_Image::parseDwg(version, buf, bs) && hasValidBoundary();
7638}
7639
7640bool DRW_Wipeout::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7641 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7642 (void)bs; (void)strBuf;
7643 constexpr std::size_t kMaxClipVerts = 100000u;
7644 if (clipPath.size() > kMaxClipVerts) {
7645 DRW_DBG("WIPEOUT clip vertices exceed DWG limit\n")DRW_dbg::dbg("WIPEOUT clip vertices exceed DWG limit\n");
7646 return false;
7647 }
7648 if (!hasValidBoundary()) {
7649 DRW_DBG("WIPEOUT has invalid clip boundary\n")DRW_dbg::dbg("WIPEOUT has invalid clip boundary\n");
7650 return false;
7651 }
7652 oType = kDwgClassNum;
7653 if (!encodeDwgCommon(version, buf)) return false;
7654
7655 buf->putBitLong(0);
7656 buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z);
7657 buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z);
7658 buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z);
7659 buf->putRawDouble(sizeu);
7660 buf->putRawDouble(sizev);
7661 buf->putBitShort(static_cast<std::uint16_t>(m_displayProps));
7662 buf->putBit(static_cast<std::uint8_t>(clip & 1));
7663 buf->putRawChar8(static_cast<std::uint8_t>(brightness));
7664 buf->putRawChar8(static_cast<std::uint8_t>(contrast));
7665 buf->putRawChar8(static_cast<std::uint8_t>(fade));
7666 if (version > DRW::AC1021) {
7667 buf->putBit(clipMode ? 1 : 0);
7668 }
7669 if (m_clipBoundaryType == 1) {
7670 buf->putBitShort(1);
7671 buf->put2RawDouble(clipPath[0]);
7672 buf->put2RawDouble(clipPath[1]);
7673 } else {
7674 buf->putBitShort(2);
7675 buf->putBitLong(static_cast<std::int32_t>(clipPath.size()));
7676 for (std::size_t i = 0; i < clipPath.size(); ++i)
7677 buf->put2RawDouble(clipPath[i]);
7678 }
7679
7680 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
7681
7682 dwgBufferW *hb = handleBuf ? handleBuf : buf;
7683 auto makeHandle = [](std::uint8_t code, std::uint32_t r) {
7684 dwgHandle h;
7685 h.code = (r == 0) ? 0 : code;
7686 h.ref = r;
7687 h.size = 0;
7688 if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } }
7689 return h;
7690 };
7691 hb->putHandle(makeHandle(5, ref));
7692 hb->putHandle(makeHandle(3, m_imageDefReactorHandle));
7693 return true;
7694}
7695
7696bool DRW_PointCloud::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7697 switch (code) {
7698 case 90: classVersion = reader->getInt32(); break;
7699 case 10: origin.x = reader->getDouble(); break;
7700 case 20: origin.y = reader->getDouble(); break;
7701 case 30: origin.z = reader->getDouble(); break;
7702 case 1: savedFilename = reader->getUtf8String(); break;
7703 case 91: sourceFileCount = reader->getInt32(); break;
7704 case 101:
7705 sourceFiles.clear();
7706 sourceFiles.reserve(static_cast<size_t>(sourceFileCount));
7707 break;
7708 case 300:
7709 if (sourceFiles.size() < static_cast<size_t>(sourceFileCount)) {
7710 sourceFiles.push_back(reader->getUtf8String());
7711 }
7712 break;
7713 case 11: extentsMin.x = reader->getDouble(); break;
7714 case 21: extentsMin.y = reader->getDouble(); break;
7715 case 31: extentsMin.z = reader->getDouble(); break;
7716 case 12: extentsMax.x = reader->getDouble(); break;
7717 case 22: extentsMax.y = reader->getDouble(); break;
7718 case 32: extentsMax.z = reader->getDouble(); break;
7719 case 92: pointCount = reader->getInt64(); break;
7720 case 2: ucsName = reader->getUtf8String(); break;
7721 case 13: ucsOrigin.x = reader->getDouble(); break;
7722 case 23: ucsOrigin.y = reader->getDouble(); break;
7723 case 33: ucsOrigin.z = reader->getDouble(); break;
7724 case 14: ucsXDirection.x = reader->getDouble(); break;
7725 case 24: ucsXDirection.y = reader->getDouble(); break;
7726 case 34: ucsXDirection.z = reader->getDouble(); break;
7727 case 15: ucsYDirection.x = reader->getDouble(); break;
7728 case 25: ucsYDirection.y = reader->getDouble(); break;
7729 case 35: ucsYDirection.z = reader->getDouble(); break;
7730 case 16: ucsZDirection.x = reader->getDouble(); break;
7731 case 26: ucsZDirection.y = reader->getDouble(); break;
7732 case 36: ucsZDirection.z = reader->getDouble(); break;
7733 case 340: definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7734 case 360: reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7735 case 290: showIntensity = reader->getBool(); break;
7736 case 280: intensityScheme = reader->getInt32(); break;
7737 case 441: intensityStyle.minIntensity = reader->getDouble(); break;
7738 case 442: intensityStyle.maxIntensity = reader->getDouble(); break;
7739 case 443: intensityStyle.lowThreshold = reader->getDouble(); break;
7740 case 444: intensityStyle.highThreshold = reader->getDouble(); break;
7741 case 291: showClipping = reader->getBool(); break;
7742 case 93: clippingCount = reader->getInt32(); break;
7743 default:
7744 return DRW_Entity::parseCode(code, reader);
7745 }
7746 return true;
7747}
7748
7749bool DRW_PointCloud::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7750 return DRW_Entity::parseDwg(version, buf, nullptr, bs);
7751}
7752
7753bool DRW_PointCloud::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7754 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7755 // Typed POINTCLOUD body encode is not implemented. Refuse rather than
7756 // emit a header-only stub that third-party readers reject.
7757 (void)version; (void)buf; (void)bs; (void)strBuf; (void)handleBuf;
7758 return false;
7759}
7760
7761bool DRW_PointCloudEx::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7762 switch (code) {
7763 case 90: classVersion = reader->getInt32(); break;
7764 case 11: extentsMin.x = reader->getDouble(); break;
7765 case 21: extentsMin.y = reader->getDouble(); break;
7766 case 31: extentsMin.z = reader->getDouble(); break;
7767 case 12: extentsMax.x = reader->getDouble(); break;
7768 case 22: extentsMax.y = reader->getDouble(); break;
7769 case 32: extentsMax.z = reader->getDouble(); break;
7770 case 13: ucsOrigin.x = reader->getDouble(); break;
7771 case 23: ucsOrigin.y = reader->getDouble(); break;
7772 case 33: ucsOrigin.z = reader->getDouble(); break;
7773 case 14: ucsXDirection.x = reader->getDouble(); break;
7774 case 24: ucsXDirection.y = reader->getDouble(); break;
7775 case 34: ucsXDirection.z = reader->getDouble(); break;
7776 case 15: ucsYDirection.x = reader->getDouble(); break;
7777 case 25: ucsYDirection.y = reader->getDouble(); break;
7778 case 35: ucsYDirection.z = reader->getDouble(); break;
7779 case 16: ucsZDirection.x = reader->getDouble(); break;
7780 case 26: ucsZDirection.y = reader->getDouble(); break;
7781 case 36: ucsZDirection.z = reader->getDouble(); break;
7782 case 290: isLocked = reader->getBool(); break;
7783 case 340: definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7784 case 360: reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); break;
7785 case 1: name = reader->getUtf8String(); break;
7786 case 291: showIntensity = reader->getBool(); break;
7787 case 292: showCropping = reader->getBool(); break;
7788 case 91: croppingCount = reader->getInt32(); break;
7789 case 92: unknownInt0 = reader->getInt32(); break;
7790 case 93: unknownInt1 = reader->getInt32(); break;
7791 case 280: stylizationType = reader->getInt32(); break;
7792 case 300: intensityColorScheme = reader->getUtf8String(); break;
7793 case 301: currentColorScheme = reader->getUtf8String(); break;
7794 case 302: classificationColorScheme = reader->getUtf8String(); break;
7795 case 440: elevationMin = reader->getDouble(); break;
7796 case 441: elevationMax = reader->getDouble(); break;
7797 case 442: intensityMin = reader->getDouble(); break;
7798 case 443: intensityMax = reader->getDouble(); break;
7799 case 281: intensityOutOfRangeBehavior = reader->getInt32(); break;
7800 case 282: elevationOutOfRangeBehavior = reader->getInt32(); break;
7801 case 293: elevationApplyToFixedRange = reader->getBool(); break;
7802 case 294: intensityAsGradient = reader->getBool(); break;
7803 case 295: elevationAsGradient = reader->getBool(); break;
7804 default:
7805 return DRW_Entity::parseCode(code, reader);
7806 }
7807 return true;
7808}
7809
7810bool DRW_PointCloudEx::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7811 return DRW_Entity::parseDwg(version, buf, nullptr, bs);
7812}
7813
7814bool DRW_PointCloudEx::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7815 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7816 (void)version; (void)buf; (void)bs; (void)strBuf; (void)handleBuf;
7817 return false;
7818}
7819
7820bool DRW_Surface::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
7821 switch (code) {
7822 case 70:
7823 modelerFormatVersion = reader->getInt32();
7824 break;
7825 case 71:
7826 uIsolines = reader->getInt32();
7827 break;
7828 case 72:
7829 vIsolines = reader->getInt32();
7830 break;
7831 case 310:
7832 {
7833 std::vector<std::uint8_t> decoded;
7834 if (!decodeHexBytes(reader->getString(), decoded))
7835 return false;
7836 appendBytes(rawAcisData, decoded);
7837 }
7838 break;
7839 default:
7840 return DRW_Entity::parseCode(code, reader);
7841 }
7842 return true;
7843}
7844
7845bool DRW_Surface::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
7846 return DRW_Entity::parseDwg(version, buf, nullptr, bs);
7847}
7848
7849bool DRW_Surface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
7850 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
7851 // Surface/ACIS body encode is not implemented as a full typed path.
7852 (void)version; (void)buf; (void)bs; (void)strBuf; (void)handleBuf;
7853 return false;
7854}
7855
7856bool DRW_Dimension::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
7857 switch (code) {
7858 case 1:
7859 text = reader->getUtf8String();
7860 break;
7861 case 2:
7862 name = reader->getString();
7863 break;
7864 case 3:
7865 style = reader->getUtf8String();
7866 break;
7867 case 70:
7868 type = reader->getInt32();
7869 break;
7870 case 71:
7871 align = reader->getInt32();
7872 break;
7873 case 72:
7874 linesty = reader->getInt32();
7875 break;
7876 case 10:
7877 defPoint.x = reader->getDouble();
7878 break;
7879 case 20:
7880 defPoint.y = reader->getDouble();
7881 break;
7882 case 30:
7883 defPoint.z = reader->getDouble();
7884 break;
7885 case 11:
7886 textPoint.x = reader->getDouble();
7887 break;
7888 case 21:
7889 textPoint.y = reader->getDouble();
7890 break;
7891 case 31:
7892 textPoint.z = reader->getDouble();
7893 break;
7894 case 12:
7895 clonePoint.x = reader->getDouble();
7896 break;
7897 case 22:
7898 clonePoint.y = reader->getDouble();
7899 break;
7900 case 32:
7901 clonePoint.z = reader->getDouble();
7902 break;
7903 case 13:
7904 def1.x = reader->getDouble();
7905 break;
7906 case 23:
7907 def1.y = reader->getDouble();
7908 break;
7909 case 33:
7910 def1.z = reader->getDouble();
7911 break;
7912 case 14:
7913 def2.x = reader->getDouble();
7914 break;
7915 case 24:
7916 def2.y = reader->getDouble();
7917 break;
7918 case 34:
7919 def2.z = reader->getDouble();
7920 break;
7921 case 15:
7922 circlePoint.x = reader->getDouble();
7923 break;
7924 case 25:
7925 circlePoint.y = reader->getDouble();
7926 break;
7927 case 35:
7928 circlePoint.z = reader->getDouble();
7929 break;
7930 case 16:
7931 arcPoint.x = reader->getDouble();
7932 break;
7933 case 26:
7934 arcPoint.y = reader->getDouble();
7935 break;
7936 case 36:
7937 arcPoint.z = reader->getDouble();
7938 break;
7939 case 41:
7940 linefactor = reader->getDouble();
7941 break;
7942 case 53:
7943 rot = reader->getDouble();
7944 break;
7945 case 50:
7946 angle = reader->getDouble();
7947 break;
7948 case 52:
7949 oblique = reader->getDouble();
7950 break;
7951 case 40:
7952 length = reader->getDouble();
7953 break;
7954 case 51:
7955 hdir = reader->getDouble();
7956 break;
7957 case 42:
7958 measureValue = reader->getDouble();
7959 break;
7960 case 74:
7961 flipArrow1 = reader->getInt32() != 0;
7962 break;
7963 case 75:
7964 flipArrow2 = reader->getInt32() != 0;
7965 break;
7966 case 76:
7967 genTol = reader->getInt32() != 0;
7968 break;
7969 case 77:
7970 limGen = reader->getInt32() != 0;
7971 break;
7972 case 43:
7973 tolPlus = reader->getDouble();
7974 break;
7975 case 44:
7976 tolMinus = reader->getDouble();
7977 break;
7978 case 45:
7979 tolScale = reader->getDouble();
7980 break;
7981 case 78:
7982 tolDecimals = reader->getInt32();
7983 break;
7984 case 79:
7985 tolAlign = reader->getInt32();
7986 break;
7987 case 80:
7988 tolZero = reader->getInt32();
7989 break;
7990 case 81:
7991 altTolDecimals = reader->getInt32();
7992 break;
7993 case 82:
7994 altZero = reader->getInt32();
7995 break;
7996 case 83:
7997 altTolZero = reader->getInt32();
7998 break;
7999 case 84:
8000 textMove = reader->getInt32();
8001 break;
8002 default:
8003 return DRW_Entity::parseCode(code, reader);
8004 }
8005
8006 return true;
8007}
8008
8009bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs)
8010{
8011 DRW_UNUSED( version)(void)version;
8012 DRW_UNUSED( buf)(void)buf;
8013 DRW_UNUSED( bs)(void)bs;
8014
8015 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"
)
;
8016
8017 return false;
8018}
8019
8020bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, std::uint32_t bs /*= 0*/) {
8021 dwgBuffer sBuff = *buf;
8022 sBuf = buf;
8023 if (version > DRW::AC1018) {//2007+
8024 sBuf = &sBuff; //separate buffer for strings
8025 }
8026
8027 if (!DRW_Entity::parseDwg( version, buf, sBuf, bs)) {
8028 return false;
8029 }
8030
8031 DRW_DBG("\n***************************** parsing dimension *********************************************")DRW_dbg::dbg("\n***************************** parsing dimension *********************************************"
)
;
8032 if (version > DRW::AC1021) { //2010+
8033 std::uint8_t dimVersion = buf->getRawChar8();
8034 DRW_DBG("\ndimVersion: ")DRW_dbg::dbg("\ndimVersion: "); DRW_DBG(dimVersion)DRW_dbg::dbg(dimVersion);
8035 }
8036 // ODA §20.4.22: Extrusion is plain 3BD (NOT BE) — confirmed by libreDWG dwg_spec_shared.h
8037 extPoint = buf->get3BitDouble();
8038 DRW_DBG("\nextPoint: ")DRW_dbg::dbg("\nextPoint: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z);
8039 textPoint.x = buf->getRawDouble();
8040 textPoint.y = buf->getRawDouble();
8041 textPoint.z = buf->getBitDouble();
8042 DRW_DBG("\ntextPoint: ")DRW_dbg::dbg("\ntextPoint: "); DRW_DBGPT(textPoint.x, textPoint.y, textPoint.z)DRW_dbg::dbgPT(textPoint.x, textPoint.y, textPoint.z);
8043 type = buf->getRawChar8();
8044 DRW_DBG("\ntype (70) read: ")DRW_dbg::dbg("\ntype (70) read: "); DRW_DBG(type)DRW_dbg::dbg(type);
8045 type = (type & 1) ? type & 0x7F : type | 0x80; //set bit 7
8046 type = (type & 2) ? type | 0x20 : type & 0xDF; //set bit 5
8047 DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(type)DRW_dbg::dbg(type);
8048 //clear last 3 bits to set integer dim type
8049 type &= 0xF8;
8050 text = sBuf->getVariableText(version, false);
8051 DRW_DBG("\nforced dim text: ")DRW_dbg::dbg("\nforced dim text: "); DRW_DBG(text.c_str())DRW_dbg::dbg(text.c_str());
8052 rot = buf->getBitDouble();
8053 hdir = buf->getBitDouble();
8054 DRW_Coord inspoint = buf->get3BitDouble();
8055 DRW_DBG("\ninspoint: ")DRW_dbg::dbg("\ninspoint: "); DRW_DBGPT(inspoint.x, inspoint.y, inspoint.z)DRW_dbg::dbgPT(inspoint.x, inspoint.y, inspoint.z);
8056 double insRot_code54 = buf->getBitDouble(); //RLZ: unknown, investigate
8057 DRW_DBG(" insRot_code54: ")DRW_dbg::dbg(" insRot_code54: "); DRW_DBG(insRot_code54)DRW_dbg::dbg(insRot_code54);
8058 if (version > DRW::AC1014) { //2000+
8059 align = buf->getBitShort();
8060 linesty = buf->getBitShort();
8061 linefactor = buf->getBitDouble();
8062 measureValue = buf->getBitDouble();
8063 DRW_DBG("\n actMeas_code42: ")DRW_dbg::dbg("\n actMeas_code42: "); DRW_DBG(measureValue)DRW_dbg::dbg(measureValue);
8064 if (version > DRW::AC1018) { //2007+
8065 bool unk = buf->getBit();
8066 flipArrow1 = buf->getBit();
8067 flipArrow2 = buf->getBit();
8068 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);
8069 }
8070 }
8071 clonePoint.x = buf->getRawDouble();
8072 clonePoint.y = buf->getRawDouble();
8073 DRW_DBG("\nclonePoint: ")DRW_dbg::dbg("\nclonePoint: "); DRW_DBGPT(clonePoint.x, clonePoint.y, clonePoint.z)DRW_dbg::dbgPT(clonePoint.x, clonePoint.y, clonePoint.z);
8074
8075 return buf->isGood();
8076}
8077
8078bool DRW_DimAligned::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8079 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8080 return false;
8081 }
8082
8083 if (oType == 0x15)
8084 DRW_DBG("\n***************************** parsing dim linear *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim linear *********************************************\n"
)
;
8085 else
8086 DRW_DBG("\n***************************** parsing dim aligned *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim aligned *********************************************\n"
)
;
8087 DRW_Coord pt = buf->get3BitDouble();
8088 setPt3(pt); //def1
8089 DRW_DBG("def1: ")DRW_dbg::dbg("def1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8090 pt = buf->get3BitDouble();
8091 setPt4(pt);
8092 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8093 pt = buf->get3BitDouble();
8094 setDefPoint(pt);
8095 DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8096 setOb52(buf->getBitDouble() * ARAD57.29577951308232); // radians → degrees
8097 if (oType == 0x15)
8098 setAn50(buf->getBitDouble() * ARAD57.29577951308232);
8099 else
8100 type |= 1;
8101 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");
8102
8103 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8104 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n"
)
;
8105 return false;
8106 }
8107 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");
8108 dimStyleH = buf->getHandle();
8109 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");
8110 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8111 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");
8112 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");
8113
8114 // RS crc; //RS */
8115 return buf->isGood();
8116 }
8117
8118bool DRW_DimRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8119 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8120 return false;
8121 }
8122
8123 DRW_DBG("\n***************************** parsing dim radial *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim radial *********************************************\n"
)
;
8124 DRW_Coord pt = buf->get3BitDouble();
8125 setDefPoint(pt); //code 10
8126 DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8127 pt = buf->get3BitDouble();
8128 setPt5(pt); //center pt code 15
8129 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);
8130 setRa40(buf->getBitDouble()); //leader length code 40
8131 DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40());
8132 type |= 4;
8133 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");
8134
8135 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8136 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n"
)
;
8137 return false;
8138 }
8139 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");
8140 dimStyleH = buf->getHandle();
8141 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");
8142 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8143 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");
8144 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");
8145
8146 // RS crc; //RS */
8147 return buf->isGood();
8148}
8149
8150// DRW_DimLargeRadial (AcDbRadialDimensionLarge, LARGE_RADIAL_DIMENSION).
8151// DXF group-code parser: the AcDbRadialDimensionLarge subclass overloads codes
8152// 13/14/15/40 (chord / override center / jog point / jog angle), so gate them on
8153// the subclass marker (like DRW_DimArc). The chord point is stored as the radial
8154// diameter point so the existing addDimRadial consumer renders center→chord.
8155bool DRW_DimLargeRadial::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
8156 if (code == 100) {
8157 std::string s = reader->getString();
8158 if (s == "AcDbRadialDimensionLarge") {
8159 m_largeRadialSubclassSeen = true;
8160 return true;
8161 }
8162 return DRW_Dimension::parseCode(code, reader);
8163 }
8164 if (m_largeRadialSubclassSeen) {
8165 DRW_Coord chord;
8166 switch (code) {
8167 case 13: chord = getPt5(); chord.x = reader->getDouble(); setPt5(chord); return true;
8168 case 23: chord = getPt5(); chord.y = reader->getDouble(); setPt5(chord); return true;
8169 case 33: chord = getPt5(); chord.z = reader->getDouble(); setPt5(chord); return true;
8170 case 14: overrideCenterPoint.x = reader->getDouble(); return true;
8171 case 24: overrideCenterPoint.y = reader->getDouble(); return true;
8172 case 34: overrideCenterPoint.z = reader->getDouble(); return true;
8173 case 15: jogPoint.x = reader->getDouble(); return true;
8174 case 25: jogPoint.y = reader->getDouble(); return true;
8175 case 35: jogPoint.z = reader->getDouble(); return true;
8176 case 40: jogAngle = reader->getDouble(); return true;
8177 default: break;
8178 }
8179 }
8180 return DRW_Dimension::parseCode(code, reader);
8181}
8182
8183// DRW_DimLargeRadial DWG body: five subclass reads then the dim-style and
8184// anon-block handles. The three subclass points are ordered
8185// definition point, JOG point, jog angle, CHORD point, OVERRIDDEN center
8186// so that the decoded fields match the DXF group codes (chord=13, override=14,
8187// jog=15) and libdxfrw's own DXF parseCode. The read-only reference parser
8188// (parseLargeRadialDimension) labels the 2nd/4th/5th reads chord/override/jog,
8189// i.e. a cyclic rotation of the point roles; that is inconsistent with the DXF
8190// semantics and with an ODA File Converter DXF↔DWG round-trip (which preserves
8191// codes 13/14/15 exactly). Verified by large_radial_dim_dwg_tests.cpp against
8192// an ODA-synthesized fixture, cross-checked with the dwg-parser's DXF read.
8193// Only the field labels change vs. the reference parser — the read sizes/order
8194// (3BD, 3BD, BD, 3BD, 3BD) are identical, so buffer alignment is unchanged.
8195bool DRW_DimLargeRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8196 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8197 return false;
8198 }
8199 setDefPoint(buf->get3BitDouble()); // definition point (code 10)
8200 jogPoint = buf->get3BitDouble(); // jog vertex (code 15)
8201 jogAngle = buf->getBitDouble(); // jog transverse angle (code 40)
8202 setPt5(buf->get3BitDouble()); // chord point → radial diameter point (code 13)
8203 overrideCenterPoint = buf->get3BitDouble(); // overridden center (code 14)
8204 type |= 4; // radial dimension type bit
8205 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8206 return false;
8207 }
8208 dimStyleH = buf->getHandle();
8209 blockH = buf->getHandle();
8210 return buf->isGood();
8211}
8212
8213bool DRW_DimDiametric::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8214 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8215 return false;
8216 }
8217
8218 DRW_DBG("\n***************************** parsing dim diametric *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim diametric *********************************************\n"
)
;
8219 DRW_Coord pt = buf->get3BitDouble();
8220 setPt5(pt); //center pt code 15
8221 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);
8222 pt = buf->get3BitDouble();
8223 setDefPoint(pt); //code 10
8224 DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8225 setRa40(buf->getBitDouble()); //leader length code 40
8226 DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40());
8227 type |= 3;
8228 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");
8229
8230 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8231 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n"
)
;
8232 return false;
8233 }
8234 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");
8235 dimStyleH = buf->getHandle();
8236 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");
8237 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8238 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");
8239 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");
8240
8241 // RS crc; //RS */
8242 return buf->isGood();
8243}
8244
8245bool DRW_DimAngular::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8246 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8247 return false;
8248 }
8249
8250 DRW_DBG("\n***************************** parsing dim angular *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular *********************************************\n"
)
;
8251 DRW_Coord pt;
8252 pt.x = buf->getRawDouble();
8253 pt.y = buf->getRawDouble();
8254 setPt6(pt); //code 16
8255 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);
8256 pt = buf->get3BitDouble();
8257 setPt3(pt); //def1 code 13
8258 DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8259 pt = buf->get3BitDouble();
8260 setPt4(pt); //def2 code 14
8261 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8262 pt = buf->get3BitDouble();
8263 setPt5(pt); //center pt code 15
8264 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);
8265 pt = buf->get3BitDouble();
8266 setDefPoint(pt); //code 10
8267 DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8268 type |= 0x02;
8269 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");
8270
8271 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8272 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n"
)
;
8273 return false;
8274 }
8275 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");
8276 dimStyleH = buf->getHandle();
8277 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");
8278 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8279 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");
8280 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");
8281
8282 // RS crc; //RS */
8283 return buf->isGood();
8284}
8285
8286bool DRW_DimAngular3p::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8287 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8288 return false;
8289 }
8290
8291 DRW_DBG("\n***************************** parsing dim angular3p *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular3p *********************************************\n"
)
;
8292 DRW_Coord pt = buf->get3BitDouble();
8293 setDefPoint(pt); //code 10
8294 DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8295 pt = buf->get3BitDouble();
8296 setPt3(pt); //def1 code 13
8297 DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8298 pt = buf->get3BitDouble();
8299 setPt4(pt); //def2 code 14
8300 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8301 pt = buf->get3BitDouble();
8302 setPt5(pt); //center pt code 15
8303 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);
8304 type |= 0x05;
8305 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");
8306
8307 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8308 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n"
)
;
8309 return false;
8310 }
8311 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");
8312 dimStyleH = buf->getHandle();
8313 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");
8314 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8315 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");
8316 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");
8317
8318 // RS crc; //RS */
8319 return buf->isGood();
8320}
8321
8322bool DRW_DimOrdinate::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8323 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) {
8324 return false;
8325 }
8326
8327 DRW_DBG("\n***************************** parsing dim ordinate *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim ordinate *********************************************\n"
)
;
8328 DRW_Coord pt = buf->get3BitDouble();
8329 setDefPoint(pt);
8330 DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8331 pt = buf->get3BitDouble();
8332 setPt3(pt); //def1
8333 DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8334 pt = buf->get3BitDouble();
8335 setPt4(pt);
8336 DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(pt.x, pt.y, pt.z)DRW_dbg::dbgPT(pt.x, pt.y, pt.z);
8337 std::uint8_t type2 = buf->getRawChar8();//RLZ: correct this
8338 DRW_DBG("type2 (70) read: ")DRW_dbg::dbg("type2 (70) read: "); DRW_DBG(type2)DRW_dbg::dbg(type2);
8339 // 0B.1: x-vs-y ordinate flag is DXF group-70 bit 6 (0x40), matching the
8340 // filter (rs_filterdxfrw.cpp `type & 64`) and the DWG parseCode path.
8341 // (Previously set bit 7/0x80, which the filter never checks.) The clear
8342 // mask 0xBF already clears 0x40. The DIMENSION base type byte (bit 7) is
8343 // a separate field — see :6141/:6409/:6660, NOT touched here.
8344 type = (type2 & 1) ? type | 0x40 : type & 0xBF; //set bit 6 (0x40)
8345 DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(type)DRW_dbg::dbg(type);
8346 type |= 6;
8347 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");
8348
8349 if (!DRW_Entity::parseDwgEntHandle(version, buf)) {
8350 DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n"
)
;
8351 return false;
8352 }
8353 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");
8354 dimStyleH = buf->getHandle();
8355 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");
8356 blockH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8357 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");
8358 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");
8359
8360 // RS crc; //RS */
8361 return buf->isGood();
8362}
8363
8364// ----------------------------------------------------------------------------
8365// DRW_Dimension shared base encoder (R2000 / AC1015)
8366// ----------------------------------------------------------------------------
8367bool DRW_Dimension::encodeDwgDimBase(DRW::Version version, dwgBufferW *buf,
8368 dwgBufferW *strBuf) const {
8369 // ODA §20.4.22: version RC present for R2010+ (mirrors parseDwg read at version > AC1021)
8370 if (version > DRW::AC1021)
8371 buf->putRawChar8(0);
8372 // R2007+: the dim text below is routed to strBuf (the separate string
8373 // stream) via the (strBuf ? strBuf : buf) selector in putVariableText.
8374 buf->put3BitDouble(extPoint); // 3BD per ODA §20.4.22 (NOT BE, NO padding bits)
8375 buf->putRawDouble(textPoint.x);
8376 buf->putRawDouble(textPoint.y);
8377 buf->putBitDouble(textPoint.z);
8378 // Reverse the parseDwg type-byte transformation:
8379 // parseDwg bit0=0 → type bit7 set; bit0=1 → type bit7 clear
8380 // parseDwg bit1=1 → type bit5 set; bit1=0 → type bit5 clear
8381 std::uint8_t rawByte = static_cast<std::uint8_t>(
8382 ((type & 0x80) ? 0 : 1) | ((type & 0x20) ? 2 : 0));
8383 buf->putRawChar8(rawByte);
8384 (strBuf ? strBuf : buf)->putVariableText(version, text);
8385 buf->putBitDouble(rot);
8386 buf->putBitDouble(hdir);
8387 // ins_scale (3BD) of the dimension's anonymous block — not stored by the
8388 // reader, but ODA/libreDWG default it to (1,1,1) (dwg.spec FIELD_3BD_1), not
8389 // (0,0,0). A zero scale is degenerate for ODA consumers. (write-review #46)
8390 const DRW_Coord insScale{1.0, 1.0, 1.0};
8391 buf->put3BitDouble(insScale);
8392 buf->putBitDouble(0.0); // ins_rotation (code 54) — default 0, not stored
8393 // R2000 (version > AC1014): alignment, spacing, line factor, measure
8394 buf->putBitShort(static_cast<std::uint16_t>(align));
8395 buf->putBitShort(static_cast<std::uint16_t>(linesty));
8396 buf->putBitDouble(linefactor);
8397 buf->putBitDouble(measureValue);
8398 if (version > DRW::AC1018) {
8399 buf->putBit(0); // unknown R2007+ bit
8400 buf->putBit(flipArrow1 ? 1 : 0);
8401 buf->putBit(flipArrow2 ? 1 : 0);
8402 }
8403 buf->putRawDouble(clonePoint.x);
8404 buf->putRawDouble(clonePoint.y);
8405 return true;
8406}
8407
8408// Helper: emit dimStyleH (defaults to STANDARD=0x15) and blockH.
8409static void putDimHandles(dwgBufferW *buf, const dwgHandle& dimStyleH, const dwgHandle& blockH,
8410 dwgBufferW *hBuf = nullptr) {
8411 dwgBufferW *hb = hBuf ? hBuf : buf;
8412 dwgHandle dsH;
8413 dsH.code = 5;
8414 dsH.ref = (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref;
8415 dsH.size = 0;
8416 if (dsH.ref != 0) { std::uint32_t t = dsH.ref; while (t != 0) { t >>= 8; ++dsH.size; } }
8417 hb->putHandle(dsH);
8418
8419 dwgHandle bhH;
8420 bhH.code = (blockH.ref == 0) ? 0 : 5;
8421 bhH.ref = blockH.ref;
8422 bhH.size = 0;
8423 if (bhH.ref != 0) { std::uint32_t t = bhH.ref; while (t != 0) { t >>= 8; ++bhH.size; } }
8424 hb->putHandle(bhH);
8425}
8426
8427// ----------------------------------------------------------------------------
8428// DRW_DimAligned::encodeDwg (oType=22)
8429// ----------------------------------------------------------------------------
8430bool DRW_DimAligned::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8431 (void)bs;
8432 oType = 22;
8433 if (!encodeDwgCommon(version, buf)) return false;
8434 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8435 buf->put3BitDouble(getPt3()); // def1
8436 buf->put3BitDouble(getPt4()); // def2
8437 buf->put3BitDouble(getDefPoint()); // defPoint
8438 buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians
8439 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8440 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8441 return true;
8442}
8443
8444// ----------------------------------------------------------------------------
8445// DRW_DimLinear::encodeDwg (oType=21)
8446// ----------------------------------------------------------------------------
8447bool DRW_DimLinear::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8448 (void)bs;
8449 oType = 21;
8450 if (!encodeDwgCommon(version, buf)) return false;
8451 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8452 buf->put3BitDouble(getPt3()); // def1
8453 buf->put3BitDouble(getPt4()); // def2
8454 buf->put3BitDouble(getDefPoint()); // defPoint
8455 buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians
8456 buf->putBitDouble(getAn50() / ARAD57.29577951308232); // rotation angle: degrees → radians
8457 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8458 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8459 return true;
8460}
8461
8462// ----------------------------------------------------------------------------
8463// DRW_DimRadial::encodeDwg (oType=25)
8464// ----------------------------------------------------------------------------
8465bool DRW_DimRadial::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8466 (void)bs;
8467 oType = 25;
8468 if (!encodeDwgCommon(version, buf)) return false;
8469 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8470 buf->put3BitDouble(getDefPoint()); // center point (code 10)
8471 buf->put3BitDouble(getPt5()); // diameter point (code 15)
8472 buf->putBitDouble(getRa40()); // leader length (code 40)
8473 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8474 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8475 return true;
8476}
8477
8478// ----------------------------------------------------------------------------
8479// DRW_DimLargeRadial::encodeDwg (oType=519, custom AcDbRadialDimensionLarge)
8480// ----------------------------------------------------------------------------
8481bool DRW_DimLargeRadial::encodeDwg(DRW::Version version, dwgBufferW *buf,
8482 std::uint32_t bs, dwgBufferW *strBuf,
8483 dwgBufferW *handleBuf) {
8484 (void)bs;
8485 oType = kDwgClassNum;
8486 if (!encodeDwgCommon(version, buf)) return false;
8487 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8488 buf->put3BitDouble(getCenterPoint()); // definition point (code 10)
8489 buf->put3BitDouble(jogPoint); // jog vertex (code 15)
8490 buf->putBitDouble(jogAngle); // jog transverse angle (code 40)
8491 buf->put3BitDouble(getChordPoint()); // chord point (code 13)
8492 buf->put3BitDouble(overrideCenterPoint); // overridden center (code 14)
8493 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8494 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8495 return true;
8496}
8497
8498// ----------------------------------------------------------------------------
8499// DRW_DimDiametric::encodeDwg (oType=26)
8500// ----------------------------------------------------------------------------
8501bool DRW_DimDiametric::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8502 (void)bs;
8503 oType = 26;
8504 if (!encodeDwgCommon(version, buf)) return false;
8505 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8506 buf->put3BitDouble(getPt5()); // first diameter point (code 15) — matches parseDwg order
8507 buf->put3BitDouble(getDefPoint()); // opposite point (code 10)
8508 buf->putBitDouble(getRa40()); // leader length (code 40)
8509 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8510 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8511 return true;
8512}
8513
8514// ----------------------------------------------------------------------------
8515// DRW_DimAngular::encodeDwg (oType=24, 2-line angular)
8516// ----------------------------------------------------------------------------
8517bool DRW_DimAngular::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8518 (void)bs;
8519 oType = 24;
8520 if (!encodeDwgCommon(version, buf)) return false;
8521 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8522 // arcPoint is 2RD (not 3BD) in parseDwg — only x and y
8523 buf->putRawDouble(getPt6().x);
8524 buf->putRawDouble(getPt6().y);
8525 buf->put3BitDouble(getPt3()); // def1 (line 1 start)
8526 buf->put3BitDouble(getPt4()); // def2 (line 1 end)
8527 buf->put3BitDouble(getPt5()); // circlePoint (center)
8528 buf->put3BitDouble(getDefPoint()); // defPoint
8529 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8530 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8531 return true;
8532}
8533
8534// ----------------------------------------------------------------------------
8535// DRW_DimAngular3p::encodeDwg (oType=23, 3-point angular)
8536// ----------------------------------------------------------------------------
8537bool DRW_DimAngular3p::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8538 (void)bs;
8539 oType = 23;
8540 if (!encodeDwgCommon(version, buf)) return false;
8541 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8542 buf->put3BitDouble(getDefPoint()); // defPoint (code 10)
8543 buf->put3BitDouble(getPt3()); // def1 (code 13)
8544 buf->put3BitDouble(getPt4()); // def2 (code 14)
8545 buf->put3BitDouble(getPt5()); // circlePoint / vertex (code 15)
8546 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8547 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8548 return true;
8549}
8550
8551// ----------------------------------------------------------------------------
8552// DRW_DimArc::parseCode (DXF group-code parser)
8553// ----------------------------------------------------------------------------
8554bool DRW_DimArc::parseCode(int code, const std::unique_ptr<dxfReader>& reader) {
8555 if (code == 100) {
8556 std::string s = reader->getString();
8557 if (s == "AcDbArcDimension") {
8558 m_arcSubclassSeen = true;
8559 return true;
8560 }
8561 // Fall through for AcDbEntity / AcDbDimension so base classes see them
8562 return DRW_Dimension::parseCode(code, reader);
8563 }
8564 if (m_arcSubclassSeen) {
8565 switch (code) {
8566 case 40: arcStartAngle = reader->getDouble(); return true;
8567 case 41: arcEndAngle = reader->getDouble(); return true;
8568 case 70: arcSymbol = reader->getInt32(); return true;
8569 case 71: isPartial = reader->getInt32() != 0; return true;
8570 }
8571 }
8572 switch (code) {
8573 case 17: leaderPt2.x = reader->getDouble(); return true;
8574 case 27: leaderPt2.y = reader->getDouble(); return true;
8575 case 37: leaderPt2.z = reader->getDouble(); return true;
8576 }
8577 return DRW_Dimension::parseCode(code, reader);
8578}
8579
8580// ----------------------------------------------------------------------------
8581// DRW_DimArc::parseDwg (ODA DWG spec §20.4.19)
8582// ----------------------------------------------------------------------------
8583bool DRW_DimArc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
8584 if (!DRW_Dimension::parseDwg(version, buf, nullptr, bs)) return false;
8585 setDefPoint(buf->get3BitDouble()); // arc dim-line arc point (code 10)
8586 setPt3(buf->get3BitDouble()); // extension line 1 (code 13)
8587 setPt4(buf->get3BitDouble()); // extension line 2 (code 14)
8588 setPt5(buf->get3BitDouble()); // arc center (code 15)
8589 isPartial = buf->getBit() != 0;
8590 arcStartAngle = buf->getBitDouble();
8591 arcEndAngle = buf->getBitDouble();
8592 hasLeader = buf->getBit() != 0;
8593 // ODA §20.4.19: leader points are UNCONDITIONAL — always present in the stream
8594 setPt6(buf->get3BitDouble()); // leader point 1 (code 16)
8595 leaderPt2 = buf->get3BitDouble(); // leader point 2 (code 17)
8596 if (!DRW_Entity::parseDwgEntHandle(version, buf)) return false;
8597 dimStyleH = buf->getHandle();
8598 blockH = buf->getHandle();
8599 return buf->isGood();
8600}
8601
8602// ----------------------------------------------------------------------------
8603// DRW_DimArc::encodeDwg (oType=500 — dynamic class, classNum from writeDwgClasses)
8604// ----------------------------------------------------------------------------
8605bool DRW_DimArc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
8606 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8607 (void)bs;
8608 oType = DRW_DimArc::kDwgClassNum; // assigned in writeDwgClasses; reader resolves via classesmap
8609 if (!encodeDwgCommon(version, buf)) return false;
8610 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8611 buf->put3BitDouble(getDefPoint()); // arc dim-line arc point (code 10)
8612 buf->put3BitDouble(getPt3()); // extension line 1 (code 13)
8613 buf->put3BitDouble(getPt4()); // extension line 2 (code 14)
8614 buf->put3BitDouble(getPt5()); // arc center (code 15)
8615 buf->putBit(isPartial ? 1 : 0);
8616 buf->putBitDouble(arcStartAngle);
8617 buf->putBitDouble(arcEndAngle);
8618 buf->putBit(hasLeader ? 1 : 0);
8619 // ODA §20.4.19: leader points are UNCONDITIONAL — always written; default to ext-line pts
8620 DRW_Coord lp1 = hasLeader ? getPt6() : getPt3();
8621 DRW_Coord lp2 = hasLeader ? leaderPt2 : getPt4();
8622 buf->put3BitDouble(lp1); // leader point 1 (code 16)
8623 buf->put3BitDouble(lp2); // leader point 2 (code 17)
8624 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8625 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8626 return true;
8627}
8628
8629// ----------------------------------------------------------------------------
8630// DRW_DimOrdinate::encodeDwg (oType=20)
8631// ----------------------------------------------------------------------------
8632bool DRW_DimOrdinate::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) {
8633 (void)bs;
8634 oType = 20;
8635 if (!encodeDwgCommon(version, buf)) return false;
8636 if (!encodeDwgDimBase(version, buf, strBuf)) return false;
8637 buf->put3BitDouble(getDefPoint()); // origin/definition point (code 10)
8638 buf->put3BitDouble(getPt3()); // feature location point (code 13)
8639 buf->put3BitDouble(getPt4()); // leader end point (code 14)
8640 // type2 byte encodes the x-vs-y ordinate flag (bit 6 / 0x40 of type, per
8641 // 0B.1) — keeps the DWG byte round-trip self-consistent with the parse
8642 // side while making the filter's `type & 64` check fire.
8643 std::uint8_t type2byte = (type & 0x40) ? 1 : 0;
8644 buf->putRawChar8(type2byte);
8645 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
8646 putDimHandles(buf, dimStyleH, blockH, handleBuf);
8647 return true;
8648}
8649
8650bool DRW_Leader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
8651 switch (code) {
8652 case 3:
8653 style = reader->getUtf8String();
8654 break;
8655 case 71:
8656 arrow = reader->getInt32();
8657 break;
8658 case 72:
8659 leadertype = reader->getInt32();
8660 break;
8661 case 73:
8662 flag = reader->getInt32();
8663 break;
8664 case 74:
8665 hookline = reader->getInt32();
8666 break;
8667 case 75:
8668 hookflag = reader->getInt32();
8669 break;
8670 case 76:
8671 vertnum = reader->getInt32();
8672 break;
8673 case 77:
8674 coloruse = reader->getInt32();
8675 break;
8676 case 40:
8677 textheight = reader->getDouble();
8678 break;
8679 case 41:
8680 textwidth = reader->getDouble();
8681 break;
8682 case 10:
8683 vertexpoint= std::make_shared<DRW_Coord>();
8684 vertexlist.push_back(vertexpoint);
8685 vertexpoint->x = reader->getDouble();
8686 break;
8687 case 20:
8688 if(vertexpoint)
8689 vertexpoint->y = reader->getDouble();
8690 break;
8691 case 30:
8692 if(vertexpoint)
8693 vertexpoint->z = reader->getDouble();
8694 break;
8695 case 340:
8696 annotHandle = reader->getHandleString();
8697 break;
8698 case 210:
8699 extrusionPoint.x = reader->getDouble();
8700 break;
8701 case 220:
8702 extrusionPoint.y = reader->getDouble();
8703 break;
8704 case 230:
8705 extrusionPoint.z = reader->getDouble();
8706 break;
8707 case 211:
8708 horizdir.x = reader->getDouble();
8709 break;
8710 case 221:
8711 horizdir.y = reader->getDouble();
8712 break;
8713 case 231:
8714 horizdir.z = reader->getDouble();
8715 break;
8716 case 212:
8717 offsetblock.x = reader->getDouble();
8718 break;
8719 case 222:
8720 offsetblock.y = reader->getDouble();
8721 break;
8722 case 232:
8723 offsetblock.z = reader->getDouble();
8724 break;
8725 case 213:
8726 offsettext.x = reader->getDouble();
8727 break;
8728 case 223:
8729 offsettext.y = reader->getDouble();
8730 break;
8731 case 233:
8732 offsettext.z = reader->getDouble();
8733 break;
8734 default:
8735 return DRW_Entity::parseCode(code, reader);
8736 }
8737
8738 return true;
8739}
8740
8741bool DRW_Leader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
8742 dwgBuffer sBuff = *buf;
8743 dwgBuffer *sBuf = buf;
8744 if (version > DRW::AC1018) {//2007+
8745 sBuf = &sBuff; //separate buffer for strings
8746 }
8747 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
8748 if (!ret)
8749 return ret;
8750 DRW_DBG("\n***************************** parsing leader *********************************************\n")DRW_dbg::dbg("\n***************************** parsing leader *********************************************\n"
)
;
8751 DRW_DBG("unknown bit ")DRW_dbg::dbg("unknown bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8752 DRW_DBG(" annot type ")DRW_dbg::dbg(" annot type "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8753 leadertype = buf->getBitShort();
8754 DRW_DBG(" Path type ")DRW_dbg::dbg(" Path type "); DRW_DBG(leadertype)DRW_dbg::dbg(leadertype);
8755 std::int32_t nPt = buf->getBitLong();
8756 DRW_DBG(" Num pts ")DRW_dbg::dbg(" Num pts "); DRW_DBG(nPt)DRW_dbg::dbg(nPt);
8757
8758 // add vertexes
8759 for (int i = 0; i< nPt; i++){
8760 DRW_Coord vertex = buf->get3BitDouble();
8761 vertexlist.push_back(std::make_shared<DRW_Coord>(vertex));
8762 DRW_DBG("\nvertex ")DRW_dbg::dbg("\nvertex "); DRW_DBGPT(vertex.x, vertex.y, vertex.z)DRW_dbg::dbgPT(vertex.x, vertex.y, vertex.z);
8763 }
8764 DRW_Coord Endptproj = buf->get3BitDouble();
8765 DRW_DBG("\nEndptproj ")DRW_dbg::dbg("\nEndptproj "); DRW_DBGPT(Endptproj.x, Endptproj.y, Endptproj.z)DRW_dbg::dbgPT(Endptproj.x, Endptproj.y, Endptproj.z);
8766 // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — confirmed by libreDWG dwg.spec:3439
8767 extrusionPoint = buf->get3BitDouble();
8768 DRW_DBG("\nextrusionPoint ")DRW_dbg::dbg("\nextrusionPoint "); DRW_DBGPT(extrusionPoint.x, extrusionPoint.y, extrusionPoint.z)DRW_dbg::dbgPT(extrusionPoint.x, extrusionPoint.y, extrusionPoint
.z)
;
8769 horizdir = buf->get3BitDouble();
8770 DRW_DBG("\nhorizdir ")DRW_dbg::dbg("\nhorizdir "); DRW_DBGPT(horizdir.x, horizdir.y, horizdir.z)DRW_dbg::dbgPT(horizdir.x, horizdir.y, horizdir.z);
8771 offsetblock = buf->get3BitDouble();
8772 DRW_DBG("\noffsetblock ")DRW_dbg::dbg("\noffsetblock "); DRW_DBGPT(offsetblock.x, offsetblock.y, offsetblock.z)DRW_dbg::dbgPT(offsetblock.x, offsetblock.y, offsetblock.z);
8773 if (version > DRW::AC1012) { //R14+
8774 DRW_Coord unk = buf->get3BitDouble();
8775 DRW_DBG("\nunknown ")DRW_dbg::dbg("\nunknown "); DRW_DBGPT(unk.x, unk.y, unk.z)DRW_dbg::dbgPT(unk.x, unk.y, unk.z);
8776 }
8777 if (version < DRW::AC1015) { //R14 -
8778 DRW_DBG("\ndimgap ")DRW_dbg::dbg("\ndimgap "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble());
8779 }
8780 if (version < DRW::AC1024) { //2010-
8781 textheight = buf->getBitDouble();
8782 textwidth = buf->getBitDouble();
8783 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);
8784 }
8785 hookline = buf->getBit();
8786 arrow = buf->getBit();
8787 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);
8788
8789 if (version < DRW::AC1015) { //R14 -
8790 DRW_DBG("\nArrow head type ")DRW_dbg::dbg("\nArrow head type "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8791 DRW_DBG("dimasz ")DRW_dbg::dbg("dimasz "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble());
8792 DRW_DBG("\nunk bit ")DRW_dbg::dbg("\nunk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8793 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8794 DRW_DBG(" unk short ")DRW_dbg::dbg(" unk short "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8795 DRW_DBG(" byBlock color ")DRW_dbg::dbg(" byBlock color "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8796 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8797 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8798 } else { //R2000+
8799 DRW_DBG("\nunk short ")DRW_dbg::dbg("\nunk short "); DRW_DBG(buf->getBitShort())DRW_dbg::dbg(buf->getBitShort());
8800 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8801 DRW_DBG(" unk bit ")DRW_dbg::dbg(" unk bit "); DRW_DBG(buf->getBit())DRW_dbg::dbg(buf->getBit());
8802 }
8803 DRW_DBG("\n")DRW_dbg::dbg("\n");
8804 ret = DRW_Entity::parseDwgEntHandle(version, buf);
8805 if (!ret)
8806 return ret;
8807 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");
8808 AnnotH = buf->getHandle();
8809 annotHandle = AnnotH.ref;
8810 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");
8811 dimStyleH = buf->getHandle(); /* H 7 STYLE (hard pointer) */
8812 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");
8813 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");
8814// RS crc; //RS */
8815 return buf->isGood();
8816}
8817
8818// DXF CONTEXT_DATA{} nested-block state machine (§20.4.86). The nested blocks
8819// open with 300 "CONTEXT_DATA{" / 302 "LEADER{" / 304 "LEADER_LINE{" and close
8820// with the distinct codes 301 / 303 / 305, so the open block is tracked with a
8821// single state int (no stack needed). The numeric group codes are overloaded
8822// by block — e.g. 40 is the overall scale in CONTEXT, the landing distance in
8823// LEADER and the arrow size in LEADER_LINE; 10/20/30 are the content base point,
8824// the connection point and a polyline vertex respectively — so they are routed
8825// per state into `context`. Returns true when the code belongs to the context
8826// block (consumed); false at entity level so parseCode handles it.
8827bool DRW_MLeader::parseDxfContextCode(int code, const std::unique_ptr<dxfReader>& reader){
8828 switch (code) { // block open/close markers
8829 case 300: m_dxfCtxState = 1; return true; // "CONTEXT_DATA{"
8830 case 301: m_dxfCtxState = 0; return true; // "}" end context
8831 case 302: context.roots.emplace_back(); m_dxfCtxState = 2; return true; // "LEADER{"
8832 case 303: m_dxfCtxState = m_dxfCtxState ? 1 : 0; return true; // "}" end leader
8833 case 304:
8834 if (reader->getString() == "LEADER_LINE{") {
8835 if (!context.roots.empty())
8836 context.roots.back().leaderLines.emplace_back();
8837 m_dxfCtxState = 3;
8838 return true;
8839 }
8840 if (m_dxfCtxState == 1) { context.textLabel = reader->getUtf8String(); return true; }
8841 return false; // not in context: defer (unused)
8842 case 305: m_dxfCtxState = 2; return true; // "}" end leader line
8843 default: break;
8844 }
8845
8846 if (m_dxfCtxState == 0)
8847 return false; // entity level — parseCode handles it
8848
8849 if (m_dxfCtxState == 3) { // LEADER_LINE{}: a polyline + overrides
8850 DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back();
8851 DRW_MLeaderLeaderLine* line =
8852 (root && !root->leaderLines.empty()) ? &root->leaderLines.back() : nullptr;
8853 if (line) switch (code) {
8854 case 10: line->points.emplace_back(reader->getDouble(), 0.0, 0.0); return true;
8855 case 20: if (!line->points.empty()) line->points.back().y = reader->getDouble(); return true;
8856 case 30: if (!line->points.empty()) line->points.back().z = reader->getDouble(); return true;
8857 case 40: line->arrowSize = reader->getDouble(); return true;
8858 case 90: line->segmentIndex = reader->getInt32(); return true;
8859 case 91: line->leaderLineIndex = reader->getInt32(); return true;
8860 case 92: line->color = reader->getInt32(); return true;
8861 case 93: line->overrideFlags = reader->getInt32(); return true;
8862 case 170: line->leaderType = reader->getInt32(); return true;
8863 case 171: line->lineWeight = reader->getInt32(); return true;
8864 default: break;
8865 }
8866 return true; // swallow other line codes
8867 }
8868
8869 if (m_dxfCtxState == 2) { // LEADER{}: one root attachment
8870 DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back();
8871 if (root) switch (code) {
8872 case 290: root->isContentValid = (reader->getInt32() != 0); return true;
8873 case 291: root->unknown291 = (reader->getInt32() != 0); return true;
8874 case 10: root->connectionPoint.x = reader->getDouble(); return true;
8875 case 20: root->connectionPoint.y = reader->getDouble(); return true;
8876 case 30: root->connectionPoint.z = reader->getDouble(); return true;
8877 case 11: root->direction.x = reader->getDouble(); return true;
8878 case 21: root->direction.y = reader->getDouble(); return true;
8879 case 31: root->direction.z = reader->getDouble(); return true;
8880 case 90: root->leaderIndex = reader->getInt32(); return true;
8881 case 40: root->landingDistance = reader->getDouble(); return true;
8882 case 271: root->attachmentDirection = reader->getInt32(); return true;
8883 default: break;
8884 }
8885 return true; // swallow other leader codes
8886 }
8887
8888 switch (code) { // m_dxfCtxState == 1: CONTEXT_DATA{}
8889 case 40: context.overallScale = reader->getDouble(); return true;
8890 case 10: context.contentBasePoint.x = reader->getDouble(); return true;
8891 case 20: context.contentBasePoint.y = reader->getDouble(); return true;
8892 case 30: context.contentBasePoint.z = reader->getDouble(); return true;
8893 case 41: context.textHeight = reader->getDouble(); return true;
8894 case 140: context.arrowHeadSize = reader->getDouble(); return true;
8895 case 145: context.landingGap = reader->getDouble(); return true;
8896 case 174: context.styleLeftAttach = reader->getInt32(); return true;
8897 case 175: context.styleRightAttach = reader->getInt32(); return true;
8898 case 176: context.textAlignType = reader->getInt32(); return true;
8899 case 177: context.attachmentType = reader->getInt32(); return true;
8900 case 290: context.hasTextContents = (reader->getInt32() != 0); return true;
8901 /* text-content branch */
8902 case 11: context.textNormal.x = reader->getDouble(); return true;
8903 case 21: context.textNormal.y = reader->getDouble(); return true;
8904 case 31: context.textNormal.z = reader->getDouble(); return true;
8905 case 12: context.textLocation.x = reader->getDouble(); return true;
8906 case 22: context.textLocation.y = reader->getDouble(); return true;
8907 case 32: context.textLocation.z = reader->getDouble(); return true;
8908 case 13: context.textDirection.x = reader->getDouble(); return true;
8909 case 23: context.textDirection.y = reader->getDouble(); return true;
8910 case 33: context.textDirection.z = reader->getDouble(); return true;
8911 case 42: context.textRotation = reader->getDouble(); return true;
8912 case 43: context.boundaryWidth = reader->getDouble(); return true;
8913 case 44: context.boundaryHeight = reader->getDouble(); return true;
8914 case 45: context.lineSpacingFactor = reader->getDouble(); return true;
8915 case 170: context.lineSpacingStyle = reader->getInt32(); return true;
8916 case 90: context.textColor = reader->getInt32(); return true;
8917 case 171: context.alignment = reader->getInt32(); return true;
8918 case 172: context.flowDirection = reader->getInt32(); return true;
8919 case 91: context.bgFillColor = reader->getInt32(); return true;
8920 case 141: context.bgScaleFactor = reader->getDouble(); return true;
8921 case 92: context.bgTransparency = reader->getInt32(); return true;
8922 case 291: context.bgFillEnabled = (reader->getInt32() != 0); return true;
8923 case 292: context.bgMaskFillOn = (reader->getInt32() != 0); return true;
8924 case 173: context.columnType = reader->getInt32(); return true;
8925 case 293: context.textHeightAuto = (reader->getInt32() != 0); return true;
8926 case 142: context.columnWidth = reader->getDouble(); return true;
8927 case 143: context.columnGutter = reader->getDouble(); return true;
8928 case 294: context.columnFlowReversed = (reader->getInt32() != 0); return true;
8929 case 144: context.columnSizes.push_back(reader->getDouble()); return true;
8930 case 295: context.wordBreak = (reader->getInt32() != 0); return true;
8931 /* block-content branch */
8932 case 296: context.hasContentsBlock = (reader->getInt32() != 0); return true;
8933 case 14: context.blockNormal.x = reader->getDouble(); return true;
8934 case 24: context.blockNormal.y = reader->getDouble(); return true;
8935 case 34: context.blockNormal.z = reader->getDouble(); return true;
8936 case 15: context.blockLocation.x = reader->getDouble(); return true;
8937 case 25: context.blockLocation.y = reader->getDouble(); return true;
8938 case 35: context.blockLocation.z = reader->getDouble(); return true;
8939 case 16: context.blockScale.x = reader->getDouble(); return true;
8940 case 26: context.blockScale.y = reader->getDouble(); return true;
8941 case 36: context.blockScale.z = reader->getDouble(); return true;
8942 case 46: context.blockRotation = reader->getDouble(); return true;
8943 case 93: context.blockColor = reader->getInt32(); return true;
8944 /* common tail */
8945 case 110: context.basePoint.x = reader->getDouble(); return true;
8946 case 120: context.basePoint.y = reader->getDouble(); return true;
8947 case 130: context.basePoint.z = reader->getDouble(); return true;
8948 case 111: context.baseDirection.x = reader->getDouble(); return true;
8949 case 121: context.baseDirection.y = reader->getDouble(); return true;
8950 case 131: context.baseDirection.z = reader->getDouble(); return true;
8951 case 112: context.baseVertical.x = reader->getDouble(); return true;
8952 case 122: context.baseVertical.y = reader->getDouble(); return true;
8953 case 132: context.baseVertical.z = reader->getDouble(); return true;
8954 case 297: context.isNormalReversed = (reader->getInt32() != 0); return true;
8955 case 272: context.styleBottomAttach = reader->getInt32(); return true;
8956 case 273: context.styleTopAttach = reader->getInt32(); return true;
8957 default: return true; // swallow any other context code
8958 }
8959}
8960
8961bool DRW_MLeader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
8962 // The embedded CONTEXT_DATA{} block (§20.4.86) is routed by the nested-block
8963 // state machine; the remaining (entity-level) fields are read below and
8964 // mirror the DWG body parser.
8965 if (parseDxfContextCode(code, reader))
8966 return true;
8967 switch (code) {
8968 case 170: leaderType = reader->getInt32(); break;
8969 case 171: leaderLineWeight = reader->getInt32(); break;
8970 case 172: styleContentType = reader->getInt32(); break;
8971 case 173: styleLeftAttach = reader->getInt32(); break;
8972 case 95: styleRightAttach = reader->getInt32(); break;
8973 case 174: styleTextAngleType = reader->getInt32(); break;
8974 case 175: unknown175 = reader->getInt32(); break;
8975 case 176: styleAttachmentType = reader->getInt32(); break;
8976 case 178: ipeAlign = reader->getInt32(); break;
8977 case 179: justification = reader->getInt32(); break;
8978 case 271: attachmentDirection = reader->getInt32(); break;
8979 case 272: styleBottomAttach = reader->getInt32(); break;
8980 case 273: styleTopAttach = reader->getInt32(); break;
8981 case 90: overrideFlags = reader->getInt32(); break;
8982 case 91: leaderColor = reader->getInt32(); break;
8983 case 92: styleTextColor = reader->getInt32(); break;
8984 case 93: styleBlockColor = reader->getInt32(); break;
8985 case 41: landingDistance = reader->getDouble(); break;
8986 case 42: defaultArrowHeadSize = reader->getDouble(); break;
8987 case 43: styleBlockRotation = reader->getDouble(); break;
8988 case 45: scaleFactor = reader->getDouble(); break;
8989 case 290: landingEnabled = (reader->getInt32() != 0); break;
8990 case 291: doglegEnabled = (reader->getInt32() != 0); break;
8991 case 292: styleTextFrameEnabled = (reader->getInt32() != 0); break;
8992 case 293: isAnnotative = (reader->getInt32() != 0); break;
8993 case 294: isTextDirectionNegative = (reader->getInt32() != 0); break;
8994 case 295: leaderExtendedToText = (reader->getInt32() != 0); break;
8995 default:
8996 return DRW_Entity::parseCode(code, reader);
8997 }
8998 return true;
8999}
9000
9001// Helper: parse one AcDbMLeaderObjectContextData::LeaderRoot entry (§20.4.86).
9002//
9003// Each root has: connection point + direction, optional break pairs, leader
9004// index, landing distance, then a count-and-list of leader lines. Lines
9005// themselves carry: point list, break-info pairs, and (R2010+) per-line
9006// style overrides. The handles inside (line-type / arrow per leader line)
9007// are deferred to the entity-level handle stream and not stored here.
9008static bool parseMLeaderRoot(DRW::Version version, dwgBuffer *buf,
9009 DRW_MLeaderRoot& root) {
9010 // Layout per libreDWG dwg2.spec:1316-1366 (Dwg_LEADER_Node + Dwg_LEADER_Line).
9011 // The two 3BD coords at the head of the node are conditional on the
9012 // preceding B flags; reading them unconditionally drifts the bit stream
9013 // when either flag is 0.
9014 bool hasLastPt = buf->getBit(); // 290 has_lastleaderlinepoint
9015 bool hasDogleg = buf->getBit(); // 291 has_dogleg
9016 root.isContentValid = hasLastPt;
9017 root.unknown291 = hasDogleg;
9018 if (hasLastPt) root.connectionPoint = buf->get3BitDouble();
9019 if (hasDogleg) root.direction = buf->get3BitDouble();
9020
9021 std::int32_t nBreaks = buf->getBitLong();
9022 if (nBreaks < 0 || nBreaks > 5000) return false; // libreDWG MAX_LEADER_NUMBER
9023 root.breaks.reserve(static_cast<size_t>(nBreaks));
9024 for (std::int32_t i = 0; i < nBreaks; ++i) {
9025 DRW_Coord a = buf->get3BitDouble();
9026 DRW_Coord b = buf->get3BitDouble();
9027 root.breaks.emplace_back(a, b);
9028 }
9029
9030 root.leaderIndex = buf->getBitLong(); // 90 branch_index
9031 root.landingDistance = buf->getBitDouble(); // 40 dogleg_length
9032
9033 std::int32_t nLines = buf->getBitLong();
9034 if (nLines < 0 || nLines > 5000) return false;
9035 root.leaderLines.reserve(static_cast<size_t>(nLines));
9036 for (std::int32_t i = 0; i < nLines; ++i) {
9037 DRW_MLeaderLeaderLine line;
9038 // Per libreDWG: BL num_points, points, BL num_breaks, breaks, BL line_index.
9039 // The previous 5-BL layout (brkInfoCount + segmentIndex + nPairs +
9040 // pairs + leaderLineIndex) inserted two spurious BL reads, drifting
9041 // every subsequent entity-level field (overallScale, contentType, …).
9042 std::int32_t nPts = buf->getBitLong();
9043 if (nPts < 0 || nPts > 5000) return false;
9044 line.points.reserve(static_cast<size_t>(nPts));
9045 for (std::int32_t j = 0; j < nPts; ++j) {
9046 line.points.push_back(buf->get3BitDouble());
9047 }
9048 std::int32_t nLineBreaks = buf->getBitLong();
9049 if (nLineBreaks < 0 || nLineBreaks > 5000) return false;
9050 for (std::int32_t j = 0; j < nLineBreaks; ++j) {
9051 DRW_Coord a = buf->get3BitDouble();
9052 DRW_Coord b = buf->get3BitDouble();
9053 line.breaks.emplace_back(a, b);
9054 }
9055 line.leaderLineIndex = buf->getBitLong(); // 91 line_index
9056
9057 // R2010+ per-line override block. The spec marks this block "R2010"
9058 // (§20.4.86 page 215); the override flags BL 93 says which fields
9059 // were overridden. The handle fields (340 line-type, 341 arrow) are
9060 // deferred to the trailing handle stream.
9061 if (version >= DRW::AC1024) {
9062 line.leaderType = buf->getBitShort();
9063 line.color = buf->getCmColor(version);
9064 // line type handle 340 — read from handles section later
9065 line.lineWeight = buf->getBitLong();
9066 line.arrowSize = buf->getBitDouble();
9067 // arrow handle 341 — handles section
9068 line.overrideFlags = buf->getBitLong();
9069 }
9070 root.leaderLines.push_back(std::move(line));
9071 }
9072
9073 if (version >= DRW::AC1024) {
9074 root.attachmentDirection = buf->getBitShort();
9075 }
9076
9077 return buf->isGood();
9078}
9079
9080// Helper: parse the AcDbMLeaderObjectContextData (§20.4.86) payload, the
9081// large embedded block at the start of the MLEADER body that carries the
9082// leader geometry plus either text or block content.
9083static bool parseMLeaderAnnotContext(DRW::Version version, dwgBuffer *buf,
9084 dwgBuffer *sBuf,
9085 DRW_MLeaderAnnotContext& ctx) {
9086 // NOTE: when AcDbMLeaderObjectContextData is embedded INSIDE the MLEADER
9087 // entity body (rather than serialized as a standalone object), the
9088 // AcDbObjectContextData base preamble (BS version, B has-file-ext-dict,
9089 // B default-flag) does NOT appear in the bit stream — those fields are
9090 // standalone-object metadata. The embedded AnnotContext starts directly
9091 // with the leader-roots count. AcDbAnnotScaleObjectContextData's scale
9092 // handle is deferred to the trailing handle stream.
9093
9094 // Number of leader roots.
9095 std::int32_t nRoots = buf->getBitLong();
9096 if (nRoots == 0) {
9097 bool rootCountBits[7] = {};
9098 for (bool& rootCountBit : rootCountBits)
9099 rootCountBit = buf->getBit() != 0;
9100 nRoots = rootCountBits[5] ? 2 : 1;
9101 }
9102 if (nRoots < 0 || nRoots > 1000000) return false;
9103 ctx.roots.clear();
9104 ctx.roots.reserve(static_cast<size_t>(nRoots));
9105 for (std::int32_t i = 0; i < nRoots; ++i) {
9106 DRW_MLeaderRoot root;
9107 if (!parseMLeaderRoot(version, buf, root)) return false;
9108 ctx.roots.push_back(std::move(root));
9109 }
9110
9111 // Common content fields.
9112 ctx.overallScale = buf->getBitDouble();
9113 ctx.contentBasePoint = buf->get3BitDouble();
9114 ctx.textHeight = buf->getBitDouble();
9115 ctx.arrowHeadSize = buf->getBitDouble();
9116 ctx.landingGap = buf->getBitDouble();
9117 ctx.styleLeftAttach = buf->getBitShort();
9118 ctx.styleRightAttach = buf->getBitShort();
9119 ctx.textAlignType = buf->getBitShort();
9120 ctx.attachmentType = buf->getBitShort();
9121 ctx.hasTextContents = buf->getBit();
9122
9123 if (ctx.hasTextContents) {
9124 ctx.textLabel = sBuf->getVariableText(version, false);
9125 ctx.textNormal = buf->get3BitDouble();
9126 // text style handle 340 — handles section
9127 ctx.textLocation = buf->get3BitDouble();
9128 ctx.textDirection = buf->get3BitDouble();
9129 ctx.textRotation = buf->getBitDouble();
9130 ctx.boundaryWidth = buf->getBitDouble();
9131 ctx.boundaryHeight = buf->getBitDouble();
9132 ctx.lineSpacingFactor = buf->getBitDouble();
9133 ctx.lineSpacingStyle = buf->getBitShort();
9134 ctx.textColor = buf->getCmColor(version);
9135 ctx.alignment = buf->getBitShort();
9136 ctx.flowDirection = buf->getBitShort();
9137 ctx.bgFillColor = buf->getCmColor(version);
9138 ctx.bgScaleFactor = buf->getBitDouble();
9139 ctx.bgTransparency = buf->getBitLong();
9140 ctx.bgFillEnabled = buf->getBit();
9141 ctx.bgMaskFillOn = buf->getBit();
9142 ctx.columnType = buf->getBitShort();
9143 ctx.textHeightAuto = buf->getBit();
9144 ctx.columnWidth = buf->getBitDouble();
9145 ctx.columnGutter = buf->getBitDouble();
9146 ctx.columnFlowReversed = buf->getBit();
9147 std::int32_t nColSizes = buf->getBitLong();
9148 if (nColSizes < 0 || nColSizes > 1000000) return false;
9149 ctx.columnSizes.reserve(static_cast<size_t>(nColSizes));
9150 for (std::int32_t i = 0; i < nColSizes; ++i) {
9151 ctx.columnSizes.push_back(buf->getBitDouble());
9152 }
9153 ctx.wordBreak = buf->getBit();
9154 buf->getBit(); // unknown trailing bit
9155 } else {
9156 ctx.hasContentsBlock = buf->getBit();
9157 if (ctx.hasContentsBlock) {
9158 // BlockTableRecord handle 341 — deferred
9159 ctx.blockNormal = buf->get3BitDouble();
9160 ctx.blockLocation = buf->get3BitDouble();
9161 ctx.blockScale = buf->get3BitDouble();
9162 ctx.blockRotation = buf->getBitDouble();
9163 ctx.blockColor = buf->getCmColor(version);
9164 for (size_t i = 0; i < 16; ++i) {
9165 ctx.blockTransform[i] = buf->getBitDouble();
9166 }
9167 }
9168 }
9169
9170 // Common tail.
9171 ctx.basePoint = buf->get3BitDouble();
9172 ctx.baseDirection = buf->get3BitDouble();
9173 ctx.baseVertical = buf->get3BitDouble();
9174 ctx.isNormalReversed = buf->getBit();
9175
9176 if (version >= DRW::AC1024) {
9177 ctx.styleTopAttach = buf->getBitShort();
9178 ctx.styleBottomAttach = buf->getBitShort();
9179 }
9180
9181 return buf->isGood();
9182}
9183
9184static bool encodeMLeaderRoot(DRW::Version version, dwgBufferW *buf,
9185 const DRW_MLeaderRoot& root) {
9186 if (root.breaks.size() > 5000 || root.leaderLines.size() > 5000)
9187 return false;
9188
9189 buf->putBit(root.isContentValid ? 1 : 0);
9190 buf->putBit(root.unknown291 ? 1 : 0);
9191 if (root.isContentValid)
9192 buf->put3BitDouble(root.connectionPoint);
9193 if (root.unknown291)
9194 buf->put3BitDouble(root.direction);
9195
9196 buf->putBitLong(static_cast<std::int32_t>(root.breaks.size()));
9197 for (const auto& brk : root.breaks) {
9198 buf->put3BitDouble(brk.first);
9199 buf->put3BitDouble(brk.second);
9200 }
9201
9202 buf->putBitLong(root.leaderIndex);
9203 buf->putBitDouble(root.landingDistance);
9204
9205 buf->putBitLong(static_cast<std::int32_t>(root.leaderLines.size()));
9206 for (const DRW_MLeaderLeaderLine& line : root.leaderLines) {
9207 if (line.points.size() > 5000 || line.breaks.size() > 5000)
9208 return false;
9209 buf->putBitLong(static_cast<std::int32_t>(line.points.size()));
9210 for (const DRW_Coord& point : line.points)
9211 buf->put3BitDouble(point);
9212
9213 buf->putBitLong(static_cast<std::int32_t>(line.breaks.size()));
9214 for (const auto& brk : line.breaks) {
9215 buf->put3BitDouble(brk.first);
9216 buf->put3BitDouble(brk.second);
9217 }
9218 buf->putBitLong(line.leaderLineIndex);
9219
9220 if (version >= DRW::AC1024) {
9221 buf->putBitShort(line.leaderType);
9222 buf->putCmColor(version, static_cast<std::uint16_t>(line.color));
9223 buf->putBitLong(line.lineWeight);
9224 buf->putBitDouble(line.arrowSize);
9225 buf->putBitLong(line.overrideFlags);
9226 }
9227 }
9228
9229 if (version >= DRW::AC1024)
9230 buf->putBitShort(root.attachmentDirection);
9231
9232 return true;
9233}
9234
9235static bool encodeMLeaderAnnotContext(DRW::Version version, dwgBufferW *buf,
9236 dwgBufferW *strBuf,
9237 const DRW_MLeaderAnnotContext& ctx) {
9238 if (ctx.roots.size() > 1000000 || ctx.columnSizes.size() > 1000000)
9239 return false;
9240 if (ctx.hasContentsBlock)
9241 return false;
9242
9243 buf->putBitLong(static_cast<std::int32_t>(ctx.roots.size()));
9244 for (const DRW_MLeaderRoot& root : ctx.roots) {
9245 if (!encodeMLeaderRoot(version, buf, root))
9246 return false;
9247 }
9248
9249 buf->putBitDouble(ctx.overallScale);
9250 buf->put3BitDouble(ctx.contentBasePoint);
9251 buf->putBitDouble(ctx.textHeight);
9252 buf->putBitDouble(ctx.arrowHeadSize);
9253 buf->putBitDouble(ctx.landingGap);
9254 buf->putBitShort(ctx.styleLeftAttach);
9255 buf->putBitShort(ctx.styleRightAttach);
9256 buf->putBitShort(ctx.textAlignType);
9257 buf->putBitShort(ctx.attachmentType);
9258 buf->putBit(ctx.hasTextContents ? 1 : 0);
9259
9260 if (ctx.hasTextContents) {
9261 (strBuf ? strBuf : buf)->putVariableText(version, ctx.textLabel);
9262 buf->put3BitDouble(ctx.textNormal);
9263 buf->put3BitDouble(ctx.textLocation);
9264 buf->put3BitDouble(ctx.textDirection);
9265 buf->putBitDouble(ctx.textRotation);
9266 buf->putBitDouble(ctx.boundaryWidth);
9267 buf->putBitDouble(ctx.boundaryHeight);
9268 buf->putBitDouble(ctx.lineSpacingFactor);
9269 buf->putBitShort(ctx.lineSpacingStyle);
9270 buf->putCmColor(version, static_cast<std::uint16_t>(ctx.textColor));
9271 buf->putBitShort(ctx.alignment);
9272 buf->putBitShort(ctx.flowDirection);
9273 buf->putCmColor(version, static_cast<std::uint16_t>(ctx.bgFillColor));
9274 buf->putBitDouble(ctx.bgScaleFactor);
9275 buf->putBitLong(ctx.bgTransparency);
9276 buf->putBit(ctx.bgFillEnabled ? 1 : 0);
9277 buf->putBit(ctx.bgMaskFillOn ? 1 : 0);
9278 buf->putBitShort(ctx.columnType);
9279 buf->putBit(ctx.textHeightAuto ? 1 : 0);
9280 buf->putBitDouble(ctx.columnWidth);
9281 buf->putBitDouble(ctx.columnGutter);
9282 buf->putBit(ctx.columnFlowReversed ? 1 : 0);
9283 buf->putBitLong(static_cast<std::int32_t>(ctx.columnSizes.size()));
9284 for (double columnSize : ctx.columnSizes)
9285 buf->putBitDouble(columnSize);
9286 buf->putBit(ctx.wordBreak ? 1 : 0);
9287 buf->putBit(0);
9288 } else {
9289 buf->putBit(0); // hasContentsBlock
9290 }
9291
9292 buf->put3BitDouble(ctx.basePoint);
9293 buf->put3BitDouble(ctx.baseDirection);
9294 buf->put3BitDouble(ctx.baseVertical);
9295 buf->putBit(ctx.isNormalReversed ? 1 : 0);
9296
9297 if (version >= DRW::AC1024) {
9298 buf->putBitShort(ctx.styleTopAttach);
9299 buf->putBitShort(ctx.styleBottomAttach);
9300 }
9301
9302 return true;
9303}
9304
9305bool DRW_MLeader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
9306 dwgBuffer sBuff = *buf;
9307 dwgBuffer *sBuf = buf;
9308 if (version > DRW::AC1018) { // 2007+
9309 sBuf = &sBuff;
9310 }
9311 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
9312 if (!ret) return ret;
9313 DRW_DBG("\n***************************** parsing MLEADER ***************\n")DRW_dbg::dbg("\n***************************** parsing MLEADER ***************\n"
)
;
9314
9315 // R2010b+ class version (BS, default 2; <=R2004 was 1). libreDWG
9316 // dwg2.spec:1303-1306. Absent in R2007 streams; reading it would drift.
9317 if (version >= DRW::AC1024) {
9318 classVersion = buf->getBitShort();
9319 if (classVersion > 10) {
9320 DRW_DBG("\nMLEADER: implausible classVersion=")DRW_dbg::dbg("\nMLEADER: implausible classVersion=");
9321 DRW_DBG(static_cast<int>(classVersion))DRW_dbg::dbg(static_cast<int>(classVersion));
9322 DRW_DBG(", aborting body\n")DRW_dbg::dbg(", aborting body\n");
9323 return true;
9324 }
9325 }
9326
9327 // Phase 4 — embedded AcDbMLeaderObjectContextData / MLeaderAnnotContext.
9328 // Body misalignment is local to this entity's buffer (each entity gets a
9329 // fresh buffer from the object map), so on a partial-parse failure we
9330 // keep whatever was captured and return true. This preserves the
9331 // entity-stream-continues invariant established in Phase 2.
9332 if (!parseMLeaderAnnotContext(version, buf, sBuf, context)) {
9333 DRW_DBG("\nMLEADER: AnnotContext parse drift — partial fields kept\n")DRW_dbg::dbg("\nMLEADER: AnnotContext parse drift — partial fields kept\n"
)
;
9334 return true;
9335 }
9336
9337 // Phase 3 — entity-level fields per §20.4.48 (after the AnnotContext).
9338 // Many handle slots are deferred to the trailing handle stream and not
9339 // stored here yet (resolution comes in Phase 7).
9340 overrideFlags = buf->getBitLong();
9341 leaderType = buf->getBitShort();
9342 leaderColor = buf->getCmColor(version);
9343 // leader line type handle 341 — handle stream
9344 leaderLineWeight = buf->getBitLong();
9345 landingEnabled = buf->getBit();
9346 doglegEnabled = buf->getBit();
9347 landingDistance = buf->getBitDouble();
9348 // arrow head handle 342 — handle stream
9349 defaultArrowHeadSize = buf->getBitDouble();
9350 styleContentType = buf->getBitShort();
9351 // text style handle 343 — handle stream
9352 styleLeftAttach = buf->getBitShort();
9353 styleRightAttach = buf->getBitShort();
9354 styleTextAngleType = buf->getBitShort();
9355 unknown175 = buf->getBitShort();
9356 styleTextColor = buf->getCmColor(version);
9357 styleTextFrameEnabled = buf->getBit();
9358 // style block handle 344 — handle stream (optional)
9359 styleBlockColor = buf->getCmColor(version);
9360 styleBlockScale = buf->get3BitDouble();
9361 styleBlockRotation = buf->getBitDouble();
9362 styleAttachmentType = buf->getBitShort();
9363 isAnnotative = buf->getBit();
9364
9365 // R2007 arrays (pre-R2010 only): per spec §20.4.48. Bounds-check the
9366 // counts; a misaligned bit stream would produce huge nonsense values.
9367 // On a sanity-check trip, abort the rest of the body parse but keep
9368 // the entity (per Phase 4 contract above).
9369 if (version < DRW::AC1024) {
9370 std::int32_t nArrows = buf->getBitLong();
9371 if (nArrows < 0 || nArrows > 1000000) return true;
9372 arrowHeads.reserve(static_cast<size_t>(nArrows));
9373 for (std::int32_t i = 0; i < nArrows; ++i) {
9374 ArrowHeadEntry e;
9375 e.isDefault = buf->getBit();
9376 arrowHeads.push_back(e);
9377 }
9378 std::int32_t nLabels = buf->getBitLong();
9379 if (nLabels < 0 || nLabels > 1000000) return true;
9380 blockLabels.reserve(static_cast<size_t>(nLabels));
9381 for (std::int32_t i = 0; i < nLabels; ++i) {
9382 BlockLabelEntry e;
9383 e.labelText = sBuf->getVariableText(version, false);
9384 e.uiIndex = buf->getBitShort();
9385 e.width = buf->getBitDouble();
9386 blockLabels.push_back(std::move(e));
9387 }
9388 }
9389
9390 isTextDirectionNegative = buf->getBit();
9391 ipeAlign = buf->getBitShort();
9392 justification = buf->getBitShort();
9393 scaleFactor = buf->getBitDouble();
9394
9395 if (version >= DRW::AC1024) { // R2010+
9396 attachmentDirection = buf->getBitShort();
9397 styleTopAttach = buf->getBitShort();
9398 styleBottomAttach = buf->getBitShort();
9399 }
9400 if (version >= DRW::AC1027) { // R2013+
9401 leaderExtendedToText = buf->getBit();
9402 }
9403
9404 // Common entity handles first (owner/reactors/xdic/layer/ltype/...) —
9405 // entity-specific handles follow in declared order from libreDWG
9406 // dwg2.spec:1386-1453. Read order in the trailing handle stream:
9407 // 1. AnnotContext content handle (text_style 340 if hasTextContents,
9408 // else block_table 341 if hasContentsBlock).
9409 // 2. (R2010b+ only) per-leader-line ltype + arrow handles, in the
9410 // same iteration order as the body block.
9411 // 3. mleaderstyle (340), line_ltype (341), arrow_handle (342),
9412 // text_style (343), block_style (344) entity-level handles.
9413 // 4. (R14-R2007 only) per-arrowhead + per-blocklabel handles.
9414 ret = DRW_Entity::parseDwgEntHandle(version, buf);
9415 if (!ret) {
9416 DRW_DBG("\nMLEADER: parseDwgEntHandle hiccup — body fields kept\n")DRW_dbg::dbg("\nMLEADER: parseDwgEntHandle hiccup — body fields kept\n"
)
;
9417 return true;
9418 }
9419
9420 auto safeHandle = [&](dwgHandle& slot, const char* tag) {
9421 if (buf->numRemainingBytes() < 1) return false;
9422 slot = buf->getHandle();
9423 DRW_DBG(" ")DRW_dbg::dbg(" "); DRW_DBG(tag)DRW_dbg::dbg(tag); DRW_DBG(": ")DRW_dbg::dbg(": ");
9424 DRW_DBGHL(slot.code, slot.size, slot.ref)DRW_dbg::dbgHL(slot.code, slot.size, slot.ref); DRW_DBG("\n")DRW_dbg::dbg("\n");
9425 return buf->isGood();
9426 };
9427
9428 // 1. AnnotContext content handle.
9429 if (context.hasTextContents) {
9430 if (!safeHandle(context.textStyleHandle, "ctx.text_style")) return true;
9431 } else if (context.hasContentsBlock) {
9432 if (!safeHandle(context.blockTableRecordHandle, "ctx.block_table")) return true;
9433 }
9434
9435 // 2. R2010b+ per-line handles, in body iteration order.
9436 if (version >= DRW::AC1024) {
9437 for (auto& root : context.roots) {
9438 for (auto& line : root.leaderLines) {
9439 if (!safeHandle(line.lineTypeHandle, "line.ltype")) return true;
9440 if (!safeHandle(line.arrowHandle, "line.arrow")) return true;
9441 }
9442 }
9443 }
9444
9445 // 3. Entity-level handles.
9446 if (!safeHandle(styleHandle, "mleaderstyle")) return true;
9447 if (!safeHandle(leaderLineTypeHandle, "line_ltype")) return true;
9448 if (!safeHandle(arrowHeadHandle, "arrow_handle")) return true;
9449 if (!safeHandle(styleTextStyleHandle, "text_style")) return true;
9450 if (!safeHandle(styleBlockHandle, "block_style")) return true;
9451
9452 // 4. R14-R2007 per-arrowhead + per-blocklabel handles (counts came
9453 // from the body-side arrays read earlier).
9454 if (version < DRW::AC1024) {
9455 for (auto& a : arrowHeads)
9456 if (!safeHandle(a.handle, "arrowheads.handle")) return true;
9457 for (auto& bl : blockLabels)
9458 if (!safeHandle(bl.attDefHandle, "blocklabels.attdef")) return true;
9459 }
9460
9461 const int rb = buf->numRemainingBytes();
9462 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");
9463 if (rb > 4) {
9464 DRW_DBG("MLEADER: handle-stream tail ")DRW_dbg::dbg("MLEADER: handle-stream tail "); DRW_DBG(rb)DRW_dbg::dbg(rb);
9465 DRW_DBG(" bytes unconsumed (handle ")DRW_dbg::dbg(" bytes unconsumed (handle ");
9466 DRW_DBGH(handle)DRW_dbg::dbgH(handle); DRW_DBG(") — review tail handle list\n")DRW_dbg::dbg(") — review tail handle list\n");
9467 }
9468
9469 return true;
9470}
9471
9472bool DRW_MLeader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9473 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9474 (void)bs;
9475 if (version < DRW::AC1024)
9476 return false;
9477
9478 oType = kDwgClassNum;
9479 if (!encodeDwgCommon(version, buf, strBuf))
9480 return false;
9481
9482 buf->putBitShort(classVersion == 0 ? 2 : classVersion);
9483 if (!encodeMLeaderAnnotContext(version, buf, strBuf, context))
9484 return false;
9485
9486 buf->putBitLong(overrideFlags);
9487 buf->putBitShort(leaderType);
9488 buf->putCmColor(version, static_cast<std::uint16_t>(leaderColor));
9489 buf->putBitLong(leaderLineWeight);
9490 buf->putBit(landingEnabled ? 1 : 0);
9491 buf->putBit(doglegEnabled ? 1 : 0);
9492 buf->putBitDouble(landingDistance);
9493 buf->putBitDouble(defaultArrowHeadSize);
9494 buf->putBitShort(styleContentType);
9495 buf->putBitShort(styleLeftAttach);
9496 buf->putBitShort(styleRightAttach);
9497 buf->putBitShort(styleTextAngleType);
9498 buf->putBitShort(unknown175);
9499 buf->putCmColor(version, static_cast<std::uint16_t>(styleTextColor));
9500 buf->putBit(styleTextFrameEnabled ? 1 : 0);
9501 buf->putCmColor(version, static_cast<std::uint16_t>(styleBlockColor));
9502 buf->put3BitDouble(styleBlockScale);
9503 buf->putBitDouble(styleBlockRotation);
9504 buf->putBitShort(styleAttachmentType);
9505 buf->putBit(isAnnotative ? 1 : 0);
9506 buf->putBit(isTextDirectionNegative ? 1 : 0);
9507 buf->putBitShort(ipeAlign);
9508 buf->putBitShort(justification);
9509 buf->putBitDouble(scaleFactor);
9510
9511 buf->putBitShort(attachmentDirection);
9512 buf->putBitShort(styleTopAttach);
9513 buf->putBitShort(styleBottomAttach);
9514 if (version >= DRW::AC1027)
9515 buf->putBit(leaderExtendedToText ? 1 : 0);
9516
9517 if (!encodeDwgEntHandle(version, buf, handleBuf))
9518 return false;
9519
9520 dwgBufferW *hb = handleBuf ? handleBuf : buf;
9521 if (context.hasTextContents) {
9522 putHardPointerHandle(hb, context.textStyleHandle.ref);
9523 } else if (context.hasContentsBlock) {
9524 putHardPointerHandle(hb, context.blockTableRecordHandle.ref);
9525 }
9526
9527 for (const DRW_MLeaderRoot& root : context.roots) {
9528 for (const DRW_MLeaderLeaderLine& line : root.leaderLines) {
9529 putHardPointerHandle(hb, line.lineTypeHandle.ref);
9530 putHardPointerHandle(hb, line.arrowHandle.ref);
9531 }
9532 }
9533
9534 putHardPointerHandle(hb, styleHandle.ref);
9535 putHardPointerHandle(hb, leaderLineTypeHandle.ref);
9536 putHardPointerHandle(hb, arrowHeadHandle.ref);
9537 putHardPointerHandle(hb, styleTextStyleHandle.ref);
9538 putHardPointerHandle(hb, styleBlockHandle.ref);
9539
9540 return true;
9541}
9542
9543bool DRW_Viewport::parseCode(int code, const std::unique_ptr<dxfReader>& reader){
9544 switch (code) {
9545 case 40:
9546 pswidth = reader->getDouble();
9547 break;
9548 case 41:
9549 psheight = reader->getDouble();
9550 break;
9551 case 68:
9552 vpstatus = reader->getInt32();
9553 break;
9554 case 69:
9555 vpID = reader->getInt32();
9556 break;
9557 case 12:
9558 centerPX = reader->getDouble();
9559 break;
9560 case 22:
9561 centerPY = reader->getDouble();
9562 break;
9563 case 15:
9564 gridSpX = reader->getDouble();
9565 break;
9566 case 25:
9567 gridSpY = reader->getDouble();
9568 break;
9569 case 46:
9570 circleZoom = reader->getDouble();
9571 break;
9572 case 72:
9573 majorGridLines = reader->getInt32();
9574 break;
9575 case 90:
9576 statusFlags = reader->getInt32();
9577 break;
9578 case 1:
9579 styleSheet = reader->getUtf8String();
9580 break;
9581 case 281:
9582 renderMode = reader->getInt32();
9583 break;
9584 case 71:
9585 ucsAtOrigin = reader->getInt32() != 0;
9586 break;
9587 case 74:
9588 ucsPerViewport = reader->getInt32() != 0;
9589 break;
9590 case 110:
9591 ucsOrigin.x = reader->getDouble();
9592 break;
9593 case 120:
9594 ucsOrigin.y = reader->getDouble();
9595 break;
9596 case 130:
9597 ucsOrigin.z = reader->getDouble();
9598 break;
9599 case 111:
9600 ucsXAxis.x = reader->getDouble();
9601 break;
9602 case 121:
9603 ucsXAxis.y = reader->getDouble();
9604 break;
9605 case 131:
9606 ucsXAxis.z = reader->getDouble();
9607 break;
9608 case 112:
9609 ucsYAxis.x = reader->getDouble();
9610 break;
9611 case 122:
9612 ucsYAxis.y = reader->getDouble();
9613 break;
9614 case 132:
9615 ucsYAxis.z = reader->getDouble();
9616 break;
9617 case 146:
9618 ucsElevation = reader->getDouble();
9619 break;
9620 case 76:
9621 ucsOrthographicType = reader->getInt32();
9622 break;
9623 case 148:
9624 shadePlotMode = reader->getInt32();
9625 break;
9626 case 292:
9627 useDefaultLighting = reader->getInt32() != 0;
9628 break;
9629 case 282:
9630 defaultLightingType = reader->getInt32();
9631 break;
9632 case 451:
9633 brightness = reader->getDouble();
9634 break;
9635 case 452:
9636 contrast = reader->getDouble();
9637 break;
9638 case 421:
9639 ambientColorRgb = reader->getInt32();
9640 break;
9641 case 431:
9642 ambientColorMethod = reader->getInt32();
9643 break;
9644 case 331:
9645 vpHeaderHandle = static_cast<std::uint32_t>(reader->getHandleString());
9646 break;
9647 case 340:
9648 clipBoundaryHandle = static_cast<std::uint32_t>(reader->getHandleString());
9649 break;
9650 case 345:
9651 namedUcsHandle = static_cast<std::uint32_t>(reader->getHandleString());
9652 break;
9653 case 346:
9654 baseUcsHandle = static_cast<std::uint32_t>(reader->getHandleString());
9655 break;
9656 case 347:
9657 backgroundHandle = static_cast<std::uint32_t>(reader->getHandleString());
9658 break;
9659 case 348:
9660 visualStyleHandle = static_cast<std::uint32_t>(reader->getHandleString());
9661 break;
9662 case 349:
9663 shadePlotHandle = static_cast<std::uint32_t>(reader->getHandleString());
9664 break;
9665 default:
9666 return DRW_Point::parseCode(code, reader);
9667 }
9668
9669 return true;
9670}
9671//ex 22 dec 34
9672bool DRW_Viewport::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){
9673 dwgBuffer sBuff = *buf;
9674 dwgBuffer *sBuf = buf;
9675 if (version > DRW::AC1018) {//2007+
9676 sBuf = &sBuff; //separate buffer for strings
9677 }
9678 bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs);
9679 if (!ret)
9680 return ret;
9681 DRW_DBG("\n***************************** parsing viewport *****************************************\n")DRW_dbg::dbg("\n***************************** parsing viewport *****************************************\n"
)
;
9682 basePoint.x = buf->getBitDouble();
9683 basePoint.y = buf->getBitDouble();
9684 basePoint.z = buf->getBitDouble();
9685 DRW_DBG("center ")DRW_dbg::dbg("center "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z);
9686 pswidth = buf->getBitDouble();
9687 psheight = buf->getBitDouble();
9688 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");
9689 //RLZ TODO: complete in dxf
9690 if (version > DRW::AC1014) {//2000+
9691 viewTarget.x = buf->getBitDouble();
9692 viewTarget.y = buf->getBitDouble();
9693 viewTarget.z = buf->getBitDouble();
9694 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);
9695 viewDir.x = buf->getBitDouble();
9696 viewDir.y = buf->getBitDouble();
9697 viewDir.z = buf->getBitDouble();
9698 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);
9699 twistAngle = buf->getBitDouble();
9700 DRW_DBG("\nView twist Angle: ")DRW_dbg::dbg("\nView twist Angle: "); DRW_DBG(twistAngle)DRW_dbg::dbg(twistAngle);
9701 viewHeight = buf->getBitDouble();
9702 DRW_DBG("\nview Height: ")DRW_dbg::dbg("\nview Height: "); DRW_DBG(viewHeight)DRW_dbg::dbg(viewHeight);
9703 viewLength = buf->getBitDouble();
9704 DRW_DBG(" Lens Length: ")DRW_dbg::dbg(" Lens Length: "); DRW_DBG(viewLength)DRW_dbg::dbg(viewLength);
9705 frontClip = buf->getBitDouble();
9706 DRW_DBG("\nfront Clip Z: ")DRW_dbg::dbg("\nfront Clip Z: "); DRW_DBG(frontClip)DRW_dbg::dbg(frontClip);
9707 backClip = buf->getBitDouble();
9708 DRW_DBG(" back Clip Z: ")DRW_dbg::dbg(" back Clip Z: "); DRW_DBG(backClip)DRW_dbg::dbg(backClip);
9709 snapAngle = buf->getBitDouble();
9710 DRW_DBG("\n snap Angle: ")DRW_dbg::dbg("\n snap Angle: "); DRW_DBG(snapAngle)DRW_dbg::dbg(snapAngle);
9711 centerPX = buf->getRawDouble();
9712 centerPY = buf->getRawDouble();
9713 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);
9714 snapPX = buf->getRawDouble();
9715 snapPY = buf->getRawDouble();
9716 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);
9717 snapSpPX = buf->getRawDouble();
9718 snapSpPY = buf->getRawDouble();
9719 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);
9720 //RLZ: need to complete
9721 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");
9722 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");
9723 }
9724 if (version > DRW::AC1018) {//2007+
9725 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");
9726 }
9727 if (version > DRW::AC1014) {//2000+
9728 frozenLyCount = buf->getBitLong();
9729 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");
9730 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");
9731 //RLZ: Warning needed separate string buffer
9732 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");
9733 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");
9734 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");
9735 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");
9736 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");
9737 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");
9738 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");
9739 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");
9740 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");
9741 }
9742 if (version > DRW::AC1015) {//2004+
9743 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");
9744 }
9745 if (version > DRW::AC1018) {//2007+
9746 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");
9747 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");
9748 DRW_DBG("Brightness: ")DRW_dbg::dbg("Brightness: "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9749 DRW_DBG("Contrast: ")DRW_dbg::dbg("Contrast: "); DRW_DBG(buf->getBitDouble())DRW_dbg::dbg(buf->getBitDouble()); DRW_DBG("\n")DRW_dbg::dbg("\n");
9750 // ODA §20.4.38: ambient color is CMC, not ENC — confirmed by libreDWG dwg.spec:2512
9751 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");
9752 }
9753 ret = DRW_Entity::parseDwgEntHandle(version, buf);
9754
9755 dwgHandle someHdl;
9756 if (version < DRW::AC1015) {//R13 & R14 only
9757 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");
9758 someHdl = buf->getHandle();
9759 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");
9760 }
9761 if (version > DRW::AC1014) {//2000+
9762 for (std::uint32_t i=0; i < frozenLyCount && buf->isGood(); ++i){
9763 someHdl = buf->getHandle();
9764 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");
9765 }
9766 someHdl = buf->getHandle();
9767 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");
9768 if (version == DRW::AC1015) {//2000 only
9769 someHdl = buf->getHandle();
9770 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");
9771 }
9772 someHdl = buf->getHandle();
9773 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");
9774 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");
9775 someHdl = buf->getHandle();
9776 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");
9777 }
9778 if (version > DRW::AC1018) {//2007+
9779 someHdl = buf->getHandle();
9780 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");
9781 someHdl = buf->getHandle();
9782 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");
9783 someHdl = buf->getHandle();
9784 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");
9785 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");
9786 someHdl = buf->getHandle();
9787 m_sunHandle = someHdl.ref;
9788 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");
9789 }
9790 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");
9791
9792 if (!ret)
9793 return ret;
9794 return buf->isGood();
9795}
9796
9797// ---------------------------------------------------------------------------
9798// Write helpers shared by the new encoders below.
9799// ---------------------------------------------------------------------------
9800
9801namespace {
9802// Write an absolute hard-pointer handle (code=5, ref=ref) or null handle
9803// (code=3, ref=0) depending on whether ref is non-zero.
9804static void putAbsHandle(dwgBufferW *hb, std::uint32_t ref) {
9805 dwgHandle h;
9806 h.code = (ref != 0) ? 5 : 3;
9807 h.ref = ref;
9808 h.size = 0;
9809 if (h.ref != 0) {
9810 std::uint32_t t = h.ref;
9811 while (t != 0) { t >>= 8; ++h.size; }
9812 }
9813 hb->putHandle(h);
9814}
9815} // namespace
9816
9817// ---------------------------------------------------------------------------
9818// DRW_MLine::encodeDwg — OT=47 (AC1015/AC1018/AC1024)
9819// ---------------------------------------------------------------------------
9820
9821bool DRW_MLine::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9822 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9823 (void)bs; (void)strBuf;
9824 oType = 47;
9825 if (!encodeDwgCommon(version, buf)) return false;
9826
9827 buf->putBitDouble(scale);
9828 buf->putRawChar8(justification);
9829 buf->put3BitDouble(basePoint);
9830 buf->putExtrusion(extPoint, false); // false = pre-2000 style (getExtrusion(false) in parser)
9831 buf->putBitShort(static_cast<std::uint16_t>(openClosed));
9832 buf->putRawChar8(numLines);
9833 buf->putBitShort(numVerts);
9834
9835 for (const auto& vtx : vertlist) {
9836 buf->put3BitDouble(vtx.position);
9837 buf->put3BitDouble(vtx.vertexDir);
9838 buf->put3BitDouble(vtx.miterDir);
9839 for (int li = 0; li < static_cast<int>(numLines); ++li) {
9840 const auto& segs = (li < static_cast<int>(vtx.segParms.size()))
9841 ? vtx.segParms[li] : std::vector<double>{};
9842 const auto& fills = (li < static_cast<int>(vtx.areaFillParms.size()))
9843 ? vtx.areaFillParms[li] : std::vector<double>{};
9844 buf->putBitShort(static_cast<std::uint16_t>(segs.size()));
9845 for (double s : segs) buf->putBitDouble(s);
9846 buf->putBitShort(static_cast<std::uint16_t>(fills.size()));
9847 for (double f : fills) buf->putBitDouble(f);
9848 }
9849 }
9850
9851 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
9852
9853 // MLINE style handle — extra handle after standard entity handles.
9854 if (version > DRW::AC1014) {
9855 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
9856 putAbsHandle(hb, styleHandle);
9857 }
9858 return true;
9859}
9860
9861// ---------------------------------------------------------------------------
9862// DRW_Vertex::encodeDwg — OT varies by flags
9863// ---------------------------------------------------------------------------
9864
9865bool DRW_Vertex::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9866 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9867 (void)bs; (void)strBuf;
9868 switch (m_dwgSubtype) {
9869 case DwgSubtype::Vertex2D: oType = 0x0A; break;
9870 case DwgSubtype::Vertex3D: oType = 0x0B; break;
9871 case DwgSubtype::Mesh: oType = 0x0C; break;
9872 case DwgSubtype::Polyface: oType = 0x0D; break;
9873 case DwgSubtype::PolyfaceFace: oType = 0x0E; break;
9874 case DwgSubtype::Auto:
9875 if ((flags & 64) != 0)
9876 oType = 0x0D; // VERTEX_PFACE coordinate vertex
9877 else if ((flags & 128) != 0)
9878 oType = 0x0E; // VERTEX_PFACE_FACE
9879 else if ((flags & 16) != 0)
9880 oType = 0x0C; // VERTEX_MESH
9881 else if ((flags & 32) != 0 || (flags & 8) != 0)
9882 oType = 0x0B; // VERTEX_3D
9883 else
9884 oType = 0x0A; // VERTEX_2D
9885 break;
9886 }
9887
9888 if (!encodeDwgCommon(version, buf)) return false;
9889
9890 if (oType == 0x0A) {
9891 buf->putRawChar8(static_cast<std::uint8_t>(flags));
9892 buf->put3BitDouble(basePoint);
9893 buf->putBitDouble(stawidth);
9894 buf->putBitDouble(endwidth);
9895 buf->putBitDouble(bulge);
9896 if (version > DRW::AC1021)
9897 buf->putBitLong(static_cast<std::int32_t>(identifier));
9898 buf->putBitDouble(tgdir);
9899 } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) {
9900 buf->putRawChar8(static_cast<std::uint8_t>(flags));
9901 buf->put3BitDouble(basePoint);
9902 } else { // 0x0E pface face
9903 buf->putBitShort(static_cast<std::uint16_t>(vindex1));
9904 buf->putBitShort(static_cast<std::uint16_t>(vindex2));
9905 buf->putBitShort(static_cast<std::uint16_t>(vindex3));
9906 buf->putBitShort(static_cast<std::uint16_t>(vindex4));
9907 }
9908
9909 return encodeDwgEntHandle(version, buf, handleBuf);
9910}
9911
9912bool DRW_SeqEnd::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) {
9913 if (!DRW_Entity::parseDwg(version, buf, nullptr, bs))
9914 return false;
9915 return DRW_Entity::parseDwgEntHandle(version, buf);
9916}
9917
9918bool DRW_SeqEnd::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9919 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9920 (void)bs; (void)strBuf;
9921 oType = 0x06;
9922 if (!encodeDwgCommon(version, buf))
9923 return false;
9924 return encodeDwgEntHandle(version, buf, handleBuf);
9925}
9926
9927// ---------------------------------------------------------------------------
9928// DRW_Polyline::encodeDwg — OT varies by flags; vertex handles emitted here.
9929// ---------------------------------------------------------------------------
9930
9931bool DRW_Polyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9932 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9933 (void)bs; (void)strBuf;
9934 // Determine object type from stored flags (mirror of parseDwg dispatch).
9935 if (flags & 64) oType = 0x1D; // POLYLINE_PFACE
9936 else if (flags & 16) oType = 0x1E; // POLYLINE_MESH
9937 else if (flags & 8) oType = 0x10; // POLYLINE_3D
9938 else oType = 0x0F; // POLYLINE_2D
9939
9940 if (!encodeDwgCommon(version, buf)) return false;
9941
9942 if (oType == 0x0F) {
9943 buf->putBitShort(static_cast<std::uint16_t>(flags));
9944 buf->putBitShort(static_cast<std::uint16_t>(curvetype));
9945 buf->putBitDouble(defstawidth);
9946 buf->putBitDouble(defendwidth);
9947 buf->putThickness(thickness, version > DRW::AC1014);
9948 buf->putBitDouble(basePoint.z);
9949 buf->putExtrusion(extPoint, version > DRW::AC1014);
9950 } else if (oType == 0x10) {
9951 // curvetype → 2 RC flag bytes (mirror of parser decode)
9952 std::uint8_t rc1 = 0;
9953 if (curvetype == 5) rc1 = 1;
9954 else if (curvetype == 6) rc1 = 2;
9955 else if (curvetype == 8) rc1 = 3;
9956 buf->putRawChar8(rc1);
9957 buf->putRawChar8(static_cast<std::uint8_t>(flags & 1)); // bit 0 = closed
9958 } else if (oType == 0x1D) {
9959 buf->putBitShort(static_cast<std::uint16_t>(vertexcount));
9960 buf->putBitShort(static_cast<std::uint16_t>(facecount));
9961 } else { // 0x1E MESH
9962 buf->putBitShort(static_cast<std::uint16_t>(flags & ~16)); // strip reader-added bit 4
9963 buf->putBitShort(static_cast<std::uint16_t>(curvetype));
9964 buf->putBitShort(static_cast<std::uint16_t>(vertexcount)); // M count
9965 buf->putBitShort(static_cast<std::uint16_t>(facecount)); // N count
9966 buf->putBitShort(static_cast<std::uint16_t>(smoothM)); // mDensity, DXF 73
9967 buf->putBitShort(static_cast<std::uint16_t>(smoothN)); // nDensity, DXF 74
9968 }
9969
9970 // AC2004+ (>AC1015): emit vertex count before the handle section.
9971 std::int32_t ooCount = static_cast<std::int32_t>(vertlist.size());
9972 if (version > DRW::AC1015)
9973 buf->putBitLong(ooCount);
9974
9975 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
9976
9977 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
9978
9979 if (version < DRW::AC1018) {
9980 // R2000-: first/last vertex handles (absolute hard pointers).
9981 putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.front()->handle);
9982 putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.back()->handle);
9983 } else {
9984 // R2004+: one handle per vertex.
9985 for (const auto& v : vertlist)
9986 putAbsHandle(hb, v ? v->handle : 0u);
9987 }
9988 putAbsHandle(hb, seqEndH.ref);
9989
9990 return true;
9991}
9992
9993// ---------------------------------------------------------------------------
9994// DRW_Leader::encodeDwg — OT=45 (AC1015/AC1018/AC1024)
9995// ---------------------------------------------------------------------------
9996
9997bool DRW_Leader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
9998 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
9999 (void)bs; (void)strBuf;
10000 oType = 45;
10001 if (!encodeDwgCommon(version, buf)) return false;
10002
10003 buf->putBit(0); // unknown bit
10004 buf->putBitShort(0); // annotType (ignored on read)
10005 buf->putBitShort(static_cast<std::int16_t>(leadertype)); // pathType (DXF code 72)
10006 buf->putBitLong(static_cast<std::int32_t>(vertexlist.size()));
10007 for (const auto& vp : vertexlist)
10008 buf->put3BitDouble(*vp);
10009 buf->put3BitDouble(DRW_Coord(0, 0, 0)); // Endptproj (ignored on read)
10010 // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — matches parseDwg.
10011 buf->put3BitDouble(extrusionPoint);
10012
10013 buf->put3BitDouble(horizdir);
10014 buf->put3BitDouble(offsetblock);
10015
10016 if (version > DRW::AC1012)
10017 buf->put3BitDouble(DRW_Coord(0, 0, 0)); // unknown coord
10018
10019 if (version < DRW::AC1015)
10020 buf->putBitDouble(0.0); // dimgap (pre-R2000)
10021
10022 if (version < DRW::AC1024) {
10023 buf->putBitDouble(textheight);
10024 buf->putBitDouble(textwidth);
10025 }
10026
10027 buf->putBit(static_cast<std::uint8_t>(hookline));
10028 buf->putBit(static_cast<std::uint8_t>(arrow));
10029
10030 if (version < DRW::AC1015) {
10031 buf->putBitShort(0); // arrowHeadType
10032 buf->putBitDouble(0.0); // dimasz
10033 buf->putBit(0); // unk
10034 buf->putBit(0); // unk
10035 buf->putBitShort(0); // unk short
10036 buf->putBitShort(0); // byBlock color
10037 buf->putBit(0); // unk
10038 buf->putBit(0); // unk
10039 } else {
10040 buf->putBitShort(0); // unk short (R2000+)
10041 buf->putBit(0); // unk
10042 buf->putBit(0); // unk
10043 }
10044
10045 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
10046
10047 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
10048 putAbsHandle(hb, 0); // AnnotH — null (no annotation entity)
10049 putAbsHandle(hb, 0x15); // dimStyleH — hard ptr to STANDARD (handle 0x15)
10050
10051 return true;
10052}
10053
10054// ---------------------------------------------------------------------------
10055// DRW_Viewport::encodeDwg — OT=34 (AC1015/AC1018/AC1024)
10056// ---------------------------------------------------------------------------
10057
10058bool DRW_Viewport::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs,
10059 dwgBufferW *strBuf, dwgBufferW *handleBuf) {
10060 (void)bs;
10061 oType = 34;
10062 // Use strBuf for TV strings in AC1024; for AC1015/AC1018 strings go inline.
10063 dwgBufferW *sb = (strBuf && version > DRW::AC1018) ? strBuf : buf;
10064 if (!encodeDwgCommon(version, buf)) return false;
10065
10066 buf->putBitDouble(basePoint.x);
10067 buf->putBitDouble(basePoint.y);
10068 buf->putBitDouble(basePoint.z);
10069 buf->putBitDouble(pswidth);
10070 buf->putBitDouble(psheight);
10071
10072 if (version > DRW::AC1014) {
10073 buf->putBitDouble(viewTarget.x);
10074 buf->putBitDouble(viewTarget.y);
10075 buf->putBitDouble(viewTarget.z);
10076 buf->putBitDouble(viewDir.x);
10077 buf->putBitDouble(viewDir.y);
10078 buf->putBitDouble(viewDir.z);
10079 buf->putBitDouble(twistAngle);
10080 buf->putBitDouble(viewHeight);
10081 buf->putBitDouble(viewLength); // lens length
10082 buf->putBitDouble(frontClip);
10083 buf->putBitDouble(backClip);
10084 buf->putBitDouble(snapAngle);
10085 buf->putRawDouble(centerPX);
10086 buf->putRawDouble(centerPY);
10087 buf->putRawDouble(snapPX);
10088 buf->putRawDouble(snapPY);
10089 buf->putRawDouble(snapSpPX);
10090 buf->putRawDouble(snapSpPY);
10091 buf->putRawDouble(0.0); // gridSpacingX
10092 buf->putRawDouble(0.0); // gridSpacingY
10093 buf->putBitShort(0); // circleZoom
10094 }
10095
10096 if (version > DRW::AC1018)
10097 buf->putBitShort(0); // gridMajor (AC2007+)
10098
10099 if (version > DRW::AC1014) {
10100 buf->putBitLong(0); // frozenLyCount
10101 buf->putBitLong(0); // statusFlags
10102 sb->putVariableText(version, ""); // styleSheet TV
10103 buf->putRawChar8(0); // renderMode
10104 buf->putBit(0); // ucsPerVP
10105 buf->putBit(0); // ucs flag
10106 // UCS origin / X-axis / Y-axis (3×3BD), elevation, ortho type
10107 for (int i = 0; i < 9; ++i) buf->putBitDouble(0.0);
10108 buf->putBitDouble(0.0); // ucsElev
10109 buf->putBitShort(0); // ucsOrthoType
10110 }
10111
10112 if (version > DRW::AC1015)
10113 buf->putBitShort(0); // shadePlotMode (AC2004+)
10114
10115 if (version > DRW::AC1018) {
10116 buf->putBit(0); // useDefLight
10117 buf->putRawChar8(0); // defLightType
10118 buf->putBitDouble(0.0); // brightness
10119 buf->putBitDouble(0.0); // contrast
10120 buf->putCmColor(version, 256); // ambientColor CMC (ByLayer) per ODA §20.4.38
10121 }
10122
10123 if (!encodeDwgEntHandle(version, buf, handleBuf)) return false;
10124
10125 dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf;
10126
10127 if (version < DRW::AC1015) {
10128 putAbsHandle(hb, 0); // viewport entity header (pre-2000)
10129 }
10130 if (version > DRW::AC1014) {
10131 // frozenLyCount=0, so no frozen layer handles.
10132 putAbsHandle(hb, 0); // clip boundary (null)
10133 if (version == DRW::AC1015)
10134 putAbsHandle(hb, 0); // viewport entity header (R2000 only)
10135 putAbsHandle(hb, 0); // namedUCS (null)
10136 putAbsHandle(hb, 0); // baseUCS (null)
10137 }
10138 if (version > DRW::AC1018) {
10139 putAbsHandle(hb, 0); // background (null)
10140 putAbsHandle(hb, 0); // visualStyle (null)
10141 putAbsHandle(hb, 0); // shadeplotID (null)
10142 putAbsHandle(hb, 0); // sun (null)
10143 }
10144
10145 return true;
10146}