zoneminder/src/zm_utils.cpp

254 lines
7.0 KiB
C++

//
// ZoneMinder General Utility Functions, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//#include "zm_logger.h"
#include "zm.h"
#include "zm_utils.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
unsigned int sseversion = 0;
const std::string stringtf( const char *format, ... )
{
va_list ap;
char tempBuffer[8192];
std::string tempString;
va_start(ap, format );
vsnprintf( tempBuffer, sizeof(tempBuffer), format , ap );
va_end(ap);
tempString = tempBuffer;
return( tempString );
}
const std::string stringtf( const std::string &format, ... )
{
va_list ap;
char tempBuffer[8192];
std::string tempString;
va_start(ap, format );
vsnprintf( tempBuffer, sizeof(tempBuffer), format.c_str() , ap );
va_end(ap);
tempString = tempBuffer;
return( tempString );
}
bool startsWith( const std::string &haystack, const std::string &needle )
{
return( haystack.substr( 0, needle.length() ) == needle );
}
StringVector split( const std::string &string, const std::string chars, int limit )
{
StringVector stringVector;
std::string tempString = string;
std::string::size_type startIndex = 0;
std::string::size_type endIndex = 0;
//Info( "Looking for '%s' in '%s', limit %d", chars.c_str(), string.c_str(), limit );
do
{
// Find delimiters
endIndex = string.find_first_of( chars, startIndex );
//Info( "Got endIndex at %d", endIndex );
if ( endIndex > 0 )
{
//Info( "Adding '%s'", string.substr( startIndex, endIndex-startIndex ).c_str() );
stringVector.push_back( string.substr( startIndex, endIndex-startIndex ) );
}
if ( endIndex == std::string::npos )
break;
// Find non-delimiters
startIndex = tempString.find_first_not_of( chars, endIndex );
if ( limit && (stringVector.size() == (unsigned int)(limit-1)) )
{
stringVector.push_back( string.substr( startIndex ) );
break;
}
//Info( "Got new startIndex at %d", startIndex );
} while ( startIndex != std::string::npos );
//Info( "Finished with %d strings", stringVector.size() );
return( stringVector );
}
const std::string base64Encode( const std::string &inString )
{
static char base64_table[64] = { '\0' };
if ( !base64_table[0] )
{
int i = 0;
for ( char c = 'A'; c <= 'Z'; c++ )
base64_table[i++] = c;
for ( char c = 'a'; c <= 'z'; c++ )
base64_table[i++] = c;
for ( char c = '0'; c <= '9'; c++ )
base64_table[i++] = c;
base64_table[i++] = '+';
base64_table[i++] = '/';
}
std::string outString;
outString.reserve( 2 * inString.size() );
const char *inPtr = inString.c_str();
while( *inPtr )
{
unsigned char selection = *inPtr >> 2;
unsigned char remainder = (*inPtr++ & 0x03) << 4;
outString += base64_table[selection];
if ( *inPtr )
{
selection = remainder | (*inPtr >> 4);
remainder = (*inPtr++ & 0x0f) << 2;
outString += base64_table[selection];
if ( *inPtr )
{
selection = remainder | (*inPtr >> 6);
outString += base64_table[selection];
selection = (*inPtr++ & 0x3f);
outString += base64_table[selection];
}
else
{
outString += base64_table[remainder];
outString += '=';
}
}
else
{
outString += base64_table[remainder];
outString += '=';
outString += '=';
}
}
return( outString );
}
/* Sets sse_version */
void ssedetect() {
#if (defined(__i386__) || defined(__x86_64__))
/* x86 or x86-64 processor */
uint32_t r_edx, r_ecx;
__asm__ __volatile__(
"mov $0x1,%%eax\n\t"
"cpuid\n\t"
: "=d" (r_edx), "=c" (r_ecx)
:
: "%eax", "%ebx"
);
if (r_ecx & 0x00000200) {
sseversion = 35; /* SSSE3 */
Debug(1,"Detected a x86\\x86-64 processor with SSSE3");
} else if (r_ecx & 0x00000001) {
sseversion = 30; /* SSE3 */
Debug(1,"Detected a x86\\x86-64 processor with SSE3");
} else if (r_edx & 0x04000000) {
sseversion = 20; /* SSE2 */
Debug(1,"Detected a x86\\x86-64 processor with SSE2");
} else if (r_edx & 0x02000000) {
sseversion = 10; /* SSE */
Debug(1,"Detected a x86\\x86-64 processor with SSE");
} else {
sseversion = 0;
Debug(1,"Detected a x86\\x86-64 processor");
}
#else
/* Non x86 or x86-64 processor, SSE2 is not available */
Debug(1,"Detected a non x86\\x86-64 processor");
sseversion = 0;
#endif
}
/* SSE2 aligned memory copy. Useful for big copying of aligned memory like image buffers in ZM */
/* For platforms without SSE2 we will use standard x86 asm memcpy or glibc's memcpy() */
__attribute__((noinline,__target__("sse2"))) void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
#if ((defined(__i386__) || defined(__x86_64__) || defined(ZM_KEEP_SSE)) && !defined(ZM_STRIP_SSE))
if(bytes > 128) {
unsigned int remainder = bytes % 128;
const uint8_t* lastsrc = (uint8_t*)src + (bytes - remainder);
__asm__ __volatile__(
"sse2_copy_iter:\n\t"
"movdqa (%0),%%xmm0\n\t"
"movdqa 0x10(%0),%%xmm1\n\t"
"movdqa 0x20(%0),%%xmm2\n\t"
"movdqa 0x30(%0),%%xmm3\n\t"
"movdqa 0x40(%0),%%xmm4\n\t"
"movdqa 0x50(%0),%%xmm5\n\t"
"movdqa 0x60(%0),%%xmm6\n\t"
"movdqa 0x70(%0),%%xmm7\n\t"
"movntdq %%xmm0,(%1)\n\t"
"movntdq %%xmm1,0x10(%1)\n\t"
"movntdq %%xmm2,0x20(%1)\n\t"
"movntdq %%xmm3,0x30(%1)\n\t"
"movntdq %%xmm4,0x40(%1)\n\t"
"movntdq %%xmm5,0x50(%1)\n\t"
"movntdq %%xmm6,0x60(%1)\n\t"
"movntdq %%xmm7,0x70(%1)\n\t"
"add $0x80, %0\n\t"
"add $0x80, %1\n\t"
"cmp %2, %0\n\t"
"jb sse2_copy_iter\n\t"
"test %3, %3\n\t"
"jz sse2_copy_finish\n\t"
"cld\n\t"
"rep movsb\n\t"
"sse2_copy_finish:\n\t"
:
: "S" (src), "D" (dest), "r" (lastsrc), "c" (remainder)
: "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "cc", "memory"
);
} else {
/* Standard memcpy */
__asm__ __volatile__("cld; rep movsb" :: "S"(src), "D"(dest), "c"(bytes) : "cc", "memory");
}
#else
/* Non x86\x86-64 platform, use memcpy */
memcpy(dest,src,bytes);
#endif
return dest;
}
void timespec_diff(struct timespec *start, struct timespec *end, struct timespec *diff) {
if (((end->tv_nsec)-(start->tv_nsec))<0) {
diff->tv_sec = end->tv_sec-start->tv_sec-1;
diff->tv_nsec = 1000000000+end->tv_nsec-start->tv_nsec;
} else {
diff->tv_sec = end->tv_sec-start->tv_sec;
diff->tv_nsec = end->tv_nsec-start->tv_nsec;
}
}