Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : /**************************************************************************
22 : TODO
23 : **************************************************************************
24 :
25 : *************************************************************************/
26 : #include "ftpdirp.hxx"
27 : #include <osl/time.h>
28 :
29 :
30 : using namespace ftp;
31 :
32 : typedef sal_uInt32 ULONG;
33 :
34 0 : inline bool ascii_isWhitespace( sal_Unicode ch )
35 : {
36 0 : return ((ch <= 0x20) && ch);
37 : }
38 :
39 :
40 :
41 : /*========================================================================
42 : *
43 : * FTPDirectoryParser implementation.
44 : *
45 : *======================================================================*/
46 : /*
47 : * parseDOS.
48 : * Accepts one of two styles:
49 : *
50 : * 1 *WSP 1*2DIGIT ("." / "-") 1*2DIGIT ("." / "-") 1*4DIGIT 1*WSP
51 : * 1*2DIGIT ":" 1*2DIGIT [*WSP ("A" / "P") "M"] 1*WSP
52 : * ((DIGIT *(DIGIT / "." / ",")) / "<DIR>") 1*WSP 1*OCTET
53 : *
54 : * interpreted as: mm.dd.yy hh:mm (size / <DIR>) name
55 : *
56 : * 2 *WSP 1*DIGIT 1*WSP *(1*CHAR *WSP) *1("DIR" 1*WSP) 1*2DIGIT "-" 1*2DIGIT
57 : * "-" 1*4DIGIT 1*WSP 1*2DIGIT ":" 1*2DIGIT 1*WSP 1*OCTET
58 : *
59 : * interpreted as: size attribs DIR mm-dd-yy hh:mm name
60 : */
61 :
62 0 : bool FTPDirectoryParser::parseDOS (
63 : FTPDirentry &rEntry,
64 : const sal_Char *pBuffer)
65 : {
66 0 : bool bDirectory = false;
67 0 : sal_uInt32 nSize = 0;
68 0 : sal_uInt16 nYear = 0;
69 0 : sal_uInt16 nMonth = 0;
70 0 : sal_uInt16 nDay = 0;
71 0 : sal_uInt16 nHour = 0;
72 0 : sal_uInt16 nMinute = 0;
73 :
74 : enum StateType
75 : {
76 : STATE_INIT_LWS,
77 : STATE_MONTH_OR_SIZE,
78 : STATE_1_DAY, STATE_1_YEAR, STATE_1_YEAR_LWS, STATE_1_HOUR,
79 : STATE_1_MINUTE, STATE_1_MINUTE_LWS, STATE_1_AP,
80 : STATE_1_APM, STATE_1_LESS, STATE_1_D, STATE_1_DI,
81 : STATE_1_DIR, STATE_1_SIZE,
82 : STATE_2_SIZE, STATE_2_SIZE_LWS, STATE_2_ATTRIB,
83 : STATE_2_D, STATE_2_DI, STATE_2_DIR_LWS,
84 : STATE_2_MONTH, STATE_2_DAY, STATE_2_YEAR, STATE_2_YEAR_LWS,
85 : STATE_2_HOUR, STATE_2_MINUTE,
86 : STATE_LWS_NAME,
87 : STATE_ERROR
88 : };
89 :
90 0 : int nDigits = 0;
91 0 : enum StateType eState = STATE_INIT_LWS;
92 0 : for (const sal_Char *p = pBuffer;
93 0 : eState != STATE_ERROR && *p;
94 : ++p)
95 : {
96 0 : switch (eState)
97 : {
98 : case STATE_INIT_LWS:
99 0 : if (*p >= '0' && *p <= '9')
100 : {
101 0 : nMonth = *p - '0';
102 0 : nDigits = 1;
103 0 : eState = STATE_MONTH_OR_SIZE;
104 : }
105 0 : else if (!ascii_isWhitespace(*p))
106 0 : eState = STATE_ERROR;
107 0 : break;
108 :
109 : case STATE_MONTH_OR_SIZE:
110 0 : if (*p >= '0' && *p <= '9')
111 : {
112 0 : nMonth = 10 * nMonth + (*p - '0');
113 0 : if (nDigits < 2)
114 0 : ++nDigits;
115 : else
116 : {
117 0 : nSize = nMonth;
118 0 : nMonth = 0;
119 0 : eState = STATE_2_SIZE;
120 : }
121 : }
122 0 : else if (ascii_isWhitespace(*p))
123 : {
124 0 : nSize = nMonth;
125 0 : nMonth = 0;
126 0 : eState = STATE_2_SIZE_LWS;
127 : }
128 0 : else if ((*p == '.' || *p == '-') && nMonth && nMonth <= 12)
129 : {
130 0 : nDigits = 0;
131 0 : eState = STATE_1_DAY;
132 : }
133 : else
134 0 : eState = STATE_ERROR;
135 0 : break;
136 :
137 : case STATE_1_DAY:
138 0 : if (*p >= '0' && *p <= '9')
139 0 : if (nDigits < 2)
140 : {
141 0 : nDay = 10 * nDay + (*p - '0');
142 0 : ++nDigits;
143 : }
144 : else
145 0 : eState = STATE_ERROR;
146 0 : else if ((*p == '.' || *p == '-') && nDay && nDay <= 31)
147 : {
148 0 : nDigits = 0;
149 0 : eState = STATE_1_YEAR;
150 : }
151 : else
152 0 : eState = STATE_ERROR;
153 0 : break;
154 :
155 : case STATE_1_YEAR:
156 0 : if (*p >= '0' && *p <= '9')
157 : {
158 0 : if (nDigits < 4)
159 : {
160 0 : nYear = 10 * nYear + (*p - '0');
161 0 : ++nDigits;
162 : }
163 : else
164 0 : eState = STATE_ERROR;
165 : }
166 : else
167 : {
168 0 : if (ascii_isWhitespace(*p))
169 0 : eState = STATE_1_YEAR_LWS;
170 : else
171 0 : eState = STATE_ERROR;
172 : }
173 0 : break;
174 :
175 : case STATE_1_YEAR_LWS:
176 0 : if (*p >= '0' && *p <= '9')
177 : {
178 0 : nHour = *p - '0';
179 0 : nDigits = 1;
180 0 : eState = STATE_1_HOUR;
181 : }
182 0 : else if (!ascii_isWhitespace(*p))
183 0 : eState = STATE_ERROR;
184 0 : break;
185 :
186 : case STATE_1_HOUR:
187 0 : if (*p >= '0' && *p <= '9')
188 0 : if (nDigits < 2)
189 : {
190 0 : nHour = 10 * nHour + (*p - '0');
191 0 : ++nDigits;
192 : }
193 : else
194 0 : eState = STATE_ERROR;
195 0 : else if (*p == ':' && nHour < 24)
196 : {
197 0 : nDigits = 0;
198 0 : eState = STATE_1_MINUTE;
199 : }
200 : else
201 0 : eState = STATE_ERROR;
202 0 : break;
203 :
204 : case STATE_1_MINUTE:
205 0 : if (*p >= '0' && *p <= '9')
206 0 : if (nDigits < 2)
207 : {
208 0 : nMinute = 10 * nMinute + (*p - '0');
209 0 : ++nDigits;
210 : }
211 : else
212 0 : eState = STATE_ERROR;
213 0 : else if ((*p == 'a' || *p == 'A') && nMinute < 60)
214 0 : if (nHour >= 1 && nHour <= 11)
215 0 : eState = STATE_1_AP;
216 0 : else if (nHour == 12)
217 : {
218 0 : nHour = 0;
219 0 : eState = STATE_1_AP;
220 : }
221 : else
222 0 : eState = STATE_ERROR;
223 0 : else if ((*p == 'p' || *p == 'P') && nMinute < 60)
224 0 : if (nHour >= 1 && nHour <= 11)
225 : {
226 0 : nHour += 12;
227 0 : eState = STATE_1_AP;
228 : }
229 0 : else if (nHour == 12)
230 0 : eState = STATE_1_AP;
231 : else
232 0 : eState = STATE_ERROR;
233 0 : else if (ascii_isWhitespace(*p) && (nMinute < 60))
234 0 : eState = STATE_1_MINUTE_LWS;
235 : else
236 0 : eState = STATE_ERROR;
237 0 : break;
238 :
239 : case STATE_1_MINUTE_LWS:
240 0 : if (*p == 'a' || *p == 'A')
241 0 : if (nHour >= 1 && nHour <= 11)
242 0 : eState = STATE_1_AP;
243 0 : else if (nHour == 12)
244 : {
245 0 : nHour = 0;
246 0 : eState = STATE_1_AP;
247 : }
248 : else
249 0 : eState = STATE_ERROR;
250 0 : else if (*p == 'p' || *p == 'P')
251 0 : if (nHour >= 1 && nHour <= 11)
252 : {
253 0 : nHour += 12;
254 0 : eState = STATE_1_AP;
255 : }
256 0 : else if (nHour == 12)
257 0 : eState = STATE_1_AP;
258 : else
259 0 : eState = STATE_ERROR;
260 0 : else if (*p == '<')
261 0 : eState = STATE_1_LESS;
262 0 : else if (*p >= '0' && *p <= '9')
263 : {
264 0 : nSize = *p - '0';
265 0 : eState = STATE_1_SIZE;
266 : }
267 0 : else if (!ascii_isWhitespace(*p))
268 0 : eState = STATE_ERROR;
269 0 : break;
270 :
271 : case STATE_1_AP:
272 0 : eState = *p == 'm' || *p == 'M' ? STATE_1_APM : STATE_ERROR;
273 0 : break;
274 :
275 : case STATE_1_APM:
276 0 : if (*p == '<')
277 0 : eState = STATE_1_LESS;
278 0 : else if (*p >= '0' && *p <= '9')
279 : {
280 0 : nSize = *p - '0';
281 0 : eState = STATE_1_SIZE;
282 : }
283 0 : else if (!ascii_isWhitespace(*p))
284 0 : eState = STATE_ERROR;
285 0 : break;
286 :
287 : case STATE_1_LESS:
288 0 : eState = *p == 'd' || *p == 'D' ? STATE_1_D : STATE_ERROR;
289 0 : break;
290 :
291 : case STATE_1_D:
292 0 : eState = *p == 'i' || *p == 'I' ? STATE_1_DI : STATE_ERROR;
293 0 : break;
294 :
295 : case STATE_1_DI:
296 0 : eState = *p == 'r' || *p == 'R' ? STATE_1_DIR : STATE_ERROR;
297 0 : break;
298 :
299 : case STATE_1_DIR:
300 0 : if (*p == '>')
301 : {
302 0 : bDirectory = true;
303 0 : eState = STATE_LWS_NAME;
304 : }
305 : else
306 0 : eState = STATE_ERROR;
307 0 : break;
308 :
309 : case STATE_1_SIZE:
310 0 : if (*p >= '0' && *p <= '9')
311 0 : nSize = 10 * nSize + (*p - '0');
312 0 : else if (ascii_isWhitespace(*p))
313 0 : eState = STATE_LWS_NAME;
314 : else
315 0 : eState = STATE_ERROR;
316 0 : break;
317 :
318 : case STATE_2_SIZE:
319 0 : if (*p >= '0' && *p <= '9')
320 0 : nSize = 10 * nSize + (*p - '0');
321 0 : else if (ascii_isWhitespace(*p))
322 0 : eState = STATE_2_SIZE_LWS;
323 : else
324 0 : eState = STATE_ERROR;
325 0 : break;
326 :
327 : case STATE_2_SIZE_LWS:
328 0 : if (*p == 'd' || *p == 'D')
329 0 : eState = STATE_2_D;
330 0 : else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
331 0 : eState = STATE_2_ATTRIB;
332 0 : else if (*p >= '0' && *p <= '9')
333 : {
334 0 : nMonth = *p - '0';
335 0 : nDigits = 1;
336 0 : eState = STATE_2_MONTH;
337 : }
338 0 : else if (!ascii_isWhitespace(*p))
339 0 : eState = STATE_ERROR;
340 0 : break;
341 :
342 : case STATE_2_ATTRIB:
343 0 : if (ascii_isWhitespace(*p))
344 0 : eState = STATE_2_SIZE_LWS;
345 0 : else if ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z'))
346 0 : eState = STATE_ERROR;
347 0 : break;
348 :
349 : case STATE_2_D:
350 0 : if (*p == 'i' || *p == 'I')
351 0 : eState = STATE_2_DI;
352 0 : else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
353 0 : eState = STATE_2_ATTRIB;
354 0 : else if (ascii_isWhitespace(*p))
355 0 : eState = STATE_2_SIZE_LWS;
356 : else
357 0 : eState = STATE_ERROR;
358 0 : break;
359 :
360 : case STATE_2_DI:
361 0 : if (*p == 'r' || *p == 'R')
362 : {
363 0 : bDirectory = true;
364 0 : eState = STATE_2_DIR_LWS;
365 : }
366 : else
367 : {
368 0 : if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
369 0 : eState = STATE_2_ATTRIB;
370 0 : else if (ascii_isWhitespace(*p))
371 0 : eState = STATE_2_SIZE_LWS;
372 : else
373 0 : eState = STATE_ERROR;
374 : }
375 0 : break;
376 :
377 : case STATE_2_DIR_LWS:
378 0 : if (*p >= '0' && *p <= '9')
379 : {
380 0 : nMonth = *p - '0';
381 0 : nDigits = 1;
382 0 : eState = STATE_2_MONTH;
383 : }
384 0 : else if (!ascii_isWhitespace(*p))
385 0 : eState = STATE_ERROR;
386 0 : break;
387 :
388 : case STATE_2_MONTH:
389 0 : if (*p >= '0' && *p <= '9')
390 0 : if (nDigits < 2)
391 : {
392 0 : nMonth = 10 * nMonth + (*p - '0');
393 0 : ++nDigits;
394 : }
395 : else
396 0 : eState = STATE_ERROR;
397 0 : else if (*p == '-' && nMonth && nMonth <= 12)
398 : {
399 0 : nDigits = 0;
400 0 : eState = STATE_2_DAY;
401 : }
402 : else
403 0 : eState = STATE_ERROR;
404 0 : break;
405 :
406 : case STATE_2_DAY:
407 0 : if (*p >= '0' && *p <= '9')
408 0 : if (nDigits < 2)
409 : {
410 0 : nDay = 10 * nDay + (*p - '0');
411 0 : ++nDigits;
412 : }
413 : else
414 0 : eState = STATE_ERROR;
415 0 : else if (*p == '-' && nDay && nDay <= 31)
416 : {
417 0 : nDigits = 0;
418 0 : eState = STATE_2_YEAR;
419 : }
420 : else
421 0 : eState = STATE_ERROR;
422 0 : break;
423 :
424 : case STATE_2_YEAR:
425 0 : if (*p >= '0' && *p <= '9')
426 : {
427 0 : if (nDigits < 4)
428 : {
429 0 : nYear = 10 * nYear + (*p - '0');
430 0 : ++nDigits;
431 : }
432 : else
433 0 : eState = STATE_ERROR;
434 : }
435 : else
436 : {
437 0 : if (ascii_isWhitespace(*p))
438 0 : eState = STATE_2_YEAR_LWS;
439 : else
440 0 : eState = STATE_ERROR;
441 : }
442 0 : break;
443 :
444 : case STATE_2_YEAR_LWS:
445 0 : if (*p >= '0' && *p <= '9')
446 : {
447 0 : nHour = *p - '0';
448 0 : nDigits = 1;
449 0 : eState = STATE_2_HOUR;
450 : }
451 0 : else if (!ascii_isWhitespace(*p))
452 0 : eState = STATE_ERROR;
453 0 : break;
454 :
455 : case STATE_2_HOUR:
456 0 : if (*p >= '0' && *p <= '9')
457 0 : if (nDigits < 2)
458 : {
459 0 : nHour = 10 * nHour + (*p - '0');
460 0 : ++nDigits;
461 : }
462 : else
463 0 : eState = STATE_ERROR;
464 0 : else if (*p == ':' && nHour < 24)
465 : {
466 0 : nDigits = 0;
467 0 : eState = STATE_2_MINUTE;
468 : }
469 : else
470 0 : eState = STATE_ERROR;
471 0 : break;
472 :
473 : case STATE_2_MINUTE:
474 0 : if (*p >= '0' && *p <= '9')
475 : {
476 0 : if (nDigits < 2)
477 : {
478 0 : nMinute = 10 * nMinute + (*p - '0');
479 0 : ++nDigits;
480 : }
481 : else
482 0 : eState = STATE_ERROR;
483 : }
484 : else
485 : {
486 0 : if (ascii_isWhitespace(*p) && (nMinute < 60))
487 0 : eState = STATE_LWS_NAME;
488 : else
489 0 : eState = STATE_ERROR;
490 : }
491 0 : break;
492 :
493 : case STATE_LWS_NAME:
494 0 : if (!ascii_isWhitespace(*p))
495 : {
496 0 : setPath (rEntry.m_aName, p);
497 0 : if (bDirectory)
498 0 : rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR;
499 0 : rEntry.m_nSize = nSize;
500 :
501 0 : setYear (rEntry.m_aDate, nYear);
502 :
503 0 : rEntry.m_aDate.SetMonth(nMonth);
504 0 : rEntry.m_aDate.SetDay(nDay);
505 0 : rEntry.m_aDate.SetHour(nHour);
506 0 : rEntry.m_aDate.SetMin(nMinute);
507 :
508 0 : return true;
509 : }
510 0 : break;
511 : case STATE_ERROR:
512 0 : break;
513 : }
514 : }
515 :
516 0 : return false;
517 : }
518 :
519 : /*
520 : * parseVMS.
521 : * Directory entries may span one or two lines:
522 : *
523 : * entry: *lws name *1(*lws <NEWLINE>) 1*lws size 1*lws datetime rest
524 : *
525 : * name: filename "." filetype ";" version
526 : * filename: 1*39fchar
527 : * filetype: 1*39fchar
528 : * version: non0digit *digit
529 : *
530 : * size: "0" / non0digit *digit
531 : *
532 : * datetime: date 1*lwsp time
533 : * date: day "-" month "-" year
534 : * day: (*1"0" non0digit) / ("1"-"2" digit) / ("3" "0"-"1")
535 : * month: "JAN" / "FEB" / "MAR" / "APR" / "MAY" / "JUN" / "JUL" / "AUG"
536 : * / "SEP" / "OCT" / "NOV" / "DEC" ; all case insensitive
537 : * year: 2digit / 4digit
538 : * time: hour ":" minute
539 : * hour: ((*1"0" / "1") digit) / ("2" "0"-"3")
540 : * minute: "0"-"5" digit
541 : *
542 : * rest: *1(lws *<ANY>)
543 : *
544 : * lws: <TAB> / <SPACE>
545 : * non0digit: "1"-"9"
546 : * digit: "0" / non0digit
547 : * fchar: "A"-"Z" / "a"-"z" / digit / "-" / "_" / "$"
548 : *
549 : * For directories, the returned name is the <filename> part; for non-
550 : * directory files, the returned name is the <filename "." filetype> part.
551 : * An entry is a directory iff its filetype is "DIR" (ignoring case).
552 : *
553 : * The READ, WRITE, and ISLINK mode bits are not supported.
554 : *
555 : * The returned size is the <size> part, multiplied by 512, and with the high
556 : * order bits truncated to fit into a ULONG.
557 : *
558 : */
559 0 : bool FTPDirectoryParser::parseVMS (
560 : FTPDirentry &rEntry,
561 : const sal_Char *pBuffer)
562 : {
563 0 : static OUString aFirstLineName;
564 : static bool bFirstLineDir = false;
565 :
566 0 : for (bool bFirstLine = true;; bFirstLine = false)
567 : {
568 0 : const sal_Char *p = pBuffer;
569 0 : if (bFirstLine)
570 : {
571 : // Skip <*lws> part:
572 0 : while (*p == '\t' || *p == ' ')
573 0 : ++p;
574 :
575 : // Parse <filename "."> part:
576 0 : const sal_Char *pFileName = p;
577 0 : while ((*p >= 'A' && *p <= 'Z') ||
578 0 : (*p >= 'a' && *p <= 'z') ||
579 0 : (*p >= '0' && *p <= '9') ||
580 0 : *p == '-' || *p == '_' || *p == '$')
581 0 : ++p;
582 :
583 0 : if (*p != '.' || p == pFileName || p - pFileName > 39)
584 : {
585 0 : if (!aFirstLineName.isEmpty())
586 0 : continue;
587 : else
588 0 : return false;
589 : }
590 :
591 : // Parse <filetype ";"> part:
592 0 : const sal_Char *pFileType = ++p;
593 0 : while ((*p >= 'A' && *p <= 'Z') ||
594 0 : (*p >= 'a' && *p <= 'z') ||
595 0 : (*p >= '0' && *p <= '9') ||
596 0 : *p == '-' || *p == '_' || *p == '$')
597 0 : ++p;
598 :
599 0 : if (*p != ';' || p == pFileName || p - pFileName > 39)
600 : {
601 0 : if (!aFirstLineName.isEmpty())
602 0 : continue;
603 : else
604 0 : return false;
605 : }
606 0 : ++p;
607 :
608 : // Set entry's name and mode (ISDIR flag):
609 0 : if ((p - pFileType == 4) &&
610 0 : (pFileType[0] == 'D' || pFileType[0] == 'd') &&
611 0 : (pFileType[1] == 'I' || pFileType[1] == 'i') &&
612 0 : (pFileType[2] == 'R' || pFileType[2] == 'r') )
613 : {
614 0 : setPath (rEntry.m_aName, pFileName, (pFileType - pFileName));
615 0 : rEntry.m_nMode = INETCOREFTP_FILEMODE_ISDIR;
616 : }
617 : else
618 : {
619 0 : setPath (rEntry.m_aName, pFileName, (p - pFileName));
620 0 : rEntry.m_nMode = 0;
621 : }
622 :
623 : // Skip <version> part:
624 0 : if (*p < '1' || *p > '9')
625 : {
626 0 : if (!aFirstLineName.isEmpty())
627 0 : continue;
628 : else
629 0 : return false;
630 : }
631 0 : ++p;
632 0 : while (*p >= '0' && *p <= '9')
633 0 : ++p;
634 :
635 : // Parse <1*lws> or <*lws <NEWLINE>> part:
636 0 : bool bLWS = false;
637 0 : while (*p == '\t' || *p == ' ')
638 : {
639 0 : bLWS = true;
640 0 : ++p;
641 : }
642 0 : if (*p)
643 : {
644 0 : if (!bLWS)
645 : {
646 0 : if (!aFirstLineName.isEmpty())
647 0 : continue;
648 : else
649 0 : return false;
650 : }
651 : }
652 : else
653 : {
654 : /*
655 : * First line of entry spanning two lines,
656 : * wait for second line.
657 : */
658 0 : aFirstLineName = rEntry.m_aName;
659 : bFirstLineDir =
660 0 : ((rEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) != 0);
661 0 : return false;
662 : }
663 : }
664 : else
665 : {
666 : /*
667 : * Second line of entry spanning two lines,
668 : * restore entry's name and mode (ISDIR flag).
669 : */
670 0 : rEntry.m_aName = aFirstLineName;
671 0 : rEntry.m_nMode = (bFirstLineDir ? INETCOREFTP_FILEMODE_ISDIR : 0);
672 :
673 : // Skip <1*lws> part:
674 0 : if (*p != '\t' && *p != ' ')
675 0 : return false;
676 0 : ++p;
677 0 : while (*p == '\t' || *p == ' ')
678 0 : ++p;
679 : }
680 :
681 : // Parse <size> part and set entry's size:
682 0 : if (*p < '0' || *p > '9')
683 0 : return false;
684 0 : ULONG nSize = *p - '0';
685 0 : if (*p++ != '0')
686 0 : while (*p >= '0' && *p <= '9')
687 0 : nSize = 10 * rEntry.m_nSize + (*p++ - '0');
688 0 : rEntry.m_nSize = 512 * nSize;
689 :
690 : // Skip <1*lws> part:
691 0 : if (*p != '\t' && *p != ' ')
692 0 : return false;
693 0 : ++p;
694 0 : while (*p == '\t' || *p == ' ')
695 0 : ++p;
696 :
697 : // Parse <day "-"> part and set entry date's day:
698 : sal_uInt16 nDay;
699 0 : if (*p == '0')
700 : {
701 0 : ++p;
702 0 : if (*p < '1' || *p > '9')
703 0 : return false;
704 0 : nDay = *p++ - '0';
705 : }
706 0 : else if (*p == '1' || *p == '2')
707 : {
708 0 : nDay = *p++ - '0';
709 0 : if (*p >= '0' && *p <= '9')
710 0 : nDay = 10 * nDay + (*p++ - '0');
711 : }
712 0 : else if (*p == '3')
713 : {
714 0 : ++p;
715 0 : nDay = (*p == '0' || *p == '1') ? 30 + (*p++ - '0') : 3;
716 : }
717 0 : else if (*p >= '4' && *p <= '9')
718 0 : nDay = *p++ - '0';
719 : else
720 0 : return false;
721 :
722 0 : rEntry.m_aDate.SetDay(nDay);
723 0 : if (*p++ != '-')
724 0 : return false;
725 :
726 : // Parse <month "-"> part and set entry date's month:
727 0 : sal_Char const * pMonth = p;
728 0 : sal_Int32 const monthLen = 3;
729 0 : for (int i = 0; i < monthLen; ++i)
730 : {
731 0 : if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')))
732 0 : return false;
733 0 : ++p;
734 : }
735 0 : if (rtl_str_compareIgnoreAsciiCase_WithLength(
736 0 : pMonth, monthLen, "JAN", monthLen) == 0)
737 0 : rEntry.m_aDate.SetMonth(1);
738 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
739 0 : pMonth, monthLen, "FEB", monthLen) == 0)
740 0 : rEntry.m_aDate.SetMonth(2);
741 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
742 0 : pMonth, monthLen, "MAR", monthLen) == 0)
743 0 : rEntry.m_aDate.SetMonth(3);
744 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
745 0 : pMonth, monthLen, "APR", monthLen) == 0)
746 0 : rEntry.m_aDate.SetMonth(4);
747 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
748 0 : pMonth, monthLen, "MAY", monthLen) == 0)
749 0 : rEntry.m_aDate.SetMonth(5);
750 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
751 0 : pMonth, monthLen, "JUN", monthLen) == 0)
752 0 : rEntry.m_aDate.SetMonth(6);
753 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
754 0 : pMonth, monthLen, "JUL", monthLen) == 0)
755 0 : rEntry.m_aDate.SetMonth(7);
756 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
757 0 : pMonth, monthLen, "AUG", monthLen) == 0)
758 0 : rEntry.m_aDate.SetMonth(8);
759 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
760 0 : pMonth, monthLen, "SEP", monthLen) == 0)
761 0 : rEntry.m_aDate.SetMonth(9);
762 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
763 0 : pMonth, monthLen, "OCT", monthLen) == 0)
764 0 : rEntry.m_aDate.SetMonth(10);
765 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
766 0 : pMonth, monthLen, "NOV", monthLen) == 0)
767 0 : rEntry.m_aDate.SetMonth(11);
768 0 : else if (rtl_str_compareIgnoreAsciiCase_WithLength(
769 0 : pMonth, monthLen, "DEC", monthLen) == 0)
770 0 : rEntry.m_aDate.SetMonth(12);
771 : else
772 0 : return false;
773 0 : if (*p++ != '-')
774 0 : return false;
775 :
776 : // Parse <year> part and set entry date's year:
777 0 : sal_uInt16 nYear = 0;
778 0 : for (int i = 0; i < 2; ++i)
779 : {
780 0 : if (*p < '0' || *p > '9')
781 0 : return false;
782 0 : nYear = 10 * nYear + (*p++ - '0');
783 : }
784 0 : if (*p >= '0' && *p <= '9')
785 : {
786 0 : nYear = 10 * nYear + (*p++ - '0');
787 0 : if (*p < '0' || *p > '9')
788 0 : return false;
789 0 : nYear = 10 * nYear + (*p++ - '0');
790 : }
791 0 : setYear (rEntry.m_aDate, nYear);
792 :
793 : // Skip <1*lws> part:
794 0 : if (*p != '\t' && *p != ' ')
795 0 : return false;
796 0 : ++p;
797 0 : while (*p == '\t' || *p == ' ')
798 0 : ++p;
799 :
800 : // Parse <hour ":"> part and set entry time's hour:
801 : sal_uInt16 nHour;
802 0 : if (*p == '0' || *p == '1')
803 : {
804 0 : nHour = *p++ - '0';
805 0 : if (*p >= '0' && *p <= '9')
806 0 : nHour = 10 * nHour + (*p++ - '0');
807 : }
808 0 : else if (*p == '2')
809 : {
810 0 : ++p;
811 0 : nHour = (*p >= '0' && *p <= '3') ? 20 + (*p++ - '0') : 2;
812 : }
813 0 : else if (*p >= '3' && *p <= '9')
814 0 : nHour = *p++ - '0';
815 : else
816 0 : return false;
817 :
818 0 : rEntry.m_aDate.SetHour(nHour);
819 0 : if (*p++ != ':')
820 0 : return false;
821 :
822 : /*
823 : * Parse <minute> part and set entry time's minutes,
824 : * seconds (0), and nanoseconds (0).
825 : */
826 0 : if (*p < '0' || *p > '5')
827 0 : return false;
828 :
829 0 : sal_uInt16 nMinute = *p++ - '0';
830 0 : if (*p < '0' || *p > '9')
831 0 : return false;
832 :
833 0 : nMinute = 10 * nMinute + (*p++ - '0');
834 0 : rEntry.m_aDate.SetMin(nMinute);
835 0 : rEntry.m_aDate.SetSec(0);
836 0 : rEntry.m_aDate.SetNanoSec(0);
837 :
838 : // Skip <rest> part:
839 0 : if (*p && (*p != '\t' && *p != ' '))
840 0 : return false;
841 :
842 0 : return true;
843 0 : }
844 : }
845 :
846 : /*
847 : * parseUNIX
848 : */
849 0 : bool FTPDirectoryParser::parseUNIX (
850 : FTPDirentry &rEntry,
851 : const sal_Char *pBuffer)
852 : {
853 : const sal_Char *p1, *p2;
854 0 : p1 = p2 = pBuffer;
855 :
856 0 : if (!((*p1 == '-') || (*p1 == 'd') || (*p1 == 'l')))
857 0 : return false;
858 :
859 : // 1st column: FileMode.
860 0 : if (*p1 == 'd')
861 0 : rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR;
862 :
863 0 : if (*p1 == 'l')
864 0 : rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISLINK;
865 :
866 : // Skip to end of column and set rights by the way
867 0 : while (*p1 && !ascii_isWhitespace(*p1)) {
868 0 : if(*p1 == 'r')
869 0 : rEntry.m_nMode |= INETCOREFTP_FILEMODE_READ;
870 0 : else if(*p1 == 'w')
871 0 : rEntry.m_nMode |= INETCOREFTP_FILEMODE_WRITE;
872 0 : p1++;
873 : }
874 :
875 : /*
876 : * Scan for the sequence of size and date fields:
877 : * *LWS 1*DIGIT 1*LWS 3CHAR 1*LWS 1*2DIGIT 1*LWS
878 : * (4DIGIT / (1*2DIGIT ":" 2DIGIT)) 1*LWS
879 : */
880 : enum Mode
881 : {
882 : FOUND_NONE, FOUND_SIZE, FOUND_MONTH, FOUND_DAY, FOUND_YEAR_TIME
883 : };
884 :
885 0 : const sal_Char *pDayStart = 0;
886 0 : const sal_Char *pDayEnd = 0;
887 : Mode eMode;
888 0 : for (eMode = FOUND_NONE; *p1 && eMode != FOUND_YEAR_TIME; p1 = p2 + 1)
889 : {
890 0 : while (*p1 && ascii_isWhitespace(*p1))
891 0 : ++p1;
892 0 : p2 = p1;
893 0 : while (*p2 && !ascii_isWhitespace(*p2))
894 0 : ++p2;
895 :
896 0 : switch (eMode)
897 : {
898 : case FOUND_NONE:
899 0 : if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
900 0 : eMode = FOUND_SIZE;
901 0 : break;
902 :
903 : case FOUND_SIZE:
904 0 : if (parseUNIX_isMonthField (p1, p2, rEntry.m_aDate))
905 0 : eMode = FOUND_MONTH;
906 0 : else if (!parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
907 0 : eMode = FOUND_NONE;
908 0 : break;
909 :
910 : case FOUND_MONTH:
911 0 : if (parseUNIX_isDayField (p1, p2, rEntry.m_aDate))
912 : {
913 0 : pDayStart = p1;
914 0 : pDayEnd = p2;
915 0 : eMode = FOUND_DAY;
916 : }
917 0 : else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
918 0 : eMode = FOUND_SIZE;
919 : else
920 0 : eMode = FOUND_NONE;
921 0 : break;
922 :
923 : case FOUND_DAY:
924 0 : if (parseUNIX_isYearTimeField (p1, p2, rEntry.m_aDate))
925 0 : eMode = FOUND_YEAR_TIME;
926 0 : else if (
927 : parseUNIX_isSizeField (
928 0 : pDayStart, pDayEnd, rEntry.m_nSize) &&
929 : parseUNIX_isMonthField (
930 0 : p1, p2, rEntry.m_aDate))
931 0 : eMode = FOUND_MONTH;
932 0 : else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
933 0 : eMode = FOUND_SIZE;
934 : else
935 0 : eMode = FOUND_NONE;
936 0 : break;
937 : case FOUND_YEAR_TIME:
938 0 : break;
939 : }
940 : }
941 :
942 0 : if (eMode == FOUND_YEAR_TIME)
943 : {
944 : // 9th column: FileName (rest of line).
945 0 : while (*p1 && ascii_isWhitespace(*p1)) p1++;
946 0 : setPath (rEntry.m_aName, p1);
947 :
948 : // Done.
949 0 : return true;
950 : }
951 0 : return false;
952 : }
953 :
954 : /*
955 : * parseUNIX_isSizeField.
956 : */
957 0 : bool FTPDirectoryParser::parseUNIX_isSizeField (
958 : const sal_Char *pStart,
959 : const sal_Char *pEnd,
960 : sal_uInt32 &rSize)
961 : {
962 0 : if (!*pStart || !*pEnd || pStart == pEnd)
963 0 : return false;
964 :
965 0 : rSize = 0;
966 0 : if (*pStart >= '0' && *pStart <= '9')
967 : {
968 0 : for (; pStart < pEnd; ++pStart)
969 0 : if ((*pStart >= '0') && (*pStart <= '9'))
970 0 : rSize = 10 * rSize + (*pStart - '0');
971 : else
972 0 : return false;
973 0 : return true;
974 : }
975 : else
976 : {
977 : /*
978 : * For a combination of long group name and large file size,
979 : * some FTPDs omit LWS between those two columns.
980 : */
981 0 : int nNonDigits = 0;
982 0 : int nDigits = 0;
983 :
984 0 : for (; pStart < pEnd; ++pStart)
985 0 : if ((*pStart >= '1') && (*pStart <= '9'))
986 : {
987 0 : ++nDigits;
988 0 : rSize = 10 * rSize + (*pStart - '0');
989 : }
990 0 : else if ((*pStart == '0') && nDigits)
991 : {
992 0 : ++nDigits;
993 0 : rSize *= 10;
994 : }
995 0 : else if ((*pStart > ' ') && (sal::static_int_cast<sal_uInt8>(*pStart) <= '\x7F'))
996 : {
997 0 : nNonDigits += nDigits + 1;
998 0 : nDigits = 0;
999 0 : rSize = 0;
1000 : }
1001 : else
1002 0 : return false;
1003 0 : return ((nNonDigits >= 9) && (nDigits >= 7));
1004 : }
1005 : }
1006 :
1007 : /*
1008 : * parseUNIX_isMonthField.
1009 : */
1010 0 : bool FTPDirectoryParser::parseUNIX_isMonthField (
1011 : const sal_Char *pStart,
1012 : const sal_Char *pEnd,
1013 : DateTime &rDateTime)
1014 : {
1015 0 : if (!*pStart || !*pEnd || pStart + 3 != pEnd)
1016 0 : return false;
1017 :
1018 0 : if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1019 0 : (pStart[1] == 'a' || pStart[1] == 'A') &&
1020 0 : (pStart[2] == 'n' || pStart[2] == 'N') )
1021 : {
1022 0 : rDateTime.SetMonth(1);
1023 0 : return true;
1024 : }
1025 0 : if ((pStart[0] == 'f' || pStart[0] == 'F') &&
1026 0 : (pStart[1] == 'e' || pStart[1] == 'E') &&
1027 0 : (pStart[2] == 'b' || pStart[2] == 'B') )
1028 : {
1029 0 : rDateTime.SetMonth(2);
1030 0 : return true;
1031 : }
1032 0 : if ((pStart[0] == 'm' || pStart[0] == 'M') &&
1033 0 : (pStart[1] == 'a' || pStart[1] == 'A') &&
1034 0 : (pStart[2] == 'r' || pStart[2] == 'R') )
1035 : {
1036 0 : rDateTime.SetMonth(3);
1037 0 : return true;
1038 : }
1039 0 : if ((pStart[0] == 'a' || pStart[0] == 'A') &&
1040 0 : (pStart[1] == 'p' || pStart[1] == 'P') &&
1041 0 : (pStart[2] == 'r' || pStart[2] == 'R') )
1042 : {
1043 0 : rDateTime.SetMonth(4);
1044 0 : return true;
1045 : }
1046 0 : if ((pStart[0] == 'm' || pStart[0] == 'M') &&
1047 0 : (pStart[1] == 'a' || pStart[1] == 'A') &&
1048 0 : (pStart[2] == 'y' || pStart[2] == 'Y') )
1049 : {
1050 0 : rDateTime.SetMonth(5);
1051 0 : return true;
1052 : }
1053 0 : if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1054 0 : (pStart[1] == 'u' || pStart[1] == 'U') &&
1055 0 : (pStart[2] == 'n' || pStart[2] == 'N') )
1056 : {
1057 0 : rDateTime.SetMonth(6);
1058 0 : return true;
1059 : }
1060 0 : if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1061 0 : (pStart[1] == 'u' || pStart[1] == 'U') &&
1062 0 : (pStart[2] == 'l' || pStart[2] == 'L') )
1063 : {
1064 0 : rDateTime.SetMonth(7);
1065 0 : return true;
1066 : }
1067 0 : if ((pStart[0] == 'a' || pStart[0] == 'A') &&
1068 0 : (pStart[1] == 'u' || pStart[1] == 'U') &&
1069 0 : (pStart[2] == 'g' || pStart[2] == 'G') )
1070 : {
1071 0 : rDateTime.SetMonth(8);
1072 0 : return true;
1073 : }
1074 0 : if ((pStart[0] == 's' || pStart[0] == 'S') &&
1075 0 : (pStart[1] == 'e' || pStart[1] == 'E') &&
1076 0 : (pStart[2] == 'p' || pStart[2] == 'P') )
1077 : {
1078 0 : rDateTime.SetMonth(9);
1079 0 : return true;
1080 : }
1081 0 : if ((pStart[0] == 'o' || pStart[0] == 'O') &&
1082 0 : (pStart[1] == 'c' || pStart[1] == 'C') &&
1083 0 : (pStart[2] == 't' || pStart[2] == 'T') )
1084 : {
1085 0 : rDateTime.SetMonth(10);
1086 0 : return true;
1087 : }
1088 0 : if ((pStart[0] == 'n' || pStart[0] == 'N') &&
1089 0 : (pStart[1] == 'o' || pStart[1] == 'O') &&
1090 0 : (pStart[2] == 'v' || pStart[2] == 'V') )
1091 : {
1092 0 : rDateTime.SetMonth(11);
1093 0 : return true;
1094 : }
1095 0 : if ((pStart[0] == 'd' || pStart[0] == 'D') &&
1096 0 : (pStart[1] == 'e' || pStart[1] == 'E') &&
1097 0 : (pStart[2] == 'c' || pStart[2] == 'C') )
1098 : {
1099 0 : rDateTime.SetMonth(12);
1100 0 : return true;
1101 : }
1102 0 : return false;
1103 : }
1104 :
1105 : /*
1106 : * parseUNIX_isDayField.
1107 : */
1108 0 : bool FTPDirectoryParser::parseUNIX_isDayField (
1109 : const sal_Char *pStart,
1110 : const sal_Char *pEnd,
1111 : DateTime &rDateTime)
1112 : {
1113 0 : if (!*pStart || !*pEnd || pStart == pEnd)
1114 0 : return false;
1115 0 : if (*pStart < '0' || *pStart > '9')
1116 0 : return false;
1117 :
1118 0 : sal_uInt16 nDay = *pStart - '0';
1119 0 : if (pStart + 1 < pEnd)
1120 : {
1121 0 : if (pStart + 2 != pEnd || pStart[1] < '0' || pStart[1] > '9')
1122 0 : return false;
1123 0 : nDay = 10 * nDay + (pStart[1] - '0');
1124 : }
1125 0 : if (!nDay || nDay > 31)
1126 0 : return false;
1127 :
1128 0 : rDateTime.SetDay(nDay);
1129 0 : return true;
1130 : }
1131 :
1132 : /*
1133 : * parseUNIX_isYearTimeField.
1134 : */
1135 0 : bool FTPDirectoryParser::parseUNIX_isYearTimeField (
1136 : const sal_Char *pStart,
1137 : const sal_Char *pEnd,
1138 : DateTime &rDateTime)
1139 : {
1140 0 : if (!*pStart || !*pEnd || pStart == pEnd ||
1141 0 : *pStart < '0' || *pStart > '9')
1142 0 : return false;
1143 :
1144 0 : sal_uInt16 nNumber = *pStart - '0';
1145 0 : ++pStart;
1146 :
1147 0 : if (pStart == pEnd)
1148 0 : return false;
1149 0 : if (*pStart == ':')
1150 0 : return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime);
1151 0 : if (*pStart < '0' || *pStart > '9')
1152 0 : return false;
1153 :
1154 0 : nNumber = 10 * nNumber + (*pStart - '0');
1155 0 : ++pStart;
1156 :
1157 0 : if (pStart == pEnd)
1158 0 : return false;
1159 0 : if (*pStart == ':')
1160 0 : return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime);
1161 0 : if (*pStart < '0' || *pStart > '9')
1162 0 : return false;
1163 :
1164 0 : nNumber = 10 * nNumber + (*pStart - '0');
1165 0 : ++pStart;
1166 :
1167 0 : if (pStart == pEnd || *pStart < '0' || *pStart > '9')
1168 0 : return false;
1169 :
1170 0 : nNumber = 10 * nNumber + (*pStart - '0');
1171 0 : if (pStart + 1 != pEnd || nNumber < 1970)
1172 0 : return false;
1173 :
1174 0 : rDateTime.SetYear(nNumber);
1175 0 : rDateTime.SetTime(0);
1176 0 : return true;
1177 : }
1178 :
1179 : /*
1180 : * parseUNIX_isTime.
1181 : */
1182 0 : bool FTPDirectoryParser::parseUNIX_isTime (
1183 : const sal_Char *pStart,
1184 : const sal_Char *pEnd,
1185 : sal_uInt16 nHour,
1186 : DateTime &rDateTime)
1187 : {
1188 0 : if ((nHour > 23 ) || (pStart + 3 != pEnd) ||
1189 0 : (pStart[1] < '0') || (pStart[1] > '5') ||
1190 0 : (pStart[2] < '0') || (pStart[2] > '9') )
1191 0 : return false;
1192 :
1193 0 : sal_uInt16 nMin = 10 * (pStart[1] - '0') + (pStart[2] - '0');
1194 :
1195 0 : rDateTime.SetHour (nHour);
1196 0 : rDateTime.SetMin (nMin);
1197 0 : rDateTime.SetSec (0);
1198 0 : rDateTime.SetNanoSec (0);
1199 :
1200 : // Date aCurDate;
1201 : // if (rDateTime.GetMonth() > aCurDate.GetMonth())
1202 : // rDateTime.SetYear(aCurDate.GetYear() - 1);
1203 : // else
1204 : // rDateTime.SetYear(aCurDate.GetYear());
1205 : // return sal_True;
1206 :
1207 : TimeValue aTimeVal;
1208 0 : osl_getSystemTime(&aTimeVal);
1209 : oslDateTime aCurrDateTime;
1210 0 : osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime);
1211 :
1212 0 : if (rDateTime.GetMonth() > aCurrDateTime.Month)
1213 0 : rDateTime.SetYear(aCurrDateTime.Year - 1);
1214 : else
1215 0 : rDateTime.SetYear(aCurrDateTime.Year);
1216 0 : return true;
1217 : }
1218 :
1219 : /*
1220 : * setYear.
1221 : *
1222 : * Two-digit years are taken as within 50 years back and 49 years forward
1223 : * (both ends inclusive) from the current year. The returned date is not
1224 : * checked for validity of the given day in the given month and year.
1225 : *
1226 : */
1227 0 : bool FTPDirectoryParser::setYear (
1228 : DateTime &rDateTime, sal_uInt16 nYear)
1229 : {
1230 0 : if (nYear < 100)
1231 : {
1232 : TimeValue aTimeVal;
1233 0 : osl_getSystemTime(&aTimeVal);
1234 : oslDateTime aCurrDateTime;
1235 0 : osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime);
1236 0 : sal_uInt16 nCurrentYear = aCurrDateTime.Year;
1237 : // sal_uInt16 nCurrentYear = Date().GetYear();
1238 0 : sal_uInt16 nCurrentCentury = nCurrentYear / 100;
1239 0 : nCurrentYear %= 100;
1240 0 : if (nCurrentYear < 50)
1241 0 : if (nYear <= nCurrentYear)
1242 0 : nYear += nCurrentCentury * 100;
1243 0 : else if (nYear < nCurrentYear + 50)
1244 0 : nYear += nCurrentCentury * 100;
1245 : else
1246 0 : nYear += (nCurrentCentury - 1) * 100;
1247 : else
1248 0 : if (nYear >= nCurrentYear)
1249 0 : nYear += nCurrentCentury * 100;
1250 0 : else if (nYear >= nCurrentYear - 50)
1251 0 : nYear += nCurrentCentury * 100;
1252 : else
1253 0 : nYear += (nCurrentCentury + 1) * 100;
1254 : }
1255 :
1256 0 : rDateTime.SetYear(nYear);
1257 0 : return true;
1258 : }
1259 :
1260 : /*
1261 : * setPath.
1262 : */
1263 0 : bool FTPDirectoryParser::setPath (
1264 : OUString &rPath, const sal_Char *value, sal_Int32 length)
1265 : {
1266 0 : if (value)
1267 : {
1268 0 : if (length < 0)
1269 0 : length = rtl_str_getLength (value);
1270 0 : rPath = OUString (value, length, RTL_TEXTENCODING_UTF8);
1271 : }
1272 0 : return (!!value);
1273 : }
1274 :
1275 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|