00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00034 #include "OW_config.h"
00035 #include "OW_SessionLanguage.hpp"
00036
00037 #include <cstdlib>
00038 #include <cstring>
00039 #include <cctype>
00040 #include <cerrno>
00041 #include <algorithm>
00042
00043 namespace OW_NAMESPACE
00044 {
00045
00046 namespace
00047 {
00048
00049 inline const char*
00050 skipWhite(const char* arg)
00051 {
00052 while (*arg && isspace(*arg)) { arg++; }
00053 return arg;
00054 }
00055
00056 bool
00057 subtagsMatch(const char* arg1, const char* arg2)
00058 {
00059
00060 if (*arg1 == '*' || *arg2 == '*')
00061 {
00062 return true;
00063 }
00064
00065
00066 return (::strcmp(arg1, arg2) == 0);
00067 }
00068
00069 }
00070
00072 LanguageTag::LanguageTag()
00073 {
00074 m_subtag1[0] = 0;
00075 m_subtag2[0] = 0;
00076 m_subtag3[0] = 0;
00077 m_weight = 0;
00078 m_explicitQualityValue = false;
00079 }
00080
00082 LanguageTag::LanguageTag(const char* languageTag)
00083 {
00084 assign(languageTag);
00085 }
00086
00088 LanguageTag::LanguageTag(const LanguageTag& arg)
00089 {
00090 copy(arg);
00091 }
00092
00094 LanguageTag&
00095 LanguageTag::operator= (const LanguageTag& arg)
00096 {
00097 return copy(arg);
00098 }
00099
00101 LanguageTag&
00102 LanguageTag::operator= (const char* arg)
00103 {
00104 assign(arg);
00105 return *this;
00106 }
00107
00109 const char*
00110 LanguageTag::assign(const char* arg)
00111 {
00112 m_weight = 0;
00113 m_explicitQualityValue = false;
00114 return setSubTags(arg);
00115 }
00116
00118 LanguageTag&
00119 LanguageTag::copy(const LanguageTag& arg)
00120 {
00121 ::memcpy(m_subtag1, arg.m_subtag1, sizeof(m_subtag1));
00122 ::memcpy(m_subtag2, arg.m_subtag2, sizeof(m_subtag2));
00123 ::memcpy(m_subtag3, arg.m_subtag3, sizeof(m_subtag3));
00124 m_weight = arg.m_weight;
00125 m_explicitQualityValue = arg.m_explicitQualityValue;
00126 return *this;
00127 }
00128
00130 int
00131 LanguageTag::compareWeight(const LanguageTag& arg) const
00132 {
00133 int v = m_weight - arg.m_weight;
00134 if (v == 0)
00135 {
00136 if (m_explicitQualityValue != arg.m_explicitQualityValue)
00137 {
00138 v = (arg.m_explicitQualityValue) ? -1 : 1;
00139 }
00140 }
00141
00142 return v;
00143 }
00144
00146 String
00147 LanguageTag::toString() const
00148 {
00149 char tmpBuf[sizeof(m_subtag1)+sizeof(m_subtag2)+sizeof(m_subtag3)+10];
00150 tmpBuf[0] = 0;
00151 if (!invalid())
00152 {
00153 ::strcpy(tmpBuf, m_subtag1);
00154 if (m_subtag2[0])
00155 {
00156 ::strcat(tmpBuf, "-");
00157 ::strcat(tmpBuf, m_subtag2);
00158 if (m_subtag3[0])
00159 {
00160 ::strcat(tmpBuf, "-");
00161 ::strcat(tmpBuf, m_subtag3);
00162 }
00163 }
00164 }
00165
00166 return String(tmpBuf);
00167 }
00168
00170 const char*
00171 LanguageTag::setSubTags(const char* languageTag)
00172 {
00173
00174
00175 m_subtag1[0] = 0;
00176 m_subtag2[0] = 0;
00177 m_subtag3[0] = 0;
00178 m_weight = 100;
00179 m_explicitQualityValue = false;
00180
00181 const char* p = skipWhite(languageTag);
00182
00183 if (!(p = parseSubTag(p, m_subtag1)))
00184 return 0;
00185
00186 p = skipWhite(p);
00187 if (*p == ';')
00188 return setWeight(p);
00189
00190 if (*p != '-')
00191 return p;
00192
00193
00194 ++p;
00195 if (!(p = parseSubTag(p, m_subtag2)))
00196 return p;
00197
00198 p = skipWhite(p);
00199 if (*p == ';')
00200 return setWeight(p);
00201
00202 if (*p != '-')
00203 return p;
00204
00205 ++p;
00206 return parseSubTag(p, m_subtag3);
00207 }
00208
00210 const char*
00211 LanguageTag::parseSubTag(const char* arg, char* tagField)
00212 {
00213 int i = 0;
00214 while (true)
00215 {
00216 if (!isalpha(*arg) && *arg != '*')
00217 {
00218 if (*arg != '-'
00219 && *arg != ';'
00220 && *arg != ','
00221 && !isspace(*arg)
00222 && *arg != 0)
00223 {
00224
00225 m_subtag1[0] = 0;
00226 arg = 0;
00227 }
00228 break;
00229 }
00230
00231 if (i == 8)
00232 {
00233
00234 m_subtag1[0] = 0;
00235 arg = 0;
00236 break;
00237 }
00238
00239 tagField[i++] = tolower(*arg);
00240 tagField[i] = 0;
00241 arg++;
00242 }
00243
00244 return arg;
00245 }
00246
00248 const char*
00249 LanguageTag::setWeight(const char* arg)
00250 {
00251
00252
00253 m_weight = 0;
00254
00255 while (*arg && (*arg == ';' || isspace(*arg)))
00256 {
00257 ++arg;
00258 }
00259
00260
00261 if (*arg != 'q' && *arg != 'Q')
00262 {
00263 m_subtag1[0] = 0;
00264 return 0;
00265 }
00266 arg++;
00267 arg = skipWhite(arg);
00268 if (*arg != '=')
00269 {
00270 m_subtag1[0] = 0;
00271 return 0;
00272 }
00273 arg++;
00274 arg = skipWhite(arg);
00275 const char* p = arg;
00276
00277 if (!isdigit(*arg) && *arg != '.')
00278 {
00279 m_subtag1[0] = 0;
00280 return 0;
00281 }
00282
00283 while (isdigit(*arg))
00284 ++arg;
00285
00286 if (*arg == '.')
00287 {
00288 do
00289 {
00290 ++arg;
00291 } while (isdigit(*arg));
00292 }
00293
00294 errno = 0;
00295 double fv = strtod(p, 0);
00296 if (errno == ERANGE)
00297 {
00298 m_subtag1[0] = 0;
00299 arg = 0;
00300 }
00301 else
00302 {
00303 fv *= 100.0;
00304 m_weight = static_cast<Int32>(fv);
00305 }
00306 m_explicitQualityValue = true;
00307 return arg;
00308 }
00309
00311 SessionLanguage::SessionLanguage()
00312 : OperationContext::Data()
00313 , m_langTags()
00314 , m_contentLanguage()
00315 , m_acceptLanguageString()
00316 {
00317 }
00318
00320 SessionLanguage::SessionLanguage(const char* acceptLangHdrValue)
00321 : OperationContext::Data()
00322 , m_langTags()
00323 , m_contentLanguage()
00324 , m_acceptLanguageString()
00325 {
00326 assign(acceptLangHdrValue);
00327 }
00328
00330 SessionLanguage::SessionLanguage(const SessionLanguage& arg)
00331 : OperationContext::Data()
00332 , m_langTags(arg.m_langTags)
00333 , m_contentLanguage(arg.m_contentLanguage)
00334 , m_acceptLanguageString(arg.m_acceptLanguageString)
00335 {
00336 }
00337
00339 SessionLanguage&
00340 SessionLanguage::operator=(const SessionLanguage& arg)
00341 {
00342 m_langTags = arg.m_langTags;
00343 m_contentLanguage = arg.m_contentLanguage;
00344 m_acceptLanguageString = arg.m_acceptLanguageString;
00345 return *this;
00346 }
00347
00349 SessionLanguage&
00350 SessionLanguage::assign(const char* acceptLangHdrValue)
00351 {
00352 buildLangTags(acceptLangHdrValue);
00353 return *this;
00354 }
00355
00357 void
00358 SessionLanguage::buildLangTags(const char* acceptLangHdrValue)
00359 {
00360 m_acceptLanguageString = acceptLangHdrValue;
00361 m_langTags.clear();
00362 const char* p = skipWhite(acceptLangHdrValue);
00363 if (!(*p))
00364 {
00365 return;
00366 }
00367
00368 LanguageTag ltag;
00369 while (*p)
00370 {
00371 p = ltag.assign(p);
00372 if (!p)
00373 {
00374 break;
00375 }
00376 m_langTags.append(ltag);
00377 if (!*p)
00378 {
00379 break;
00380 }
00381 ++p;
00382 }
00383
00384 if (!p)
00385 {
00386 m_langTags.clear();
00387 }
00388 else
00389 {
00390 std::sort(m_langTags.begin(), m_langTags.end(),
00391 std::greater<LanguageTag>());
00392 }
00393 }
00394
00396
00397 bool
00398 SessionLanguage::langsMatch(const LanguageTag& t1, const LanguageTag& t2,
00399 int level)
00400 {
00401 bool matches = subtagsMatch(t1.m_subtag1, t2.m_subtag1);
00402 if (level > 1 && matches)
00403 {
00404 matches = subtagsMatch(t1.m_subtag2, t2.m_subtag2);
00405 }
00406 if (level > 2 && matches)
00407 {
00408 matches = subtagsMatch(t1.m_subtag3, t2.m_subtag3);
00409 }
00410 return matches;
00411 }
00412
00414 String
00415 SessionLanguage::getBestLanguage(const StringArray& languages, const String& defaultLanguage) const
00416 {
00417 if (languages.size() == 0)
00418 {
00419 return defaultLanguage;
00420 }
00421
00422 if (m_langTags.size() == 0)
00423 {
00424 return languages[0];
00425 }
00426
00427 int bestIndex = 0;
00428 int bestWeight = -1;
00429
00430 for (int level = 3; level > 0; level--)
00431 {
00432
00433 for (StringArray::size_type i = 0; i < languages.size(); i++)
00434 {
00435 LanguageTag lt(languages[i].c_str());
00436 for (LanguageTagArray::size_type j = 0; j < m_langTags.size(); j++)
00437 {
00438 if (langsMatch(m_langTags[j], lt, level))
00439 {
00440 if (m_langTags[j].getWeight() > 0)
00441 {
00442
00443
00444
00445 if (m_langTags[j].getWeight() > bestWeight)
00446 {
00447 bestWeight = m_langTags[j].getWeight();
00448 bestIndex = i;
00449 }
00450 break;
00451 }
00452 }
00453 }
00454 }
00455 }
00456
00457 return (bestWeight > -1) ? languages[bestIndex] : defaultLanguage;
00458 }
00459
00461 void
00462 SessionLanguage::addContentLanguage(const String& contentLanguage)
00463 {
00464 if (!m_contentLanguage.empty())
00465 {
00466 m_contentLanguage += ", ";
00467 }
00468
00469 StringArray currentLangs = m_contentLanguage.tokenize(", ");
00470 if (std::find(currentLangs.begin(), currentLangs.end(), contentLanguage) == currentLangs.end())
00471 {
00472 m_contentLanguage += contentLanguage;
00473 }
00474 }
00475
00477 String
00478 SessionLanguage::getContentLanguage() const
00479 {
00480 return m_contentLanguage;
00481 }
00482
00483 }
00484