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