LCOV - code coverage report
Current view: top level - core/bitmap - SPBitmapCustom.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 94 113 83.2 %
Date: 2024-05-12 00:16:13 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #include "SPBitmapFormat.h"
      25             : #include "SPHtmlParser.h"
      26             : #include "SPLog.h"
      27             : 
      28             : namespace STAPPLER_VERSIONIZED stappler::bitmap::custom {
      29             : 
      30        1500 : static size_t detectSvgSize(StringView value) {
      31        1500 :         StringView str(value);
      32        1500 :         auto fRes = str.readFloat();
      33        1500 :         if (!fRes.valid()) {
      34           0 :                 return 0;
      35             :         }
      36             : 
      37        1500 :         auto fvalue = fRes.get();
      38        1500 :         if (fvalue == 0.0f) {
      39           0 :                 return 0;
      40             :         }
      41             : 
      42        1500 :         str.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
      43             : 
      44        1500 :         if (str == "px" || str.empty()) {
      45             :                 // do nothing
      46         900 :         } else if (str == "pt") {
      47         225 :                 fvalue = fvalue * 4.0f / 3.0f;
      48         675 :         } else if (str == "pc") {
      49         225 :                 fvalue = fvalue * 15.0f;
      50         450 :         } else if (str == "mm") {
      51         225 :                 fvalue = fvalue * 3.543307f;
      52         225 :         } else if (str == "cm") {
      53         225 :                 fvalue = fvalue * 35.43307f;
      54             :         } else {
      55           0 :                 log::error("Bitmap", "Invalid size metric in svg: %s", str.data());
      56           0 :                 return 0;
      57             :         }
      58             : 
      59        1500 :         return size_t(ceilf(fvalue));
      60             : }
      61             : 
      62        2525 : static bool detectSvg(StringView str, uint32_t &w, uint32_t &h) {
      63        2525 :         str.skipUntilString("<svg", true);
      64        2525 :         if (!str.starts_with("<svg")) {
      65        1775 :                 return false;
      66             :         }
      67         750 :         str += "<svg"_len;
      68             : 
      69         750 :         if (!str.empty() && str.is<StringView::CharGroup<CharGroupId::WhiteSpace>>()) {
      70         750 :                 bool found = false;
      71         750 :                 bool isSvg = false;
      72         750 :                 uint32_t width = 0;
      73         750 :                 uint32_t height = 0;
      74        3700 :                 while (!found && !str.empty()) {
      75        2950 :                         str.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
      76        2950 :                         auto key = html::Tag_readAttrName(str);
      77        2950 :                         auto value = html::Tag_readAttrValue(str);
      78        2950 :                         if (!key.empty() && !value.empty()) {
      79        2950 :                                 if (key == "xmlns") {
      80         750 :                                         if (value.is("http://www.w3.org/2000/svg")) {
      81         750 :                                                 isSvg = true;
      82             :                                         }
      83        2200 :                                 } else if (key == "width") {
      84         750 :                                         width = detectSvgSize(value);
      85        1450 :                                 } else if (key == "height") {
      86         750 :                                         height = detectSvgSize(value);
      87             :                                 }
      88        2950 :                                 if (isSvg && width && height) {
      89         750 :                                         found = true;
      90             :                                 }
      91             :                         }
      92             :                 }
      93         750 :                 if (isSvg) {
      94         750 :                         w = width;
      95         750 :                         h = height;
      96             :                 }
      97         750 :                 return isSvg;
      98             :         }
      99             : 
     100           0 :         return false;
     101             : }
     102             : 
     103        1725 : static bool detectSvg(const StringView &buf) {
     104        1725 :         uint32_t w = 0, h = 0;
     105        3450 :         return detectSvg(buf, w, h);
     106             : }
     107             : 
     108        1725 : static bool isSvg(const uint8_t * data, size_t dataLen) {
     109        1725 :         if (dataLen <= 127) {
     110           0 :                 return false;
     111             :         }
     112             : 
     113        1725 :         return detectSvg(StringView((const char *)data, dataLen));
     114             : }
     115             : 
     116         800 : static bool getSvgImageSize(const io::Producer &file, StackBuffer<512> &data, uint32_t &width, uint32_t &height) {
     117         800 :         if (detectSvg(StringView((const char *)data.data(), data.size()), width, height)) {
     118         225 :                 return true;
     119             :         }
     120             : 
     121         575 :         return false;
     122             : }
     123             : 
     124         650 : static bool isTiff(const uint8_t * data, size_t dataLen) {
     125         650 :         if (dataLen <= 4) {
     126           0 :                 return false;
     127             :         }
     128             : 
     129             :         static const char* TIFF_II = "II";
     130             :         static const char* TIFF_MM = "MM";
     131             : 
     132        1075 :         return (memcmp(data, TIFF_II, 2) == 0 && *(static_cast<const unsigned char*>(data) + 2) == 42 && *(static_cast<const unsigned char*>(data) + 3) == 0) ||
     133        1075 :                 (memcmp(data, TIFF_MM, 2) == 0 && *(static_cast<const unsigned char*>(data) + 2) == 0 && *(static_cast<const unsigned char*>(data) + 3) == 42);
     134             : }
     135             : 
     136             : template <typename Reader>
     137         150 : static bool getTiffImageSizeImpl(const io::Producer &file, StackBuffer<512> &data, uint32_t &width, uint32_t &height) {
     138         150 :         auto reader = Reader(data.data() + 4, 4);
     139         150 :         auto offset = reader.readUnsigned32();
     140             : 
     141         150 :         data.clear();
     142         150 :         if (file.seekAndRead(offset, data, 2) != 2) {
     143           0 :                 return false;
     144             :         }
     145         150 :         auto size = Reader(data.data(), 2).readUnsigned16();
     146         150 :         auto dictSize = size * 12;
     147         150 :         offset += 2;
     148         150 :         while (dictSize > 0) {
     149         150 :                 data.clear();
     150         150 :                 size_t blockSize = min(12 * 21, dictSize);
     151         150 :                 if (file.read(data, blockSize) != blockSize) {
     152           0 :                         return false;
     153             :                 }
     154             : 
     155         150 :                 auto blocks = blockSize / 12;
     156         150 :                 reader = Reader(data.data(), blockSize);
     157             : 
     158         300 :                 for (uint16_t i = 0; i < blocks; ++i) {
     159         300 :                         auto tagid = reader.readUnsigned16();
     160         300 :                         auto type = reader.readUnsigned16();
     161         300 :                         auto count = reader.readUnsigned32();
     162         300 :                         if (tagid == 256 && count == 1) {
     163         150 :                                 if (type == 3) {
     164         150 :                                         width = reader.readUnsigned16();
     165         150 :                                         reader.offset(2);
     166           0 :                                 } else if (type == 4) {
     167           0 :                                         width = reader.readUnsigned32();
     168             :                                 } else {
     169           0 :                                         reader.offset(4);
     170             :                                 }
     171         150 :                         } else if (tagid == 257 && count == 1) {
     172         150 :                                 if (type == 3) {
     173         150 :                                         height = reader.readUnsigned16();
     174         150 :                                         reader.offset(2);
     175           0 :                                 } else if (type == 4) {
     176           0 :                                         height = reader.readUnsigned32();
     177             :                                 } else {
     178           0 :                                         reader.offset(4);
     179             :                                 }
     180         150 :                                 return true;
     181             :                         } else {
     182           0 :                                 if (tagid > 257) {
     183           0 :                                         return false;
     184             :                                 }
     185           0 :                                 reader.offset(4);
     186             :                         }
     187             :                 }
     188             :         }
     189           0 :         return false;
     190             : }
     191             : 
     192         200 : static bool getTiffImageSize(const io::Producer &file, StackBuffer<512> &data, uint32_t &width, uint32_t &height) {
     193         200 :         if (isTiff(data.data(), data.size())) {
     194         150 :                 if (memcmp(data.data(), "II", 2) == 0) {
     195          75 :                         if (getTiffImageSizeImpl<BytesViewTemplate<Endian::Little>>(file, data, width, height)) {
     196          75 :                                 return true;
     197             :                         }
     198             :                 } else {
     199          75 :                         if (getTiffImageSizeImpl<BytesViewTemplate<Endian::Big>>(file, data, width, height)) {
     200          75 :                                 return true;
     201             :                         }
     202             :                 }
     203             :         }
     204          50 :         return false;
     205             : }
     206             : 
     207             : }

Generated by: LCOV version 1.14