Update ooo320-m1
[ooovba.git] / ucb / source / ucp / ftp / ftpdirp.cxx
blobf25474ef53ad5a213cef61779a363c1b1f4ba56b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ftpdirp.cxx,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_ucb.hxx"
34 /**************************************************************************
35 TODO
36 **************************************************************************
38 *************************************************************************/
39 #include "ftpdirp.hxx"
40 #include <osl/time.h>
43 using namespace rtl;
44 using namespace ftp;
47 typedef sal_uInt32 ULONG;
50 inline sal_Bool ascii_isLetter( sal_Unicode ch )
52 return (( (ch >= 0x0041) && (ch <= 0x005A)) ||
53 (( ch >= 0x0061) && (ch <= 0x007A)));
56 inline sal_Bool ascii_isWhitespace( sal_Unicode ch )
58 return ((ch <= 0x20) && ch);
63 /*========================================================================
65 * FTPDirectoryParser implementation.
67 *======================================================================*/
69 * parseDOS.
70 * Accepts one of two styles:
72 * 1 *WSP 1*2DIGIT ("." / "-") 1*2DIGIT ("." / "-") 1*4DIGIT 1*WSP
73 * 1*2DIGIT ":" 1*2DIGIT [*WSP ("A" / "P") "M"] 1*WSP
74 * ((DIGIT *(DIGIT / "." / ",")) / "<DIR>") 1*WSP 1*OCTET
76 * interpreted as: mm.dd.yy hh:mm (size / <DIR>) name
78 * 2 *WSP 1*DIGIT 1*WSP *(1*CHAR *WSP) *1("DIR" 1*WSP) 1*2DIGIT "-" 1*2DIGIT
79 * "-" 1*4DIGIT 1*WSP 1*2DIGIT ":" 1*2DIGIT 1*WSP 1*OCTET
81 * interpreted as: size attribs DIR mm-dd-yy hh:mm name
84 sal_Bool FTPDirectoryParser::parseDOS (
85 FTPDirentry &rEntry,
86 const sal_Char *pBuffer)
88 sal_Bool bDirectory = false;
89 sal_uInt32 nSize = 0;
90 sal_uInt16 nYear = 0;
91 sal_uInt16 nMonth = 0;
92 sal_uInt16 nDay = 0;
93 sal_uInt16 nHour = 0;
94 sal_uInt16 nMinute = 0;
96 enum StateType
98 STATE_INIT_LWS,
99 STATE_MONTH_OR_SIZE,
100 STATE_1_DAY, STATE_1_YEAR, STATE_1_YEAR_LWS, STATE_1_HOUR,
101 STATE_1_MINUTE, STATE_1_MINUTE_LWS, STATE_1_AP,
102 STATE_1_APM, STATE_1_LESS, STATE_1_D, STATE_1_DI,
103 STATE_1_DIR, STATE_1_SIZE,
104 STATE_2_SIZE, STATE_2_SIZE_LWS, STATE_2_ATTRIB,
105 STATE_2_D, STATE_2_DI, STATE_2_DIR_LWS,
106 STATE_2_MONTH, STATE_2_DAY, STATE_2_YEAR, STATE_2_YEAR_LWS,
107 STATE_2_HOUR, STATE_2_MINUTE,
108 STATE_LWS_NAME,
109 STATE_ERROR
112 int nDigits = 0;
113 enum StateType eState = STATE_INIT_LWS;
114 for (const sal_Char *p = pBuffer;
115 eState != STATE_ERROR && *p;
116 ++p)
118 switch (eState)
120 case STATE_INIT_LWS:
121 if (*p >= '0' && *p <= '9')
123 nMonth = *p - '0';
124 nDigits = 1;
125 eState = STATE_MONTH_OR_SIZE;
127 else if (!ascii_isWhitespace(*p))
128 eState = STATE_ERROR;
129 break;
131 case STATE_MONTH_OR_SIZE:
132 if (*p >= '0' && *p <= '9')
134 nMonth = 10 * nMonth + (*p - '0');
135 if (nDigits < 2)
136 ++nDigits;
137 else
139 nSize = nMonth;
140 nMonth = 0;
141 eState = STATE_2_SIZE;
144 else if (ascii_isWhitespace(*p))
146 nSize = nMonth;
147 nMonth = 0;
148 eState = STATE_2_SIZE_LWS;
150 else if ((*p == '.' || *p == '-') && nMonth && nMonth <= 12)
152 nDigits = 0;
153 eState = STATE_1_DAY;
155 else
156 eState = STATE_ERROR;
157 break;
159 case STATE_1_DAY:
160 if (*p >= '0' && *p <= '9')
161 if (nDigits < 2)
163 nDay = 10 * nDay + (*p - '0');
164 ++nDigits;
166 else
167 eState = STATE_ERROR;
168 else if ((*p == '.' || *p == '-') && nDay && nDay <= 31)
170 nDigits = 0;
171 eState = STATE_1_YEAR;
173 else
174 eState = STATE_ERROR;
175 break;
177 case STATE_1_YEAR:
178 if (*p >= '0' && *p <= '9')
180 if (nDigits < 4)
182 nYear = 10 * nYear + (*p - '0');
183 ++nDigits;
185 else
186 eState = STATE_ERROR;
188 else
190 if (ascii_isWhitespace(*p))
191 eState = STATE_1_YEAR_LWS;
192 else
193 eState = STATE_ERROR;
195 break;
197 case STATE_1_YEAR_LWS:
198 if (*p >= '0' && *p <= '9')
200 nHour = *p - '0';
201 nDigits = 1;
202 eState = STATE_1_HOUR;
204 else if (!ascii_isWhitespace(*p))
205 eState = STATE_ERROR;
206 break;
208 case STATE_1_HOUR:
209 if (*p >= '0' && *p <= '9')
210 if (nDigits < 2)
212 nHour = 10 * nHour + (*p - '0');
213 ++nDigits;
215 else
216 eState = STATE_ERROR;
217 else if (*p == ':' && nHour < 24)
219 nDigits = 0;
220 eState = STATE_1_MINUTE;
222 else
223 eState = STATE_ERROR;
224 break;
226 case STATE_1_MINUTE:
227 if (*p >= '0' && *p <= '9')
228 if (nDigits < 2)
230 nMinute = 10 * nMinute + (*p - '0');
231 ++nDigits;
233 else
234 eState = STATE_ERROR;
235 else if ((*p == 'a' || *p == 'A') && nMinute < 60)
236 if (nHour >= 1 && nHour <= 11)
237 eState = STATE_1_AP;
238 else if (nHour == 12)
240 nHour = 0;
241 eState = STATE_1_AP;
243 else
244 eState = STATE_ERROR;
245 else if ((*p == 'p' || *p == 'P') && nMinute < 60)
246 if (nHour >= 1 && nHour <= 11)
248 nHour += 12;
249 eState = STATE_1_AP;
251 else if (nHour == 12)
252 eState = STATE_1_AP;
253 else
254 eState = STATE_ERROR;
255 else if (ascii_isWhitespace(*p) && (nMinute < 60))
256 eState = STATE_1_MINUTE_LWS;
257 else
258 eState = STATE_ERROR;
259 break;
261 case STATE_1_MINUTE_LWS:
262 if (*p == 'a' || *p == 'A')
263 if (nHour >= 1 && nHour <= 11)
264 eState = STATE_1_AP;
265 else if (nHour == 12)
267 nHour = 0;
268 eState = STATE_1_AP;
270 else
271 eState = STATE_ERROR;
272 else if (*p == 'p' || *p == 'P')
273 if (nHour >= 1 && nHour <= 11)
275 nHour += 12;
276 eState = STATE_1_AP;
278 else if (nHour == 12)
279 eState = STATE_1_AP;
280 else
281 eState = STATE_ERROR;
282 else if (*p == '<')
283 eState = STATE_1_LESS;
284 else if (*p >= '0' && *p <= '9')
286 nSize = *p - '0';
287 eState = STATE_1_SIZE;
289 else if (!ascii_isWhitespace(*p))
290 eState = STATE_ERROR;
291 break;
293 case STATE_1_AP:
294 eState = *p == 'm' || *p == 'M' ? STATE_1_APM : STATE_ERROR;
295 break;
297 case STATE_1_APM:
298 if (*p == '<')
299 eState = STATE_1_LESS;
300 else if (*p >= '0' && *p <= '9')
302 nSize = *p - '0';
303 eState = STATE_1_SIZE;
305 else if (!ascii_isWhitespace(*p))
306 eState = STATE_ERROR;
307 break;
309 case STATE_1_LESS:
310 eState = *p == 'd' || *p == 'D' ? STATE_1_D : STATE_ERROR;
311 break;
313 case STATE_1_D:
314 eState = *p == 'i' || *p == 'I' ? STATE_1_DI : STATE_ERROR;
315 break;
317 case STATE_1_DI:
318 eState = *p == 'r' || *p == 'R' ? STATE_1_DIR : STATE_ERROR;
319 break;
321 case STATE_1_DIR:
322 if (*p == '>')
324 bDirectory = true;
325 eState = STATE_LWS_NAME;
327 else
328 eState = STATE_ERROR;
329 break;
331 case STATE_1_SIZE:
332 if (*p >= '0' && *p <= '9')
333 nSize = 10 * nSize + (*p - '0');
334 else if (ascii_isWhitespace(*p))
335 eState = STATE_LWS_NAME;
336 else
337 eState = STATE_ERROR;
338 break;
340 case STATE_2_SIZE:
341 if (*p >= '0' && *p <= '9')
342 nSize = 10 * nSize + (*p - '0');
343 else if (ascii_isWhitespace(*p))
344 eState = STATE_2_SIZE_LWS;
345 else
346 eState = STATE_ERROR;
347 break;
349 case STATE_2_SIZE_LWS:
350 if (*p == 'd' || *p == 'D')
351 eState = STATE_2_D;
352 else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
353 eState = STATE_2_ATTRIB;
354 else if (*p >= '0' && *p <= '9')
356 nMonth = *p - '0';
357 nDigits = 1;
358 eState = STATE_2_MONTH;
360 else if (!ascii_isWhitespace(*p))
361 eState = STATE_ERROR;
362 break;
364 case STATE_2_ATTRIB:
365 if (ascii_isWhitespace(*p))
366 eState = STATE_2_SIZE_LWS;
367 else if ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z'))
368 eState = STATE_ERROR;
369 break;
371 case STATE_2_D:
372 if (*p == 'i' || *p == 'I')
373 eState = STATE_2_DI;
374 else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
375 eState = STATE_2_ATTRIB;
376 else if (ascii_isWhitespace(*p))
377 eState = STATE_2_SIZE_LWS;
378 else
379 eState = STATE_ERROR;
380 break;
382 case STATE_2_DI:
383 if (*p == 'r' || *p == 'R')
385 bDirectory = true;
386 eState = STATE_2_DIR_LWS;
388 else
390 if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z'))
391 eState = STATE_2_ATTRIB;
392 else if (ascii_isWhitespace(*p))
393 eState = STATE_2_SIZE_LWS;
394 else
395 eState = STATE_ERROR;
397 break;
399 case STATE_2_DIR_LWS:
400 if (*p >= '0' && *p <= '9')
402 nMonth = *p - '0';
403 nDigits = 1;
404 eState = STATE_2_MONTH;
406 else if (!ascii_isWhitespace(*p))
407 eState = STATE_ERROR;
408 break;
410 case STATE_2_MONTH:
411 if (*p >= '0' && *p <= '9')
412 if (nDigits < 2)
414 nMonth = 10 * nMonth + (*p - '0');
415 ++nDigits;
417 else
418 eState = STATE_ERROR;
419 else if (*p == '-' && nMonth && nMonth <= 12)
421 nDigits = 0;
422 eState = STATE_2_DAY;
424 else
425 eState = STATE_ERROR;
426 break;
428 case STATE_2_DAY:
429 if (*p >= '0' && *p <= '9')
430 if (nDigits < 2)
432 nDay = 10 * nDay + (*p - '0');
433 ++nDigits;
435 else
436 eState = STATE_ERROR;
437 else if (*p == '-' && nDay && nDay <= 31)
439 nDigits = 0;
440 eState = STATE_2_YEAR;
442 else
443 eState = STATE_ERROR;
444 break;
446 case STATE_2_YEAR:
447 if (*p >= '0' && *p <= '9')
449 if (nDigits < 4)
451 nYear = 10 * nYear + (*p - '0');
452 ++nDigits;
454 else
455 eState = STATE_ERROR;
457 else
459 if (ascii_isWhitespace(*p))
460 eState = STATE_2_YEAR_LWS;
461 else
462 eState = STATE_ERROR;
464 break;
466 case STATE_2_YEAR_LWS:
467 if (*p >= '0' && *p <= '9')
469 nHour = *p - '0';
470 nDigits = 1;
471 eState = STATE_2_HOUR;
473 else if (!ascii_isWhitespace(*p))
474 eState = STATE_ERROR;
475 break;
477 case STATE_2_HOUR:
478 if (*p >= '0' && *p <= '9')
479 if (nDigits < 2)
481 nHour = 10 * nHour + (*p - '0');
482 ++nDigits;
484 else
485 eState = STATE_ERROR;
486 else if (*p == ':' && nHour < 24)
488 nDigits = 0;
489 eState = STATE_2_MINUTE;
491 else
492 eState = STATE_ERROR;
493 break;
495 case STATE_2_MINUTE:
496 if (*p >= '0' && *p <= '9')
498 if (nDigits < 2)
500 nMinute = 10 * nMinute + (*p - '0');
501 ++nDigits;
503 else
504 eState = STATE_ERROR;
506 else
508 if (ascii_isWhitespace(*p) && (nMinute < 60))
509 eState = STATE_LWS_NAME;
510 else
511 eState = STATE_ERROR;
513 break;
515 case STATE_LWS_NAME:
516 if (!ascii_isWhitespace(*p))
518 setPath (rEntry.m_aName, p);
519 if (bDirectory)
520 rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR;
521 rEntry.m_nSize = nSize;
523 setYear (rEntry.m_aDate, nYear);
525 rEntry.m_aDate.SetMonth(nMonth);
526 rEntry.m_aDate.SetDay(nDay);
527 rEntry.m_aDate.SetHour(nHour);
528 rEntry.m_aDate.SetMin(nMinute);
530 return sal_True;
532 break;
533 case STATE_ERROR:
534 break;
538 return sal_False;
542 * parseVMS.
543 * Directory entries may span one or two lines:
545 * entry: *lws name *1(*lws <NEWLINE>) 1*lws size 1*lws datetime rest
547 * name: filename "." filetype ";" version
548 * filename: 1*39fchar
549 * filetype: 1*39fchar
550 * version: non0digit *digit
552 * size: "0" / non0digit *digit
554 * datetime: date 1*lwsp time
555 * date: day "-" month "-" year
556 * day: (*1"0" non0digit) / ("1"-"2" digit) / ("3" "0"-"1")
557 * month: "JAN" / "FEB" / "MAR" / "APR" / "MAY" / "JUN" / "JUL" / "AUG"
558 * / "SEP" / "OCT" / "NOV" / "DEC" ; all case insensitive
559 * year: 2digit / 4digit
560 * time: hour ":" minute
561 * hour: ((*1"0" / "1") digit) / ("2" "0"-"3")
562 * minute: "0"-"5" digit
564 * rest: *1(lws *<ANY>)
566 * lws: <TAB> / <SPACE>
567 * non0digit: "1"-"9"
568 * digit: "0" / non0digit
569 * fchar: "A"-"Z" / "a"-"z" / digit / "-" / "_" / "$"
571 * For directories, the returned name is the <filename> part; for non-
572 * directory files, the returned name is the <filename "." filetype> part.
573 * An entry is a directory iff its filetype is "DIR" (ignoring case).
575 * The READ, WRITE, and ISLINK mode bits are not supported.
577 * The returned size is the <size> part, multiplied by 512, and with the high
578 * order bits truncated to fit into a ULONG.
581 sal_Bool FTPDirectoryParser::parseVMS (
582 FTPDirentry &rEntry,
583 const sal_Char *pBuffer)
585 static OUString aFirstLineName;
586 static sal_Bool bFirstLineDir = sal_False;
588 for (sal_Bool bFirstLine = sal_True;; bFirstLine = sal_False)
590 const sal_Char *p = pBuffer;
591 if (bFirstLine)
593 // Skip <*lws> part:
594 while (*p == '\t' || *p == ' ')
595 ++p;
597 // Parse <filename "."> part:
598 const sal_Char *pFileName = p;
599 while ((*p >= 'A' && *p <= 'Z') ||
600 (*p >= 'a' && *p <= 'z') ||
601 (*p >= '0' && *p <= '9') ||
602 *p == '-' || *p == '_' || *p == '$')
603 ++p;
605 if (*p != '.' || p == pFileName || p - pFileName > 39)
607 if (aFirstLineName.getLength())
608 continue;
609 else
610 return sal_False;
613 // Parse <filetype ";"> part:
614 const sal_Char *pFileType = ++p;
615 while ((*p >= 'A' && *p <= 'Z') ||
616 (*p >= 'a' && *p <= 'z') ||
617 (*p >= '0' && *p <= '9') ||
618 *p == '-' || *p == '_' || *p == '$')
619 ++p;
621 if (*p != ';' || p == pFileName || p - pFileName > 39)
623 if (aFirstLineName.getLength())
624 continue;
625 else
626 return sal_False;
628 ++p;
630 // Set entry's name and mode (ISDIR flag):
631 if ((p - pFileType == 4) &&
632 (pFileType[0] == 'D' || pFileType[0] == 'd') &&
633 (pFileType[1] == 'I' || pFileType[1] == 'i') &&
634 (pFileType[2] == 'R' || pFileType[2] == 'r') )
636 setPath (rEntry.m_aName, pFileName, (pFileType - pFileName));
637 rEntry.m_nMode = INETCOREFTP_FILEMODE_ISDIR;
639 else
641 setPath (rEntry.m_aName, pFileName, (p - pFileName));
642 rEntry.m_nMode = 0;
645 // Skip <version> part:
646 if (*p < '1' || *p > '9')
648 if (aFirstLineName.getLength())
649 continue;
650 else
651 return sal_False;
653 ++p;
654 while (*p >= '0' && *p <= '9')
655 ++p;
657 // Parse <1*lws> or <*lws <NEWLINE>> part:
658 sal_Bool bLWS = false;
659 while (*p == '\t' || *p == ' ')
661 bLWS = true;
662 ++p;
664 if (*p)
666 if (!bLWS)
668 if (aFirstLineName.getLength())
669 continue;
670 else
671 return sal_False;
674 else
677 * First line of entry spanning two lines,
678 * wait for second line.
680 aFirstLineName = rEntry.m_aName;
681 bFirstLineDir =
682 ((rEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) != 0);
683 return sal_False;
686 else
689 * Second line of entry spanning two lines,
690 * restore entry's name and mode (ISDIR flag).
692 rEntry.m_aName = aFirstLineName;
693 rEntry.m_nMode = (bFirstLineDir ? INETCOREFTP_FILEMODE_ISDIR : 0);
695 // Skip <1*lws> part:
696 if (*p != '\t' && *p != ' ')
697 return sal_False;
698 ++p;
699 while (*p == '\t' || *p == ' ')
700 ++p;
703 // Parse <size> part and set entry's size:
704 if (*p < '0' || *p > '9')
705 return sal_False;
706 ULONG nSize = *p - '0';
707 if (*p++ != '0')
708 while (*p >= '0' && *p <= '9')
709 nSize = 10 * rEntry.m_nSize + (*p++ - '0');
710 rEntry.m_nSize = 512 * nSize;
712 // Skip <1*lws> part:
713 if (*p != '\t' && *p != ' ')
714 return sal_False;
715 ++p;
716 while (*p == '\t' || *p == ' ')
717 ++p;
719 // Parse <day "-"> part and set entry date's day:
720 sal_uInt16 nDay;
721 if (*p == '0')
723 ++p;
724 if (*p < '1' || *p > '9')
725 return sal_False;
726 nDay = *p++ - '0';
728 else if (*p == '1' || *p == '2')
730 nDay = *p++ - '0';
731 if (*p >= '0' && *p <= '9')
732 nDay = 10 * nDay + (*p++ - '0');
734 else if (*p == '3')
736 ++p;
737 nDay = (*p == '0' || *p == '1') ? 30 + (*p++ - '0') : 3;
739 else if (*p >= '4' && *p <= '9')
740 nDay = *p++ - '0';
741 else
742 return sal_False;
744 rEntry.m_aDate.SetDay(nDay);
745 if (*p++ != '-')
746 return sal_False;
748 // Parse <month "-"> part and set entry date's month:
749 sal_Char const * pMonth = p;
750 sal_Int32 const monthLen = 3;
751 for (int i = 0; i < monthLen; ++i)
753 if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')))
754 return sal_False;
755 ++p;
757 if (rtl_str_compareIgnoreAsciiCase_WithLength(
758 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("JAN")) == 0)
759 rEntry.m_aDate.SetMonth(1);
760 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
761 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("FEB")) == 0)
762 rEntry.m_aDate.SetMonth(2);
763 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
764 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("MAR")) == 0)
765 rEntry.m_aDate.SetMonth(3);
766 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
767 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("APR")) == 0)
768 rEntry.m_aDate.SetMonth(4);
769 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
770 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("MAY")) == 0)
771 rEntry.m_aDate.SetMonth(5);
772 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
773 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("JUN")) == 0)
774 rEntry.m_aDate.SetMonth(6);
775 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
776 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("JUL")) == 0)
777 rEntry.m_aDate.SetMonth(7);
778 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
779 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("AUG")) == 0)
780 rEntry.m_aDate.SetMonth(8);
781 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
782 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("SEP")) == 0)
783 rEntry.m_aDate.SetMonth(9);
784 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
785 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("OCT")) == 0)
786 rEntry.m_aDate.SetMonth(10);
787 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
788 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("NOV")) == 0)
789 rEntry.m_aDate.SetMonth(11);
790 else if (rtl_str_compareIgnoreAsciiCase_WithLength(
791 pMonth, monthLen, RTL_CONSTASCII_STRINGPARAM("DEC")) == 0)
792 rEntry.m_aDate.SetMonth(12);
793 else
794 return sal_False;
795 if (*p++ != '-')
796 return sal_False;
798 // Parse <year> part and set entry date's year:
799 sal_uInt16 nYear = 0;
800 {for (int i = 0; i < 2; ++i)
802 if (*p < '0' || *p > '9')
803 return sal_False;
804 nYear = 10 * nYear + (*p++ - '0');
806 if (*p >= '0' && *p <= '9')
808 nYear = 10 * nYear + (*p++ - '0');
809 if (*p < '0' || *p > '9')
810 return sal_False;
811 nYear = 10 * nYear + (*p++ - '0');
813 setYear (rEntry.m_aDate, nYear);
815 // Skip <1*lws> part:
816 if (*p != '\t' && *p != ' ')
817 return sal_False;
818 ++p;
819 while (*p == '\t' || *p == ' ')
820 ++p;
822 // Parse <hour ":"> part and set entry time's hour:
823 sal_uInt16 nHour;
824 if (*p == '0' || *p == '1')
826 nHour = *p++ - '0';
827 if (*p >= '0' && *p <= '9')
828 nHour = 10 * nHour + (*p++ - '0');
830 else if (*p == '2')
832 ++p;
833 nHour = (*p >= '0' && *p <= '3') ? 20 + (*p++ - '0') : 2;
835 else if (*p >= '3' && *p <= '9')
836 nHour = *p++ - '0';
837 else
838 return sal_False;
840 rEntry.m_aDate.SetHour(nHour);
841 if (*p++ != ':')
842 return sal_False;
845 * Parse <minute> part and set entry time's minutes,
846 * seconds (0), and 1/100 seconds (0).
848 if (*p < '0' || *p > '5')
849 return sal_False;
851 sal_uInt16 nMinute = *p++ - '0';
852 if (*p < '0' || *p > '9')
853 return sal_False;
855 nMinute = 10 * nMinute + (*p++ - '0');
856 rEntry.m_aDate.SetMin(nMinute);
857 rEntry.m_aDate.SetSec(0);
858 rEntry.m_aDate.Set100Sec(0);
860 // Skip <rest> part:
861 if (*p && (*p != '\t' && *p != ' '))
862 return sal_False;
864 return sal_True;
869 * parseUNIX
871 sal_Bool FTPDirectoryParser::parseUNIX (
872 FTPDirentry &rEntry,
873 const sal_Char *pBuffer)
875 const sal_Char *p1, *p2;
876 p1 = p2 = pBuffer;
878 if (!((*p1 == '-') || (*p1 == 'd') || (*p1 == 'l')))
879 return sal_False;
881 // 1st column: FileMode.
882 if (*p1 == 'd')
883 rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR;
885 if (*p1 == 'l')
886 rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISLINK;
888 // Skip to end of column and set rights by the way
889 while (*p1 && !ascii_isWhitespace(*p1)) {
890 if(*p1 == 'r')
891 rEntry.m_nMode |= INETCOREFTP_FILEMODE_READ;
892 else if(*p1 == 'w')
893 rEntry.m_nMode |= INETCOREFTP_FILEMODE_WRITE;
894 p1++;
898 * Scan for the sequence of size and date fields:
899 * *LWS 1*DIGIT 1*LWS 3CHAR 1*LWS 1*2DIGIT 1*LWS
900 * (4DIGIT / (1*2DIGIT ":" 2DIGIT)) 1*LWS
902 enum Mode
904 FOUND_NONE, FOUND_SIZE, FOUND_MONTH, FOUND_DAY, FOUND_YEAR_TIME
907 const sal_Char *pDayStart = 0;
908 const sal_Char *pDayEnd = 0;
909 Mode eMode;
910 for (eMode = FOUND_NONE; *p1 && eMode != FOUND_YEAR_TIME; p1 = p2 + 1)
912 while (*p1 && ascii_isWhitespace(*p1))
913 ++p1;
914 p2 = p1;
915 while (*p2 && !ascii_isWhitespace(*p2))
916 ++p2;
918 switch (eMode)
920 case FOUND_NONE:
921 if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
922 eMode = FOUND_SIZE;
923 break;
925 case FOUND_SIZE:
926 if (parseUNIX_isMonthField (p1, p2, rEntry.m_aDate))
927 eMode = FOUND_MONTH;
928 else if (!parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
929 eMode = FOUND_NONE;
930 break;
932 case FOUND_MONTH:
933 if (parseUNIX_isDayField (p1, p2, rEntry.m_aDate))
935 pDayStart = p1;
936 pDayEnd = p2;
937 eMode = FOUND_DAY;
939 else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
940 eMode = FOUND_SIZE;
941 else
942 eMode = FOUND_NONE;
943 break;
945 case FOUND_DAY:
946 if (parseUNIX_isYearTimeField (p1, p2, rEntry.m_aDate))
947 eMode = FOUND_YEAR_TIME;
948 else if (
949 parseUNIX_isSizeField (
950 pDayStart, pDayEnd, rEntry.m_nSize) &&
951 parseUNIX_isMonthField (
952 p1, p2, rEntry.m_aDate))
953 eMode = FOUND_MONTH;
954 else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize))
955 eMode = FOUND_SIZE;
956 else
957 eMode = FOUND_NONE;
958 break;
959 case FOUND_YEAR_TIME:
960 break;
964 if (eMode == FOUND_YEAR_TIME)
966 // 9th column: FileName (rest of line).
967 while (*p1 && ascii_isWhitespace(*p1)) p1++;
968 setPath (rEntry.m_aName, p1);
970 // Done.
971 return sal_True;
973 return sal_False;
977 * parseUNKNOWN.
979 sal_Bool FTPDirectoryParser::parseUNKNOWN (
980 FTPDirentry &rEntry,
981 const sal_Char *pBuffer,
982 sal_uInt32 nLength)
984 setPath (rEntry.m_aName, pBuffer,sal_Int32 (nLength));
985 return sal_True;
989 * parseUNIX_isSizeField.
991 sal_Bool FTPDirectoryParser::parseUNIX_isSizeField (
992 const sal_Char *pStart,
993 const sal_Char *pEnd,
994 sal_uInt32 &rSize)
996 if (!*pStart || !*pEnd || pStart == pEnd)
997 return sal_False;
999 rSize = 0;
1000 if (*pStart >= '0' && *pStart <= '9')
1002 for (; pStart < pEnd; ++pStart)
1003 if ((*pStart >= '0') && (*pStart <= '9'))
1004 rSize = 10 * rSize + (*pStart - '0');
1005 else
1006 return sal_False;
1007 return sal_True;
1009 else
1012 * For a combination of long group name and large file size,
1013 * some FTPDs omit LWS between those two columns.
1015 int nNonDigits = 0;
1016 int nDigits = 0;
1018 for (; pStart < pEnd; ++pStart)
1019 if ((*pStart >= '1') && (*pStart <= '9'))
1021 ++nDigits;
1022 rSize = 10 * rSize + (*pStart - '0');
1024 else if ((*pStart == '0') && nDigits)
1026 ++nDigits;
1027 rSize *= 10;
1029 else if ((*pStart > ' ') && (sal::static_int_cast<sal_uInt8>(*pStart) <= '\x7F'))
1031 nNonDigits += nDigits + 1;
1032 nDigits = 0;
1033 rSize = 0;
1035 else
1036 return sal_False;
1037 return ((nNonDigits >= 9) && (nDigits >= 7));
1042 * parseUNIX_isMonthField.
1044 sal_Bool FTPDirectoryParser::parseUNIX_isMonthField (
1045 const sal_Char *pStart,
1046 const sal_Char *pEnd,
1047 DateTime &rDateTime)
1049 if (!*pStart || !*pEnd || pStart + 3 != pEnd)
1050 return sal_False;
1052 if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1053 (pStart[1] == 'a' || pStart[1] == 'A') &&
1054 (pStart[2] == 'n' || pStart[2] == 'N') )
1056 rDateTime.SetMonth(1);
1057 return sal_True;
1059 if ((pStart[0] == 'f' || pStart[0] == 'F') &&
1060 (pStart[1] == 'e' || pStart[1] == 'E') &&
1061 (pStart[2] == 'b' || pStart[2] == 'B') )
1063 rDateTime.SetMonth(2);
1064 return sal_True;
1066 if ((pStart[0] == 'm' || pStart[0] == 'M') &&
1067 (pStart[1] == 'a' || pStart[1] == 'A') &&
1068 (pStart[2] == 'r' || pStart[2] == 'R') )
1070 rDateTime.SetMonth(3);
1071 return sal_True;
1073 if ((pStart[0] == 'a' || pStart[0] == 'A') &&
1074 (pStart[1] == 'p' || pStart[1] == 'P') &&
1075 (pStart[2] == 'r' || pStart[2] == 'R') )
1077 rDateTime.SetMonth(4);
1078 return sal_True;
1080 if ((pStart[0] == 'm' || pStart[0] == 'M') &&
1081 (pStart[1] == 'a' || pStart[1] == 'A') &&
1082 (pStart[2] == 'y' || pStart[2] == 'Y') )
1084 rDateTime.SetMonth(5);
1085 return sal_True;
1087 if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1088 (pStart[1] == 'u' || pStart[1] == 'U') &&
1089 (pStart[2] == 'n' || pStart[2] == 'N') )
1091 rDateTime.SetMonth(6);
1092 return sal_True;
1094 if ((pStart[0] == 'j' || pStart[0] == 'J') &&
1095 (pStart[1] == 'u' || pStart[1] == 'U') &&
1096 (pStart[2] == 'l' || pStart[2] == 'L') )
1098 rDateTime.SetMonth(7);
1099 return sal_True;
1101 if ((pStart[0] == 'a' || pStart[0] == 'A') &&
1102 (pStart[1] == 'u' || pStart[1] == 'U') &&
1103 (pStart[2] == 'g' || pStart[2] == 'G') )
1105 rDateTime.SetMonth(8);
1106 return sal_True;
1108 if ((pStart[0] == 's' || pStart[0] == 'S') &&
1109 (pStart[1] == 'e' || pStart[1] == 'E') &&
1110 (pStart[2] == 'p' || pStart[2] == 'P') )
1112 rDateTime.SetMonth(9);
1113 return sal_True;
1115 if ((pStart[0] == 'o' || pStart[0] == 'O') &&
1116 (pStart[1] == 'c' || pStart[1] == 'C') &&
1117 (pStart[2] == 't' || pStart[2] == 'T') )
1119 rDateTime.SetMonth(10);
1120 return sal_True;
1122 if ((pStart[0] == 'n' || pStart[0] == 'N') &&
1123 (pStart[1] == 'o' || pStart[1] == 'O') &&
1124 (pStart[2] == 'v' || pStart[2] == 'V') )
1126 rDateTime.SetMonth(11);
1127 return sal_True;
1129 if ((pStart[0] == 'd' || pStart[0] == 'D') &&
1130 (pStart[1] == 'e' || pStart[1] == 'E') &&
1131 (pStart[2] == 'c' || pStart[2] == 'C') )
1133 rDateTime.SetMonth(12);
1134 return sal_True;
1136 return sal_False;
1140 * parseUNIX_isDayField.
1142 sal_Bool FTPDirectoryParser::parseUNIX_isDayField (
1143 const sal_Char *pStart,
1144 const sal_Char *pEnd,
1145 DateTime &rDateTime)
1147 if (!*pStart || !*pEnd || pStart == pEnd)
1148 return sal_False;
1149 if (*pStart < '0' || *pStart > '9')
1150 return sal_False;
1152 sal_uInt16 nDay = *pStart - '0';
1153 if (pStart + 1 < pEnd)
1155 if (pStart + 2 != pEnd || pStart[1] < '0' || pStart[1] > '9')
1156 return sal_False;
1157 nDay = 10 * nDay + (pStart[1] - '0');
1159 if (!nDay || nDay > 31)
1160 return sal_False;
1162 rDateTime.SetDay(nDay);
1163 return sal_True;
1167 * parseUNIX_isYearTimeField.
1169 sal_Bool FTPDirectoryParser::parseUNIX_isYearTimeField (
1170 const sal_Char *pStart,
1171 const sal_Char *pEnd,
1172 DateTime &rDateTime)
1174 if (!*pStart || !*pEnd || pStart == pEnd ||
1175 *pStart < '0' || *pStart > '9')
1176 return sal_False;
1178 sal_uInt16 nNumber = *pStart - '0';
1179 ++pStart;
1181 if (pStart == pEnd)
1182 return sal_False;
1183 if (*pStart == ':')
1184 return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime);
1185 if (*pStart < '0' || *pStart > '9')
1186 return sal_False;
1188 nNumber = 10 * nNumber + (*pStart - '0');
1189 ++pStart;
1191 if (pStart == pEnd)
1192 return sal_False;
1193 if (*pStart == ':')
1194 return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime);
1195 if (*pStart < '0' || *pStart > '9')
1196 return sal_False;
1198 nNumber = 10 * nNumber + (*pStart - '0');
1199 ++pStart;
1201 if (pStart == pEnd || *pStart < '0' || *pStart > '9')
1202 return sal_False;
1204 nNumber = 10 * nNumber + (*pStart - '0');
1205 if (pStart + 1 != pEnd || nNumber < 1970)
1206 return sal_False;
1208 rDateTime.SetYear(nNumber);
1209 rDateTime.SetTime(0);
1210 return sal_True;
1214 * parseUNIX_isTime.
1216 sal_Bool FTPDirectoryParser::parseUNIX_isTime (
1217 const sal_Char *pStart,
1218 const sal_Char *pEnd,
1219 sal_uInt16 nHour,
1220 DateTime &rDateTime)
1222 if ((nHour > 23 ) || (pStart + 3 != pEnd) ||
1223 (pStart[1] < '0') || (pStart[1] > '5') ||
1224 (pStart[2] < '0') || (pStart[2] > '9') )
1225 return sal_False;
1227 sal_uInt16 nMin = 10 * (pStart[1] - '0') + (pStart[2] - '0');
1229 rDateTime.SetHour (nHour);
1230 rDateTime.SetMin (nMin);
1231 rDateTime.SetSec (0);
1232 rDateTime.Set100Sec (0);
1234 // Date aCurDate;
1235 // if (rDateTime.GetMonth() > aCurDate.GetMonth())
1236 // rDateTime.SetYear(aCurDate.GetYear() - 1);
1237 // else
1238 // rDateTime.SetYear(aCurDate.GetYear());
1239 // return sal_True;
1241 TimeValue aTimeVal;
1242 osl_getSystemTime(&aTimeVal);
1243 oslDateTime aCurrDateTime;
1244 osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime);
1246 if (rDateTime.GetMonth() > aCurrDateTime.Month)
1247 rDateTime.SetYear(aCurrDateTime.Year - 1);
1248 else
1249 rDateTime.SetYear(aCurrDateTime.Year);
1250 return sal_True;
1254 * setYear.
1256 * Two-digit years are taken as within 50 years back and 49 years forward
1257 * (both ends inclusive) from the current year. The returned date is not
1258 * checked for validity of the given day in the given month and year.
1261 sal_Bool FTPDirectoryParser::setYear (
1262 DateTime &rDateTime, sal_uInt16 nYear)
1264 if (nYear < 100)
1266 TimeValue aTimeVal;
1267 osl_getSystemTime(&aTimeVal);
1268 oslDateTime aCurrDateTime;
1269 osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime);
1270 sal_uInt16 nCurrentYear = aCurrDateTime.Year;
1271 // sal_uInt16 nCurrentYear = Date().GetYear();
1272 sal_uInt16 nCurrentCentury = nCurrentYear / 100;
1273 nCurrentYear %= 100;
1274 if (nCurrentYear < 50)
1275 if (nYear <= nCurrentYear)
1276 nYear += nCurrentCentury * 100;
1277 else if (nYear < nCurrentYear + 50)
1278 nYear += nCurrentCentury * 100;
1279 else
1280 nYear += (nCurrentCentury - 1) * 100;
1281 else
1282 if (nYear >= nCurrentYear)
1283 nYear += nCurrentCentury * 100;
1284 else if (nYear >= nCurrentYear - 50)
1285 nYear += nCurrentCentury * 100;
1286 else
1287 nYear += (nCurrentCentury + 1) * 100;
1290 rDateTime.SetYear(nYear);
1291 return sal_True;
1295 * setPath.
1297 sal_Bool FTPDirectoryParser::setPath (
1298 OUString &rPath, const sal_Char *value, sal_Int32 length)
1300 if (value)
1302 if (length < 0)
1303 length = rtl_str_getLength (value);
1304 rPath = OUString (value, length, RTL_TEXTENCODING_UTF8);
1306 return (!!value);