diff options
Diffstat (limited to 'indra/llcommon')
34 files changed, 2861 insertions, 171 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt new file mode 100644 index 0000000000..72d267d794 --- /dev/null +++ b/indra/llcommon/CMakeLists.txt @@ -0,0 +1,188 @@ +# -*- cmake -*- + +project(llcommon) + +include(00-Common) +include(LLCommon) + +include_directories( + ${EXPAT_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIRS} + ) + +set(llcommon_SOURCE_FILES + llapp.cpp + llapr.cpp + llassettype.cpp + llbase32.cpp + llbase64.cpp + llcommon.cpp + llcrc.cpp + llcriticaldamp.cpp + lldate.cpp + llerror.cpp + llerrorthread.cpp + llevent.cpp + llfasttimer.cpp + llfile.cpp + llfindlocale.cpp + llfixedbuffer.cpp + llformat.cpp + llframetimer.cpp + llheartbeat.cpp + llindraconfigfile.cpp + llliveappconfig.cpp + lllivefile.cpp + lllog.cpp + llmd5.cpp + llmemory.cpp + llmemorystream.cpp + llmetrics.cpp + llmortician.cpp + llprocessor.cpp + llqueuedthread.cpp + llrand.cpp + llrun.cpp + llsd.cpp + llsdserialize.cpp + llsdserialize_xml.cpp + llsdutil.cpp + llsecondlifeurls.cpp + llstat.cpp + llstreamtools.cpp + llstring.cpp + llstringtable.cpp + llsys.cpp + llthread.cpp + lltimer.cpp + lluri.cpp + lluuid.cpp + llworkerthread.cpp + metaclass.cpp + metaproperty.cpp + reflective.cpp + timing.cpp + u64.cpp + ) + +set(llcommon_HEADER_FILES + CMakeLists.txt + + bitpack.h + ctype_workaround.h + doublelinkedlist.h + imageids.h + indra_constants.h + linden_common.h + linked_lists.h + llagentconstants.h + llapp.h + llapr.h + llassettype.h + llassoclist.h + llavatarconstants.h + llbase32.h + llbase64.h + llboost.h + llchat.h + llclickaction.h + llcommon.h + llcrc.h + llcriticaldamp.h + lldarray.h + lldarrayptr.h + lldate.h + lldefs.h + lldepthstack.h + lldlinked.h + lldqueueptr.h + llendianswizzle.h + llenum.h + llerror.h + llerrorcontrol.h + llerrorlegacy.h + llerrorthread.h + llevent.h + lleventemitter.h + llextendedstatus.h + llfasttimer.h + llfile.h + llfindlocale.h + llfixedbuffer.h + llformat.h + llframetimer.h + llhash.h + llheartbeat.h + llindexedqueue.h + llindraconfigfile.h + llkeythrottle.h + lllinkedqueue.h + llliveappconfig.h + lllivefile.h + lllocalidhashmap.h + lllog.h + lllslconstants.h + llmap.h + llmd5.h + llmemory.h + llmemorystream.h + llmemtype.h + llmetrics.h + llmortician.h + llnametable.h + llpreprocessor.h + llpriqueuemap.h + llprocessor.h + llptrskiplist.h + llptrskipmap.h + llqueuedthread.h + llrand.h + llrun.h + llsd.h + llsdserialize.h + llsdserialize_xml.h + llsdutil.h + llsecondlifeurls.h + llsimplehash.h + llskiplist.h + llskipmap.h + llstack.h + llstat.h + llstatenums.h + llstl.h + llstreamtools.h + llstrider.h + llstring.h + llstringtable.h + llsys.h + llthread.h + lltimer.h + lluri.h + lluuid.h + lluuidhashmap.h + llversionserver.h + llversionviewer.h + llworkerthread.h + metaclass.h + metaclasst.h + metaproperty.h + metapropertyt.h + processor.h + reflective.h + reflectivet.h + roles_constants.h + stdenums.h + stdtypes.h + string_table.h + timer.h + timing.h + u64.h + ) + +set_source_files_properties(${llcommon_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) + +add_library (llcommon ${llcommon_SOURCE_FILES}) diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index 9ee4d1159e..60ea21d642 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -45,9 +45,10 @@ #include <iostream> #include <fstream> -// Work around stupid Microsoft STL warning +// Work Microsoft compiler warnings #ifdef LL_WINDOWS -#pragma warning (disable : 4702) // warning C4702: unreachable code +#pragma warning (disable : 4702) // unreachable code +#pragma warning (disable : 4244) // conversion from time_t to S32 #endif // LL_WINDOWS #include <algorithm> diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index b6c363886c..3927d5f014 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -40,11 +40,11 @@ #include <boost/noncopyable.hpp> -#include "apr-1/apr_thread_proc.h" -#include "apr-1/apr_thread_mutex.h" -#include "apr-1/apr_getopt.h" -#include "apr-1/apr_signal.h" -#include "apr-1/apr_atomic.h" +#include "apr_thread_proc.h" +#include "apr_thread_mutex.h" +#include "apr_getopt.h" +#include "apr_signal.h" +#include "apr_atomic.h" #include "llstring.h" extern apr_thread_mutex_t* gLogMutexp; diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index 207b367f6d..ce10e07a0a 100644 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -36,7 +36,7 @@ #include <string> -#include "apr-1/apr_base64.h" +#include "apr_base64.h" // static diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp new file mode 100644 index 0000000000..0836ccb66b --- /dev/null +++ b/indra/llcommon/llcrc.cpp @@ -0,0 +1,224 @@ +/** + * @file llcrc.cpp + * @brief implementation of the crc class. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llcrc.h" +#include "llerror.h" + +/* Copyright (C) 1986 Gary S. Brown. You may use this program, or + code or tables extracted from it, as desired without restriction.*/ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* 1. The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +/* be they sixteen or thirty-two bits wide. You simply choose the */ +/* appropriate table. Alternatively, because the table can be */ +/* generated at runtime, you can start by generating the table for */ +/* the polynomial in question and use exactly the same "updcrc", */ +/* if your application needn't simultaneously handle two CRC */ +/* polynomials. (Note, however, that XMODEM is strange.) */ +/* */ +/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +/* */ +/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +///---------------------------------------------------------------------------- +/// Local function declarations, constants, enums, and typedefs +///---------------------------------------------------------------------------- + +#define UPDC32(octet,crc) (crc_32_tab[((crc) \ + ^ ((U8)octet)) & 0xff] ^ ((crc) >> 8)) + + +static U32 crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, +0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, +0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, +0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, +0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, +0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, +0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, +0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, +0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, +0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, +0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, +0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, +0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, +0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, +0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, +0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, +0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, +0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, +0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, +0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, +0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, +0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, +0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, +0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, +0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, +0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, +0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, +0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, +0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, +0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, +0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, +0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, +0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + +///---------------------------------------------------------------------------- +/// Class llcrc +///---------------------------------------------------------------------------- + +// Default constructor +LLCRC::LLCRC() : mCurrent(0xffffffff) +{ +} + + +U32 LLCRC::getCRC() const +{ + return ~mCurrent; +} + +void LLCRC::update(U8 next_byte) +{ + mCurrent = UPDC32(next_byte, mCurrent); +} + +void LLCRC::update(const U8* buffer, size_t buffer_size) +{ + for (size_t i = 0; i < buffer_size; i++) + { + mCurrent = UPDC32(buffer[i], mCurrent); + } +} + +void LLCRC::update(const char* filename) +{ + if (!filename) + { + llerrs << "No filename specified" << llendl; + return; + } + + FILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ + + if (fp) + { + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + + fseek(fp, 0, SEEK_SET); + + if (size > 0) + { + U8* data = new U8[size]; + size_t nread; + + nread = fread(data, 1, size, fp); + fclose(fp); + + if (nread < (size_t) size) + { + llwarns << "Short read on " << filename << llendl; + } + + update(data, nread); + delete[] data; + } + } +} + + +#ifdef _DEBUG +BOOL LLCRC::testHarness() +{ + const S32 TEST_BUFFER_SIZE = 16; + const char TEST_BUFFER[TEST_BUFFER_SIZE] = "hello &#$)$&Nd0"; /* Flawfinder: ignore */ + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER, TEST_BUFFER_SIZE - 1); + char* rh = (char*)TEST_BUFFER; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + return(c1.getCRC() == c2.getCRC()); +} +#endif + + + +///---------------------------------------------------------------------------- +/// Local function definitions +///---------------------------------------------------------------------------- diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h new file mode 100644 index 0000000000..287c1fbc41 --- /dev/null +++ b/indra/llcommon/llcrc.h @@ -0,0 +1,73 @@ +/** + * @file llcrc.h + * @brief LLCRC class header file. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLCRC_H +#define LL_LLCRC_H + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class llcrc +// +// Simple 32 bit crc. To use, instantiate an LLCRC instance and feed +// it the bytes you want to check. It will update the internal crc as +// you go, and you can qery it at the end. As a horribly inefficient +// example (don't try this at work kids): +// +// LLCRC crc; +// FILE* fp = LLFile::fopen(filename,"rb"); +// while(!feof(fp)) { +// crc.update(fgetc(fp)); +// } +// fclose(fp); +// llinfos << "File crc: " << crc.getCRC() << llendl; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLCRC +{ +protected: + U32 mCurrent; + +public: + LLCRC(); + + U32 getCRC() const; + void update(U8 next_byte); + void update(const U8* buffer, size_t buffer_size); + void update(const char *filename); + +#ifdef _DEBUG + // This function runs tests to make sure the crc is + // working. Returns TRUE if it is. + static BOOL testHarness(); +#endif +}; + + +#endif // LL_LLCRC_H diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h index c7268b8dab..8784bdfb02 100644 --- a/indra/llcommon/lldarray.h +++ b/indra/llcommon/lldarray.h @@ -32,7 +32,6 @@ #ifndef LL_LLDARRAY_H #define LL_LLDARRAY_H -#include "llmath.h" #include "llerror.h" #include <vector> diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 37b912df3d..3cc4cca706 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -34,7 +34,7 @@ #include "linden_common.h" #include "lldate.h" -#include "apr-1/apr_time.h" +#include "apr_time.h" #include <iomanip> #include <sstream> diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 95038bea4c..fa3a01c191 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -168,7 +168,7 @@ namespace { private: bool mTimestamp; - typedef enum ANSIState {ANSI_PROBE, ANSI_YES, ANSI_NO}; + enum ANSIState {ANSI_PROBE, ANSI_YES, ANSI_NO}; ANSIState mUseANSI; void colorANSI(const std::string color) { diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 4e868eb5a1..6b8f8e68c5 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -32,6 +32,10 @@ * $/LicenseInfo$ */ +#if LL_WINDOWS +#include <windows.h> +#endif + #include "linden_common.h" #include "llfile.h" #include "llstring.h" @@ -128,6 +132,50 @@ int LLFile::stat(const char* filename, llstat* filestatus) #endif } +bool LLFile::isdir(const char *filename) +{ + llstat st; + + return stat(filename, &st) == 0 && S_ISDIR(st.st_mode); +} + +bool LLFile::isfile(const char *filename) +{ + llstat st; + + return stat(filename, &st) == 0 && S_ISREG(st.st_mode); +} + +const char *LLFile::tmpdir() +{ + static std::string utf8path; + + if (utf8path.empty()) + { + char sep; +#if LL_WINDOWS + sep = '\\'; + + DWORD len = GetTempPathW(0, L""); + llutf16string utf16path; + utf16path.resize(len + 1); + len = GetTempPathW(static_cast<DWORD>(utf16path.size()), &utf16path[0]); + utf8path = utf16str_to_utf8str(utf16path); +#else + sep = '/'; + + char *env = getenv("TMPDIR"); + + utf8path = env ? env : "/tmp/"; +#endif + if (utf8path[utf8path.size() - 1] != sep) + { + utf8path += sep; + } + } + return utf8path.c_str(); +} + /***************** Modified file stream created to overcome the incorrect behaviour of posix fopen in windows *******************/ diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index a8a6965c0d..bd51ac2aa9 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -50,15 +50,23 @@ typedef FILE LLFILE; #define USE_LLFILESTREAMS 0 #endif +#include <sys/stat.h> #if LL_WINDOWS // windows version of stat function and stat data structure are called _stat typedef struct _stat llstat; #else -#include <sys/stat.h> typedef struct stat llstat; #endif +#ifndef S_ISREG +# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) +#endif + +#ifndef S_ISDIR +# define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) +#endif + class LLFile { public: @@ -74,7 +82,10 @@ public: static int remove(const char* filename); static int rename(const char* filename,const char* newname); static int stat(const char* filename,llstat* file_status); + static bool isdir(const char* filename); + static bool isfile(const char* filename); static LLFILE * _Fiopen(const char *filename, std::ios::openmode mode,int); // protection currently unused + static const char * tmpdir(); }; diff --git a/indra/llcommon/llhash.h b/indra/llcommon/llhash.h index f4b05869a4..08299f5ddc 100644 --- a/indra/llcommon/llhash.h +++ b/indra/llcommon/llhash.h @@ -38,7 +38,9 @@ #include <hash_map> #include <algorithm> #elif LL_DARWIN || LL_LINUX -# if GCC_VERSION >= 30400 // gcc 3.4 and up +# if GCC_VERSION >= 40300 // gcc 4.3 and up +# include <backward/hashtable.h> +# elif GCC_VERSION >= 30400 // gcc 3.4 and up # include <ext/hashtable.h> # elif __GNUC__ >= 3 # include <ext/stl_hashtable.h> diff --git a/indra/llcommon/llheartbeat.cpp b/indra/llcommon/llheartbeat.cpp index 782a4f7ff6..b08e72137a 100644 --- a/indra/llcommon/llheartbeat.cpp +++ b/indra/llcommon/llheartbeat.cpp @@ -72,8 +72,13 @@ LLHeartbeat::rawSend() if (mSuppressed) return 0; // Pretend we succeeded. + int result; +#ifndef LL_DARWIN union sigval dummy; - int result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy); + result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy); +#else + result = kill(getppid(), LL_HEARTBEAT_SIGNAL); +#endif if (result == 0) return 0; // success diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp new file mode 100644 index 0000000000..033eb2f44d --- /dev/null +++ b/indra/llcommon/llmd5.cpp @@ -0,0 +1,531 @@ +/** + * @file llmd5.cpp + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// llMD5.CC - source code for the C++/object oriented translation and +// modification of MD5. +// +// Adapted to Linden Lab by Frank Filipanits, 6/25/2002 +// Fixed potential memory leak, James Cook, 6/27/2002 + +// Translation and modification (c) 1995 by Mordechai T. Abzug + +// This translation/ modification is provided "as is," without express or +// implied warranty of any kind. + +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially +// copied from the disclaimer below). + +/* based on: + + MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + MDDRIVER.C - test driver for MD2, MD4 and MD5 + + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + + */ + + + + + +#include "linden_common.h" + +#include "llmd5.h" + +#include <cassert> + +// how many bytes to grab at a time when checking files +const int LLMD5::BLOCK_LEN = 4096; + + +// LLMD5 simple initialization method + +LLMD5::LLMD5() +{ + init(); +} + + + + +// MD5 block update operation. Continues an MD5 message-digest +// operation, processing another message block, and updating the +// context. + +void LLMD5::update (const uint1 *input, const uint4 input_length) { + + uint4 input_index, buffer_index; + uint4 buffer_space; // how much space is left in buffer + + if (finalized){ // so we can't update! + std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl; + return; + } + + // Compute number of bytes mod 64 + buffer_index = (unsigned int)((count[0] >> 3) & 0x3F); + + // Update number of bits + if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) ) + count[1]++; + + count[1] += ((uint4)input_length >> 29); + + + buffer_space = 64 - buffer_index; // how much space is left in buffer + + // Transform as many times as possible. + if (input_length >= buffer_space) { // ie. we have enough to fill the buffer + // fill the rest of the buffer and transform + memcpy( /* Flawfinder: ignore */ + buffer + buffer_index, + input, + buffer_space); + transform (buffer); + + // now, transform each 64-byte piece of the input, bypassing the buffer + if (input == NULL || input_length == 0){ + std::cerr << "LLMD5::update: Invalid input!" << std::endl; + return; + } + + for (input_index = buffer_space; input_index + 63 < input_length; + input_index += 64) + transform (input+input_index); + + buffer_index = 0; // so we can buffer remaining + } + else + input_index=0; // so we can buffer the whole input + + + // and here we do the buffering: + memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */ +} + + + +// MD5 update for files. +// Like above, except that it works on files (and uses above as a primitive.) + +void LLMD5::update(FILE* file){ + + unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ + int len; + + while ( (len=(int)fread(buffer, 1, BLOCK_LEN, file)) ) + update(buffer, len); + + fclose (file); + +} + + + + + + +// MD5 update for istreams. +// Like update for files; see above. + +void LLMD5::update(std::istream& stream){ + + unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ + int len; + + while (stream.good()){ + stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable. + len=stream.gcount(); + update(buffer, len); + } + +} + + + + + +// MD5 finalization. Ends an MD5 message-digest operation, writing the +// the message digest and zeroizing the context. + + +void LLMD5::finalize (){ + + unsigned char bits[8]; /* Flawfinder: ignore */ + unsigned int index, padLen; + static uint1 PADDING[64]={ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (finalized){ + std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl; + return; + } + + // Save number of bits + encode (bits, count, 8); + + // Pad out to 56 mod 64. + index = (uint4) ((count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + update (PADDING, padLen); + + // Append length (before padding) + update (bits, 8); + + // Store state in digest + encode (digest, state, 16); + + // Zeroize sensitive information + memset (buffer, 0, sizeof(*buffer)); + + finalized=1; + +} + + + + +LLMD5::LLMD5(FILE *file){ + + init(); // must be called be all constructors + update(file); + finalize (); +} + + + + +LLMD5::LLMD5(std::istream& stream){ + + init(); // must called by all constructors + update (stream); + finalize(); +} + +// Digest a string of the format ("%s:%i" % (s, number)) +LLMD5::LLMD5(const unsigned char *string, const unsigned int number) +{ + const char *colon = ":"; + char tbuf[16]; /* Flawfinder: ignore */ + init(); + update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */ + update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ + snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */ + update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */ + finalize(); +} + +// Digest a string +LLMD5::LLMD5(const unsigned char *s) +{ + init(); + update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */ + finalize(); +} + +void LLMD5::raw_digest(unsigned char *s) +{ + if (!finalized) + { + std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<< + "finalized the digest!" << std::endl; + s[0] = '\0'; + return; + } + + memcpy(s, digest, 16); /* Flawfinder: ignore */ + return; +} + + + +void LLMD5::hex_digest(char *s) +{ + int i; + + if (!finalized) + { + std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<< + "finalized the digest!" <<std::endl; + s[0] = '\0'; + return; + } + + for (i=0; i<16; i++) + { + sprintf(s+i*2, "%02x", digest[i]); /* Flawfinder: ignore */ + } + + s[32]='\0'; + + return; +} + + + + + +std::ostream& operator<<(std::ostream &stream, LLMD5 context) +{ + char s[33]; /* Flawfinder: ignore */ + context.hex_digest(s); + stream << s; + return stream; +} + + + + +// PRIVATE METHODS: + + + +void LLMD5::init(){ + finalized=0; // we just started! + + // Nothing counted, so count=0 + count[0] = 0; + count[1] = 0; + + // Load magic initialization constants. + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; +} + + + +// Constants for MD5Transform routine. +// Although we could use C++ style constants, defines are actually better, +// since they let us easily evade scope clashes. + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +// #defines are faster then inline, etc because the compiler is not required to inline. +// Timing tests prove that this works ~40% faster on win with msvc++2k3 over using static inline. + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (U32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (U32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (U32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (U32)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + + +// LLMD5 basic transformation. Transforms state based on block. +void LLMD5::transform (const U8 block[64]){ + + uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + decode (x, block, 64); + + assert(!finalized); // not just a user error, since the method is private + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + // Zeroize sensitive information. + memset ( (uint1 *) x, 0, sizeof(x)); + +} + + + +// Encodes input (UINT4) into output (unsigned char). Assumes len is +// a multiple of 4. +void LLMD5::encode (uint1 *output, const uint4 *input, const uint4 len) { + + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (uint1) (input[i] & 0xff); + output[j+1] = (uint1) ((input[i] >> 8) & 0xff); + output[j+2] = (uint1) ((input[i] >> 16) & 0xff); + output[j+3] = (uint1) ((input[i] >> 24) & 0xff); + } +} + + + + +// Decodes input (unsigned char) into output (UINT4). Assumes len is +// a multiple of 4. +void LLMD5::decode (uint4 *output, const uint1 *input, const uint4 len){ + + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | + (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); +} diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h new file mode 100644 index 0000000000..7dabbfeb0f --- /dev/null +++ b/indra/llcommon/llmd5.h @@ -0,0 +1,133 @@ +/** + * @file llmd5.h + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLMD5_H +#define LL_LLMD5_H + +// LLMD5.CC - source code for the C++/object oriented translation and +// modification of MD5. + +// Translation and modification (c) 1995 by Mordechai T. Abzug + +// This translation/ modification is provided "as is," without express or +// implied warranty of any kind. + +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially +// copied from the disclaimer below). + +/* based on: + + MD5.H - header file for MD5C.C + MDDRIVER.C - test driver for MD2, MD4 and MD5 + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + +*/ + +// use for the raw digest output +const int MD5RAW_BYTES = 16; + +// use for outputting hex digests +const int MD5HEX_STR_SIZE = 33; // char hex[MD5HEX_STR_SIZE]; with null +const int MD5HEX_STR_BYTES = 32; // message system fixed size + +class LLMD5 { +// first, some types: + typedef unsigned int uint4; // assumes integer is 4 words long + typedef unsigned short int uint2; // assumes short integer is 2 words long + typedef unsigned char uint1; // assumes char is 1 word long + +// how many bytes to grab at a time when checking files + static const int BLOCK_LEN; + +public: +// methods for controlled operation: + LLMD5 (); // simple initializer + void update (const uint1 *input, const uint4 input_length); + void update (std::istream& stream); + void update (FILE *file); + void finalize (); + +// constructors for special circumstances. All these constructors finalize +// the MD5 context. + LLMD5 (const unsigned char *string); // digest string, finalize + LLMD5 (std::istream& stream); // digest stream, finalize + LLMD5 (FILE *file); // digest file, close, finalize + LLMD5 (const unsigned char *string, const unsigned int number); + +// methods to acquire finalized result + void raw_digest(unsigned char *array); // provide 16-byte array for binary data + void hex_digest(char *string); // provide 33-byte array for ascii-hex string + friend std::ostream& operator<< (std::ostream&, LLMD5 context); + + + +private: + + +// next, the private data: + uint4 state[4]; + uint4 count[2]; // number of *bits*, mod 2^64 + uint1 buffer[64]; // input buffer + uint1 digest[16]; + uint1 finalized; + +// last, the private methods, mostly static: + void init (); // called by all constructors + void transform (const uint1 *buffer); // does the real update work. Note + // that length is implied to be 64. + + static void encode (uint1 *dest, const uint4 *src, const uint4 length); + static void decode (uint4 *dest, const uint1 *src, const uint4 length); + +}; + +#endif // LL_LLMD5_H diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 454a820ce5..dc4ac18c4d 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -64,6 +64,9 @@ #ifndef LL_MSVC #define LL_MSVC 1 #endif + #if _MSC_VER < 1400 + #define LL_MSVC7 //Visual C++ 2003 or earlier + #endif #endif // Deal with minor differences on Unixy OSes. @@ -104,9 +107,7 @@ using snprintf_hack::snprintf; #if defined(LL_WINDOWS) #define BOOST_REGEX_NO_LIB 1 #define CURL_STATICLIB 1 - -#define LL_LCD_COMPILE 1 - +#define XML_STATIC #endif // LL_WINDOWS diff --git a/indra/llcommon/llptrskiplist.h b/indra/llcommon/llptrskiplist.h index b03faf57f1..90bcec535d 100644 --- a/indra/llcommon/llptrskiplist.h +++ b/indra/llcommon/llptrskiplist.h @@ -33,6 +33,7 @@ #define LL_LLPTRSKIPLIST_H #include "llerror.h" +#include "llrand.h" //#include "vmath.h" #include "llrand.h" diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp new file mode 100644 index 0000000000..11ecd8efde --- /dev/null +++ b/indra/llcommon/llrand.cpp @@ -0,0 +1,176 @@ +/** + * @file llrand.cpp + * @brief Global random generator. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llrand.h" +#include "lluuid.h" + +/** + * Through analysis, we have decided that we want to take values which + * are close enough to 1.0 to map back to 0.0. We came to this + * conclusion from noting that: + * + * [0.0, 1.0) + * + * when scaled to the integer set: + * + * [0, 4) + * + * there is some value close enough to 1.0 that when multiplying by 4, + * gets truncated to 4. Therefore: + * + * [0,1-eps] => 0 + * [1,2-eps] => 1 + * [2,3-eps] => 2 + * [3,4-eps] => 3 + * + * So 0 gets uneven distribution if we simply clamp. The actual + * clamp utilized in this file is to map values out of range back + * to 0 to restore uniform distribution. + * + * Also, for clamping floats when asking for a distribution from + * [0.0,g) we have determined that for values of g < 0.5, then + * rand*g=g, which is not the desired result. As above, we clamp to 0 + * to restore uniform distribution. + */ + +// *NOTE: The system rand implementation is probably not correct. +#define LL_USE_SYSTEM_RAND 0 + +#if LL_USE_SYSTEM_RAND +#include <cstdlib> +#endif + +#if LL_USE_SYSTEM_RAND +class LLSeedRand +{ +public: + LLSeedRand() + { +#if LL_WINDOWS + srand(LLUUID::getRandomSeed()); +#else + srand48(LLUUID::getRandomSeed()); +#endif + } +}; +static LLSeedRand sRandomSeeder; +inline F64 ll_internal_random_double() +{ +#if LL_WINDOWS + return (F64)rand() / (F64)RAND_MAX; +#else + return drand48(); +#endif +} +inline F32 ll_internal_random_float() +{ +#if LL_WINDOWS + return (F32)rand() / (F32)RAND_MAX; +#else + return (F32)drand48(); +#endif +} +#else +static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); +inline F64 ll_internal_random_double() +{ + // *HACK: Through experimentation, we have found that dual core + // CPUs (or at least multi-threaded processes) seem to + // occasionally give an obviously incorrect random number -- like + // 5^15 or something. Sooooo, clamp it as described above. + F64 rv = gRandomGenerator(); + if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0); + return rv; +} + +inline F32 ll_internal_random_float() +{ + // The clamping rules are described above. + F32 rv = (F32)gRandomGenerator(); + if(!((rv >= 0.0f) && (rv < 1.0f))) return fmod(rv, 1.f); + return rv; +} +#endif + +S32 ll_rand() +{ + return ll_rand(RAND_MAX); +} + +S32 ll_rand(S32 val) +{ + // The clamping rules are described above. + S32 rv = (S32)(ll_internal_random_double() * val); + if(rv == val) return 0; + return rv; +} + +F32 ll_frand() +{ + return ll_internal_random_float(); +} + +F32 ll_frand(F32 val) +{ + // The clamping rules are described above. + F32 rv = ll_internal_random_float() * val; + if(val > 0) + { + if(rv >= val) return 0.0f; + } + else + { + if(rv <= val) return 0.0f; + } + return rv; +} + +F64 ll_drand() +{ + return ll_internal_random_double(); +} + +F64 ll_drand(F64 val) +{ + // The clamping rules are described above. + F64 rv = ll_internal_random_double() * val; + if(val > 0) + { + if(rv >= val) return 0.0; + } + else + { + if(rv <= val) return 0.0; + } + return rv; +} diff --git a/indra/llcommon/llrand.h b/indra/llcommon/llrand.h new file mode 100644 index 0000000000..5bd874ba83 --- /dev/null +++ b/indra/llcommon/llrand.h @@ -0,0 +1,132 @@ +/** + * @file llrand.h + * @brief Information, functions, and typedefs for randomness. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLRAND_H +#define LL_LLRAND_H + +#include <boost/random/lagged_fibonacci.hpp> +#include <boost/random/mersenne_twister.hpp> + +/** + * Use the boost random number generators if you want a stateful + * random numbers. If you want more random numbers, use the + * c-functions since they will generate faster/better randomness + * across the process. + * + * I tested some of the boost random engines, and picked a good double + * generator and a good integer generator. I also took some timings + * for them on linux using gcc 3.3.5. The harness also did some other + * fairly trivial operations to try to limit compiler optimizations, + * so these numbers are only good for relative comparisons. + * + * usec/inter algorithm + * 0.21 boost::minstd_rand0 + * 0.039 boost:lagged_fibonacci19937 + * 0.036 boost:lagged_fibonacci607 + * 0.44 boost::hellekalek1995 + * 0.44 boost::ecuyer1988 + * 0.042 boost::rand48 + * 0.043 boost::mt11213b + * 0.028 stdlib random() + * 0.05 stdlib lrand48() + * 0.034 stdlib rand() + * 0.020 the old & lame LLRand + */ + +/** + *@brief Generate a float from [0, RAND_MAX). + */ +S32 ll_rand(); + +/** + *@brief Generate a float from [0, val) or (val, 0]. + */ +S32 ll_rand(S32 val); + +/** + *@brief Generate a float from [0, 1.0). + */ +F32 ll_frand(); + +/** + *@brief Generate a float from [0, val) or (val, 0]. + */ +F32 ll_frand(F32 val); + +/** + *@brief Generate a double from [0, 1.0). + */ +F64 ll_drand(); + +/** + *@brief Generate a double from [0, val) or (val, 0]. + */ +F64 ll_drand(F64 val); + +/** + * @brief typedefs for good boost lagged fibonacci. + * @see boost::lagged_fibonacci + * + * These generators will quickly generate doubles. Note the memory + * requirements, because they are somewhat high. I chose the smallest + * one, and one comparable in speed but higher periodicity without + * outrageous memory requirements. + * To use: + * LLRandLagFib607 foo((U32)time(NULL)); + * double bar = foo(); + */ + +typedef boost::lagged_fibonacci607 LLRandLagFib607; +/**< + * lengh of cycle: 2^32,000 + * memory: 607*sizeof(double) (about 5K) + */ + +typedef boost::lagged_fibonacci2281 LLRandLagFib2281; +/**< + * lengh of cycle: 2^120,000 + * memory: 2281*sizeof(double) (about 17K) + */ + +/** + * @breif typedefs for a good boost mersenne twister implementation. + * @see boost::mersenne_twister + * + * This fairly quickly generates U32 values + * To use: + * LLRandMT19937 foo((U32)time(NULL)); + * U32 bar = foo(); + * + * lengh of cycle: 2^19,937-1 + * memory: about 2496 bytes + */ +typedef boost::mt11213b LLRandMT19937; +#endif diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 19030cd4fd..099f233f56 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -42,10 +42,11 @@ #endif #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace { +namespace LLSDUnnamedNamespace #else -namespace { +namespace #endif +{ class ImplMap; class ImplArray; } @@ -127,10 +128,10 @@ public: virtual void erase(Integer) { } virtual const LLSD& ref(Integer) const { return undef(); } - virtual LLSD::map_const_iterator beginMap() const { return LLSD::map_const_iterator(); } - virtual LLSD::map_const_iterator endMap() const { return LLSD::map_const_iterator(); } - virtual LLSD::array_const_iterator beginArray() const { return LLSD::array_const_iterator(); } - virtual LLSD::array_const_iterator endArray() const { return LLSD::array_const_iterator(); } + virtual LLSD::map_const_iterator beginMap() const { return endMap(); } + virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); } + virtual LLSD::array_const_iterator beginArray() const { return endArray(); } + virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); } static const LLSD& undef(); @@ -139,10 +140,11 @@ public: }; #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace { +namespace LLSDUnnamedNamespace #else -namespace { +namespace #endif +{ template<LLSD::Type T, class Data, class DataRef = Data> class ImplBase : public LLSD::Impl ///< This class handles most of the work for a subclass of Impl @@ -655,10 +657,11 @@ U32 LLSD::Impl::sOutstandingCount = 0; #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace { +namespace LLSDUnnamedNamespace #else -namespace { +namespace #endif +{ inline LLSD::Impl& safe(LLSD::Impl* impl) { return LLSD::Impl::safe(impl); } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 1ba57b1e95..307d73608c 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -40,7 +40,7 @@ #include "lldate.h" #include "lluri.h" -#include "../llmath/lluuid.h" +#include "lluuid.h" /** LLSD provides a flexible data system similar to the data facilities of diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 6f4a49180d..2183792bb1 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -37,7 +37,7 @@ #include "llstreamtools.h" // for fullread #include <iostream> -#include "apr-1/apr_base64.h" +#include "apr_base64.h" #if !LL_WINDOWS #include <netinet/in.h> // htonl & ntohl diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index b3596e8705..cddb243faf 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -35,7 +35,7 @@ #include <iostream> #include <deque> -#include "apr-1/apr_base64.h" +#include "apr_base64.h" extern "C" { diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 992c883a7e..6f26447695 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -46,124 +46,6 @@ #include "llsdserialize.h" -// vector3 -LLSD ll_sd_from_vector3(const LLVector3& vec) -{ - LLSD rv; - rv.append((F64)vec.mV[VX]); - rv.append((F64)vec.mV[VY]); - rv.append((F64)vec.mV[VZ]); - return rv; -} - -LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index) -{ - LLVector3 rv; - rv.mV[VX] = (F32)sd[start_index].asReal(); - rv.mV[VY] = (F32)sd[++start_index].asReal(); - rv.mV[VZ] = (F32)sd[++start_index].asReal(); - return rv; -} - -// vector4 -LLSD ll_sd_from_vector4(const LLVector4& vec) -{ - LLSD rv; - rv.append((F64)vec.mV[VX]); - rv.append((F64)vec.mV[VY]); - rv.append((F64)vec.mV[VZ]); - rv.append((F64)vec.mV[VW]); - return rv; -} - -LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index) -{ - LLVector4 rv; - rv.mV[VX] = (F32)sd[start_index].asReal(); - rv.mV[VY] = (F32)sd[++start_index].asReal(); - rv.mV[VZ] = (F32)sd[++start_index].asReal(); - rv.mV[VW] = (F32)sd[++start_index].asReal(); - return rv; -} - -// vector3d -LLSD ll_sd_from_vector3d(const LLVector3d& vec) -{ - LLSD rv; - rv.append(vec.mdV[VX]); - rv.append(vec.mdV[VY]); - rv.append(vec.mdV[VZ]); - return rv; -} - -LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index) -{ - LLVector3d rv; - rv.mdV[VX] = sd[start_index].asReal(); - rv.mdV[VY] = sd[++start_index].asReal(); - rv.mdV[VZ] = sd[++start_index].asReal(); - return rv; -} - -//vector2 -LLSD ll_sd_from_vector2(const LLVector2& vec) -{ - LLSD rv; - rv.append((F64)vec.mV[VX]); - rv.append((F64)vec.mV[VY]); - return rv; -} - -LLVector2 ll_vector2_from_sd(const LLSD& sd) -{ - LLVector2 rv; - rv.mV[VX] = (F32)sd[0].asReal(); - rv.mV[VY] = (F32)sd[1].asReal(); - return rv; -} - -// Quaternion -LLSD ll_sd_from_quaternion(const LLQuaternion& quat) -{ - LLSD rv; - rv.append((F64)quat.mQ[VX]); - rv.append((F64)quat.mQ[VY]); - rv.append((F64)quat.mQ[VZ]); - rv.append((F64)quat.mQ[VW]); - return rv; -} - -LLQuaternion ll_quaternion_from_sd(const LLSD& sd) -{ - LLQuaternion quat; - quat.mQ[VX] = (F32)sd[0].asReal(); - quat.mQ[VY] = (F32)sd[1].asReal(); - quat.mQ[VZ] = (F32)sd[2].asReal(); - quat.mQ[VW] = (F32)sd[3].asReal(); - return quat; -} - -// color4 -LLSD ll_sd_from_color4(const LLColor4& c) -{ - LLSD rv; - rv.append(c.mV[0]); - rv.append(c.mV[1]); - rv.append(c.mV[2]); - rv.append(c.mV[3]); - return rv; -} - -LLColor4 ll_color4_from_sd(const LLSD& sd) -{ - LLColor4 c; - c.mV[0] = (F32)sd[0].asReal(); - c.mV[1] = (F32)sd[1].asReal(); - c.mV[2] = (F32)sd[2].asReal(); - c.mV[3] = (F32)sd[3].asReal(); - return c; -} - // U32 LLSD ll_sd_from_U32(const U32 val) { diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 9f73222bc3..7098fa8252 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -35,35 +35,34 @@ #define LL_LLSDUTIL_H #include "llsd.h" -#include "../llmath/v3math.h" -#include "../llmath/v4math.h" -#include "../llmath/v3dmath.h" -#include "../llmath/v2math.h" -#include "../llmath/llquaternion.h" -#include "../llmath/v4color.h" -#include "../llprimitive/lltextureanim.h" // vector3 +class LLVector3; LLSD ll_sd_from_vector3(const LLVector3& vec); LLVector3 ll_vector3_from_sd(const LLSD& sd, S32 start_index = 0); // vector4 +class LLVector4; LLSD ll_sd_from_vector4(const LLVector4& vec); LLVector4 ll_vector4_from_sd(const LLSD& sd, S32 start_index = 0); // vector3d (double) +class LLVector3d; LLSD ll_sd_from_vector3d(const LLVector3d& vec); LLVector3d ll_vector3d_from_sd(const LLSD& sd, S32 start_index = 0); // vector2 +class LLVector2; LLSD ll_sd_from_vector2(const LLVector2& vec); LLVector2 ll_vector2_from_sd(const LLSD& sd); // Quaternion +class LLQuaternion; LLSD ll_sd_from_quaternion(const LLQuaternion& quat); LLQuaternion ll_quaternion_from_sd(const LLSD& sd); // color4 +class LLColor4; LLSD ll_sd_from_color4(const LLColor4& c); LLColor4 ll_color4_from_sd(const LLSD& sd); diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 59d71a8e8e..7a2d42dfaa 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -70,7 +70,7 @@ bool _read_file_into_string(std::string& str, const char* filename) llifstream ifs(filename, llifstream::binary); if (!ifs.is_open()) { - llinfos << "Unable to open file" << filename << llendl; + llinfos << "Unable to open file " << filename << llendl; return false; } diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 02ed0dcfc6..dc0a7a83e4 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -31,7 +31,7 @@ #include "linden_common.h" #include "llapr.h" -#include "apr-1/apr_portable.h" +#include "apr_portable.h" #include "llthread.h" diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index a07c64b8fc..7864d93395 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -36,7 +36,7 @@ #include "llapp.h" #include "llmemory.h" -#include "apr-1/apr_thread_cond.h" +#include "apr_thread_cond.h" class LLThread; class LLMutex; diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index af89a09d2f..3d05699cd6 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -429,10 +429,9 @@ BOOL LLTimer::knownBadTimer() // /////////////////////////////////////////////////////////////////////////////// -U32 time_corrected() +time_t time_corrected() { - U32 corrected_time = (U32)time(NULL) + gUTCOffset; - return corrected_time; + return time(NULL) + gUTCOffset; } @@ -452,27 +451,25 @@ BOOL is_daylight_savings() } -struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time) +struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) { - time_t unix_time = (time_t)utc_time; - S32 pacific_offset_hours; if (pacific_daylight_time) { - pacific_offset_hours = -7; + pacific_offset_hours = 7; } else { - pacific_offset_hours = -8; + pacific_offset_hours = 8; } // We subtract off the PST/PDT offset _before_ getting // "UTC" time, because this will handle wrapping around // for 5 AM UTC -> 10 PM PDT of the previous day. - unix_time += pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN; + utc_time -= pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN; // Internal buffer to PST/PDT (see above) - struct tm* internal_time = gmtime(&unix_time); + struct tm* internal_time = gmtime(&utc_time); /* // Don't do this, this won't correctly tell you if daylight savings is active in CA or not. diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 57f9e23e7a..41562f4a51 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -35,6 +35,7 @@ #if LL_LINUX || LL_DARWIN #include <sys/time.h> #endif +#include <limits.h> #include "stdtypes.h" @@ -117,7 +118,35 @@ void ms_sleep(U32 ms); // Returns the correct UTC time in seconds, like time(NULL). // Useful on the viewer, which may have its local clock set wrong. -U32 time_corrected(); +time_t time_corrected(); + +static inline time_t time_min() +{ + if (sizeof(time_t) == 4) + { + return (time_t) INT_MIN; + } else { +#ifdef LLONG_MIN + return (time_t) LLONG_MIN; +#else + return (time_t) LONG_MIN; +#endif + } +} + +static inline time_t time_max() +{ + if (sizeof(time_t) == 4) + { + return (time_t) INT_MAX; + } else { +#ifdef LLONG_MAX + return (time_t) LLONG_MAX; +#else + return (time_t) LONG_MAX; +#endif + } +} // Correction factor used by time_corrected() above. extern S32 gUTCOffset; @@ -131,7 +160,7 @@ BOOL is_daylight_savings(); // S32 utc_time; // utc_time = time_corrected(); // struct tm* internal_time = utc_to_pacific_time(utc_time, gDaylight); -struct tm* utc_to_pacific_time(S32 utc_time, BOOL pacific_daylight_time); +struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time); void microsecondsToTimecodeString(U64 current_time, char *tcstring); void secondsToTimecodeString(F32 current_time, char *tcstring); diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 022742660d..57d55c7e71 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -38,7 +38,7 @@ #include "llsd.h" #include <iomanip> -#include "../llmath/lluuid.h" +#include "lluuid.h" // system includes #include <boost/tokenizer.hpp> diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp new file mode 100644 index 0000000000..3f86681315 --- /dev/null +++ b/indra/llcommon/lluuid.cpp @@ -0,0 +1,923 @@ +/** + * @file lluuid.cpp + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes. +#if LL_WINDOWS +# undef WIN32_LEAN_AND_MEAN +# include <winsock2.h> +# include <windows.h> +#endif + +#include "lldefs.h" +#include "llerror.h" + +#include "lluuid.h" +#include "llerror.h" +#include "llrand.h" +#include "llmd5.h" +#include "llstring.h" +#include "lltimer.h" + +const LLUUID LLUUID::null; +const LLTransactionID LLTransactionID::tnull; + +/* + +NOT DONE YET!!! + +static char BASE85_TABLE[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '!', '#', '$', '%', '&', '(', ')', '*', + '+', '-', ';', '[', '=', '>', '?', '@', '^', '_', + '`', '{', '|', '}', '~', '\0' +}; + + +void encode( char * fiveChars, unsigned int word ) throw( ) +{ +for( int ix = 0; ix < 5; ++ix ) { +fiveChars[4-ix] = encodeTable[ word % 85]; +word /= 85; +} +} + +To decode: +unsigned int decode( char const * fiveChars ) throw( bad_input_data ) +{ +unsigned int ret = 0; +for( int ix = 0; ix < 5; ++ix ) { +char * s = strchr( encodeTable, fiveChars[ ix ] ); +if( s == 0 ) throw bad_input_data(); +ret = ret * 85 + (s-encodeTable); +} +return ret; +} + +void LLUUID::toBase85(char* out) +{ + U32* me = (U32*)&(mData[0]); + for(S32 i = 0; i < 4; ++i) + { + char* o = &out[i*i]; + for(S32 j = 0; j < 5; ++j) + { + o[4-j] = BASE85_TABLE[ me[i] % 85]; + word /= 85; + } + } +} + +unsigned int decode( char const * fiveChars ) throw( bad_input_data ) +{ + unsigned int ret = 0; + for( S32 ix = 0; ix < 5; ++ix ) + { + char * s = strchr( encodeTable, fiveChars[ ix ] ); + ret = ret * 85 + (s-encodeTable); + } + return ret; +} +*/ + +#define LL_USE_JANKY_RANDOM_NUMBER_GENERATOR 0 +#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR +/** + * @brief a global for + */ +static U64 sJankyRandomSeed(LLUUID::getRandomSeed()); + +/** + * @brief generate a random U32. + */ +U32 janky_fast_random_bytes() +{ + sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223); + return (U32)sJankyRandomSeed; +} + +/** + * @brief generate a random U32 from [0, val) + */ +U32 janky_fast_random_byes_range(U32 val) +{ + sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223); + return (U32)(sJankyRandomSeed) % val; +} + +/** + * @brief generate a random U32 from [0, val) + */ +U32 janky_fast_random_seeded_bytes(U32 seed, U32 val) +{ + seed = U64L(1664525) * (U64)(seed) + U64L(1013904223); + return (U32)(seed) % val; +} +#endif + +// Common to all UUID implementations +void LLUUID::toString(char *out) const +{ + sprintf(out, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (U8)(mData[0]), + (U8)(mData[1]), + (U8)(mData[2]), + (U8)(mData[3]), + (U8)(mData[4]), + (U8)(mData[5]), + (U8)(mData[6]), + (U8)(mData[7]), + (U8)(mData[8]), + (U8)(mData[9]), + (U8)(mData[10]), + (U8)(mData[11]), + (U8)(mData[12]), + (U8)(mData[13]), + (U8)(mData[14]), + (U8)(mData[15])); +} + +void LLUUID::toCompressedString(char *out) const +{ + memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */ + out[UUID_BYTES] = '\0'; +} + +std::string LLUUID::getString() const +{ + return asString(); +} + +std::string LLUUID::asString() const +{ + char str[UUID_STR_SIZE]; /* Flawfinder: ignore */ + toString(str); + return std::string(str); +} + +BOOL LLUUID::set(const std::string& in_string, BOOL emit) +{ + return set(in_string.c_str(), emit); +} + +BOOL LLUUID::set(const char *in_string, BOOL emit) +{ + BOOL broken_format = FALSE; + if (!in_string) + { + llerrs << "No string pointer in LLUUID::set!" << llendl; + setNull(); + return FALSE; + } + + // empty strings should make NULL uuid + if (!in_string[0]) + { + setNull(); + return TRUE; + } + + if (strlen(in_string) != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ + { + // I'm a moron. First implementation didn't have the right UUID format. + // Shouldn't see any of these any more + if (strlen(in_string) == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ + { + if(emit) + { + llinfos << "Warning! Using broken UUID string format" << llendl; + } + broken_format = TRUE; + } + else + { + // Bad UUID string. Spam as INFO, as most cases we don't care. + if(emit) + { + llinfos << "Bad UUID string: " << in_string << llendl; + } + setNull(); + return FALSE; + } + } + + U8 cur_pos = 0; + S32 i; + for (i = 0; i < UUID_BYTES; i++) + { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) + { + cur_pos++; + if (broken_format && (i==10)) + { + // Missing - in the broken format + cur_pos--; + } + } + + mData[i] = 0; + + if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9')) + { + mData[i] += (U8)(*(in_string + cur_pos) - '0'); + } + else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f')) + { + mData[i] += (U8)(10 + *(in_string + cur_pos) - 'a'); + } + else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F')) + { + mData[i] += (U8)(10 + *(in_string + cur_pos) - 'A'); + } + else + { + if(emit) + { + llwarns << "Invalid UUID string character" << llendl; + } + setNull(); + return FALSE; + } + + mData[i] = mData[i] << 4; + cur_pos++; + + if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9')) + { + mData[i] += (U8)(*(in_string + cur_pos) - '0'); + } + else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f')) + { + mData[i] += (U8)(10 + *(in_string + cur_pos) - 'a'); + } + else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F')) + { + mData[i] += (U8)(10 + *(in_string + cur_pos) - 'A'); + } + else + { + if(emit) + { + llwarns << "Invalid UUID string character" << llendl; + } + setNull(); + return FALSE; + } + cur_pos++; + } + + return TRUE; +} + +BOOL LLUUID::validate(const std::string& in_string) +{ + return validate(in_string.c_str()); +} + +BOOL LLUUID::validate(const char *in_string) +{ + BOOL broken_format = FALSE; + if (!in_string) + { + return FALSE; + } + if (strlen(in_string) != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ + { + // I'm a moron. First implementation didn't have the right UUID format. + if (strlen(in_string) == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ + { + broken_format = TRUE; + } + else + { + return FALSE; + } + } + + U8 cur_pos = 0; + U32 i; + for (i = 0; i < 16; i++) + { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) + { + cur_pos++; + if (broken_format && (i==10)) + { + // Missing - in the broken format + cur_pos--; + } + } + + if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9')) + { + } + else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f')) + { + } + else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F')) + { + } + else + { + return FALSE; + } + + cur_pos++; + + if ((*(in_string + cur_pos) >= '0') && (*(in_string+cur_pos) <= '9')) + { + } + else if ((*(in_string + cur_pos) >= 'a') && (*(in_string+cur_pos) <='f')) + { + } + else if ((*(in_string + cur_pos) >= 'A') && (*(in_string+cur_pos) <='F')) + { + } + else + { + return FALSE; + } + cur_pos++; + } + return TRUE; +} + +const LLUUID& LLUUID::operator^=(const LLUUID& rhs) +{ + U32* me = (U32*)&(mData[0]); + const U32* other = (U32*)&(rhs.mData[0]); + for(S32 i = 0; i < 4; ++i) + { + me[i] = me[i] ^ other[i]; + } + return *this; +} + +LLUUID LLUUID::operator^(const LLUUID& rhs) const +{ + LLUUID id(*this); + id ^= rhs; + return id; +} + +void LLUUID::combine(const LLUUID& other, LLUUID& result) const +{ + LLMD5 md5_uuid; + md5_uuid.update((unsigned char*)mData, 16); + md5_uuid.update((unsigned char*)other.mData, 16); + md5_uuid.finalize(); + md5_uuid.raw_digest(result.mData); +} + +LLUUID LLUUID::combine(const LLUUID &other) const +{ + LLUUID combination; + combine(other, combination); + return combination; +} + +std::ostream& operator<<(std::ostream& s, const LLUUID &uuid) +{ + char uuid_str[UUID_STR_LENGTH]; + + uuid.toString(uuid_str); + s << uuid_str; + return s; +} + +std::istream& operator>>(std::istream &s, LLUUID &uuid) +{ + U32 i; + char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */ + for (i = 0; i < UUID_STR_LENGTH-1; i++) + { + s >> uuid_str[i]; + } + uuid_str[i] = '\0'; + uuid.set(uuid_str); + return s; +} + +static void get_random_bytes(void *buf, int nbytes) +{ + int i; + char *cp = (char *) buf; + + // *NOTE: If we are not using the janky generator ll_rand() + // generates at least 3 good bytes of data since it is 0 to + // RAND_MAX. This could be made more efficient by copying all the + // bytes. + for (i=0; i < nbytes; i++) +#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR + *cp++ = janky_fast_random_bytes() & 0xFF; +#else + *cp++ = ll_rand() & 0xFF; +#endif + return; +} + +#if LL_WINDOWS +typedef struct _ASTAT_ +{ + ADAPTER_STATUS adapt; + NAME_BUFFER NameBuff [30]; +}ASTAT, * PASTAT; + +// static +S32 LLUUID::getNodeID(unsigned char * node_id) +{ + ASTAT Adapter; + NCB Ncb; + UCHAR uRetCode; + LANA_ENUM lenum; + int i; + int retval = 0; + + memset( &Ncb, 0, sizeof(Ncb) ); + Ncb.ncb_command = NCBENUM; + Ncb.ncb_buffer = (UCHAR *)&lenum; + Ncb.ncb_length = sizeof(lenum); + uRetCode = Netbios( &Ncb ); + // printf( "The NCBENUM return code is: 0x%x \n", uRetCode ); + + for(i=0; i < lenum.length ;i++) + { + memset( &Ncb, 0, sizeof(Ncb) ); + Ncb.ncb_command = NCBRESET; + Ncb.ncb_lana_num = lenum.lana[i]; + + uRetCode = Netbios( &Ncb ); + // printf( "The NCBRESET on LANA %d return code is: 0x%x \n", + // lenum.lana[i], uRetCode ); + + memset( &Ncb, 0, sizeof (Ncb) ); + Ncb.ncb_command = NCBASTAT; + Ncb.ncb_lana_num = lenum.lana[i]; + + strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */ + Ncb.ncb_buffer = (unsigned char *)&Adapter; + Ncb.ncb_length = sizeof(Adapter); + + uRetCode = Netbios( &Ncb ); +// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n", +// lenum.lana[i], uRetCode ); + if ( uRetCode == 0 ) + { +// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n", +// lenum.lana[i], +// Adapter.adapt.adapter_address[0], +// Adapter.adapt.adapter_address[1], +// Adapter.adapt.adapter_address[2], +// Adapter.adapt.adapter_address[3], +// Adapter.adapt.adapter_address[4], +// Adapter.adapt.adapter_address[5] ); + memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */ + retval = 1; + + } + } + return retval; +} + +#elif LL_DARWIN +// Mac OS X version of the UUID generation code... +/* + * Get an ethernet hardware address, if we can find it... + */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <net/if_types.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <ifaddrs.h> + +// static +S32 LLUUID::getNodeID(unsigned char *node_id) +{ + int i; + unsigned char *a = NULL; + struct ifaddrs *ifap, *ifa; + int rv; + S32 result = 0; + + if ((rv=getifaddrs(&ifap))==-1) + { + return -1; + } + if (ifap == NULL) + { + return -1; + } + + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) + { +// printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family); + for(i=0; i< ifa->ifa_addr->sa_len; i++) + { +// printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]); + } +// printf("\n"); + + if(ifa->ifa_addr->sa_family == AF_LINK) + { + // This is a link-level address + struct sockaddr_dl *lla = (struct sockaddr_dl *)ifa->ifa_addr; + +// printf("\tLink level address, type %02X\n", lla->sdl_type); + + if(lla->sdl_type == IFT_ETHER) + { + // Use the first ethernet MAC in the list. + // For some reason, the macro LLADDR() defined in net/if_dl.h doesn't expand correctly. This is what it would do. + a = (unsigned char *)&((lla)->sdl_data); + a += (lla)->sdl_nlen; + + if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) + { + continue; + } + + if (node_id) + { + memcpy(node_id, a, 6); + result = 1; + } + + // We found one. + break; + } + } + } + freeifaddrs(ifap); + + return result; +} + +#else + +// Linux version of the UUID generation code... +/* + * Get the ethernet hardware address, if we can find it... + */ +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#define HAVE_NETINET_IN_H +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#if LL_SOLARIS +#include <sys/sockio.h> +#elif !LL_DARWIN +#include <linux/sockios.h> +#endif +#endif + +// static +S32 LLUUID::getNodeID(unsigned char *node_id) +{ + int sd; + struct ifreq ifr, *ifrp; + struct ifconf ifc; + char buf[1024]; + int n, i; + unsigned char *a; + +/* + * BSD 4.4 defines the size of an ifreq to be + * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len + * However, under earlier systems, sa_len isn't present, so the size is + * just sizeof(struct ifreq) + */ +#ifdef HAVE_SA_LEN +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif +#define ifreq_size(i) max(sizeof(struct ifreq),\ + sizeof((i).ifr_name)+(i).ifr_addr.sa_len) +#else +#define ifreq_size(i) sizeof(struct ifreq) +#endif /* HAVE_SA_LEN*/ + + sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sd < 0) { + return -1; + } + memset(buf, 0, sizeof(buf)); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { + close(sd); + return -1; + } + n = ifc.ifc_len; + for (i = 0; i < n; i+= ifreq_size(*ifr) ) { + ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */ +#ifdef SIOCGIFHWADDR + if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) + continue; + a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; +#else +#ifdef SIOCGENADDR + if (ioctl(sd, SIOCGENADDR, &ifr) < 0) + continue; + a = (unsigned char *) ifr.ifr_enaddr; +#else + /* + * XXX we don't have a way of getting the hardware + * address + */ + close(sd); + return 0; +#endif /* SIOCGENADDR */ +#endif /* SIOCGIFHWADDR */ + if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) + continue; + if (node_id) { + memcpy(node_id, a, 6); /* Flawfinder: ignore */ + close(sd); + return 1; + } + } + close(sd); + return 0; +} + +#endif + +S32 LLUUID::cmpTime(uuid_time_t *t1, uuid_time_t *t2) +{ + // Compare two time values. + + if (t1->high < t2->high) return -1; + if (t1->high > t2->high) return 1; + if (t1->low < t2->low) return -1; + if (t1->low > t2->low) return 1; + return 0; +} + +void LLUUID::getSystemTime(uuid_time_t *timestamp) +{ + // Get system time with 100ns precision. Time is since Oct 15, 1582. +#if LL_WINDOWS + ULARGE_INTEGER time; + GetSystemTimeAsFileTime((FILETIME *)&time); + // NT keeps time in FILETIME format which is 100ns ticks since + // Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582. + // The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec) + // + 18 years and 5 leap days. + time.QuadPart += + (unsigned __int64) (1000*1000*10) // seconds + * (unsigned __int64) (60 * 60 * 24) // days + * (unsigned __int64) (17+30+31+365*18+5); // # of days + + timestamp->high = time.HighPart; + timestamp->low = time.LowPart; +#else + struct timeval tp; + gettimeofday(&tp, 0); + + // Offset between UUID formatted times and Unix formatted times. + // UUID UTC base time is October 15, 1582. + // Unix base time is January 1, 1970. + U64 uuid_time = ((U64)tp.tv_sec * 10000000) + (tp.tv_usec * 10) + + U64L(0x01B21DD213814000); + timestamp->high = (U32) (uuid_time >> 32); + timestamp->low = (U32) (uuid_time & 0xFFFFFFFF); +#endif +} + +void LLUUID::getCurrentTime(uuid_time_t *timestamp) +{ + // Get current time as 60 bit 100ns ticks since whenever. + // Compensate for the fact that real clock resolution is less + // than 100ns. + + const U32 uuids_per_tick = 1024; + + static uuid_time_t time_last; + static U32 uuids_this_tick; + static BOOL init = FALSE; + + if (!init) { + getSystemTime(&time_last); + uuids_this_tick = uuids_per_tick; + init = TRUE; + } + + uuid_time_t time_now = {0,0}; + + while (1) { + getSystemTime(&time_now); + + // if clock reading changed since last UUID generated + if (cmpTime(&time_last, &time_now)) { + // reset count of uuid's generated with this clock reading + uuids_this_tick = 0; + break; + } + if (uuids_this_tick < uuids_per_tick) { + uuids_this_tick++; + break; + } + // going too fast for our clock; spin + } + + time_last = time_now; + + if (uuids_this_tick != 0) { + if (time_now.low & 0x80000000) { + time_now.low += uuids_this_tick; + if (!(time_now.low & 0x80000000)) + time_now.high++; + } else + time_now.low += uuids_this_tick; + } + + timestamp->high = time_now.high; + timestamp->low = time_now.low; +} + +void LLUUID::generate() +{ + // Create a UUID. + uuid_time_t timestamp; + + static unsigned char node_id[6]; /* Flawfinder: ignore */ + static int has_init = 0; + + // Create a UUID. + static uuid_time_t time_last = {0,0}; + static U16 clock_seq = 0; +#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR + static U32 seed = 0L; // dummy seed. reset it below +#endif + if (!has_init) + { + if (getNodeID(node_id) <= 0) + { + get_random_bytes(node_id, 6); + /* + * Set multicast bit, to prevent conflicts + * with IEEE 802 addresses obtained from + * network cards + */ + node_id[0] |= 0x80; + } + + getCurrentTime(&time_last); +#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR + seed = time_last.low; +#endif + +#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR + clock_seq = (U16)janky_fast_random_seeded_bytes(seed, 65536); +#else + clock_seq = (U16)ll_rand(65536); +#endif + has_init = 1; + } + + // get current time + getCurrentTime(×tamp); + + // if clock went backward change clockseq + if (cmpTime(×tamp, &time_last) == -1) { + clock_seq = (clock_seq + 1) & 0x3FFF; + if (clock_seq == 0) clock_seq++; + } + + memcpy(mData+10, node_id, 6); /* Flawfinder: ignore */ + U32 tmp; + tmp = timestamp.low; + mData[3] = (unsigned char) tmp; + tmp >>= 8; + mData[2] = (unsigned char) tmp; + tmp >>= 8; + mData[1] = (unsigned char) tmp; + tmp >>= 8; + mData[0] = (unsigned char) tmp; + + tmp = (U16) timestamp.high; + mData[5] = (unsigned char) tmp; + tmp >>= 8; + mData[4] = (unsigned char) tmp; + + tmp = (timestamp.high >> 16) | 0x1000; + mData[7] = (unsigned char) tmp; + tmp >>= 8; + mData[6] = (unsigned char) tmp; + + tmp = clock_seq; + mData[9] = (unsigned char) tmp; + tmp >>= 8; + mData[8] = (unsigned char) tmp; + + LLMD5 md5_uuid; + + md5_uuid.update(mData,16); + md5_uuid.finalize(); + md5_uuid.raw_digest(mData); + + time_last = timestamp; +} + +void LLUUID::generate(const std::string& hash_string) +{ + LLMD5 md5_uuid((U8*)hash_string.c_str()); + md5_uuid.raw_digest(mData); +} + +U32 LLUUID::getRandomSeed() +{ + static unsigned char seed[16]; /* Flawfinder: ignore */ + + getNodeID(&seed[0]); + seed[6]='\0'; + seed[7]='\0'; + getSystemTime((uuid_time_t *)(&seed[8])); + + LLMD5 md5_seed; + + md5_seed.update(seed,16); + md5_seed.finalize(); + md5_seed.raw_digest(seed); + + return(*(U32 *)seed); +} + +BOOL LLUUID::parseUUID(const char* buf, LLUUID* value) +{ + if( buf == NULL || buf[0] == '\0' || value == NULL) + { + return FALSE; + } + + LLString temp( buf ); + LLString::trim(temp); + if( LLUUID::validate( temp ) ) + { + value->set( temp ); + return TRUE; + } + return FALSE; +} + +LLAssetID LLTransactionID::makeAssetID(const LLUUID& session) const +{ + LLAssetID result; + if (isNull()) + { + result.setNull(); + } + else + { + combine(session, result); + } + return result; +} diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h new file mode 100644 index 0000000000..2f82ec9a93 --- /dev/null +++ b/indra/llcommon/lluuid.h @@ -0,0 +1,330 @@ +/** + * @file lluuid.h + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLUUID_H +#define LL_LLUUID_H + +#include <iostream> +#include <set> +#include "stdtypes.h" + +const S32 UUID_BYTES = 16; +const S32 UUID_WORDS = 4; +const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below +const S32 UUID_STR_SIZE = 37; +const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL. + +struct uuid_time_t { + U32 high; + U32 low; + }; + +class LLUUID +{ +public: + // + // CREATORS + // + LLUUID(); + explicit LLUUID(const char *in_string); // Convert from string. + explicit LLUUID(const std::string& in_string); // Convert from string. + LLUUID(const LLUUID &in); + LLUUID &operator=(const LLUUID &rhs); + + ~LLUUID(); + + // + // MANIPULATORS + // + void generate(); // Generate a new UUID + void generate(const std::string& stream); //Generate a new UUID based on hash of input stream + BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings + BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings + void setNull(); // Faster than setting to LLUUID::null. + + S32 cmpTime(uuid_time_t *t1, uuid_time_t *t2); + static void getSystemTime(uuid_time_t *timestamp); + void getCurrentTime(uuid_time_t *timestamp); + + // + // ACCESSORS + // + BOOL isNull() const; // Faster than comparing to LLUUID::null. + BOOL notNull() const; // Faster than comparing to LLUUID::null. + // JC: This is dangerous. It allows UUIDs to be cast automatically + // to integers, among other things. Use isNull() or notNull(). + // operator bool() const; + + // JC: These must return real bool's (not BOOLs) or else use of the STL + // will generate bool-to-int performance warnings. + bool operator==(const LLUUID &rhs) const; + bool operator!=(const LLUUID &rhs) const; + bool operator<(const LLUUID &rhs) const; + bool operator>(const LLUUID &rhs) const; + + // xor functions. Useful since any two random uuids xored together + // will yield a determinate third random unique id that can be + // used as a key in a single uuid that represents 2. + const LLUUID& operator^=(const LLUUID& rhs); + LLUUID operator^(const LLUUID& rhs) const; + + // similar to functions above, but not invertible + // yields a third random UUID that can be reproduced from the two inputs + // but which, given the result and one of the inputs can't be used to + // deduce the other input + LLUUID combine(const LLUUID& other) const; + void combine(const LLUUID& other, LLUUID& result) const; + + friend std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); + friend std::istream& operator>>(std::istream& s, LLUUID &uuid); + + void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0) + void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0) + + std::string asString() const; + std::string getString() const; + + U16 getCRC16() const; + U32 getCRC32() const; + + static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. + static BOOL validate(const char *in_string); // Validate that the UUID string is legal. + + static const LLUUID null; + + static U32 getRandomSeed(); + static S32 getNodeID(unsigned char * node_id); + + static BOOL parseUUID(const char* buf, LLUUID* value); + + U8 mData[UUID_BYTES]; +}; + + +// Construct +inline LLUUID::LLUUID() +{ + setNull(); +} + + +// Faster than copying from memory +inline void LLUUID::setNull() +{ + U32 *word = (U32 *)mData; + word[0] = 0; + word[1] = 0; + word[2] = 0; + word[3] = 0; +} + + +// Compare +inline bool LLUUID::operator==(const LLUUID& rhs) const +{ + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + // Note: binary & to avoid branching + return + (tmp[0] == rhstmp[0]) & + (tmp[1] == rhstmp[1]) & + (tmp[2] == rhstmp[2]) & + (tmp[3] == rhstmp[3]); +} + + +inline bool LLUUID::operator!=(const LLUUID& rhs) const +{ + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + // Note: binary | to avoid branching + return + (tmp[0] != rhstmp[0]) | + (tmp[1] != rhstmp[1]) | + (tmp[2] != rhstmp[2]) | + (tmp[3] != rhstmp[3]); +} + +/* +// JC: This is dangerous. It allows UUIDs to be cast automatically +// to integers, among other things. Use isNull() or notNull(). +inline LLUUID::operator bool() const +{ + U32 *word = (U32 *)mData; + return (word[0] | word[1] | word[2] | word[3]) > 0; +} +*/ + +inline BOOL LLUUID::notNull() const +{ + U32 *word = (U32 *)mData; + return (word[0] | word[1] | word[2] | word[3]) > 0; +} + +// Faster than == LLUUID::null because doesn't require +// as much memory access. +inline BOOL LLUUID::isNull() const +{ + U32 *word = (U32 *)mData; + // If all bits are zero, return !0 == TRUE + return !(word[0] | word[1] | word[2] | word[3]); +} + +// Copy constructor +inline LLUUID::LLUUID(const LLUUID& rhs) +{ + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + tmp[0] = rhstmp[0]; + tmp[1] = rhstmp[1]; + tmp[2] = rhstmp[2]; + tmp[3] = rhstmp[3]; +} + +inline LLUUID::~LLUUID() +{ +} + +// Assignment +inline LLUUID& LLUUID::operator=(const LLUUID& rhs) +{ + // No need to check the case where this==&rhs. The branch is slower than the write. + U32 *tmp = (U32 *)mData; + U32 *rhstmp = (U32 *)rhs.mData; + tmp[0] = rhstmp[0]; + tmp[1] = rhstmp[1]; + tmp[2] = rhstmp[2]; + tmp[3] = rhstmp[3]; + + return *this; +} + + +inline LLUUID::LLUUID(const char *in_string) +{ + if (!in_string || in_string[0] == 0) + { + setNull(); + return; + } + + set(in_string); +} + +inline LLUUID::LLUUID(const std::string& in_string) +{ + if (in_string.empty()) + { + setNull(); + return; + } + + set(in_string); +} + +// IW: DON'T "optimize" these w/ U32s or you'll scoogie the sort order +// IW: this will make me very sad +inline bool LLUUID::operator<(const LLUUID &rhs) const +{ + U32 i; + for( i = 0; i < (UUID_BYTES - 1); i++ ) + { + if( mData[i] != rhs.mData[i] ) + { + return (mData[i] < rhs.mData[i]); + } + } + return (mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1]); +} + +inline bool LLUUID::operator>(const LLUUID &rhs) const +{ + U32 i; + for( i = 0; i < (UUID_BYTES - 1); i++ ) + { + if( mData[i] != rhs.mData[i] ) + { + return (mData[i] > rhs.mData[i]); + } + } + return (mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1]); +} + +inline U16 LLUUID::getCRC16() const +{ + // A UUID is 16 bytes, or 8 shorts. + U16 *short_data = (U16*)mData; + U16 out = 0; + out += short_data[0]; + out += short_data[1]; + out += short_data[2]; + out += short_data[3]; + out += short_data[4]; + out += short_data[5]; + out += short_data[6]; + out += short_data[7]; + return out; +} + +inline U32 LLUUID::getCRC32() const +{ + U32 *tmp = (U32*)mData; + return tmp[0] + tmp[1] + tmp[2] + tmp[3]; +} + + +// Helper structure for ordering lluuids in stl containers. +// eg: std::map<LLUUID, LLWidget*, lluuid_less> widget_map; +struct lluuid_less +{ + bool operator()(const LLUUID& lhs, const LLUUID& rhs) const + { + return (lhs < rhs) ? true : false; + } +}; + +typedef std::set<LLUUID, lluuid_less> uuid_list_t; + +/* + * Sub-classes for keeping transaction IDs and asset IDs + * straight. + */ +typedef LLUUID LLAssetID; + +class LLTransactionID : public LLUUID +{ +public: + LLTransactionID() : LLUUID() { } + + static const LLTransactionID tnull; + LLAssetID makeAssetID(const LLUUID& session) const; +}; + +#endif diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index f8982d79f8..ea89d724d8 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -31,6 +31,8 @@ #ifndef LL_STDTYPES_H #define LL_STDTYPES_H +#include <cfloat> + typedef signed char S8; typedef unsigned char U8; typedef signed short S16; |