LibreOffice Module vcl (master) 1
GraphicFormatDetector.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <algorithm>
23
26#include <tools/solar.h>
27#include <tools/zcodec.hxx>
28#include <utility>
29
30constexpr sal_uInt32 SVG_CHECK_SIZE = 2048;
31constexpr sal_uInt32 WMF_EMF_CHECK_SIZE = 44;
32
33namespace vcl
34{
35bool peekGraphicFormat(SvStream& rStream, OUString& rFormatExtension, bool bTest)
36{
37 vcl::GraphicFormatDetector aDetector(rStream, rFormatExtension);
38 if (!aDetector.detect())
39 return false;
40
41 // The following variable is used when bTest == true. It remains false
42 // if the format (rFormatExtension) has not yet been set.
43 bool bSomethingTested = false;
44
45 // Now the different formats are checked. The order *does* matter. e.g. a MET file
46 // could also go through the BMP test, however, a BMP file can hardly go through the MET test.
47 // So MET should be tested prior to BMP. However, theoretically a BMP file could conceivably
48 // go through the MET test. These problems are of course not only in MET and BMP.
49 // Therefore, in the case of a format check (bTest == true) we only test *exactly* this
50 // format. Everything else could have fatal consequences, for example if the user says it is
51 // a BMP file (and it is a BMP) file, and the file would go through the MET test ...
52
53 if (!bTest || rFormatExtension.startsWith("MET"))
54 {
55 bSomethingTested = true;
56 if (aDetector.checkMET())
57 {
58 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
59 return true;
60 }
61 }
62
63 if (!bTest || rFormatExtension.startsWith("BMP"))
64 {
65 bSomethingTested = true;
66 if (aDetector.checkBMP())
67 {
68 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
69 return true;
70 }
71 }
72
73 if (!bTest || rFormatExtension.startsWith("WMF") || rFormatExtension.startsWith("WMZ")
74 || rFormatExtension.startsWith("EMF") || rFormatExtension.startsWith("EMZ"))
75 {
76 bSomethingTested = true;
77 if (aDetector.checkWMForEMF())
78 {
79 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
80 return true;
81 }
82 }
83
84 if (!bTest || rFormatExtension.startsWith("PCX"))
85 {
86 bSomethingTested = true;
87 if (aDetector.checkPCX())
88 {
89 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
90 return true;
91 }
92 }
93
94 if (!bTest || rFormatExtension.startsWith("TIF"))
95 {
96 bSomethingTested = true;
97 if (aDetector.checkTIF())
98 {
99 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
100 return true;
101 }
102 }
103
104 if (!bTest || rFormatExtension.startsWith("GIF"))
105 {
106 bSomethingTested = true;
107 if (aDetector.checkGIF())
108 {
109 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
110 return true;
111 }
112 }
113
114 if (!bTest || rFormatExtension.startsWith("PNG"))
115 {
116 bSomethingTested = true;
117 if (aDetector.checkPNG())
118 {
119 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
120 return true;
121 }
122 }
123
124 if (!bTest || rFormatExtension.startsWith("JPG"))
125 {
126 bSomethingTested = true;
127 if (aDetector.checkJPG())
128 {
129 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
130 return true;
131 }
132 }
133
134 if (!bTest || rFormatExtension.startsWith("SVM"))
135 {
136 bSomethingTested = true;
137 if (aDetector.checkSVM())
138 {
139 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
140 return true;
141 }
142 }
143
144 if (!bTest || rFormatExtension.startsWith("PCD"))
145 {
146 bSomethingTested = true;
147 if (aDetector.checkPCD())
148 {
149 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
150 return true;
151 }
152 }
153
154 if (!bTest || rFormatExtension.startsWith("PSD"))
155 {
156 bSomethingTested = true;
157 if (aDetector.checkPSD())
158 {
159 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
160 return true;
161 }
162 }
163
164 if (!bTest || rFormatExtension.startsWith("EPS"))
165 {
166 bSomethingTested = true;
167 if (aDetector.checkEPS())
168 {
169 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
170 return true;
171 }
172 }
173
174 if (!bTest || rFormatExtension.startsWith("DXF"))
175 {
176 if (aDetector.checkDXF())
177 {
178 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
179 return true;
180 }
181 }
182
183 if (!bTest || rFormatExtension.startsWith("PCT"))
184 {
185 bSomethingTested = true;
186 if (aDetector.checkPCT())
187 {
188 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
189 return true;
190 }
191 }
192
193 if (!bTest || rFormatExtension.startsWith("PBM") || rFormatExtension.startsWith("PGM")
194 || rFormatExtension.startsWith("PPM"))
195 {
196 bSomethingTested = true;
197 if (aDetector.checkPBMorPGMorPPM())
198 {
199 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
200 return true;
201 }
202 }
203
204 if (!bTest || rFormatExtension.startsWith("RAS"))
205 {
206 bSomethingTested = true;
207 if (aDetector.checkRAS())
208 {
209 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
210 return true;
211 }
212 }
213
214 if (!bTest)
215 {
216 bSomethingTested = true;
217 if (aDetector.checkXPM())
218 {
219 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
220 return true;
221 }
222 }
223 else if (rFormatExtension.startsWith("XPM"))
224 {
225 return true;
226 }
227
228 if (!bTest)
229 {
230 if (aDetector.checkXBM())
231 {
232 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
233 return true;
234 }
235 }
236 else if (rFormatExtension.startsWith("XBM"))
237 {
238 return true;
239 }
240
241 if (!bTest)
242 {
243 if (aDetector.checkSVG())
244 {
245 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
246 return true;
247 }
248 }
249 else if (rFormatExtension.startsWith("SVG"))
250 {
251 return true;
252 }
253
254 if (!bTest || rFormatExtension.startsWith("TGA"))
255 {
256 bSomethingTested = true;
257 if (aDetector.checkTGA())
258 {
259 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
260 return true;
261 }
262 }
263
264 if (!bTest || rFormatExtension.startsWith("MOV"))
265 {
266 if (aDetector.checkMOV())
267 {
268 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
269 return true;
270 }
271 }
272
273 if (!bTest || rFormatExtension.startsWith("PDF"))
274 {
275 if (aDetector.checkPDF())
276 {
277 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
278 return true;
279 }
280 }
281
282 if (!bTest || rFormatExtension.startsWith("WEBP"))
283 {
284 bSomethingTested = true;
285 if (aDetector.checkWEBP())
286 {
287 rFormatExtension = getImportFormatShortName(aDetector.getMetadata().mnFormat);
288 return true;
289 }
290 }
291
292 return bTest && !bSomethingTested;
293}
294
295namespace
296{
297bool isPCT(SvStream& rStream, sal_uLong nStreamPos, sal_uLong nStreamLen)
298{
299 sal_uInt8 sBuf[3];
300 // store number format
301 SvStreamEndian oldNumberFormat = rStream.GetEndian();
302 sal_uInt32 nOffset; // in MS documents the pict format is used without the first 512 bytes
303 for (nOffset = 0; (nOffset <= 512) && ((nStreamPos + nOffset + 14) <= nStreamLen);
304 nOffset += 512)
305 {
306 short y1, x1, y2, x2;
307 bool bdBoxOk = true;
308
309 rStream.Seek(nStreamPos + nOffset);
310 // size of the pict in version 1 pict ( 2bytes) : ignored
311 rStream.SeekRel(2);
312 // bounding box (bytes 2 -> 9)
313 rStream.SetEndian(SvStreamEndian::BIG);
314 rStream.ReadInt16(y1).ReadInt16(x1).ReadInt16(y2).ReadInt16(x2);
315 rStream.SetEndian(oldNumberFormat); // reset format
316
317 // read version op
318 rStream.ReadBytes(sBuf, 3);
319
320 if (!rStream.good())
321 break;
322
323 if (x1 > x2 || y1 > y2 || // bad bdbox
324 (x1 == x2 && y1 == y2) || // 1 pixel picture
325 x2 - x1 > 2048 || y2 - y1 > 2048) // picture abnormally big
326 bdBoxOk = false;
327
328 // see http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Imaging_With_QuickDraw/Appendix_A.pdf
329 // normal version 2 - page A23 and A24
330 if (sBuf[0] == 0x00 && sBuf[1] == 0x11 && sBuf[2] == 0x02)
331 return true;
332 // normal version 1 - page A25
333 else if (sBuf[0] == 0x11 && sBuf[1] == 0x01 && bdBoxOk)
334 return true;
335 }
336 return false;
337}
338
339} // end anonymous namespace
340
341GraphicFormatDetector::GraphicFormatDetector(SvStream& rStream, OUString aFormatExtension,
342 bool bExtendedInfo)
343 : mrStream(rStream)
344 , maExtension(std::move(aFormatExtension))
345 , mnFirstLong(0)
346 , mnSecondLong(0)
347 , mnStreamPosition(0)
348 , mnStreamLength(0)
349 , mbExtendedInfo(bExtendedInfo)
350 , maMetadata()
351{
352}
353
355{
356 maFirstBytes.clear();
357 maFirstBytes.resize(256, 0);
358
359 mnFirstLong = 0;
360 mnSecondLong = 0;
361
364
365 if (!mnStreamLength)
366 {
367 SvLockBytes* pLockBytes = mrStream.GetLockBytes();
368 if (pLockBytes)
369 pLockBytes->SetSynchronMode();
371 }
372
373 if (mnStreamLength == 0)
374 {
375 return false; // this prevents at least a STL assertion
376 }
377 else if (mnStreamLength >= maFirstBytes.size())
378 {
379 // load first 256 bytes into a buffer
380 sal_uInt64 nRead = mrStream.ReadBytes(maFirstBytes.data(), maFirstBytes.size());
381 if (nRead < maFirstBytes.size())
382 mnStreamLength = nRead;
383 }
384 else
385 {
387 }
388
389 if (mrStream.GetError())
390 return false;
391
392 for (int i = 0; i < 4; ++i)
393 {
394 mnFirstLong = (mnFirstLong << 8) | sal_uInt32(maFirstBytes[i]);
395 mnSecondLong = (mnSecondLong << 8) | sal_uInt32(maFirstBytes[i + 4]);
396 }
397 return true;
398}
399
401{
402 if (maFirstBytes[2] != 0xd3)
403 return false;
404 mrStream.SetEndian(SvStreamEndian::BIG);
406 sal_uInt16 nFieldSize;
408
409 mrStream.ReadUInt16(nFieldSize).ReadUChar(nMagic);
410 for (int i = 0; i < 3; i++)
411 {
412 if (nFieldSize < 6)
413 return false;
414 if (mnStreamLength < mrStream.Tell() + nFieldSize)
415 return false;
416 mrStream.SeekRel(nFieldSize - 3);
417 mrStream.ReadUInt16(nFieldSize).ReadUChar(nMagic);
418 if (nMagic != 0xd3)
419 return false;
420 }
421 mrStream.SetEndian(SvStreamEndian::LITTLE);
422
423 if (mrStream.GetError())
424 return false;
425
427 return true;
428}
429
431{
432 sal_uInt8 nOffset;
433
434 // We're possibly also able to read an OS/2 bitmap array
435 // ('BA'), therefore we must adjust the offset to discover the
436 // first bitmap in the array
437 if (maFirstBytes[0] == 0x42 && maFirstBytes[1] == 0x41)
438 nOffset = 14;
439 else
440 nOffset = 0;
441
442 // Now we initially test on 'BM'
443 if (maFirstBytes[0 + nOffset] == 0x42 && maFirstBytes[1 + nOffset] == 0x4d)
444 {
445 // OS/2 can set the Reserved flags to a value other than 0
446 // (which they really should not do...);
447 // In this case we test the size of the BmpInfoHeaders
448 if ((maFirstBytes[6 + nOffset] == 0x00 && maFirstBytes[7 + nOffset] == 0x00
449 && maFirstBytes[8 + nOffset] == 0x00 && maFirstBytes[9 + nOffset] == 0x00)
450 || maFirstBytes[14 + nOffset] == 0x28 || maFirstBytes[14 + nOffset] == 0x0c)
451 {
453 return true;
454 }
455 }
456 return false;
457}
458
460{
461 sal_uInt64 nCheckSize = std::min<sal_uInt64>(mnStreamLength, 256);
462 sal_uInt8 sExtendedOrDecompressedFirstBytes[WMF_EMF_CHECK_SIZE];
463 sal_uInt64 nDecompressedSize = nCheckSize;
464 // check if it is gzipped -> wmz/emz
465 sal_uInt8* pCheckArray = checkAndUncompressBuffer(sExtendedOrDecompressedFirstBytes,
466 WMF_EMF_CHECK_SIZE, nDecompressedSize);
467 if (mnFirstLong == 0xd7cdc69a || mnFirstLong == 0x01000900)
468 {
469 if (mbWasCompressed)
471 else
473 return true;
474 }
475 else if (mnFirstLong == 0x01000000 && pCheckArray[40] == 0x20 && pCheckArray[41] == 0x45
476 && pCheckArray[42] == 0x4d && pCheckArray[43] == 0x46)
477 {
478 if (mbWasCompressed)
480 else
482 return true;
483 }
484 return false;
485}
486
488{
489 if (maFirstBytes[0] != 0x0a)
490 return false;
491
493 sal_uInt8 nEncoding = maFirstBytes[2];
494 if ((nVersion == 0 || nVersion == 2 || nVersion == 3 || nVersion == 5) && nEncoding <= 1)
495 {
497 return true;
498 }
499
500 return false;
501}
502
504{
505 if (mnFirstLong == 0x49492a00 || mnFirstLong == 0x4d4d002a)
506 {
508 return true;
509 }
510 return false;
511}
512
514{
515 if (mnFirstLong == 0x47494638 && (maFirstBytes[4] == 0x37 || maFirstBytes[4] == 0x39)
516 && maFirstBytes[5] == 0x61)
517 {
519 if (mbExtendedInfo)
520 {
521 sal_uInt16 nWidth = maFirstBytes[6] | (maFirstBytes[7] << 8);
522 sal_uInt16 nHeight = maFirstBytes[8] | (maFirstBytes[9] << 8);
523 maMetadata.maPixSize = Size(nWidth, nHeight);
524 maMetadata.mnBitsPerPixel = ((maFirstBytes[10] & 112) >> 4) + 1;
525 }
526 return true;
527 }
528 return false;
529}
530
532{
533 if (mnFirstLong == 0x89504e47 && mnSecondLong == 0x0d0a1a0a)
534 {
536 return true;
537 }
538 return false;
539}
540
542{
543 if ((mnFirstLong == 0xffd8ffe0 && maFirstBytes[6] == 0x4a && maFirstBytes[7] == 0x46
544 && maFirstBytes[8] == 0x49 && maFirstBytes[9] == 0x46)
545 || (mnFirstLong == 0xffd8fffe) || (0xffd8ff00 == (mnFirstLong & 0xffffff00)))
546 {
548 return true;
549 }
550 return false;
551}
552
554{
555 if (mnFirstLong == 0x53564744 && maFirstBytes[4] == 0x49)
556 {
558 return true;
559 }
560 else if (maFirstBytes[0] == 0x56 && maFirstBytes[1] == 0x43 && maFirstBytes[2] == 0x4C
561 && maFirstBytes[3] == 0x4D && maFirstBytes[4] == 0x54 && maFirstBytes[5] == 0x46)
562 {
564 return true;
565 }
566 return false;
567}
568
570{
571 if (mnStreamLength < 2055)
572 return false;
573 char sBuffer[8];
575 sBuffer[mrStream.ReadBytes(sBuffer, 7)] = 0;
576
577 if (strncmp(sBuffer, "PCD_IPI", 7) == 0)
578 {
580 return true;
581 }
582 return false;
583}
584
586{
587 if ((mnFirstLong == 0x38425053) && ((mnSecondLong >> 16) == 1))
588 {
590 return true;
591 }
592 return false;
593}
594
596{
597 const char* pFirstBytesAsCharArray = reinterpret_cast<char*>(maFirstBytes.data());
598
599 if (mnFirstLong == 0xC5D0D3C6)
600 {
602 return true;
603 }
604 else if (checkArrayForMatchingStrings(pFirstBytesAsCharArray, 30, { "%!PS-Adobe", " EPS" }))
605 {
607 return true;
608 }
609
610 return false;
611}
612
614{
615 if (strncmp(reinterpret_cast<char*>(maFirstBytes.data()), "AutoCAD Binary DXF", 18) == 0)
616 {
618 return true;
619 }
620
621 // ASCII DXF File Format
622 int i = 0;
623 while (i < 256 && maFirstBytes[i] <= 32)
624 {
625 ++i;
626 }
627
628 if (i < 256 && maFirstBytes[i] == '0')
629 {
630 ++i;
631
632 // only now do we have sufficient data to make a judgement
633 // based on a '0' + 'SECTION' == DXF argument
634
635 while (i < 256 && maFirstBytes[i] <= 32)
636 {
637 ++i;
638 }
639
640 if (i + 7 < 256
641 && (strncmp(reinterpret_cast<char*>(maFirstBytes.data() + i), "SECTION", 7) == 0))
642 {
644 return true;
645 }
646 }
647 return false;
648}
649
651{
653 {
655 return true;
656 }
657 return false;
658}
659
661{
662 if (maFirstBytes[0] == 'P')
663 {
664 switch (maFirstBytes[1])
665 {
666 case '1':
667 case '4':
669 return true;
670
671 case '2':
672 case '5':
674 return true;
675
676 case '3':
677 case '6':
679 return true;
680 }
681 }
682 return false;
683}
684
686{
687 if (mnFirstLong == 0x59a66a95)
688 {
690 return true;
691 }
692 return false;
693}
694
696{
697 const char* pFirstBytesAsCharArray = reinterpret_cast<char*>(maFirstBytes.data());
698 if (matchArrayWithString(pFirstBytesAsCharArray, 256, "/* XPM */"))
699 {
701 return true;
702 }
703 return false;
704}
705
707{
708 sal_uInt64 nSize = std::min<sal_uInt64>(mnStreamLength, 2048);
709 std::unique_ptr<sal_uInt8[]> pBuffer(new sal_uInt8[nSize]);
710
712 nSize = mrStream.ReadBytes(pBuffer.get(), nSize);
713
714 const char* pBufferAsCharArray = reinterpret_cast<char*>(pBuffer.get());
715
716 if (checkArrayForMatchingStrings(pBufferAsCharArray, nSize, { "#define", "_width" }))
717 {
719 return true;
720 }
721 return false;
722}
723
725{
726 sal_uInt64 nCheckSize = std::min<sal_uInt64>(mnStreamLength, 256);
727 sal_uInt8 sExtendedOrDecompressedFirstBytes[SVG_CHECK_SIZE];
728 sal_uInt64 nDecompressedSize = nCheckSize;
729 // check if it is gzipped -> svgz
730 sal_uInt8* pCheckArray = checkAndUncompressBuffer(sExtendedOrDecompressedFirstBytes,
731 SVG_CHECK_SIZE, nDecompressedSize);
732 nCheckSize = std::min<sal_uInt64>(nDecompressedSize, 256);
733 bool bIsSvg(false);
734 bool bIsGZip = (nDecompressedSize > 0);
735 const char* pCheckArrayAsCharArray = reinterpret_cast<char*>(pCheckArray);
736 // check for XML
737 // #119176# SVG files which have no xml header at all have shown up this is optional
738 // check for "xml" then "version" then "DOCTYPE" and "svg" tags
739 if (checkArrayForMatchingStrings(pCheckArrayAsCharArray, nCheckSize,
740 { "<?xml", "version", "DOCTYPE", "svg" }))
741 {
742 bIsSvg = true;
743 }
744
745 // check for svg element in 1st 256 bytes
746 // search for '<svg'
747 if (!bIsSvg && checkArrayForMatchingStrings(pCheckArrayAsCharArray, nCheckSize, { "<svg" }))
748 {
749 bIsSvg = true;
750 }
751
752 // extended search for svg element
753 if (!bIsSvg)
754 {
755 // it's a xml, look for '<svg' in full file. Should not happen too
756 // often since the tests above will handle most cases, but can happen
757 // with Svg files containing big comment headers or Svg as the host
758 // language
759
760 pCheckArrayAsCharArray = reinterpret_cast<char*>(sExtendedOrDecompressedFirstBytes);
761
762 if (bIsGZip)
763 {
764 nCheckSize = std::min<sal_uInt64>(nDecompressedSize, 2048);
765 }
766 else
767 {
768 nCheckSize = std::min<sal_uInt64>(mnStreamLength, 2048);
770 nCheckSize = mrStream.ReadBytes(sExtendedOrDecompressedFirstBytes, nCheckSize);
771 }
772
773 // search for '<svg'
774 if (checkArrayForMatchingStrings(pCheckArrayAsCharArray, nCheckSize, { "<svg" }))
775 {
776 bIsSvg = true;
777 }
778 }
779
780 if (bIsSvg)
781 {
782 if (mbWasCompressed)
784 else
786 return true;
787 }
788 return false;
789}
790
792{
793 // Check TGA ver.2 footer bytes
794 if (mnStreamLength > 18)
795 {
796 char sFooterBytes[18];
797
799 mrStream.SeekRel(-18);
800 if (mrStream.ReadBytes(sFooterBytes, 18) == 18
801 && memcmp(sFooterBytes, "TRUEVISION-XFILE.", SAL_N_ELEMENTS(sFooterBytes)) == 0)
802 {
804 return true;
805 }
806 }
807
808 // Fallback to file extension check
809 if (maExtension.startsWith("TGA"))
810 {
812 return true;
813 }
814 return false;
815}
816
818{
819 if ((maFirstBytes[4] == 'f' && maFirstBytes[5] == 't' && maFirstBytes[6] == 'y'
820 && maFirstBytes[7] == 'p' && maFirstBytes[8] == 'q' && maFirstBytes[9] == 't')
821 || (maFirstBytes[4] == 'm' && maFirstBytes[5] == 'o' && maFirstBytes[6] == 'o'
822 && maFirstBytes[7] == 'v' && maFirstBytes[11] == 'l' && maFirstBytes[12] == 'm'))
823 {
825 return true;
826 }
827 return false;
828}
829
831{
832 if (maFirstBytes[0] == '%' && maFirstBytes[1] == 'P' && maFirstBytes[2] == 'D'
833 && maFirstBytes[3] == 'F' && maFirstBytes[4] == '-')
834 {
836 return true;
837 }
838 return false;
839}
840
842{
843 if (maFirstBytes[0] == 'R' && maFirstBytes[1] == 'I' && maFirstBytes[2] == 'F'
844 && maFirstBytes[3] == 'F' && maFirstBytes[8] == 'W' && maFirstBytes[9] == 'E'
845 && maFirstBytes[10] == 'B' && maFirstBytes[11] == 'P')
846 {
848 return true;
849 }
850 return false;
851}
852
854
856 sal_uInt32 nSize, sal_uInt64& nRetSize)
857{
859 {
860 ZCodec aCodec;
862 aCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/ true);
863 auto nDecompressedOut = aCodec.Read(mrStream, aUncompressedBuffer, nSize);
864 // ZCodec::Decompress returns -1 on failure
865 nRetSize = nDecompressedOut < 0 ? 0 : nDecompressedOut;
866 aCodec.EndCompression();
867 // Recalculate first/second long
868 for (int i = 0; i < 4; ++i)
869 {
870 mnFirstLong = (mnFirstLong << 8) | sal_uInt32(aUncompressedBuffer[i]);
871 mnSecondLong = (mnSecondLong << 8) | sal_uInt32(aUncompressedBuffer[i + 4]);
872 }
873 mbWasCompressed = true;
874 return aUncompressedBuffer;
875 }
876 nRetSize = 0;
877 mbWasCompressed = false;
878 return maFirstBytes.data();
879}
880
881} // vcl namespace
882
883/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr sal_uInt32 WMF_EMF_CHECK_SIZE
constexpr sal_uInt32 SVG_CHECK_SIZE
void SetSynchronMode(bool bTheSync=true)
sal_uInt64 Tell() const
void SetEndian(SvStreamEndian SvStreamEndian)
bool good() const
SvStream & ReadInt16(sal_Int16 &rInt16)
SvStreamEndian GetEndian() const
SvLockBytes * GetLockBytes() const
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
sal_uInt64 SeekRel(sal_Int64 nPos)
ErrCode GetError() const
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
sal_uInt64 remainingSize()
SvStream & ReadUChar(unsigned char &rChar)
tools::Long Read(SvStream &rIStm, sal_uInt8 *pData, sal_uInt32 nSize)
static bool IsZCompressed(SvStream &rIStm)
tools::Long EndCompression()
void BeginCompression(int nCompressLevel=ZCODEC_DEFAULT_COMPRESSION, bool gzLib=false)
const GraphicMetadata & getMetadata()
sal_uInt8 * checkAndUncompressBuffer(sal_uInt8 *aUncompressedBuffer, sal_uInt32 nSize, sal_uInt64 &nDecompressedSize)
Checks whether mrStream needs to be uncompressed and returns a pointer to the to aUncompressedBuffer ...
std::vector< sal_uInt8 > maFirstBytes
GraphicFormatDetector(SvStream &rStream, OUString aFormatExtension, bool bExtendedInfo=false)
sal_Int16 nVersion
bool isPCT(SvStream &rStream, sal_uLong nStreamPos, sal_uLong nStreamLen)
#define SAL_N_ELEMENTS(arr)
int i
bool peekGraphicFormat(SvStream &rStream, OUString &rFormatExtension, bool bTest)
static OUString getImportFormatShortName(GraphicFileFormat nFormat)
bool checkArrayForMatchingStrings(const char *pSource, sal_Int32 nSourceSize, std::vector< OString > const &rStrings)
const char * matchArrayWithString(const char *pSource, sal_Int32 nSourceSize, OString const &rString)
const sal_uInt16 nMagic
sal_uIntPtr sal_uLong
#define STREAM_SEEK_TO_END
SvStreamEndian
GraphicFileFormat mnFormat
sal_uInt16 mnBitsPerPixel
unsigned char sal_uInt8
#define ZCODEC_DEFAULT_COMPRESSION