fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / ucb / source / ucp / ftp / ftpdirp.cxx
blobd5d7d93e48bec07af9d13ab2e8864052c253997b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 /**************************************************************************
22 TODO
23 **************************************************************************
25 *************************************************************************/
26 #include "ftpdirp.hxx"
27 #include <osl/time.h>
30 using namespace ftp;
32 typedef sal_uInt32 ULONG;
34 inline bool ascii_isWhitespace( sal_Unicode ch )
36 return ((ch <= 0x20) && ch);
41 /*========================================================================
43 * FTPDirectoryParser implementation.
45 *======================================================================*/
47 * parseDOS.
48 * Accepts one of two styles:
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
54 * interpreted as: mm.dd.yy hh:mm (size / <DIR>) name
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
59 * interpreted as: size attribs DIR mm-dd-yy hh:mm name
62 bool FTPDirectoryParser::parseDOS (
63 FTPDirentry &rEntry,
64 const sal_Char *pBuffer)
66 bool bDirectory = false;
67 sal_uInt32 nSize = 0;
68 sal_uInt16 nYear = 0;
69 sal_uInt16 nMonth = 0;
70 sal_uInt16 nDay = 0;
71 sal_uInt16 nHour = 0;
72 sal_uInt16 nMinute = 0;
74 enum StateType
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
90 int nDigits = 0;
91 enum StateType eState = STATE_INIT_LWS;
92 for (const sal_Char *p = pBuffer;
93 eState != STATE_ERROR && *p;
94 ++p)
96 switch (eState)
98 case STATE_INIT_LWS:
99 if (*p >= '0' && *p <= '9')
101 nMonth = *p - '0';
102 nDigits = 1;
103 eState = STATE_MONTH_OR_SIZE;
105 else if (!ascii_isWhitespace(*p))
106 eState = STATE_ERROR;
107 break;
109 case STATE_MONTH_OR_SIZE:
110 if (*p >= '0' && *p <= '9')
112 nMonth = 10 * nMonth + (*p - '0');
113 if (nDigits < 2)
114 ++nDigits;
115 else
117 nSize = nMonth;
118 nMonth = 0;
119 eState = STATE_2_SIZE;
122 else if (ascii_isWhitespace(*p))
124 nSize = nMonth;
125 nMonth = 0;
126 eState = STATE_2_SIZE_LWS;
128 else if ((*p == '.' || *p == '-') && nMonth && nMonth <= 12)
130 nDigits = 0;
131 eState = STATE_1_DAY;
133 else
134 eState = STATE_ERROR;
135 break;
137 case STATE_1_DAY:
138 if (*p >= '0' && *p <= '9')
139 if (nDigits < 2)
141 nDay = 10 * nDay + (*p - '0');
142 ++nDigits;
144 else
145 eState = STATE_ERROR;
146 else if ((*p == '.' || *p == '-') && nDay && nDay <= 31)
148 nDigits = 0;
149 eState = STATE_1_YEAR;
151 else
152 eState = STATE_ERROR;
153 break;
155 case STATE_1_YEAR:
156 if (*p >= '0' && *p <= '9')
158 if (nDigits < 4)
160 nYear = 10 * nYear + (*p - '0');
161 ++nDigits;
163 else
164 eState = STATE_ERROR;
166 else
168 if (ascii_isWhitespace(*p))
169 eState = STATE_1_YEAR_LWS;
170 else
171 eState = STATE_ERROR;
173 break;
175 case STATE_1_YEAR_LWS:
176 if (*p >= '0' && *p <= '9')
178 nHour = *p - '0';
179 nDigits = 1;
180 eState = STATE_1_HOUR;
182 else if (!ascii_isWhitespace(*p))
183 eState = STATE_ERROR;
184 break;
186 case STATE_1_HOUR:
187 if (*p >= '0' && *p <= '9')
188 if (nDigits < 2)
190 nHour = 10 * nHour + (*p - '0');
191 ++nDigits;
193 else
194 eState = STATE_ERROR;
195 else if (*p == ':' && nHour < 24)
197 nDigits = 0;
198 eState = STATE_1_MINUTE;
200 else
201 eState = STATE_ERROR;
202 break;
204 case STATE_1_MINUTE:
205 if (*p >= '0' && *p <= '9')
206 if (nDigits < 2)
208 nMinute = 10 * nMinute + (*p - '0');
209 ++nDigits;
211 else
212 eState = STATE_ERROR;
213 else if ((*p == 'a' || *p == 'A') && nMinute < 60)
214 if (nHour >= 1 && nHour <= 11)
215 eState = STATE_1_AP;
216 else if (nHour == 12)
218 nHour = 0;
219 eState = STATE_1_AP;
221 else
222 eState = STATE_ERROR;
223 else if ((*p == 'p' || *p == 'P') && nMinute < 60)
224 if (nHour >= 1 && nHour <= 11)
226 nHour += 12;
227 eState = STATE_1_AP;
229 else if (nHour == 12)
230 eState = STATE_1_AP;
231 else
232 eState = STATE_ERROR;
233 else if (ascii_isWhitespace(*p) && (nMinute < 60))
234 eState = STATE_1_MINUTE_LWS;
235 else
236 eState = STATE_ERROR;
237 break;
239 case STATE_1_MINUTE_LWS:
240 if (*p == 'a' || *p == 'A')
241 if (nHour >= 1 && nHour <= 11)
242 eState = STATE_1_AP;
243 else if (nHour == 12)
245 nHour = 0;
246 eState = STATE_1_AP;
248 else
249 eState = STATE_ERROR;
250 else if (*p == 'p' || *p == 'P')
251 if (nHour >= 1 && nHour <= 11)
253 nHour += 12;
254 eState = STATE_1_AP;
256 else if (nHour == 12)
257 eState = STATE_1_AP;
258 else
259 eState = STATE_ERROR;
260 else if (*p == '<')
261 eState = STATE_1_LESS;
262 else if (*p >= '0' && *p <= '9')
264 nSize = *p - '0';
265 eState = STATE_1_SIZE;
267 else if (!ascii_isWhitespace(*p))
268 eState = STATE_ERROR;
269 break;
271 case STATE_1_AP:
272 eState = *p == 'm' || *p == 'M' ? STATE_1_APM : STATE_ERROR;
273 break;
275 case STATE_1_APM:
276 if (*p == '<')
277 eState = STATE_1_LESS;
278 else if (*p >= '0' && *p <= '9')
280 nSize = *p - '0';
281 eState = STATE_1_SIZE;
283 else if (!ascii_isWhitespace(*p))
284 eState = STATE_ERROR;
285 break;
287 case STATE_1_LESS:
288 eState = *p == 'd' || *p == 'D' ? STATE_1_D : STATE_ERROR;
289 break;
291 case STATE_1_D:
292 eState = *p == 'i' || *p == 'I' ? STATE_1_DI : STATE_ERROR;
293 break;
295 case STATE_1_DI:
296 eState = *p == 'r' || *p == 'R' ? STATE_1_DIR : STATE_ERROR;
297 break;
299 case STATE_1_DIR:
300 if (*p == '>')
302 bDirectory = true;
303 eState = STATE_LWS_NAME;
305 else
306 eState = STATE_ERROR;
307 break;
309 case STATE_1_SIZE:
310 if (*p >= '0' && *p <= '9')
311 nSize = 10 * nSize + (*p - '0');
312 else if (ascii_isWhitespace(*p))
313 eState = STATE_LWS_NAME;
314 else
315 eState = STATE_ERROR;
316 break;
318 case STATE_2_SIZE:
319 if (*p >= '0' && *p <= '9')
320 nSize = 10 * nSize + (*p - '0');
321 else if (ascii_isWhitespace(*p))
322 eState = STATE_2_SIZE_LWS;
323 else
324 eState = STATE_ERROR;
325 break;
327 case STATE_2_SIZE_LWS:
328 if (*p == 'd' || *p == 'D')
329 eState = STATE_2_D;
330 else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
331 eState = STATE_2_ATTRIB;
332 else if (*p >= '0' && *p <= '9')
334 nMonth = *p - '0';
335 nDigits = 1;
336 eState = STATE_2_MONTH;
338 else if (!ascii_isWhitespace(*p))
339 eState = STATE_ERROR;
340 break;
342 case STATE_2_ATTRIB:
343 if (ascii_isWhitespace(*p))
344 eState = STATE_2_SIZE_LWS;
345 else if ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z'))
346 eState = STATE_ERROR;
347 break;
349 case STATE_2_D:
350 if (*p == 'i' || *p == 'I')
351 eState = STATE_2_DI;
352 else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
353 eState = STATE_2_ATTRIB;
354 else if (ascii_isWhitespace(*p))
355 eState = STATE_2_SIZE_LWS;
356 else
357 eState = STATE_ERROR;
358 break;
360 case STATE_2_DI:
361 if (*p == 'r' || *p == 'R')
363 bDirectory = true;
364 eState = STATE_2_DIR_LWS;
366 else
368 if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
369 eState = STATE_2_ATTRIB;
370 else if (ascii_isWhitespace(*p))
371 eState = STATE_2_SIZE_LWS;
372 else
373 eState = STATE_ERROR;
375 break;
377 case STATE_2_DIR_LWS:
378 if (*p >= '0' && *p <= '9')
380 nMonth = *p - '0';
381 nDigits = 1;
382 eState = STATE_2_MONTH;
384 else if (!ascii_isWhitespace(*p))
385 eState = STATE_ERROR;
386 break;
388 case STATE_2_MONTH:
389 if (*p >= '0' && *p <= '9')
390 if (nDigits < 2)
392 nMonth = 10 * nMonth + (*p - '0');
393 ++nDigits;
395 else
396 eState = STATE_ERROR;
397 else if (*p == '-' && nMonth && nMonth <= 12)
399 nDigits = 0;
400 eState = STATE_2_DAY;
402 else
403 eState = STATE_ERROR;
404 break;
406 case STATE_2_DAY:
407 if (*p >= '0' && *p <= '9')
408 if (nDigits < 2)
410 nDay = 10 * nDay + (*p - '0');
411 ++nDigits;
413 else
414 eState = STATE_ERROR;
415 else if (*p == '-' && nDay && nDay <= 31)
417 nDigits = 0;
418 eState = STATE_2_YEAR;
420 else
421 eState = STATE_ERROR;
422 break;
424 case STATE_2_YEAR:
425 if (*p >= '0' && *p <= '9')
427 if (nDigits < 4)
429 nYear = 10 * nYear + (*p - '0');
430 ++nDigits;
432 else
433 eState = STATE_ERROR;
435 else
437 if (ascii_isWhitespace(*p))
438 eState = STATE_2_YEAR_LWS;
439 else
440 eState = STATE_ERROR;
442 break;
444 case STATE_2_YEAR_LWS:
445 if (*p >= '0' && *p <= '9')
447 nHour = *p - '0';
448 nDigits = 1;
449 eState = STATE_2_HOUR;
451 else if (!ascii_isWhitespace(*p))
452 eState = STATE_ERROR;
453 break;
455 case STATE_2_HOUR:
456 if (*p >= '0' && *p <= '9')
457 if (nDigits < 2)
459 nHour = 10 * nHour + (*p - '0');
460 ++nDigits;
462 else
463 eState = STATE_ERROR;
464 else if (*p == ':' && nHour < 24)
466 nDigits = 0;
467 eState = STATE_2_MINUTE;
469 else
470 eState = STATE_ERROR;
471 break;
473 case STATE_2_MINUTE:
474 if (*p >= '0' && *p <= '9')
476 if (nDigits < 2)
478 nMinute = 10 * nMinute + (*p - '0');
479 ++nDigits;
481 else
482 eState = STATE_ERROR;
484 else
486 if (ascii_isWhitespace(*p) && (nMinute < 60))
487 eState = STATE_LWS_NAME;
488 else
489 eState = STATE_ERROR;
491 break;
493 case STATE_LWS_NAME:
494 if (!ascii_isWhitespace(*p))
496 setPath (rEntry.m_aName, p);
497 if (bDirectory)
498 rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR;
499 rEntry.m_nSize = nSize;
501 setYear (rEntry.m_aDate, nYear);
503 rEntry.m_aDate.SetMonth(nMonth);
504 rEntry.m_aDate.SetDay(nDay);
505 rEntry.m_aDate.SetHour(nHour);
506 rEntry.m_aDate.SetMin(nMinute);
508 return true;
510 break;
511 case STATE_ERROR:
512 break;
516 return false;
520 * parseVMS.
521 * Directory entries may span one or two lines:
523 * entry: *lws name *1(*lws <NEWLINE>) 1*lws size 1*lws datetime rest
525 * name: filename "." filetype ";" version
526 * filename: 1*39fchar
527 * filetype: 1*39fchar
528 * version: non0digit *digit
530 * size: "0" / non0digit *digit
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
542 * rest: *1(lws *<ANY>)
544 * lws: <TAB> / <SPACE>
545 * non0digit: "1"-"9"
546 * digit: "0" / non0digit
547 * fchar: "A"-"Z" / "a"-"z" / digit / "-" / "_" / "$"
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).
553 * The READ, WRITE, and ISLINK mode bits are not supported.
555 * The returned size is the <size> part, multiplied by 512, and with the high
556 * order bits truncated to fit into a ULONG.
559 bool FTPDirectoryParser::parseVMS (
560 FTPDirentry &rEntry,
561 const sal_Char *pBuffer)
563 static OUString aFirstLineName;
564 static bool bFirstLineDir = false;
566 for (bool bFirstLine = true;; bFirstLine = false)
568 const sal_Char *p = pBuffer;
569 if (bFirstLine)
571 // Skip <*lws> part:
572 while (*p == '\t' || *p == ' ')
573 ++p;
575 // Parse <filename "."> part:
576 const sal_Char *pFileName = p;
577 while ((*p >= 'A' && *p <= 'Z') ||
578 (*p >= 'a' && *p <= 'z') ||
579 (*p >= '0' && *p <= '9') ||
580 *p == '-' || *p == '_' || *p == '$')
581 ++p;
583 if (*p != '.' || p == pFileName || p - pFileName > 39)
585 if (!aFirstLineName.isEmpty())
586 continue;
587 else
588 return false;
591 // Parse <filetype ";"> part:
592 const sal_Char *pFileType = ++p;
593 while ((*p >= 'A' && *p <= 'Z') ||
594 (*p >= 'a' && *p <= 'z') ||
595 (*p >= '0' && *p <= '9') ||
596 *p == '-' || *p == '_' || *p == '$')
597 ++p;
599 if (*p != ';' || p == pFileName || p - pFileName > 39)
601 if (!aFirstLineName.isEmpty())
602 continue;
603 else
604 return false;
606 ++p;
608 // Set entry's name and mode (ISDIR flag):
609 if ((p - pFileType == 4) &&
610 (pFileType[0] == 'D' || pFileType[0] == 'd') &&
611 (pFileType[1] == 'I' || pFileType[1] == 'i') &&
612 (pFileType[2] == 'R' || pFileType[2] == 'r') )
614 setPath (rEntry.m_aName, pFileName, (pFileType - pFileName));
615 rEntry.m_nMode = INETCOREFTP_FILEMODE_ISDIR;
617 else
619 setPath (rEntry.m_aName, pFileName, (p - pFileName));
620 rEntry.m_nMode = 0;
623 // Skip <version> part:
624 if (*p < '1' || *p > '9')
626 if (!aFirstLineName.isEmpty())
627 continue;
628 else
629 return false;
631 ++p;
632 while (*p >= '0' && *p <= '9')
633 ++p;
635 // Parse <1*lws> or <*lws <NEWLINE>> part:
636 bool bLWS = false;
637 while (*p == '\t' || *p == ' ')
639 bLWS = true;
640 ++p;
642 if (*p)
644 if (!bLWS)
646 if (!aFirstLineName.isEmpty())
647 continue;
648 else
649 return false;
652 else
655 * First line of entry spanning two lines,
656 * wait for second line.
658 aFirstLineName = rEntry.m_aName;
659 bFirstLineDir =
660 ((rEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) != 0);
661 return false;
664 else
667 * Second line of entry spanning two lines,
668 * restore entry's name and mode (ISDIR flag).
670 rEntry.m_aName = aFirstLineName;
671 rEntry.m_nMode = (bFirstLineDir ? INETCOREFTP_FILEMODE_ISDIR : 0);
673 // Skip <1*lws> part:
674 if (*p != '\t' && *p != ' ')
675 return false;
676 ++p;
677 while (*p == '\t' || *p == ' ')
678 ++p;
681 // Parse <size> part and set entry's size:
682 if (*p < '0' || *p > '9')
683 return false;
684 ULONG nSize = *p - '0';
685 if (*p++ != '0')
686 while (*p >= '0' && *p <= '9')
687 nSize = 10 * rEntry.m_nSize + (*p++ - '0');
688 rEntry.m_nSize = 512 * nSize;
690 // Skip <1*lws> part:
691 if (*p != '\t' && *p != ' ')
692 return false;
693 ++p;
694 while (*p == '\t' || *p == ' ')
695 ++p;
697 // Parse <day "-"> part and set entry date's day:
698 sal_uInt16 nDay;
699 if (*p == '0')
701 ++p;
702 if (*p < '1' || *p > '9')
703 return false;
704 nDay = *p++ - '0';
706 else if (*p == '1' || *p == '2')
708 nDay = *p++ - '0';
709 if (*p >= '0' && *p <= '9')
710 nDay = 10 * nDay + (*p++ - '0');
712 else if (*p == '3')
714 ++p;
715 nDay = (*p == '0' || *p == '1') ? 30 + (*p++ - '0') : 3;
717 else if (*p >= '4' && *p <= '9')
718 nDay = *p++ - '0';
719 else
720 return false;
722 rEntry.m_aDate.SetDay(nDay);
723 if (*p++ != '-')
724 return false;
726 // Parse <month "-"> part and set entry date's month:
727 sal_Char const * pMonth = p;
728 sal_Int32 const monthLen = 3;
729 for (int i = 0; i < monthLen; ++i)
731 if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')))
732 return false;
733 ++p;
735 if (rtl_str_compareIgnoreAsciiCase_WithLength(
736 pMonth, monthLen, "JAN", monthLen) == 0)
737 rEntry.m_aDate.SetMonth(1);
738 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
739 pMonth, monthLen, "FEB", monthLen) == 0)
740 rEntry.m_aDate.SetMonth(2);
741 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
742 pMonth, monthLen, "MAR", monthLen) == 0)
743 rEntry.m_aDate.SetMonth(3);
744 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
745 pMonth, monthLen, "APR", monthLen) == 0)
746 rEntry.m_aDate.SetMonth(4);
747 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
748 pMonth, monthLen, "MAY", monthLen) == 0)
749 rEntry.m_aDate.SetMonth(5);
750 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
751 pMonth, monthLen, "JUN", monthLen) == 0)
752 rEntry.m_aDate.SetMonth(6);
753 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
754 pMonth, monthLen, "JUL", monthLen) == 0)
755 rEntry.m_aDate.SetMonth(7);
756 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
757 pMonth, monthLen, "AUG", monthLen) == 0)
758 rEntry.m_aDate.SetMonth(8);
759 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
760 pMonth, monthLen, "SEP", monthLen) == 0)
761 rEntry.m_aDate.SetMonth(9);
762 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
763 pMonth, monthLen, "OCT", monthLen) == 0)
764 rEntry.m_aDate.SetMonth(10);
765 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
766 pMonth, monthLen, "NOV", monthLen) == 0)
767 rEntry.m_aDate.SetMonth(11);
768 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
769 pMonth, monthLen, "DEC", monthLen) == 0)
770 rEntry.m_aDate.SetMonth(12);
771 else
772 return false;
773 if (*p++ != '-')
774 return false;
776 // Parse <year> part and set entry date's year:
777 sal_uInt16 nYear = 0;
778 for (int i = 0; i < 2; ++i)
780 if (*p < '0' || *p > '9')
781 return false;
782 nYear = 10 * nYear + (*p++ - '0');
784 if (*p >= '0' && *p <= '9')
786 nYear = 10 * nYear + (*p++ - '0');
787 if (*p < '0' || *p > '9')
788 return false;
789 nYear = 10 * nYear + (*p++ - '0');
791 setYear (rEntry.m_aDate, nYear);
793 // Skip <1*lws> part:
794 if (*p != '\t' && *p != ' ')
795 return false;
796 ++p;
797 while (*p == '\t' || *p == ' ')
798 ++p;
800 // Parse <hour ":"> part and set entry time's hour:
801 sal_uInt16 nHour;
802 if (*p == '0' || *p == '1')
804 nHour = *p++ - '0';
805 if (*p >= '0' && *p <= '9')
806 nHour = 10 * nHour + (*p++ - '0');
808 else if (*p == '2')
810 ++p;
811 nHour = (*p >= '0' && *p <= '3') ? 20 + (*p++ - '0') : 2;
813 else if (*p >= '3' && *p <= '9')
814 nHour = *p++ - '0';
815 else
816 return false;
818 rEntry.m_aDate.SetHour(nHour);
819 if (*p++ != ':')
820 return false;
823 * Parse <minute> part and set entry time's minutes,
824 * seconds (0), and nanoseconds (0).
826 if (*p < '0' || *p > '5')
827 return false;
829 sal_uInt16 nMinute = *p++ - '0';
830 if (*p < '0' || *p > '9')
831 return false;
833 nMinute = 10 * nMinute + (*p++ - '0');
834 rEntry.m_aDate.SetMin(nMinute);
835 rEntry.m_aDate.SetSec(0);
836 rEntry.m_aDate.SetNanoSec(0);
838 // Skip <rest> part:
839 if (*p && (*p != '\t' && *p != ' '))
840 return false;
842 return true;
847 * parseUNIX
849 bool FTPDirectoryParser::parseUNIX (
850 FTPDirentry &rEntry,
851 const sal_Char *pBuffer)
853 const sal_Char *p1, *p2;
854 p1 = p2 = pBuffer;
856 if (!((*p1 == '-') || (*p1 == 'd') || (*p1 == 'l')))
857 return false;
859 // 1st column: FileMode.
860 if (*p1 == 'd')
861 rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR;
863 if (*p1 == 'l')
864 rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISLINK;
866 // Skip to end of column and set rights by the way
867 while (*p1 && !ascii_isWhitespace(*p1)) {
868 if(*p1 == 'r')
869 rEntry.m_nMode |= INETCOREFTP_FILEMODE_READ;
870 else if(*p1 == 'w')
871 rEntry.m_nMode |= INETCOREFTP_FILEMODE_WRITE;
872 p1++;
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
880 enum Mode
882 FOUND_NONE, FOUND_SIZE, FOUND_MONTH, FOUND_DAY, FOUND_YEAR_TIME
885 const sal_Char *pDayStart = 0;
886 const sal_Char *pDayEnd = 0;
887 Mode eMode;
888 for (eMode = FOUND_NONE; *p1 && eMode != FOUND_YEAR_TIME; p1 = p2 + 1)
890 while (*p1 && ascii_isWhitespace(*p1))
891 ++p1;
892 p2 = p1;
893 while (*p2 && !ascii_isWhitespace(*p2))
894 ++p2;
896 switch (eMode)
898 case FOUND_NONE:
899 if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
900 eMode = FOUND_SIZE;
901 break;
903 case FOUND_SIZE:
904 if (parseUNIX_isMonthField (p1, p2, rEntry.m_aDate))
905 eMode = FOUND_MONTH;
906 else if (!parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
907 eMode = FOUND_NONE;
908 break;
910 case FOUND_MONTH:
911 if (parseUNIX_isDayField (p1, p2, rEntry.m_aDate))
913 pDayStart = p1;
914 pDayEnd = p2;
915 eMode = FOUND_DAY;
917 else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
918 eMode = FOUND_SIZE;
919 else
920 eMode = FOUND_NONE;
921 break;
923 case FOUND_DAY:
924 if (parseUNIX_isYearTimeField (p1, p2, rEntry.m_aDate))
925 eMode = FOUND_YEAR_TIME;
926 else if (
927 parseUNIX_isSizeField (
928 pDayStart, pDayEnd, rEntry.m_nSize) &&
929 parseUNIX_isMonthField (
930 p1, p2, rEntry.m_aDate))
931 eMode = FOUND_MONTH;
932 else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
933 eMode = FOUND_SIZE;
934 else
935 eMode = FOUND_NONE;
936 break;
937 // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
938 case FOUND_YEAR_TIME:
939 break;
943 if (eMode == FOUND_YEAR_TIME)
945 // 9th column: FileName (rest of line).
946 while (*p1 && ascii_isWhitespace(*p1)) p1++;
947 setPath (rEntry.m_aName, p1);
949 // Done.
950 return true;
952 return false;
956 * parseUNIX_isSizeField.
958 bool FTPDirectoryParser::parseUNIX_isSizeField (
959 const sal_Char *pStart,
960 const sal_Char *pEnd,
961 sal_uInt32 &rSize)
963 if (!*pStart || !*pEnd || pStart == pEnd)
964 return false;
966 rSize = 0;
967 if (*pStart >= '0' && *pStart <= '9')
969 for (; pStart < pEnd; ++pStart)
970 if ((*pStart >= '0') && (*pStart <= '9'))
971 rSize = 10 * rSize + (*pStart - '0');
972 else
973 return false;
974 return true;
976 else
979 * For a combination of long group name and large file size,
980 * some FTPDs omit LWS between those two columns.
982 int nNonDigits = 0;
983 int nDigits = 0;
985 for (; pStart < pEnd; ++pStart)
986 if ((*pStart >= '1') && (*pStart <= '9'))
988 ++nDigits;
989 rSize = 10 * rSize + (*pStart - '0');
991 else if ((*pStart == '0') && nDigits)
993 ++nDigits;
994 rSize *= 10;
996 else if ((*pStart > ' ') && (sal::static_int_cast<sal_uInt8>(*pStart) <= '\x7F'))
998 nNonDigits += nDigits + 1;
999 nDigits = 0;
1000 rSize = 0;
1002 else
1003 return false;
1004 return ((nNonDigits >= 9) && (nDigits >= 7));
1009 * parseUNIX_isMonthField.
1011 bool FTPDirectoryParser::parseUNIX_isMonthField (
1012 const sal_Char *pStart,
1013 const sal_Char *pEnd,
1014 DateTime &rDateTime)
1016 if (!*pStart || !*pEnd || pStart + 3 != pEnd)
1017 return false;
1019 if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1020 (pStart[1] == 'a' || pStart[1] == 'A') &&
1021 (pStart[2] == 'n' || pStart[2] == 'N') )
1023 rDateTime.SetMonth(1);
1024 return true;
1026 if ((pStart[0] == 'f' || pStart[0] == 'F') &&
1027 (pStart[1] == 'e' || pStart[1] == 'E') &&
1028 (pStart[2] == 'b' || pStart[2] == 'B') )
1030 rDateTime.SetMonth(2);
1031 return true;
1033 if ((pStart[0] == 'm' || pStart[0] == 'M') &&
1034 (pStart[1] == 'a' || pStart[1] == 'A') &&
1035 (pStart[2] == 'r' || pStart[2] == 'R') )
1037 rDateTime.SetMonth(3);
1038 return true;
1040 if ((pStart[0] == 'a' || pStart[0] == 'A') &&
1041 (pStart[1] == 'p' || pStart[1] == 'P') &&
1042 (pStart[2] == 'r' || pStart[2] == 'R') )
1044 rDateTime.SetMonth(4);
1045 return true;
1047 if ((pStart[0] == 'm' || pStart[0] == 'M') &&
1048 (pStart[1] == 'a' || pStart[1] == 'A') &&
1049 (pStart[2] == 'y' || pStart[2] == 'Y') )
1051 rDateTime.SetMonth(5);
1052 return true;
1054 if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1055 (pStart[1] == 'u' || pStart[1] == 'U') &&
1056 (pStart[2] == 'n' || pStart[2] == 'N') )
1058 rDateTime.SetMonth(6);
1059 return true;
1061 if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1062 (pStart[1] == 'u' || pStart[1] == 'U') &&
1063 (pStart[2] == 'l' || pStart[2] == 'L') )
1065 rDateTime.SetMonth(7);
1066 return true;
1068 if ((pStart[0] == 'a' || pStart[0] == 'A') &&
1069 (pStart[1] == 'u' || pStart[1] == 'U') &&
1070 (pStart[2] == 'g' || pStart[2] == 'G') )
1072 rDateTime.SetMonth(8);
1073 return true;
1075 if ((pStart[0] == 's' || pStart[0] == 'S') &&
1076 (pStart[1] == 'e' || pStart[1] == 'E') &&
1077 (pStart[2] == 'p' || pStart[2] == 'P') )
1079 rDateTime.SetMonth(9);
1080 return true;
1082 if ((pStart[0] == 'o' || pStart[0] == 'O') &&
1083 (pStart[1] == 'c' || pStart[1] == 'C') &&
1084 (pStart[2] == 't' || pStart[2] == 'T') )
1086 rDateTime.SetMonth(10);
1087 return true;
1089 if ((pStart[0] == 'n' || pStart[0] == 'N') &&
1090 (pStart[1] == 'o' || pStart[1] == 'O') &&
1091 (pStart[2] == 'v' || pStart[2] == 'V') )
1093 rDateTime.SetMonth(11);
1094 return true;
1096 if ((pStart[0] == 'd' || pStart[0] == 'D') &&
1097 (pStart[1] == 'e' || pStart[1] == 'E') &&
1098 (pStart[2] == 'c' || pStart[2] == 'C') )
1100 rDateTime.SetMonth(12);
1101 return true;
1103 return false;
1107 * parseUNIX_isDayField.
1109 bool FTPDirectoryParser::parseUNIX_isDayField (
1110 const sal_Char *pStart,
1111 const sal_Char *pEnd,
1112 DateTime &rDateTime)
1114 if (!*pStart || !*pEnd || pStart == pEnd)
1115 return false;
1116 if (*pStart < '0' || *pStart > '9')
1117 return false;
1119 sal_uInt16 nDay = *pStart - '0';
1120 if (pStart + 1 < pEnd)
1122 if (pStart + 2 != pEnd || pStart[1] < '0' || pStart[1] > '9')
1123 return false;
1124 nDay = 10 * nDay + (pStart[1] - '0');
1126 if (!nDay || nDay > 31)
1127 return false;
1129 rDateTime.SetDay(nDay);
1130 return true;
1134 * parseUNIX_isYearTimeField.
1136 bool FTPDirectoryParser::parseUNIX_isYearTimeField (
1137 const sal_Char *pStart,
1138 const sal_Char *pEnd,
1139 DateTime &rDateTime)
1141 if (!*pStart || !*pEnd || pStart == pEnd ||
1142 *pStart < '0' || *pStart > '9')
1143 return false;
1145 sal_uInt16 nNumber = *pStart - '0';
1146 ++pStart;
1148 if (pStart == pEnd)
1149 return false;
1150 if (*pStart == ':')
1151 return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime);
1152 if (*pStart < '0' || *pStart > '9')
1153 return false;
1155 nNumber = 10 * nNumber + (*pStart - '0');
1156 ++pStart;
1158 if (pStart == pEnd)
1159 return false;
1160 if (*pStart == ':')
1161 return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime);
1162 if (*pStart < '0' || *pStart > '9')
1163 return false;
1165 nNumber = 10 * nNumber + (*pStart - '0');
1166 ++pStart;
1168 if (pStart == pEnd || *pStart < '0' || *pStart > '9')
1169 return false;
1171 nNumber = 10 * nNumber + (*pStart - '0');
1172 if (pStart + 1 != pEnd || nNumber < 1970)
1173 return false;
1175 rDateTime.SetYear(nNumber);
1176 rDateTime.SetTime(0);
1177 return true;
1181 * parseUNIX_isTime.
1183 bool FTPDirectoryParser::parseUNIX_isTime (
1184 const sal_Char *pStart,
1185 const sal_Char *pEnd,
1186 sal_uInt16 nHour,
1187 DateTime &rDateTime)
1189 if ((nHour > 23 ) || (pStart + 3 != pEnd) ||
1190 (pStart[1] < '0') || (pStart[1] > '5') ||
1191 (pStart[2] < '0') || (pStart[2] > '9') )
1192 return false;
1194 sal_uInt16 nMin = 10 * (pStart[1] - '0') + (pStart[2] - '0');
1196 rDateTime.SetHour (nHour);
1197 rDateTime.SetMin (nMin);
1198 rDateTime.SetSec (0);
1199 rDateTime.SetNanoSec (0);
1201 // Date aCurDate;
1202 // if (rDateTime.GetMonth() > aCurDate.GetMonth())
1203 // rDateTime.SetYear(aCurDate.GetYear() - 1);
1204 // else
1205 // rDateTime.SetYear(aCurDate.GetYear());
1206 // return sal_True;
1208 TimeValue aTimeVal;
1209 osl_getSystemTime(&aTimeVal);
1210 oslDateTime aCurrDateTime;
1211 osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime);
1213 if (rDateTime.GetMonth() > aCurrDateTime.Month)
1214 rDateTime.SetYear(aCurrDateTime.Year - 1);
1215 else
1216 rDateTime.SetYear(aCurrDateTime.Year);
1217 return true;
1221 * setYear.
1223 * Two-digit years are taken as within 50 years back and 49 years forward
1224 * (both ends inclusive) from the current year. The returned date is not
1225 * checked for validity of the given day in the given month and year.
1228 bool FTPDirectoryParser::setYear (
1229 DateTime &rDateTime, sal_uInt16 nYear)
1231 if (nYear < 100)
1233 TimeValue aTimeVal;
1234 osl_getSystemTime(&aTimeVal);
1235 oslDateTime aCurrDateTime;
1236 osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime);
1237 sal_uInt16 nCurrentYear = aCurrDateTime.Year;
1238 // sal_uInt16 nCurrentYear = Date().GetYear();
1239 sal_uInt16 nCurrentCentury = nCurrentYear / 100;
1240 nCurrentYear %= 100;
1241 if (nCurrentYear < 50)
1242 if (nYear <= nCurrentYear)
1243 nYear += nCurrentCentury * 100;
1244 else if (nYear < nCurrentYear + 50)
1245 nYear += nCurrentCentury * 100;
1246 else
1247 nYear += (nCurrentCentury - 1) * 100;
1248 else
1249 if (nYear >= nCurrentYear)
1250 nYear += nCurrentCentury * 100;
1251 else if (nYear >= nCurrentYear - 50)
1252 nYear += nCurrentCentury * 100;
1253 else
1254 nYear += (nCurrentCentury + 1) * 100;
1257 rDateTime.SetYear(nYear);
1258 return true;
1262 * setPath.
1264 bool FTPDirectoryParser::setPath (
1265 OUString &rPath, const sal_Char *value, sal_Int32 length)
1267 if (value)
1269 if (length < 0)
1270 length = rtl_str_getLength (value);
1271 rPath = OUString (value, length, RTL_TEXTENCODING_UTF8);
1273 return (!!value);
1276 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */