1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_ucb.hxx" 30 31 #include <limits> 32 #include <com/sun/star/ucb/RuleOperator.hpp> 33 #include <com/sun/star/ucb/SearchInfo.hpp> 34 #include <com/sun/star/util/Date.hpp> 35 #include <tools/date.hxx> 36 #include <tools/inetmime.hxx> 37 #include <tools/string.hxx> 38 39 #ifndef CHAOS_UCBDEMO_SRCHARG_HXX 40 #include <srcharg.hxx> 41 #endif 42 43 namespace unnamed_chaos_ucbdemo_srcharg {} 44 using namespace unnamed_chaos_ucbdemo_srcharg; 45 // unnamed namespaces don't work well yet... 46 47 using namespace com::sun::star; 48 49 //============================================================================ 50 // 51 // skipWhiteSpace 52 // 53 //============================================================================ 54 55 namespace unnamed_chaos_ucbdemo_srcharg { 56 57 void skipWhiteSpace(sal_Unicode const *& rBegin, sal_Unicode const * pEnd) 58 { 59 while (rBegin != pEnd 60 && (*rBegin == '\n' || *rBegin == '\t' || *rBegin == ' ')) 61 ++rBegin; 62 } 63 64 //============================================================================ 65 // 66 // scanAtom 67 // 68 //============================================================================ 69 70 String scanAtom(sal_Unicode const *& rBegin, sal_Unicode const * pEnd) 71 { 72 sal_Unicode const * pTheBegin = rBegin; 73 while (rBegin != pEnd && INetMIME::isAlpha(*rBegin)) 74 ++rBegin; 75 return String(pTheBegin, rBegin - pTheBegin); 76 } 77 78 //============================================================================ 79 // 80 // scanProperty 81 // 82 //============================================================================ 83 84 String scanProperty(sal_Unicode const *& rBegin, sal_Unicode const * pEnd) 85 { 86 sal_Unicode const * pTheBegin = rBegin; 87 while (rBegin != pEnd 88 && !(*rBegin == '\n' || *rBegin == '\t' || *rBegin == ' ')) 89 ++rBegin; 90 return String(pTheBegin, rBegin - pTheBegin); 91 } 92 93 //============================================================================ 94 // 95 // scanOperator 96 // 97 //============================================================================ 98 99 String scanOperator(sal_Unicode const *& rBegin, sal_Unicode const * pEnd) 100 { 101 sal_Unicode const * pTheBegin = rBegin; 102 while (rBegin != pEnd 103 && (INetMIME::isAlpha(*rBegin) || *rBegin == '!' 104 || *rBegin >= '<' && *rBegin <= '>')) 105 ++rBegin; 106 return String(pTheBegin, rBegin - pTheBegin); 107 } 108 109 } 110 111 //============================================================================ 112 // 113 // parseSearchArgument 114 // 115 //============================================================================ 116 117 bool parseSearchArgument(String const & rInput, ucb::SearchInfo & rInfo) 118 { 119 /* Format of rInput: 120 121 argument = *option [criterium *("OR" criterium)] 122 123 option = ("--RECURSE" "=" ("NONE" / "ONE" / "DEEP")) 124 / (("--BASE" / "--FOLDERVIEW" / "--DOCVIEW" 125 / "--INDIRECT") 126 "=" bool) 127 128 criterium = "EMPTY" / (term *("AND" term)) 129 130 term = text-term / date-term / numeric-term / bool-term 131 132 text-term = property ("CONT" / "!CONT" / ">=" / "<=" / "==" / "!=") 133 string *("-C" / "-R") 134 135 date-term = property 136 (((">=" / "<=" / "==" / "!=") date) 137 / (("OLDER" / "YOUNGER") number)) 138 139 numeric-term = property (">=" / "<=" / "==" / "!=") number 140 141 bool-term = property ("TRUE" / "FALSE") 142 143 property = 1*VCHAR 144 145 string = DQUOTE 146 *(<any Unicode code point except DQUOTE or "\"> 147 / ("\" %x75 4HEXDIG) ; \uHHHH 148 / ("\" (DQUOTE / "\"))) 149 DQUOTE 150 151 date = 1*2DIGIT "/" 1*2DIGIT "/" 4DIGIT ; mm/dd/yyyy 152 153 number = ["+" / "-"] 1*DIGIT 154 */ 155 156 sal_Unicode const * p = rInput.GetBuffer(); 157 sal_Unicode const * pEnd = p + rInput.Len(); 158 159 // Parse options: 160 rInfo.Recursion = ucb::SearchRecursion_ONE_LEVEL; 161 rInfo.IncludeBase = true; 162 rInfo.RespectFolderViewRestrictions = true; 163 rInfo.RespectDocViewRestrictions = false; 164 rInfo.FollowIndirections = false; 165 enum OptionID { OPT_RECURSE, OPT_BASE, OPT_FOLDERVIEW, OPT_DOCVIEW, 166 OPT_INDIRECT, OPT_Count }; 167 struct OptionInfo 168 { 169 bool m_bSpecified; 170 sal_Bool * m_pValue; 171 }; 172 OptionInfo aOptions[OPT_Count]; 173 aOptions[OPT_RECURSE].m_bSpecified = false; 174 aOptions[OPT_RECURSE].m_pValue = 0; 175 aOptions[OPT_BASE].m_bSpecified = false; 176 aOptions[OPT_BASE].m_pValue = &rInfo.IncludeBase; 177 aOptions[OPT_FOLDERVIEW].m_bSpecified = false; 178 aOptions[OPT_FOLDERVIEW].m_pValue 179 = &rInfo.RespectFolderViewRestrictions; 180 aOptions[OPT_DOCVIEW].m_bSpecified = false; 181 aOptions[OPT_DOCVIEW].m_pValue = &rInfo.RespectDocViewRestrictions; 182 aOptions[OPT_INDIRECT].m_bSpecified = false; 183 aOptions[OPT_INDIRECT].m_pValue = &rInfo.FollowIndirections; 184 while (p != pEnd) 185 { 186 sal_Unicode const * q = p; 187 188 skipWhiteSpace(q, pEnd); 189 if (pEnd - q < 2 || *q++ != '-' || *q++ != '-') 190 break; 191 String aOption(scanAtom(q, pEnd)); 192 OptionID eID; 193 if (aOption.EqualsIgnoreCaseAscii("recurse")) 194 eID = OPT_RECURSE; 195 else if (aOption.EqualsIgnoreCaseAscii("base")) 196 eID = OPT_BASE; 197 else if (aOption.EqualsIgnoreCaseAscii("folderview")) 198 eID = OPT_FOLDERVIEW; 199 else if (aOption.EqualsIgnoreCaseAscii("docview")) 200 eID = OPT_DOCVIEW; 201 else if (aOption.EqualsIgnoreCaseAscii("indirect")) 202 eID = OPT_INDIRECT; 203 else 204 break; 205 206 if (aOptions[eID].m_bSpecified) 207 break; 208 aOptions[eID].m_bSpecified = true; 209 210 skipWhiteSpace(q, pEnd); 211 if (q == pEnd || *q++ != '=') 212 break; 213 214 skipWhiteSpace(q, pEnd); 215 String aValue(scanAtom(q, pEnd)); 216 if (eID == OPT_RECURSE) 217 { 218 if (aValue.EqualsIgnoreCaseAscii("none")) 219 rInfo.Recursion = ucb::SearchRecursion_NONE; 220 else if (aValue.EqualsIgnoreCaseAscii("one")) 221 rInfo.Recursion = ucb::SearchRecursion_ONE_LEVEL; 222 else if (aValue.EqualsIgnoreCaseAscii("deep")) 223 rInfo.Recursion = ucb::SearchRecursion_DEEP; 224 else 225 break; 226 } 227 else if (aValue.EqualsIgnoreCaseAscii("true")) 228 *aOptions[eID].m_pValue = true; 229 else if (aValue.EqualsIgnoreCaseAscii("false")) 230 *aOptions[eID].m_pValue = false; 231 else 232 break; 233 234 p = q; 235 } 236 237 // Parse criteria: 238 ucb::SearchCriterium aCriterium; 239 for (;;) 240 { 241 sal_Unicode const * q = p; 242 243 // Parse either property name or "empty": 244 skipWhiteSpace(q, pEnd); 245 String aProperty(scanProperty(q, pEnd)); 246 sal_Unicode const * pPropertyEnd = q; 247 248 // Parse operator: 249 skipWhiteSpace(q, pEnd); 250 String aOperator(scanOperator(q, pEnd)); 251 struct Operator 252 { 253 sal_Char const * m_pName; 254 sal_Int16 m_nText; 255 sal_Int16 m_nDate; 256 sal_Int16 m_nNumeric; 257 sal_Int16 m_nBool; 258 }; 259 static Operator const aOperators[] 260 = { { "cont", ucb::RuleOperator::CONTAINS, 0, 0, 0 }, 261 { "!cont", ucb::RuleOperator::CONTAINSNOT, 0, 0, 0 }, 262 { ">=", ucb::RuleOperator::GREATEREQUAL, 263 ucb::RuleOperator::GREATEREQUAL, 264 ucb::RuleOperator::GREATEREQUAL, 0 }, 265 { "<=", ucb::RuleOperator::LESSEQUAL, 266 ucb::RuleOperator::LESSEQUAL, ucb::RuleOperator::LESSEQUAL, 267 0 }, 268 { "==", ucb::RuleOperator::EQUAL, ucb::RuleOperator::EQUAL, 269 ucb::RuleOperator::EQUAL, 0 }, 270 { "!=", ucb::RuleOperator::NOTEQUAL, 271 ucb::RuleOperator::NOTEQUAL, ucb::RuleOperator::NOTEQUAL, 272 0 }, 273 { "true", 0, 0, 0, ucb::RuleOperator::VALUE_TRUE }, 274 { "false", 0, 0, 0, ucb::RuleOperator::VALUE_FALSE } }; 275 int const nOperatorCount = sizeof aOperators / sizeof (Operator); 276 Operator const * pTheOperator = 0; 277 for (int i = 0; i < nOperatorCount; ++i) 278 if (aOperator.EqualsIgnoreCaseAscii(aOperators[i].m_pName)) 279 { 280 pTheOperator = aOperators + i; 281 break; 282 } 283 bool bTerm = pTheOperator != 0; 284 285 sal_Int16 nOperatorID; 286 uno::Any aTheOperand; 287 bool bCaseSensitive = false; 288 bool bRegularExpression = false; 289 if (bTerm) 290 { 291 skipWhiteSpace(q, pEnd); 292 bool bHasOperand = false; 293 294 // Parse string operand: 295 if (!bHasOperand && pTheOperator->m_nText) 296 { 297 if (q != pEnd && *q == '"') 298 { 299 String aString; 300 for (sal_Unicode const * r = q + 1;;) 301 { 302 if (r == pEnd) 303 break; 304 sal_Unicode c = *r++; 305 if (c == '"') 306 { 307 bHasOperand = true; 308 aTheOperand <<= rtl::OUString(aString); 309 nOperatorID = pTheOperator->m_nText; 310 q = r; 311 break; 312 } 313 if (c == '\\') 314 { 315 if (r == pEnd) 316 break; 317 c = *r++; 318 if (c == 'u') 319 { 320 if (pEnd - r < 4) 321 break; 322 c = 0; 323 bool bBad = false; 324 for (int i = 0; i < 4; ++i) 325 { 326 int nWeight 327 = INetMIME::getHexWeight(*r++); 328 if (nWeight < 0) 329 { 330 bBad = false; 331 break; 332 } 333 c = sal_Unicode(c << 4 | nWeight); 334 } 335 if (bBad) 336 break; 337 } 338 else if (c != '"' && c != '\\') 339 break; 340 } 341 aString += c; 342 } 343 } 344 345 // Parse "-C" and "-R": 346 if (bHasOperand) 347 for (;;) 348 { 349 skipWhiteSpace(q, pEnd); 350 if (pEnd - q >= 2 && q[0] == '-' 351 && (q[1] == 'C' || q[1] == 'c') 352 && !bCaseSensitive) 353 { 354 bCaseSensitive = true; 355 q += 2; 356 } 357 else if (pEnd - q >= 2 && q[0] == '-' 358 && (q[1] == 'R' || q[1] == 'r') 359 && !bRegularExpression) 360 { 361 bRegularExpression = true; 362 q += 2; 363 } 364 else 365 break; 366 } 367 } 368 369 // Parse date operand: 370 if (!bHasOperand && pTheOperator->m_nDate != 0) 371 { 372 sal_Unicode const * r = q; 373 bool bOK = true; 374 USHORT nMonth = 0; 375 if (bOK && r != pEnd && INetMIME::isDigit(*r)) 376 nMonth = INetMIME::getWeight(*r++); 377 else 378 bOK = false; 379 if (bOK && r != pEnd && INetMIME::isDigit(*r)) 380 nMonth = 10 * nMonth + INetMIME::getWeight(*r++); 381 if (!(bOK && r != pEnd && *r++ == '/')) 382 bOK = false; 383 USHORT nDay = 0; 384 if (bOK && r != pEnd && INetMIME::isDigit(*r)) 385 nDay = INetMIME::getWeight(*r++); 386 else 387 bOK = false; 388 if (bOK && r != pEnd && INetMIME::isDigit(*r)) 389 nDay = 10 * nDay + INetMIME::getWeight(*r++); 390 if (!(bOK && r != pEnd && *r++ == '/')) 391 bOK = false; 392 USHORT nYear = 0; 393 for (int i = 0; bOK && i < 4; ++i) 394 if (r != pEnd && INetMIME::isDigit(*r)) 395 nYear = 10 * nYear + INetMIME::getWeight(*r++); 396 else 397 bOK = false; 398 if (bOK && Date(nDay, nMonth, nYear).IsValid()) 399 { 400 bHasOperand = true; 401 aTheOperand <<= util::Date(nDay, nMonth, nYear); 402 nOperatorID = pTheOperator->m_nDate; 403 q = r; 404 } 405 } 406 407 // Parse number operand: 408 if (!bHasOperand && pTheOperator->m_nNumeric != 0) 409 { 410 sal_Unicode const * r = q; 411 bool bNegative = false; 412 if (*r == '+') 413 ++r; 414 else if (*r == '-') 415 { 416 bNegative = true; 417 ++r; 418 } 419 sal_Int64 nNumber = 0; 420 bool bDigits = false; 421 while (r != pEnd && INetMIME::isDigit(*r)) 422 { 423 nNumber = 10 * nNumber + INetMIME::getWeight(*r++); 424 if (nNumber > std::numeric_limits< sal_Int32 >::max()) 425 { 426 bDigits = false; 427 break; 428 } 429 } 430 if (bDigits) 431 { 432 bHasOperand = true; 433 aTheOperand 434 <<= sal_Int32(bNegative ? -sal_Int32(nNumber) : 435 sal_Int32(nNumber)); 436 nOperatorID = pTheOperator->m_nNumeric; 437 q = r; 438 } 439 } 440 441 // Bool operator has no operand: 442 if (!bHasOperand && pTheOperator->m_nBool != 0) 443 { 444 bHasOperand = true; 445 nOperatorID = pTheOperator->m_nBool; 446 } 447 448 bTerm = bHasOperand; 449 } 450 451 bool bEmpty = false; 452 if (bTerm) 453 { 454 aCriterium.Terms.realloc(aCriterium.Terms.getLength() + 1); 455 aCriterium.Terms[aCriterium.Terms.getLength() - 1] 456 = ucb::RuleTerm(aProperty, aTheOperand, nOperatorID, 457 bCaseSensitive, bRegularExpression); 458 } 459 else if (aCriterium.Terms.getLength() == 0 460 && aProperty.EqualsIgnoreCaseAscii("empty")) 461 { 462 bEmpty = true; 463 q = pPropertyEnd; 464 } 465 466 if (!(bTerm || bEmpty)) 467 break; 468 469 p = q; 470 skipWhiteSpace(p, pEnd); 471 472 q = p; 473 String aConnection(scanAtom(q, pEnd)); 474 if (p == pEnd || aConnection.EqualsIgnoreCaseAscii("or")) 475 { 476 rInfo.Criteria.realloc(rInfo.Criteria.getLength() + 1); 477 rInfo.Criteria[rInfo.Criteria.getLength() - 1] = aCriterium; 478 aCriterium = ucb::SearchCriterium(); 479 p = q; 480 } 481 else if (bTerm && aConnection.EqualsIgnoreCaseAscii("and")) 482 p = q; 483 else 484 break; 485 } 486 487 skipWhiteSpace(p, pEnd); 488 return p == pEnd; 489 } 490 491