Initialize Tizen 2.3 accepted/tizen_2.3_mobile accepted/tizen_2.3_wearable 2.3a_release accepted/tizen/2.3/mobile/20150311.060911 accepted/tizen/2.3/wearable/20150311.060923 submit/tizen_2.3/20140531.064103 submit/tizen_2.3/20150311.060646 tizen_2.3_release
authorSehong Na <sehong.na@samsung.com>
Sat, 31 May 2014 03:34:54 +0000 (12:34 +0900)
committerSehong Na <sehong.na@samsung.com>
Sat, 31 May 2014 03:34:54 +0000 (12:34 +0900)
57 files changed:
CMakeLists.txt [new file with mode: 0755]
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
csr-framework.changes [new file with mode: 0644]
csr-framework.pc.in [new file with mode: 0755]
doc/Tizen Content Screening API Specification.pdf [new file with mode: 0644]
doc/Tizen Content Screening Plugin API Specification.pdf [new file with mode: 0644]
doc/Tizen Content Screening Test Specification.pdf [new file with mode: 0644]
doc/Tizen Content Security Framework Proposal.pdf [new file with mode: 0644]
doc/Tizen Web Protection API Specification.pdf [new file with mode: 0644]
doc/Tizen Web Protection Plugin API Specification.pdf [new file with mode: 0644]
doc/Tizen Web Protection Test Specification.pdf [new file with mode: 0644]
framework/Makefile [new file with mode: 0644]
framework/TCSErrorCodes.h [new file with mode: 0644]
framework/TCSImpl.c [new file with mode: 0644]
framework/TCSImpl.h [new file with mode: 0644]
framework/TWPImpl.c [new file with mode: 0644]
framework/TWPImpl.h [new file with mode: 0644]
packaging/csr-framework.manifest [new file with mode: 0644]
packaging/csr-framework.spec [new file with mode: 0755]
test/SampleInfo.c [new file with mode: 0644]
test/SampleInfo.h [new file with mode: 0644]
test/TCSTest.c [new file with mode: 0644]
test/TCSTest.h [new file with mode: 0644]
test/TCSTestUtils.c [new file with mode: 0644]
test/TWPTest.c [new file with mode: 0644]
test/TWPTest.h [new file with mode: 0644]
test/TWPTestUtils.c [new file with mode: 0644]
test/UrlInfo.h [new file with mode: 0644]
test/XMHttp.c [new file with mode: 0644]
test/XMHttp.h [new file with mode: 0644]
test/XMPHttp.c [new file with mode: 0644]
test/XMPHttp.h [new file with mode: 0644]
test/db/sdb/2E [new file with mode: 0755]
test/db/xlm/2D [new file with mode: 0755]
test/scripts/Test.sh [new file with mode: 0755]
test/scripts/WPTest.sh [new file with mode: 0755]
test/testcontents/tcs-testfile-0.buf [new file with mode: 0755]
test/testcontents/tcs-testfile-0.class [new file with mode: 0755]
test/testcontents/tcs-testfile-0.email [new file with mode: 0755]
test/testcontents/tcs-testfile-0.html [new file with mode: 0755]
test/testcontents/tcs-testfile-0.js [new file with mode: 0755]
test/testcontents/tcs-testfile-0.multiple [new file with mode: 0755]
test/testcontents/tcs-testfile-0.phone [new file with mode: 0755]
test/testcontents/tcs-testfile-0.txt [new file with mode: 0755]
test/testcontents/tcs-testfile-0.url [new file with mode: 0755]
test/testcontents/tcs-testfile-0.z [new file with mode: 0755]
test/testcontents/tcs-testfile-1.buf [new file with mode: 0755]
test/testcontents/tcs-testfile-1.class [new file with mode: 0755]
test/testcontents/tcs-testfile-1.email [new file with mode: 0755]
test/testcontents/tcs-testfile-1.html [new file with mode: 0755]
test/testcontents/tcs-testfile-1.js [new file with mode: 0755]
test/testcontents/tcs-testfile-1.multiple [new file with mode: 0755]
test/testcontents/tcs-testfile-1.phone [new file with mode: 0755]
test/testcontents/tcs-testfile-1.txt [new file with mode: 0755]
test/testcontents/tcs-testfile-1.url [new file with mode: 0755]
test/testcontents/tcs-testfile-1.z [new file with mode: 0755]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f786c50
--- /dev/null
@@ -0,0 +1,85 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(PACKAGE_NAME csr-framework)
+SET(LIB_NAME secfw)
+PROJECT(${LIB_NAME} C)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include")
+SET(VERSION 0.1)
+
+SET(TEST_ROOT "${CMAKE_SOURCE_DIR}/test")
+SET(TEST_DB "${TEST_ROOT}/db")
+SET(TEST_CONTENTS "${TEST_ROOT}/testcontents")
+SET(TEST_SCRIPT "${TEST_ROOT}/scripts")
+SET(TEST_INSTALL_ROOT "local/compatibility-test")
+
+SET(SRCS
+    framework/TCSImpl.c
+    framework/TWPImpl.c
+)
+
+SET(TCS_SRCS
+    test/SampleInfo.c
+    test/TCSTest.c
+    test/TCSTestUtils.c
+)
+
+
+SET(TWP_SRCS
+    test/TWPTest.c
+    test/TWPTestUtils.c
+    test/XMHttp.c
+    test/XMPHttp.c
+)
+
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/framework ${CMAKE_SOURCE_DIR}/test)
+
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -pthread ")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+ADD_DEFINITIONS("-Werror")
+ADD_DEFINITIONS("-Wall")
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"")
+ADD_DEFINITIONS("-DDATAFS=\"$ENV{DATADIR}\"")
+
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} "-ldl")
+
+ADD_EXECUTABLE(tcstest ${TCS_SRCS})
+ADD_EXECUTABLE(twptest ${TWP_SRCS})
+TARGET_LINK_LIBRARIES(tcstest ${PROJECT_NAME} ${pkgs_LDFLAGS})
+TARGET_LINK_LIBRARIES(twptest ${PROJECT_NAME} ${pkgs_LDFLAGS})
+
+INSTALL(TARGETS ${LIB_NAME} DESTINATION lib)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/framework/TCSErrorCodes.h DESTINATION include)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/framework/TCSImpl.h DESTINATION include)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/framework/TWPImpl.h DESTINATION include)
+
+INSTALL(TARGETS tcstest twptest DESTINATION sbin)
+INSTALL(FILES ${TEST_DB}/sdb/2E DESTINATION ${TEST_INSTALL_ROOT}/db/sdb)
+INSTALL(FILES ${TEST_DB}/xlm/2D DESTINATION ${TEST_INSTALL_ROOT}/db/xlm)
+FILE(GLOB files "${TEST_SCRIPT}/*.sh")
+INSTALL(FILES ${files} DESTINATION ${TEST_INSTALL_ROOT})
+FILE(GLOB files "${TEST_CONTENTS}/*.*")
+INSTALL(FILES ${files} DESTINATION ${TEST_INSTALL_ROOT}/testcontents)
+
+SET(PC_NAME ${PACKAGE_NAME})
+SET(PC_CFLAGS -I\${includedir})
+SET(PC_LDFLAGS -l${LIB_NAME})
+
+CONFIGURE_FILE(
+    ${PACKAGE_NAME}.pc.in
+    ${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE_NAME}.pc
+    @ONLY
+)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE_NAME}.pc DESTINATION lib/pkgconfig)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..81a1a6a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+
+  Copyright (c) 2013, McAfee, Inc.
+
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification,
+  are permitted provided that the following conditions are met:
+
+  Redistributions of source code must retain the above copyright notice, this list
+  of conditions and the following disclaimer.
+
+  Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+  Neither the name of McAfee, Inc. nor the names of its contributors may be used
+  to endorse or promote products derived from this software without specific prior
+  written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+  OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..0e61af0
--- /dev/null
+++ b/README
@@ -0,0 +1,69 @@
+#
+#  Copyright (c) 2013, McAfee, Inc.
+#  
+#  All rights reserved.
+#  
+#  Redistribution and use in source and binary forms, with or without modification,
+#  are permitted provided that the following conditions are met:
+#  
+#  Redistributions of source code must retain the above copyright notice, this list
+#  of conditions and the following disclaimer.
+#  
+#  Redistributions in binary form must reproduce the above copyright notice, this
+#  list of conditions and the following disclaimer in the documentation and/or other
+#  materials provided with the distribution.
+#  
+#  Neither the name of McAfee, Inc. nor the names of its contributors may be used
+#  to endorse or promote products derived from this software without specific prior
+#  written permission.
+#  
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+#  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+#  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+#  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+#  OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Tizen Content Screening Framework
+=====================================
+Following steps to create Tizen content screening framework library:
+- cd framework (change your current folder to 'framework')
+- make distclean; make
+- The library can be found inside 'lib'
+
+Tizen Content Screening Test Suite
+=====================================
+Following steps to create test suite
+- cd test (change your current folder to 'test')
+- make distclean; make
+
+Tizen Web Protection Test Suite
+=====================================
+Following steps to create test suite
+- cd test (change your current folder to 'test')
+- make distclean; make -f WPMakefile
+
+Porting
+=====================================
+TCS_CC: use this environment variable to specify your cross compiler
+TCS_LD: use this environment variable to specify your cross linker
+TCS_AR: use this environment variable to specify your cross ar
+PORT: x86, arm
+CFLAGS: use this environment variable to specify your compiler specific compiling flags
+LD_FLAGS: use this environment variable to specify your linker specific linker flags or libraries
+
+Example for Tizen 2.0.18 Emulator:
+export PORT=x86
+export SDK_HOME=${HOME}/tizen-sdk
+export CFLAGS="-I$SDK_HOME/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp.partner/usr/include"
+export LD_FLAGS="-B $SDK_HOME/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp.partner/usr/lib -L$SDK_HOME/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp.partner/lib -L$SDK_HOME/platforms/tizen2.0/rootstraps/tizen-emulator-2.0.cpp.partner/usr/lib -lc-2.13 -lpthread-2.13 -lc_nonshared"
+export TCS_CC="$SDK_HOME/tools/i386-linux-gnueabi-gcc-4.5/bin/i386-linux-gnueabi-gcc"
+export TCS_LD="$SDK_HOME/tools/i386-linux-gnueabi-gcc-4.5/bin/i386-linux-gnueabi-gcc"
+export TCS_AR="$SDK_HOME/tools/i386-linux-gnueabi-gcc-4.5/bin/i386-linux-gnueabi-ar"
+
+
diff --git a/csr-framework.changes b/csr-framework.changes
new file mode 100644 (file)
index 0000000..7d4005d
--- /dev/null
@@ -0,0 +1,4 @@
+* Monday Feb 11 2013 Ryan Ware <ryan.r.ware@intel.com> - 1.0.0
+- This is the initial checkin and spec file for csf-framework
+- Adding a default manifest
+
diff --git a/csr-framework.pc.in b/csr-framework.pc.in
new file mode 100755 (executable)
index 0000000..ecdf74f
--- /dev/null
@@ -0,0 +1,14 @@
+
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@ 
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
diff --git a/doc/Tizen Content Screening API Specification.pdf b/doc/Tizen Content Screening API Specification.pdf
new file mode 100644 (file)
index 0000000..1110687
Binary files /dev/null and b/doc/Tizen Content Screening API Specification.pdf differ
diff --git a/doc/Tizen Content Screening Plugin API Specification.pdf b/doc/Tizen Content Screening Plugin API Specification.pdf
new file mode 100644 (file)
index 0000000..5802d99
Binary files /dev/null and b/doc/Tizen Content Screening Plugin API Specification.pdf differ
diff --git a/doc/Tizen Content Screening Test Specification.pdf b/doc/Tizen Content Screening Test Specification.pdf
new file mode 100644 (file)
index 0000000..7ae0e6b
Binary files /dev/null and b/doc/Tizen Content Screening Test Specification.pdf differ
diff --git a/doc/Tizen Content Security Framework Proposal.pdf b/doc/Tizen Content Security Framework Proposal.pdf
new file mode 100644 (file)
index 0000000..b46288f
Binary files /dev/null and b/doc/Tizen Content Security Framework Proposal.pdf differ
diff --git a/doc/Tizen Web Protection API Specification.pdf b/doc/Tizen Web Protection API Specification.pdf
new file mode 100644 (file)
index 0000000..7730ca2
Binary files /dev/null and b/doc/Tizen Web Protection API Specification.pdf differ
diff --git a/doc/Tizen Web Protection Plugin API Specification.pdf b/doc/Tizen Web Protection Plugin API Specification.pdf
new file mode 100644 (file)
index 0000000..3e7191a
Binary files /dev/null and b/doc/Tizen Web Protection Plugin API Specification.pdf differ
diff --git a/doc/Tizen Web Protection Test Specification.pdf b/doc/Tizen Web Protection Test Specification.pdf
new file mode 100644 (file)
index 0000000..5461684
Binary files /dev/null and b/doc/Tizen Web Protection Test Specification.pdf differ
diff --git a/framework/Makefile b/framework/Makefile
new file mode 100644 (file)
index 0000000..03e6717
--- /dev/null
@@ -0,0 +1,95 @@
+#
+#  Copyright (c) 2013, McAfee, Inc.
+#  
+#  All rights reserved.
+#  
+#  Redistribution and use in source and binary forms, with or without modification,
+#  are permitted provided that the following conditions are met:
+#  
+#  Redistributions of source code must retain the above copyright notice, this list
+#  of conditions and the following disclaimer.
+#  
+#  Redistributions in binary form must reproduce the above copyright notice, this
+#  list of conditions and the following disclaimer in the documentation and/or other
+#  materials provided with the distribution.
+#  
+#  Neither the name of McAfee, Inc. nor the names of its contributors may be used
+#  to endorse or promote products derived from this software without specific prior
+#  written permission.
+#  
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+#  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+#  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+#  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+#  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+#  OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+OUTDIR = lib
+TARGET = $(OUTDIR)/libsecfw.so
+SRCDIR = .
+INCLUDE = -I. $(TCS_INC) -I../plugin
+LD_FLAGS := $(LD_FLAGS) -ldl
+
+ifeq ($(TCS_CC), )
+       CC = gcc
+else
+       CC = $(TCS_CC)
+endif
+ifeq ($(TCS_LD), )
+       LD = ld
+else
+       LD = $(TCS_LD)
+endif
+ifeq ($(TCS_AR), )
+       AR = ar
+else
+       AR = $(TCS_AR)
+endif
+
+ifeq ($(TCS_CFG), release)
+       CFLAGS := -O3 -fPIC $(INCLUDE) -DUNIX $(CFLAGS)
+else
+       CFLAGS := -g -fPIC $(INCLUDE) -DUNIX -DDEBUG $(CFLAGS)
+endif
+
+CFLAGS := $(CFLAGS) $(PKCL_CFLAGS) $(TCS_CFLAGS)
+
+SOURCES = $(SRCDIR)/TCSImpl.c $(SRCDIR)/TWPImpl.c
+
+OBJECTS = $(OUTDIR)/TCSImpl.o $(OUTDIR)/TWPImpl.o
+
+MKDEP = mkdep -f .depend
+
+
+$(OUTDIR)/%.o: $(SRCDIR)/%.c
+       $(CC) $(CFLAGS) -o $(OUTDIR)/$*.o -c $(SRCDIR)/$*.c
+
+all: $(OUTDIR) .depend $(TARGET)
+
+.depend: $(SOURCES)
+       $(MKDEP) $(CFLAGS) $(SOURCES)
+
+$(TARGET): $(OBJECTS)
+       $(LD) -shared -Wl,-zdefs -o $(TARGET) $(OBJECTS) $(LD_FLAGS)
+
+#      $(AR) -cr $(TARGET) $(OBJECTS)
+
+$(OUTDIR):
+       @mkdir $(OUTDIR)
+
+distclean: clean
+       @rm -f .depend
+       @rm -rf $(OUTDIR)
+
+clean:
+       @rm -f $(TARGET)
+       @rm -f $(OBJECTS) *~
+       @rm -f *.bb *.bbg *.da *.gcov
+
+-include .depend
+
diff --git a/framework/TCSErrorCodes.h b/framework/TCSErrorCodes.h
new file mode 100644 (file)
index 0000000..45ccad6
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef TCSERRORCODES_H
+#define TCSERRORCODES_H
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+/**
+ * \file TCSErrorCodes.h
+ * \brief TCS Error Code Header File
+ *  
+ * This file provides the TCS error code definition.
+ */
+
+#define TCS_ERROR_MODULE_GENERIC 1 /* A generic error code. */
+
+#define TCS_ERROR_CANCELLED 1 /* Operations cancelled. */
+
+#define TCS_ERROR_DATA_ACCESS 2 /* Unable to access data. */
+
+#define TCS_ERROR_INVALID_PARAM 3 /* Invalid parameter. */
+
+#define TCS_ERROR_INSUFFICIENT_RES 4 /* Insufficient resource. */
+
+#define TCS_ERROR_INTERNAL 5 /* Unexpected internal error. */
+
+#define TCS_ERROR_INVALID_HANDLE 6 /* Invalid handle. */
+
+#define TCS_ERROR_NOT_IMPLEMENTED 7 /* Specified functionality is not implemented in the TCS plug-in. (e.g. repair) */
+
+#ifdef __cplusplus
+}
+#endif 
+
+#endif /* TCSERRORCODES_H */
diff --git a/framework/TCSImpl.c b/framework/TCSImpl.c
new file mode 100644 (file)
index 0000000..1cea1b3
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <malloc.h>
+
+#include "TCSImpl.h"
+#include "TCSErrorCodes.h"
+
+
+#define TCS_CONSTRUCT_ERRCODE(m, e) (((m) << 24) | (e))
+
+#if defined(DEBUG)
+#define DEBUG_LOG(_fmt_, _param_...)    { \
+                                            printf("[TCS] %s,%d: " _fmt_, __FILE__, __LINE__, ##_param_); \
+                                        }
+#else
+#define DEBUG_LOG(_fmt_, _param_...)
+#endif
+
+
+#define PLUGIN_PATH "/opt/usr/share/sec_plugin/libengine.so"
+
+
+typedef TCSLIB_HANDLE (*FuncLibraryOpen)(void);
+typedef int (*FuncLibraryClose)(TCSLIB_HANDLE hLib);
+typedef TCSErrorCode (*FuncGetLastError)(TCSLIB_HANDLE hLib);
+typedef int (*FuncScanData)(TCSLIB_HANDLE hLib, TCSScanParam *pParam, TCSScanResult *pResult);
+typedef int (*FuncScanFile)(TCSLIB_HANDLE hLib, char const *pszFileName, int iDataType,
+                            int iAction, int iCompressFlag, TCSScanResult *pResult);
+
+
+typedef struct PluginContext_struct
+{
+    TCSLIB_HANDLE hLib;
+    void *pPlugin;
+    FuncLibraryOpen pfLibraryOpen;
+    FuncLibraryClose pfLibraryClose;
+    FuncGetLastError pfGetLastError;
+    FuncScanData pfScanData;
+    FuncScanFile pfScanFile;
+} PluginContext;
+
+
+static PluginContext *LoadPlugin(void);
+
+
+TCSLIB_HANDLE TCSLibraryOpen(void)
+{
+    PluginContext *pCtx = NULL;
+
+    DEBUG_LOG("%s", "tcs lib open\n");
+    pCtx = LoadPlugin();
+    if (pCtx != NULL)
+    {
+        if (pCtx->pfLibraryOpen == NULL)
+        {
+            free(pCtx);
+            return INVALID_TCSLIB_HANDLE;
+        }
+        DEBUG_LOG("%s", "call to TCSPLibraryOpen\n");
+        pCtx->hLib = (*pCtx->pfLibraryOpen)();
+        if (pCtx->hLib == INVALID_TCSLIB_HANDLE)
+        {
+            DEBUG_LOG("%s", "failed to open engine\n");
+            if (pCtx->pPlugin != NULL)
+                dlclose(pCtx->pPlugin);
+            free(pCtx);
+        }
+        else
+        {
+            return (TCSLIB_HANDLE) pCtx;
+        }
+    }
+
+    return INVALID_TCSLIB_HANDLE;
+}
+
+int TCSLibraryClose(TCSLIB_HANDLE hLib)
+{
+    int iRet = -1;
+    PluginContext *pCtx = NULL;
+
+    if (hLib == INVALID_TCSLIB_HANDLE)
+        return iRet;
+
+    pCtx = (PluginContext *) hLib;
+    if (pCtx->pfLibraryClose == NULL)
+        return iRet;
+
+    iRet = (*pCtx->pfLibraryClose)(pCtx->hLib);
+    if (pCtx->pPlugin != NULL)
+        dlclose(pCtx->pPlugin);
+   
+    free(pCtx);
+
+    return iRet;
+}
+
+
+TCSErrorCode TCSGetLastError(TCSLIB_HANDLE hLib)
+{
+    PluginContext *pCtx = (PluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfGetLastError == NULL)
+    {
+        return TCS_CONSTRUCT_ERRCODE(TCS_ERROR_MODULE_GENERIC,
+                                     TCS_ERROR_NOT_IMPLEMENTED);
+    }
+    return (*pCtx->pfGetLastError)(pCtx->hLib);
+}
+
+
+int TCSScanData(TCSLIB_HANDLE hLib, TCSScanParam *pParam, TCSScanResult *pResult)
+{
+    PluginContext *pCtx = (PluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfScanData == NULL)
+    {
+        return -1;
+    }
+    return (*pCtx->pfScanData)(pCtx->hLib, pParam, pResult);
+}
+
+
+int TCSScanFile(TCSLIB_HANDLE hLib, char const *pszFileName, int iDataType,
+                int iAction, int iCompressFlag, TCSScanResult *pResult)
+{
+    PluginContext *pCtx = (PluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfScanFile == NULL)
+    {
+        return -1;
+    }
+    return (*pCtx->pfScanFile)(pCtx->hLib, pszFileName, iDataType, iAction, iCompressFlag, pResult);
+}
+
+
+static PluginContext *LoadPlugin(void)
+{
+    PluginContext *pCtx = NULL;
+    void *pTmp = dlopen(PLUGIN_PATH, RTLD_LAZY);
+    DEBUG_LOG("%s", "load plugin\n");
+    if (pTmp != NULL)
+    {
+        FuncLibraryOpen TmpLibraryOpen;
+        FuncLibraryClose TmpLibraryClose;
+        FuncGetLastError TmpGetLastError;
+        FuncScanData TmpScanData;
+        FuncScanFile TmpScanFile;
+        
+        do
+        {
+            TmpLibraryOpen = dlsym(pTmp, "TCSPLibraryOpen");
+            DEBUG_LOG("%s", "load api TCSPLibraryOpen\n");
+            if (TmpLibraryOpen == NULL)
+            {
+                DEBUG_LOG("Failed to load TCSPLibraryOpen in %s\n", PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+            
+            TmpLibraryClose = dlsym(pTmp, "TCSPLibraryClose");
+            if (TmpLibraryClose == NULL)
+            {
+                DEBUG_LOG("Failed to load TCSPLibraryClose in %s\n", PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+            
+            TmpGetLastError = dlsym(pTmp, "TCSPGetLastError");
+            if (TmpGetLastError == NULL)
+            {
+                DEBUG_LOG("Failed to load TCSPGetLastError in %s\n", PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+            
+            TmpScanData = dlsym(pTmp, "TCSPScanData");
+            if (TmpScanData == NULL)
+            {
+                DEBUG_LOG("Failed to load TCSPScanData in %s\n", PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+            
+            TmpScanFile = dlsym(pTmp, "TCSPScanFile");
+            if (TmpScanFile == NULL)
+            {
+                DEBUG_LOG("Failed to load TCSPScanFile in %s\n", PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+            
+            pCtx = (PluginContext *) malloc(sizeof(PluginContext));
+            if (pCtx == NULL)
+            {
+                dlclose(pTmp);
+                break;
+            }
+            pCtx->pPlugin = pTmp;
+            pCtx->pfLibraryOpen = TmpLibraryOpen;
+            pCtx->pfLibraryClose = TmpLibraryClose;
+            pCtx->pfGetLastError = TmpGetLastError;
+            pCtx->pfScanData = TmpScanData;
+            pCtx->pfScanFile = TmpScanFile;
+        } while(0);
+    }
+    else
+    {
+        DEBUG_LOG("No plugin found.\n");
+    }
+
+    return pCtx;
+}
+
+
diff --git a/framework/TCSImpl.h b/framework/TCSImpl.h
new file mode 100644 (file)
index 0000000..fcc8a24
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef TCSIMPL_H
+#define TCSIMPL_H
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+/**
+ * \file TCSImpl.h
+ * \brief TCS Header File
+ *  
+ * This file provides the Tizen Content Screen API functions.
+ */
+
+#define TCS_SA_SCANONLY 1 /* Instructs the scan functions to perform scanning only. */
+
+#define TCS_SA_SCANREPAIR 2 /* Instructs the scan functions to carry out both
+                                                                    scanning and repair/removal of detected malware. */
+
+#define TCS_CB_DETECTED 1 /* Informs the caller a malicious code has been
+                                                              detected in the scan target. The callback data
+                                                              argument pParam is set to point to a TCSDetected
+                                                              structure. */
+
+#define TCS_DTYPE_UNKNOWN 0 /* Scan for malicious content in an unknown data
+                                                                    type. This data type should be used when the
+                                                                    other types are not appropriate. */
+
+#define TCS_DTYPE_HTML 1 /* Scan for malicious content in HTML. */
+
+#define TCS_DTYPE_URL 2 /* Scan for URL with malicious content.
+                                                            url-string format should conform to the
+                                                            Uniform Resource Locators (RFC 1738)
+                                                            specification. */
+
+#define TCS_DTYPE_EMAIL 3 /* Scan for email-address with malicious intent.
+                                                                  email-string format should conform with
+                                                                  the Internet E-mail address format
+                                                                  (RFC 822) specification. */
+
+#define TCS_DTYPE_PHONE 4 /* Scan for phone number with malicious intent.
+                                                              phone-number string consists of the numeric
+                                                              characters '0' through '9', and the
+                                                              '#' and '*' characters. */
+
+#define TCS_DTYPE_JAVA 5 /* Scan for malicious Java code. */
+
+#define TCS_DTYPE_JAVAS 6 /* Scan for malicious Java code. */
+
+#define TCS_DTYPE_TEXT 7 /* Scan text data for malicious content. */
+
+#define TCS_VTYPE_MALWARE 1 /* Malware type. */
+
+#define TCS_SC_USER 1 /* Detected malware is harmful to the user. */
+
+#define TCS_SC_TERMINAL 2 /* Detected malware is harmful to the terminal. */
+
+#define TCS_BC_LEVEL0 0 /* Process with a warning. This severity level may
+                                                          be assigned to data previously considered malicious. */
+
+#define TCS_BC_LEVEL1 1 /* Prompt the user before processing. Ask the user
+                                                            if they want the application to process the data. */
+
+#define TCS_BC_LEVEL2 2 /* Do not process the data. */
+
+#define TCS_BC_LEVEL3 3 /* Do not process the data and prompt user for removal.
+                                                        If the content is stored on the terminal,
+                                                        prompt the user for permission before removal. */
+
+#define TCS_BC_LEVEL4 4 /* Do not process the data and automatically remove if stored. */
+
+
+/*==================================================================================================
+                                            MACROS
+==================================================================================================*/
+
+/**
+ * Helper macro to get error module.
+ */
+#define TCS_ERRMODULE(e) (((e) >> 24) & 0xff)
+
+/**
+ * Helper macro to get error code.
+ */
+#define TCS_ERRCODE(e) ((e) & 0x00ffffff)
+
+/*==================================================================================================
+                                 STRUCTURES AND OTHER TYPEDEFS
+==================================================================================================*/
+
+/**
+ * Dummy data structure to avoid unexpected data type casting.
+ */
+struct TCSLibHandle_struct {int iDummy;};
+
+/**
+ * TCS library handle type.
+ */
+typedef struct TCSLibHandle_struct *TCSLIB_HANDLE;
+
+#define INVALID_TCSLIB_HANDLE ((TCSLIB_HANDLE) 0) /* Invalid Content Screening library interface handle. */
+
+/**
+ * error code type.
+ */
+typedef unsigned long TCSErrorCode;
+
+/**
+ * Support 64 bits data / file locating
+ */
+typedef long long TCSOffset;
+
+/**
+ * The calling application specifies scan
+ * parameters using the TCSScanParam structure. The information
+ * contained in the structure provides the scan functions with:
+ * - scan action type (iAction)
+ * - the scan data type (iDataType)
+ * - data pointer to the scan target (pPrivate)
+ * - callback function to retrieve the data size in bytes (pfGetSize)
+ * - callback function to resize the scan data (pfSetSize)
+ * - callback function used by the scan functions to retrieve a
+ *     block of scan data (pfRead)
+ * - callback function used to write to the scan data (pfWrite)
+ * - callback function for status/progress reporting (pfCallBack)
+ */
+typedef struct TCSScanParam_struct
+{
+    int iAction; /* The scan-action specifies the type of scanning to be performed on supplied scan data. */
+
+    int iDataType; /* The calling application specifies the data type/format of the data to be scanned using this variable. */
+
+    int iCompressFlag; /* 0 - decompression disabled, 1 - decompression enabled. */
+
+    void *pPrivate; /* Pointer (or handle) to an application object being scanned.
+                       The scan functions do not perform direct memory I/O using this data
+                       pointer/handle. The data pointer/handle is simply passed back to the caller when
+                       performing data read/write using caller specified I/O functions. Also the private
+                       data is passed back to the caller using the pfCallback function if it is set. */
+
+    TCSOffset (*pfGetSize)(void *pPrivate); /* Used by the scan functions
+                                               to obtain the scan target data size (in bytes) from the caller.
+                                                                                                            
+                                               This is a synchronous API.
+                                               [in] pPrivate Pointer (or handle) to an application object being scanned.
+
+                                               return - Return Type (int)
+                                               The size (in bytes) of the data to be scanned.
+                                               */
+
+    int (*pfSetSize)(void *pPrivate, TCSOffset uSize); /* Called by the scan
+                                                          functions to resize the scanned data to a given size (in bytes) during
+                                                          repair/clean. The resize function pointer needs to be set if the scan-action
+                                                          (iAction) is set to TCS_SA_SCANREPAIR.
+
+                                                          This is a synchronous API.
+
+                                                          @param[in] pPrivate Pointer (or handle) to an application object being scanned.
+                                                          @param[in] uSize The size (in bytes) of the repaired data.
+
+                                                          @return Return Type (int)
+                                                          The size (in bytes) of the application data.
+                                                          Not equal to the value of uSize indicating this call fails.
+                                                          */
+
+    unsigned int (*pfRead)(void *pPrivate, TCSOffset uOffset, void *pBuffer,
+                           unsigned int uCount); /* Used for reading a specified
+                                                    amount of application data during scanning/analysis.
+                                                                                                                    
+                                                    This is a synchronous API.
+
+                                                    @param[in] pPrivate Pointer (or handle) to an application object being scanned.
+                                                    @param[in] uOffset Read from the offset in the application data.
+                                                    @param[out] pBuffer The buffer used to store the read data.
+                                                    @param[in] uCount The size (in bytes) of the data to be read.
+
+                                                    @return Return Type (int) 
+                                                    The size (in bytes) of the read data. 
+                                                    Not equal to the value of uCount indicating this call fails.
+                                                    */
+
+    unsigned int (*pfWrite)(void *pPrivate, TCSOffset uOffset, void const *pBuffer,
+                            unsigned int uCount); /* The scan functions use the
+                                                     given function to write a specified amount of data to the scanned object as a part
+                                                     of the repair process. The function pointer needs to be set if the scan action
+                                                     (iAction) is set to TCS_SA_SCANREPAIR.
+                                                                                                                    
+                                                     This is a synchronous API.
+
+                                                     @param[in] pPrivate Pointer (or handle) to an application object being scanned.
+                                                     @param[in] uOffset Write data from the offset in the application data.
+                                                     @param[in] pBuffer The buffer hold the data to be written.
+                                                     @param[in] uCount The size (in bytes) of the data to be written.
+
+                                                     @return Return Type (int)
+                                                     The size (in bytes) of the written data.
+                                                     Not equal to the value of uCount indicating this call fails.
+                                                     */
+
+    int (*pfCallBack)(void *pPrivate, int iReason, void *pParam); /* This callback
+                                                                     function is set by the caller to be notified to each detected malware while
+                                                                     scanning is in process. If specified (not NULL), the scan functions call the
+                                                                     specified function with the information (e.g. TCS_CB_DETECTED) for each malware
+                                                                     detected in the content/data during scanning.
+                                                                                                                                                        
+                                                                     This is a synchronous API.
+                                                                                                                                                    
+                                                                     @param[in] pPrivate Pointer (or handle) to an application object being scanned.
+                                                                     @param[in] iReason Reason of this callback.
+                                                                     @param[in] pParam The data for specified callback reason respectively.
+                                                                                                                                                    
+                                                                     @return Return Type (int) 
+                                                                     The scanning process continues if the callback function returns 0. If a negative
+                                                                     value (e.g. -1) is returned, the scanning process is aborted and control is
+                                                                     returned to the caller.
+                                                                     */
+} TCSScanParam;
+
+/**
+ * Detected malicious code/content information structure.
+ */
+typedef struct TCSDetected_struct
+{
+    struct TCSDetected_struct *pNext; /* Pointer to next malware found, NULL if at the end of list. */
+
+    char const *pszName; /* Detected malware name. */
+    char const *pszVariant; /* Detected malware's variant name. pszName and
+                               pszVariant report detected malicious code/content and variant names. The maximum
+                               string length for both strings is 64 characters and each is terminated by a null
+                               character ('\\0') - the maximum buffer size for both strings is 65 bytes.
+
+                               pszVariant is set to an empty string ("\0") if the detected malware is not a
+                               variant. */
+
+    unsigned int uType; /* Detected malware type. \see TCS_VTYPE_MALWARE */
+    unsigned int uAction; /* Bit-field specifying severity, class and behavior level.
+
+                             Included in the TCSDetected structure is a bit-field variable containing malware
+                             severity flags and client application behavior levels.
+
+                             The scan functions set the TCS_SC_USER flag if the scanned object/data contains
+                             malware harmful to the user. TCS_SC_TERMINAL flag is set if the malware is
+                             harmful to the terminal itself. Both TCS_SC_USER and TCS_SC_TERMINAL flags are
+                             set if the malware is harmful to both the user and the terminal.
+
+                             The application behavior level specifies what to do with the data/object
+                             containing the detected malware.
+
+                             When multiple behavior level codes are found in a scanned data/object, the
+                             calling application would be expected to act with the highest behavior level.
+                             For example, if both TCS_BC_LEVEL0 and TCS_BC_LEVEL3 were reported, the application
+                             would need to take on TCS_BC_LEVEL3 action. */
+
+    char const *pszFileName; /* Path of the infected file. The pszFileName field
+                                report, if not NULL, the complete file path of the infected content. If the scan
+                                functions have the ability to scan/analyze inside archives, then the path
+                                reported in pszFileName would be composed of multiple paths separated by the '|'
+                                character. The first path of the sequence is the real file system path of the
+                                currently scanned file, for TCSScanFile(), or empty for TCSScanData(). No
+                                assumption should be made on the path name separator used for the archive
+                                components of the path (the ones following the first). Only the first component,
+                                if not empty, is the real file path of the currently scanned content. */
+} TCSDetected;
+
+/**
+ * Detected malware information is returned to the caller in the TCSScanResult 
+ * structure provided by the caller. The TCSScanResult structure contains a pointer 
+ * to a structure that contains scan result information and a pointer to a function 
+ * used to remove the scan result resource. The memory used to hold the scan result 
+ * is allocated by the scan functions and freed by calling the function pointed by the 
+ * pfFreeResult pointer. The detected malware information includes the malware
+ * information which had been reported via the callback (pfCallback) function during
+ * scanning.
+ *
+ * \code
+ * int ScanAppData( ... )
+ * {
+ *     TCSScanResult scanResult;
+ *     .
+ *     .
+ *     if (TCSScanData(hScanner, &scanParam, &scanResult) == 0)
+ *     {
+ *         .
+ *         .
+ *         scanResult.pfFreeResult( &scanResult );
+ *     }
+ *     .
+ *     .
+ * }
+ * \endcode
+ */
+typedef struct TCSScanResult_struct
+{
+    int iNumDetected; /* Number of malware found. */
+    TCSDetected *pDList; /* Detected malware list. */
+    void (*pfFreeResult)(struct TCSScanResult_struct *pResult); /* Function pointer
+                                                                   used to free reported scan result.
+                                                                                                                                                
+                                                                   This is a synchronous API.
+                                                                   \param[in] pResult Pointer to data structure in which detected scan result
+                                                                   information is stored.
+
+                                                                   \return None
+                                                                   */
+} TCSScanResult;
+
+/*==================================================================================================
+                                     FUNCTION PROTOTYPES
+==================================================================================================*/
+
+/**
+ * \brief Initializes and returns a Tizen Content Screening library
+ * interface handle.
+ *
+ * A Content Screening library interface handle (or TCS library handle) is
+ * obtained using the TCSLibraryOpen() function. The library handle is required for
+ * subsequent TCS API calls. The TCSLibraryClose() function releases/closes the library
+ * handle. Multiple library handles can be obtained using TCSLibraryOpen().
+ *
+ * This is a synchronous API.
+ *
+ * \return Return Type (TCSLIB_HANDLE) \n
+ * TCS library interface handle - on success. \n
+ * INVALID_TCSLIB_HANDLE - on failure. \n
+ */
+TCSLIB_HANDLE TCSLibraryOpen(void);
+
+/**
+ * \brief Releases system resources associated with an TCS API library
+ * handle returned by the TCSLibraryOpen() function.
+ *
+ * This is a synchronous API.
+ *
+ * \param[in] hLib TCS library handle returned by TCSLibraryOpen().
+ *
+ * \return Return Type (int) \n
+ * 0 - on success. \n
+ * -1 - on failure. \n
+ */
+int TCSLibraryClose(TCSLIB_HANDLE hLib);
+
+/**
+ * \brief Returns the last error code associated with the given
+ * TCS library handle.
+ *
+ * Once the TCS library handle has been successfully obtained from TCSLibraryOpen(),
+ * TCSGetLastError() can be used to retrieve the last TCS error that occurred. All TCS
+ * API functions return zero (= 0) or a valid object pointer if successful, and -1
+ * or a null object handle (e.g. INVALID_TCSSCAN_HANDLE) in case of an error. The
+ * TCSGetLastError() function is used to retrieve error information when a TCS
+ * function fails.
+ *
+ * This is a synchronous API.
+ *
+ * \param[in] hLib TCS library handle returned by TCSLibraryOpen().
+ *
+ * \return Return Type (TCSErrorCode) \n
+ * Last error code set by the TCS library. The TCSErrorCode data type is defined as a
+ * 32-bit unsigned integer which contains both component and an error code (see
+ * Figure about TCS Error Code Format). Two macros are available to extract the error
+ * module and the error code. Call TCS_ERRMODULE(error-code) to get the error module,
+ * and TCS_ERRCODE(error-code) to get the error code (where error-code is the value
+ * returned by TCSGetLastError()).
+ *
+ * TCS library call sequence with a call to the TCSGetLastError() function:
+ *
+ */
+TCSErrorCode TCSGetLastError(TCSLIB_HANDLE hLib);
+
+/**
+ * \brief TCSScanData() is used to scan a data buffer for malware. The caller
+ * specifies a scanner action, scan target data type, set I/O functions to access
+ * the data, and an optional callback function for information retrieval. The result
+ * of the data scanning is returned in a caller provided data structure.
+ *
+ * This is a synchronous API.
+ *
+ * \param[in] hLib instance handle obtained from a call to the TCSLibraryOpen()
+ * function.
+ * \param[in] pParam Pointer to a structure containing data scan parameters.
+ * \param[out] pResult Pointer to a structure containing data scan
+ * results.
+ *
+ * \return Return Type (int) \n
+ * 0 - on success. \n
+ * -1 - on failure and error code is set. \n
+ *
+ */
+int TCSScanData(TCSLIB_HANDLE hLib, TCSScanParam *pParam, TCSScanResult *pResult);
+
+/**
+ * \brief TCSScanFile() is used to scan a file for malware. The caller specifies a
+ * file name, a scanner action, and scan target data type. The scan result is
+ * returned in a caller provided data structure.
+ *
+ * This is a synchronous API.
+ *
+ * \param[in] hLib instance handle obtained from a call to the
+ * TCSLibraryOpen() function.
+ * \param[in] pszFileName Name of file to scan. The file name must include the
+ * absolute path.
+ * \param[in] iDataType Type of data contained in the file. This is used to
+ * perform data type specific scans on files.
+ * \param[in] iAction Type of scanning to perform on file.
+ * \param[out] pResult Pointer to a structure containing data scan results.
+ *
+ * \return Return Type (int) \n
+ * 0 - on success. \n
+ * -1 - on failure and error code is set. \n
+ */
+int TCSScanFile(TCSLIB_HANDLE hLib, char const *pszFileName, int iDataType,
+                int iAction, int iCompressFlag, TCSScanResult *pResult);
+
+#ifdef __cplusplus
+}
+#endif 
+
+#endif  /* TCSIMPL_H */
diff --git a/framework/TWPImpl.c b/framework/TWPImpl.c
new file mode 100644 (file)
index 0000000..82b7062
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <unistd.h>
+#include <dlfcn.h>
+#include <malloc.h>
+
+#include "TWPImpl.h"
+
+
+#define SITE_PLUGIN_PATH "/opt/usr/share/sec_plugin/libwpengine.so"
+
+#if defined(DEBUG)
+#define DEBUG_LOG(_fmt_, _param_...)    { \
+                                            printf("[TCS] %s,%d: " _fmt_, __FILE__, __LINE__, ##_param_); \
+                                        }
+#else
+#define DEBUG_LOG(_fmt_, _param_...)
+#endif
+
+
+typedef TWP_RESULT (*FuncInitLibrary)(TWPAPIInit *pApiInit);
+typedef void (*FuncUninitLibrary)(void);
+typedef TWP_RESULT (*FuncConfigurationCreate)(TWPConfiguration *pConfigure, TWPConfigurationHandle *phConfigure);
+typedef TWP_RESULT (*FuncConfigurationDestroy)(TWPConfigurationHandle *hConfigure);
+typedef TWP_RESULT (*FuncLookupUrls)(TWPConfigurationHandle hConfigure, TWPRequest *pRequest, int iRedirUrl,
+                                     const char **ppUrls, unsigned int uCount, TWPResponseHandle *phResponse);
+typedef TWP_RESULT (*FuncResponseWrite)(TWPResponseHandle hResponse, const void *pData, unsigned uLength);
+typedef TWP_RESULT (*FuncResponseGetUrlRatingByIndex)(TWPResponseHandle hResponse, unsigned int iIndex,
+                                                      TWPUrlRatingHandle *hRating);
+typedef TWP_RESULT (*FuncResponseGetUrlRatingByUrl)(TWPResponseHandle hResponse, const char *pUrl,
+                                                    unsigned int iUrlLength, TWPUrlRatingHandle *hRating);
+typedef TWP_RESULT (*FuncResponseGetRedirUrlFor)(TWPResponseHandle hResponse, TWPUrlRatingHandle hRating,
+                                                 TWPPolicyHandle hPolicy, char **ppUrl, unsigned int *puLength);
+typedef TWP_RESULT (*FuncResponseGetUrlRatingsCount)(TWPResponseHandle hResponse, unsigned int *puCount);
+typedef TWP_RESULT (*FuncResponseDestroy)(TWPResponseHandle *handle_response);
+typedef TWP_RESULT (*FuncPolicyCreate)(TWPConfigurationHandle hCfg, TWPCategories *pCategories, unsigned int uCount,
+                                       TWPPolicyHandle *phPolicy);
+typedef TWP_RESULT (*FuncPolicyValidate)(TWPPolicyHandle hPolicy, TWPUrlRatingHandle hRating, int *piViolated);
+typedef TWP_RESULT (*FuncPolicyGetViolations)(TWPPolicyHandle hPolicy, TWPUrlRatingHandle hRating,
+                                              TWPCategories **ppViolated, unsigned *puLength);
+typedef TWP_RESULT (*FuncPolicyDestroy)(TWPPolicyHandle *hPolicy);
+typedef TWP_RESULT (*FuncUrlRatingGetScore)(TWPUrlRatingHandle hRating, int *piScore);
+typedef TWP_RESULT (*FuncUrlRatingGetUrl)(TWPUrlRatingHandle hRating, const char **ppUrl,
+                                          unsigned int *puLength);
+typedef TWP_RESULT (*FuncUrlRatingGetDLAUrl)(TWPUrlRatingHandle hRating, const char **ppDlaUrl,
+                                             unsigned int *puLength);
+typedef TWP_RESULT (*FuncUrlRatingHasCategory)(TWPUrlRatingHandle hRating, TWPCategories Category,
+                                               int *piPresent);
+typedef TWP_RESULT (*FuncUrlRatingGetCategories)(TWPUrlRatingHandle hRating, TWPCategories **ppCategories,
+                                                 unsigned int *puLength);
+
+
+typedef struct SitePluginContext_struct
+{
+    void *pPlugin;
+    FuncUninitLibrary pfUninitLibrary;
+    FuncInitLibrary pfInitLibrary;
+    FuncConfigurationCreate pfConfigurationCreate;
+    FuncConfigurationDestroy pfConfigurationDestroy;
+    FuncLookupUrls pfLookupUrls;
+    FuncResponseWrite pfResponseWrite;
+    FuncResponseGetUrlRatingByIndex pfResponseGetUrlRatingByIndex;
+    FuncResponseGetUrlRatingByUrl pfResponseGetUrlRatingByUrl;
+    FuncResponseGetRedirUrlFor pfResponseGetRedirUrlFor;
+    FuncResponseGetUrlRatingsCount pfResponseGetUrlRatingsCount;
+    FuncResponseDestroy pfResponseDestroy;
+    FuncPolicyCreate pfPolicyCreate;
+    FuncPolicyValidate pfPolicyValidate;
+    FuncPolicyGetViolations pfPolicyGetViolations;
+    FuncPolicyDestroy pfPolicyDestroy;
+    FuncUrlRatingGetScore pfUrlRatingGetScore;
+    FuncUrlRatingGetUrl pfUrlRatingGetUrl;
+    FuncUrlRatingGetDLAUrl pfUrlRatingGetDLAUrl;
+    FuncUrlRatingHasCategory pfUrlRatingHasCategory;
+    FuncUrlRatingGetCategories pfUrlRatingGetCategories;
+} SitePluginContext;
+
+
+static SitePluginContext *LoadPlugin(void);
+
+
+TWPLIB_HANDLE TWPInitLibrary(TWPAPIInit *pApiInit)
+{
+    SitePluginContext *pCtx = NULL;
+
+    pCtx = LoadPlugin();
+    if (pCtx != NULL)
+    {
+        if (pCtx->pfInitLibrary != NULL &&
+            (*pCtx->pfInitLibrary)(pApiInit) == TWP_SUCCESS)
+            return (TWPLIB_HANDLE) pCtx;
+
+        TWPUninitLibrary((TWPLIB_HANDLE) pCtx);
+        return INVALID_TWPLIB_HANDLE;
+    }
+
+    return INVALID_TWPLIB_HANDLE;
+}
+
+void TWPUninitLibrary(TWPLIB_HANDLE hLib)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx != NULL)
+    {
+        if (pCtx->pfUninitLibrary != NULL)
+            (*pCtx->pfUninitLibrary)();
+        if (pCtx->pPlugin != NULL)
+            dlclose(pCtx->pPlugin);
+        free(pCtx);
+    }
+}
+
+TWP_RESULT TWPConfigurationCreate(TWPLIB_HANDLE hLib, TWPConfiguration *pConfigure,
+                                  TWPConfigurationHandle *phConfigure)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfConfigurationCreate == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfConfigurationCreate)(pConfigure, phConfigure);
+}
+
+TWP_RESULT TWPConfigurationDestroy(TWPLIB_HANDLE hLib, TWPConfigurationHandle *hConfigure)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfConfigurationDestroy == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfConfigurationDestroy)(hConfigure);
+}
+
+TWP_RESULT TWPLookupUrls(TWPLIB_HANDLE hLib, TWPConfigurationHandle hConfigure, TWPRequest *pRequest,
+                         int iRedirUrl, const char **ppUrls, unsigned int uCount, TWPResponseHandle *phResponse)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfLookupUrls == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfLookupUrls)(hConfigure, pRequest, iRedirUrl, ppUrls, uCount, phResponse);
+}
+
+TWP_RESULT TWPResponseWrite(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, const void *pData, unsigned uLength)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfResponseWrite == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfResponseWrite)(hResponse, pData, uLength);
+}
+
+TWP_RESULT TWPResponseGetUrlRatingByIndex(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, unsigned int uIndex,
+                                          TWPUrlRatingHandle *hRating)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfResponseGetUrlRatingByIndex == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfResponseGetUrlRatingByIndex)(hResponse, uIndex, hRating);
+}
+
+TWP_RESULT TWPResponseGetUrlRatingByUrl(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, const char *pUrl,
+                                        unsigned int uUrlLength, TWPUrlRatingHandle *hRating)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfResponseGetUrlRatingByUrl == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfResponseGetUrlRatingByUrl)(hResponse, pUrl, uUrlLength, hRating);
+}
+
+TWP_RESULT TWPResponseGetRedirUrlFor(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, TWPUrlRatingHandle hRating,
+                                     TWPPolicyHandle hPolicy, char **ppUrl, unsigned int *puLength)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfResponseGetRedirUrlFor == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfResponseGetRedirUrlFor)(hResponse, hRating, hPolicy, ppUrl, puLength);
+}
+
+TWP_RESULT TWPResponseGetUrlRatingsCount(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, unsigned int *puCount)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfResponseGetUrlRatingsCount == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfResponseGetUrlRatingsCount)(hResponse, puCount);
+}
+
+TWP_RESULT TWPResponseDestroy(TWPLIB_HANDLE hLib, TWPResponseHandle *hResponse)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfResponseDestroy == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfResponseDestroy)(hResponse);
+}
+
+TWP_RESULT TWPPolicyCreate(TWPLIB_HANDLE hLib, TWPConfigurationHandle hCfg, TWPCategories *pCategories,
+                           unsigned int uCount, TWPPolicyHandle *phPolicy)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfPolicyCreate == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfPolicyCreate)(hCfg, pCategories, uCount, phPolicy);
+}
+
+TWP_RESULT TWPPolicyValidate(TWPLIB_HANDLE hLib, TWPPolicyHandle hPolicy, TWPUrlRatingHandle hRating, int *piViolated)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfPolicyValidate == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfPolicyValidate)(hPolicy, hRating, piViolated);
+}
+
+TWP_RESULT TWPPolicyGetViolations(TWPLIB_HANDLE hLib, TWPPolicyHandle hPolicy, TWPUrlRatingHandle hRating,
+                                  TWPCategories **ppViolated, unsigned *puLength)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfPolicyGetViolations == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfPolicyGetViolations)(hPolicy, hRating, ppViolated, puLength);
+}
+
+TWP_RESULT TWPPolicyDestroy(TWPLIB_HANDLE hLib, TWPPolicyHandle *hPolicy)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfPolicyDestroy == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfPolicyDestroy)(hPolicy);
+}
+
+TWP_RESULT TWPUrlRatingGetScore(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, int *piScore)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfUrlRatingGetScore == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfUrlRatingGetScore)(hRating, piScore);
+}
+
+TWP_RESULT TWPUrlRatingGetUrl(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, char **ppUrl,
+                              unsigned int *puLength)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfUrlRatingGetUrl == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfUrlRatingGetUrl)(hRating, (const char **) ppUrl, puLength);
+}
+
+TWP_RESULT TWPUrlRatingGetDLAUrl(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, char **ppDlaUrl,
+                                 unsigned int *puLength)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfUrlRatingGetDLAUrl == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfUrlRatingGetDLAUrl)(hRating, (const char **) ppDlaUrl, puLength);
+}
+
+TWP_RESULT TWPUrlRatingHasCategory(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, TWPCategories Category,
+                                   int *piPresent)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfUrlRatingHasCategory == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfUrlRatingHasCategory)(hRating, Category, piPresent);
+}
+
+TWP_RESULT TWPUrlRatingGetCategories(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, TWPCategories **ppCategories,
+                                     unsigned int *puLength)
+{
+    SitePluginContext *pCtx = (SitePluginContext *) hLib;
+
+    if (pCtx == NULL || pCtx->pfUrlRatingGetCategories == NULL)
+        return TWP_NOT_IMPLEMENTED;
+
+    return (*pCtx->pfUrlRatingGetCategories)(hRating, ppCategories, puLength);
+}
+
+static SitePluginContext *LoadPlugin(void)
+{
+    SitePluginContext *pCtx = NULL;
+    void *pTmp = dlopen(SITE_PLUGIN_PATH, RTLD_LAZY);
+    DEBUG_LOG("%s", "load site plugin\n");
+    if (pTmp != NULL)
+    {
+        FuncUninitLibrary TmpUninitLibrary;
+        FuncInitLibrary TmpInitLibrary;
+        FuncConfigurationCreate TmpConfigurationCreate;
+        FuncConfigurationDestroy TmpConfigurationDestroy;
+        FuncLookupUrls TmpLookupUrls;
+        FuncResponseWrite TmpResponseWrite;
+        FuncResponseGetUrlRatingByIndex TmpResponseGetUrlRatingByIndex;
+        FuncResponseGetUrlRatingByUrl TmpResponseGetUrlRatingByUrl;
+        FuncResponseGetRedirUrlFor TmpResponseGetRedirUrlFor;
+        FuncResponseGetUrlRatingsCount TmpResponseGetUrlRatingsCount;
+        FuncResponseDestroy TmpResponseDestroy;
+        FuncPolicyCreate TmpPolicyCreate;
+        FuncPolicyValidate TmpPolicyValidate;
+        FuncPolicyGetViolations TmpPolicyGetViolations;
+        FuncPolicyDestroy TmpPolicyDestroy;
+        FuncUrlRatingGetScore TmpUrlRatingGetScore;
+        FuncUrlRatingGetUrl TmpUrlRatingGetUrl;
+        FuncUrlRatingGetDLAUrl TmpUrlRatingGetDLAUrl;
+        FuncUrlRatingHasCategory TmpUrlRatingHasCategory;
+        FuncUrlRatingGetCategories TmpUrlRatingGetCategories;
+        
+        do
+        {
+            TmpInitLibrary = dlsym(pTmp, "TWPPInitLibrary");
+            DEBUG_LOG("%s", "load api TWPPInitLibrary\n");
+            if (TmpInitLibrary == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPInitLibrary in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpUninitLibrary = dlsym(pTmp, "TWPPUninitLibrary");
+            DEBUG_LOG("%s", "load api TWPPUninitLibrary\n");
+            if (TmpUninitLibrary == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPUninitLibrary in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpConfigurationCreate = dlsym(pTmp, "TWPPConfigurationCreate");
+            DEBUG_LOG("%s", "load api TWPPConfigurationCreate\n");
+            if (TmpConfigurationCreate == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPConfigurationCreate in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpConfigurationDestroy = dlsym(pTmp, "TWPPConfigurationDestroy");
+            DEBUG_LOG("%s", "load api TWPPConfigurationDestroy\n");
+            if (TmpConfigurationDestroy == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPConfigurationDestroy in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpLookupUrls = dlsym(pTmp, "TWPPLookupUrls");
+            DEBUG_LOG("%s", "load api TWPPLookupUrls\n");
+            if (TmpLookupUrls == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPLookupUrls in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpResponseWrite = dlsym(pTmp, "TWPPResponseWrite");
+            DEBUG_LOG("%s", "load api TWPPResponseWrite\n");
+            if (TmpResponseWrite == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPResponseWrite in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpResponseGetUrlRatingByIndex = dlsym(pTmp, "TWPPResponseGetUrlRatingByIndex");
+            DEBUG_LOG("%s", "load api TWPPResponseGetUrlRatingByIndex\n");
+            if (TmpResponseGetUrlRatingByIndex == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPResponseGetUrlRatingByIndex in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpResponseGetUrlRatingByUrl = dlsym(pTmp, "TWPPResponseGetUrlRatingByUrl");
+            DEBUG_LOG("%s", "load api TWPPResponseGetUrlRatingByUrl\n");
+            if (TmpResponseGetUrlRatingByUrl == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPResponseGetUrlRatingByUrl in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpResponseGetRedirUrlFor = dlsym(pTmp, "TWPPResponseGetRedirUrlFor");
+            DEBUG_LOG("%s", "load api TWPPResponseGetRedirUrlFor\n");
+            if (TmpResponseGetRedirUrlFor == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPResponseGetRedirUrlFor in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpResponseGetUrlRatingsCount = dlsym(pTmp, "TWPPResponseGetUrlRatingsCount");
+            DEBUG_LOG("%s", "load api TWPPResponseGetUrlRatingsCount\n");
+            if (TmpResponseGetUrlRatingsCount == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPResponseGetUrlRatingsCount in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpResponseDestroy = dlsym(pTmp, "TWPPResponseDestroy");
+            DEBUG_LOG("%s", "load api TWPPResponseDestroy\n");
+            if (TmpResponseDestroy == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPResponseDestroy in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpPolicyCreate = dlsym(pTmp, "TWPPPolicyCreate");
+            DEBUG_LOG("%s", "load api TWPPPolicyCreate\n");
+            if (TmpPolicyCreate == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPPolicyCreate in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpPolicyValidate = dlsym(pTmp, "TWPPPolicyValidate");
+            DEBUG_LOG("%s", "load api TWPPPolicyValidate\n");
+            if (TmpPolicyValidate == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPPolicyValidate in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpPolicyGetViolations = dlsym(pTmp, "TWPPPolicyGetViolations");
+            DEBUG_LOG("%s", "load api TWPPPolicyGetViolations\n");
+            if (TmpPolicyGetViolations == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPPolicyGetViolations in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpPolicyDestroy = dlsym(pTmp, "TWPPPolicyDestroy");
+            DEBUG_LOG("%s", "load api TWPPPolicyDestroy\n");
+            if (TmpPolicyDestroy == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPPolicyDestroy in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpUrlRatingGetScore = dlsym(pTmp, "TWPPUrlRatingGetScore");
+            DEBUG_LOG("%s", "load api TWPPUrlRatingGetScore\n");
+            if (TmpUrlRatingGetScore == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPUrlRatingGetScore in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpUrlRatingGetUrl = dlsym(pTmp, "TWPPUrlRatingGetUrl");
+            DEBUG_LOG("%s", "load api TWPPUrlRatingGetUrl\n");
+            if (TmpUrlRatingGetUrl == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPUrlRatingGetUrl in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpUrlRatingGetDLAUrl = dlsym(pTmp, "TWPPUrlRatingGetDLAUrl");
+            DEBUG_LOG("%s", "load api TWPPUrlRatingGetDLAUrl\n");
+            if (TmpUrlRatingGetDLAUrl == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPUrlRatingGetDLAUrl in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpUrlRatingHasCategory = dlsym(pTmp, "TWPPUrlRatingHasCategory");
+            DEBUG_LOG("%s", "load api TWPPUrlRatingHasCategory\n");
+            if (TmpUrlRatingHasCategory == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPUrlRatingHasCategory in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            TmpUrlRatingGetCategories = dlsym(pTmp, "TWPPUrlRatingGetCategories");
+            DEBUG_LOG("%s", "load api TWPPUrlRatingGetCategories\n");
+            if (TmpUrlRatingGetCategories == NULL)
+            {
+                DEBUG_LOG("Failed to load TWPPUrlRatingGetCategories in %s\n", SITE_PLUGIN_PATH);
+                dlclose(pTmp);
+                break;
+            }
+
+            pCtx = (SitePluginContext *) malloc(sizeof(SitePluginContext));
+            if (pCtx == NULL)
+            {
+                dlclose(pTmp);
+                break;
+            }
+            
+            pCtx->pPlugin = pTmp;
+            pCtx->pfUninitLibrary = TmpUninitLibrary;
+            pCtx->pfInitLibrary = TmpInitLibrary;
+            pCtx->pfConfigurationCreate = TmpConfigurationCreate;
+            pCtx->pfConfigurationDestroy = TmpConfigurationDestroy;
+            pCtx->pfLookupUrls = TmpLookupUrls;
+            pCtx->pfResponseWrite = TmpResponseWrite;
+            pCtx->pfResponseGetUrlRatingByIndex = TmpResponseGetUrlRatingByIndex;
+            pCtx->pfResponseGetUrlRatingByUrl = TmpResponseGetUrlRatingByUrl;
+            pCtx->pfResponseGetRedirUrlFor = TmpResponseGetRedirUrlFor;
+            pCtx->pfResponseGetUrlRatingsCount = TmpResponseGetUrlRatingsCount;
+            pCtx->pfResponseDestroy = TmpResponseDestroy;
+            pCtx->pfPolicyCreate = TmpPolicyCreate;
+            pCtx->pfPolicyValidate = TmpPolicyValidate;
+            pCtx->pfPolicyGetViolations = TmpPolicyGetViolations;
+            pCtx->pfPolicyDestroy = TmpPolicyDestroy;
+            pCtx->pfUrlRatingGetScore = TmpUrlRatingGetScore;
+            pCtx->pfUrlRatingGetUrl = TmpUrlRatingGetUrl;
+            pCtx->pfUrlRatingGetDLAUrl = TmpUrlRatingGetDLAUrl;
+            pCtx->pfUrlRatingHasCategory = TmpUrlRatingHasCategory;
+            pCtx->pfUrlRatingGetCategories = TmpUrlRatingGetCategories;
+        } while(0);
+    }
+    else
+    {
+        DEBUG_LOG("No plugin found.\n");
+    }
+
+    return pCtx;
+}
diff --git a/framework/TWPImpl.h b/framework/TWPImpl.h
new file mode 100644 (file)
index 0000000..7eaf9c0
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef TWPIMPL_H
+#define TWPIMPL_H
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+/**
+ * \file TWPImpl.h
+ * \brief TWP Header File
+ *
+ * This file provides the Tizen Web Protection API functions.
+ */
+
+typedef long unsigned int TWPMallocSizeT; /* Size unit */
+
+struct TWPLibHandle_struct {int iDummy;};
+
+typedef struct TWPLibHandle_struct *TWPLIB_HANDLE;
+
+#define TWPAPI_VERSION 1 /* SDK version */
+       
+#define TWPCONFIG_VERSION 1 /* Configure version */
+       
+#define TWPREQUEST_VERSION 1 /* Request version */
+
+#define INVALID_TWPLIB_HANDLE ((TWPLIB_HANDLE) 0) /* Invalid web protection library interface handle. */
+       
+/**
+ * Result code used by TWP_RESULT
+ */
+typedef enum
+{
+       TWP_SUCCESS = 0,        
+       TWP_ERROR = 1,  
+       TWP_NOMEM = 2,  
+       TWP_INVALID_HANDLE = 3, 
+       TWP_INVALID_PARAMETER = 4,      
+       TWP_INVALID_VERSION = 5, 
+       TWP_INVALID_RESPONSE = 6, 
+       TWP_NO_DATA = 7,
+       TWP_NOT_IMPLEMENTED = 500       
+} TWP_RESULT;
+
+/**
+ * Web site category definitions
+ */
+typedef enum 
+{
+       TWP_Artcultureheritage, 
+       TWP_Alcohol,            
+       TWP_Anonymizers, 
+       TWP_Anonymizingutilities, 
+       TWP_Business, 
+       TWP_Chat, 
+       TWP_Publicinformation, 
+       TWP_Potentialcriminalactivities,  
+       TWP_Drugs, 
+       TWP_Educationreference, 
+       TWP_Entertainment, 
+       TWP_Extreme, 
+       TWP_Financebanking, 
+       TWP_Gambling, 
+       TWP_Games, 
+       TWP_Governmentmilitary, 
+       TWP_Potentialhackingcomputercrime, 
+       TWP_Health, 
+       TWP_Humorcomics, 
+       TWP_Discrimination, 
+       TWP_Instantmessaging, 
+       TWP_Stocktrading, 
+       TWP_Internetradiotv, 
+       TWP_Jobsearch, 
+       TWP_Informationsecurity, 
+       TWP_E_RESERVED_1, 
+       TWP_Mobilephone, 
+       TWP_Mediadownloads, 
+       TWP_Malicioussites, 
+       TWP_E_RESERVED_2, 
+       TWP_Nudity, 
+       TWP_Nonprofitadvocacyngo, 
+       TWP_Generalnews, 
+       TWP_Onlineshopping, 
+       TWP_Provocativeattire, 
+       TWP_P2pfilesharing, 
+       TWP_Politicsopinion, 
+       TWP_Personalpages, 
+       TWP_Portalsites, 
+       TWP_Remoteaccess, 
+       TWP_Religionideology, 
+       TWP_Resourcesharing, 
+       TWP_Searchengines, 
+       TWP_Sports, 
+       TWP_Streamingmedia, 
+       TWP_Sharewarefreeware, 
+       TWP_Pornography, 
+       TWP_Spywareadwarekeyloggers, 
+       TWP_Tobacco, 
+       TWP_Travel, 
+       TWP_Violence, 
+       TWP_Webads, 
+       TWP_Weapons, 
+       TWP_Webmail, 
+       TWP_Webphone, 
+       TWP_Auctionsclassifieds, 
+       TWP_Forumbulletinboards, 
+       TWP_Profanity, 
+       TWP_Schoolcheatinginformation, 
+       TWP_Sexualmaterials, 
+       TWP_Gruesomecontent, 
+       TWP_Visualsearchengine, 
+       TWP_Technicalbusinessforums, 
+       TWP_Gamblingrelated, 
+       TWP_Messaging, 
+       TWP_Gamecartoonviolence, 
+       TWP_Phishing, 
+       TWP_Personalnetworkstorage, 
+       TWP_Spamurls, 
+       TWP_Interactivewebapplications, 
+       TWP_Fashionbeauty, 
+       TWP_Softwarehardware, 
+       TWP_Potentialillegalsoftware, 
+       TWP_Contentserver, 
+       TWP_Internetservices, 
+       TWP_Mediasharing, 
+       TWP_Incidentalnudity, 
+       TWP_Marketingmerchandising, 
+       TWP_Parkeddomain, 
+       TWP_Pharmacy, 
+       TWP_Restaurants, 
+       TWP_Realestate, 
+       TWP_Recreationhobbies, 
+       TWP_Blogswiki, 
+       TWP_Digitalpostcards, 
+       TWP_Historicalrevisionism, 
+       TWP_Technicalinformation, 
+       TWP_Datingpersonals, 
+       TWP_Motorvehicles, 
+       TWP_Professionalnetworking, 
+       TWP_Socialnetworking, 
+       TWP_Texttranslators, 
+       TWP_Webmeetings, 
+       TWP_Forkids, 
+       TWP_E_RESERVED_3, 
+       TWP_Moderated, 
+       TWP_Textspokenonly, 
+       TWP_Controversialopinions, 
+       TWP_Residentialipaddresses, 
+       TWP_Browserexploits, 
+       TWP_Consumerprotection, 
+       TWP_Illegaluk, 
+       TWP_Majorglobalreligions, 
+       TWP_Maliciousdownloads, 
+       TWP_Potentiallyunwantedprograms, 
+       
+       TWP_LastCategoryPlaceholder = 128,       
+       TWP_OverallPhishing = 129,                      
+       TWP_OverallRiskHigh = 130,                      
+       TWP_OverallRiskMedium = 131,            
+       TWP_OverallRiskMinimal = 132,           
+       TWP_OverallRiskUnverified = 137,
+       TWP_LastAttributePlaceholder = 160,     
+} TWPCategories;
+
+/**
+ * Risk level
+ */
+typedef enum
+{
+       TWP_Minimal,            
+       TWP_Unverified,         
+       TWP_Medium,                     
+       TWP_High,                       
+} TWPRiskLevel;
+
+/**
+ * Score range
+ */
+typedef enum 
+{
+       TWP_MinimalLow = 0,     
+       TWP_MinimalHigh = 14, 
+       TWP_UnverifiedLow = 15, 
+       TWP_UnverifiedHigh = 29, 
+       TWP_MediumLow = 30, 
+       TWP_MediumHigh = 49, 
+       TWP_HighLow= 50, 
+       TWP_HighHigh = 127 
+} TWPScoreRange;
+
+/**
+ * HTTP submit method
+ */
+typedef enum
+{
+       TWPPOST, 
+} TWPSubmitMethod;
+       
+/* forward declaration */
+struct TWPRequest;      
+typedef struct TWPConfiguration *TWPConfigurationHandle;
+typedef struct TWPResponse*    TWPResponseHandle;
+typedef struct TWPUrlRating *TWPUrlRatingHandle;
+typedef struct TWPPolicy *TWPPolicyHandle;
+typedef void *(*TWPFnMemAlloc)(TWPMallocSizeT size);
+typedef void (*TWPFnMemFree)(void *address);
+typedef long (*TWPFnRandom)(void);
+typedef TWP_RESULT (*TWPFnRequestSetUrl)(struct TWPRequest *request, const char *url,
+                                         unsigned int length);
+typedef TWP_RESULT (*TWPFnRequestSetMethod)(struct TWPRequest *request, TWPSubmitMethod method);
+typedef TWP_RESULT (*TWPFnRequestSend)(struct TWPRequest *request, TWPResponseHandle response,
+                                       const void *data, unsigned int length);
+typedef TWP_RESULT (*TWPFnRequestReceive)(struct TWPRequest *request, void *buffer,
+                                          unsigned int buffer_length, unsigned int *length);   
+
+/**
+ * Initialize data requested by SDK initialization
+ */
+typedef struct TWPAPIInit
+{
+    int api_version;           
+    TWPFnMemAlloc memallocfunc;                
+    TWPFnMemFree memfreefunc;
+} TWPAPIInit;
+
+/**
+ * Configuration which enable caller to customize the SDK
+ */
+typedef struct TWPConfiguration
+{
+       int config_version; /* Configuration version */
+       const char *client_id; /* Client id for cloud to qualify */
+       const char *client_key; /* Corresponding key for specific client for validation from cloud */
+       const char *host; /* Host name for cloud where SDK send request to, set to NULL for SDK to use default settings in plug-in */
+       int     secure_connection; /* 1 - use secured connection (HTTPS), 0 - not secured connection. */
+       int     skip_dla; /* 1 - disable DLA lookup, 0 - enable DLA lookup */
+       int     obfuscate_request; /* 1 - obfuscate request data, 0 - do not obfuscate request data */
+       TWPFnRandom randomfunc; /* Caller customized random function */
+} TWPConfiguration;
+
+/**
+ * Request for SDK to check URL against cloud database
+ */
+typedef struct TWPRequest
+{
+       int request_version; /* Request version */
+       TWPFnRequestSetUrl seturlfunc; /* Callback for SDK to set URL from SDK */       
+       TWPFnRequestSetMethod setmethodfunc; /* Callback for SDK to set HTTP request method */
+       TWPFnRequestSend sendfunc; /* Callback for SDK to send HTTP request */
+       TWPFnRequestReceive receivefunc; /* Callback for SDK to receive HTTP response, if caller set it to be NULL,
+                                        SDK will assume the HTTP request will be handled in a-synchronized manner */
+} TWPRequest;
+       
+/**
+ * \brief
+ * Initialize SDK
+ *
+ * This is a synchronized API
+ *
+ * \param[in] pApiInit API initialization data structure.
+ *
+ * \return TWP_RESULT
+ */
+TWPLIB_HANDLE TWPInitLibrary(TWPAPIInit *pApiInit);
+
+/**
+ * \brief
+ * Uninitialize SDK
+ *
+ * This is a synchronized API
+ *
+ */
+void TWPUninitLibrary(TWPLIB_HANDLE hLib);
+
+/**
+ * \brief
+ * Create TWP configuration to customize SDK
+ * 
+ * This is a synchronized API
+ *
+ * \param[in] pConfigure caller configurations
+ * \param[out] phConfigure created configuration for SDK
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPConfigurationCreate(TWPLIB_HANDLE hLib, TWPConfiguration *pConfigure, TWPConfigurationHandle *phConfigure);
+
+/**
+ * \brief
+ * Release the configuration resources allocated by TWPConfigurationCreate
+ *
+ * This is a synchronized API
+ *
+ * \param[in] hConfigure configuration to be destroyed
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPConfigurationDestroy(TWPLIB_HANDLE hLib, TWPConfigurationHandle *hConfigure);
+
+/**
+ * \brief
+ * Main function for caller to check URL reputation against the cloud database
+ *
+ * This can be a synchronized API or a-synchronized API depends on the configuration from caller
+ *
+ * Synchronous mode
+ *      In this synchronous operation mode, the function invokes TWPRequest::sendfunc and
+ *      TWPRequest::receivefunc, one right after the other, expecting the entire HTTP
+ *      transaction to be completed between the calls. Upon successful completion, the
+ *      phResponse will point to a valid response handle that can be used to analyze results.
+ *
+ * Asynchronous mode
+ *      In the asynchronous mode, the function invokes TWPRequest::sendfunc and returns
+ *      immediately with TWP_SUCCESS. Upon completion, phResponse is NULL. The application
+ *      is supposed to complete the HTTP transaction while calling TWPResponseWrite as
+ *      response data becomes available. When all data was read, TWPResponseWrite must
+ *      be called again with zero data length to signal the end transaction.
+ *
+ * \param[in] hConfigure Configuration of caller
+ * \param[in] pRequest Request data structure for SDK to check with cloud
+ * \param[in] iRedirUrl 1 indicating instruct the cloud server to provide a landing page
+ *            URL to which blocked URLs can be redirected.
+ * \param[in] ppUrls An array of 7 bit ASCII character strings representing URLs to obtain
+ *            the rating for.
+ *
+ *            Note: All URLs have to be normalized before submission (see RFC 3986) and
+ *            pynicoded if required.
+ * \param[in] uCount Length of the ppUrls array.
+ * \param[out] phResponse For synchronous requests, a pointer to the location where the
+ *             response object handle will be stored upon completion. It can be NULL for
+ *             asynchronous requests.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPLookupUrls(TWPLIB_HANDLE hLib, TWPConfigurationHandle hConfigure, TWPRequest *pRequest,
+                         int iRedirUrl, const char **ppUrls, unsigned int uCount, TWPResponseHandle *phResponse);
+
+/**
+ * \brief
+ * In asynchronous mode, caller will call this API to write received HTTP response data
+ * to SDK. Writing with zero data length will be taken as end of HTTP transaction for
+ * SDK.
+ *
+ * This is a synchronized API
+ *
+ * \param[in] hResponse Response handle for SDK to keep track on HTTP transaction.
+ * \param[in] pData Received HTTP response data chunk.
+ * \param[in] uLength Length of the HTTP response data.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPResponseWrite(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, const void *pData, unsigned uLength);
+
+/**
+ * \brief
+ * Get web site rating by its index in URL list in the response which comply to
+ * the URL list order passed by caller in TWPLookupUrls().
+ *
+ * This is a synchronized API
+ *
+ * \param[in] hResponse Response handle created based on cloud response.
+ * \param[in] iIndex Index of the web site in request list.
+ * \param[out] phRating Rating of the specified web site.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPResponseGetUrlRatingByIndex(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, unsigned int uIndex,
+                                          TWPUrlRatingHandle *phRating);
+
+/**
+ * \brief
+ * Get web site rating by its URL string.
+ *
+ * This is a synchronized API
+ *
+ * \param[in] hResponse Response handle created based on cloud response.
+ * \param[in] pUrl URL string
+ * \param[in] iUrlLength URL string length
+ * \param[out] hRating Rating of the specified web site
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPResponseGetUrlRatingByUrl(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, const char *pUrl,
+                                        unsigned int uUrlLength, TWPUrlRatingHandle *hRating);
+
+/**
+ * \brief
+ * Get the redirection URL for blocked URL to display to user.
+ *
+ * Blocking pages can be used by application that want to block users
+ * from navigating to a URL that violates one of the defined policies.
+ * The returned string must be deallocated by the application using
+ * TWPAPIInit::TWPFnMemFree function.
+ *
+ * \param[in] hResponse Response handle created based on cloud response.
+ * \param[in] hRating Rating handle resolved from cloud response.
+ * \param[in] hPolicy Policy handle created by caller.
+ * \param[out] ppUrl Redirection URL.
+ * \param[ou] puLength Length of redirection URL
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPResponseGetRedirUrlFor(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, TWPUrlRatingHandle hRating,
+                                     TWPPolicyHandle hPolicy, char **ppUrl, unsigned int *puLength);
+
+/**
+ * \brief
+ * Get the rating count of specified response.
+ *
+ * \param[in] hResponse Response handle created based on cloud response.
+ * \param[out] puCount Rating count.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPResponseGetUrlRatingsCount(TWPLIB_HANDLE hLib, TWPResponseHandle hResponse, unsigned int *puCount);      
+
+/**
+ * \brief
+ * Release resource for response handle.
+ *
+ * \param[in] hResponse Response handle created based on cloud response.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPResponseDestroy(TWPLIB_HANDLE hLib, TWPResponseHandle *hResponse);
+
+/**
+ * \brief
+ * Create the policy (set of web site categories) caller want to check.
+ *
+ * \param[in] hCfg configuration handle
+ * \param[in] pCategories Web site category list
+ * \param[in] uCount Category list length.
+ * \param[out] phPolicy Policy handle.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPPolicyCreate(TWPLIB_HANDLE hLib, TWPConfigurationHandle hCfg, TWPCategories *pCategories, unsigned int uCount, TWPPolicyHandle *hPolicy);
+
+/**
+ * \brief
+ * Compare the categories assigned by security vendor to the URL represented
+ * by hRating with the categories assigned to the policy handle.
+ *
+ * \param[in] hPolicy Polcy handle
+ * \param[in] hRating Rating for specific URL
+ * \param[out] piVialated non-zero if intersection found between the policy and URL rating categories.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPPolicyValidate(TWPLIB_HANDLE hLib, TWPPolicyHandle hPolicy, TWPUrlRatingHandle hRating, int *piViolated);
+
+/**
+ * \brief
+ * Retrieves all categories common between the policy and URL rating.
+ *
+ * \param[in] hPolicy Policy handle.
+ * \param[in] hRating URL rating handle.
+ * \param[out] ppViolated An array of all common categories. This array is allocated by using
+ *             TWPAPIInit::memallocfunc and has to be deallocated by the caller.
+ * \param[out] puLength Length of violation array.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPPolicyGetViolations(TWPLIB_HANDLE hLib, TWPPolicyHandle hPolicy, TWPUrlRatingHandle hRating,
+                                  TWPCategories **ppViolated, unsigned *puLength);
+
+/**
+ * \brief
+ * Release resource for policy handle.
+ *
+ * \param[in] phPolicy Pointer to policy handle.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPPolicyDestroy(TWPLIB_HANDLE hLib, TWPPolicyHandle *hPolicy);
+
+/**
+ * \brief
+ * Get score from URL rating data structure which is assigned by security vendor.
+ *
+ * \param[in] hRating Rating handle.
+ * \param[out] piScore URL score.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPUrlRatingGetScore(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, int *piScore);
+
+/**
+ * \brief
+ * Get corresponding URL from rating handle.
+ *
+ * \param[in] hRating Rating handle.
+ * \param[out] ppUrl A pointer to a NULL terminated string representing
+ *             the URL. The string is valid as long as the URL rating
+ *             handle is valid.
+ * \param[out] puLength An optional pointer to the length of URL string.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPUrlRatingGetUrl(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, char **ppUrl,
+                              unsigned int *puLength);
+
+/**
+ * \brief
+ * Get DLA (Deep Link Analysis) URL
+ *
+ * \param[in] hRating Rating handle.
+ * \param[out] ppDlaUrl A ponit to a NULL terminated string representing
+ *             the DLA URL. This string is valid as long as the URL rating
+ *             handle is valid.
+ * \param[out] puLength Length of DLA URL string.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPUrlRatingGetDLAUrl(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, char **ppDlaUrl,
+                                 unsigned int *puLength);
+
+/**
+ * \brief
+ * Determine whether the URL rating object has the specified category.
+ *
+ * \param[in] hRating Rating handle.
+ * \param[in] Category Category enum value.
+ * \param[out] piPresent Non-zero value indicating exists.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPUrlRatingHasCategory(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, TWPCategories Category,
+                                   int *piPresent);
+
+/**
+ * \brief
+ * Retrives categories assigned by security vendor for the rated URL.
+ *
+ * \param[in] hRating Rating handle.
+ * \param[out] ppCategories The pointer to a variable that contains the address
+ *             of the category list.
+ * \param[out] puLength Length of category list.
+ *
+ * \return TWP_RESULT
+ */
+TWP_RESULT TWPUrlRatingGetCategories(TWPLIB_HANDLE hLib, TWPUrlRatingHandle hRating, TWPCategories **ppCategories,
+                                     unsigned int *puLength);
+       
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/packaging/csr-framework.manifest b/packaging/csr-framework.manifest
new file mode 100644 (file)
index 0000000..2a0cec5
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+  <request>
+    <domain name="_"/>
+  </request>
+</manifest>
diff --git a/packaging/csr-framework.spec b/packaging/csr-framework.spec
new file mode 100755 (executable)
index 0000000..afb6a63
--- /dev/null
@@ -0,0 +1,77 @@
+Summary: A general purpose content screening and reputation solution
+Name: csr-framework
+Version: 1.1.0
+Release: 2
+
+Source: %{name}-%{version}.tar.gz
+
+License: BSD
+Group: System/Libraries
+URL: http://tizen.org
+
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(dlog)
+
+%description
+csr-framework
+
+%package devel
+Summary:    Development files for csr-framework
+Group:      TO_BE/FILLED_IN
+Requires:   %{name} = %{version}
+
+%description devel
+To be described
+
+
+%package test
+Summary:    test program for csr-framework
+Group:      TO_BE/FILLED_IN
+Requires:   %{name} = %{version}
+
+%description test
+Comaptilibty test program
+
+
+%prep
+%setup -q 
+
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+mkdir -p %{buildroot}/usr/share/license
+cp -f LICENSE %{buildroot}/usr/share/license/%{name}
+
+%make_install
+
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/libsecfw.so
+/usr/share/license/%{name}
+
+%files devel
+%defattr(-,root,root,-)
+%doc README
+%doc doc/
+%{_includedir}/TCSErrorCodes.h
+%{_includedir}/TCSImpl.h
+%{_includedir}/TWPImpl.h
+%{_libdir}/pkgconfig/*.pc
+
+%files test
+%defattr(-,root,root,-)
+/usr/sbin/*
+/usr/local/compatibility-test/*
+
diff --git a/test/SampleInfo.c b/test/SampleInfo.c
new file mode 100644 (file)
index 0000000..266593f
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "stdlib.h"
+#include "TCSTest.h"
+#include "TCSImpl.h"
+
+#include "SampleInfo.h"
+
+
+/*
+ * Maximum sample file name length.
+ */
+#define MAX_SAMPLE_NAME_LEN 128
+
+#define MAX_INFECTED_NUM 3
+
+
+typedef struct SampleInfo_struct
+{
+    enum ENUM_MALWARE_TEST_TYPES eTestType;
+    char szName[TCS_MAX_MALWARE_NAME_LEN];
+    char szVariant[TCS_MAX_MALWARE_NAME_LEN];
+    unsigned int uSeverity;
+    unsigned int uBehavior;
+    unsigned int uType;
+    char szInfectedFileName[MAX_SAMPLE_NAME_LEN];
+    char szBenignFileName[MAX_SAMPLE_NAME_LEN];
+} SampleInfo;
+
+
+static SampleInfo Samples[][MAX_INFECTED_NUM] =
+{
+    {
+        {
+            MALWARE_TTYPE_BUFFER,
+            BUFFER_MALWARE_NAME,
+            BUFFER_VARIANT_NAME,
+            BUFFER_SEVERITY_CLASS,
+            BUFFER_BEHAVIOR_CLASS,
+            BUFFER_MALWARE_TYPE,
+            BUFFER_FILE_NAME_1,
+            BUFFER_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_HTML,
+            HTML_MALWARE_NAME,
+            HTML_VARIANT_NAME,
+            HTML_SEVERITY_CLASS,
+            HTML_BEHAVIOR_CLASS,
+            HTML_MALWARE_TYPE,
+            HTML_FILE_NAME_1,
+            HTML_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_URL,
+            URL_MALWARE_NAME,
+            URL_VARIANT_NAME,
+            URL_SEVERITY_CLASS,
+            URL_BEHAVIOR_CLASS,
+            URL_MALWARE_TYPE,
+            URL_FILE_NAME_1,
+            URL_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_EMAIL,
+            EMAIL_MALWARE_NAME,
+            EMAIL_VARIANT_NAME,
+            EMAIL_SEVERITY_CLASS,
+            EMAIL_BEHAVIOR_CLASS,
+            EMAIL_MALWARE_TYPE,
+            EMAIL_FILE_NAME_1,
+            EMAIL_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_PHONE,
+            PHONE_MALWARE_NAME,
+            PHONE_VARIANT_NAME,
+            PHONE_SEVERITY_CLASS,
+            PHONE_BEHAVIOR_CLASS,
+            PHONE_MALWARE_TYPE,
+            PHONE_FILE_NAME_1,
+            PHONE_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_TEXT,
+            TEXT_MALWARE_NAME,
+            TEXT_VARIANT_NAME,
+            TEXT_SEVERITY_CLASS,
+            TEXT_BEHAVIOR_CLASS,
+            TEXT_MALWARE_TYPE,
+            TEXT_FILE_NAME_1,
+            TEXT_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_JAVA,
+            JAVA_MALWARE_NAME,
+            JAVA_VARIANT_NAME,
+            JAVA_SEVERITY_CLASS,
+            JAVA_BEHAVIOR_CLASS,
+            JAVA_MALWARE_TYPE,
+            JAVA_FILE_NAME_1,
+            JAVA_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_MULTIPLE,
+            MULTIPLE0_MALWARE_NAME,
+            MULTIPLE0_VARIANT_NAME,
+            MULTIPLE0_SEVERITY_CLASS,
+            MULTIPLE0_BEHAVIOR_CLASS,
+            MULTIPLE0_MALWARE_TYPE,
+            MULTIPLE0_FILE_NAME_1,
+            MULTIPLE0_FILE_NAME_0
+        },
+        {
+            MALWARE_TTYPE_MULTIPLE,
+            MULTIPLE1_MALWARE_NAME,
+            MULTIPLE1_VARIANT_NAME,
+            MULTIPLE1_SEVERITY_CLASS,
+            MULTIPLE1_BEHAVIOR_CLASS,
+            MULTIPLE1_MALWARE_TYPE,
+            MULTIPLE1_FILE_NAME_1,
+            MULTIPLE1_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_JAVAS,
+            JAVAS_MALWARE_NAME,
+            JAVAS_VARIANT_NAME,
+            JAVAS_SEVERITY_CLASS,
+            JAVAS_BEHAVIOR_CLASS,
+            JAVAS_MALWARE_TYPE,
+            JAVAS_FILE_NAME_1,
+            JAVAS_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    },
+    {
+        {
+            MALWARE_TTYPE_COMPRESS,
+            COMPRESS_MALWARE_NAME,
+            COMPRESS_VARIANT_NAME,
+            COMPRESS_SEVERITY_CLASS,
+            COMPRESS_BEHAVIOR_CLASS,
+            COMPRESS_MALWARE_TYPE,
+            COMPRESS_FILE_NAME_1,
+            COMPRESS_FILE_NAME_0
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        },
+        {
+            -1, "", "", 0, 0, 0, "", ""
+        }
+    }
+};
+
+
+static SampleInfo *SampleGetInfo(int iType, int iIndex)
+{
+    int i;
+    int n = (int) (sizeof(Samples) / (sizeof(SampleInfo) * MAX_INFECTED_NUM));
+
+    for (i = 0; i < n; i++)
+    {
+        if (Samples[i][0].eTestType == iType)
+            return &Samples[i][iIndex];
+    }
+
+    return NULL;
+}
+
+
+const char *SampleGetMalName(int iType, int iIndex)
+{
+
+    return SampleGetInfo(iType, iIndex)->szName;
+}
+
+
+const char *SampleGetVarName(int iType, int iIndex)
+{
+
+    return SampleGetInfo(iType, iIndex)->szVariant;
+}
+
+
+unsigned int SampleGetSeverity(int iType, int iIndex)
+{
+
+    return SampleGetInfo(iType, iIndex)->uSeverity;
+}
+
+
+unsigned int SampleGetMalType(int iType, int iIndex)
+{
+
+    return SampleGetInfo(iType, iIndex)->uType;
+}
+
+
+unsigned int SampleGetBehavior(int iType, int iIndex)
+{
+
+    return SampleGetInfo(iType, iIndex)->uBehavior;
+}
+
+
+const char *SampleGetInfectedFileName(int iType)
+{
+
+    return SampleGetInfo(iType, 0)->szInfectedFileName;
+}
+
+
+const char *SampleGetBenignFileName(int iType)
+{
+
+    return SampleGetInfo(iType, 0)->szBenignFileName;
+}
+
+
+int SampleGetCount(int iType)
+{
+    int i = 0;
+
+    while (SampleGetInfo(iType, i)->eTestType == iType)
+        i++;
+
+    return i;
+}
+
diff --git a/test/SampleInfo.h b/test/SampleInfo.h
new file mode 100644 (file)
index 0000000..e5438b1
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SAMPLE_INFO_H
+#define SAMPLE_INFO_H
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+#define TCS_MAX_MALWARE_NAME_LEN 64
+
+#define MALWARE_1_0_0 "Malware-fortest-1.0.0"
+#define MALWARE_1_1_0 "Malware-fortest-1.1.0"
+#define MALWARE_1_2_0 "Malware-fortest-1.2.0"
+#define MALWARE_1_3_0 "Malware-fortest-1.3.0"
+#define MALWARE_1_4_0 "Malware-fortest-1.4.0"
+#define MALWARE_1_5_0 "Malware-fortest-1.5.0"
+#define MALWARE_1_6_0 "Malware-fortest-1.6.0"
+#define MALWARE_1_7_0 "Malware-fortest-1.7.0"
+#define MALWARE_1_8_0 "Malware-fortest-1.8.0"
+#define MALWARE_1_9_0 "Malware-fortest-1.9.0"
+
+#define VARIANT_1_0_0 "Variant-fortest-1.0.0"
+#define VARIANT_1_1_0 "Variant-fortest-1.1.0"
+#define VARIANT_1_2_0 "Variant-fortest-1.2.0"
+#define VARIANT_1_3_0 "Variant-fortest-1.3.0"
+#define VARIANT_1_4_0 "Variant-fortest-1.4.0"
+#define VARIANT_1_5_0 "Variant-fortest-1.5.0"
+#define VARIANT_1_6_0 "Variant-fortest-1.6.0"
+#define VARIANT_1_7_0 "Variant-fortest-1.7.0"
+#define VARIANT_1_8_0 "Variant-fortest-1.8.0"
+#define VARIANT_1_9_0 "Variant-fortest-1.9.0"
+
+#define BUFFER_MALWARE_NAME MALWARE_1_6_0
+#define BUFFER_VARIANT_NAME VARIANT_1_6_0
+#define BUFFER_SEVERITY_CLASS TCS_SC_USER
+#define BUFFER_BEHAVIOR_CLASS TCS_BC_LEVEL1
+#define BUFFER_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define BUFFER_FILE_NAME_1 "tcs-testfile-1.buf"
+#define BUFFER_FILE_NAME_0 "tcs-testfile-0.buf"
+
+#define HTML_MALWARE_NAME MALWARE_1_0_0
+#define HTML_VARIANT_NAME VARIANT_1_0_0
+#define HTML_SEVERITY_CLASS TCS_SC_USER
+#define HTML_BEHAVIOR_CLASS TCS_BC_LEVEL0
+#define HTML_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define HTML_FILE_NAME_1 "tcs-testfile-1.html"
+#define HTML_FILE_NAME_0 "tcs-testfile-0.html"
+
+#define URL_MALWARE_NAME MALWARE_1_1_0
+#define URL_VARIANT_NAME VARIANT_1_1_0
+#define URL_SEVERITY_CLASS TCS_SC_USER
+#define URL_BEHAVIOR_CLASS TCS_BC_LEVEL1
+#define URL_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define URL_FILE_NAME_1 "tcs-testfile-1.url"
+#define URL_FILE_NAME_0 "tcs-testfile-0.url"
+
+#define EMAIL_MALWARE_NAME MALWARE_1_2_0
+#define EMAIL_VARIANT_NAME VARIANT_1_2_0
+#define EMAIL_SEVERITY_CLASS TCS_SC_TERMINAL
+#define EMAIL_BEHAVIOR_CLASS TCS_BC_LEVEL2
+#define EMAIL_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define EMAIL_FILE_NAME_1 "tcs-testfile-1.email"
+#define EMAIL_FILE_NAME_0 "tcs-testfile-0.email"
+
+#define PHONE_MALWARE_NAME MALWARE_1_3_0
+#define PHONE_VARIANT_NAME VARIANT_1_3_0
+#define PHONE_SEVERITY_CLASS TCS_SC_TERMINAL
+#define PHONE_BEHAVIOR_CLASS TCS_BC_LEVEL3
+#define PHONE_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define PHONE_FILE_NAME_1 "tcs-testfile-1.phone"
+#define PHONE_FILE_NAME_0 "tcs-testfile-0.phone"
+
+#define TEXT_MALWARE_NAME MALWARE_1_4_0
+#define TEXT_VARIANT_NAME VARIANT_1_4_0
+#define TEXT_SEVERITY_CLASS TCS_SC_TERMINAL
+#define TEXT_BEHAVIOR_CLASS TCS_BC_LEVEL4
+#define TEXT_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define TEXT_FILE_NAME_1 "tcs-testfile-1.txt"
+#define TEXT_FILE_NAME_0 "tcs-testfile-0.txt"
+
+#define JAVA_MALWARE_NAME MALWARE_1_7_0
+#define JAVA_VARIANT_NAME VARIANT_1_7_0
+#define JAVA_SEVERITY_CLASS TCS_SC_USER
+#define JAVA_BEHAVIOR_CLASS TCS_BC_LEVEL0
+#define JAVA_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define JAVA_FILE_NAME_1 "tcs-testfile-1.class"
+#define JAVA_FILE_NAME_0 "tcs-testfile-0.class"
+
+#define MULTIPLE0_MALWARE_NAME MALWARE_1_5_0
+#define MULTIPLE0_VARIANT_NAME VARIANT_1_5_0
+#define MULTIPLE0_SEVERITY_CLASS TCS_SC_USER
+#define MULTIPLE0_BEHAVIOR_CLASS TCS_BC_LEVEL0
+#define MULTIPLE0_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define MULTIPLE0_FILE_NAME_1 "tcs-testfile-1.multiple"
+#define MULTIPLE0_FILE_NAME_0 "tcs-testfile-0.multiple"
+
+#define MULTIPLE1_MALWARE_NAME MALWARE_1_6_0
+#define MULTIPLE1_VARIANT_NAME VARIANT_1_6_0
+#define MULTIPLE1_SEVERITY_CLASS TCS_SC_USER
+#define MULTIPLE1_BEHAVIOR_CLASS TCS_BC_LEVEL1
+#define MULTIPLE1_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define MULTIPLE1_FILE_NAME_1 "tcs-testfile-1.multiple"
+#define MULTIPLE1_FILE_NAME_0 "tcs-testfile-0.multiple"
+
+#define JAVAS_MALWARE_NAME MALWARE_1_8_0
+#define JAVAS_VARIANT_NAME VARIANT_1_8_0
+#define JAVAS_SEVERITY_CLASS TCS_SC_USER
+#define JAVAS_BEHAVIOR_CLASS TCS_BC_LEVEL2
+#define JAVAS_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define JAVAS_FILE_NAME_1 "tcs-testfile-1.js"
+#define JAVAS_FILE_NAME_0 "tcs-testfile-0.js"
+
+#define COMPRESS_MALWARE_NAME MALWARE_1_9_0
+#define COMPRESS_VARIANT_NAME VARIANT_1_9_0
+#define COMPRESS_SEVERITY_CLASS TCS_SC_USER
+#define COMPRESS_BEHAVIOR_CLASS TCS_BC_LEVEL2
+#define COMPRESS_MALWARE_TYPE TCS_VTYPE_MALWARE
+#define COMPRESS_FILE_NAME_1 "tcs-testfile-1.z"
+#define COMPRESS_FILE_NAME_0 "tcs-testfile-0.z"
+
+#ifdef __cplusplus 
+}
+#endif
+
+#endif /* SAMPLE_INFO_H */
+
diff --git a/test/TCSTest.c b/test/TCSTest.c
new file mode 100644 (file)
index 0000000..315ac91
--- /dev/null
@@ -0,0 +1,1111 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include "TCSImpl.h"
+#include "TCSErrorCodes.h"
+
+#include "TCSTest.h"
+
+
+/* Test cases. */
+static void TCSStartup(void);
+static void TCSCleanup(void);
+static void TCSLibraryOpen_0001(void);
+static void TCSLibraryOpen_0002(void);
+static void TCSLibraryOpen_0003(void);
+static void TCSLibraryOpen_0004(void);
+static void TCSGetLastError_0001(void);
+static void TCSLibraryClose_0001(void);
+
+static void TCSScanData_0001(void);
+static void TCSScanData_0002(void);
+static void TCSScanData_0003(void);
+static void TCSScanData_0004(void);
+static void TCSScanData_0005(void);
+static void TCSScanData_0006(void);
+static void TCSScanData_0007(void);
+static void TCSScanData_0008(void);
+static void TCSScanData_0009(void);
+static void TCSScanData_0010(void);
+static void TCSScanData_0011(void);
+static void TCSScanData_0012(void);
+static void TCSScanData_0013(void);
+static void TCSScanData_0014(void);
+static void TCSScanData_0015(void);
+static void TCSScanData_0016(void);
+static void TCSScanData_0017(void);
+static void TCSScanData_0018(void);
+static void TCSScanData_0019(void);
+static void TCSScanData_0020(void);
+static void TCSScanData_0021(void);
+static void TCSScanData_0022(void);
+static void TCSScanData_0023(void);
+static void TCSScanData_0024(void);
+static void TCSScanData_0025(void);
+static void TCSScanData_0026(void);
+static void TCSScanData_0027(void);
+static void TCSScanData_0028(void);
+static void TCSScanData_0029(void);
+static void TCSScanData_0030(void);
+static void TCSScanData_0031(void);
+static void TCSScanData_0032(void);
+static void TCSScanData_0033(void);
+static void TCSScanData_0034(void);
+static void TCSScanData_0035(void);
+static void TCSScanData_0036(void);
+static void TCSScanData_0037(void);
+static void TCSScanData_0038(void);
+static void TCSScanData_0039(void);
+static void TCSScanData_0040(void);
+static void TCSScanData_0041(void);
+static void TCSScanData_0042(void);
+static void TCSScanData_0043(void);
+static void TCSScanData_0044(void);
+static void TCSScanData_0045(void);
+static void TCSScanData_0046(void);
+static void TCSScanData_0047(void);
+static void TCSScanData_0048(void);
+static void TCSScanData_0049(void);
+static void TCSScanData_0050(void);
+static void TCSScanData_0051(void);
+static void TCSScanData_0052(void);
+
+static void TCSScanFile_0001(void);
+static void TCSScanFile_0002(void);
+static void TCSScanFile_0003(void);
+static void TCSScanFile_0004(void);
+static void TCSScanFile_0005(void);
+static void TCSScanFile_0006(void);
+static void TCSScanFile_0007(void);
+static void TCSScanFile_0008(void);
+static void TCSScanFile_0009(void);
+static void TCSScanFile_0010(void);
+static void TCSScanFile_0011(void);
+static void TCSScanFile_0012(void);
+static void TCSScanFile_0013(void);
+static void TCSScanFile_0014(void);
+static void TCSScanFile_0015(void);
+static void TCSScanFile_0016(void);
+static void TCSScanFile_0017(void);
+static void TCSScanFile_0018(void);
+static void TCSScanFile_0019(void);
+static void TCSScanFile_0020(void);
+static void TCSScanFile_0021(void);
+static void TCSScanFile_0022(void);
+static void TCSScanFile_0023(void);
+static void TCSScanFile_0024(void);
+static void TCSScanFile_0025(void);
+static void TCSScanFile_0026(void);
+static void TCSScanFile_0027(void);
+static void TCSScanFile_0028(void);
+static void TCSScanFile_0029(void);
+static void TCSScanFile_0030(void);
+static void TCSScanFile_0031(void);
+static void TCSScanFile_0032(void);
+static void TCSScanFile_0033(void);
+static void TCSScanFile_0034(void);
+
+static void TestCases(void);
+
+
+extern int TestCasesCount;
+extern int Success;
+extern int Failures;
+
+
+int main(int argc, char **argv)
+{
+
+    TCSStartup();
+    TestCases();
+    TCSCleanup();
+
+    return 0;
+}
+
+
+static void TestCases(void)
+{
+    TCSLibraryOpen_0001();
+    TCSLibraryOpen_0002();
+    TCSLibraryOpen_0003();
+    TCSLibraryOpen_0004();
+
+    TCSGetLastError_0001();
+
+    TCSLibraryClose_0001();
+
+    TCSScanData_0001();
+    TCSScanData_0002();
+    TCSScanData_0003();
+    TCSScanData_0004();
+    TCSScanData_0005();
+    TCSScanData_0006();
+    TCSScanData_0007();
+    TCSScanData_0008();
+    TCSScanData_0009();
+    TCSScanData_0010();
+    TCSScanData_0011();
+    TCSScanData_0012();
+    TCSScanData_0013();
+    TCSScanData_0014();
+    TCSScanData_0015();
+    TCSScanData_0016();
+    TCSScanData_0017();
+    TCSScanData_0018();
+    TCSScanData_0019();
+    TCSScanData_0020();
+    TCSScanData_0021();
+    TCSScanData_0022();
+    TCSScanData_0023();
+    TCSScanData_0024();
+    TCSScanData_0025();
+    TCSScanData_0026();
+    TCSScanData_0027();
+    TCSScanData_0028();
+    TCSScanData_0029();
+    TCSScanData_0030();
+    TCSScanData_0031();
+    TCSScanData_0032();
+    TCSScanData_0033();
+    TCSScanData_0034();
+    TCSScanData_0035();
+    TCSScanData_0036();
+    TCSScanData_0037();
+    TCSScanData_0038();
+    TCSScanData_0039();
+    TCSScanData_0040();
+    TCSScanData_0041();
+    TCSScanData_0042();
+    TCSScanData_0043();
+    TCSScanData_0044();
+    TCSScanData_0045();
+    TCSScanData_0046();
+    TCSScanData_0047();
+    TCSScanData_0048();
+    TCSScanData_0049();
+    TCSScanData_0050();
+    TCSScanData_0051();
+    TCSScanData_0052();
+
+    TCSScanFile_0001();
+    TCSScanFile_0002();
+    TCSScanFile_0003();
+    TCSScanFile_0004();
+    TCSScanFile_0005();
+    TCSScanFile_0006();
+    TCSScanFile_0007();
+    TCSScanFile_0008();
+    TCSScanFile_0009();
+    TCSScanFile_0010();
+    TCSScanFile_0011();
+    TCSScanFile_0012();
+    TCSScanFile_0013();
+    TCSScanFile_0014();
+    TCSScanFile_0015();
+    TCSScanFile_0016();
+    TCSScanFile_0017();
+    TCSScanFile_0018();
+    TCSScanFile_0019();
+    TCSScanFile_0020();
+    TCSScanFile_0021();
+    TCSScanFile_0022();
+    TCSScanFile_0023();
+    TCSScanFile_0024();
+    TCSScanFile_0025();
+    TCSScanFile_0026();
+    TCSScanFile_0027();
+    TCSScanFile_0028();
+    TCSScanFile_0029();
+    TCSScanFile_0030();
+    TCSScanFile_0031();
+    TCSScanFile_0032();
+    TCSScanFile_0033();
+    TCSScanFile_0034();
+}
+
+
+static void TCSLibraryOpen_0001(void)
+{
+    TestCase TestCtx;
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib != INVALID_TCSLIB_HANDLE);
+
+    TESTCASEDTOR(&TestCtx);
+    TCSLibraryClose(hLib);
+}
+
+
+static void TCSLibraryOpen_0002(void)
+{
+    int iErr;
+    TestCase TestCtx;
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+
+    BackupEngine();
+    iErr = system("rm -f /opt/usr/share/sec_plugin/libengine.so");
+    TEST_ASSERT(iErr == 0)
+
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib == INVALID_TCSLIB_HANDLE);
+
+    iErr = TCSGetLastError(hLib);
+    TEST_ASSERT(TCS_ERRMODULE(iErr) == TCS_ERROR_MODULE_GENERIC);
+    TEST_ASSERT(TCS_ERRCODE(iErr) == TCS_ERROR_NOT_IMPLEMENTED);
+    TESTCASEDTOR(&TestCtx);
+
+    RestoreEngine();
+}
+
+
+static void TCSGetLastError_0001(void)
+{
+    int iErr;
+    TestCase TestCtx;
+
+    BackupEngine();
+    iErr = system("rm -f /opt/usr/share/sec_plugin/libengine.so");
+    TEST_ASSERT(iErr == 0)
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    iErr = TCSGetLastError(INVALID_TCSLIB_HANDLE);
+    TEST_ASSERT(TCS_ERRMODULE(iErr) == TCS_ERROR_MODULE_GENERIC);
+    TEST_ASSERT(TCS_ERRCODE(iErr) == TCS_ERROR_NOT_IMPLEMENTED);
+    TESTCASEDTOR(&TestCtx);
+
+    RestoreEngine();
+}
+
+
+static void TCSScanData_0052(void)
+{
+    int iErr;
+    TestCase TestCtx;
+    TCSScanParam SP = {0};
+    TCSScanResult SR= {0};
+
+    BackupEngine();
+    iErr = system("rm -f /opt/usr/share/sec_plugin/libengine.so");
+    TEST_ASSERT(iErr == 0)
+
+    SP.iAction = TCS_SA_SCANONLY;
+    SP.iDataType = TCS_DTYPE_UNKNOWN;
+    SP.iCompressFlag = 1;
+    SP.pPrivate = NULL;
+    SP.pfGetSize = NULL;
+    SP.pfSetSize = NULL;
+    SP.pfRead = NULL;
+    SP.pfWrite = NULL;
+    SP.pfCallBack = NULL;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    TEST_ASSERT(TCSScanData(INVALID_TCSLIB_HANDLE, &SP, &SR) == -1);
+    TESTCASEDTOR(&TestCtx);
+
+    RestoreEngine();
+}
+
+
+static void TCSScanFile_0034(void)
+{
+    TestCase TestCtx;
+    TCSScanResult SR = {0};
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    TEST_ASSERT(TCSScanFile(INVALID_TCSLIB_HANDLE, "file",
+                            TCS_DTYPE_UNKNOWN, TCS_SA_SCANONLY, 1, &SR) == -1);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSLibraryClose_0001(void)
+{
+    TestCase TestCtx;
+    TCSLIB_HANDLE hLib;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib != INVALID_TCSLIB_HANDLE);
+    TEST_ASSERT(TCSLibraryClose(hLib) == 0);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSScanData_0001(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_BUFFER, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0002(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_BUFFER, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0003(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0004(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0005(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_HTML, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0006(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_HTML, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0007(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_HTML, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0008(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_HTML, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0009(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_URL, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0010(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_URL, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0011(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_URL, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0012(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_URL, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0013(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_EMAIL, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0014(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_EMAIL, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0015(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_EMAIL, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0016(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_EMAIL, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0017(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_PHONE, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0018(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_PHONE, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0019(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_PHONE, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0020(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_PHONE, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0021(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVA, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0022(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVA, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0023(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVA, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0024(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVA, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0025(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVAS, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0026(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVAS, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0027(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVAS, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0028(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVAS, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0029(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_TEXT, BENIGN_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0030(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_TEXT, BENIGN_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0031(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_TEXT, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0032(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_TEXT, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0033(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_MULTIPLE, INFECTED_DATA,
+                 TCS_SA_SCANONLY, NULL);
+}
+
+
+static void TCSScanData_0034(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_MULTIPLE, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbScanCallback);
+}
+
+
+static void TCSScanData_0035(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0036(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_HTML, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0037(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_URL, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0038(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_EMAIL, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0039(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_PHONE, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0040(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_JAVA, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0041(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_TEXT, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0042(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_MULTIPLE, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0043(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA,
+                 TCS_SA_SCANONLY, &CbAbortCallback);
+}
+
+
+static void TCSScanData_0044(void)
+{
+
+    TestScanData(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR, &CbScanCallback);
+}
+
+
+static void TCSScanData_0045(void)
+{
+    TestCase TestCtx;
+    TCSScanParam SP = {0};
+    TCSScanResult SR= {0};
+
+    SP.iAction = TCS_SA_SCANONLY;
+    SP.iDataType = TCS_DTYPE_UNKNOWN;
+    SP.iCompressFlag = 1;
+    SP.pPrivate = NULL;
+    SP.pfGetSize = NULL;
+    SP.pfSetSize = NULL;
+    SP.pfRead = NULL;
+    SP.pfWrite = NULL;
+    SP.pfCallBack = NULL;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    TEST_ASSERT(TCSScanData(INVALID_TCSLIB_HANDLE, &SP, &SR) == -1);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSScanData_0046(void)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    ConScanData(&TestCtx, TCS_SA_SCANONLY);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSScanData_0047(void)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    ConScanData(&TestCtx, TCS_SA_SCANREPAIR);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSScanData_0048(void)
+{
+
+    TestScanDataEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, BENIGN_DATA,
+                   TCS_SA_SCANONLY, 1, &CbScanCallback);
+}
+
+
+static void TCSScanData_0049(void)
+{
+
+    TestScanDataEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, BENIGN_DATA,
+                   TCS_SA_SCANONLY, 0, &CbScanCallback);
+}
+
+
+static void TCSScanData_0050(void)
+{
+
+    TestScanDataEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, INFECTED_DATA,
+                   TCS_SA_SCANONLY, 1, &CbScanCallback);
+}
+
+
+static void TCSScanData_0051(void)
+{
+
+    TestScanDataEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, INFECTED_DATA,
+                   TCS_SA_SCANONLY, 0, &CbScanCallback);
+}
+
+
+static void TCSScanFile_0001(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_BUFFER, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0002(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0003(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_HTML, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0004(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_HTML, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0005(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_URL, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0006(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_URL, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0007(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_EMAIL, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0008(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_EMAIL, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0009(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_PHONE, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0010(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_PHONE, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0011(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_JAVA, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0012(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_JAVA, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0013(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_TEXT, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0014(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_TEXT, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0015(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_MULTIPLE, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0016(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0017(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_HTML, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0018(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_URL, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0019(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_EMAIL, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0020(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_PHONE, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0021(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_JAVA, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0022(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_TEXT, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0023(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_MULTIPLE, INFECTED_DATA,
+                 TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0024(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_BUFFER, INFECTED_DATA, TCS_SA_SCANREPAIR);
+}
+
+
+static void TCSScanFile_0025(void)
+{
+    TestCase TestCtx;
+    TCSScanResult SR = {0};
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    TEST_ASSERT(TCSScanFile(INVALID_TCSLIB_HANDLE, "file",
+                            TCS_DTYPE_UNKNOWN, TCS_SA_SCANONLY, 1, &SR) == -1);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSScanFile_0026(void)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    ConScanFile(&TestCtx, TCS_SA_SCANONLY);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSScanFile_0027(void)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    ConScanFile(&TestCtx, TCS_SA_SCANREPAIR);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSScanFile_0028(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_JAVAS, BENIGN_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0029(void)
+{
+
+    TestScanFile(__FUNCTION__, MALWARE_TTYPE_JAVAS, INFECTED_DATA, TCS_SA_SCANONLY);
+}
+
+
+static void TCSScanFile_0030(void)
+{
+
+    TestScanFileEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, BENIGN_DATA, TCS_SA_SCANONLY, 1);
+}
+
+
+static void TCSScanFile_0031(void)
+{
+
+    TestScanFileEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, INFECTED_DATA, TCS_SA_SCANONLY, 1);
+}
+
+
+static void TCSScanFile_0032(void)
+{
+
+    TestScanFileEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, BENIGN_DATA, TCS_SA_SCANONLY, 0);
+}
+
+
+static void TCSScanFile_0033(void)
+{
+
+    TestScanFileEx(__FUNCTION__, MALWARE_TTYPE_COMPRESS, INFECTED_DATA, TCS_SA_SCANONLY, 0);
+}
+
+
+static void TCSStartup(void)
+{
+    extern int TestCasesCount;
+    extern int Success;
+    extern int Failures;
+
+    TestCasesCount = 0;
+    Success = 0;
+    Failures = 0;
+    CreateTestDirs();
+    TEST_ASSERT(DetermineEngineLib() == 0);
+}
+
+
+static void TCSCleanup(void)
+{
+    LOG_OUT("@@@@@@@@@@@@@@@@@@@@@@@@\n");
+    LOG_OUT("Test done: %d executed, %d passed, %d failure\n", TestCasesCount, Success, Failures);
+    DestoryTestDirs();
+}
+
+
+static void TCSLibraryOpen_0003(void)
+{
+    int iErr;
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+    TestCase TestCtx;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+    /* pre-condition is stub library */
+    BackupEngine();
+    iErr = system("rm -f /opt/usr/share/sec_plugin/libengine.so");
+    TEST_ASSERT(iErr == 0);
+
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib == INVALID_TCSLIB_HANDLE);
+    RestoreEngine();
+
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib != INVALID_TCSLIB_HANDLE);
+
+    TCSLibraryClose(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TCSLibraryOpen_0004(void)
+{
+    int iErr;
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+    TestCase TestCtx;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__, 0, 0, 0, NULL);
+
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib != INVALID_TCSLIB_HANDLE);
+
+    BackupEngine();
+    iErr = system("rm -f /opt/usr/share/sec_plugin/libengine.so");
+    TEST_ASSERT(iErr == 0);
+    TCSLibraryClose(hLib);
+
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib == INVALID_TCSLIB_HANDLE);
+    hLib = INVALID_TCSLIB_HANDLE;
+
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
diff --git a/test/TCSTest.h b/test/TCSTest.h
new file mode 100644 (file)
index 0000000..e2fd03e
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef TCSTEST_H
+#define TCSTEST_H
+
+
+#include <setjmp.h>
+
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+#define TEST_SUITE_VERSION "0.0.1"
+
+/* Immediate value definitions. */
+#define MAX_TEST_NUM 128
+
+/* Test content polarities */
+#define BENIGN_DATA 0
+#define INFECTED_DATA 1
+
+/* Maximum CS API name length. */
+#define MAX_TCS_API_NAME_LEN 128
+
+/* Content backup directory before repairing test. */
+#define TCS_BACKUP_CONTENT_DIR "contents_bak"
+
+/* Content directory for testing. */
+#define TCS_TEST_CONTENT_DIR "contents_test"
+
+/* Default maximum number of threads for concurrency test. */
+#define MAX_TEST_THREADS 10
+
+/* Default maximum concurrency test timeout (in seconds). */
+#define DEFAULT_CONCURRENCY_TEST_TIMEOUT 30
+
+/* Sleep interval for thread context switch. */
+#define SLEEP_INTERVAL 500
+
+
+/* Output methods. */
+#define LOG_OUT(fmt, x...) printf("Log:"fmt, ##x)
+
+#define TRY_TEST { \
+    int _ret_ = setjmp(JmpBuf); \
+    if (_ret_ == 1) { \
+        Failures++; \
+    } else { \
+
+#define FAIL_TEST longjmp(JmpBuf, 1);
+
+#define TESTCASECTOR(_ctx_, _api_, _testtype_, _polarity_, _action_, _callback_) \
+        TRY_TEST \
+        TestCaseCtor(_ctx_, _api_, _testtype_, _polarity_, _action_, _callback_);
+
+#define TESTCASECTOREX(_ctx_, _api_, _testtype_, _polarity_, _action_, _flag_, _callback_) \
+        TRY_TEST \
+        TestCaseCtorEx(_ctx_, _api_, _testtype_, _polarity_, _action_, _flag_, _callback_);
+
+#define TESTCASEDTOR(_ctx_) \
+        TestCaseDtor(_ctx_); \
+    } \
+} \
+
+/* Test assert method. */
+#define TEST_ASSERT(cond) if (!(cond)) {LOG_OUT("Test failed!! at : %s, %d\n", __FILE__, __LINE__); FAIL_TEST}
+
+#define ELEMENT_NUM(ary) (sizeof(ary) / sizeof((ary)[0]))
+
+#define TEST_CONSTRUCT_ERRCODE(m, e) (((m) << 24) | (e))
+
+
+/* Test content file types */
+enum ENUM_MALWARE_TEST_TYPES
+{
+    MALWARE_TTYPE_BUFFER = 0,
+    MALWARE_TTYPE_HTML,
+    MALWARE_TTYPE_URL,
+    MALWARE_TTYPE_EMAIL,
+    MALWARE_TTYPE_PHONE,
+    MALWARE_TTYPE_TEXT,
+    MALWARE_TTYPE_JAVA,
+    MALWARE_TTYPE_MULTIPLE,
+    MALWARE_TTYPE_JAVAS,
+    MALWARE_TTYPE_COMPRESS,
+    MALWARE_TTYPE_MAX
+};
+
+typedef int (*PFScan)(void *pPrivate, int nReason, void *pParam);
+
+/**
+ * Test case information data
+ */
+typedef struct TestCase_struct
+{
+    char szAPIName[MAX_TCS_API_NAME_LEN]; /* TCS API names */
+    int iInfected; /* Index of infected malware passed in pfCallback. */
+    int iTestType; /* Sample type. */
+    int iPolarity; /* INFECTED_DATA - Infected, BENIGN_DATA - Benign
+                      otherwise undefined. */
+    int iAction;
+    int iCompressFlag;
+    int iNotImplTestFlag; /* 1 - repair not implemented test flag, otherwise not. */
+    int *pFlags;
+    PFScan pfCallback;
+
+    pthread_mutex_t MutexCon; /* Concurrency test communication stuff. */
+    pthread_cond_t CondCon; /* Concurrency test communication stuff. */
+} TestCase;
+
+/**
+ * Concurrency test data
+ */
+typedef struct ConTestContext_struct
+{
+    TestCase *pTestCtx;
+    int iCid; /* Concurrency test id. */
+
+    /* Report concurrency test status. 1 - success, -1 - failure, 0 - running. */
+    int iConTestRet;
+} ConTestContext;
+
+
+/*
+ * Very simple/thin porting layer
+ *
+ * Test malware informations. Malware names to be tested should be
+ * prepared in compiling time. Please see the porting guide for test
+ * suite.
+ */
+extern const char *SampleGetMalName(int iType, int iIndex);
+extern const char *SampleGetVarName(int iType, int iIndex);
+extern const char *SampleGetBenignFileName(int iType);
+extern const char *SampleGetInfectedFileName(int iType);
+extern unsigned int SampleGetSeverity(int iType, int iIndex);
+extern unsigned int SampleGetBehavior(int iType, int iIndex);
+extern unsigned int SampleGetMalType(int iType, int iIndex);
+extern int SampleGetCount(int iType);
+
+/* Test framework */
+extern int CbScanCallback(void *pPrivate, int nReason, void *pParam);
+extern int CbAbortCallback(void *pPrivate, int nReason, void *pParam);
+extern void TestCaseCtor(TestCase *pCtx, const char *pszAPI, int iTestType,
+                         int iPolarity, int iAction, PFScan pfCallback);
+extern void TestCaseDtor(TestCase *pCtx);
+extern void TestScanFile(const char *pszFunc, int iTType, int iPolarity,
+                         int iAction);
+extern void TestScanData(const char *pszFunc, int iTType, int iPolarity,
+                         int iAction, PFScan pfCallback);
+extern void TestScanFileEx(const char *pszFunc, int iTType, int iPolarity,
+                           int iAction, int iCompressFlag);
+extern void TestScanDataEx(const char *pszFunc, int iTType, int iPolarity,
+                           int iAction, int iCompressFlag, PFScan pfCallback);
+extern void ConScanFile(TestCase *pCtx, int iAction);
+extern void ConScanData(TestCase *pCtx, int iAction);
+extern int DetectRepairFunc(void);
+extern int CreateTestDirs(void);
+extern void DestoryTestDirs(void);
+extern int DetectStubLibrary(void);
+extern int IsStubTest(void);
+extern int IsTestRepair(void);
+extern void RestoreEngine(void);
+extern void BackupEngine(void);
+extern int DetermineEngineLib(void);
+
+extern jmp_buf JmpBuf;
+
+#ifdef __cplusplus 
+}
+#endif
+
+#endif /* TCSTEST_H */
diff --git a/test/TCSTestUtils.c b/test/TCSTestUtils.c
new file mode 100644 (file)
index 0000000..3049518
--- /dev/null
@@ -0,0 +1,2128 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "TCSErrorCodes.h"
+#include "TCSImpl.h"
+#include "TCSTest.h"
+
+/* Concurrency test macros. */
+#define CONTEST_START \
+{\
+    int iTestRet = 1;
+
+#define CONTEST_ERROR \
+    CONTEST_ASSERT(0)
+
+#define CONTEST_ASSERT(condition) \
+if (!(condition)) \
+{ \
+    LOG_OUT("test failed: %s,%d\n", __FILE__, __LINE__); \
+    iTestRet = -1; \
+}
+
+#define CONTEST_RETURN(ret) \
+    ret = iTestRet; \
+}
+
+#define CONTEST_RELEASE(con_test_ctx) \
+    ReleaseTestObject(con_test_ctx, iTestRet);\
+}
+
+#define TCS_ACTION_CLASS(a) ((a) & 0xff)
+#define TCS_ACTION_BEHAVIOR(a) (((a) >> 8) & 0xff)
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define CONTENTS_ROOT "contents"
+#define CONTENTS_TMP "tmp"
+
+#define TCS_SECLIB_DEFAULT "/opt/usr/apps/EmbkcJFK7q/lib/plugin/libengine.so"
+#define TCS_SECLIB_DCM "/opt/usr/apps/docomo6004/lib/plugin/libengine.so"
+
+
+/**
+ * Scan context
+ */
+typedef struct ScanContext_struct
+{
+    /* Test status */
+    TestCase *pCurrentTestCase;
+    char *pData;
+    unsigned int uSize;
+} ScanContext;
+
+
+/**
+ * Concurrency Scan context
+ */
+typedef struct ConScanContext_struct
+{
+    /* Test status */
+    int iTestType;
+    int iInfected;
+    int iPolarity;
+    int iTestRet;
+    int *pFlags;
+    char *pData;
+    unsigned int uSize;
+} ConScanContext;
+
+
+pthread_mutex_t g_Mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t g_Cond = PTHREAD_COND_INITIALIZER;
+
+
+static int ScanBufferProc(TestCase *pCtx, char *pData, int iDataLen);
+static int SaveTestContents(void);
+static int LoadTestContents(void);
+static char *GetBackupDir(void);
+static void PutBackupDir(char *pszBackupDir);
+static char *GetSamplePath(TestCase *pCtx);
+static void PutSamplePath(char *pszSamplePath);
+static int GetSampleDataType(int iTType);
+static char *LoadFile(char const *pszFileName, int *piSize);
+static void PutLoadedFile(char *pData);
+static void ReportTestCase(TestCase *pCtx);
+static TCSOffset CbScanGetSize(void *pPrivate);
+static unsigned int CbScanRead(void *pPrivate, TCSOffset uOffset,
+                               void *pBuffer, unsigned int uSize);
+static unsigned int CbScanWrite(void *pPrivate, TCSOffset uOffset,
+                                void const *pBuffer, unsigned int uSize);
+static int CbScanSetSize(void *pPrivate, TCSOffset uSize);
+static void CheckDetected(TestCase *pCtx, TCSDetected *pFound);
+static void CheckDetectedList(TestCase *pCtx, TCSScanResult *pSR);
+static int ScanBuffer(TestCase *pCtx);
+static int ScanFile(TestCase *pCtx);
+static char *GetTestRoot(void);
+static void PutTestRoot(char *pszRoot);
+static int VerifyRepairData(TestCase *pCtx, char *pRepairedBuffer,
+                            int iRepairedLen);
+static int VerifyRepairFile(TestCase *pCtx);
+static void PutBenignSamplePath(char *pszPath);
+static char *GetBenignSamplePath(int iTType);
+static int Infected(TestCase *pCtx, char *pData, int iDataLen);
+static int InfectedFile(TestCase *pCtx, const char *pszPath);
+static void TestCaseCtorEx(TestCase *pCtx, const char *pszAPI, int iTestType,
+                           int iPolarity, int iAction, int iCompressFlag,
+                           PFScan pfCallback);
+static void CallSys(const char *pszCmd);
+
+/* Concurrency test functions. */
+static char *ConGetSampleDir(int iCid);
+static void ConPutSampleDir(char *pszDir);
+static void ConCreateSampleDirs(void);
+static void ConDestorySampleDirs(void);
+static char *ConGetSamplePath(int iTType, int iPolarity, int iCid);
+static void ConPutSamplePath(char *pszSamplePath);
+static void ConTestCaseCtor(ConTestContext *pConCtx, int iCid, TestCase *pCtx);
+static void ConTestCaseDtor(ConTestContext *pConCtx);
+
+static int ConWaitOnTestCond(ConTestContext *pConCtxAry);
+static void ReleaseTestObject(ConTestContext *pConCtx, int iResult);
+
+static int ConCheckDetected(int iTType, TCSDetected *pFound, int *pFlags);
+static int ConCheckDetectedList(int iTType, TCSScanResult *pSR, int *pFlags);
+static int ConVerifyRepairData(int iTType, int iCompressFlag, char *pRepairedBuffer,
+                               int iRepairedLen);
+static int ConVerifyRepairFile(char *pszSamplePath, int iTType, int iCompressFlag);
+
+static TCSOffset ConCbScanGetSize(void *pPrivate);
+static unsigned int ConCbScanRead(void *pPrivate, TCSOffset uOffset,
+                                  void *pBuffer, unsigned int uSize);
+static unsigned int ConCbScanWrite(void *pPrivate, TCSOffset uOffset,
+                                void const *pBuffer, unsigned int uSize);
+static int ConCbScanSetSize(void *pPrivate, TCSOffset uSize);
+static int ConCbScanCallback(void *pPrivate, int nReason, void *pParam);
+static void ConScanDataProc(ConTestContext *pConCtx, int iAction);
+static void *ConScanDataSCProc(void *pConCtxParam);
+static void *ConScanDataSRProc(void *pConCtxParam);
+
+static int ConTestSuccess(ConTestContext *pConCtxAry);
+static int ConTestComplete(ConTestContext *pConCtxAry);
+
+static void ConScanFileProc(ConTestContext *pConCtx, int iAction);
+static void *ConScanFileSCProc(void *pConCtxParam);
+static void *ConScanFileSRProc(void *pConCtxParam);
+static int ConInfectedFile(int iType, int iCompressFlag, const char *pszPath);
+static int ConInfected(int iType, int iCompressFlag, char *pData, int iDataLen);
+
+
+
+const char *pszSecLibPath = TCS_SECLIB_DEFAULT;
+int TestCasesCount = 0;
+int Success = 0;
+int Failures = 0;
+jmp_buf JmpBuf; 
+
+
+static char *LoadFile(char const *pszFileName, int *piSize)
+{
+    FILE *pFile = NULL;
+    char *pData = NULL;
+
+    if ((pFile = fopen(pszFileName, "rb")) == NULL)
+        return NULL;
+
+    fseek(pFile, 0, SEEK_END);
+    *piSize = (long) ftell(pFile);
+
+    if (*piSize < 0)
+    {
+        fclose(pFile);
+        return NULL;
+    }
+
+    fseek(pFile, 0, SEEK_SET);
+    pData = (char *) malloc(*piSize + 1);
+    if (pData == NULL)
+    {
+        fclose(pFile);
+        return NULL;
+    }
+
+    if (fread(pData, 1, (size_t) *piSize, pFile) != *piSize)
+    {
+        free(pData);
+        fclose(pFile);
+        return NULL;
+    }
+    fclose(pFile);
+    pData[*piSize] = '\0';
+
+    return pData;
+}
+
+
+static void PutLoadedFile(char *pData)
+{
+
+    if (pData != NULL)
+        free(pData);
+}
+
+
+/**
+ * Output for test case result.
+ */
+static void ReportTestCase(TestCase *pCtx)
+{
+    char *pszTmp;
+
+    LOG_OUT("@@@@@@@@@@@@@@@@@@@@@@@@\n");
+
+    LOG_OUT("@ID: TC_SEC_CS_%s\n", pCtx->szAPIName);
+    pszTmp = strchr(pCtx->szAPIName, '_');
+    *pszTmp = 0;
+    LOG_OUT("@API Name: %s\n", pCtx->szAPIName);
+    *pszTmp = '_';
+
+    TestCasesCount++;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static TCSOffset CbScanGetSize(void *pPrivate)
+{
+    ScanContext *pCtx = (ScanContext *) pPrivate;
+
+    return pCtx->uSize;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static unsigned int CbScanRead(void *pPrivate, TCSOffset uOffset,
+                               void *pBuffer, unsigned int uSize)
+{
+    unsigned int uRead = 0;
+    ScanContext *pCtx = (ScanContext *) pPrivate;
+
+    if (uOffset < pCtx->uSize)
+    {
+        if ((uRead = pCtx->uSize - uOffset) > uSize)
+            uRead = uSize;
+    }
+    if (uRead)
+        memcpy(pBuffer, pCtx->pData + uOffset, uRead);
+
+    return uRead;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static unsigned int CbScanWrite(void *pPrivate, TCSOffset uOffset,
+                                void const *pBuffer, unsigned int uSize)
+{
+    unsigned int uWrite = 0;
+    ScanContext *pCtx = (ScanContext *) pPrivate;
+
+    if (uOffset < pCtx->uSize)
+    {
+        if ((uWrite = pCtx->uSize - uOffset) > uSize)
+            uWrite = uSize;
+    }
+    if (uWrite)
+        memcpy(pCtx->pData + uOffset, pBuffer, uWrite);
+
+    return uWrite;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static int CbScanSetSize(void *pPrivate, TCSOffset uSize)
+{
+
+    return 0;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+int CbScanCallback(void *pPrivate, int nReason, void *pParam)
+{
+    ScanContext *pCtx = (ScanContext *) pPrivate;
+    const char *pszMalName = NULL, *pszVarName = NULL;
+    int i, iTType = pCtx->pCurrentTestCase->iTestType;
+    int n = SampleGetCount(iTType);
+
+    /*
+     * Fix this is important since pParam could be different
+     * if the nReason is not DETECTED.
+     */
+    if (nReason != TCS_CB_DETECTED)
+        return 0;
+    TEST_ASSERT(nReason == TCS_CB_DETECTED);
+    TEST_ASSERT(pCtx->pCurrentTestCase->iPolarity == INFECTED_DATA);
+
+    pCtx->pCurrentTestCase->iInfected++;
+
+    for (i = 0; i < n; i++)
+    {
+        if (pCtx->pCurrentTestCase->pFlags[i])
+            continue;
+
+        pszMalName = SampleGetMalName(iTType, i);
+        if (pszMalName != NULL)
+        {
+            TEST_ASSERT(((TCSDetected *) pParam)->pszName != NULL);
+            if (((TCSDetected *) pParam)->pszName == NULL ||
+                strcmp(((TCSDetected *) pParam)->pszName, pszMalName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        pszVarName = SampleGetVarName(iTType, i);
+        if (pszVarName != NULL)
+        {
+            TEST_ASSERT(((TCSDetected *) pParam)->pszVariant != NULL);
+            if (((TCSDetected *) pParam)->pszVariant == NULL ||
+                strcmp(((TCSDetected *) pParam)->pszVariant, pszVarName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        TEST_ASSERT(TCS_ACTION_CLASS(((TCSDetected *) pParam)->uAction) ==
+                    SampleGetSeverity(iTType, i));
+
+        TEST_ASSERT(TCS_ACTION_BEHAVIOR(((TCSDetected *) pParam)->uAction) ==
+                    SampleGetBehavior(iTType, i));
+
+        pCtx->pCurrentTestCase->pFlags[i] = 1;
+        break;
+    }
+
+    TEST_ASSERT(i != n);
+
+    return 0;
+}
+
+
+/**
+ * The difference between ScanFile and ScanBuffer is:
+ * ScanBuffer is the helper function to test scan data.
+ */
+static int ScanBuffer(TestCase *pCtx)
+{
+    int iFSize;
+    char *pData, *pszFilePath;
+
+    if ((pszFilePath = GetSamplePath(pCtx)) == NULL)
+        return -1;
+
+    if ((pData = LoadFile(pszFilePath, &iFSize)) == NULL)
+    {
+        PutSamplePath(pszFilePath);
+        return -1;
+    }
+
+    TEST_ASSERT(ScanBufferProc(pCtx, pData, iFSize) == 0);
+    PutLoadedFile(pData);
+    PutSamplePath(pszFilePath);
+
+    return 0;
+}
+
+
+/**
+ * Scan file test helper function.
+ */
+static int ScanFile(TestCase *pCtx)
+{
+    int iErr, iExpected = SampleGetCount(pCtx->iTestType);
+    TCSScanResult SR;
+    TCSLIB_HANDLE hLib;
+    char *pszFilePath;
+
+    if ((pszFilePath = GetSamplePath(pCtx)) == NULL)
+        return -1;
+
+    hLib = TCSLibraryOpen();
+    if (hLib == INVALID_TCSLIB_HANDLE)
+    {
+        PutSamplePath(pszFilePath);
+        return -1;
+    }
+
+    if (iExpected > 0)
+    {
+        pCtx->pFlags = (int *) calloc(iExpected, sizeof(int));
+        if (pCtx->pFlags == NULL)
+            TEST_ASSERT(0);
+    }
+    else
+        pCtx->pFlags = NULL;
+
+    if (pCtx->iAction == TCS_SA_SCANREPAIR && IsTestRepair() == 0)
+    {
+        TEST_ASSERT(TCSScanFile(hLib, pszFilePath,
+                                GetSampleDataType(pCtx->iTestType),
+                                pCtx->iAction, pCtx->iCompressFlag, &SR) == -1);
+        iErr = TCSGetLastError(hLib);
+        TEST_ASSERT(TCS_ERRMODULE(iErr) == TCS_ERROR_MODULE_GENERIC);
+        TEST_ASSERT(TCS_ERRCODE(iErr) == TCS_ERROR_NOT_IMPLEMENTED);
+    }
+    else
+    {
+        TEST_ASSERT(TCSScanFile(hLib, pszFilePath,
+                                GetSampleDataType(pCtx->iTestType),
+                                pCtx->iAction, pCtx->iCompressFlag, &SR) == 0);
+        if (pCtx->pFlags)
+            memset(pCtx->pFlags, 0, sizeof(int) * iExpected);
+
+
+        if (pCtx->iAction == TCS_SA_SCANONLY)
+        {
+            if (pCtx->iPolarity == INFECTED_DATA)
+            {
+                if (pCtx->iTestType == MALWARE_TTYPE_COMPRESS &&
+                    pCtx->iCompressFlag == 0)
+                /* Not suppose to detect when compress flag is
+                 * set to 0 for compressed samples. */
+                {
+                    TEST_ASSERT(SR.iNumDetected == 0);
+                }
+                else
+                {
+                    TEST_ASSERT(SR.iNumDetected == SampleGetCount(pCtx->iTestType));
+                    if (SR.iNumDetected == SampleGetCount(pCtx->iTestType))
+                        CheckDetectedList(pCtx, &SR);
+                }
+            }
+            else
+            {
+                TEST_ASSERT(SR.iNumDetected == 0);
+            }
+        }
+        else
+        {
+            /* Verify */
+            TEST_ASSERT(VerifyRepairFile(pCtx) == 0);
+        }
+        if (*SR.pfFreeResult != NULL)
+            (*SR.pfFreeResult)(&SR);
+    }
+
+    if (pCtx->pFlags)
+        free(pCtx->pFlags);
+
+    TCSLibraryClose(hLib);
+    PutSamplePath(pszFilePath);
+
+    return 0;
+}
+
+
+/**
+ * Helper function for detected one malware.
+ */
+static void CheckDetected(TestCase *pCtx, TCSDetected *pFound)
+{
+    const char *pszMalName = NULL, *pszVarName = NULL;
+    int i, iTType = pCtx->iTestType, n = SampleGetCount(iTType);
+
+    for (i = 0; i < n; i++)
+    {
+        if (pCtx->pFlags[i])
+            continue;
+
+        pszMalName = SampleGetMalName(iTType, i);
+        if (pszMalName != NULL)
+        {
+            TEST_ASSERT(pFound->pszName != NULL);
+            if (pFound->pszName == NULL ||
+                strcmp(pFound->pszName, pszMalName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        pszVarName = SampleGetVarName(iTType, i);
+        if (pszVarName != NULL)
+        {
+            TEST_ASSERT(pFound->pszVariant != NULL);
+            if (pFound->pszVariant == NULL ||
+                strcmp(pFound->pszVariant, pszVarName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        TEST_ASSERT(TCS_ACTION_CLASS(pFound->uAction) ==
+                    SampleGetSeverity(iTType, i));
+
+        TEST_ASSERT(TCS_ACTION_BEHAVIOR(pFound->uAction) ==
+                    SampleGetBehavior(iTType, i));
+
+        pCtx->pFlags[i] = 1;
+        break;
+    }
+
+    TEST_ASSERT(i != n);
+}
+
+
+/**
+ * Helper function for detected malware list checking.
+ */
+static void CheckDetectedList(TestCase *pCtx, TCSScanResult *pSR)
+{
+    TCSDetected *pFound = pSR->pDList;
+
+    while (pFound != NULL)
+    {
+        CheckDetected(pCtx, pFound);
+        pFound = pFound->pNext;
+    }
+}
+
+
+/**
+ * Helper function for data scan, see ScanBuffer()
+ */
+static int ScanBufferProc(TestCase *pCtx, char *pData, int iDataLen)
+{
+    TCSLIB_HANDLE hLib;
+    TCSScanParam SP = {0};
+    TCSScanResult SR = {0};
+    ScanContext ScanCtx = {0};
+    int iErr, iExpected = SampleGetCount(pCtx->iTestType);
+
+    hLib = TCSLibraryOpen();
+    if (hLib == INVALID_TCSLIB_HANDLE)
+        return -1;
+
+    ScanCtx.pData = pData;
+    ScanCtx.uSize = (unsigned int) iDataLen;
+    ScanCtx.pCurrentTestCase = pCtx;
+
+    if (iExpected > 0)
+    {
+        pCtx->pFlags = (int *) calloc(iExpected, sizeof(int));
+        if (pCtx->pFlags == NULL)
+            TEST_ASSERT(0);
+    }
+    else
+        pCtx->pFlags = NULL;
+
+    SP.iAction = pCtx->iAction;
+    SP.iDataType = GetSampleDataType(pCtx->iTestType);
+    SP.iCompressFlag = pCtx->iCompressFlag;
+    SP.pPrivate = &ScanCtx;
+    SP.pfGetSize = CbScanGetSize;
+    SP.pfSetSize = CbScanSetSize;
+    SP.pfRead = CbScanRead;
+    SP.pfWrite = CbScanWrite;
+    SP.pfCallBack = pCtx->pfCallback;
+
+    if (pCtx->pfCallback == &CbAbortCallback)
+    {
+        TEST_ASSERT(TCSScanData(hLib, &SP, &SR) == -1);
+        iErr = TCSGetLastError(hLib);
+    }
+    else if (pCtx->iAction == TCS_SA_SCANREPAIR && IsTestRepair() == 0)
+    {
+        TEST_ASSERT(TCSScanData(hLib, &SP, &SR) == -1);
+        iErr = TCSGetLastError(hLib);
+        TEST_ASSERT(TCS_ERRMODULE(iErr) == TCS_ERROR_MODULE_GENERIC);
+        TEST_ASSERT(TCS_ERRCODE(iErr) == TCS_ERROR_NOT_IMPLEMENTED);
+    }
+    else
+    {
+        TEST_ASSERT(TCSScanData(hLib, &SP, &SR) == 0);
+        if (pCtx->pFlags)
+            memset(pCtx->pFlags, 0, sizeof(int) * iExpected);
+
+        /* Make sure pfCallback is called as expected. */
+        if (pCtx->pfCallback == &CbScanCallback &&
+            pCtx->iAction == TCS_SA_SCANONLY &&
+            pCtx->iPolarity == INFECTED_DATA)
+        {
+            if (pCtx->iTestType == MALWARE_TTYPE_COMPRESS &&
+                pCtx->iCompressFlag == 0)
+            /* Not suppose to detect virus when compress flag is
+             * disabled for compress test sample */
+            {
+                TEST_ASSERT(SR.iNumDetected == 0);
+            }
+            else
+            {
+                TEST_ASSERT(pCtx->iInfected == iExpected);
+            }
+        }
+
+        if (pCtx->iAction == TCS_SA_SCANONLY)
+        {
+            if (pCtx->iPolarity == INFECTED_DATA)
+            {
+                if (pCtx->iTestType == MALWARE_TTYPE_COMPRESS &&
+                    pCtx->iCompressFlag == 0)
+                /* Not suppose to detect virus when compress flag is
+                 * disabled for compress test sample */
+                {
+                    TEST_ASSERT(SR.iNumDetected == 0);
+                }
+                else
+                {
+                    TEST_ASSERT(SR.iNumDetected == iExpected);
+                    if (SR.iNumDetected == iExpected)
+                        CheckDetectedList(pCtx, &SR);
+                }
+            }
+            else
+            {
+                TEST_ASSERT(SR.iNumDetected == 0);
+            }
+        }
+        else
+        {
+            TEST_ASSERT(VerifyRepairData(pCtx, ScanCtx.pData,
+                                         ScanCtx.uSize) == 0);
+        }
+
+        if (*SR.pfFreeResult)
+            (*SR.pfFreeResult)(&SR);
+    }
+
+    if (pCtx->pFlags)
+        free(pCtx->pFlags);
+
+    TCSLibraryClose(hLib);
+
+    return 0;
+}
+
+
+/**
+ * Abort test callback helper function for data scan.
+ */
+int CbAbortCallback(void *pPrivate, int nReason, void *pParam)
+{
+
+    return -1;
+}
+
+
+int CreateTestDirs(void)
+{
+    int iLen, iRet = -1;
+    char *pszCommand, *pszRoot = GetTestRoot(), *pszEnv, *pszBackup;
+
+    if (pszRoot != NULL)
+    {
+        pszBackup = GetBackupDir();
+        if (pszBackup != NULL)
+        {
+            iLen = MAX(strlen(pszRoot) * 2, strlen(pszBackup));
+            iLen += 64; /* Reserved for "mkdir -p", "cp -f " */
+            pszCommand = (char *) calloc(iLen + 1, sizeof(char));
+            if (pszCommand != NULL)
+            {
+                snprintf(pszCommand, iLen, "mkdir -p %s", pszRoot);
+                CallSys(pszCommand);
+                pszCommand[0] = 0;
+
+                snprintf(pszCommand, iLen, "mkdir -p %s", pszBackup);
+                CallSys(pszCommand);
+                pszCommand[0] = 0;
+
+                pszEnv = getenv("TCS_CONTENT_PATH");
+                if (pszEnv == NULL)
+                    pszEnv = "./";
+                if (pszEnv[strlen(pszEnv) - 1] == '/')
+                    snprintf(pszCommand, iLen, "cp -f %s* %s", pszEnv, pszRoot);
+                else
+                    snprintf(pszCommand, iLen, "cp -f %s/* %s", pszEnv, pszRoot);
+                CallSys(pszCommand);
+
+                free(pszCommand);
+
+                iRet = 0;
+            }
+            PutBackupDir(pszBackup);
+        }
+        PutTestRoot(pszRoot);
+    }
+
+    return iRet;
+}
+
+
+void DestoryTestDirs(void)
+{
+    int iLen, iEnvLen;
+    char *pszCommand, *pszEnv = getenv("TCS_CONTENT_PATH");
+
+    if (pszEnv == NULL || strlen(pszEnv) == 0)
+        pszEnv = "./";
+    iEnvLen = strlen(pszEnv);
+    iLen = iEnvLen;
+    iLen += 72; /* Reserved for "rm -rf" and PID */
+    pszCommand = (char *) calloc(iLen + 1, sizeof(char));
+    if (pszCommand != NULL)
+    {
+        if (pszEnv[iEnvLen - 1] == '/')
+            snprintf(pszCommand, iLen, "rm -rf %s%d", pszEnv, (int) getpid());
+        else
+            snprintf(pszCommand, iLen, "rm -rf %s/%d", pszEnv, (int) getpid());
+        CallSys(pszCommand);
+        free(pszCommand);
+    }
+}
+
+
+/**
+ * Test framework helper function: get content files' root path.
+ */
+static char *GetTestRoot(void)
+{
+    int iLen, iEnvLen;
+    char *pszRoot = NULL, *pszEnv = getenv("TCS_CONTENT_PATH");
+
+    if (pszEnv != NULL &&
+        (iEnvLen = strlen(pszEnv)) > 0)
+    {
+        iLen = iEnvLen;
+        iLen += 64; /* Reserved 64 bytes for PID. */
+        iLen += strlen(TCS_TEST_CONTENT_DIR);
+        pszRoot = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszRoot != NULL)
+        {
+            if (pszEnv[iEnvLen - 1] != '/')
+                snprintf(pszRoot, iLen, "%s/%d/%s", pszEnv, (int) getpid(),
+                         TCS_TEST_CONTENT_DIR);
+            else
+                snprintf(pszRoot, iLen, "%s%d/%s", pszEnv, (int) getpid(),
+                         TCS_TEST_CONTENT_DIR);
+        }
+    }
+    else
+    {
+        iLen = sizeof("./") + 64; /* Reserved 64 bytes for PID. */
+        pszRoot = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszRoot != NULL)
+        {
+            snprintf(pszRoot, iLen, "./%d", (int) getpid());
+        }
+    }
+
+    return pszRoot;
+}
+
+
+static void PutTestRoot(char *pszRoot)
+{
+
+    if (pszRoot != NULL)
+        free(pszRoot);
+}
+
+
+void TestCaseCtor(TestCase *pCtx, const char *pszAPI, int iTestType,
+                  int iPolarity, int iAction, PFScan pfCallback)
+{
+
+    TestCaseCtorEx(pCtx, pszAPI, iTestType, iPolarity, iAction, 1, pfCallback);
+}
+
+
+/**
+ * Test case constructor.
+ */
+static void TestCaseCtorEx(TestCase *pCtx, const char *pszAPI, int iTestType,
+                           int iPolarity, int iAction, int iCompressFlag,
+                           PFScan pfCallback)
+{
+
+    strncpy(pCtx->szAPIName, pszAPI, sizeof(pCtx->szAPIName) - 1);
+    pCtx->iInfected = 0;
+    pCtx->iTestType = iTestType;
+    pCtx->iPolarity = iPolarity;
+    pCtx->iAction = iAction;
+    pCtx->iCompressFlag = iCompressFlag;
+    pCtx->pfCallback = pfCallback;
+    pCtx->pFlags = NULL;
+    TEST_ASSERT(SaveTestContents() == 0);
+}
+
+
+/**
+ * Test case destructor.
+ */
+void TestCaseDtor(TestCase *pCtx)
+{
+
+    ReportTestCase(pCtx);
+    TEST_ASSERT(LoadTestContents() == 0);
+    Success++;
+}
+
+
+static char *GetBackupDir(void)
+{
+    int iLen, iEnvLen;
+    char *pszEnv = getenv("TCS_CONTENT_PATH"), *pszPath;
+
+    if (pszEnv == NULL || strlen(pszEnv) == 0)
+        pszEnv = "./";
+    iEnvLen = strlen(pszEnv);
+    iLen = iEnvLen;
+    iLen += strlen(TCS_BACKUP_CONTENT_DIR);
+    iLen += 64; /* Reserved for slash char and PID. */
+    pszPath = (char *) calloc(iLen + 1, sizeof(char));
+
+    if (pszPath)
+    {
+        if (pszEnv[iEnvLen - 1] == '/')
+            snprintf(pszPath, iLen, "%s%d/%s", pszEnv, (int) getpid(),
+                     TCS_BACKUP_CONTENT_DIR);
+        else
+            snprintf(pszPath, iLen, "%s/%d/%s", pszEnv, (int) getpid(),
+                     TCS_BACKUP_CONTENT_DIR);
+    }
+
+    return pszPath;
+}
+
+
+static void PutBackupDir(char *pszBackupDir)
+{
+
+    if (pszBackupDir != NULL)
+        free(pszBackupDir);
+}
+
+
+static int SaveTestContents(void)
+{
+    int iLen = 0, iRet = -1;
+    char *pszRoot = NULL, *pszCommand = NULL, *pszBackupDir = GetBackupDir();
+
+    if (pszBackupDir != NULL)
+    {
+        pszRoot = GetTestRoot();
+        if (pszRoot != NULL)
+        {
+            iLen = strlen(pszBackupDir);
+            iLen += strlen(pszRoot);
+            iLen += 32; /* Reserved for unix commmand. */
+
+            pszCommand = (char *) calloc(iLen, sizeof(char));
+            if (pszCommand != NULL)
+            {
+                snprintf(pszCommand, iLen - sizeof(char), "cp -f %s/* %s/",
+                         pszRoot, pszBackupDir);
+
+                CallSys(pszCommand);
+                free(pszCommand);
+                iRet = 0;
+            }
+
+            PutTestRoot(pszRoot);
+        }
+
+        PutBackupDir(pszBackupDir);
+    }
+
+    return iRet;
+}
+
+
+static int LoadTestContents(void)
+{
+    int iLen = 0, iRet = -1;
+    char *pszRoot = NULL, *pszCommand = NULL, *pszBackupDir = GetBackupDir();
+
+    if (pszBackupDir != NULL)
+    {
+        pszRoot = GetTestRoot();
+        if (pszRoot != NULL)
+        {
+            iLen = strlen(pszBackupDir);
+            iLen += strlen(pszRoot);
+            iLen += 32; /* Reserved for unix command. */
+
+            pszCommand = (char *) calloc(iLen, sizeof(char));
+            if (pszCommand != NULL)
+            {
+                snprintf(pszCommand, iLen - sizeof(char), "cp -f %s/* %s/",
+                         pszBackupDir, pszRoot);
+
+                CallSys(pszCommand);
+                free(pszCommand);
+                iRet = 0;
+            }
+            PutTestRoot(pszRoot);
+        }
+
+        PutBackupDir(pszBackupDir);
+    }
+
+    return iRet;
+}
+
+
+static char *GetSamplePath(TestCase *pCtx)
+{
+    const char *pszSampleFileName;
+    char *pszSamplePath = NULL, *pszRoot = NULL;
+    int iLen, iTType = pCtx->iTestType, iPolarity = pCtx->iPolarity;
+    char *pwd = getenv("PWD");
+
+    if (pwd == NULL)
+        return NULL;
+
+    pszRoot = GetTestRoot();
+
+    if (pszRoot != NULL)
+    {
+        pszSampleFileName = (iPolarity == INFECTED_DATA ?
+                             SampleGetInfectedFileName(iTType) :
+                             SampleGetBenignFileName(iTType));
+
+        iLen = strlen(pszRoot);
+        iLen += strlen(pszSampleFileName);
+        iLen++; /* Reserved for slash char. */
+        iLen += strlen(pwd) + 3;
+
+        pszSamplePath = (char *) calloc(iLen + 1, sizeof(char));
+
+        if (pszSamplePath != NULL)
+        {
+            if (pszRoot[strlen(pszRoot) - 1] == '/')
+                snprintf(pszSamplePath, iLen, "%s/%s%s", pwd, pszRoot, pszSampleFileName);
+            else
+                snprintf(pszSamplePath, iLen, "%s/%s/%s", pwd, pszRoot, pszSampleFileName);
+        }
+
+        PutTestRoot(pszRoot);
+    }
+
+    return pszSamplePath;
+}
+
+
+static void PutSamplePath(char *pszSamplePath)
+{
+
+    if (pszSamplePath != NULL)
+        free(pszSamplePath);
+}
+
+
+static int GetSampleDataType(int iTType)
+{
+    switch (iTType)
+    {
+    case MALWARE_TTYPE_BUFFER:
+        return TCS_DTYPE_UNKNOWN;
+    case MALWARE_TTYPE_HTML:
+        return TCS_DTYPE_HTML;
+    case MALWARE_TTYPE_URL:
+        return TCS_DTYPE_URL;
+    case MALWARE_TTYPE_EMAIL:
+        return TCS_DTYPE_EMAIL;
+    case MALWARE_TTYPE_PHONE:
+        return TCS_DTYPE_PHONE;
+    case MALWARE_TTYPE_TEXT:
+        return TCS_DTYPE_TEXT;
+    case MALWARE_TTYPE_JAVA:
+        return TCS_DTYPE_JAVA;
+    case MALWARE_TTYPE_JAVAS:
+        return TCS_DTYPE_JAVAS;
+    case MALWARE_TTYPE_MULTIPLE:
+        return TCS_DTYPE_UNKNOWN;
+    case MALWARE_TTYPE_COMPRESS:
+        return TCS_DTYPE_UNKNOWN;
+    default:
+        return 0; /* Unlikely be here. */
+    }
+}
+
+
+void TestScanData(const char *pszFunc, int iTType, int iPolarity,
+                  int iAction, PFScan pfCallback)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOREX(&TestCtx, pszFunc, iTType, iPolarity, iAction, 1, pfCallback);
+    ScanBuffer(&TestCtx);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+void TestScanFile(const char *pszFunc, int iTType, int iPolarity, int iAction)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOREX(&TestCtx, pszFunc, iTType, iPolarity, iAction, 1, NULL);
+    TEST_ASSERT(ScanFile(&TestCtx) == 0);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+void TestScanDataEx(const char *pszFunc, int iTType, int iPolarity,
+                    int iAction, int iCompressFlag, PFScan pfCallback)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOREX(&TestCtx, pszFunc, iTType, iPolarity, iAction,
+                   iCompressFlag, pfCallback);
+    TEST_ASSERT(ScanBuffer(&TestCtx) == 0);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+void TestScanFileEx(const char *pszFunc, int iTType, int iPolarity,
+                    int iAction, int iCompressFlag)
+{
+    TestCase TestCtx;
+
+    TESTCASECTOREX(&TestCtx, pszFunc, iTType, iPolarity,
+                   iAction, iCompressFlag, NULL);
+    TEST_ASSERT(ScanFile(&TestCtx) == 0);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static int ConInfectedFile(int iType, int iCompressFlag, const char *pszPath)
+{
+    int iRet = -1;
+    TCSScanResult SR = {0};
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+
+    hLib = TCSLibraryOpen();
+    if (hLib == INVALID_TCSLIB_HANDLE)
+        return -1;
+    iRet = TCSScanFile(hLib, pszPath, GetSampleDataType(iType),
+                       TCS_SA_SCANONLY, iCompressFlag, &SR);
+    if (iRet != 0)
+    {
+        TCSLibraryClose(hLib);
+        return -1;
+    }
+    iRet = SR.iNumDetected;
+    if (SR.pfFreeResult != NULL)
+        SR.pfFreeResult(&SR);
+    TCSLibraryClose(hLib);
+
+    return iRet;
+}
+
+
+static int ConInfected(int iType, int iCompressFlag, char *pData, int iDataLen)
+{
+    int iRet = -1;
+    TCSScanParam SP = {0};
+    TCSScanResult SR = {0};
+    ScanContext ScanCtx = {0};
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+
+    ScanCtx.pData = pData;
+    ScanCtx.uSize = (unsigned int) iDataLen;
+
+    SP.iAction = TCS_SA_SCANONLY;
+    SP.iDataType = GetSampleDataType(iType);
+    SP.iCompressFlag = iCompressFlag;
+    SP.pPrivate = &ScanCtx;
+    SP.pfGetSize = CbScanGetSize;
+    SP.pfSetSize = CbScanSetSize;
+    SP.pfRead = CbScanRead;
+    SP.pfWrite = CbScanWrite;
+    SP.pfCallBack = NULL;
+
+    hLib = TCSLibraryOpen();
+    if (hLib == INVALID_TCSLIB_HANDLE)
+        return -1;
+    iRet = TCSScanData(hLib, &SP, &SR);
+    if (iRet != 0)
+    {
+        TCSLibraryClose(hLib);
+        return -1;
+    }
+    iRet = SR.iNumDetected;
+    if (SR.pfFreeResult != NULL)
+        SR.pfFreeResult(&SR);
+    TCSLibraryClose(hLib);
+
+    return iRet;
+}
+
+
+static int InfectedFile(TestCase *pCtx, const char *pszPath)
+{
+    int iRet = -1;
+    TCSScanResult SR = {0};
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib != INVALID_TCSLIB_HANDLE);
+    TEST_ASSERT(TCSScanFile(hLib, pszPath,
+                            GetSampleDataType(pCtx->iTestType),
+                            TCS_SA_SCANONLY, pCtx->iCompressFlag, &SR) == 0);
+    iRet = SR.iNumDetected;
+    if (SR.pfFreeResult != NULL)
+        SR.pfFreeResult(&SR);
+    TCSLibraryClose(hLib);
+
+    return iRet;
+}
+
+
+static int Infected(TestCase *pCtx, char *pData, int iDataLen)
+{
+    int iRet = -1;
+    TCSScanParam SP = {0};
+    TCSScanResult SR = {0};
+    ScanContext ScanCtx = {0};
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+
+    ScanCtx.pData = pData;
+    ScanCtx.uSize = (unsigned int) iDataLen;
+    ScanCtx.pCurrentTestCase = pCtx;
+
+    SP.iAction = TCS_SA_SCANONLY;
+    SP.iDataType = GetSampleDataType(pCtx->iTestType);
+    SP.iCompressFlag = pCtx->iCompressFlag;
+    SP.pPrivate = &ScanCtx;
+    SP.pfGetSize = CbScanGetSize;
+    SP.pfSetSize = CbScanSetSize;
+    SP.pfRead = CbScanRead;
+    SP.pfWrite = CbScanWrite;
+    SP.pfCallBack = NULL;
+
+    hLib = TCSLibraryOpen();
+    TEST_ASSERT(hLib != INVALID_TCSLIB_HANDLE);
+    TEST_ASSERT(TCSScanData(hLib, &SP, &SR) == 0);
+    iRet = SR.iNumDetected;
+    if (SR.pfFreeResult != NULL)
+        SR.pfFreeResult(&SR);
+    TCSLibraryClose(hLib);
+
+    return iRet;
+}
+
+
+static int VerifyRepairData(TestCase *pCtx, char *pRepairedBuffer,
+                            int iRepairedLen)
+{
+
+    return Infected(pCtx, pRepairedBuffer, iRepairedLen);
+}
+
+
+static int VerifyRepairFile(TestCase *pCtx)
+{
+
+    return InfectedFile(pCtx, GetSamplePath(pCtx));
+}
+
+
+static void ConTestCaseCtor(ConTestContext *pConCtx, int iCid, TestCase *pCtx)
+{
+
+    pConCtx->pTestCtx = pCtx;
+    pConCtx->iCid = iCid;
+    pConCtx->iConTestRet = 0; /* running. */
+}
+
+
+static void ConTestCaseDtor(ConTestContext *pConCtx)
+{
+
+}
+
+
+static char *GetBenignSamplePath(int iTType)
+{
+    int iLen, iRootLen;
+    char *pszSamplePath = NULL, *pszRoot = GetTestRoot();
+    const char *pszSampleFileName = NULL;
+
+    if (pszRoot != NULL)
+    {
+        pszSampleFileName = SampleGetBenignFileName(iTType);
+        iRootLen = strlen(pszRoot);
+        iLen = iRootLen;
+        iLen += strlen(pszSampleFileName);
+        iLen += 2; /* Slash char and \0 */
+
+        pszSamplePath = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszSamplePath != NULL)
+        {
+            if (pszRoot[iRootLen - 1] == '/')
+                snprintf(pszSamplePath, iLen, "%s%s", pszRoot, pszSampleFileName);
+            else
+                snprintf(pszSamplePath, iLen, "%s/%s", pszRoot, pszSampleFileName);
+        }
+        PutTestRoot(pszRoot);
+    }
+
+    return pszSamplePath;
+}
+
+
+static void PutBenignSamplePath(char *pszPath)
+{
+    if (pszPath != NULL)
+        free(pszPath);
+}
+
+
+static int ConVerifyRepairData(int iTType, int iCompressFlag, char *pRepairedBuffer,
+                               int iRepairedLen)
+{
+
+    return ConInfected(iTType, iCompressFlag, pRepairedBuffer, iRepairedLen);
+}
+
+
+static int ConVerifyRepairFile(char *pszSamplePath, int iTType, int iCompressFlag)
+{
+
+    return ConInfectedFile(iTType, iCompressFlag, pszSamplePath);
+}
+
+
+static int ConTestComplete(ConTestContext *pConCtxAry)
+{
+    int i;
+
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+    {
+        if (pConCtxAry[i].iConTestRet == 0)
+            return 0; /* not complete */
+    }
+
+    return 1; /* Complete */
+}
+
+
+static int ConTestSuccess(ConTestContext *pConCtxAry)
+{
+    int i;
+
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+    {
+        if (pConCtxAry[i].iConTestRet != 1)
+            return 0; /* failure */
+    }
+
+    return 1; /* success */
+}
+
+
+static void ReleaseTestObject(ConTestContext *pConCtx, int iResult)
+{
+
+    pthread_mutex_lock(&g_Mutex);
+    pConCtx->iConTestRet = iResult;
+    pthread_cond_broadcast(&g_Cond);
+    pthread_mutex_unlock(&g_Mutex);
+}
+
+
+static int ConCheckDetected(int iTType, TCSDetected *pFound, int *pFlags)
+{
+    const char *pszMalName = NULL, *pszVarName = NULL;
+    int i, n = SampleGetCount(iTType), iRet = 0;
+
+    for (i = 0; i < n; i++)
+    {
+        if (pFlags[i])
+            continue;
+
+        pszMalName = SampleGetMalName(iTType, i);
+        if (pszMalName != NULL)
+        {
+            if (pFound->pszName == NULL ||
+                strcmp(pFound->pszName, pszMalName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        pszVarName = SampleGetVarName(iTType, i);
+        if (pszVarName != NULL)
+        {
+            if (pFound->pszVariant == NULL ||
+                strcmp(pFound->pszVariant, pszVarName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        if (TCS_ACTION_CLASS(pFound->uAction) != SampleGetSeverity(iTType, i))
+            iRet = -1;
+
+        if (TCS_ACTION_BEHAVIOR(pFound->uAction) != SampleGetBehavior(iTType, i))
+            iRet = -1;
+
+        pFlags[i] = 1;
+        break;
+    }
+
+    if (i >= n)
+        iRet = -1;
+
+    return iRet;
+}
+
+
+static int ConCheckDetectedList(int iTType, TCSScanResult *pSR, int *pFlags)
+{
+    int iRet = 0;
+    TCSDetected *pFound = pSR->pDList;
+
+    while (pFound != NULL)
+    {
+        iRet = ConCheckDetected(iTType, pFound, pFlags);
+        if (iRet == -1)
+            break;
+        pFound = pFound->pNext;
+    }
+
+    return iRet;
+}
+
+
+static void *ConScanDataSCProc(void *pConCtxParam)
+{
+    ConTestContext *pConCtx = (ConTestContext *) pConCtxParam;
+
+    ConScanDataProc(pConCtx, TCS_SA_SCANONLY);
+
+    return NULL;
+}
+
+
+static void *ConScanDataSRProc(void *pConCtxParam)
+{
+    ConTestContext *pConCtx = (ConTestContext *) pConCtxParam;
+
+    ConScanDataProc(pConCtx, TCS_SA_SCANREPAIR);
+
+    return NULL;
+}
+
+
+static void ConScanDataProc(ConTestContext *pConCtx, int iAction)
+{
+    TCSLIB_HANDLE hLib;
+    TCSScanParam SP;
+    TCSScanResult SR = {0};
+    ConScanContext ScanCtx = {0};
+    char *pszSamplePath = NULL, *pData;
+    int i, j, iDataLen = 0, iCid= pConCtx->iCid, iOldType, iExpected;
+    int *pFlags;
+
+    CONTEST_START
+
+    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &iOldType);
+
+    i = MALWARE_TTYPE_BUFFER;
+    for (i = MALWARE_TTYPE_BUFFER; i < MALWARE_TTYPE_MULTIPLE; i++)
+    {
+        if ((iExpected = SampleGetCount(i)) > 0)
+        {
+            pFlags = (int *) malloc(sizeof(int) * iExpected);
+            if (pFlags == NULL)
+                CONTEST_ERROR
+        }
+        else
+            pFlags = NULL;
+
+        for (j = BENIGN_DATA; j <= INFECTED_DATA; j++)
+        {
+            hLib = TCSLibraryOpen();
+            if (hLib != INVALID_TCSLIB_HANDLE)
+            {
+                /* Test benign data. */
+                pszSamplePath = ConGetSamplePath(i, j, iCid);
+                pData = LoadFile(pszSamplePath, &iDataLen);
+
+                ConPutSamplePath(pszSamplePath);
+                ScanCtx.pData = pData;
+                ScanCtx.uSize = (unsigned int) iDataLen;
+                ScanCtx.iTestType = i;
+                ScanCtx.iInfected = 0;
+                ScanCtx.iPolarity = j;
+                ScanCtx.iTestRet = 1;
+                ScanCtx.pFlags = pFlags;
+
+                SP.iAction = iAction;
+                SP.iDataType = GetSampleDataType(i);
+                SP.pPrivate = &ScanCtx;
+                SP.pfGetSize = ConCbScanGetSize;
+                SP.pfSetSize = ConCbScanSetSize;
+                SP.pfRead = ConCbScanRead;
+                SP.pfWrite = ConCbScanWrite;
+                SP.pfCallBack = ConCbScanCallback;
+
+                if (pFlags)
+                    memset(pFlags, 0, sizeof(int) * iExpected);
+
+                if (TCSScanData(hLib, &SP, &SR) == 0)
+                {
+                    if (pFlags)
+                        memset(pFlags, 0, sizeof(int) * iExpected);
+
+                    if (j == BENIGN_DATA)
+                    {
+                        CONTEST_ASSERT(SR.iNumDetected == 0)
+                    }
+                    else
+                    {
+                        if (iAction == TCS_SA_SCANONLY)
+                        {
+                            CONTEST_ASSERT(SR.iNumDetected == iExpected &&
+                                           ConCheckDetectedList(i, &SR, pFlags) == 0)
+                        }
+                        else /* Repair */
+                        {
+                            CONTEST_ASSERT(ConVerifyRepairData(i, pConCtx->pTestCtx->iCompressFlag,
+                                                               ScanCtx.pData, ScanCtx.uSize) == 0)
+                        }
+                    }
+
+                    CONTEST_ASSERT(ScanCtx.iTestRet == 1)
+                    (*SR.pfFreeResult)(&SR);
+                }
+                else
+                {
+                    CONTEST_ERROR
+                }
+
+                PutLoadedFile(pData);
+
+                TCSLibraryClose(hLib);
+            }
+            else
+            {
+                CONTEST_ERROR
+            }
+
+            pthread_testcancel();
+            usleep(SLEEP_INTERVAL);
+            pthread_testcancel();
+        }
+
+        if (pFlags)
+            free(pFlags);
+    }
+    CONTEST_RELEASE(pConCtx);
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static TCSOffset ConCbScanGetSize(void *pPrivate)
+{
+    ConScanContext *pCtx = (ConScanContext *) pPrivate;
+
+    return pCtx->uSize;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static unsigned int ConCbScanRead(void *pPrivate, TCSOffset uOffset,
+                               void *pBuffer, unsigned int uSize)
+{
+    unsigned int uRead = 0;
+    ConScanContext *pCtx = (ConScanContext *) pPrivate;
+
+    if (uOffset < pCtx->uSize)
+    {
+        if ((uRead = pCtx->uSize - uOffset) > uSize)
+            uRead = uSize;
+    }
+    if (uRead)
+        memcpy(pBuffer, pCtx->pData + uOffset, uRead);
+
+    return uRead;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static unsigned int ConCbScanWrite(void *pPrivate, TCSOffset uOffset,
+                                   void const *pBuffer, unsigned int uSize)
+{
+    unsigned int uWrite = 0;
+    ConScanContext *pCtx = (ConScanContext *) pPrivate;
+
+    if (uOffset < pCtx->uSize)
+    {
+        if ((uWrite = pCtx->uSize - uOffset) > uSize)
+            uWrite = uSize;
+    }
+    if (uWrite)
+        memcpy(pCtx->pData + uOffset, pBuffer, uWrite);
+
+    return uWrite;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static int ConCbScanSetSize(void *pPrivate, TCSOffset uSize)
+{
+
+    return 0;
+}
+
+
+/**
+ * Callback helper for data scan, please reference API
+ * specification for more information about data scan.
+ */
+static int ConCbScanCallback(void *pPrivate, int nReason, void *pParam)
+{
+    ConScanContext *pCtx = (ConScanContext *) pPrivate;
+    const char *pszMalName = NULL, *pszVarName = NULL;
+    int i, iTType = pCtx->iTestType, n = SampleGetCount(iTType);
+
+    CONTEST_START
+
+    /*
+     * Fix this is important since pParam could be different
+     * if the nReason is not DETECTED.
+     */
+    if (nReason != TCS_CB_DETECTED)
+        return 0;
+
+    CONTEST_ASSERT(nReason == TCS_CB_DETECTED)
+    CONTEST_ASSERT(pCtx->iPolarity == INFECTED_DATA)
+
+    pCtx->iInfected++;
+
+    for (i = 0; i < n; i++)
+    {
+        if (pCtx->pFlags[i])
+            continue;
+
+        pszMalName = SampleGetMalName(iTType, i);
+        if (pszMalName != NULL)
+        {
+            CONTEST_ASSERT(pParam != NULL);
+            CONTEST_ASSERT(((TCSDetected *) pParam)->pszName != NULL);
+            if (((TCSDetected *) pParam)->pszName == NULL ||
+                strcmp(((TCSDetected *) pParam)->pszName, pszMalName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        pszVarName = SampleGetVarName(iTType, i);
+        if (pszVarName != NULL)
+        {
+            CONTEST_ASSERT(((TCSDetected *) pParam)->pszVariant != NULL);
+            if (((TCSDetected *) pParam)->pszVariant == NULL ||
+                strcmp(((TCSDetected *) pParam)->pszVariant, pszVarName) != 0)
+                continue;
+        }
+        else
+        {
+            continue;
+        }
+        CONTEST_ASSERT(TCS_ACTION_CLASS(((TCSDetected *) pParam)->uAction) ==
+                       SampleGetSeverity(iTType, i));
+
+        CONTEST_ASSERT(TCS_ACTION_BEHAVIOR(((TCSDetected *) pParam)->uAction) ==
+                       SampleGetBehavior(iTType, i));
+
+        pCtx->pFlags[i] = 1;
+        break;
+    }
+
+    CONTEST_ASSERT(i != n);
+
+    CONTEST_RETURN(pCtx->iTestRet)
+
+    return 0;
+}
+
+
+void ConScanData(TestCase *pCtx, int iAction)
+{
+    int i, iRet = 0;
+    ConTestContext ConCtxs[MAX_TEST_THREADS];
+    pthread_t Threads[MAX_TEST_THREADS];
+
+    /* Prepare for concurrency tests. */
+    ConCreateSampleDirs();
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+        ConTestCaseCtor(&ConCtxs[i], i + 1, pCtx);
+
+    /* Concurrency tests. */
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+    {
+        if (iAction == TCS_SA_SCANONLY)
+            pthread_create(&Threads[i], NULL, ConScanDataSCProc, &ConCtxs[i]);
+        else
+            pthread_create(&Threads[i], NULL, ConScanDataSRProc, &ConCtxs[i]);
+    }
+
+    /* Wait for all tests completed. */
+    iRet = ConWaitOnTestCond(&ConCtxs[0]);
+    if (iRet == ETIMEDOUT)
+    {
+        usleep(SLEEP_INTERVAL);
+        /* Cancel them all, if timeout. */
+        for (i = 0; i < MAX_TEST_THREADS; i++)
+        {
+            pthread_cancel(Threads[i]);
+            /* Wait for cancelling. */
+            usleep(SLEEP_INTERVAL);
+        }
+    }
+
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+        pthread_join(Threads[i], NULL);
+
+    /* Check test result. */
+    TEST_ASSERT(ConTestSuccess(&ConCtxs[0]) == 1);
+
+    /* Release concurrency tests. */
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+        ConTestCaseDtor(&ConCtxs[i]);
+    ConDestorySampleDirs();
+}
+
+
+static void *ConScanFileSCProc(void *pConCtxParam)
+{
+    ConTestContext *pConCtx = (ConTestContext *) pConCtxParam;
+
+    ConScanFileProc(pConCtx, TCS_SA_SCANONLY);
+
+    return NULL;
+}
+
+
+static void *ConScanFileSRProc(void *pConCtxParam)
+{
+    ConTestContext *pConCtx = (ConTestContext *) pConCtxParam;
+
+    ConScanFileProc(pConCtx, TCS_SA_SCANREPAIR);
+
+    return NULL;
+}
+
+
+static void ConScanFileProc(ConTestContext *pConCtx, int iAction)
+{
+    TCSLIB_HANDLE hLib;
+    TCSScanResult SR = {0};
+    char *pszSamplePath = NULL;
+    int i, j, iOldType, iCid = pConCtx->iCid, iExpected;
+    int *pFlags;
+
+    CONTEST_START
+
+    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &iOldType);
+
+    for (i = MALWARE_TTYPE_BUFFER; i < MALWARE_TTYPE_MULTIPLE; i++)
+    {
+        if ((iExpected = SampleGetCount(i)) > 0)
+        {
+            pFlags = (int *) malloc(sizeof(int) * iExpected);
+            if (pFlags == NULL)
+                CONTEST_ERROR
+        }
+        else
+            pFlags = NULL;
+
+        for (j = BENIGN_DATA; j <= INFECTED_DATA; j++)
+        {
+            hLib = TCSLibraryOpen();
+            if (hLib != INVALID_TCSLIB_HANDLE)
+            {
+                /* Test benign data. */
+                pszSamplePath = ConGetSamplePath(i, j, iCid);
+
+                if (TCSScanFile(hLib, pszSamplePath, GetSampleDataType(i),
+                                iAction, pConCtx->pTestCtx->iCompressFlag, &SR) == 0)
+                {
+                    if (pFlags)
+                        memset(pFlags, 0, sizeof(int) * iExpected);
+
+                    if (j == BENIGN_DATA)
+                    {
+                        CONTEST_ASSERT(SR.iNumDetected == 0)
+                    }
+                    else
+                    {
+                        if (iAction == TCS_SA_SCANONLY)
+                        {
+                            CONTEST_ASSERT(SR.iNumDetected == iExpected &&
+                                           ConCheckDetectedList(i, &SR, pFlags) == 0)
+                        }
+                        else /* Repair */
+                        {
+                            CONTEST_ASSERT(ConVerifyRepairFile(pszSamplePath, i,
+                                           pConCtx->pTestCtx->iCompressFlag) == 0)
+                        }
+                    }
+
+                    (*SR.pfFreeResult)(&SR);
+                }
+                else
+                {
+                    CONTEST_ERROR
+                }
+                ConPutSamplePath(pszSamplePath);
+                TCSLibraryClose(hLib);
+            }
+            else
+            {
+                CONTEST_ERROR
+            }
+
+            pthread_testcancel();
+            usleep(SLEEP_INTERVAL);
+            pthread_testcancel();
+        }
+
+        if (pFlags)
+            free(pFlags);
+    }
+
+    CONTEST_RELEASE(pConCtx)
+}
+
+
+static int ConWaitOnTestCond(ConTestContext *pConCtxAry)
+{
+    int iRet;
+    struct timeval Now;
+    struct timespec Timeout;
+
+    gettimeofday(&Now, NULL);
+    Timeout.tv_sec = Now.tv_sec + DEFAULT_CONCURRENCY_TEST_TIMEOUT;
+    Timeout.tv_nsec = Now.tv_usec * 1000;
+    iRet = 0;
+
+    pthread_mutex_lock(&g_Mutex);
+    while (ConTestComplete(pConCtxAry) != 1 && iRet != ETIMEDOUT)
+        iRet = pthread_cond_timedwait(&g_Cond, &g_Mutex, &Timeout);
+    pthread_mutex_unlock(&g_Mutex);
+
+    return iRet;
+}
+
+
+void ConScanFile(TestCase *pCtx, int iAction)
+{
+    int i, iRet = 0;
+    ConTestContext ConCtxs[MAX_TEST_THREADS];
+    pthread_t Threads[MAX_TEST_THREADS];
+
+    /* Prepare for concurrency tests. */
+    ConCreateSampleDirs();
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+        ConTestCaseCtor(&ConCtxs[i], i + 1, pCtx);
+
+    /* Concurrency tests. */
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+    {
+        if (iAction == TCS_SA_SCANONLY)
+            pthread_create(&Threads[i], NULL, ConScanFileSCProc, &ConCtxs[i]);
+        else
+            pthread_create(&Threads[i], NULL, ConScanFileSRProc, &ConCtxs[i]);
+    }
+    /* Wait for all tests completed. */
+    iRet = ConWaitOnTestCond(&ConCtxs[0]);
+    if (iRet == ETIMEDOUT)
+    {
+        usleep(SLEEP_INTERVAL);
+        /* Cancel them all, if timeout. */
+        for (i = 0; i < MAX_TEST_THREADS; i++)
+        {
+            pthread_cancel(Threads[i]);
+            /* Wait for cancelling. */
+            usleep(SLEEP_INTERVAL);
+        }
+    }
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+        pthread_join(Threads[i], NULL);
+    
+    /* Check test result. */
+    TEST_ASSERT(ConTestSuccess(ConCtxs) == 1);
+
+    /* Release concurrency tests. */
+    for (i = 0; i < MAX_TEST_THREADS; i++)
+        ConTestCaseDtor(&ConCtxs[i]);
+    ConDestorySampleDirs();
+}
+
+
+static char *ConGetSampleDir(int iCid)
+{
+    int iLen;
+    char *pszDir = NULL, *pszRoot = GetTestRoot();
+
+    if (pszRoot != NULL)
+    {
+        iLen = strlen(pszRoot);
+        iLen++; /* Reserved for slash char. */
+        iLen += 64; /* Reserved for thread id. */
+
+        pszDir = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszDir != NULL)
+        {
+            if (pszRoot[strlen(pszRoot) - 1] == '/')
+                snprintf(pszDir, iLen, "%s%s/t-%d", pszRoot, CONTENTS_ROOT, iCid);
+            else
+                snprintf(pszDir, iLen, "%s/%s/t-%d", pszRoot, CONTENTS_ROOT, iCid);
+        }
+        PutTestRoot(pszRoot);
+    }
+
+    return pszDir;
+}
+
+
+static void ConPutSampleDir(char *pszDir)
+{
+    if (pszDir != NULL)
+        free(pszDir);
+}
+
+
+static void ConCreateSampleDirs(void)
+{
+    int i, iLen, iRootLen;
+    char *pszRoot = GetTestRoot(), *pszCommand;
+
+    if (pszRoot != NULL)
+    {
+        for (i = 0; i < MAX_TEST_THREADS; i++)
+        {
+            iRootLen = strlen(pszRoot);
+            iLen = iRootLen * 2;
+            iLen += 72; /* Reserved for "mkdir t-" , "cp -f "*/
+            pszCommand = (char *) calloc(iLen + 1, sizeof(char));
+            if (pszCommand)
+            {
+                if (pszRoot[iRootLen - 1] == '/')
+                    snprintf(pszCommand, iLen, "mkdir -p %s%st-%d", pszRoot, CONTENTS_ROOT, i + 1);
+                else
+                    snprintf(pszCommand, iLen, "mkdir -p %s/%s/t-%d", pszRoot, CONTENTS_ROOT, i + 1);
+                CallSys(pszCommand);
+
+                pszCommand[0] = 0;
+                if (pszRoot[iRootLen - 1] == '/')
+                    snprintf(pszCommand, iLen, "cp -f %s*.* %s%s/t-%d/",
+                             pszRoot, pszRoot, CONTENTS_ROOT, i + 1);
+                else
+                    snprintf(pszCommand, iLen, "cp -f %s/*.* %s/%s/t-%d/",
+                             pszRoot, pszRoot, CONTENTS_ROOT, i + 1);
+                CallSys(pszCommand);
+
+                free(pszCommand);
+                pszCommand = NULL;
+            }
+        }
+        PutTestRoot(pszRoot);
+    }
+}
+
+
+static void ConDestorySampleDirs(void)
+{
+    int iLen, iRootLen;
+    char *pszRoot = GetTestRoot(), *pszCommand;
+
+    if (pszRoot != NULL)
+    {
+        iRootLen = strlen(pszRoot);
+        iLen = iRootLen;
+        iLen += 72; /* "rm -rf "*/
+        pszCommand = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszCommand)
+        {
+            if (pszRoot[iRootLen - 1] == '/')
+                snprintf(pszCommand, iLen, "rm -rf %s%s/t-*", pszRoot, CONTENTS_ROOT);
+            else
+                snprintf(pszCommand, iLen, "rm -rf %s/%s/t-*", pszRoot, CONTENTS_ROOT);
+            CallSys(pszCommand);
+
+            free(pszCommand);
+            pszCommand = NULL;
+        }
+        PutTestRoot(pszRoot);
+    }
+}
+
+
+static char *ConGetSamplePath(int iTType, int iPolarity, int iCid)
+{
+    int iLen, iDirLen;
+    const char *pszSampleFileName;
+    char *pszSamplePath = NULL, *pszDir = NULL;
+    char *pwd = getenv("PWD");
+
+    if (pwd == NULL)
+        return NULL;
+
+    pszDir = ConGetSampleDir(iCid);
+
+    if (pszDir != NULL)
+    {
+        pszSampleFileName = (iPolarity == INFECTED_DATA ?
+                             SampleGetInfectedFileName(iTType) :
+                             SampleGetBenignFileName(iTType));
+
+        if (pszSampleFileName == NULL)
+            return NULL;
+
+        iDirLen = strlen(pszDir);
+        iLen = iDirLen;
+        iLen += strlen(pszSampleFileName);
+        iLen++; /* Reserved for slash char. */
+        iLen++; /* Reserved for \0. */
+        iLen += strlen(pwd) + 1;
+
+        pszSamplePath = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszSamplePath != NULL)
+        {
+            if (pszDir[iDirLen - 1] == '/')
+                snprintf(pszSamplePath, iLen, "%s/%s%s", pwd, pszDir, pszSampleFileName);
+            else
+                snprintf(pszSamplePath, iLen, "%s/%s/%s", pwd, pszDir, pszSampleFileName);
+        }
+        ConPutSampleDir(pszDir);
+    }
+
+    return pszSamplePath;
+}
+
+
+static void ConPutSamplePath(char *pszSamplePath)
+{
+
+    if (pszSamplePath != NULL)
+        free(pszSamplePath);
+}
+
+
+int DetectRepairFunc(void)
+{
+    int iRet = 0; /* Not support by default. */
+    TCSScanResult SR = {0};
+    char *pszTestSamplePath;
+    TCSLIB_HANDLE hLib = INVALID_TCSLIB_HANDLE;
+
+    hLib = TCSLibraryOpen();
+    if (hLib != INVALID_TCSLIB_HANDLE)
+    {
+        pszTestSamplePath = GetBenignSamplePath(MALWARE_TTYPE_BUFFER);
+        if (pszTestSamplePath != NULL)
+        {
+            if (TCSScanFile(hLib, pszTestSamplePath,
+                            GetSampleDataType(MALWARE_TTYPE_BUFFER),
+                            TCS_SA_SCANREPAIR, 1, &SR) == 0)
+            {
+                (*SR.pfFreeResult)(&SR);
+                iRet = 1; /* Supported. */
+            }
+
+            PutBenignSamplePath(pszTestSamplePath);
+        }
+        TCSLibraryClose(hLib);
+    }
+
+    return iRet;
+}
+
+
+int IsTestRepair()
+{
+    const char *pszType = getenv("TCS_SCAN_TYPE");
+    if (pszType != NULL)
+        return atoi(pszType);
+
+    return 0;
+}
+
+
+int DetermineEngineLib()
+{
+    struct stat statBuf;
+    if (stat(TCS_SECLIB_DEFAULT, &statBuf) == 0 &&
+        S_ISREG(statBuf.st_mode))
+        pszSecLibPath = TCS_SECLIB_DEFAULT;
+    else if (stat(TCS_SECLIB_DCM, &statBuf) == 0 &&
+        S_ISREG(statBuf.st_mode))
+        pszSecLibPath = TCS_SECLIB_DCM;
+    else
+        return -1;
+
+    return 0;
+}
+
+
+void BackupEngine()
+{
+    char *pszRoot = GetTestRoot(), *pszCommand;
+
+    if (pszRoot != NULL)
+    {
+        if (asprintf(&pszCommand, "mkdir %s/backup", pszRoot) < 0)
+        {
+            PutTestRoot(pszRoot);
+            return;
+        }
+        CallSys(pszCommand);
+        free(pszCommand);
+
+        if (asprintf(&pszCommand, "cp -f /opt/usr/share/sec_plugin/libengine.so %s/backup", pszRoot) < 0)
+        {
+            PutTestRoot(pszRoot);
+            return;
+        }
+        CallSys(pszCommand);
+        free(pszCommand);
+        PutTestRoot(pszRoot);
+    }
+}
+
+
+void RestoreEngine()
+{
+    char *pszRoot = GetTestRoot(), *pszCommand;
+
+    if (pszRoot != NULL)
+    {
+        if (asprintf(&pszCommand, "ln -s %s /opt/usr/share/sec_plugin/libengine.so", pszSecLibPath) < 0)
+        {
+            PutTestRoot(pszRoot);
+            return;
+        }
+        CallSys(pszCommand);
+        free(pszCommand);
+
+        PutTestRoot(pszRoot);
+    }
+}
+
+
+static void CallSys(const char *pszCmd)
+{
+    int iRet = system(pszCmd);
+    if (iRet != 0)
+    {
+        // LOG_OUT("system returns %d for command %s\n", iRet, pszCmd);
+    }
+}
+
diff --git a/test/TWPTest.c b/test/TWPTest.c
new file mode 100644 (file)
index 0000000..7462268
--- /dev/null
@@ -0,0 +1,1218 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include "TWPImpl.h"
+
+#include "XMHttp.h"
+#include "TWPTest.h"
+#include "UrlInfo.h"
+
+/* Test cases. */
+static void TWPStartup(void);
+static void TWPCleanup(void);
+static void TWPInitLibrary_0001(void);
+static void TWPInitLibrary_0002(void);
+static void TWPInitLibrary_0003(void);
+static void TWPInitLibrary_0004(void);
+static void TWPConfigurationCreate_0001(void);
+static void TWPConfigurationCreate_0002(void);
+static void TWPConfigurationCreate_0003(void);
+static void TWPPolicyCreate_0001(void);
+static void TWPPolicyCreate_0002(void);
+static void TWPPolicyCreate_0003(void);
+static void TWPLookupUrls_0001(void);
+static void TWPLookupUrls_0002(void);
+static void TWPLookupUrls_0003(void);
+static void TWPLookupUrls_0004(void);
+static void TWPLookupUrls_0005(void);
+static void TWPGetUrlRating_0001(void);
+static void TWPGetUrlRating_0002(void);
+static void TWPGetUrlRating_0003(void);
+static void TWPGetUrlRating_0004(void);
+static void TWPGetUrlRating_0005(void);
+static void TWPGetUrlRating_0006(void);
+static void TWPGetUrlRatingsCount_0001(void);
+static void TWPGetUrlRatingsCount_0002(void);
+static void TWPGetRedirUrlFor_0001(void);
+static void TWPGetRedirUrlFor_0002(void);
+static void TWPPolicyValidate_0001(void);
+static void TWPPolicyValidate_0002(void);
+static void TWPPolicyValidate_0003(void);
+static void TWPPolicyGetViolations_0001(void);
+static void TWPPolicyGetViolations_0002(void);
+static void TWPPolicyGetViolations_0003(void);
+static void TWPRatingGetScore_0001(void);
+static void TWPRatingGetScore_0002(void);
+static void TWPRatingGetUrl_0001(void);
+static void TWPRatingGetUrl_0002(void);
+static void TWPRatingGetDLAUrl_0001(void);
+static void TWPRatingGetDLAUrl_0002(void);
+static void TWPRatingHasCategory_0001(void);
+static void TWPRatingHasCategory_0002(void);
+static void TWPRatingHasCategory_0003(void);
+static void TWPRatingGetCategories_0001(void);
+static void TWPRatingGetCategories_0002(void);
+static void TWPRatingGetCategories_0003(void);
+
+static void TestCases(void);
+
+
+extern int TestCasesCount;
+extern int Success;
+extern int Failures;
+extern TWPResponseHandle hAResponse;
+
+TWPAPIInit Init;
+TWPConfiguration Cfg;
+TRequest Request;
+
+
+int main(int argc, char **argv)
+{
+    TWPStartup();
+    TestCases();
+    TWPCleanup();
+
+    return 0;
+}
+
+
+static void TestCases(void)
+{
+    TWPInitLibrary_0001();
+    TWPInitLibrary_0002();
+    TWPInitLibrary_0003();
+    TWPInitLibrary_0004();
+    TWPConfigurationCreate_0001();
+    TWPConfigurationCreate_0002();
+    TWPConfigurationCreate_0003();
+    TWPPolicyCreate_0001();
+    TWPPolicyCreate_0002();
+    TWPPolicyCreate_0003();
+    TWPLookupUrls_0001();
+    TWPLookupUrls_0002();
+    TWPLookupUrls_0003();
+    TWPLookupUrls_0004();
+    TWPLookupUrls_0005();
+    TWPGetUrlRating_0001();
+    TWPGetUrlRating_0002();
+    TWPGetUrlRating_0003();
+    TWPGetUrlRating_0004();
+    TWPGetUrlRating_0005();
+    TWPGetUrlRating_0006();
+    TWPGetUrlRatingsCount_0001();
+    TWPGetUrlRatingsCount_0002();
+    TWPGetRedirUrlFor_0001();
+    TWPGetRedirUrlFor_0002();
+    TWPPolicyValidate_0001();
+    TWPPolicyValidate_0002();
+    TWPPolicyValidate_0003();
+    TWPPolicyGetViolations_0001();
+    TWPPolicyGetViolations_0002();
+    TWPPolicyGetViolations_0003();
+    TWPRatingGetScore_0001();
+    TWPRatingGetScore_0002();
+    TWPRatingGetUrl_0001();
+    TWPRatingGetUrl_0002();
+    TWPRatingGetDLAUrl_0001();
+    TWPRatingGetDLAUrl_0002();
+    TWPRatingHasCategory_0001();
+    TWPRatingHasCategory_0002();
+    TWPRatingHasCategory_0003();
+    TWPRatingGetCategories_0001();
+    TWPRatingGetCategories_0002();
+    TWPRatingGetCategories_0003();
+}
+
+
+static void TWPInitLibrary_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib = INVALID_TWPLIB_HANDLE;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TESTCASEDTOR(&TestCtx);
+    TWPUninitLibrary(hLib);
+}
+
+
+static void TWPInitLibrary_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib = INVALID_TWPLIB_HANDLE;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+
+    RemoveEngine();
+
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib == INVALID_TWPLIB_HANDLE);
+
+    TESTCASEDTOR(&TestCtx);
+
+    RestoreEngine();
+}
+
+
+static void TWPInitLibrary_0003(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib = INVALID_TWPLIB_HANDLE;
+
+    RemoveEngine();
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib == INVALID_TWPLIB_HANDLE);
+
+    RestoreEngine();
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPInitLibrary_0004(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib = INVALID_TWPLIB_HANDLE;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+
+    TWPUninitLibrary(hLib);
+    RemoveEngine();
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib == INVALID_TWPLIB_HANDLE);
+
+    TESTCASEDTOR(&TestCtx);
+    RestoreEngine();
+}
+
+
+static void TWPConfigurationCreate_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPConfigurationCreate_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+
+    TEST_ASSERT(TWPConfigurationCreate(hLib, NULL, &hCfg) != TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPConfigurationCreate_0003(void)
+{
+    TestCase TestCtx;
+    TWPConfigurationHandle hCfg;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    TEST_ASSERT(TWPConfigurationCreate(INVALID_TWPLIB_HANDLE, NULL, &hCfg) != TWP_SUCCESS);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyCreate_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPPolicyHandle hPolicy;
+    TWPConfigurationHandle hCfg;
+    TWPCategories Categories[1] =
+    {
+        TWP_Artcultureheritage, 
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyCreate(hLib, hCfg, Categories, ELEMENT_NUM(Categories), &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(hPolicy != NULL);
+    TEST_ASSERT(TWPPolicyDestroy(hLib, &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyCreate_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPPolicyHandle hPolicy;
+    TWPConfigurationHandle hCfg;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyCreate(hLib, hCfg, NULL, 0, &hPolicy) != TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyCreate_0003(void)
+{
+    TestCase TestCtx;
+    TWPPolicyHandle hPolicy;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    TEST_ASSERT(TWPPolicyCreate(INVALID_TWPLIB_HANDLE, NULL, NULL, 0, &hPolicy) != TWP_SUCCESS);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPLookupUrls_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0, ppUrls,
+                              ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPLookupUrls_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                NULL, 0, &hResponse) != TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPLookupUrls_0003(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TRequest ARequest = Request;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    ARequest.Request.receivefunc = NULL;
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &ARequest, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseWrite(hLib, hAResponse, ARequest.ResponseBody, ARequest.ResponseLength) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseWrite(hLib, hAResponse, "", 0) == TWP_SUCCESS);
+    TEST_ASSERT(hAResponse != NULL);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hAResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPLookupUrls_0004(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0, ppUrls,
+                ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPLookupUrls_0005(void)
+{
+    TestCase TestCtx;
+    TWPResponseHandle hResponse;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    RemoveEngine();
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    TEST_ASSERT(TWPLookupUrls(INVALID_TWPLIB_HANDLE, NULL, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRating_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByIndex(hLib, hResponse, 0, &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRating_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, URL_0_0,
+                strlen(URL_0_0), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRating_0003(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, NULL, 0, &hRating) != TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRating_0004(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByIndex(hLib, hResponse, 0, &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRating_0005(void)
+{
+    TestCase TestCtx;
+    TWPUrlRatingHandle hRating;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    /* pre-condition is stub library */
+    RemoveEngine();
+    TEST_ASSERT(TWPResponseGetUrlRatingByIndex(INVALID_TWPLIB_HANDLE,
+                NULL, 0, &hRating) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRating_0006(void)
+{
+    TestCase TestCtx;
+    TWPUrlRatingHandle hRating;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    /* pre-condition is stub library */
+    RemoveEngine();
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(INVALID_TWPLIB_HANDLE, NULL,
+                NULL, 0, &hRating) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRatingsCount_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[] =
+    {
+        URL_0_0,
+        URL_1_0
+    };
+    unsigned int uCount = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByIndex(hLib, hResponse, 0, &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseGetUrlRatingsCount(hLib, hResponse, &uCount) == TWP_SUCCESS);
+    TEST_ASSERT(uCount == ELEMENT_NUM(ppUrls));
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetUrlRatingsCount_0002(void)
+{
+    unsigned int uCount;
+    TestCase TestCtx;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    /* pre-condition is stub library */
+    RemoveEngine();
+    TEST_ASSERT(TWPResponseGetUrlRatingsCount(INVALID_TWPLIB_HANDLE,
+                NULL, &uCount) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetRedirUrlFor_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_3_0
+    };
+    char *pUrl = NULL;
+    unsigned int uLength = 0;
+    TWPPolicyHandle hPolicy;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 1,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByIndex(hLib, hResponse, 0, &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(hRating != NULL);
+    TEST_ASSERT(TWPPolicyCreate(hLib, hCfg, CATEGORIES_0_0_1, ELEMENT_NUM(CATEGORIES_0_0_1), &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(hPolicy != NULL);
+    TEST_ASSERT(TWPResponseGetRedirUrlFor(hLib, hResponse, hRating, hPolicy, &pUrl, &uLength) == TWP_SUCCESS);
+    TEST_ASSERT(pUrl != NULL);
+    free(pUrl);
+    TEST_ASSERT(TWPPolicyDestroy(hLib, &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPGetRedirUrlFor_0002(void)
+{
+    TestCase TestCtx;
+    TWPPolicyHandle hPolicy = NULL;
+    char *pUrl = NULL;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    /* pre-condition is stub library */
+    RemoveEngine();
+    TEST_ASSERT(TWPResponseGetRedirUrlFor(INVALID_TWPLIB_HANDLE,
+                NULL, NULL, hPolicy, &pUrl, &uLength) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyValidate_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    TWPPolicyHandle hPolicy;
+    int iViolated = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyCreate(hLib, hCfg, CATEGORIES_0_0_1, ELEMENT_NUM(CATEGORIES_0_0_1), &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyValidate(hLib, hPolicy, hRating, &iViolated) == TWP_SUCCESS);
+    TEST_ASSERT(iViolated == 1);
+    TEST_ASSERT(TWPPolicyDestroy(hLib, &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyValidate_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    TWPPolicyHandle hPolicy;
+    int iViolated = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyCreate(hLib, hCfg, CATEGORIES_0_0_0, ELEMENT_NUM(CATEGORIES_0_0_0), &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyValidate(hLib, hPolicy, hRating, &iViolated) == TWP_SUCCESS);
+    TEST_ASSERT(iViolated == 0);
+    TEST_ASSERT(TWPPolicyDestroy(hLib, &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyValidate_0003(void)
+{
+    TestCase TestCtx;
+    int iViolated = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    RemoveEngine();
+    TEST_ASSERT(TWPPolicyValidate(INVALID_TWPLIB_HANDLE,
+                NULL, NULL, &iViolated) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyGetViolations_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    TWPPolicyHandle hPolicy;
+    TWPCategories *pViolated = NULL;
+    unsigned int uLength = 0;
+    int i;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyCreate(hLib, hCfg, CATEGORIES_0_0_2, ELEMENT_NUM(CATEGORIES_0_0_2), &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyGetViolations(hLib, hPolicy, hRating, &pViolated, &uLength) == TWP_SUCCESS);
+    TEST_ASSERT(uLength == ELEMENT_NUM(VIOLATIONS_0_0_2));
+    for (i = 0; i < uLength; i++)
+    {
+        TEST_ASSERT(pViolated[i] == VIOLATIONS_0_0_2[i]);
+    }
+    free(pViolated);
+    TEST_ASSERT(TWPPolicyDestroy(hLib, &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyGetViolations_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    TWPPolicyHandle hPolicy;
+    TWPCategories *pViolated = NULL;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyCreate(hLib, hCfg, CATEGORIES_0_0_0, ELEMENT_NUM(CATEGORIES_0_0_0), &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPPolicyGetViolations(hLib, hPolicy, hRating, &pViolated, &uLength) == TWP_SUCCESS);
+    TEST_ASSERT(uLength == 0);
+    TEST_ASSERT(pViolated == NULL);
+    TEST_ASSERT(TWPPolicyDestroy(hLib, &hPolicy) == TWP_SUCCESS);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPPolicyGetViolations_0003(void)
+{
+    TestCase TestCtx;
+    TWPCategories *pViolated = NULL;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    RemoveEngine();
+    TEST_ASSERT(TWPPolicyGetViolations(INVALID_TWPLIB_HANDLE, NULL, NULL,
+        &pViolated, &uLength) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetScore_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    int iScore;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPUrlRatingGetScore(hLib, hRating, &iScore) == TWP_SUCCESS);
+    TEST_ASSERT(iScore == SCORE_0_0);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetScore_0002(void)
+{
+    TestCase TestCtx;
+    int iScore;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    RemoveEngine();
+    TEST_ASSERT(TWPUrlRatingGetScore(INVALID_TWPLIB_HANDLE, NULL, &iScore) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetUrl_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    char *pUrl;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPUrlRatingGetUrl(hLib, hRating, &pUrl, &uLength) == TWP_SUCCESS);
+    TEST_ASSERT(strcmp(pUrl, ppUrls[0]) == 0);
+    TEST_ASSERT(uLength == strlen(ppUrls[0]));
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetUrl_0002(void)
+{
+    TestCase TestCtx;
+    char *pUrl;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    RemoveEngine();
+    TEST_ASSERT(TWPUrlRatingGetUrl(INVALID_TWPLIB_HANDLE, NULL, &pUrl, &uLength) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetDLAUrl_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_2_0
+    };
+    char *pUrl;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPUrlRatingGetDLAUrl(hLib, hRating, &pUrl, &uLength) == TWP_SUCCESS);
+    TEST_ASSERT(pUrl != NULL);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetDLAUrl_0002(void)
+{
+    TestCase TestCtx;
+    char *pUrl;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    RemoveEngine();
+    TEST_ASSERT(TWPUrlRatingGetDLAUrl(INVALID_TWPLIB_HANDLE, NULL, &pUrl, &uLength) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingHasCategory_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    int iPresent = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPUrlRatingHasCategory(hLib, hRating, CATEGORY_0_0_1, &iPresent) == TWP_SUCCESS);
+    TEST_ASSERT(iPresent == 1);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingHasCategory_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    int iPresent = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPUrlRatingHasCategory(hLib, hRating, CATEGORY_0_0_0, &iPresent) == TWP_SUCCESS);
+    TEST_ASSERT(iPresent == 0);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingHasCategory_0003(void)
+{
+    TestCase TestCtx;
+    int iPresent = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    RemoveEngine();
+    TEST_ASSERT(TWPUrlRatingHasCategory(INVALID_TWPLIB_HANDLE, NULL, CATEGORY_0_0_0, &iPresent) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetCategories_0001(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_0_0
+    };
+    TWPCategories *pCategories;
+    unsigned int uLength;
+    int i;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPUrlRatingGetCategories(hLib, hRating, &pCategories, &uLength) == TWP_SUCCESS);
+    TEST_ASSERT(uLength == ELEMENT_NUM(CATEGORIES_0_0_3));
+    for (i = 0; i < uLength; i++)
+    {
+        TEST_ASSERT(pCategories[i] == CATEGORIES_0_0_3[i]);
+    }
+    free(pCategories);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetCategories_0002(void)
+{
+    TestCase TestCtx;
+    TWPLIB_HANDLE hLib;
+    TWPConfigurationHandle hCfg;
+    TWPResponseHandle hResponse;
+    TWPUrlRatingHandle hRating;
+    const char *ppUrls[1] =
+    {
+        URL_1_0
+    };
+    TWPCategories *pCategories = NULL;
+    unsigned int uLength = 0;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    hLib = TWPInitLibrary(&Init);
+    TEST_ASSERT(hLib != INVALID_TWPLIB_HANDLE);
+    TEST_ASSERT(TWPConfigurationCreate(hLib, &Cfg, &hCfg) == TWP_SUCCESS);
+    TEST_ASSERT(hCfg != NULL);
+    TEST_ASSERT(TWPLookupUrls(hLib, hCfg, (TWPRequest *) &Request, 0,
+                              ppUrls, ELEMENT_NUM(ppUrls), &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(hResponse != NULL);
+    TEST_ASSERT(TWPResponseGetUrlRatingByUrl(hLib, hResponse, ppUrls[0], strlen(ppUrls[0]), &hRating) == TWP_SUCCESS);
+    TEST_ASSERT(TWPUrlRatingGetCategories(hLib, hRating, &pCategories, &uLength) == TWP_SUCCESS);
+    TEST_ASSERT(pCategories != NULL);
+    TEST_ASSERT(TWPResponseDestroy(hLib, &hResponse) == TWP_SUCCESS);
+    TEST_ASSERT(TWPConfigurationDestroy(hLib, &hCfg) == TWP_SUCCESS);
+    TWPUninitLibrary(hLib);
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPRatingGetCategories_0003(void)
+{
+    TestCase TestCtx;
+    TWPCategories *pCategories;
+    unsigned int uLength;
+
+    TESTCASECTOR(&TestCtx, __FUNCTION__);
+    RemoveEngine();
+    TEST_ASSERT(TWPUrlRatingGetCategories(INVALID_TWPLIB_HANDLE, NULL, &pCategories, &uLength) != TWP_SUCCESS);
+    RestoreEngine();
+    TESTCASEDTOR(&TestCtx);
+}
+
+
+static void TWPStartup(void)
+{
+    extern int TestCasesCount;
+    extern int Success;
+    extern int Failures;
+
+    TEST_ASSERT(DetermineWpEngineLib() == 0);
+    TestCasesCount = 0;
+    Success = 0;
+    Failures = 0;
+
+    Init.api_version = TWPAPI_VERSION;
+    Init.memallocfunc = (TWPFnMemAlloc) malloc;
+    Init.memfreefunc = free;
+
+    srandom(time(NULL));
+
+    Cfg.config_version = TWPCONFIG_VERSION;
+    Cfg.client_id = NULL;
+    Cfg.client_key = NULL;
+    Cfg.host = NULL;
+#if !defined(TWP_USESSL)
+    Cfg.secure_connection = 0;
+#else
+    Cfg.secure_connection = 1;
+#endif
+    Cfg.skip_dla = 0;
+    Cfg.obfuscate_request = 1;
+    Cfg.randomfunc = GenerateRandomNumber;
+
+    Request.Request.request_version = TWPREQUEST_VERSION;
+    Request.Request.seturlfunc = CbSetUrl;
+    Request.Request.setmethodfunc = CbSetMethod;
+    Request.Request.sendfunc = CbSend;
+    Request.Request.receivefunc = CbRecv;
+    CreateTestDirs();
+}
+
+
+static void TWPCleanup(void)
+{
+    LOG_OUT("@@@@@@@@@@@@@@@@@@@@@@@@\n");
+    LOG_OUT("Test done: %d executed, %d passed, %d failure\n", TestCasesCount, Success, Failures);
+
+    if (Request.hHttp != INVALID_XM_HTTP_HANDLE)
+        XmHttpClose(Request.hHttp);
+
+    DestoryTestDirs();
+}
diff --git a/test/TWPTest.h b/test/TWPTest.h
new file mode 100644 (file)
index 0000000..bb14408
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef TWPTEST_H
+#define TWPTEST_H
+
+
+#include <setjmp.h>
+
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+#define TEST_SUITE_VERSION "0.0.1"
+
+/* Immediate value definitions. */
+#define MAX_TEST_NUM 128
+
+/* Maximum WP API name length. */
+#define MAX_TWP_API_NAME_LEN 128
+
+/* Output methods. */
+#define LOG_OUT(fmt, x...) printf("Log:"fmt, ##x)
+
+#define TRY_TEST { \
+    int _ret_ = setjmp(WPJmpBuf); \
+    if (_ret_ == 1) { \
+        Failures++; \
+    } else { \
+
+#define FAIL_TEST longjmp(WPJmpBuf, 1);
+
+#define TESTCASECTOR(_ctx_, _api_) \
+        TRY_TEST \
+        TestCaseCtor(_ctx_, _api_);
+
+#define TESTCASEDTOR(_ctx_) \
+        TestCaseDtor(_ctx_); \
+    } \
+} \
+
+/* Test assert method. */
+#define TEST_ASSERT(cond) if (!(cond)) {LOG_OUT("Test failed!! at : %s, %d\n", __FILE__, __LINE__); FAIL_TEST}
+
+#define ELEMENT_NUM(ary) (sizeof(ary) / sizeof((ary)[0]))
+
+/* Content directory for testing. */
+#define TWP_TEST_CONTENT_DIR "contents_test"
+
+/* Content backup directory. */
+#define TWP_BACKUP_CONTENT_DIR "contents_bak"
+
+
+/**
+ * Test case information data
+ */
+typedef struct TestCase_struct
+{
+    char szAPIName[MAX_TWP_API_NAME_LEN]; /* TWP API names */
+} TestCase;
+
+/**
+ * Test request data structure
+ */
+typedef struct TRequest
+{
+    TWPRequest Request;
+    const char *pszUrl;
+    size_t ResponseLength;
+    char *ResponseBody;
+    XM_HTTP_HANDLE hHttp;
+    char *pData;
+    unsigned int uLength;
+    unsigned int uRead;
+    size_t ResponseBytesRead;
+} TRequest;
+
+
+/*
+ * Very simple/thin porting layer
+ */
+
+/* Test framework */
+extern void TestCaseCtor(TestCase *pCtx, const char *pszAPI);
+extern void TestCaseDtor(TestCase *pCtx);
+extern void RestoreEngine();
+extern void RemoveEngine();
+extern void BackupEngine();
+
+extern TWP_RESULT CbSend(struct TWPRequest *pRequest, TWPResponseHandle hResponse,
+                         const void *pData, unsigned int uLength);
+extern TWP_RESULT CbRecv(struct TWPRequest *pRequest, void *pBuffer, unsigned int uBufferLength,
+                         unsigned int *puLength);
+extern TWP_RESULT CbSetUrl(struct TWPRequest *pRequest, const char *pszUrl, unsigned int uLength);
+extern TWP_RESULT CbSetMethod(struct TWPRequest *pRequest, TWPSubmitMethod Method);
+extern long GenerateRandomNumber();
+extern void DestoryTestDirs(void);
+extern int CreateTestDirs(void);
+extern int DetermineWpEngineLib(void);
+
+extern jmp_buf WPJmpBuf;
+
+#ifdef __cplusplus 
+}
+#endif
+
+#endif /* TWPTEST_H */
diff --git a/test/TWPTestUtils.c b/test/TWPTestUtils.c
new file mode 100644 (file)
index 0000000..03be548
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include "TWPImpl.h"
+#include "XMHttp.h"
+#include "TWPTest.h"
+
+
+#if !defined(MIN)
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+
+#define TWP_SECLIB_DEFAULT "/opt/usr/apps/EmbkcJFK7q/lib/plugin/libwpengine.so"
+#define TWP_SECLIB_DCM "/opt/usr/apps/docomo6004/lib/plugin/libwpengine.so"
+
+
+static void ReportTestCase(TestCase *pCtx);
+static void CallSys(const char *pszCmd);
+static void PutTestRoot(char *pszRoot);
+static char *GetTestRoot(void);
+static char *GetBackupDir(void);
+static void PutBackupDir(char *pszBackupDir);
+
+
+const char *pszSecWpLibPath = TWP_SECLIB_DEFAULT;
+int TestCasesCount = 0;
+int Success = 0;
+int Failures = 0;
+jmp_buf WPJmpBuf;
+TWPResponseHandle hAResponse = NULL;
+
+
+/**
+ * Output for test case result.
+ */
+static void ReportTestCase(TestCase *pCtx)
+{
+    char *pszTmp;
+
+    LOG_OUT("@@@@@@@@@@@@@@@@@@@@@@@@\n");
+
+    LOG_OUT("@ID: TC_SEC_WP_%s\n", pCtx->szAPIName);
+    pszTmp = strchr(pCtx->szAPIName, '_');
+    *pszTmp = 0;
+    LOG_OUT("@API Name: %s\n", pCtx->szAPIName);
+    *pszTmp = '_';
+
+    TestCasesCount++;
+}
+
+
+/**
+ * Test case constructor.
+ */
+void TestCaseCtor(TestCase *pCtx, const char *pszAPI)
+{
+
+    strncpy(pCtx->szAPIName, pszAPI, sizeof(pCtx->szAPIName) - 1);
+}
+
+
+/**
+ * Test case destructor.
+ */
+void TestCaseDtor(TestCase *pCtx)
+{
+
+    ReportTestCase(pCtx);
+    Success++;
+    
+    extern TRequest Request;
+    if (Request.ResponseBody != NULL)
+        free(Request.ResponseBody);
+
+    Request.pszUrl = NULL;
+    Request.ResponseLength = 0;
+    Request.ResponseBody = NULL;
+    
+    Request.pData = NULL;
+    Request.uLength = 0;
+    Request.uRead = 0;
+    Request.ResponseBytesRead = 0;
+}
+
+
+void BackupEngine()
+{
+    char *pszRoot = GetTestRoot(), *pszCommand;
+
+    if (pszRoot != NULL)
+    {
+        if (asprintf(&pszCommand, "mkdir %s/backup", pszRoot) == -1)
+        {
+            PutTestRoot(pszRoot);
+            return;
+        }
+
+        CallSys(pszCommand);
+        free(pszCommand);
+
+        if (asprintf(&pszCommand, "cp -f /opt/usr/share/sec_plugin/libwpengine.so %s/backup", pszRoot) == -1)
+        {
+            PutTestRoot(pszRoot);
+            return;
+        }
+        CallSys(pszCommand);
+        free(pszCommand);
+        PutTestRoot(pszRoot);
+    }
+}
+
+
+void RestoreEngine()
+{
+    char *pszRoot = GetTestRoot(), *pszCommand;
+
+    if (pszRoot != NULL)
+    {
+        if (asprintf(&pszCommand, "ln -s %s /opt/usr/share/sec_plugin/libwpengine.so", pszSecWpLibPath) < 0)
+        {
+            PutTestRoot(pszRoot);
+            return;
+        }
+
+        CallSys(pszCommand);
+        free(pszCommand);
+        PutTestRoot(pszRoot);
+    }
+}
+
+
+void RemoveEngine()
+{
+    char *pszRoot = GetTestRoot(), *pszCommand;
+
+    BackupEngine();
+    if (pszRoot != NULL)
+    {
+        if (asprintf(&pszCommand, "rm -f /opt/usr/share/sec_plugin/libwpengine.so") < 0)
+        {
+            PutTestRoot(pszRoot);
+            return;
+        }
+        CallSys(pszCommand);
+        free(pszCommand);
+        PutTestRoot(pszRoot);
+    }
+}
+
+
+int DetermineWpEngineLib()
+{
+    struct stat statBuf;
+    if (stat(TWP_SECLIB_DEFAULT, &statBuf) == 0 &&
+        S_ISREG(statBuf.st_mode))
+        pszSecWpLibPath = TWP_SECLIB_DEFAULT;
+    else if (stat(TWP_SECLIB_DCM, &statBuf) == 0 &&
+        S_ISREG(statBuf.st_mode))
+        pszSecWpLibPath = TWP_SECLIB_DCM;
+    else
+    {
+        LOG_OUT("WpEngine was not found \n");
+        return -1;
+    }
+    LOG_OUT("WpEngine found = '%s'\n", pszSecWpLibPath);
+    return 0;
+}
+
+long GenerateRandomNumber()
+{
+
+       return rand();
+}
+
+
+TWP_RESULT CbSetUrl(struct TWPRequest *pRequest, const char *pszUrl, unsigned int uLength)
+{
+    TRequest *pCtx = (TRequest *) pRequest;
+
+    // LOG_OUT("url is: %s\n", pszUrl);
+    if (pCtx->pszUrl != NULL)
+        free((void *) pCtx->pszUrl);
+    pCtx->pszUrl = strdup(pszUrl);
+
+    return pCtx->pszUrl ? TWP_SUCCESS : TWP_NOMEM;
+}
+
+
+TWP_RESULT CbSetMethod(struct TWPRequest *pRequest, TWPSubmitMethod Method)
+{
+
+    return Method == TWPPOST ? TWP_SUCCESS : TWP_INVALID_PARAMETER;
+}
+
+
+static int CbHttpWrite(void *pPrivate, void const *pData, int iSize)
+{
+    TRequest *pCtx = (TRequest *) pPrivate;
+    char *pTmp = NULL;
+
+    // LOG_OUT("[http] recv data\n");
+    pTmp = (char *) realloc(pCtx->ResponseBody, pCtx->ResponseLength + iSize);
+    if (pTmp == NULL)
+    {
+        LOG_OUT("failed to alloc mem\n");
+        return 0;
+    }
+
+    pCtx->ResponseBody = pTmp;
+    memcpy(pCtx->ResponseBody + pCtx->ResponseLength, pData, iSize);
+    pCtx->ResponseLength += iSize;
+
+    return iSize;
+}
+
+
+static int CbHttpRead(void *pPrivate, void *pData, int iSize)
+{
+    TRequest *pCtx = (TRequest *) pPrivate;
+    unsigned int uToRead = MIN(iSize, pCtx->uLength - pCtx->uRead);
+
+    // LOG_OUT("[http] send data\n");
+
+    memcpy(pData, pCtx->pData + pCtx->uRead, uToRead);
+
+    return (int) uToRead;
+}
+
+
+static long CbHttpGetSize(void *pPrivate)
+{
+    TRequest *pCtx = (TRequest *) pPrivate;
+
+    // LOG_OUT("[http] get size\n");
+
+    return (long) (pCtx->uLength - pCtx->uRead);
+}
+
+
+static TWP_RESULT HttpSend(TRequest *pCtx, const void *pData, unsigned int uLength)
+{
+    int iRet;
+    XmHttpCallbacks HttpCb;
+
+    if (pCtx->hHttp == INVALID_XM_HTTP_HANDLE)
+    {
+        pCtx->hHttp = XmHttpOpen();
+        if (pCtx->hHttp == NULL)
+            return TWP_NOMEM;
+    }
+
+    HttpCb.pfWrite = CbHttpWrite;
+    HttpCb.pfRead = CbHttpRead;
+    HttpCb.pfGetSize = CbHttpGetSize;
+
+    pCtx->pData = (char *) pData;
+    pCtx->uLength = uLength;
+
+    iRet = XmHttpExec(pCtx->hHttp, "POST", pCtx->pszUrl, &HttpCb, pCtx);
+
+    return iRet == 0 ? TWP_SUCCESS : TWP_ERROR;
+}
+
+
+TWP_RESULT CbSend(struct TWPRequest *pRequest, TWPResponseHandle hResponse,
+                  const void *pData, unsigned int uLength)
+{
+
+    // For a-sync call
+    hAResponse = hResponse;
+    return HttpSend((TRequest *) pRequest, pData, uLength);
+}
+
+
+TWP_RESULT CbRecv(struct TWPRequest *pRequest, void *pBuffer, unsigned int uBufferLength,
+                  unsigned int *puLength)
+{
+    TRequest* pCtx = (TRequest*) pRequest;
+    size_t BytesToCopy = 0;
+
+    if ( pCtx->ResponseBytesRead < pCtx->ResponseLength )
+    {
+       BytesToCopy = uBufferLength < (pCtx->ResponseLength - pCtx->ResponseBytesRead) ? uBufferLength : (pCtx->ResponseLength - pCtx->ResponseBytesRead);
+       memcpy(pBuffer, (void*) (pCtx->ResponseBody + pCtx->ResponseBytesRead), BytesToCopy);
+       pCtx->ResponseBytesRead += BytesToCopy;
+    }
+
+    *puLength = (int) BytesToCopy;
+
+    return TWP_SUCCESS;
+}
+
+
+static void CallSys(const char *pszCmd)
+{
+    int iRet = 0;
+    iRet = system(pszCmd);
+    if (iRet != 0)
+    {
+        // LOG_OUT("failed to exe command: %x\n", (int) pszCmd);
+    }
+}
+
+
+/**
+ * Test framework helper function: get content files' root path.
+ */
+static char *GetTestRoot(void)
+{
+    int iLen, iEnvLen;
+    char *pszRoot = NULL, *pszEnv = getenv("TWP_CONTENT_PATH");
+
+    if (pszEnv != NULL &&
+        (iEnvLen = strlen(pszEnv)) > 0)
+    {
+        iLen = iEnvLen;
+        iLen += 64; /* Reserved 64 bytes for PID. */
+        iLen += strlen(TWP_TEST_CONTENT_DIR);
+        pszRoot = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszRoot != NULL)
+        {
+            if (pszEnv[iEnvLen - 1] != '/')
+                snprintf(pszRoot, iLen, "%s/%d/%s", pszEnv, (int) getpid(),
+                         TWP_TEST_CONTENT_DIR);
+            else
+                snprintf(pszRoot, iLen, "%s%d/%s", pszEnv, (int) getpid(),
+                         TWP_TEST_CONTENT_DIR);
+        }
+    }
+    else
+    {
+        iLen = sizeof("./") + 64; /* Reserved 64 bytes for PID. */
+        pszRoot = (char *) calloc(iLen + 1, sizeof(char));
+        if (pszRoot != NULL)
+        {
+            snprintf(pszRoot, iLen, "./%d", (int) getpid());
+        }
+    }
+
+    return pszRoot;
+}
+
+
+static void PutTestRoot(char *pszRoot)
+{
+
+    if (pszRoot != NULL)
+        free(pszRoot);
+}
+
+
+int CreateTestDirs(void)
+{
+    int iLen, iRet = -1;
+    char *pszCommand, *pszRoot = GetTestRoot(), *pszEnv, *pszBackup;
+
+    if (pszRoot != NULL)
+    {
+        pszBackup = GetBackupDir();
+        if (pszBackup != NULL)
+        {
+            iLen = MAX(strlen(pszRoot) * 2, strlen(pszBackup));
+            iLen += 64; /* Reserved for "mkdir -p", "cp -f " */
+            pszCommand = (char *) calloc(iLen + 1, sizeof(char));
+            if (pszCommand != NULL)
+            {
+                snprintf(pszCommand, iLen, "mkdir -p %s", pszRoot);
+                CallSys(pszCommand);
+                pszCommand[0] = 0;
+
+                snprintf(pszCommand, iLen, "mkdir -p %s", pszBackup);
+                CallSys(pszCommand);
+                pszCommand[0] = 0;
+
+                pszEnv = getenv("TWP_CONTENT_PATH");
+                if (pszEnv == NULL)
+                    pszEnv = "./";
+                if (pszEnv[strlen(pszEnv) - 1] == '/')
+                    snprintf(pszCommand, iLen, "cp -f %s* %s", pszEnv, pszRoot);
+                else
+                    snprintf(pszCommand, iLen, "cp -f %s/* %s", pszEnv, pszRoot);
+                CallSys(pszCommand);
+
+                free(pszCommand);
+
+                iRet = 0;
+            }
+            PutBackupDir(pszBackup);
+        }
+        PutTestRoot(pszRoot);
+    }
+
+    return iRet;
+}
+
+
+void DestoryTestDirs(void)
+{
+    int iLen, iEnvLen;
+    char *pszCommand, *pszEnv = getenv("TWP_CONTENT_PATH");
+
+    if (pszEnv == NULL || strlen(pszEnv) == 0)
+        pszEnv = "./";
+    iEnvLen = strlen(pszEnv);
+    iLen = iEnvLen;
+    iLen += 72; /* Reserved for "rm -rf" and PID */
+    pszCommand = (char *) calloc(iLen + 1, sizeof(char));
+    if (pszCommand != NULL)
+    {
+        if (pszEnv[iEnvLen - 1] == '/')
+            snprintf(pszCommand, iLen, "rm -rf %s%d", pszEnv, (int) getpid());
+        else
+            snprintf(pszCommand, iLen, "rm -rf %s/%d", pszEnv, (int) getpid());
+        CallSys(pszCommand);
+        free(pszCommand);
+    }
+}
+
+
+static char *GetBackupDir(void)
+{
+    int iLen, iEnvLen;
+    char *pszEnv = getenv("TWP_CONTENT_PATH"), *pszPath;
+
+    if (pszEnv == NULL || strlen(pszEnv) == 0)
+        pszEnv = "./";
+    iEnvLen = strlen(pszEnv);
+    iLen = iEnvLen;
+    iLen += strlen(TWP_BACKUP_CONTENT_DIR);
+    iLen += 64; /* Reserved for slash char and PID. */
+    pszPath = (char *) calloc(iLen + 1, sizeof(char));
+
+    if (pszPath)
+    {
+        if (pszEnv[iEnvLen - 1] == '/')
+            snprintf(pszPath, iLen, "%s%d/%s", pszEnv, (int) getpid(),
+                     TWP_BACKUP_CONTENT_DIR);
+        else
+            snprintf(pszPath, iLen, "%s/%d/%s", pszEnv, (int) getpid(),
+                     TWP_BACKUP_CONTENT_DIR);
+    }
+
+    return pszPath;
+}
+
+
+static void PutBackupDir(char *pszBackupDir)
+{
+
+    if (pszBackupDir != NULL)
+        free(pszBackupDir);
+}
+
diff --git a/test/UrlInfo.h b/test/UrlInfo.h
new file mode 100644 (file)
index 0000000..b5e081a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef URL_INFO_H
+#define URL_INFO_H
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+#define MAX_CATEGORIES 8
+
+#define URL_0_0 "http://www.screensavers.com"
+#define URL_1_0 "http://www.google.com"
+#define URL_2_0 "http://www.targetingnow.com/delivery"
+#define URL_3_0 "www.zcrack.com"
+
+TWPCategories CATEGORIES_0_0_1[2] =
+{
+    TWP_Malicioussites,
+    TWP_OverallRiskHigh
+};
+
+TWPCategories CATEGORIES_0_0_0[2] =
+{
+    TWP_Pharmacy,
+    TWP_Restaurants
+};
+
+TWPCategories CATEGORIES_0_0_2[2] =
+{
+    TWP_Malicioussites,
+    TWP_OverallRiskHigh
+};
+
+TWPCategories VIOLATIONS_0_0_2[2] =
+{
+    TWP_Malicioussites,
+    TWP_OverallRiskHigh
+};
+
+
+TWPCategories CATEGORIES_0_0_3[3] =
+{
+    TWP_Malicioussites,
+    TWP_Maliciousdownloads,
+    TWP_OverallRiskHigh
+};
+
+#define SCORE_0_0 127
+#define CATEGORY_0_0_0 TWP_Pharmacy
+#define CATEGORY_0_0_1 TWP_OverallRiskHigh
+
+#ifdef __cplusplus 
+}
+#endif
+
+#endif /* URL_INFO_H */
+
diff --git a/test/XMHttp.c b/test/XMHttp.c
new file mode 100644 (file)
index 0000000..5aee19c
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <malloc.h>
+
+#include "XMPHttp.h"
+
+
+typedef struct XmHttpCtx_struct
+{
+    XmPHttpCtx PCtx;
+} XmHttpCtx;
+
+
+XM_HTTP_HANDLE XmHttpOpen()
+{
+    XmHttpCtx *pCtx;
+
+    if ((pCtx = (XmHttpCtx *) malloc(sizeof(XmHttpCtx))) == NULL)
+        return INVALID_XM_HTTP_HANDLE;
+    if (XmPHttpInit(&pCtx->PCtx) < 0)
+    {
+        free(pCtx);
+        return INVALID_XM_HTTP_HANDLE;
+    }
+
+    return (XM_HTTP_HANDLE) pCtx;
+}
+
+
+void XmHttpClose(XM_HTTP_HANDLE hHTTP)
+{
+    XmHttpCtx *pCtx = (XmHttpCtx *) hHTTP;
+
+    XmPHttpCleanup(&pCtx->PCtx);
+    free(pCtx);
+}
+
+
+int XmHttpExec(XM_HTTP_HANDLE hHTTP, char const *pszMethod, char const *pszURL,
+               XmHttpCallbacks *pHCB, void *pPrivate)
+{
+    XmHttpCtx *pCtx = (XmHttpCtx *) hHTTP;
+
+    return XmPHttpExec(&pCtx->PCtx, pszMethod, pszURL, pHCB, pPrivate);
+}
+
diff --git a/test/XMHttp.h b/test/XMHttp.h
new file mode 100644 (file)
index 0000000..e6a8d24
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_XMHTTP_H)
+#define _XMHTTP_H
+
+#if defined(__cplusplus)
+#define EXTERNC_BEGIN extern "C" {
+#define EXTERNC_END }
+#define EXTERNC extern "C"
+#else
+#define EXTERNC_BEGIN
+#define EXTERNC_END
+#define EXTERNC
+#endif
+
+#define XMHANDLE(n)         struct n##_struct { int iDummy; }; typedef struct n##_struct *n
+
+XMHANDLE(XM_HTTP_HANDLE);
+
+#define INVALID_XM_HTTP_HANDLE ((XM_HTTP_HANDLE) 0)
+
+typedef struct XmHttpCallbacks_struct
+{
+    int (*pfWrite)(void *pPrivate, void const *pData, int iSize);
+    int (*pfRead)(void *pPrivate, void *pData, int iSize);
+    long (*pfGetSize)(void *pPrivate);
+} XmHttpCallbacks;
+
+
+EXTERNC_BEGIN;
+
+XM_HTTP_HANDLE XmHttpOpen();
+void XmHttpClose(XM_HTTP_HANDLE hHTTP);
+int XmHttpExec(XM_HTTP_HANDLE hHTTP, char const *pszMethod, char const *pszURL,
+               XmHttpCallbacks *pHCB, void *pPrivate);
+
+EXTERNC_END;
+
+#endif
+
diff --git a/test/XMPHttp.c b/test/XMPHttp.c
new file mode 100644 (file)
index 0000000..26681e5
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdarg.h>
+
+#include <XMPHttp.h>
+
+#define XME_HTTP_TIMEOUT 11300
+#define XME_HTTP_SELECT 11301
+#define XME_HTTP_SKREAD 11302
+#define XME_HTTP_SKWRITE 11303
+#define XME_HTTP_SETSOCKOPT 11003
+#define XME_HTTP_DISCONNECT 11005
+#define XME_HTTP_UNKNOWN_HOST 11006
+#define XME_HTTP_CONNECT 11007
+
+#define SOCK_STD_CONTIMEO 60
+#define SOCK_STD_RCVTIMEO 60
+#define SOCK_STD_SNDTIMEO 60
+#define HTTP_DEFAULT_PORT 80
+#define HTTPS_DEFAULT_PORT 443
+#define CONTLEN_HEADER "Content-Length:"
+#define CONTENC_HEADER "Transfer-Encoding:"
+#define CHUNKED_ENCODED(s) (strcasecmp(s, "chunked") == 0)
+#define XM_HTTP_HEADERS "XM_HTTP_HEADERS"
+#define XM_HTTP_VERSION "XM_HTTP_VERSION"
+#define XM_SKRECV_TIMEO "XM_NET_RECVTIMEO"
+#define XM_SKSEND_TIMEO "XM_NET_SENDTIMEO"
+#define XM_SKCONN_TIMEO "XM_NET_CONNTIMEO"
+
+
+#define SSTREAM_BUFFER_SIZE 4096
+
+#define URL_PROTO_HTTP  1
+#define URL_PROTO_HTTPS 2
+
+#if !defined(INADDR_NONE)
+#define INADDR_NONE ((XmUInt32) -1)
+#endif
+
+#define URL_PARSE_INIT  { 0, NULL, 0, NULL, NULL }
+
+#define PHTTP_MIN(a, b) ((a) < (b) ? (a): (b))
+#define PHTTP_SKIPSPACE(p) for(; *(p) == ' ' || *(p) == '\t'; (p)++)
+#define PHTTP_CSTRSIZE(s) (sizeof(s) - 1)
+
+#define PHTTP_DBGPRINT(c, args) do { if ((c)->iPHttpDebug) XmPHttpDbgPrintf args; } while (0)
+
+#define PHTTP_ENVGET(c, s) getenv(s)
+#define PHTTP_ENVFREE(e) free(e)
+
+
+#define INVALID_SOCKET (-1)
+#define closesocket(s) close(s)
+#define PHTTP_INPROGRESS(SockFd) (errno == EINPROGRESS || errno == EWOULDBLOCK)
+
+typedef int SOCKET;
+
+
+struct PHttpUrl
+{
+    int iProto;
+    char const *pszHost;
+    int iPort;
+    char const *pszDoc;
+    char const *pszUrl;
+};
+
+struct SStream
+{
+    XmPHttpCtx *pCtx;
+    SOCKET SockFd;
+    int iReadTimeo, iWriteTimeo;
+    int iIndex;
+    int iInBuffer;
+    char Buffer[SSTREAM_BUFFER_SIZE];
+};
+
+
+static int XmPHttpDbgPrintf(char const *pszFmt, ...)
+{
+    int iPrintRes;
+    va_list Args;
+
+    va_start(Args, pszFmt);
+    iPrintRes = vfprintf(stderr, pszFmt, Args);
+    va_end(Args);
+
+    return iPrintRes;
+}
+
+static int XmPHttpGetIntEnv(XmPHttpCtx *pCtx, char const *pszVar, int iDefault)
+{
+    int iValue = iDefault;
+    char *pszValue;
+
+    if ((pszValue = (char *) PHTTP_ENVGET(pCtx, pszVar)) != NULL)
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] %s environment is '%s'\n", pszVar, pszValue));
+
+        iValue = atoi(pszValue);
+        PHTTP_ENVFREE(pszValue);
+    }
+
+    return iValue;
+}
+
+static int XmPHttpSkBlocking(SOCKET SockFd, int iOn)
+{
+    int iFlags, iError;
+
+    if ((iFlags = fcntl(SockFd, F_GETFL, 0)) == -1)
+        return -XME_HTTP_SETSOCKOPT;
+    if (iOn)
+        iError = fcntl(SockFd, F_SETFL, iFlags & ~O_NONBLOCK);
+    else
+        iError = fcntl(SockFd, F_SETFL, iFlags | O_NONBLOCK);
+
+    return iError == -1 ? -XME_HTTP_SETSOCKOPT: 0;
+}
+
+static int XmPHttpSkConnect(SOCKET SockFd, struct sockaddr *pAddr, int iAddrSize,
+                            int iTimeout)
+{
+    int iError;
+
+    if ((iError = XmPHttpSkBlocking(SockFd, 0)) < 0)
+        return iError;
+    if (connect(SockFd, pAddr, iAddrSize) != 0)
+    {
+        struct timeval TV;
+        fd_set FdSet;
+
+        if (!PHTTP_INPROGRESS(SockFd))
+            return -XME_HTTP_CONNECT;
+        FD_ZERO(&FdSet);
+        FD_SET(SockFd, &FdSet);
+        TV.tv_sec = iTimeout;
+        TV.tv_usec = 0;
+        if (select((int) SockFd + 1, NULL, &FdSet, NULL, &TV) < 0)
+            return -XME_HTTP_SELECT;
+        if (!FD_ISSET(SockFd, &FdSet))
+            return -XME_HTTP_TIMEOUT;
+    }
+
+    return XmPHttpSkBlocking(SockFd, 1);
+}
+
+static int XmPHttpSkRead(SOCKET SockFd, void *pData, int iSize, int iTimeout)
+{
+    int iRead;
+    struct timeval TV;
+    fd_set FdSet;
+
+    FD_ZERO(&FdSet);
+    FD_SET(SockFd, &FdSet);
+    TV.tv_sec = iTimeout;
+    TV.tv_usec = 0;
+    if (select((int) SockFd + 1, &FdSet, NULL, NULL, &TV) < 0)
+        return -XME_HTTP_SELECT;
+    if (!FD_ISSET(SockFd, &FdSet))
+        return -XME_HTTP_TIMEOUT;
+    if ((iRead = recv(SockFd, pData, iSize, 0)) < 0)
+        return -XME_HTTP_SKREAD;
+    else if (iRead == 0)
+        return -XME_HTTP_DISCONNECT;
+
+    return iRead;
+}
+
+static int XmPHttpSkWrite(SOCKET SockFd, void const *pData, int iSize, int iTimeout)
+{
+    int iWrite;
+    struct timeval TV;
+    fd_set FdSet;
+
+    FD_ZERO(&FdSet);
+    FD_SET(SockFd, &FdSet);
+    TV.tv_sec = iTimeout;
+    TV.tv_usec = 0;
+    if (select((int) SockFd + 1, NULL, &FdSet, NULL, &TV) < 0)
+        return -XME_HTTP_SELECT;
+    if (!FD_ISSET(SockFd, &FdSet))
+        return -XME_HTTP_TIMEOUT;
+    if ((iWrite = send(SockFd, pData, iSize, 0)) < 0)
+        return -XME_HTTP_SKWRITE;
+
+    return iWrite;
+}
+
+static SOCKET XmPHttpSocket(XmPHttpCtx *pCtx)
+{
+    SOCKET SockFd;
+
+    if ((SockFd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Socket creation failed\n"));
+        return INVALID_SOCKET;
+    }
+
+    return SockFd;
+}
+
+int XmPHttpInit(XmPHttpCtx *pCtx)
+{
+    pCtx->iPHttpDebug = 1;
+    pCtx->iPHttpConnTimeo = XmPHttpGetIntEnv(pCtx, XM_SKCONN_TIMEO, SOCK_STD_CONTIMEO);
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Library initialization succeeded\n"));
+
+    return 0;
+}
+
+void XmPHttpCleanup(XmPHttpCtx *pCtx)
+{
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Library cleanup done\n"));
+}
+
+static struct SStream *XmPHttpStreamAttach(XmPHttpCtx *pCtx, SOCKET SockFd)
+{
+    struct SStream *pStream;
+
+    if ((pStream = (struct SStream *) malloc(sizeof(struct SStream))) == NULL)
+        return NULL;
+
+    pStream->pCtx = pCtx;
+    pStream->SockFd = SockFd;
+    pStream->iIndex = 0;
+    pStream->iInBuffer = 0;
+    pStream->iReadTimeo = XmPHttpGetIntEnv(pCtx, XM_SKRECV_TIMEO, SOCK_STD_RCVTIMEO);
+    pStream->iWriteTimeo = XmPHttpGetIntEnv(pCtx, XM_SKSEND_TIMEO, SOCK_STD_SNDTIMEO);
+
+    return pStream;
+}
+
+static void XmPHttpStreamClose(struct SStream *pStream)
+{
+    closesocket(pStream->SockFd);
+    PHTTP_DBGPRINT(pStream->pCtx, ("[phttp] Socket closed: sock=%u\n", pStream->SockFd));
+    free(pStream);
+}
+
+static int XmPHttpStreamBRefil(struct SStream *pStream)
+{
+    XmPHttpCtx *pCtx = pStream->pCtx;
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Reading socket: sock=%u\n", pStream->SockFd));
+    pStream->iIndex = 0;
+
+    pStream->iInBuffer = XmPHttpSkRead(pStream->SockFd, pStream->Buffer,
+                                       SSTREAM_BUFFER_SIZE, pStream->iReadTimeo);
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Socket read done: sock=%u recv=%d\n", pStream->SockFd,
+                          pStream->iInBuffer));
+    if (pStream->iInBuffer < 0)
+        PHTTP_DBGPRINT(pCtx, ("[phttp] error is %d\n", (unsigned int) -pStream->iInBuffer));
+
+    return pStream->iInBuffer;
+}
+
+static char *XmPHttpRdLine(char *pszLine, int iSize, struct SStream *pStream)
+{
+    int iLnSize, iTxSize;
+    XmPHttpCtx *pCtx = pStream->pCtx;
+    char *pszNL;
+
+    for (iLnSize = 0, iSize--; iLnSize < iSize;)
+    {
+        if (pStream->iIndex >= pStream->iInBuffer &&
+            XmPHttpStreamBRefil(pStream) <= 0)
+            break;
+
+        if ((pszNL = (char *) memchr(pStream->Buffer + pStream->iIndex, '\n',
+                                     pStream->iInBuffer - pStream->iIndex)) != NULL)
+        {
+            iTxSize = PHTTP_MIN(iSize - iLnSize,
+                                (int) (pszNL - (pStream->Buffer + pStream->iIndex) + 1));
+            memcpy(pszLine + iLnSize, pStream->Buffer + pStream->iIndex, iTxSize);
+            pStream->iIndex += iTxSize;
+            iLnSize += iTxSize;
+            break;
+        }
+        else
+        {
+            iTxSize = PHTTP_MIN(iSize - iLnSize, pStream->iInBuffer - pStream->iIndex);
+            memcpy(pszLine + iLnSize, pStream->Buffer + pStream->iIndex, iTxSize);
+            pStream->iIndex += iTxSize;
+            iLnSize += iTxSize;
+        }
+    }
+
+    if (iLnSize == 0)
+        return NULL;
+
+    for (; iLnSize > 0 && (pszLine[iLnSize - 1] == '\r' ||
+                           pszLine[iLnSize - 1] == '\n'); iLnSize--);
+    pszLine[iLnSize] = '\0';
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Line read: sock=%u\n"
+                          "\t'%s'\n", pStream->SockFd, pszLine));
+
+    return pszLine;
+}
+
+static int XmPHttpRead(char *pData, int iSize, struct SStream *pStream)
+{
+    int iRead = 0, iRxSize;
+    XmPHttpCtx *pCtx = pStream->pCtx;
+
+    if (pStream->iIndex < pStream->iInBuffer)
+    {
+        iRxSize = PHTTP_MIN(iSize, pStream->iInBuffer - pStream->iIndex);
+        memcpy(pData, pStream->Buffer + pStream->iIndex, iRxSize);
+        pStream->iIndex += iRxSize;
+        iRead += iRxSize;
+    }
+    while (iRead < iSize)
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Reading socket: sock=%u\n", pStream->SockFd));
+
+        iRxSize = XmPHttpSkRead(pStream->SockFd, pData + iRead,
+                                iSize - iRead, pStream->iReadTimeo);
+
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Socket read done: sock=%u recv=%d\n", pStream->SockFd,
+                              iRxSize));
+        if (iRxSize < 0)
+            break;
+        iRead += iRxSize;
+    }
+
+    return iRead;
+}
+
+static int XmPHttpPrintf(struct SStream *pStream, char const *pszFmt, ...)
+{
+    int iSize, iSent, iTxSize;
+    XmPHttpCtx *pCtx = pStream->pCtx;
+    va_list Args;
+    char szBuffer[4096];
+
+    va_start(Args, pszFmt);
+
+    iSize = vsnprintf(szBuffer, sizeof(szBuffer) - 1, pszFmt, Args);
+
+    va_end(Args);
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Sending ...\n"
+                          "(\n"
+                          "%s"
+                          ")\n", szBuffer));
+    for (iSent = 0; iSent < iSize;)
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Writing socket: sock=%u\n", pStream->SockFd));
+
+        iTxSize = XmPHttpSkWrite(pStream->SockFd, szBuffer + iSent,
+                                 iSize - iSent, pStream->iWriteTimeo);
+
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Socket write done: sock=%u send=%d\n", pStream->SockFd,
+                              iTxSize));
+        if (iTxSize < 0)
+            break;
+        iSent += iTxSize;
+    }
+
+    return iSize;
+}
+
+static int XmPHttpWrite(char const *pData, int iSize, struct SStream *pStream)
+{
+    int iSent, iTxSize;
+    XmPHttpCtx *pCtx = pStream->pCtx;
+
+    for (iSent = 0; iSent < iSize;)
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Writing socket: sock=%u\n", pStream->SockFd));
+
+        iTxSize = XmPHttpSkWrite(pStream->SockFd, pData + iSent,
+                                 iSize - iSent, pStream->iWriteTimeo);
+
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Socket write done: sock=%u send=%d\n", pStream->SockFd,
+                              iTxSize));
+        if (iTxSize < 0)
+            break;
+        iSent += iTxSize;
+    }
+
+    return iSize;
+}
+
+static struct SStream *XmPHttpConnect(XmPHttpCtx *pCtx, char const *pszServer, int iPort)
+{
+    int iError;
+    SOCKET SockFd;
+    struct hostent *pHE;
+    struct SStream *pStream;
+    struct in_addr InAddr;
+    struct sockaddr_in SAIn;
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Resolving server name: server='%s'\n", pszServer));
+    if ((InAddr.s_addr = inet_addr(pszServer)) == INADDR_NONE)
+    {
+        if ((pHE = gethostbyname(pszServer)) == NULL)
+        {
+            PHTTP_DBGPRINT(pCtx, ("[phttp] Server name resolve error: server='%s' error = %d\n", pszServer, errno));
+            return NULL;
+        }
+
+        memcpy(&InAddr.s_addr, pHE->h_addr_list[0], pHE->h_length);
+    }
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Server name resolved: server='%s'\n", pszServer));
+
+    if ((SockFd = XmPHttpSocket(pCtx)) == INVALID_SOCKET)
+        return NULL;
+
+    memset(&SAIn, 0, sizeof(SAIn));
+    memcpy(&SAIn.sin_addr, &InAddr.s_addr, 4);
+    SAIn.sin_port = htons((short int) iPort);
+    SAIn.sin_family = AF_INET;
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Connecting to remote server: server='%s'\n", pszServer));
+    if ((iError = XmPHttpSkConnect(SockFd, (struct sockaddr *) &SAIn, sizeof(SAIn),
+                                   pCtx->iPHttpConnTimeo)) < 0)
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Connect failed: server='%s'\n", pszServer));
+        closesocket(SockFd);
+        return NULL;
+    }
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Connect succeeded: server='%s'\n", pszServer));
+
+    if ((pStream = XmPHttpStreamAttach(pCtx, SockFd)) == NULL)
+    {
+        closesocket(SockFd);
+        return NULL;
+    }
+
+    return pStream;
+}
+
+static int XmPHttpSendRequest(struct SStream *pStream, char const *pszServer,
+                              char const *pszReq, char const *pszDoc,
+                              char const * const *ppszHdrs,
+                              XmHttpCallbacks *pHCB, void *pPrivate)
+{
+    int i, iCurr;
+    long lReqSize, lRead;
+    XmPHttpCtx *pCtx = pStream->pCtx;
+    char *pszHttpVer;
+    char TxBuff[512];
+
+    if ((lReqSize = pHCB->pfGetSize(pPrivate)) < 0)
+        return -1;
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Outbound data length retrieved: size=%ld\n",
+                          lReqSize));
+
+    pszHttpVer = (char *) PHTTP_ENVGET(pCtx, XM_HTTP_VERSION);
+    if (XmPHttpPrintf(pStream, "%s %s %s\r\n", pszReq, pszDoc,
+                      pszHttpVer != NULL ? pszHttpVer: "HTTP/1.0") < 0 ||
+        XmPHttpPrintf(pStream, "Host: %s\r\n", pszServer) < 0)
+    {
+        PHTTP_ENVFREE(pszHttpVer);
+        return -1;
+    }
+    PHTTP_ENVFREE(pszHttpVer);
+    if (ppszHdrs)
+        for (i = 0; ppszHdrs[i]; i++)
+            if (XmPHttpPrintf(pStream, "%s\r\n", ppszHdrs[i]) < 0)
+                return -1;
+
+    if (XmPHttpPrintf(pStream, "Content-Length: %ld\r\n\r\n", lReqSize) < 0)
+        return -1;
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Reading and sending outbound data: sock=%u\n",
+                          pStream->SockFd));
+    for (lRead = 0; lRead < lReqSize;)
+    {
+        iCurr = (int) PHTTP_MIN(lReqSize - lRead, sizeof(TxBuff));
+        if (pHCB->pfRead(pPrivate, TxBuff, iCurr) != iCurr ||
+            XmPHttpWrite(TxBuff, iCurr, pStream) != iCurr)
+            return -1;
+        lRead += iCurr;
+    }
+    PHTTP_DBGPRINT(pCtx, ("[phttp] Outbound data sent: sock=%u\n", pStream->SockFd));
+
+    return 0;
+}
+
+static void XmPHttpParseInit(struct PHttpUrl *pPU)
+{
+    memset(pPU, 0, sizeof(*pPU));
+}
+
+static int XmPHttpParseUrl(XmPHttpCtx *pCtx, struct PHttpUrl *pPU, char const *pszUrl)
+{
+    char *pszDUrl = strdup(pszUrl), *pszTmp;
+
+    if (pszDUrl == NULL)
+    {
+        return -1;
+    }
+
+    memset(pPU, 0, sizeof(*pPU));
+    pPU->pszUrl = pszDUrl;
+    if (!strncasecmp(pszDUrl, "http://", 7))
+        pPU->iProto = URL_PROTO_HTTP, pszDUrl += 7, pPU->iPort = HTTP_DEFAULT_PORT;
+    else if (!strncasecmp(pszDUrl, "https://", 8))
+        pPU->iProto = URL_PROTO_HTTPS, pszDUrl += 8, pPU->iPort = HTTPS_DEFAULT_PORT;
+    else
+        pPU->iProto = URL_PROTO_HTTP, pPU->iPort = HTTP_DEFAULT_PORT;
+
+    pPU->pszHost = pszDUrl;
+
+    if ((pszTmp = strchr(pszDUrl, ':')) != NULL)
+    {
+        *pszTmp++ = '\0';
+        if (!isdigit(*pszTmp))
+        {
+            free((char *) pPU->pszUrl);
+            memset(pPU, 0, sizeof(*pPU));
+            return -1;
+        }
+        pPU->iPort = atoi(pszTmp);
+        pszDUrl = pszTmp;
+    }
+
+    if ((pszTmp = strchr(pszDUrl, '/')) != NULL)
+    {
+        pPU->pszDoc = strdup(pszTmp);
+        *pszTmp++ = '\0';
+    }
+    else
+        pPU->pszDoc = strdup("/");
+
+    if (pPU->pszDoc == NULL)
+    {
+        free((char *) pPU->pszUrl);
+        memset(pPU, 0, sizeof(*pPU));
+        return -1;
+    }
+
+    return 0;
+}
+
+static void XmPHttpParseFree(struct PHttpUrl *pPU)
+{
+    free((char *) pPU->pszUrl);
+    free((char *) pPU->pszDoc);
+    memset(pPU, 0, sizeof(*pPU));
+}
+
+static int XmPHttpReadChunked(struct SStream *pStream, XmHttpCallbacks *pHCB,
+                              void *pPrivate)
+{
+    int iCkSize;
+    // XmPHttpCtx *pCtx = pStream->pCtx;
+    char RxBuff[512];
+
+    do
+    {
+        if (!XmPHttpRdLine(RxBuff, sizeof(RxBuff) - 1, pStream))
+            return -1;
+        if (!sscanf(RxBuff, "%d", &iCkSize))
+            return -1;
+        if (iCkSize)
+        {
+            int iSize, iRead;
+
+            for (iSize = 0; iSize < iCkSize;)
+            {
+                iRead = PHTTP_MIN(iCkSize - iSize, sizeof(RxBuff));
+                if (XmPHttpRead(RxBuff, iRead, pStream) != iRead)
+                    return -1;
+                if (pHCB && pHCB->pfWrite &&
+                    pHCB->pfWrite(pPrivate, RxBuff, iRead) != iRead)
+                    return -1;
+                iSize += iRead;
+            }
+        }
+    } while (iCkSize);
+    while (XmPHttpRdLine(RxBuff, sizeof(RxBuff) - 1, pStream))
+        if (strlen(RxBuff) == 0)
+            break;
+
+    return 0;
+}
+
+static int XmPHttpReadResponse(struct SStream *pStream, XmHttpCallbacks *pHCB,
+                               void *pPrivate)
+{
+    int iHttpRCode, iChunked = 0, iValidRCode;
+    long lContLen = -1;
+    char *pszValue;
+    XmPHttpCtx *pCtx = pStream->pCtx;
+    char szBuffer[512];
+
+    if (!XmPHttpRdLine(szBuffer, sizeof(szBuffer) - 1, pStream))
+        return -1;
+
+    PHTTP_DBGPRINT(pCtx, ("[phttp] HTTP response: sock=%u resp='%s'\n", pStream->SockFd, szBuffer));
+    if (!sscanf(szBuffer, "%*s %d %*s", &iHttpRCode))
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] Wrong HTTP response: sock=%u resp='%s'\n", pStream->SockFd, szBuffer));
+        return -1;
+    }
+
+    // printf("[XMPHTTP] : HTTP CODE = %d\n", iHttpRCode);
+    iValidRCode = iHttpRCode == 200 || iHttpRCode == 204;
+    if ((iHttpRCode >= 100 && iHttpRCode < 200) || iHttpRCode == 204 || iHttpRCode == 304)
+        lContLen = 0;
+
+    while (XmPHttpRdLine(szBuffer, sizeof(szBuffer) - 1, pStream) != NULL)
+    {
+        PHTTP_DBGPRINT(pCtx, ("[phttp] HTTP header: sock=%u hdr='%s'\n", pStream->SockFd, szBuffer));
+        if (strlen(szBuffer) == 0)
+            break;
+        if (!strncasecmp(szBuffer, CONTLEN_HEADER, PHTTP_CSTRSIZE(CONTLEN_HEADER)))
+        {
+            pszValue = szBuffer + PHTTP_CSTRSIZE(CONTLEN_HEADER);
+            PHTTP_SKIPSPACE(pszValue);
+            lContLen = atol(pszValue);
+        }
+        else if (!strncasecmp(szBuffer, CONTENC_HEADER, PHTTP_CSTRSIZE(CONTENC_HEADER)))
+        {
+            pszValue = szBuffer + PHTTP_CSTRSIZE(CONTENC_HEADER);
+            PHTTP_SKIPSPACE(pszValue);
+            iChunked = CHUNKED_ENCODED(pszValue);
+        }
+    }
+    if (lContLen >= 0)
+    {
+        int iRead;
+        long lSize;
+
+        for (lSize = 0; lSize < lContLen;)
+        {
+            iRead = (int) PHTTP_MIN(lContLen - lSize, sizeof(szBuffer));
+            if (XmPHttpRead(szBuffer, iRead, pStream) != iRead)
+                return -1;
+            if (iValidRCode && pHCB->pfWrite &&
+                pHCB->pfWrite(pPrivate, szBuffer, iRead) != iRead)
+                return -1;
+            lSize += iRead;
+        }
+    }
+    else if (iChunked)
+    {
+        if (XmPHttpReadChunked(pStream, iValidRCode ? pHCB: NULL, pPrivate) < 0)
+            return -1;
+    }
+    else
+    {
+        int iRead;
+        long lSize;
+
+        for (lSize = 0;;)
+        {
+            if ((iRead = XmPHttpRead(szBuffer, sizeof(szBuffer), pStream)) <= 0)
+                break;
+            if (iValidRCode && pHCB->pfWrite &&
+                pHCB->pfWrite(pPrivate, szBuffer, iRead) != iRead)
+                return -1;
+            lSize += iRead;
+        }
+    }
+
+    return iValidRCode ? 0: -1;
+}
+
+static char **XmPHttpHdrSplit(char const *pszStr)
+{
+    int i, j, k, iNumStrs;
+    void *pMemBlk;
+    char **ppszPtrs;
+    char *pszDupStr;
+
+    for (i = 0, iNumStrs = 1; pszStr[i]; i++)
+        if (pszStr[i] == '|')
+            iNumStrs++;
+    if ((pMemBlk = malloc(i + 1 +
+                          (iNumStrs + 1) * sizeof(char *))) == NULL)
+        return NULL;
+    ppszPtrs = (char **) pMemBlk;
+    pszDupStr = (char *) pMemBlk + (iNumStrs + 1) * sizeof(char *);
+    memcpy(pszDupStr, pszStr, i + 1);
+    for (i = j = 0, k = -1; pszDupStr[i]; i++)
+        if (pszDupStr[i] == '|')
+        {
+            if (k >= 0)
+                ppszPtrs[j++] = pszDupStr + k;
+            pszDupStr[i] = '\0';
+            k = -1;
+        }
+        else if (k < 0)
+            k = i;
+    if (k >= 0)
+        ppszPtrs[j++] = pszDupStr + k;
+    ppszPtrs[j] = NULL;
+
+    return ppszPtrs;
+}
+
+int XmPHttpExec(XmPHttpCtx *pCtx, char const *pszMethod, char const *pszUrl,
+                XmHttpCallbacks *pHCB, void *pPrivate)
+{
+    char *pszEnv = NULL;
+    char **ppszHdrs = NULL;
+    struct SStream *pStream;
+    struct PHttpUrl PU;
+
+    XmPHttpParseInit(&PU);
+    if (XmPHttpParseUrl(pCtx, &PU, pszUrl) < 0)
+        return -1;
+    if ((pStream = XmPHttpConnect(pCtx, PU.pszHost, PU.iPort)) == NULL)
+    {
+
+        XmPHttpParseFree(&PU);
+        return -1;
+    }
+    if ((pszEnv = (char *) PHTTP_ENVGET(pCtx, XM_HTTP_HEADERS)) != NULL &&
+        (ppszHdrs = XmPHttpHdrSplit(pszEnv)) == NULL)
+    {
+
+        PHTTP_ENVFREE(pszEnv);
+        XmPHttpStreamClose(pStream);
+        XmPHttpParseFree(&PU);
+        return -1;
+    }
+    PHTTP_ENVFREE(pszEnv);
+
+    if (XmPHttpSendRequest(pStream, PU.pszHost, pszMethod, PU.pszDoc,
+                           (char const * const *) ppszHdrs, pHCB, pPrivate) < 0 ||
+        XmPHttpReadResponse(pStream, pHCB, pPrivate) < 0)
+    {
+
+        if (ppszHdrs != NULL)
+            free(ppszHdrs);
+        XmPHttpStreamClose(pStream);
+        XmPHttpParseFree(&PU);
+        return -1;
+    }
+    free(ppszHdrs);
+    XmPHttpStreamClose(pStream);
+    XmPHttpParseFree(&PU);
+
+    return 0;
+}
+
diff --git a/test/XMPHttp.h b/test/XMPHttp.h
new file mode 100644 (file)
index 0000000..08ce721
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+    Copyright (c) 2013, McAfee, Inc.
+    
+    All rights reserved.
+    
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+    
+    Redistributions of source code must retain the above copyright notice, this list
+    of conditions and the following disclaimer.
+    
+    Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+    
+    Neither the name of McAfee, Inc. nor the names of its contributors may be used
+    to endorse or promote products derived from this software without specific prior
+    written permission.
+    
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+    OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_XMPOSIXHTTP_H)
+#define _XMPOSIXHTTP_H
+
+#include "XMHttp.h"
+
+
+typedef struct XmPHttpCtx_struct
+{
+    int iPHttpConnTimeo;
+    int iPHttpDebug;
+} XmPHttpCtx;
+
+
+EXTERNC_BEGIN;
+
+int XmPHttpInit(XmPHttpCtx *pCtx);
+void XmPHttpCleanup(XmPHttpCtx *pCtx);
+int XmPHttpExec(XmPHttpCtx *pCtx, char const *pszMethod, char const *pszUrl,
+                XmHttpCallbacks *pHCB, void *pPrivate);
+
+EXTERNC_END;
+
+#endif
+
diff --git a/test/db/sdb/2E b/test/db/sdb/2E
new file mode 100755 (executable)
index 0000000..0ef15c1
Binary files /dev/null and b/test/db/sdb/2E differ
diff --git a/test/db/xlm/2D b/test/db/xlm/2D
new file mode 100755 (executable)
index 0000000..3a55780
--- /dev/null
@@ -0,0 +1 @@
+éàðé\94\85\85\85¡¥¥¥¥¥¥¥\99¥¥¥'ª¥¥¡¥¥¥eª¥¥\91¥¥¥¢¥¥¥Qª¥¥¡¥¥¥ ¥¥¥]ª¥¥Q¥¥¥\8c»»»\90¥%¥\88%¥¥¥¥ ­¥ã¥\90¥\ 6¥¸¥\9e¢\1e¡¥¥¥ ­%ꥸ%¤¥¥¥¸¤»\90¥* \88%¥¥¥¥ ­%ý¥¸%¥¥¥¥\8bû¥¸%§¥¥¥\8bû¥¸%¦¥¥¥\8bû¥¸%¡¥¥¥\93¸%¥¥¥¥¸¤»\90¥* \88;¥¥¥¥ ­¥Ü¥®»\93¯®¥¥¥\93\8a¤¸%\89¤¥¥¬»¥º$»¥¸¥»¸$\89¤¥¥¯´¥¥¥¸º¥\95¤\93¸¥»¸¤º©¥¤¥¥µ¥ã䥥¤¥«¥§¤ÙÙ¥¥'¥\93\8a¯¸¯¥\90¥Î¨\88%¤¥¥¥ ­%x¥¸¥¯¯¨¥¥¥\95¯\93\88%¥¥¥¥ ­¥\96¤¸¦¥\88$¥¥¥¥ ­¥\9f¤\84¥¤¤\87$¤§¥¥¥ \85¥\9f¤¸%¤¥¥¥\85¤¤§\88'ù¥¥¥ ­¥ä¤\80¥¥\83¤¤\88¤¦ ­%ª¤¸%¤¥¥¥\93¸%§¥¥¥\93¸%¦¥¥¥\93\80¤¤¸§¥\8c¥¥¥\93\90¥¥¥\88%¥¥¥¥ ­%#¤¸¥»\90¥d¥¯¼¥¥¥¸$¥¥¥¥¸¥»\90¥ß¥\88%¥¥¥¥ ­%#¤\82\1e\9e[ZZZ\90¥ú¥\93\8a¯\8a®\8a©\8a¨\8a«\8aª\8aµ\8a´\8a·\8a\8a±\8a°\8a³\8a²\8a\9e¸0¥¥¥¥¸3¥¥¥¥¸1¥¥¥¥\85¥¥¯\85奮¡¥\85奩­¥\85奨©¥\85奫µ¥\85奪±¥\84%µ½¥¥¥\84µ´ª¸¥´\82\1e\9e^ZZZ¯»¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦¸¶§²¥·\886¥¥¥¥ ­%q¦\88·¯ ­%q¦¸¥´¸$¤¥¥¥\82\1e\9e^ZZZ¯\81¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦¸±¤¸¥±¸$¥¥¥¥°®¥\82\1e\9e^ZZZ¯\83¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦\88)¥¥¥¥ ­¥s§¬°©¸¥±¸¤°¸§©\82\1e\9e^ZZZ¯\82¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦\88¤© ­%q¦¸%¥¥¥¥«¥°©²\88²¨ ­%q¦\88*¥¥¥¥ ­¥Õ¦¸¥±¸$¥¥¥¥°«¥\82\1e\9e^ZZZ¯\83¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦¬³ª¸¥±¸¤³¸§ª\82\1e\9e^ZZZ¯\82¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦\88¤ª ­%q¦¸¥³¸¤µ¸§ª\82\1e\9e^ZZZ¯¶¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦¸¥±\82\1e\9e^ZZZ¯\80¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦¸%¤¥¥¥¸¤´\90¥* ¸¥´\82\1e\9e^ZZZ¯®¥¥¥¢\1e¡¥¥¥ ­¥q¦\88%¥¥¥¥ ­%q¦¸%¥¥¥¥¸¤´\90¥* \881¥¥¥¥ ­¥H¦¸¥±¯\80¥¥¥¸1¥¥¥¥\880¥¥¥¥ ­¥_¦®°¸0¥¥¥¥\883¥¥¥¥ ­¥¨¡®³¸3¥¥¥¥\95\9e\95²\95³\95°\95±\95\95·\95´\95µ\95ª\95«\95¨\95©\95®\95¯\93\82\1e\9e^ZZZ¯¿¥¥¥¢\1e¡¥¥¥ ­¥ø¡\88%¤¥¡¥ ­%ø¡¸%¤¥¥¥\8bÆ¡¸%¥¥¥¥\93\8a¯¸/¥¥¥¥\82\1e\9e^ZZZ¯\86¥¥¥¢\1e¡¥¥¥ ­¥³ \88%\1c®¥¥ µ¥³ \88$\1c®¥¥ µ¥³ ¸/µ¥¥¥¬¯¯¤¥\97 ¥¥¸¤¯¸'µ¥¥¥\82\1e\9e^ZZZ¯\91¥¥¥¢\1e¡¥¥¥ ­¥¨ \88%¥¥¥¥ ­%³ ¤¥å ¥¥¸¤¯¸'¢¥¥¥\82\1e\9e^ZZZ¯²¥¥¥¢\1e¡¥¥¥ ­¥¨ \88%¥¥¥¥ ­%¨ ¸%¤¥¥¥\8b¹ ¸%¥¥¥¥\8b¹ ¸%§¥¥¥\88/¥¥¥¥ ­¥\8c ®¯¸/¥¥¥¥\95¯\93õéäñãê÷èúñüõà¥ÄËÁ×ÊÌÁ¥¤¤# ¥¥¸'­¥¥¥\82\1e\9e^ZZZ¯²¥¥¥¢\1e¡¥¥¥ ­¥Ú \88%¥¥¥¥ ­%Ú ¸%¤¥¥¥\8b  ¸%¥¥¥¥\93\8aÖÜÖÑÀÈ\8a¥\8a¯\8a®¸¯¥¸®¤\90¥\97¡\88%¥¥¥¥ ­¥\89£\90¥Á¡\88%¥¥¥¥ ­¥\89£¸¥®\90¥í \88%¥¥¥¥ ­¥\89£\90¥Ô¢\88%¥¥¥¥ ­¥\89£\88/¥¥¥¥ ­%¬£¤¥Æ£¥¥¸$ ¥¥¥\82\1e\9e^ZZZ¯ª¥¥¥¢\1e¡¥¥¥ ­¥\89£\8b\89£¤¥\94£¥¥¸$ ¥¥¥\82\1e\9e^ZZZ¯ª¥¥¥¢\1e¡¥¥¥ ­¥\89£\95®\95¯\93\8aÖÜÖÑÀÈ\8aÇÌË\8aÈÊÐËÑ\85\88Ê\85×Ò\89×ÀÈÊÐËÑ\85\8aÁÀÓ\8aËÐÉÉ\85\8aÖÜÖÑÀÈ¥\8aÖÜÖÑÀÈ\8aÇÌË\8aÈÊÐËÑ\85\88Ê\85×Ê\89×ÀÈÊÐËÑ\85\8aÁÀÓ\8aËÐÉÉ\85\8aÖÜÖÑÀÈ¥\8a¯\8a®\8a©\8a¨\8a«\8aª¸¯¥¸®¤¸)¥¥¥¥¸¥¯\82\1e\9e^ZZZ¯°¥¥¥¢\1e¡¥¥¥ ­¥à¢¸¨¥¸¥®\82\1e\9e^ZZZ¯°¥¥¥¢\1e¡¥¥¥ ­¥à¢¸«¥\80««\84¨ª«¬©ªº$©¥¸¥©¸¤¯¸'ZZZZ\82\1e\9e^ZZZ¯³¥¥¥¢\1e¡¥¥¥ ­¥à¢\84©¥¨¸¤®¸'ZZZZ\82\1e\9e^ZZZ¯³¥¥¥¢\1e¡¥¥¥ ­¥à¢¸¥©¸¤ª\8bÁ¢\88)¥¥¥¥ ­¥÷¢®©¸)¥¥¥¥¸%¥¥¥¥¸$¥¥¥¥\95ª\95«\95¨\95©\95®\95¯\93\8a\9e\8a¯\8a®\8a©\8a¨\8a«\8aª\8aµ\8a´\8a·\8a\8a±\8a°\8a³¸/¥¥¥¥¸.¥¥¥¥¸+¥¥¥¥¸*¥¥¥¥¸5¥¥¥¥¸0¥¥¥¥¸%¥¥¥¥\82\1e\9e^ZZZ¯\96¥¥¥¢\1e¡¥¥¥ ­¥\89®¸¯¥\82\1e\9e^ZZZ¯°¥¥¥¢\1e¡¥¥¥ ­¥\89®¸©¥\80©©¸%¥¥¥¥\82\1e\9e^ZZZ¯\96¥¥¥¢\1e¡¥¥¥ ­¥\89®¸®¥\82\1e\9e^ZZZ¯°¥¥¥¢\1e¡¥¥¥ ­¥\89®¸¨¥\80¨¨¤¥D®¥¥¸¤®\90¥0£\88%¥¥¥¥ ­¥\89®¸ª¥¸·¤¤¥V®¥¥¸¤¯\90¥0£\88%¥¥¥¥ ­¥\89®¸«¥¸´¤¤¥¦©¥¥¸¤¯\90¥0£\88%¥¥¥¥ ­¥\89®¸µ¥¸¶¤¸¥¯¸$£¥¥¥\82\1e\9e^ZZZ¯\81¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸±¤¸¥±\82\1e\9e^ZZZ¯\80¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸1¥¥¥¥¸¥¯\82\1e\9e^ZZZ¯»¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®\88'¥¥¥¥ ­%\89®¸¥µ¸$ ¥¥¥\82\1e\9e^ZZZ¯ª¥¥¥¢\1e¡¥¥¥ ­¥\89®¸¥¯¸$§¥¥¥\82\1e\9e^ZZZ¯\81¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸±¤¸¥±¸¤ª¸§·\82\1e\9e^ZZZ¯\8d¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸¥±°·¥\82\1e\9e^ZZZ¯\8c¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸¥±\82\1e\9e^ZZZ¯\80¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸1¥¥¥¥¸¥«¸$ ¥¥¥\82\1e\9e^ZZZ¯ª¥¥¥¢\1e¡¥¥¥ ­¥\89®¸¥®\82\1e\9e^ZZZ¯»¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®\88'¥¥¥¥ ­%\89®¸3¥¤¥¥¬°³¸¥®¸$¤¥¥¥\82\1e\9e^ZZZ¯\81¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸±¤¸¥±¸¤°¸§³\82\1e\9e^ZZZ¯\82¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®¸¥±\82\1e\9e^ZZZ¯\80¥¥¥¢\1e¡¥¥¥ ­¥\89®\88%¥¥¥¥ ­%\89®©°³¥¥\85¥ã䥥§¥½¥»¥¤¯ÐÌÁ\98\95\8d×ÊÊÑ¥¥§¤\8c\8c¤¥'¥¢\1e¤¥¥¥ ­¥\89®\82\1e\9e[ZZZ©°³¥¥\85¥ã䥥§¥½¥»¥¤¯ÂÌÁ\98\95\8d×ÊÊÑ¥¥§¤\8c\8c¤¥'¥¢\1e¤¥¥¥ ­¥\89®\82\1e\9e[ZZZ¸%¤¥¥¥\8b\97®¸%¥¥¥¥\8a¥¸¥¯¸$¥¥¥¥¯®¥¥¥¸¥®¸$¥¥¥¥¯®¥¥¥\95¥\88/¥¥¥¥ ­¥ú®®¯¸/¥¥¥¥\88.¥¥¥¥ ­¥×®®®¸.¥¥¥¥\88+¥¥¥¥ ­¥ ®®«¸+¥¥¥¥\88*¥¥¥¥ ­¥=®®ª¸*¥¥¥¥\885¥¥¥¥ ­¥\ e®®µ¸5¥¥¥¥\880¥¥¥¥ ­¥\e®®°¸0¥¥¥¥\95³\95°\95±\95\95·\95´\95µ\95ª\95«\95¨\95©\95®\95¯\95\9e\93\8aÖÜÖÑÀÈ\8aÇÌË\8aÌÁ\85\9b\85¥\8aÖÜÖÑÀÈ\8aÇÌË\8aÖÍ\85¥\8aÖÜÖÑÀÈ\8aÇÌË\8aÆÍÈÊÁ\85\93\95\95\85¥\8a¯\8a®\8a©\8a¨\8a«\8aª\8aµ\8a´\8a·\8a\8a±\8a°¸7¥¥¥¥¸6¥¥¥¥\85¥¥¯\85奮¡¥\85奩­¥\85奨©¥\85奫µ¥\85奪±¥\85奵½¥\84%´¹¥¥¥\88\9f¯ ­%°¨\88)¥¥¥¥ ­¥\b©\88\9f® µ¥°¨¬·©¸\99®\96©·¥\88¥© ­%°¨¸%¥¥¥¥«¥·©±\88±¨ ­%°¨\88*¥¥¥¥ ­¥@©\88\9f« µ¥°¨¬¶ª¸\99«\96ª¶¥\88¥ª ­%°¨¸%¥¥¥¥«¥¶ª°\88°µ ­%°¨¸¥´\82\1e\9e^ZZZ¯\8b¥¥¥¢\1e¡¥¥¥ ­¥°¨\8d\1e\9e¤¥¥¥¢\1e%¥¥¥ ­¥°¨\90¥é¤\887¥¥¥¥ ­¥\87¨®·¸7¥¥¥¥\886¥¥¥¥ ­¥\90¨®¶¸6¥¥¥¥\95°\95±\95\95·\95´\95µ\95ª\95«\95¨\95©\95®\95¯\93\8d\1e\9e¤¥¥¥¢\1e%¥¥¥ ­¥Ï¨\90¥é¤¥\8a\99\8a¯¸\19¥¥¥¥\88\1f¡¥¥¥ \85¥2¨\94¥¯\88/Úàéã ­%2¨¸%¤¥¥¥\8b8¨¸%¥¥¥¥\95¯\95\99\93\8a\99\8a¯\8a®\8a©\8a¨\8a«\8aª\8aµ\8a´\8a·\8a\8a±\8a°¸(ZZZZ¸«\9f\8cªªª\8cµµµ\8c¥¥¥¤¤ ª¥¥¯\94¥¥¥¢¥¥ ­%¯«¢¤¤ ­¥¯«\88'­¥¥¥ ­¥¯«\8c¨¨¨\85¥¤«\85夰¡¥®¤\8bD«¸\19\9d¥¥¥\94¥¯\94¥®¢¯¯ ­¥D«\88/\ 5#¤¥ µ¥\8a«¸/\ 5#¤¥¸)å9¥¥¬µ©¢µµ ­¥D«¢¯¯ ­¥\f«¸·¯\88\82¥¥ µ¥ù«¸7µ\82¥¥\8e7¶§¸\99®\96¶µ©\88¶© ­%D«\87¯¯·\84®®¶¸´µ¢·· ­¥å«\85¥´±\88«± µ¥4«¸«±\88ª± ½%9«¸ª±\844´¡¥¥¥\83··\8bß«\8c¨¨¨\88ª\9f µ¥\1d«¸ª\9f\87ª°«\8c¥¥¥¤¤ ª¥¥¤§±ª¥¥º¥§«ºå§°¡¥¸&­¥¥¥¯\95¥¥¥¸¥¨¸¤«¸§°\95°\95±\95\95·\95´\95µ\95ª\95«\95¨\95©\95®\95¯\95\99\93áàýúöñ÷ìëâúõêö¥¥¥¥¥¥¥¥¥\8a\99\8a§¸§¥\88\99\9f \85%åª\97¤¤\83§§\88'¥¥¥¥ ­%\86ª\87¥¥§\95§\95\99\93\8c»»»\90¥%¥\88%¥¥¥¥ ­¥Ôª\90¥\ 6¥¸¥\9e¢\1e¡¥¥¥ ­%Ôª\8c¥¥¥\8bÒª¸%¤¥¥¥®»\8c»»»\93¥¥¥¥¥¥¥¥¥¥ú¥¥¥ß¥¥¥d¥¥¥%¥¥¥E¥¥¥é¤¥¥.¤¥¥¿©¥¥ñ¨¥¥\a¨¥¥¹ª¥¥àª¥¥¤¥¥¥àª¥¥ªìÖìËä×ÆÍÌÓÀãÌÉÀ¥¹ª¥¥¨êÓÀ×Ò×ÌÑÀáÄÑÄ¥\a¨¥¥´âÀÑáÀÝöÑ×ÌËÂ÷ÄËÂÀ¥ñ¨¥¥ªçÐÉÎãÌËÁäËÁàÝÌÑ¥¿©¥¥®çÐÉÎõ×ÊÆÀÖÖ¥.¤¥¥µæÉÀÄË÷ÀÉÄÑÀÁãÌÉÀ¥é¤¥¥µæÉÀÄËöÆÄËËÀÁãÌÉÀ¥E¥¥¥®âÀÑãÌÉÀëÄÈÀ¥%¥¥¥®âÀÑãÌÉÀõÄÑÍ¥d¥¥¥®îÌÉÉõ×ÊÆÀÖ֥ߥ¥¥¯áÀÉÀÑÀãÌÉÀ¥ú¥¥¥¯÷ÀÕÄÌ×àÝÌÑ¥¥¥¥¥¯÷ÀÕÄÌ×ìËÌÑ¥
\ No newline at end of file
diff --git a/test/scripts/Test.sh b/test/scripts/Test.sh
new file mode 100755 (executable)
index 0000000..71a7a7e
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+function setupsigdb () {
+    rm /opt/usr/apps/$1/data/database/sdb/*
+    rm /opt/usr/apps/$1/data/database/xlm/*
+    cp ./db/sdb/* /opt/usr/apps/$1/data/database/sdb/
+    cp ./db/xlm/* /opt/usr/apps/$1/data/database/xlm/
+    chown 5000:5000 /opt/usr/apps/$1/data/database/sdb/2E
+    chown 5000:5000 /opt/usr/apps/$1/data/database/xlm/2D
+    chsmack -a "$1" /opt/usr/apps/$1/data/database/sdb/2E
+    chsmack -a "$1" /opt/usr/apps/$1/data/database/xlm/2D
+    return 0
+}
+
+echo "preparing test contents ..."
+rm -rf testcontents-1
+cp -rf testcontents testcontents-1
+
+echo "setup environment ..."
+export XM_HOME=testcontents-1
+export TCS_CONTENT_PATH=testcontents-1
+export TCS_ENABLE_SCANREPAIR="yes"
+export TCS_SCAN_TYPE="1"
+
+
+if [ -d /opt/usr/apps/EmbkcJFK7q ]; then
+    echo "MMS found"
+    setupsigdb "EmbkcJFK7q"
+elif [ -d /opt/usr/apps/docomo6004 ]; then
+    echo "Anshin scan found"
+    setupsigdb "docomo6004"
+else
+    echo "Engine not found"
+    exit 1
+fi
+
+echo "start to run test cases ..."
+tcstest
+echo "end of test cases ..."
+
+echo "cleanup test contents ..."
+rm -rf testcontents-1
+
diff --git a/test/scripts/WPTest.sh b/test/scripts/WPTest.sh
new file mode 100755 (executable)
index 0000000..1ea4cbb
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+echo "setup environment ..."
+mkdir testcontents-1
+export TWP_CONTENT_PATH=testcontents-1
+
+if [ -d /opt/usr/apps/EmbkcJFK7q ]; then
+    echo "Found MMS"
+    chsmack -e EmbkcJFK7q `which twptest` 
+elif [ -d /opt/usr/apps/docomo6004 ]; then
+    echo "Found Anshin Scan"
+    chsmack -e docomo6004 `which twptest` 
+else
+    echo "Engine not found"
+    exit 1
+fi
+
+
+echo "start to run test cases ..."
+twptest
+echo "end of test cases ..."
+
+echo "cleanup test contents ..."
+rm -rf testcontents-1
+
diff --git a/test/testcontents/tcs-testfile-0.buf b/test/testcontents/tcs-testfile-0.buf
new file mode 100755 (executable)
index 0000000..0133fe6
--- /dev/null
@@ -0,0 +1 @@
+tcs-testfile-0.1.unknown
diff --git a/test/testcontents/tcs-testfile-0.class b/test/testcontents/tcs-testfile-0.class
new file mode 100755 (executable)
index 0000000..845db37
Binary files /dev/null and b/test/testcontents/tcs-testfile-0.class differ
diff --git a/test/testcontents/tcs-testfile-0.email b/test/testcontents/tcs-testfile-0.email
new file mode 100755 (executable)
index 0000000..09fe547
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
+<HTML>
+<HEAD>
+  <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
+  <META NAME="GENERATOR" CONTENT="GtkHTML/3.15.5">
+</HEAD>
+<BODY>
+tcs-testfile-0.email
+</BODY>
+</HTML>
diff --git a/test/testcontents/tcs-testfile-0.html b/test/testcontents/tcs-testfile-0.html
new file mode 100755 (executable)
index 0000000..1fb6fce
--- /dev/null
@@ -0,0 +1,10 @@
+<html>
+    <head>
+        <title>Page for Testing</title>
+    </head>
+    <body>
+        <h1 class="title"><a name="name"></a>tcs-testfile-0.html</h1>
+    </body>
+</html>
+
+
diff --git a/test/testcontents/tcs-testfile-0.js b/test/testcontents/tcs-testfile-0.js
new file mode 100755 (executable)
index 0000000..ac75e8e
--- /dev/null
@@ -0,0 +1,2 @@
+tcs-testfile-0.js
+
diff --git a/test/testcontents/tcs-testfile-0.multiple b/test/testcontents/tcs-testfile-0.multiple
new file mode 100755 (executable)
index 0000000..4000e80
--- /dev/null
@@ -0,0 +1,2 @@
+tcs-testfile-0.0.unknown
+tcs-testfile-0.1.unknown
diff --git a/test/testcontents/tcs-testfile-0.phone b/test/testcontents/tcs-testfile-0.phone
new file mode 100755 (executable)
index 0000000..32597f5
--- /dev/null
@@ -0,0 +1 @@
++0000000000000
diff --git a/test/testcontents/tcs-testfile-0.txt b/test/testcontents/tcs-testfile-0.txt
new file mode 100755 (executable)
index 0000000..20af3b9
--- /dev/null
@@ -0,0 +1,2 @@
+tcs-testfile-0.txt
+
diff --git a/test/testcontents/tcs-testfile-0.url b/test/testcontents/tcs-testfile-0.url
new file mode 100755 (executable)
index 0000000..fa7d3cb
--- /dev/null
@@ -0,0 +1 @@
+http://ftp.tcs-testfile-0.url.com/test/test
diff --git a/test/testcontents/tcs-testfile-0.z b/test/testcontents/tcs-testfile-0.z
new file mode 100755 (executable)
index 0000000..4965cae
--- /dev/null
@@ -0,0 +1,2 @@
+tcs-testfile-0.z
+
diff --git a/test/testcontents/tcs-testfile-1.buf b/test/testcontents/tcs-testfile-1.buf
new file mode 100755 (executable)
index 0000000..fb2fc18
--- /dev/null
@@ -0,0 +1,5 @@
+TIZEN TEST FILE:
+TYPE: UNKNOWN
+Malware Name: Malware-fortest-1.6.0
+Variant Name: Variant-fortest-1.6.0
+END
\ No newline at end of file
diff --git a/test/testcontents/tcs-testfile-1.class b/test/testcontents/tcs-testfile-1.class
new file mode 100755 (executable)
index 0000000..07afa3f
Binary files /dev/null and b/test/testcontents/tcs-testfile-1.class differ
diff --git a/test/testcontents/tcs-testfile-1.email b/test/testcontents/tcs-testfile-1.email
new file mode 100755 (executable)
index 0000000..e4aea8c
Binary files /dev/null and b/test/testcontents/tcs-testfile-1.email differ
diff --git a/test/testcontents/tcs-testfile-1.html b/test/testcontents/tcs-testfile-1.html
new file mode 100755 (executable)
index 0000000..15c3db5
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />\r
+<title>infected web page</title>\r
+</head>\r
+<body>\r
+<th>Malware Name: Malware-fortest-1.0.0 <BR></th>\r
+<th>Variant Name: Variant-fortest-1.0.0</th>\r
+</body>\r
+</html>\r
diff --git a/test/testcontents/tcs-testfile-1.js b/test/testcontents/tcs-testfile-1.js
new file mode 100755 (executable)
index 0000000..bdcfe11
--- /dev/null
@@ -0,0 +1,3 @@
+document.write("<b> This is an infected javascript </b>" + "<BR>")\r
+document.write("<b> Malware Name: Malware-fortest-1.8.0 </b>" + "<BR>")\r
+document.write("<b> Variant Name: Variant-fortest-1.8.0 </b>")
\ No newline at end of file
diff --git a/test/testcontents/tcs-testfile-1.multiple b/test/testcontents/tcs-testfile-1.multiple
new file mode 100755 (executable)
index 0000000..b14c123
--- /dev/null
@@ -0,0 +1,8 @@
+TIZEN TEST FILE:
+TYPE: UNKNOWN
+Malware Name: Malware-fortest-1.6.0
+Variant Name: Variant-fortest-1.6.0
+
+Malware Name: Malware-fortest-1.5.0
+Variant Name: Variant-fortest-1.5.0
+END
\ No newline at end of file
diff --git a/test/testcontents/tcs-testfile-1.phone b/test/testcontents/tcs-testfile-1.phone
new file mode 100755 (executable)
index 0000000..c6d3439
--- /dev/null
@@ -0,0 +1,11 @@
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />\r
+<title>infected web page, phone number</title>\r
+</head>\r
+<body>\r
+<th>Malware Name: Malware-fortest-1.3.0 <BR></th>\r
+<th>Variant Name: Variant-fortest-1.3.0 <BR></th>\r
+<th>Call: +000 555 5555</th>\r
+</body>\r
+</html>\r
diff --git a/test/testcontents/tcs-testfile-1.txt b/test/testcontents/tcs-testfile-1.txt
new file mode 100755 (executable)
index 0000000..1d5ac0f
--- /dev/null
@@ -0,0 +1,5 @@
+TIZEN TEST FILE:
+TYPE: UNKNOWN
+Malware Name: Malware-fortest-1.4.0
+Variant Name: Variant-fortest-1.4.0
+END
\ No newline at end of file
diff --git a/test/testcontents/tcs-testfile-1.url b/test/testcontents/tcs-testfile-1.url
new file mode 100755 (executable)
index 0000000..1d7f452
--- /dev/null
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />\r
+<title>infected web page, URL</title>\r
+</head>\r
+<body>\r
+<a href= "http://InfectedURL/Malware-fortest-1.1.0.html">http://InfectedURL/Malware-fortest-1.1.0.html<BR></a>\r
+<a href= "http://InfectedURL/Variant-fortest-1.1.0.html">http://InfectedURL/Variant-fortest-1.1.0.html</a>\r
+</body>\r
+</html>\r
diff --git a/test/testcontents/tcs-testfile-1.z b/test/testcontents/tcs-testfile-1.z
new file mode 100755 (executable)
index 0000000..e87e9b6
Binary files /dev/null and b/test/testcontents/tcs-testfile-1.z differ