zlib is now mandatory component; implemented table pack/unpack
authorVictor Kirhenshtein <victor@netxms.org>
Mon, 15 Aug 2016 16:09:10 +0000 (19:09 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Mon, 15 Aug 2016 16:09:10 +0000 (19:09 +0300)
configure.ac
include/nms_util.h
src/libnetxms/Makefile.am
src/libnetxms/table.cpp
tests/test-libnetxms/test-libnetxms.cpp

index a98bad9..19fd96c 100644 (file)
@@ -59,7 +59,6 @@ BUILD_AGENT="no"
 BUILD_CLIENT="no"
 BUILD_STATIC_AGENT="no"
 BUILD_SDK="no"
-NEED_ZLIB="no"
 MODULES="libnetxms tools install"
 STATIC_SUBAGENT_LIST=""
 PROPOSED_STATIC_SUBAGENTS="default"
@@ -618,7 +617,6 @@ fi
 
 check_substr "$COMPONENTS" "snmp"
 if test $? = 0; then
-       NEED_ZLIB="yes"
        MODULES="$MODULES snmp"
 fi
 
@@ -791,7 +789,6 @@ fi
 check_substr "$COMPONENTS" "client"
 if test $? = 0; then
        BUILD_CLIENT="yes"
-       NEED_ZLIB="yes"
        MODULES="$MODULES client"
        CLIENT_COMPONENTS="$CLIENT_COMPONENTS nxalarm nxevent nxpush nxsms"
 fi
@@ -841,7 +838,6 @@ fi
 
 check_substr "$COMPONENTS" "raspberrypi"
 if test $? = 0; then
-       NEED_ZLIB="yes"
        SUBAGENT_DIRS="$SUBAGENT_DIRS rpi"
 fi
 
@@ -1697,20 +1693,18 @@ if test $? = 0; then
        fi
 fi
 
-if test "x$NEED_ZLIB" = "xyes"; then
-       if test "x$FORCE_INTERNAL_ZLIB" = "xyes"; then
-               HAVE_ZLIB=no
-       else
-               HAVE_ZLIB=yes
-               AC_CHECK_HEADER(zlib.h,,HAVE_ZLIB=no)
-               if test "x$HAVE_ZLIB" = "xyes"; then
-                       AC_CHECK_LIB(z, deflate, [], [ HAVE_ZLIB=no ])
-               fi
-       fi
-       if test "x$HAVE_ZLIB" = "xno"; then
-               MODULES="zlib $MODULES"
+if test "x$FORCE_INTERNAL_ZLIB" = "xyes"; then
+       HAVE_ZLIB=no
+else
+       HAVE_ZLIB=yes
+       AC_CHECK_HEADER(zlib.h,,HAVE_ZLIB=no)
+       if test "x$HAVE_ZLIB" = "xyes"; then
+               AC_CHECK_LIB(z, deflate, [], [ HAVE_ZLIB=no ])
        fi
 fi
+if test "x$HAVE_ZLIB" = "xno"; then
+       MODULES="zlib $MODULES"
+fi
 
 if test "x$FORCE_INTERNAL_EXPAT" = "xyes"; then
        HAVE_LIBEXPAT=no
@@ -3034,7 +3028,7 @@ AM_CONDITIONAL([USE_INTERNAL_EXPAT], [test "x$HAVE_LIBEXPAT" = "xno"])
 AM_CONDITIONAL([USE_INTERNAL_LIBTRE], [test "x$HAVE_LIBTRE" = "xno"])
 AM_CONDITIONAL([USE_INTERNAL_JANSSON], [test "x$HAVE_JANSSON" = "xno"])
 AM_CONDITIONAL([USE_INTERNAL_SQLITE], [test "x$HAVE_SQLITE" = "xno"])
-AM_CONDITIONAL([USE_INTERNAL_ZLIB], [test "$NEED_ZLIB/$HAVE_ZLIB" = "yes/no"])
+AM_CONDITIONAL([USE_INTERNAL_ZLIB], [test "$HAVE_ZLIB" = "no"])
 AM_CONDITIONAL([STATIC_BUILD], [test "x$STATIC_BUILD" = "xyes"])
 AM_CONDITIONAL([ALL_STATIC], [test "x$ALL_STATIC" = "xyes"])
 AM_CONDITIONAL([USE_ENCRYPTION], [test "x${HAVE_LIBCRYPTO}" = "xyes"])
@@ -3469,12 +3463,10 @@ if test $? = 0; then
                echo "Use internal sqlite     : NO"
        fi
 fi
-if test "x${NEED_ZLIB}" = "xyes"; then
-       if test "x${HAVE_ZLIB}" = "xno"; then
-               echo "Use internal zlib       : YES"
-       else
-               echo "Use internal zlib       : NO"
-       fi
+if test "x${HAVE_ZLIB}" = "xno"; then
+       echo "Use internal zlib       : YES"
+else
+       echo "Use internal zlib       : NO"
 fi
 if test "x${FORCE_32BIT_BUILD}" = "xyes"; then
        echo "Force 32bit build       : YES"
index 754b228..5ab7cb8 100644 (file)
@@ -1117,6 +1117,9 @@ public:
 
    static Table *createFromXML(const char *xml);
    TCHAR *createXML();
+
+   static Table *createFromPackedXML(const char *packedXml);
+   char *createPackedXML();
 };
 
 /**
index 450e7a0..c0ed9ac 100644 (file)
@@ -29,6 +29,10 @@ endif
 if USE_INTERNAL_LIBTRE
 libnetxms_la_LIBADD += ../libtre/libnxtre.la
 endif
+if USE_INTERNAL_ZLIB
+libnetxms_la_CPPFLAGS += -I../../zlib
+libnetxms_la_LIBADD += ../../zlib/libnxzlib.la
+endif
 
 EXTRA_DIST = \
        libnetxms.vcproj \
index 07f5639..aacf41a 100644 (file)
 
 #include "libnetxms.h"
 #include <expat.h>
+#include <zlib.h>
+
+#define DEFAULT_OBJECT_ID  (0)
+#define DEFAULT_STATUS     (-1)
 
 /**
  * Create empty table row
@@ -30,7 +34,7 @@ TableRow::TableRow(int columnCount)
 {
    m_cells = new ObjectArray<TableCell>(columnCount, 8, true);
    for(int i = 0; i < columnCount; i++)
-      m_cells->add(new TableCell);
+      m_cells->add(new TableCell());
    m_objectId = 0;
 }
 
@@ -83,6 +87,26 @@ Table::Table(Table *src) : RefCountObject()
       m_columns->add(new TableColumnDefinition(src->m_columns->get(i)));
 }
 
+/**
+ * Table destructor
+ */
+Table::~Table()
+{
+   destroy();
+   delete m_columns;
+   delete m_data;
+}
+
+/**
+ * Destroy table data
+ */
+void Table::destroy()
+{
+   m_columns->clear();
+   m_data->clear();
+   safe_free(m_title);
+}
+
 /**
  * XML parser state for creating LogParser object from XML
  */
@@ -175,7 +199,7 @@ static void StartElement(void *userData, const char *name, const char **attrs)
       if (ps->state == XML_STATE_DATA)
       {
          ps->table->addRow();
-         ps->table->setObjectId(ps->table->getNumRows() - 1, XMLGetAttrInt(attrs, "objectId", 0));
+         ps->table->setObjectId(ps->table->getNumRows() - 1, XMLGetAttrInt(attrs, "objectId", DEFAULT_OBJECT_ID));
          ps->column = 0;
                   ps->state = XML_STATE_ROW;
       }
@@ -188,7 +212,7 @@ static void StartElement(void *userData, const char *name, const char **attrs)
        {
       if (ps->state == XML_STATE_ROW)
       {
-         ps->table->setStatus(ps->column, XMLGetAttrInt(attrs, "status", 0));
+         ps->table->setStatus(ps->column, XMLGetAttrInt(attrs, "status", DEFAULT_STATUS));
          ps->state = XML_STATE_CELL;
          ps->buffer->clear();
       }
@@ -285,6 +309,38 @@ Table *Table::createFromXML(const char *xml)
    return NULL;
 }
 
+/**
+ * Create table from packed XML document
+ */
+Table *Table::createFromPackedXML(const char *packedXml)
+{
+   char *compressedXml = NULL;
+   size_t compressedSize = 0;
+   base64_decode_alloc(packedXml, strlen(packedXml), &compressedXml, &compressedSize);
+   if (compressedXml == NULL)
+      return NULL;
+
+   size_t xmlSize = (size_t)ntohl(*((UINT32 *)compressedXml));
+   char *xml = (char *)malloc(xmlSize + 1);
+   uLongf uncompSize = (uLongf)xmlSize;
+   if (uncompress((BYTE *)xml, &uncompSize, (BYTE *)&compressedXml[4], compressedSize - 4) != Z_OK)
+   {
+      free(xml);
+      return NULL;
+   }
+   xml[xmlSize] = 0;
+
+   Table *table = new Table();
+   if (table->parseXML(xml))
+   {
+      free(xml);
+      return table;
+   }
+   free(xml);
+   delete table;
+   return NULL;
+}
+
 /**
  * Create XML document from table
  */
@@ -304,11 +360,26 @@ TCHAR *Table::createXML()
    xml.append(_T("<data>\r\n"));
    for(i = 0; i < m_data->size(); i++)
    {
-      xml.appendFormattedString(_T("<tr objectId=\"%d\">\r\n"), m_data->get(i)->getObjectId());
+      UINT32 objectId = m_data->get(i)->getObjectId();
+      if (objectId != DEFAULT_OBJECT_ID)
+         xml.appendFormattedString(_T("<tr objectId=\"%u\">\r\n"), objectId);
+      else
+         xml.append(_T("<tr>\r\n"));
       for(int j = 0; j < m_columns->size(); j++)
       {
-         xml.appendFormattedString(_T("<td status=\"%d\">%s</td>\r\n"), m_data->get(i)->getStatus(j),
-                                    (const TCHAR *)EscapeStringForXML2(m_data->get(i)->getValue(j), -1));
+         int status = m_data->get(i)->getStatus(j);
+         if (status != DEFAULT_STATUS)
+         {
+            xml.append(_T("<td status=\""));
+            xml.append(status);
+            xml.append(_T("\">"));
+         }
+         else
+         {
+            xml.append(_T("<td>"));
+         }
+         xml.append((const TCHAR *)EscapeStringForXML2(m_data->get(i)->getValue(j), -1));
+         xml.append(_T("</td>\r\n"));
       }
       xml.append(_T("</tr>\r\n"));
    }
@@ -318,23 +389,30 @@ TCHAR *Table::createXML()
 }
 
 /**
- * Table destructor
- */
-Table::~Table()
-{
-       destroy();
-   delete m_columns;
-   delete m_data;
-}
-
-/**
- * Destroy table data
+ * Create packed XML document
  */
-void Table::destroy()
+char *Table::createPackedXML()
 {
-   m_columns->clear();
-   m_data->clear();
-       safe_free(m_title);
+   TCHAR *xml = createXML();
+   if (xml == NULL)
+      return NULL;
+   char *utf8xml = UTF8StringFromTString(xml);
+   free(xml);
+   size_t len = strlen(utf8xml);
+   uLongf buflen = compressBound(len);
+   BYTE *buffer = (BYTE *)malloc(buflen + 4);
+   if (compress(&buffer[4], &buflen, (BYTE *)utf8xml, len) != Z_OK)
+   {
+      free(utf8xml);
+      free(buffer);
+      return NULL;
+   }
+   free(utf8xml);
+   char *encodedBuffer = NULL;
+   *((UINT32 *)buffer) = htonl((UINT32)len);
+   base64_encode_alloc((char *)buffer, buflen + 4, &encodedBuffer);
+   free(buffer);
+   return encodedBuffer;
 }
 
 /**
index a67a92c..925d6bd 100644 (file)
@@ -594,6 +594,41 @@ static void TestTable()
    AssertEquals(table->getNumRows(), 1);
    AssertEquals(table->getNumColumns(), 0);
    EndTest();
+
+   table->addColumn(_T("NAME"));
+   table->addColumn(_T("VALUE"));
+   table->addColumn(_T("DATA1"));
+   table->addColumn(_T("DATA2"));
+   table->addColumn(_T("DATA3"));
+   table->addColumn(_T("DATA4"));
+   for(int i = 0; i < 50; i++)
+   {
+      table->addRow();
+      TCHAR b[64];
+      _sntprintf(b, 64, _T("Process #%d"), i);
+      table->set(0, b);
+      table->set(1, i);
+      table->set(2, i * 100);
+      table->set(3, i * 100001);
+      table->set(4, _T("/some/long/path/on/file/system"));
+      table->set(5, _T("constant"));
+   }
+
+   StartTest(_T("Table: pack"));
+   INT64 start = GetCurrentTimeMs();
+   char *packedTable = table->createPackedXML();
+   AssertNotNull(packedTable);
+   EndTest(GetCurrentTimeMs() - start);
+
+   StartTest(_T("Table: unpack"));
+   start = GetCurrentTimeMs();
+   Table *table2 = Table::createFromPackedXML(packedTable);
+   free(packedTable);
+   AssertNotNull(table2);
+   AssertEquals(table2->getNumColumns(), table->getNumColumns());
+   AssertEquals(table2->getNumRows(), table->getNumRows());
+   AssertEquals(table2->getAsInt(10, 1), table->getAsInt(10, 1));
+   EndTest(GetCurrentTimeMs() - start);
 }
 
 /**