Bug Summary

File:intern/dwgbuffer.cpp
Warning:line 832, column 9
Value stored to 'cb' is never read

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 dwgbuffer.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-06-02-163325-5106-1 -x c++ src/intern/dwgbuffer.cpp
1/******************************************************************************
2** libDXFrw - Library to read/write DXF files (ascii & binary) **
3** **
4** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com **
5** **
6** This library is free software, licensed under the terms of the GNU **
7** General Public License as published by the Free Software Foundation, **
8** either version 2 of the License, or (at your option) any later version. **
9** You should have received a copy of the GNU General Public License **
10** along with this program. If not, see <http://www.gnu.org/licenses/>. **
11******************************************************************************/
12
13
14#include "dwgbuffer.h"
15#include "../libdwgr.h"
16#include "drw_textcodec.h"
17#include "drw_dbg.h"
18#include <cstring>
19//#include <bitset>
20/*#include <fstream>
21#include <algorithm>
22#include <sstream>
23#include "dwgreader.h"*/
24//#include "dxfwriter.h"
25
26
27//#define FIRSTHANDLE 48
28
29/*enum sections {
30 secUnknown,
31 secHeader,
32 secTables,
33 secBlocks,
34 secEntities,
35 secObjects
36};*/
37
38static unsigned int crctable[256]= {
390x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
400xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
410xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
420x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
430xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
440x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
450x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
460xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
470xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
480x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
490x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
500xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
510x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
520xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
530xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
540x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
550xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
560x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
570x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
580xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
590x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
600xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
610xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
620x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
630x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
640x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
650x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
660x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
670x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
680x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
690x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
700x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040 };
71
72static unsigned int crc32Table[256] ={
730x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
740x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
750x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
760x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
770x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
780x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
790x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
800x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
810x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
820x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
830x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
840x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
850x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
860x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
870x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
880x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
890xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
900xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
910xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
920xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
930xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
940xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
950xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
960xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
970x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
980x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
990x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1000x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1010xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1020xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1030xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1040xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
105
106union typeCast {
107 char buf[8];
108 duint16 i16;
109 duint32 i32;
110 duint64 i64;
111 ddouble64 d64;
112};
113
114bool dwgFileStream::setPos(duint64 p){
115 if (p >= sz)
116 return false;
117
118 stream->seekg(p);
119 return stream->good();
120}
121
122bool dwgFileStream::read(duint8* s, duint64 n){
123 stream->read (reinterpret_cast<char*>(s),n);
124 return stream->good();
125}
126
127bool dwgCharStream::setPos(duint64 p){
128 if (p > size()) {
129 isOk = false;
130 return false;
131 }
132
133 pos = p;
134 return true;
135}
136
137bool dwgCharStream::read(duint8* s, duint64 n){
138 if ( n > (sz - pos) ) {
139 isOk = false;
140 return false;
141 }
142 for (duint64 i=0; i<n; i++){
143 s[i]= stream[pos++];
144 }
145 return true;
146}
147
148dwgBuffer::dwgBuffer(duint8 *buf, duint64 size, DRW_TextCodec *dc)
149 :decoder{dc}
150 ,filestr{new dwgCharStream(buf, size)}
151 ,maxSize{size}
152{}
153
154dwgBuffer::dwgBuffer(std::ifstream *stream, DRW_TextCodec *dc)
155 :decoder{dc}
156 ,filestr{new dwgFileStream(stream)}
157 ,maxSize{filestr->size()}
158{}
159
160dwgBuffer::dwgBuffer( const dwgBuffer& org )
161 :decoder{org.decoder}
162 ,filestr{org.filestr->clone()}
163 ,maxSize{filestr->size()}
164 ,currByte{org.currByte}
165 ,bitPos{org.bitPos}
166{}
167
168dwgBuffer& dwgBuffer::operator=( const dwgBuffer& org ){
169 filestr.reset( org.filestr->clone());
170 decoder = org.decoder;
171 maxSize = filestr->size();
172 currByte = org.currByte;
173 bitPos = org.bitPos;
174 return *this;
175}
176
177/**Gets the current byte position in buffer **/
178duint64 dwgBuffer::getPosition() const{
179 if (bitPos != 0)
180 return filestr->getPos() -1;
181 return filestr->getPos();
182 }
183
184/**Sets the buffer position in pos byte, reset the bit position **/
185bool dwgBuffer::setPosition(duint64 pos){
186 bitPos = 0;
187/* if (pos>=maxSize)
188 return false;*/
189 return filestr->setPos(pos);
190// return true;
191}
192
193//RLZ: Fails if ... ???
194void dwgBuffer::setBitPos(duint8 pos){
195 if (pos>7)
196 return;
197 if (pos != 0 && bitPos == 0){
198 duint8 buffer;
199 filestr->read (&buffer,1);
200 currByte = buffer;
201 }
202 if (pos == 0 && bitPos != 0){//reset current byte
203 filestr->setPos(filestr->getPos()-1);
204 }
205 bitPos = pos;
206}
207
208bool dwgBuffer::moveBitPos(dint32 size){
209 if (size == 0) return true;
210
211 dint32 b= size + bitPos;
212 filestr->setPos(getPosition() + (b >> 3) );
213 bitPos = b & 7;
214
215 if (bitPos != 0){
216 filestr->read (&currByte,1);
217 }
218 return filestr->good();
219}
220
221/**Reads one Bit returns a char with value 0/1 (B) **/
222duint8 dwgBuffer::getBit(){
223 if (!isGood()) return 0;
224 duint8 buffer;
225 duint8 ret = 0;
226 if (bitPos == 0){
227 filestr->read (&buffer,1);
228 currByte = buffer;
229 }
230
231 ret = (currByte >> (7 - bitPos) & 1);
232 bitPos +=1;
233 if (bitPos == 8)
234 bitPos = 0;
235
236 return ret;
237}
238
239/**Reads one Bit returns a bool value 0==false 1==true (B) **/
240bool dwgBuffer::getBoolBit(){
241 return (getBit() != 0);
242}
243
244/**Reads two Bits returns a char (BB) **/
245duint8 dwgBuffer::get2Bits(){
246 duint8 buffer = 0;
247 duint8 ret = 0;
248 if (bitPos == 0){
249 filestr->read (&buffer,1);
250 currByte = buffer;
251 }
252
253 bitPos +=2;
254 if (bitPos < 9)
255 ret = currByte >>(8 - bitPos);
256 else {//read one bit per byte
257 ret = currByte << 1;
258 filestr->read (&buffer,1);
259 currByte = buffer;
260 bitPos = 1;
261 ret = ret | currByte >> 7;
262 }
263 if (bitPos == 8)
264 bitPos = 0;
265 ret = ret & 3;
266 return ret;
267}
268
269/**Reads three Bits returns a char (3B) **/
270duint8 dwgBuffer::get3Bits(){
271 duint8 buffer = 0;
272 duint8 ret = 0;
273 if (bitPos == 0){
274 filestr->read (&buffer,1);
275 currByte = buffer;
276 }
277
278 bitPos +=3;
279 if (bitPos < 9)
280 ret = currByte >>(8 - bitPos);
281 else {//read one bit per byte
282 ret = currByte << 1;
283 filestr->read (&buffer,1);
284 currByte = buffer;
285 bitPos = 1;
286 ret = ret | currByte >> 7;
287 }
288 if (bitPos == 8)
289 bitPos = 0;
290 ret = ret & 7;
291 return ret;
292}
293
294/**Reads tree Bits returns a char (3B) for R24 **/
295//to be written
296
297/**Reads compressed Short (max. 16 + 2 bits) little-endian order, returns a UNsigned 16 bits (BS) **/
298duint16 dwgBuffer::getBitShort(){
299 duint8 b = get2Bits();
300 if (b == 0)
301 return getRawShort16();
302 else if (b== 1)
303 return getRawChar8();
304 else if (b == 2)
305 return 0;
306 else
307 return 256;
308}
309/**Reads compressed Short (max. 16 + 2 bits) little-endian order, returns a signed 16 bits (BS) **/
310dint16 dwgBuffer::getSBitShort(){
311 duint8 b = get2Bits();
312 if (b == 0)
313 return static_cast<dint16>(getRawShort16());
314 else if (b== 1)
315 return static_cast<dint16>(getRawChar8());
316 else if (b == 2)
317 return 0;
318 else
319 return 256;
320}
321
322/**Reads compressed 32 bits Int (max. 32 + 2 bits) little-endian order, returns a signed 32 bits (BL) **/
323//to be written
324dint32 dwgBuffer::getBitLong(){
325 dint8 b = get2Bits();
326 if (b == 0)
327 return getRawLong32();
328 else if (b== 1)
329 return getRawChar8();
330 else //if (b == 2)
331 return 0;
332}
333
334/**Reads compressed 64 bits Int (max. 56 + 3 bits) little-endian order, returns a unsigned 64 bits (BLL) **/
335duint64 dwgBuffer::getBitLongLong(){
336 dint8 b = get3Bits();
337 duint64 ret=0;
338 for (duint8 i=0; i<b; i++){
339 ret = ret << 8;
340 ret |= getRawChar8();
341 }
342 return ret;
343}
344
345/**Reads compressed Double (max. 64 + 2 bits) returns a floating point double of 64 bits (BD) **/
346double dwgBuffer::getBitDouble(){
347 dint8 b = get2Bits();
348 if (b == 1)
349 return 1.0;
350 else if (b == 0){
351 duint8 buffer[8] = {0};
352 if (bitPos != 0) {
353 for (int i = 0; i < 8; i++)
354 buffer[i] = getRawChar8();
355 } else {
356 filestr->read (buffer,8);
357 }
358 double ret = 0.0;
359 std::memcpy(&ret, buffer, 8);
360 return ret;
361 }
362 // if (b == 2)
363 return 0.0;
364}
365
366/**Reads 3 compressed Double (max. 64 + 2 bits) returns a DRW_Coord of floating point double of 64 bits (3BD) **/
367DRW_Coord dwgBuffer::get3BitDouble(){
368 DRW_Coord crd;
369 crd.x = getBitDouble();
370 crd.y = getBitDouble();
371 crd.z = getBitDouble();
372 return crd;
373}
374
375/**Reads raw char 8 bits returns a unsigned char (RC) **/
376duint8 dwgBuffer::getRawChar8(){
377 duint8 ret=0;
378 duint8 buffer=0;
379 filestr->read (&buffer,1);
380 if (bitPos == 0)
381 return buffer;
382 else {
383 ret = currByte << bitPos;
384 currByte = buffer;
385 ret = ret | (currByte >>(8 - bitPos));
386 }
387 return ret;
388}
389
390/**Reads raw short 16 bits little-endian order, returns a unsigned short (RS) **/
391duint16 dwgBuffer::getRawShort16(){
392 duint8 buffer[2]={0,0};
393 duint16 ret=0;
394
395 filestr->read (buffer,2);
396 if (bitPos == 0) {
397 /* no offset directly swap bytes for little-endian */
398 ret = static_cast<duint16>((static_cast<duint32>(buffer[1]) << 8) | buffer[0]);
399 } else {
400 ret = static_cast<duint16>((static_cast<duint32>(buffer[0]) << 8) | buffer[1]);
401 /* apply offset; promote currByte to duint32 to avoid implicit-int shift surprises */
402 ret = static_cast<duint16>(ret >> (8 - bitPos));
403 ret = static_cast<duint16>(ret | (static_cast<duint32>(currByte) << (8 + bitPos)));
404 currByte = buffer[1];
405 /* swap bytes for little-endian */
406 ret = static_cast<duint16>((ret << 8) | (ret >> 8));
407 }
408 return ret;
409}
410
411/**Reads raw double IEEE standard 64 bits returns a double (RD) **/
412double dwgBuffer::getRawDouble(){
413 duint8 buffer[8] = {0};
414 if (bitPos == 0)
415 filestr->read (buffer,8);
416 else {
417 for (int i = 0; i < 8; i++)
418 buffer[i] = getRawChar8();
419 }
420 double ret = 0.0;
421 std::memcpy(&ret, buffer, 8);
422 return ret;
423}
424
425/**Reads 2 raw double IEEE standard 64 bits returns a DRW_Coord of floating point double 64 bits (2RD) **/
426DRW_Coord dwgBuffer::get2RawDouble(){
427 DRW_Coord crd;
428 crd.x = getRawDouble();
429 crd.y = getRawDouble();
430 return crd;
431}
432
433
434/**Reads raw int 32 bits little-endian order, returns a unsigned int (RL) **/
435duint32 dwgBuffer::getRawLong32(){
436 duint16 tmp1 = getRawShort16();
437 duint16 tmp2 = getRawShort16();
438 duint32 ret = (tmp2 << 16) | (tmp1 & 0x0000FFFF);
439
440 return ret;
441}
442
443/**Reads raw int 64 bits little-endian order, returns a unsigned long long (RLL) **/
444duint64 dwgBuffer::getRawLong64(){
445 duint32 tmp1 = getRawLong32();
446 duint64 tmp2 = getRawLong32();
447 duint64 ret = (tmp2 << 32) | (tmp1 & 0x00000000FFFFFFFF);
448
449 return ret;
450}
451
452/**Reads modular unsigner int, char based, compressed form, little-endian order, returns a unsigned int (U-MC) **/
453duint32 dwgBuffer::getUModularChar(){
454 std::vector<duint8> buffer;
455 duint32 result =0;
456 for (int i=0; i<4;i++){
457 duint8 b= getRawChar8();
458 buffer.push_back(b & 0x7F);
459 if (! (b & 0x80))
460 break;
461 }
462 int offset = 0;
463 for (unsigned int i=0; i<buffer.size();i++){
464 result += buffer[i] << offset;
465 offset +=7;
466 }
467//RLZ: WARNING!!! needed to verify on read handles
468 //result = result & 0x7F;
469 return result;
470}
471
472/**Reads modular int, char based, compressed form, little-endian order, returns a signed int (MC) **/
473dint32 dwgBuffer::getModularChar(){
474 bool negative = false;
475 std::vector<dint8> buffer;
476 dint32 result =0;
477 for (int i=0; i<4;i++){
478 duint8 b= getRawChar8();
479 buffer.push_back(b & 0x7F);
480 if (! (b & 0x80))
481 break;
482 }
483 dint8 b= buffer.back();
484 if (b & 0x40) {
485 negative = true;
486 buffer.pop_back();
487 buffer.push_back(b & 0x3F);
488 }
489
490 int offset = 0;
491 for (unsigned int i=0; i<buffer.size();i++){
492 result += buffer[i] << offset;
493 offset +=7;
494 }
495 if (negative)
496 result = -result;
497 return result;
498}
499
500/**Reads modular int, short based, compressed form, little-endian order, returns a unsigned int (MC) **/
501dint32 dwgBuffer::getModularShort(){
502// bool negative = false;
503 std::vector<dint16> buffer;
504 dint32 result =0;
505 for (int i=0; i<2;i++){
506 duint16 b= getRawShort16();
507 buffer.push_back(b & 0x7FFF);
508 if (! (b & 0x8000))
509 break;
510 }
511
512 //only positive ?
513/* dint8 b= buffer.back();
514 if (! (b & 0x40)) {
515 negative = true;
516 buffer.pop_back();
517 buffer.push_back(b & 0x3F);
518 }*/
519
520 int offset = 0;
521 for (unsigned int i=0; i<buffer.size();i++){
522 result += buffer[i] << offset;
523 offset +=15;
524 }
525/* if (negative)
526 result = -result;*/
527 return result;
528}
529
530dwgHandle dwgBuffer::getHandle(){ //H
531 dwgHandle hl;
532 duint8 data = getRawChar8();
533 hl.code = (data >> 4) & 0x0F;
534 hl.size = data & 0x0F;
535 hl.ref=0;
536 for (int i=0; i< hl.size;i++){
537 hl.ref = (hl.ref << 8) | getRawChar8();
538 }
539 return hl;
540}
541
542dwgHandle dwgBuffer::getOffsetHandle(duint32 href){ //H
543 dwgHandle hl = getHandle();
544 if (hl.code > 5){
545 if (hl.code == 0x0C)
546 hl.ref = href - hl.ref;
547 else if (hl.code == 0x0A)
548 hl.ref = href + hl.ref;
549 else if (hl.code == 0x08)
550 hl.ref = href - 1;
551 else if (hl.code == 0x06)
552 hl.ref = href + 1;
553//all are soft pointer reference change to 7 (without offset)
554 hl.code = 7;
555 }
556 return hl;
557}
558
559//internal until 2004
560std::string dwgBuffer::get8bitStr(){
561 duint16 textSize = getBitShort();
562 if (textSize == 0)
563 return std::string();
564 duint8 *tmpBuffer = new duint8[textSize];
565 bool good = getBytes(tmpBuffer, textSize);
566 if (!good)
567 return std::string();
568
569/* filestr->read (buffer,textSize);
570 if (!filestr->good())
571 return std::string();
572
573 duint8 tmp;
574 if (bitPos != 0){
575 for (int i=0; i<textSize;i++){
576 tmp = buffer[i];
577 buffer[i] = (currByte << bitPos) | (tmp >> (8 - bitPos));
578 currByte = tmp;
579 }
580 }*/
581 std::string str(reinterpret_cast<char*>(tmpBuffer), textSize);
582 delete[]tmpBuffer;
583 // R13/R14 TV strings include the null terminator in the length field;
584 // strip it so comparisons like recName == "LWPOLYLINE" work correctly.
585 while (!str.empty() && str.back() == '\0')
586 str.pop_back();
587 return str;
588}
589
590//internal since 2007 //pending: are 2 bytes null terminated??
591//nullTerm = true if string are 2 bytes null terminated from the stream
592std::string dwgBuffer::get16bitStr(duint16 textSize, bool nullTerm){
593 if (textSize == 0)
594 return std::string();
595 textSize *=2;
596 duint16 ts = textSize;
597 if (nullTerm)
598 ts += 2;
599 duint8 *tmpBuffer = new duint8[textSize + 2];
600 bool good = getBytes(tmpBuffer, ts);
601 if (!good)
602 return std::string();
603 if (!nullTerm) {
604 tmpBuffer[textSize] = '\0';
605 tmpBuffer[textSize + 1] = '\0';
606 }
607 std::string str(reinterpret_cast<char*>(tmpBuffer), ts);
608 delete[]tmpBuffer;
609
610 return str;
611}
612
613//T 8 bit text converted from codepage to utf8
614std::string dwgBuffer::getCP8Text(){
615 std::string strData;
616 strData = get8bitStr();//RLZ correct these function
617 if (!decoder)
618 return strData;
619
620 return decoder->toUtf8(strData);
621}
622
623//TU unicode 16 bit (UCS) text converted to utf8
624/**Reads 2-bytes char (UCS2, NULL terminated) and convert to std::string (only for Latin-1)
625 ts= total input size in bytes.
626**/
627std::string dwgBuffer::getUCSStr(duint16 ts){
628 std::string strData;
629 if (ts<4) //at least 1 char
630 return std::string();
631 strData = get16bitStr(ts/2, false);
632 if (!decoder)
633 return strData;
634
635 return decoder->toUtf8(strData);
636}
637
638//TU unicode 16 bit (UCS) text converted to utf8
639//nullTerm = true if string are 2 bytes null terminated from the stream
640std::string dwgBuffer::getUCSText(bool nullTerm){
641 std::string strData;
642 duint16 ts = getBitShort();
643 if (ts == 0)
644 return std::string();
645
646 strData = get16bitStr(ts, nullTerm);
647 if (!decoder)
648 return strData;
649
650 return decoder->toUtf8(strData);
651}
652
653//RLZ: read a T or TU if version is 2007+
654//nullTerm = true if string are 2 bytes null terminated from the stream
655std::string dwgBuffer::getVariableText(DRW::Version v, bool nullTerm){//TV
656 if (v > DRW::AC1018)
657 return getUCSText(nullTerm);
658 return getCP8Text();
659}
660duint16 dwgBuffer::getObjType(DRW::Version v){//OT
661 if (v > DRW::AC1021) {
662 duint8 b = get2Bits();
663 if (b == 0)
664 return getRawChar8();
665 else if (b== 1){
666 return (getRawChar8() + 0x01F0);
667 } else //b == 2
668 return getRawShort16();
669 }
670 return getBitShort();
671}
672
673/* Bit Extrusion
674* For R2000+, this is a single bit, If the single bit is 1,
675* the extrusion value is assumed to be 0,0,1 and no explicit
676* extrusion is stored. If the single bit is 0, then it will
677* be followed by 3BD.
678* For R13-R14 this is 3BD.
679*/
680DRW_Coord dwgBuffer::getExtrusion(bool b_R2000_style) {
681 DRW_Coord ext(0.0,0.0,1.0);
682 if ( b_R2000_style )
683 /* If the bit is one, the extrusion value is assumed to be 0,0,1*/
684 if ( getBit() == 1 )
685 return ext;
686 /*R13-R14 or bit == 0*/
687 ext.x = getBitDouble();
688 ext.y = getBitDouble();
689 ext.z = getBitDouble();
690 return ext;
691}
692
693/**Reads compressed Double with default (max. 64 + 2 bits) returns a floating point double of 64 bits (DD) **/
694double dwgBuffer::getDefaultDouble(double d){
695 dint8 b = get2Bits();
696 if (b == 0)
697 return d;
698 else if (b == 1){
699 duint8 buffer[4];
700 char *tmp=nullptr;
701 if (bitPos != 0) {
702 for (int i = 0; i < 4; i++)
703 buffer[i] = getRawChar8();
704 } else {
705 filestr->read (buffer,4);
706 }
707 tmp = reinterpret_cast<char*>(&d);
708 for (int i = 0; i < 4; i++)
709 tmp[i] = buffer[i];
710 double ret = *reinterpret_cast<double*>( tmp );
711 return ret;
712 } else if (b == 2){
713 duint8 buffer[6];
714 char *tmp=nullptr;
715 if (bitPos != 0) {
716 for (int i = 0; i < 6; i++)
717 buffer[i] = getRawChar8();
718 } else {
719 filestr->read (buffer,6);
720 }
721 tmp = reinterpret_cast<char*>(&d);
722 for (int i = 2; i < 6; i++)
723 tmp[i-2] = buffer[i];
724 tmp[4] = buffer[0];
725 tmp[5] = buffer[1];
726 double ret = *reinterpret_cast<double*>( tmp );
727 return ret;
728 }
729 // if (b == 3) return a full raw double
730 return getRawDouble();
731}
732
733
734/* BitThickness
735* For R13-R14, this is a BD.
736* For R2000+, this is a single bit, If the bit is one,
737* the thickness value is assumed to be 0.0, if not a BD follow
738*/
739double dwgBuffer::getThickness(bool b_R2000_style) {
740 if ( b_R2000_style )
741 /* If the bit is one, the thickness value is assumed to be 0.0.*/
742 if ( getBit() == 1 )
743 return 0.0;
744 /*R13-R14 or bit == 0*/
745 return getBitDouble();
746}
747
748/* CmColor (CMC)
749* For R15 and earlier call directly BS as ACIS color.
750* For R2004+, can be CMC or ENC
751* RGB value, first 4bits 0xC0 => ByLayer, 0xC1 => ByBlock, 0xC2 => RGB, 0xC3 => last 4 are ACIS
752*/
753duint32 dwgBuffer::getCmColor(DRW::Version v, dint32* rgb24,
754 dwgBuffer* strBuf,
755 UTF8STRINGstd::string* outName,
756 UTF8STRINGstd::string* outBookName) {
757 if (v < DRW::AC1018) //2000-
758 return getSBitShort();
759 duint16 idx = getBitShort();
760 duint32 rgb = getBitLong();
761 duint8 cb = getRawChar8();
762 duint8 type = rgb >> 24;
763 DRW_DBG("\ntype COLOR: ")DRW_dbg::getInstance()->print("\ntype COLOR: "); DRW_DBGH(type)DRW_dbg::getInstance()->printH(type);
764 DRW_DBG("\nindex COLOR: ")DRW_dbg::getInstance()->print("\nindex COLOR: "); DRW_DBGH(idx)DRW_dbg::getInstance()->printH(idx);
765 DRW_DBG("\nRGB COLOR: ")DRW_dbg::getInstance()->print("\nRGB COLOR: "); DRW_DBGH(rgb)DRW_dbg::getInstance()->printH(rgb);
766 DRW_DBG("\nbyte COLOR: ")DRW_dbg::getInstance()->print("\nbyte COLOR: "); DRW_DBGH(cb)DRW_dbg::getInstance()->printH(cb);
767 // libreDWG bits.c:3722-3724 reads color.name / book_name via bit_read_T
768 // from str_dat — for R2007+ that's the separate string stream, for
769 // earlier versions it's the same buffer. We mirror that: read from the
770 // strBuf if provided, otherwise from this (matches historical behavior).
771 dwgBuffer* nameSource = strBuf ? strBuf : this;
772 if (cb&1){
773 UTF8STRINGstd::string colorName = nameSource->getVariableText(v, false);
774 DRW_DBG("\ncolorName: ")DRW_dbg::getInstance()->print("\ncolorName: "); DRW_DBG(colorName)DRW_dbg::getInstance()->print(colorName);
775 if (outName) *outName = std::move(colorName);
776 }
777 if (cb&2){
778 UTF8STRINGstd::string bookName = nameSource->getVariableText(v, false);
779 DRW_DBG("\nbookName: ")DRW_dbg::getInstance()->print("\nbookName: "); DRW_DBG(bookName)DRW_dbg::getInstance()->print(bookName);
780 if (outBookName) *outBookName = std::move(bookName);
781 }
782 switch (type) {
783 case 0xC0:
784 return 256;//ByLayer
785 case 0xC1:
786 return 0;//ByBlock
787 case 0xC2:
788 //true RGB: expose the 24-bit color via out-param for callers that
789 //track DXF code 420 (DRW_Layer.color24, etc.); return ByLayer
790 //sentinel for the indexed-color slot.
791 if (rgb24)
792 *rgb24 = static_cast<dint32>(rgb & 0xFFFFFF);
793 return 256;
794 case 0xC3:
795 return rgb&0xFF;//ACIS
796 default:
797 break;
798 }
799 //check cb if strings follows RLZ TODO
800 return 256; //default return ByLayer
801}
802
803/* EnColor (ENC)
804* For R15 and earlier call directly BS as ACIS color.
805* For R2004+, can be CMC or ENC
806* RGB value, first 4bits 0xC0 => ByLayer, 0xC1 => ByBlock, 0xC2 => RGB, 0xC3 => last 4 are ACIS
807*/
808duint32 dwgBuffer::getEnColor(DRW::Version v) {
809 if (v < DRW::AC1018) //2000-
810 return getSBitShort();
811 duint32 rgb = 0;
812 duint32 cb = 0;
813 duint16 idx = getBitShort();
814 DRW_DBG("idx reads COLOR: ")DRW_dbg::getInstance()->print("idx reads COLOR: "); DRW_DBGH(idx)DRW_dbg::getInstance()->printH(idx);
815 duint16 flags = idx>>8;
816 // libreDWG common_entity_data.spec:424 uses 0x1ff because index 256 (ByLayer)
817 // requires bit 8. Bit 8 is shared between flag's LSB and index's MSB; the
818 // encoder ORs them at write time. We replicate the decoder mask exactly.
819 idx = idx & 0x1FF;
820 DRW_DBG("\nflag COLOR: ")DRW_dbg::getInstance()->print("\nflag COLOR: "); DRW_DBGH(flags)DRW_dbg::getInstance()->printH(flags);
821 DRW_DBG(", index COLOR: ")DRW_dbg::getInstance()->print(", index COLOR: "); DRW_DBGH(idx)DRW_dbg::getInstance()->printH(idx);
822// if (flags & 0x80) {
823// rgb = getBitLong();
824// DRW_DBG("\nRGB COLOR: "); DRW_DBGH(rgb);
825// }
826 // libreDWG common_entity_data.spec:432-453 — when flag 0x20 set, BL
827 // alpha_raw follows. High byte is alpha_type (0/1/3), low byte is
828 // alpha 0..255. Stored in side-channel for DRW_Entity::parseDwg.
829 lastEnColorAlphaRaw = 0;
830 if (flags & 0x20) {
831 lastEnColorAlphaRaw = static_cast<duint32>(getBitLong());
832 cb = lastEnColorAlphaRaw; // keep cb for legacy DRW_DBG below
Value stored to 'cb' is never read
833 DRW_DBG("\nTransparency COLOR (alpha_raw): ")DRW_dbg::getInstance()->print("\nTransparency COLOR (alpha_raw): "
)
; DRW_DBGH(lastEnColorAlphaRaw)DRW_dbg::getInstance()->printH(lastEnColorAlphaRaw);
834 }
835 // libreDWG common_entity_data.spec:454-466: when 0x40 set, an AcDbColor
836 // handle reference follows in hdl_dat — set side-channel flag for
837 // DRW_Entity::parseDwg / parseDwgEntHandle to consume it from the handle
838 // stream. When 0x40 NOT set but 0x80 IS set, an inline RGB BL follows.
839 lastEnColorHadDbColorRef = false;
840 if (flags & 0x40) {
841 DRW_DBG("\nacdbColor COLOR ref (handle in hdl_dat)")DRW_dbg::getInstance()->print("\nacdbColor COLOR ref (handle in hdl_dat)"
)
;
842 lastEnColorHadDbColorRef = true;
843 } else if (flags & 0x80) {
844 rgb = getBitLong();
845 DRW_DBG("\nRGB COLOR: ")DRW_dbg::getInstance()->print("\nRGB COLOR: "); DRW_DBGH(rgb)DRW_dbg::getInstance()->printH(rgb);
846 }
847 // libreDWG common_entity_data.spec:468-475 — when 0x41/0x42 set
848 // (i.e., 0x40 + bit 0/1), inline 8-bit TV strings follow. libreDWG
849 // explicitly uses FIELD_TV (8-bit from dat), not FIELD_T (which would
850 // dispatch to TU/str_dat for R2007+) — deliberate spec quirk verified
851 // against real files. We use getCP8Text which reads 8-bit length-
852 // prefixed and codepage-decodes to UTF-8.
853 lastEnColorName.clear();
854 lastEnColorBookName.clear();
855 if ((flags & 0x41) == 0x41) {
856 lastEnColorName = getCP8Text();
857 DRW_DBG("\nENC color name: ")DRW_dbg::getInstance()->print("\nENC color name: "); DRW_DBG(lastEnColorName)DRW_dbg::getInstance()->print(lastEnColorName);
858 }
859 if ((flags & 0x42) == 0x42) {
860 lastEnColorBookName = getCP8Text();
861 DRW_DBG("\nENC book name: ")DRW_dbg::getInstance()->print("\nENC book name: "); DRW_DBG(lastEnColorBookName)DRW_dbg::getInstance()->print(lastEnColorBookName);
862 }
863
864/* if (flags & 0x80)
865 return getBitLong();*/
866
867 return idx; //default return ByLayer
868}
869
870
871/**Reads raw short 16 bits big-endian order, returns a unsigned short crc & size **/
872duint16 dwgBuffer::getBERawShort16(){
873 char buffer[2];
874 buffer[0] = getRawChar8();
875 buffer[1] = getRawChar8();
876 duint16 size = (buffer[0] << 8) | (buffer[1] & 0xFF);
877 return size;
878}
879
880/* reads "size" bytes and stores in "buf" return false if fail */
881bool dwgBuffer::getBytes(unsigned char *buf, duint64 size){
882 duint8 tmp;
883 filestr->read (buf,size);
884 if (!filestr->good())
885 return false;
886
887 if (bitPos != 0){
888 for (duint64 i=0; i<size;i++){
889 tmp = buf[i];
890 buf[i] = (currByte << bitPos) | (tmp >> (8 - bitPos));
891 currByte = tmp;
892 }
893 }
894 return true;
895}
896
897duint16 dwgBuffer::crc8(duint16 dx,dint32 start,dint32 end){
898 duint64 pos = filestr->getPos();
899 filestr->setPos(start);
900 int n = end-start;
901 duint8 *tmpBuf = new duint8[n];
902 duint8 *p = tmpBuf;
903 filestr->read (tmpBuf,n);
904 filestr->setPos(pos);
905 if (!filestr->good())
906 return 0;
907
908 duint8 al;
909
910 while (n-- > 0) {
911 al = (duint8)((*p) ^ ((dint8)(dx & 0xFF)));
912 dx = (dx>>8) & 0xFF;
913 dx = dx ^ crctable[al & 0xFF];
914 p++;
915 }
916 delete[]tmpBuf;
917 return(dx);
918}
919
920duint32 dwgBuffer::crc32(duint32 seed,dint32 start,dint32 end){
921 duint64 pos = filestr->getPos();
922 filestr->setPos(start);
923 int n = end-start;
924 duint8 *tmpBuf = new duint8[n];
925 duint8 *p = tmpBuf;
926 filestr->read (tmpBuf,n);
927 filestr->setPos(pos);
928 if (!filestr->good())
929 return 0;
930
931 duint32 invertedCrc = ~seed;
932 while (n-- > 0) {
933 duint8 data = *p++;
934 invertedCrc = (invertedCrc >> 8) ^ crc32Table[(invertedCrc ^ data) & 0xff];
935 }
936 delete[]tmpBuf;
937 return ~invertedCrc;
938}
939
940
941/*std::string dwgBuffer::getBytes(int size){
942 char buffer[size];
943 char tmp;
944 filestr->read (buffer,size);
945 if (!filestr->good())
946 return NULL;
947
948 if (bitPos != 0){
949 for (int i=0; i<=size;i++){
950 tmp = buffer[i];
951 buffer[i] = (currByte << bitPos) | (tmp >> (8 - bitPos));
952 currByte = tmp;
953 }
954 }
955 std::string st;
956 for (int i=0; i<size;i++) {
957 st.push_back(buffer[i]);
958 }
959 return st;
960// return std::string(buffer);
961}*/
962