+#include "gdcmDebug.h"
+
+#include <iostream>
+#include <stdarg.h> // for va_list
+
+// For GetCurrentDate, GetCurrentTime
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
+#include <sys/timeb.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include <stdarg.h> //only included in implementation file
+#include <stdio.h> //only included in implementation file
+
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
+ #include <winsock.h> // for gethostname and gethostbyname and GetTickCount...
+// I haven't find a way to determine wether we need to under GetCurrentTime or not...
+// I think the best solution would simply to get rid of this problematic function
+// and use a 'less' common name...
+#if !defined(__BORLANDC__) || (__BORLANDC__ >= 0x0560)
+ #undef GetCurrentTime
+#endif
+#else
+ #include <unistd.h> // for gethostname
+ #include <netdb.h> // for gethostbyname
+#endif
+
+// For GetMACAddress
+#ifdef _WIN32
+ #include <snmp.h>
+ #include <conio.h>
+#else
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sys/types.h>
+#endif
+
+#ifdef CMAKE_HAVE_SYS_IOCTL_H
+ #include <sys/ioctl.h> // For SIOCGIFCONF on Linux
+#endif
+#ifdef CMAKE_HAVE_SYS_SOCKET_H
+ #include <sys/socket.h>
+#endif
+#ifdef CMAKE_HAVE_SYS_SOCKIO_H
+ #include <sys/sockio.h> // For SIOCGIFCONF on SunOS
+#endif
+#ifdef CMAKE_HAVE_NET_IF_H
+ #include <net/if.h>
+#endif
+#ifdef CMAKE_HAVE_NETINET_IN_H
+ #include <netinet/in.h> //For IPPROTO_IP
+#endif
+#ifdef CMAKE_HAVE_NET_IF_DL_H
+ #include <net/if_dl.h>
+#endif
+#if defined(CMAKE_HAVE_NET_IF_ARP_H) && defined(__sun)
+ // This is absolutely necessary on SunOS
+ #include <net/if_arp.h>
+#endif
+
+// For GetCurrentThreadID()
+#ifdef __linux__
+ #include <sys/types.h>
+ #include <linux/unistd.h>
+#endif
+#ifdef __sun
+ #include <thread.h>
+#endif
+
+namespace GDCM_NAME_SPACE
+{
+//-------------------------------------------------------------------------
+const std::string Util::GDCM_UID = "1.2.826.0.1.3680043.2.1143";
+std::string Util::RootUID = GDCM_UID;
+/*
+ * File Meta Information Version (0002,0001) shall contain a two byte OB
+ * value consisting of a 0x00 byte, followed by 0x01 byte, and not the
+ * value 0x0001 encoded as a little endian 16 bit short value,
+ * which would be the other way around...
+ */
+
+#if defined(GDCM_WORDS_BIGENDIAN) || defined(GDCM_FORCE_BIGENDIAN_EMULATION)
+ const uint16_t Util::FMIV = 0x0001;
+#else
+ const uint16_t Util::FMIV = 0x0100;
+#endif
+ uint8_t *Util::FileMetaInformationVersion = (uint8_t *)&FMIV;
+
+ std::string Util::GDCM_MAC_ADDRESS = GetMACAddress();
+
+//-------------------------------------------------------------------------
+// Public
+/**
+ * \brief Provide a better 'c++' approach for sprintf
+ * For example c code is:
+ * char result[2048]; // hope 2048 is enough
+ * sprintf(result, "%04x|%04x", group , elem);
+ *
+ * c++ code is
+ * std::ostringstream buf;
+ * buf << std::right << std::setw(4) << std::setfill('0') << std::hex
+ * << group << "|" << std::right << std::setw(4) << std::setfill('0')
+ * << std::hex << elem;
+ * buf.str();
+ *
+ * gdcm style code is
+ * string result;
+ * result = gdcm::Util::Format("%04x|%04x", group , elem);
+ */
+std::string Util::Format(const char *format, ...)
+{
+ char buffer[2048]; // hope 2048 is enough
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args); //might be a security flaw
+ va_end(args); // Each invocation of va_start should be matched
+ // by a corresponding invocation of va_end
+ // args is then 'undefined'
+ return buffer;
+}
+
+
+/**
+ * \brief Because not available in C++ (?)
+ * @param str string to check
+ * @param tokens std::vector to receive the tokenized substrings
+ * @param delimiters string containing the character delimitors
+
+ */
+void Util::Tokenize (const std::string &str,
+ std::vector<std::string> &tokens,
+ const std::string &delimiters)
+{
+ std::string::size_type lastPos = str.find_first_not_of(delimiters,0);
+ std::string::size_type pos = str.find_first_of (delimiters,lastPos);
+ while (std::string::npos != pos || std::string::npos != lastPos)
+ {
+ tokens.push_back(str.substr(lastPos, pos - lastPos));
+ lastPos = str.find_first_not_of(delimiters, pos);
+ pos = str.find_first_of (delimiters, lastPos);
+ }
+}
+
+/**
+ * \brief Because not available in C++ (?)
+ * Counts the number of occurences of a substring within a string
+ * @param str string to check
+ * @param subStr substring to count
+ */
+
+int Util::CountSubstring (const std::string &str,
+ const std::string &subStr)
+{
+ int count = 0; // counts how many times it appears
+ std::string::size_type x = 0; // The index position in the string
+
+ do
+ {
+ x = str.find(subStr,x); // Find the substring
+ if (x != std::string::npos) // If present
+ {
+ count++; // increase the count
+ x += subStr.length(); // Skip this word
+ }
+ }
+ while (x != std::string::npos);// Carry on until not present
+
+ return count;
+}
+
+/**
+ * \brief Checks whether a 'string' is printable or not (in order
+ * to avoid corrupting the terminal of invocation when printing)
+ * @param s string to check
+ */
+bool Util::IsCleanString(std::string const &s)
+{
+ for(unsigned int i=0; i<s.size(); i++)
+ {
+ if (!isprint((unsigned char)s[i]) )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * \brief Checks whether an 'area' is printable or not (in order
+ * to avoid corrupting the terminal of invocation when printing)
+ * @param s area to check (uint8_t is just for prototyping. feel free to cast)
+ * @param l area length to check
+ */
+bool Util::IsCleanArea(uint8_t *s, int l)
+{
+ for( int i=0; i<l; i++)
+ {
+ if (!isprint((unsigned char)s[i]) )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+/**
+ * \brief Weed out a string from the non-printable characters (in order
+ * to avoid corrupting the terminal of invocation when printing)
+ * @param s string to check (uint8_t is just for prototyping. feel free to cast)
+ */
+std::string Util::CreateCleanString(std::string const &s)
+{
+ std::string str = s;
+
+ for(unsigned int i=0; i<str.size(); i++)
+ {
+ if (!isprint((unsigned char)str[i]) )
+ {
+ str[i] = '.';
+ }
+ }
+ if (str.size() > 0 )
+ {
+ if (!isprint((unsigned char)s[str.size()-1]) )
+ {
+ if (s[str.size()-1] == 0 )
+ {
+ str[str.size()-1] = ' ';
+ }
+ }
+ }
+ return str;
+}
+/**
+ * \brief Replaces all special characters
+ * @param s string to modify
+ * @param rep replacement char
+ */
+void Util::ReplaceSpecChar(std::string &s, std::string &rep)
+{
+ unsigned int s_size = s.size();
+ for(unsigned int i=0; i<s_size; i++)
+ {
+ if (! ( s[i] == '.' || s[i] == '%' || s[i] == '_'
+ || (s[i] >= '+' && s[i] <= '-')
+ || (s[i] >= 'a' && s[i] <= 'z')
+ || (s[i] >= '0' && s[i] <= '9')
+ || (s[i] >= 'A' && s[i] <= 'Z')))
+ {
+ s.replace(i, 1, rep);
+ }
+ }
+ // deal with Dicom strings trailing '\0'
+ if(s[s_size-1] == rep.c_str()[0])
+ s.erase(s_size-1, 1);
+}
+
+
+/**
+ * \brief Weed out a string from the non-printable characters (in order
+ * to avoid corrupting the terminal of invocation when printing)
+ * @param s area to process (uint8_t is just for prototyping. feel free to cast)
+ * @param l area length to check
+ */
+std::string Util::CreateCleanString(uint8_t *s, int l)
+{
+ std::string str;
+
+ for( int i=0; i<l; i++)
+ {
+ if (!isprint((unsigned char)s[i]) )
+ {
+ str = str + '.';
+ }
+ else
+ {
+ str = str + (char )s[i];
+ }
+ }
+
+ return str;
+}
+/**
+ * \brief Add a SEPARATOR to the end of the name if necessary
+ * @param pathname file/directory name to normalize
+ */
+std::string Util::NormalizePath(std::string const &pathname)
+{
+/*
+ const char SEPARATOR_X = '/';
+ const char SEPARATOR_WIN = '\\';
+#ifdef _WIN32
+ const std::string SEPARATOR = "\\";
+#else
+ const std::string SEPARATOR = "/";
+#endif
+*/
+ std::string name = pathname;
+ int size = name.size();
+
+// if ( name[size-1] != SEPARATOR_X && name[size-1] != SEPARATOR_WIN )
+ if ( name[size-1] != GDCM_FILESEPARATOR )
+ {
+ name += GDCM_FILESEPARATOR;
+ }
+ return name;
+}
+
+/**
+ * \brief Get the (directory) path from a full path file name
+ * @param fullName file/directory name to extract Path from
+ */
+std::string Util::GetPath(std::string const &fullName)
+{
+ std::string res = fullName;
+/*
+
+ int pos1 = res.rfind("/");
+ int pos2 = res.rfind("\\");
+ if ( pos1 > pos2 )
+ {
+ res.resize(pos1);
+ }
+ else
+ {
+ res.resize(pos2);
+ }
+*/
+ int pos = res.rfind(GDCM_FILESEPARATOR);
+ res.resize(pos);
+ return res;
+}
+
+/**
+ * \brief Get the (last) name of a full path file name
+ * @param fullName file/directory name to extract end name from
+ */
+std::string Util::GetName(std::string const &fullName)
+{
+ std::string filename = fullName;
+/*
+ std::string::size_type slash_pos = filename.rfind("/");
+ std::string::size_type backslash_pos = filename.rfind("\\");
+ // At least with my gcc4.0.1, unfound char results in pos =4294967295 ...
+ //slash_pos = slash_pos > backslash_pos ? slash_pos : backslash_pos;
+ slash_pos = slash_pos < backslash_pos ? slash_pos : backslash_pos;
+*/
+ std::string::size_type slash_pos = filename.rfind(GDCM_FILESEPARATOR);
+ if (slash_pos != std::string::npos )
+ {
+ return filename.substr(slash_pos + 1);
+ }
+ else
+ {
+ return filename;
+ }
+}
+
+/**
+ * \brief Get the current date of the system in a dicom string
+ */
+std::string Util::GetCurrentDate()
+{
+ char tmp[512];
+ time_t tloc;
+ time (&tloc);
+ strftime(tmp,512,"%Y%m%d", localtime(&tloc) );
+ return tmp;
+}
+
+/**
+ * \brief Get the current time of the system in a dicom string
+ */
+std::string Util::GetCurrentTime()
+{
+ char tmp[512];
+ time_t tloc;
+ time (&tloc);
+ strftime(tmp,512,"%H%M%S", localtime(&tloc) );
+ return tmp;
+}
+
+/**
+ * \brief Get both the date and time at the same time to avoid problem
+ * around midnight where the two calls could be before and after midnight
+ */
+std::string Util::GetCurrentDateTime()
+{
+ char tmp[40];
+ long milliseconds;
+ time_t timep;
+
+ // We need implementation specific functions to obtain millisecond precision
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
+ struct timeb tb;
+ ::ftime(&tb);
+ timep = tb.time;
+ milliseconds = tb.millitm;
+#else
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ timep = tv.tv_sec;
+ // Compute milliseconds from microseconds.
+ milliseconds = tv.tv_usec / 1000;
+#endif
+ // Obtain the time of day, and convert it to a tm struct.
+ struct tm *ptm = localtime (&timep);
+ // Format the date and time, down to a single second.
+ strftime (tmp, sizeof (tmp), "%Y%m%d%H%M%S", ptm);
+
+ // Add milliseconds
+ // Don't use Util::Format to accelerate execution of code
+ char tmpAll[80];
+ sprintf(tmpAll,"%s%03ld",tmp,milliseconds);
+
+ return tmpAll;
+}
+
+unsigned int Util::GetCurrentThreadID()
+{
+// FIXME the implementation is far from complete
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
+ return (unsigned int)GetCurrentThreadId();
+#else
+#ifdef __linux__
+ return 0;
+ // Doesn't work on fedora, but is in the man page...
+ //return (unsigned int)gettid();
+#else
+#ifdef __sun
+ return (unsigned int)thr_self();
+#else
+ //default implementation
+ return 0;
+#endif // __sun
+#endif // __linux__
+#endif // Win32
+}
+
+unsigned int Util::GetCurrentProcessID()
+{
+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
+ // NOTE: There is also a _getpid()...
+ return (unsigned int)GetCurrentProcessId();
+#else
+ // get process identification, POSIX
+ return (unsigned int)getpid();
+#endif
+}
+
+/**
+ * \brief tells us whether the processor we are working with is BigEndian or not
+ */
+bool Util::IsCurrentProcessorBigEndian()
+{
+#if defined(GDCM_WORDS_BIGENDIAN)
+ return true;
+#else
+ return false;
+#endif
+}
+
+/**
+ * \brief Create a /DICOM/ string:
+ * It should a of even length (no odd length ever)
+ * It can contain as many (if you are reading this from your
+ * editor the following character is backslash followed by zero
+ * that needed to be escaped with an extra backslash for doxygen) \\0
+ * as you want.
+ */
+std::string Util::DicomString(const char *s, size_t l)
+{
+ std::string r(s, s+l);
+ gdcmAssertMacro( !(r.size() % 2) ); // == basically 'l' is even
+ return r;
+}
+
+/**
+ * \brief Create a /DICOM/ string:
+ * It should a of even length (no odd length ever)
+ * It can contain as many (if you are reading this from your
+ * editor the following character is backslash followed by zero
+ * that needed to be escaped with an extra backslash for doxygen) \\0
+ * as you want.
+ * This function is similar to DicomString(const char*),
+ * except it doesn't take a length.
+ * It only pad with a null character if length is odd
+ */
+std::string Util::DicomString(const char *s)
+{
+ size_t l = strlen(s);
+ if ( l%2 )
+ {
+ l++;
+ }
+ std::string r(s, s+l);
+ gdcmAssertMacro( !(r.size() % 2) );
+ return r;
+}
+
+/**
+ * \brief Safely check the equality of two Dicom String:
+ * - Both strings should be of even length
+ * - We allow padding of even length string by either
+ * a null character of a space
+ */
+bool Util::DicomStringEqual(const std::string &s1, const char *s2)
+{
+ // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
+ std::string s1_even = s1; //Never change input parameter
+ std::string s2_even = DicomString( s2 );
+ if ( s1_even[s1_even.size()-1] == ' ' )
+ {
+ s1_even[s1_even.size()-1] = '\0'; //replace space character by null
+ }
+ return s1_even == s2_even;
+}
+
+/**
+ * \brief Safely compare two Dicom String:
+ * - Both strings should be of even length
+ * - We allow padding of even length string by either
+ * a null character of a space
+ */
+bool Util::CompareDicomString(const std::string &s1, const char *s2, int op)
+{
+ // s2 is the string from the DICOM reference e.g. : 'MONOCHROME1'
+ std::string s1_even = s1; //Never change input parameter
+ std::string s2_even = DicomString( s2 );
+ if ( s1_even[s1_even.size()-1] == ' ' )
+ {
+ s1_even[s1_even.size()-1] = '\0'; //replace space character by null
+ }
+ switch (op)
+ {
+ case GDCM_EQUAL :
+ return s1_even == s2_even;
+ case GDCM_DIFFERENT :
+ return s1_even != s2_even;
+ case GDCM_GREATER :
+ return s1_even > s2_even;
+ case GDCM_GREATEROREQUAL :
+ return s1_even >= s2_even;
+ case GDCM_LESS :
+ return s1_even < s2_even;
+ case GDCM_LESSOREQUAL :
+ return s1_even <= s2_even;
+ default :
+ gdcmDebugMacro(" Wrong operator : " << op);
+ return false;
+ }
+}
+
+#ifdef _WIN32
+ typedef BOOL(WINAPI * pSnmpExtensionInit) (
+ IN DWORD dwTimeZeroReference,
+ OUT HANDLE * hPollForTrapEvent,
+ OUT AsnObjectIdentifier * supportedView);
+
+ typedef BOOL(WINAPI * pSnmpExtensionTrap) (
+ OUT AsnObjectIdentifier * enterprise,
+ OUT AsnInteger * genericTrap,
+ OUT AsnInteger * specificTrap,
+ OUT AsnTimeticks * timeStamp,
+ OUT RFC1157VarBindList * variableBindings);
+
+ typedef BOOL(WINAPI * pSnmpExtensionQuery) (
+ IN BYTE requestType,
+ IN OUT RFC1157VarBindList * variableBindings,
+ OUT AsnInteger * errorStatus,
+ OUT AsnInteger * errorIndex);
+
+ typedef BOOL(WINAPI * pSnmpExtensionInitEx) (
+ OUT AsnObjectIdentifier * supportedView);
+#endif //_WIN32
+
+#ifdef __sgi
+static int SGIGetMacAddress(unsigned char *addr)
+{
+ FILE *f = popen("/etc/nvram eaddr","r");
+ if(f == 0)
+ {
+ return -1;
+ }
+ unsigned int x[6];
+ if(fscanf(f,"%02x:%02x:%02x:%02x:%02x:%02x",
+ x,x+1,x+2,x+3,x+4,x+5) != 6)
+ {
+ pclose(f);
+ return -1;
+ }
+ for(unsigned int i = 0; i < 6; i++)
+ {
+ addr[i] = static_cast<unsigned char>(x[i]);
+ }
+ return 0;
+}
+#endif
+
+/// \brief gets current M.A.C adress (for internal use only)
+int GetMacAddrSys ( unsigned char *addr );
+int GetMacAddrSys ( unsigned char *addr )
+{
+#ifdef _WIN32
+ WSADATA WinsockData;
+ if ( (WSAStartup(MAKEWORD(2, 0), &WinsockData)) != 0 )
+ {
+ std::cerr << "in Get MAC Adress (internal) : This program requires Winsock 2.x!"
+ << std::endl;
+ return -1;
+ }
+
+ HANDLE PollForTrapEvent;
+ AsnObjectIdentifier SupportedView;
+ UINT OID_ifEntryType[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
+ UINT OID_ifEntryNum[] = { 1, 3, 6, 1, 2, 1, 2, 1 };
+ UINT OID_ipMACEntAddr[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 6 };
+ AsnObjectIdentifier MIB_ifMACEntAddr = {
+ sizeof(OID_ipMACEntAddr) / sizeof(UINT), OID_ipMACEntAddr };
+ AsnObjectIdentifier MIB_ifEntryType = {
+ sizeof(OID_ifEntryType) / sizeof(UINT), OID_ifEntryType };
+ AsnObjectIdentifier MIB_ifEntryNum = {
+ sizeof(OID_ifEntryNum) / sizeof(UINT), OID_ifEntryNum };
+ RFC1157VarBindList varBindList;
+ RFC1157VarBind varBind[2];
+ AsnInteger errorStatus;
+ AsnInteger errorIndex;
+ AsnObjectIdentifier MIB_NULL = { 0, 0 };
+ int ret;
+ int dtmp;
+ int j = 0;
+
+ // Load the SNMP dll and get the addresses of the functions necessary
+ HINSTANCE m_hInst = LoadLibrary("inetmib1.dll");
+ if (m_hInst < (HINSTANCE) HINSTANCE_ERROR)
+ {
+ return -1;
+ }
+ pSnmpExtensionInit m_Init =
+ (pSnmpExtensionInit) GetProcAddress(m_hInst, "SnmpExtensionInit");
+ pSnmpExtensionQuery m_Query =
+ (pSnmpExtensionQuery) GetProcAddress(m_hInst, "SnmpExtensionQuery");
+ m_Init(GetTickCount(), &PollForTrapEvent, &SupportedView);
+
+ /* Initialize the variable list to be retrieved by m_Query */
+ varBindList.list = varBind;
+ varBind[0].name = MIB_NULL;
+ varBind[1].name = MIB_NULL;
+
+ // Copy in the OID to find the number of entries in the
+ // Inteface table
+ varBindList.len = 1; // Only retrieving one item
+ SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryNum);
+ m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
+ &errorIndex);
+// printf("# of adapters in this system : %i\n",
+// varBind[0].value.asnValue.number);
+ varBindList.len = 2;
+
+ // Copy in the OID of ifType, the type of interface
+ SNMP_oidcpy(&varBind[0].name, &MIB_ifEntryType);
+
+ // Copy in the OID of ifPhysAddress, the address
+ SNMP_oidcpy(&varBind[1].name, &MIB_ifMACEntAddr);
+
+ do
+ {
+ // Submit the query. Responses will be loaded into varBindList.
+ // We can expect this call to succeed a # of times corresponding
+ // to the # of adapters reported to be in the system
+ ret = m_Query(ASN_RFC1157_GETNEXTREQUEST, &varBindList, &errorStatus,
+ &errorIndex);
+ if (!ret)
+ {
+ ret = 1;
+ }
+ else
+ {
+ // Confirm that the proper type has been returned
+ ret = SNMP_oidncmp(&varBind[0].name, &MIB_ifEntryType,
+ MIB_ifEntryType.idLength);
+ }
+ if (!ret)
+ {
+ j++;
+ dtmp = varBind[0].value.asnValue.number;
+
+ // Type 6 describes ethernet interfaces
+ if (dtmp == 6)
+ {
+ // Confirm that we have an address here
+ ret = SNMP_oidncmp(&varBind[1].name, &MIB_ifMACEntAddr,
+ MIB_ifMACEntAddr.idLength);
+ if ( !ret && varBind[1].value.asnValue.address.stream != NULL )
+ {
+ if ( (varBind[1].value.asnValue.address.stream[0] == 0x44)
+ && (varBind[1].value.asnValue.address.stream[1] == 0x45)
+ && (varBind[1].value.asnValue.address.stream[2] == 0x53)
+ && (varBind[1].value.asnValue.address.stream[3] == 0x54)
+ && (varBind[1].value.asnValue.address.stream[4] == 0x00) )
+ {
+ // Ignore all dial-up networking adapters
+ std::cerr << "in Get MAC Adress (internal) : Interface #"
+ << j << " is a DUN adapter\n";
+ continue;
+ }
+ if ( (varBind[1].value.asnValue.address.stream[0] == 0x00)
+ && (varBind[1].value.asnValue.address.stream[1] == 0x00)
+ && (varBind[1].value.asnValue.address.stream[2] == 0x00)
+ && (varBind[1].value.asnValue.address.stream[3] == 0x00)
+ && (varBind[1].value.asnValue.address.stream[4] == 0x00)
+ && (varBind[1].value.asnValue.address.stream[5] == 0x00) )
+ {
+ // Ignore NULL addresses returned by other network
+ // interfaces
+ std::cerr << "in Get MAC Adress (internal) : Interface #"
+ << j << " is a NULL address\n";
+ continue;
+ }
+ memcpy( addr, varBind[1].value.asnValue.address.stream, 6);
+ }
+ }
+ }
+ } while (!ret);
+
+ // Free the bindings
+ SNMP_FreeVarBind(&varBind[0]);
+ SNMP_FreeVarBind(&varBind[1]);
+ return 0;
+#endif //Win32 version