Bug Summary

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