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 
30 using 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 
60  FTPDirentry &rEntry,
61  const sal_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 sal_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 sal_Char *pBuffer)
559 {
560  static OUString aFirstLineName;
561  static bool bFirstLineDir = false;
562 
563  for (bool bFirstLine = true;; bFirstLine = false)
564  {
565  const sal_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 sal_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 sal_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  sal_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 sal_Char *pBuffer)
846 {
847  const sal_Char *p1, *p2;
848  p1 = p2 = 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 sal_Char *pDayStart = nullptr;
880  const sal_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 sal_Char *pStart,
954  const sal_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 sal_Char *pStart,
1007  const sal_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 sal_Char *pStart,
1105  const sal_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 sal_Char *pStart,
1132  const sal_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 sal_Char *pStart,
1179  const sal_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 sal_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 sal_Char *pStart, const sal_Char *pEnd, sal_uInt16 nHour, DateTime &rDateTime)
Definition: ftpdirp.cxx:1177
void SetNanoSec(sal_uInt32 nanoSec)
Definition: ftpdirp.hxx:54
void SetSec(sal_uInt16 seconds)
Definition: ftpdirp.hxx:53
static bool parseUNIX_isDayField(const sal_Char *pStart, const sal_Char *pEnd, DateTime &rDateTime)
Definition: ftpdirp.cxx:1103
static bool parseUNIX_isMonthField(const sal_Char *pStart, const sal_Char *pEnd, DateTime &rDateTime)
Definition: ftpdirp.cxx:1005
static bool parseUNIX_isYearTimeField(const sal_Char *pStart, const sal_Char *pEnd, DateTime &rDateTime)
Definition: ftpdirp.cxx:1130
static bool parseUNIX_isSizeField(const sal_Char *pStart, const sal_Char *pEnd, sal_uInt32 &rSize)
Definition: ftpdirp.cxx:952
static bool parseUNIX(FTPDirentry &rEntry, const sal_Char *pBuffer)
Definition: ftpdirp.cxx:843
sal_uInt16 sal_Unicode
char sal_Char
sal_uInt32 m_nMode
Definition: ftpdirp.hxx:77
void SetMin(sal_uInt16 minutes)
Definition: ftpdirp.hxx:52
int i
static bool parseDOS(FTPDirentry &rEntry, const sal_Char *pBuffer)
Definition: ftpdirp.cxx:59
Definition of ftpcontentprovider.
static bool ascii_isWhitespace(sal_Unicode ch)
Definition: ftpdirp.cxx:32
void SetDay(sal_uInt16 day)
Definition: ftpdirp.hxx:48
void SetYear(sal_uInt16 year)
Definition: ftpdirp.hxx:46
unsigned char sal_uInt8
static bool setPath(OUString &rPath, const sal_Char *value, sal_Int32 length=-1)
Definition: ftpdirp.cxx:1257
sal_uInt16 GetMonth()
Definition: ftpdirp.hxx:56
void SetHour(sal_uInt16 hours)
Definition: ftpdirp.hxx:51
DateTime m_aDate
Definition: ftpdirp.hxx:76
sal_uInt32 m_nSize
Definition: ftpdirp.hxx:78
void SetMonth(sal_uInt16 month)
Definition: ftpdirp.hxx:47
static void setYear(DateTime &rDateTime, sal_uInt16 nYear)
Definition: ftpdirp.cxx:1222
void SetTime()
Definition: ftpdirp.hxx:50
OUString m_aName
Definition: ftpdirp.hxx:75
static bool parseVMS(FTPDirentry &rEntry, const sal_Char *pBuffer)
Definition: ftpdirp.cxx:556