LibreOffice Module ucb (master)  1
LockSequence.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * Copyright 2000, 2010 Oracle and/or its affiliates.
7  *
8  * OpenOffice.org - a multi-platform office productivity suite
9  *
10  * This file is part of OpenOffice.org.
11  *
12  * OpenOffice.org is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 3
14  * only, as published by the Free Software Foundation.
15  *
16  * OpenOffice.org is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License version 3 for more details
20  * (a copy is included in the LICENSE file that accompanied this code).
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * version 3 along with OpenOffice.org. If not, see
24  * <http://www.openoffice.org/license.html>
25  * for a copy of the LGPLv3 License.
26  *
27  ************************************************************************/
28 
29 #include <config_lgpl.h>
30 #include <string.h>
31 #include <ne_xml.h>
32 #include "LockSequence.hxx"
33 #include <memory>
34 #include <sal/log.hxx>
35 
36 using namespace webdav_ucp;
37 using namespace com::sun::star;
38 
39 namespace {
40 
41 struct LockSequenceParseContext
42 {
43  std::unique_ptr<ucb::Lock> pLock;
44  bool hasLockScope;
45  bool hasLockType;
46  bool hasDepth;
47  bool hasHREF;
48  bool hasTimeout;
49 
50  LockSequenceParseContext()
51  : hasLockScope( false ), hasLockType( false ),
52  hasDepth( false ), hasHREF( false ), hasTimeout( false ) {}
53 };
54 
55 }
56 
57 #define STATE_TOP (1)
58 
59 #define STATE_ACTIVELOCK (STATE_TOP)
60 #define STATE_LOCKSCOPE (STATE_TOP + 1)
61 #define STATE_LOCKTYPE (STATE_TOP + 2)
62 #define STATE_DEPTH (STATE_TOP + 3)
63 #define STATE_OWNER (STATE_TOP + 4)
64 #define STATE_TIMEOUT (STATE_TOP + 5)
65 #define STATE_LOCKTOKEN (STATE_TOP + 6)
66 #define STATE_EXCLUSIVE (STATE_TOP + 7)
67 #define STATE_SHARED (STATE_TOP + 8)
68 #define STATE_WRITE (STATE_TOP + 9)
69 #define STATE_HREF (STATE_TOP + 10)
70 
71 
72 extern "C" {
73 
75  void *,
76  int parent,
77  const char * /*nspace*/,
78  const char *name,
79  const char ** )
80 {
81  if ( name != nullptr )
82  {
83  switch ( parent )
84  {
85  case NE_XML_STATEROOT:
86  if ( strcmp( name, "activelock" ) == 0 )
87  return STATE_ACTIVELOCK;
88  break;
89 
90  case STATE_ACTIVELOCK:
91  if ( strcmp( name, "lockscope" ) == 0 )
92  return STATE_LOCKSCOPE;
93  else if ( strcmp( name, "locktype" ) == 0 )
94  return STATE_LOCKTYPE;
95  else if ( strcmp( name, "depth" ) == 0 )
96  return STATE_DEPTH;
97  else if ( strcmp( name, "owner" ) == 0 )
98  return STATE_OWNER;
99  else if ( strcmp( name, "timeout" ) == 0 )
100  return STATE_TIMEOUT;
101  else if ( strcmp( name, "locktoken" ) == 0 )
102  return STATE_LOCKTOKEN;
103  break;
104 
105  case STATE_LOCKSCOPE:
106  if ( strcmp( name, "exclusive" ) == 0 )
107  return STATE_EXCLUSIVE;
108  else if ( strcmp( name, "shared" ) == 0 )
109  return STATE_SHARED;
110  break;
111 
112  case STATE_LOCKTYPE:
113  if ( strcmp( name, "write" ) == 0 )
114  return STATE_WRITE;
115  break;
116 
117  case STATE_LOCKTOKEN:
118  if ( strcmp( name, "href" ) == 0 )
119  return STATE_HREF;
120  break;
121 
122  case STATE_OWNER:
123  // owner elem contains ANY. Accept anything; no state change.
124  return STATE_OWNER;
125  }
126  }
127  return NE_XML_DECLINE;
128 }
129 
130 
132  void *userdata,
133  int state,
134  const char *buf,
135  size_t len )
136 {
137  LockSequenceParseContext * pCtx
138  = static_cast< LockSequenceParseContext * >( userdata );
139  if ( !pCtx->pLock )
140  pCtx->pLock.reset( new ucb::Lock );
141 
142  // Beehive sends XML values containing trailing newlines.
143  if ( buf[ len - 1 ] == 0x0a )
144  len--;
145 
146  switch ( state )
147  {
148  case STATE_DEPTH:
149  if ( rtl_str_compareIgnoreAsciiCase_WithLength(
150  buf, len, "0", 1 ) == 0 )
151  {
152  pCtx->pLock->Depth = ucb::LockDepth_ZERO;
153  pCtx->hasDepth = true;
154  }
155  else if ( rtl_str_compareIgnoreAsciiCase_WithLength(
156  buf, len, "1", 1 ) == 0 )
157  {
158  pCtx->pLock->Depth = ucb::LockDepth_ONE;
159  pCtx->hasDepth = true;
160  }
161  else if ( rtl_str_compareIgnoreAsciiCase_WithLength(
162  buf, len, "infinity", 8 ) == 0 )
163  {
164  pCtx->pLock->Depth = ucb::LockDepth_INFINITY;
165  pCtx->hasDepth = true;
166  }
167  else
168  SAL_WARN( "ucb.ucp.webdav", "LockSequence_chardata_callback - Unknown depth!" );
169  break;
170 
171  case STATE_OWNER:
172  {
173  // collect raw XML data... (owner contains ANY)
174  OUString aValue;
175  pCtx->pLock->Owner >>= aValue;
176  aValue += OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
177  pCtx->pLock->Owner <<= aValue;
178  break;
179  }
180 
181  case STATE_TIMEOUT:
182 
183  // RFC2518, RFC2616:
184 
185  // TimeType = ("Second-" DAVTimeOutVal | "Infinite" | Other)
186  // DAVTimeOutVal = 1*digit
187  // Other = "Extend" field-value
188  // field-value = *( field-content | LWS )
189  // field-content = <the OCTETs making up the field-value
190  // and consisting of either *TEXT or combinations
191  // of token, separators, and quoted-string>
192  //
193  // RFC4918, <http://tools.ietf.org/html/rfc4918#section-10.7>
194  // "The timeout value for TimeType "Second" MUST
195  // NOT be greater than 2^32-1."
196 
197  if ( rtl_str_compareIgnoreAsciiCase_WithLength(
198  buf, len, "Infinite", 8 ) == 0 )
199  {
200  pCtx->pLock->Timeout = sal_Int64( -1 );
201  pCtx->hasTimeout = true;
202  }
203  else if ( rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
204  buf, len, "Second-", 7, 7 ) == 0 )
205  {
206  pCtx->pLock->Timeout
207  = OString( buf + 7, len - 7 ).toInt64();
208  pCtx->hasTimeout = true;
209  }
210 // else if ( rtl_str_shortenedCompareIgnoreCase_WithLength(
211 // buf, len, "Extend", 6, 6 ) == 0 )
212 // {
213 // @@@
214 // }
215  else
216  {
217  pCtx->pLock->Timeout = sal_Int64( -1 );
218  pCtx->hasTimeout = true;
219  SAL_WARN( "ucb.ucp.webdav", "LockSequence_chardata_callback - Unknown timeout!" );
220  }
221  break;
222 
223  case STATE_HREF:
224  {
225  // collect hrefs.
226  sal_Int32 nPos = pCtx->pLock->LockTokens.getLength();
227  pCtx->pLock->LockTokens.realloc( nPos + 1 );
228  pCtx->pLock->LockTokens[ nPos ]
229  = OUString( buf, len, RTL_TEXTENCODING_ASCII_US );
230  pCtx->hasHREF = true;
231  break;
232  }
233 
234  }
235 
236  return 0; // zero to continue, non-zero to abort parsing
237 }
238 
239 
241  void *userdata,
242  int state,
243  const char *,
244  const char * )
245 {
246  LockSequenceParseContext * pCtx
247  = static_cast< LockSequenceParseContext * >( userdata );
248  if ( !pCtx->pLock )
249  pCtx->pLock.reset( new ucb::Lock );
250 
251  switch ( state )
252  {
253  case STATE_EXCLUSIVE:
254  pCtx->pLock->Scope = ucb::LockScope_EXCLUSIVE;
255  pCtx->hasLockScope = true;
256  break;
257 
258  case STATE_SHARED:
259  pCtx->pLock->Scope = ucb::LockScope_SHARED;
260  pCtx->hasLockScope = true;
261  break;
262 
263  case STATE_WRITE:
264  pCtx->pLock->Type = ucb::LockType_WRITE;
265  pCtx->hasLockType = true;
266  break;
267 
268  case STATE_DEPTH:
269  if ( !pCtx->hasDepth )
270  return 1; // abort
271  break;
272 
273  case STATE_HREF:
274  if ( !pCtx->hasHREF )
275  return 1; // abort
276  break;
277 
278  case STATE_TIMEOUT:
279  if ( !pCtx->hasTimeout )
280  return 1; // abort
281  break;
282 
283  case STATE_LOCKSCOPE:
284  if ( !pCtx->hasLockScope )
285  return 1; // abort
286  break;
287 
288  case STATE_LOCKTYPE:
289  if ( !pCtx->hasLockType )
290  return 1; // abort
291  break;
292 
293  case STATE_ACTIVELOCK:
294  if ( !pCtx->hasLockType || !pCtx->hasDepth )
295  return 1; // abort
296  break;
297 
298  default:
299  break;
300  }
301  return 0; // zero to continue, non-zero to abort parsing
302 }
303 
304 }
305 
306 // static
307 bool LockSequence::createFromXML( const OString & rInData,
308  uno::Sequence< ucb::Lock > & rOutData )
309 {
310  const sal_Int32 TOKEN_LENGTH = 13; // </activelock>
311  bool success = true;
312 
313  // rInData may contain multiple <activelock>...</activelock> tags.
314  sal_Int32 nCount = 0;
315  sal_Int32 nStart = 0;
316  sal_Int32 nEnd = rInData.indexOf( "</activelock>" );
317  while ( nEnd > -1 )
318  {
319  ne_xml_parser * parser = ne_xml_create();
320  if ( !parser )
321  {
322  success = false;
323  break;
324  }
325 
326  LockSequenceParseContext aCtx;
327  ne_xml_push_handler( parser,
331  &aCtx );
332 
333  ne_xml_parse( parser,
334  rInData.getStr() + nStart,
335  nEnd - nStart + TOKEN_LENGTH );
336 
337  success = !ne_xml_failed( parser );
338 
339  ne_xml_destroy( parser );
340 
341  if ( !success )
342  break;
343 
344  if ( aCtx.pLock )
345  {
346  nCount++;
347  if ( nCount > rOutData.getLength() )
348  rOutData.realloc( rOutData.getLength() + 1 );
349 
350  rOutData[ nCount - 1 ] = *aCtx.pLock;
351  }
352 
353  nStart = nEnd + TOKEN_LENGTH;
354  nEnd = rInData.indexOf( "</activelock>", nStart );
355  }
356 
357  return success;
358 }
359 
360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define STATE_WRITE
#define STATE_LOCKTYPE
tuple parser
#define STATE_TIMEOUT
#define STATE_EXCLUSIVE
static int LockSequence_chardata_callback(void *userdata, int state, const char *buf, size_t len)
int nCount
static bool createFromXML(const OString &rInData, css::uno::Sequence< css::ucb::Lock > &rOutData)
#define STATE_LOCKTOKEN
#define STATE_SHARED
#define STATE_OWNER
#define STATE_ACTIVELOCK
#define STATE_DEPTH
#define SAL_WARN(area, stream)
static int LockSequence_endelement_callback(void *userdata, int state, const char *, const char *)
static int LockSequence_startelement_callback(void *, int parent, const char *, const char *name, const char **)
#define STATE_LOCKSCOPE
sal_uInt16 nPos
#define STATE_HREF