Bug Summary

File:intern/dwgbuffer.cpp
Warning:line 522, column 29
The result of left shift is undefined because the right operand '45' is not smaller than 32, the capacity of 'int'

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++){
1
Loop condition is true. Entering loop body
506 duint16 b= getRawShort16();
507 buffer.push_back(b & 0x7FFF);
508 if (! (b & 0x8000))
2
Assuming the condition is true
3
Taking true branch
509 break;
4
Execution continues on line 520
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++){
5
Assuming the condition is true
6
Loop condition is true. Entering loop body
7
Assuming the condition is true
8
Loop condition is true. Entering loop body
9
Assuming the condition is true
10
Loop condition is true. Entering loop body
12
Assuming the condition is true
13
Loop condition is true. Entering loop body
522 result += buffer[i] << offset;
14
The result of left shift is undefined because the right operand '45' is not smaller than 32, the capacity of 'int'
523 offset +=15;
11
The value 45 is assigned to 'offset'
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
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