vcl/inc/graphic/DetectorTools.hxx            |   63 ++++++++++++++++
 vcl/qa/cppunit/GraphicFormatDetectorTest.cxx |  106 +++++++++++++++++++++++++++
 vcl/source/filter/GraphicFormatDetector.cxx  |   53 ++++---------
 3 files changed, 188 insertions(+), 34 deletions(-)

New commits:
commit bb459008de9d410e6e7ea982ce30aa22f70ae849
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Sat May 2 14:35:23 2020 +0200
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Sun May 3 19:37:13 2020 +0200

    vcl: add DetectorTools + tests, refactor array string matching
    
    Add DetectorTools with byte array searching and matching to a
    input string (or another byte array). This refactors the existing
    function in GraphicFormatDetector. It needs to go into its own
    header so that the function(s) can be tested easily. Replace
    the previous searchEntry implementation with refactored one in
    the source code.
    
    Change-Id: I59d30b694e13f28d6366f1a99fe2ef2ea3c1a07d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93339
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/vcl/inc/graphic/DetectorTools.hxx 
b/vcl/inc/graphic/DetectorTools.hxx
new file mode 100644
index 000000000000..b9163de135d9
--- /dev/null
+++ b/vcl/inc/graphic/DetectorTools.hxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+namespace vcl
+{
+const char* matchArray(const char* pSource, sal_Int32 nSourceSize, const char* 
pSearch,
+                       sal_Int32 nSearchSize)
+{
+    for (sal_Int32 increment = 0; increment <= (nSourceSize - nSearchSize); 
++increment)
+    {
+        bool bMatch = true;
+        // search both arrays if they match
+        for (sal_Int32 index = 0; index < nSearchSize && bMatch; ++index)
+        {
+            if (pSource[index] != pSearch[index])
+                bMatch = false;
+        }
+        // match has been found
+        if (bMatch)
+            return pSource;
+        pSource++;
+    }
+    return nullptr;
+}
+
+const char* matchArrayWithString(const char* pSource, sal_Int32 nSourceSize, 
OString const& rString)
+{
+    return matchArray(pSource, nSourceSize, rString.getStr(), 
rString.getLength());
+}
+
+bool checkArrayForMatchingStrings(const char* pSource, sal_Int32 nSourceSize,
+                                  std::vector<OString> const& rStrings)
+{
+    if (rStrings.empty())
+        return false;
+    if (rStrings.size() < 2)
+        return matchArrayWithString(pSource, nSourceSize, rStrings[0]) != 
nullptr;
+
+    const char* pBegin = pSource;
+    const char* pCurrent = pSource;
+    for (OString const& rString : rStrings)
+    {
+        sal_Int32 nCurrentSize = nSourceSize - sal_Int32(pCurrent - pBegin);
+        printf("Current size %d -> %d\n", nCurrentSize, nSourceSize);
+        pCurrent = matchArray(pCurrent, nCurrentSize, rString.getStr(), 
rString.getLength());
+        if (pCurrent == nullptr)
+            return false;
+        printf("%s\n", pCurrent);
+    }
+    return true;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx 
b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx
index 90183279dbc9..155ff089811b 100644
--- a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx
+++ b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx
@@ -12,6 +12,7 @@
 #include <unotest/bootstrapfixturebase.hxx>
 
 #include <graphic/GraphicFormatDetector.hxx>
+#include <graphic/DetectorTools.hxx>
 
 #include <tools/stream.hxx>
 
@@ -41,6 +42,8 @@ class GraphicFormatDetectorTest : public 
test::BootstrapFixtureBase
     void testDetectSVG();
     void testDetectSVGZ();
     void testDetectPDF();
+    void testMatchArray();
+    void testCheckArrayForMatchingStrings();
 
     CPPUNIT_TEST_SUITE(GraphicFormatDetectorTest);
     CPPUNIT_TEST(testDetectMET);
@@ -58,6 +61,8 @@ class GraphicFormatDetectorTest : public 
test::BootstrapFixtureBase
     CPPUNIT_TEST(testDetectSVG);
     CPPUNIT_TEST(testDetectSVGZ);
     CPPUNIT_TEST(testDetectPDF);
+    CPPUNIT_TEST(testMatchArray);
+    CPPUNIT_TEST(testCheckArrayForMatchingStrings);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -286,6 +291,107 @@ void GraphicFormatDetectorTest::testDetectPDF()
     CPPUNIT_ASSERT_EQUAL(OUString("PDF"), rFormatExtension);
 }
 
+void GraphicFormatDetectorTest::testMatchArray()
+{
+    std::string aString("<?xml version=\"1.0\" standalone=\"no\"?>\n"
+                        "<svg width=\"5cm\" height=\"4cm\" version=\"1.1\"\n"
+                        "xmlns=\"http://www.w3.org/2000/svg\";>\n"
+                        "</svg>");
+
+    const char* pCompleteStringPointer = aString.c_str();
+    const char* pMatchPointer;
+    int nCheckSize = aString.size();
+
+    // Check beginning of the input string
+    pMatchPointer = vcl::matchArrayWithString(pCompleteStringPointer, 
nCheckSize, "<?xml");
+    CPPUNIT_ASSERT(pMatchPointer != nullptr);
+    CPPUNIT_ASSERT_EQUAL(0, int(pMatchPointer - pCompleteStringPointer));
+    CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("<?xml"));
+
+    // Check middle of the input string
+    pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, 
"version");
+    CPPUNIT_ASSERT(pMatchPointer != nullptr);
+    CPPUNIT_ASSERT_EQUAL(6, int(pMatchPointer - pCompleteStringPointer));
+    CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("version"));
+
+    pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, 
"<svg");
+    CPPUNIT_ASSERT(pMatchPointer != nullptr);
+    CPPUNIT_ASSERT_EQUAL(38, int(pMatchPointer - pCompleteStringPointer));
+    CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("<svg"));
+
+    // Check end of the input string
+    pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, 
"/svg>");
+    CPPUNIT_ASSERT(pMatchPointer != nullptr);
+    CPPUNIT_ASSERT_EQUAL(119, int(pMatchPointer - pCompleteStringPointer));
+    CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("/svg>"));
+
+    // Check that non-existing search string
+    pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, 
"none");
+    CPPUNIT_ASSERT(pMatchPointer == nullptr);
+}
+
+void GraphicFormatDetectorTest::testCheckArrayForMatchingStrings()
+{
+    std::string aString("<?xml version=\"1.0\" standalone=\"no\"?>\n"
+                        "<svg width=\"5cm\" height=\"4cm\" version=\"1.1\"\n"
+                        "xmlns=\"http://www.w3.org/2000/svg\";>\n"
+                        "</svg>");
+    const char* pCompleteStringPointer = aString.c_str();
+    int nCheckSize = aString.size();
+    bool bResult;
+
+    // check beginning string
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize, { "<?xml" });
+    CPPUNIT_ASSERT_EQUAL(true, bResult);
+
+    // check ending string
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize, { "/svg>" });
+    CPPUNIT_ASSERT_EQUAL(true, bResult);
+
+    // check middle string
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize, { "version" });
+    CPPUNIT_ASSERT_EQUAL(true, bResult);
+
+    // check beginning and then ending string
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize,
+                                                { "<?xml", "/svg>" });
+    CPPUNIT_ASSERT_EQUAL(true, bResult);
+
+    // check ending and then beginning string
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize,
+                                                { "/svg>", "<?xml" });
+    CPPUNIT_ASSERT_EQUAL(false, bResult);
+
+    // check middle strings
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize,
+                                                { "version", "<svg" });
+    CPPUNIT_ASSERT_EQUAL(true, bResult);
+
+    // check beginning, middle and ending strings
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize,
+                                                { "<?xml", "version", "<svg", 
"/svg>" });
+    CPPUNIT_ASSERT_EQUAL(true, bResult);
+
+    // check non-existing
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize, { "none" });
+    CPPUNIT_ASSERT_EQUAL(false, bResult);
+
+    // check non-existing on the beginning
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize,
+                                                { "none", "version", "<svg", 
"/svg>" });
+    CPPUNIT_ASSERT_EQUAL(false, bResult);
+
+    // check non-existing on the end
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize,
+                                                { "<?xml", "version", "<svg", 
"none" });
+    CPPUNIT_ASSERT_EQUAL(false, bResult);
+
+    // check non-existing after the end
+    bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, 
nCheckSize,
+                                                { "<?xml", "/svg>", "none" });
+    CPPUNIT_ASSERT_EQUAL(false, bResult);
+}
+
 } // namespace
 
 CPPUNIT_TEST_SUITE_REGISTRATION(GraphicFormatDetectorTest);
diff --git a/vcl/source/filter/GraphicFormatDetector.cxx 
b/vcl/source/filter/GraphicFormatDetector.cxx
index 56624074366e..5682d78f8e3c 100644
--- a/vcl/source/filter/GraphicFormatDetector.cxx
+++ b/vcl/source/filter/GraphicFormatDetector.cxx
@@ -22,6 +22,7 @@
 #include <algorithm>
 
 #include <graphic/GraphicFormatDetector.hxx>
+#include <graphic/DetectorTools.hxx>
 #include <tools/solar.h>
 #include <tools/zcodec.hxx>
 
@@ -67,23 +68,6 @@ bool isPCT(SvStream& rStream, sal_uLong nStreamPos, 
sal_uLong nStreamLen)
     return false;
 }
 
-sal_uInt8* searchEntry(sal_uInt8* pSource, const char* pDest, sal_uLong nComp, 
sal_uLong nSize)
-{
-    while (nComp-- >= nSize)
-    {
-        sal_uLong i;
-        for (i = 0; i < nSize; i++)
-        {
-            if ((pSource[i] & ~0x20) != (pDest[i] & ~0x20))
-                break;
-        }
-        if (i == nSize)
-            return pSource;
-        pSource++;
-    }
-    return nullptr;
-}
-
 } // end anonymous namespace
 
 GraphicFormatDetector::GraphicFormatDetector(SvStream& rStream, OUString 
const& rFormatExtension)
@@ -320,13 +304,15 @@ bool GraphicFormatDetector::checkPSD()
 
 bool GraphicFormatDetector::checkEPS()
 {
+    const char* pFirstBytesAsCharArray = 
reinterpret_cast<char*>(maFirstBytes.data());
+
     if (mnFirstLong == 0xC5D0D3C6)
     {
         msDetectedFormat = "EPS";
         return true;
     }
-    else if (searchEntry(maFirstBytes.data(), "%!PS-Adobe", 10, 10)
-             && searchEntry(&maFirstBytes[15], "EPS", 3, 3))
+    else if (matchArrayWithString(pFirstBytesAsCharArray, 10, "%!PS-Adobe")
+             && matchArrayWithString(pFirstBytesAsCharArray + 15, 3, "EPS"))
     {
         msDetectedFormat = "EPS";
         return true;
@@ -419,7 +405,8 @@ bool GraphicFormatDetector::checkRAS()
 
 bool GraphicFormatDetector::checkXPM()
 {
-    if (searchEntry(maFirstBytes.data(), "/* XPM */", 256, 9))
+    const char* pFirstBytesAsCharArray = 
reinterpret_cast<char*>(maFirstBytes.data());
+    if (matchArrayWithString(pFirstBytesAsCharArray, 256, "/* XPM */"))
     {
         msDetectedFormat = "XPM";
         return true;
@@ -434,15 +421,13 @@ bool GraphicFormatDetector::checkXBM()
 
     mrStream.Seek(mnStreamPosition);
     mrStream.ReadBytes(pBuffer.get(), nSize);
-    sal_uInt8* pPtr = searchEntry(pBuffer.get(), "#define", nSize, 7);
 
-    if (pPtr)
+    const char* pBufferAsCharArray = reinterpret_cast<char*>(pBuffer.get());
+
+    if (checkArrayForMatchingStrings(pBufferAsCharArray, nSize, { "#define", 
"_width" }))
     {
-        if (searchEntry(pPtr, "_width", pBuffer.get() + nSize - pPtr, 6))
-        {
-            msDetectedFormat = "XBM";
-            return true;
-        }
+        msDetectedFormat = "XBM";
+        return true;
     }
     return false;
 }
@@ -473,20 +458,20 @@ bool GraphicFormatDetector::checkSVG()
 
     bool bIsSvg(false);
 
+    const char* pCheckArrayAsCharArray = reinterpret_cast<char*>(pCheckArray);
+
     // check for XML
     // #119176# SVG files which have no xml header at all have shown up this 
is optional
     // check for "xml" then "version" then "DOCTYPE" and "svg" tags
-    if (searchEntry(pCheckArray, "<?xml", nCheckSize, 5)
-        && searchEntry(pCheckArray, "version", nCheckSize, 7)
-        && searchEntry(pCheckArray, "DOCTYPE", nCheckSize, 7)
-        && searchEntry(pCheckArray, "svg", nCheckSize, 3))
+    if (checkArrayForMatchingStrings(pCheckArrayAsCharArray, nCheckSize,
+                                     { "<?xml", "version", "DOCTYPE", "svg" }))
     {
         bIsSvg = true;
     }
 
     // check for svg element in 1st 256 bytes
     // search for '<svg'
-    if (!bIsSvg && searchEntry(pCheckArray, "<svg", nCheckSize, 4))
+    if (!bIsSvg && checkArrayForMatchingStrings(pCheckArrayAsCharArray, 
nCheckSize, { "<svg" }))
     {
         bIsSvg = true;
     }
@@ -499,7 +484,7 @@ bool GraphicFormatDetector::checkSVG()
         // with Svg files containing big comment headers or Svg as the host
         // language
 
-        pCheckArray = sExtendedOrDecompressedFirstBytes;
+        pCheckArrayAsCharArray = 
reinterpret_cast<char*>(sExtendedOrDecompressedFirstBytes);
 
         if (bIsGZip)
         {
@@ -513,7 +498,7 @@ bool GraphicFormatDetector::checkSVG()
         }
 
         // search for '<svg'
-        if (searchEntry(pCheckArray, "<svg", nCheckSize, 4))
+        if (checkArrayForMatchingStrings(pCheckArrayAsCharArray, nCheckSize, { 
"<svg" }))
         {
             bIsSvg = true;
         }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to