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