00001 /* 00002 * datahash.cpp 00003 * 00004 * Copyright (C) 2003, 2008, 2010 Thomas A. Vaughan 00005 * All rights reserved. 00006 * 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * * Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * * Neither the name of the <organization> nor the 00016 * names of its contributors may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY 00020 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00022 * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY 00023 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00026 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 * 00030 * 00031 * Implementation of the recursive data hash. 00032 */ 00033 00034 // includes -------------------------------------------------------------------- 00035 #include "datahash.h" // always include our own header first 00036 00037 #include "common/wave_ex.h" 00038 #include "util/parsing.h" 00039 00040 00041 static const int s_maxHashKeyLength = 32; 00042 00043 00044 //////////////////////////////////////////////////////////////////////////////// 00045 // 00046 // static helper methods 00047 // 00048 //////////////////////////////////////////////////////////////////////////////// 00049 00050 static bool 00051 isValidHashKeyCharacter 00052 ( 00053 IN char a, 00054 IN bool isFirstCharacter 00055 ) 00056 throw() 00057 { 00058 // must be single byte character! 00059 if (!isSingleByteUTF8Character(a)) 00060 return false; 00061 00062 // any alphabetic character a-zA-Z is fine 00063 if (a >= 'a' && a <= 'z') 00064 return true; 00065 if (a >= 'A' && a <= 'Z') 00066 return true; 00067 00068 // first character must be alphabetic 00069 if (isFirstCharacter) 00070 return false; 00071 00072 // later characters can also be numeric 00073 if (a >= '0' && a <= '9') 00074 return true; 00075 00076 // not alphanumeric! 00077 return false; 00078 } 00079 00080 00081 00082 //////////////////////////////////////////////////////////////////////////////// 00083 // 00084 // hash_value_t methods 00085 // 00086 //////////////////////////////////////////////////////////////////////////////// 00087 00088 hash_value_t::hash_value_t 00089 ( 00090 IN const char * txt 00091 ) 00092 { 00093 // ASSERT(txt) -- we don't care 00094 type = eHashDataType_String; 00095 text = (txt) ? txt : ""; 00096 } 00097 00098 00099 00100 hash_value_t::hash_value_t 00101 ( 00102 IN const std::string& s 00103 ) 00104 { 00105 type = eHashDataType_String; 00106 text = s; 00107 } 00108 00109 00110 00111 hash_value_t::hash_value_t 00112 ( 00113 IN smart_ptr<Datahash>& h 00114 ) 00115 { 00116 // ASSERT(h) -- we don't care 00117 type = eHashDataType_Hash; 00118 hash = h; 00119 } 00120 00121 00122 00123 void 00124 hash_value_t::clear 00125 ( 00126 void 00127 ) 00128 throw() 00129 { 00130 type = eHashDataType_Invalid; 00131 text.clear(); 00132 hash = NULL; 00133 } 00134 00135 00136 00137 //////////////////////////////////////////////////////////////////////////////// 00138 // 00139 // public API 00140 // 00141 //////////////////////////////////////////////////////////////////////////////// 00142 00143 bool 00144 isValidHashKeyName 00145 ( 00146 IN const char * key_name 00147 ) 00148 throw() 00149 { 00150 ASSERT(key_name, "null"); 00151 00152 // Why so restrictive? Mainly because it is best to ensure that 00153 // key names can easily be put into URLs, etc. without encoding. 00154 // Also, keys could potentially be used to generate code (variables 00155 // that have the same name). 00156 // This imposes a lot of restrictions on the key names but being 00157 // very restrictive at first and perhaps relaxing the restrictions 00158 // later is much better (more feasible) than the reverse. 00159 00160 // Why enforce length? Partly to catch garbage, but mainly because 00161 // very long names are probably an indication that someone is 00162 // encoding structure into the key names instead of using the hash. 00163 00164 const char * p = key_name; 00165 for (; *p; ++p) { 00166 if (!isValidHashKeyCharacter(*p, p == key_name)) 00167 return false; 00168 00169 // too long? 00170 if (p - key_name > s_maxHashKeyLength) { 00171 return false; 00172 } 00173 } 00174 00175 return true; 00176 } 00177 00178 00179 00180 void 00181 validateHashKeyName 00182 ( 00183 IN const char * key_name 00184 ) 00185 { 00186 ASSERT(key_name, "null"); 00187 if (!isValidHashKeyName(key_name)) { 00188 WAVE_EX(wex); 00189 wex << "Invalid data hash key name: '" << key_name << "'\n"; 00190 wex << "Only ASCII alphanumeric characters are allowed.\n"; 00191 wex << "The first character must be alphabetic.\n"; 00192 wex << "The full key must be less than "; 00193 wex << s_maxHashKeyLength << " characters in length."; 00194 } 00195 } 00196