diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /ucb/source/ucp/ftp/ftpdirp.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ucb/source/ucp/ftp/ftpdirp.cxx')
-rw-r--r-- | ucb/source/ucp/ftp/ftpdirp.cxx | 1269 |
1 files changed, 1269 insertions, 0 deletions
diff --git a/ucb/source/ucp/ftp/ftpdirp.cxx b/ucb/source/ucp/ftp/ftpdirp.cxx new file mode 100644 index 000000000..69bea64ab --- /dev/null +++ b/ucb/source/ucp/ftp/ftpdirp.cxx @@ -0,0 +1,1269 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ +#include "ftpdirp.hxx" +#include <osl/time.h> + + +using namespace ftp; + +static bool ascii_isWhitespace( sal_Unicode ch ) +{ + return ((ch <= 0x20) && ch); +} + + +/*======================================================================== + * + * FTPDirectoryParser implementation. + * + *======================================================================*/ +/* + * parseDOS. + * Accepts one of two styles: + * + * 1 *WSP 1*2DIGIT ("." / "-") 1*2DIGIT ("." / "-") 1*4DIGIT 1*WSP + * 1*2DIGIT ":" 1*2DIGIT [*WSP ("A" / "P") "M"] 1*WSP + * ((DIGIT *(DIGIT / "." / ",")) / "<DIR>") 1*WSP 1*OCTET + * + * interpreted as: mm.dd.yy hh:mm (size / <DIR>) name + * + * 2 *WSP 1*DIGIT 1*WSP *(1*CHAR *WSP) *1("DIR" 1*WSP) 1*2DIGIT "-" 1*2DIGIT + * "-" 1*4DIGIT 1*WSP 1*2DIGIT ":" 1*2DIGIT 1*WSP 1*OCTET + * + * interpreted as: size attribs DIR mm-dd-yy hh:mm name + */ + +bool FTPDirectoryParser::parseDOS ( + FTPDirentry &rEntry, + const char *pBuffer) +{ + bool bDirectory = false; + sal_uInt32 nSize = 0; + sal_uInt16 nYear = 0; + sal_uInt16 nMonth = 0; + sal_uInt16 nDay = 0; + sal_uInt16 nHour = 0; + sal_uInt16 nMinute = 0; + + enum StateType + { + STATE_INIT_LWS, + STATE_MONTH_OR_SIZE, + STATE_1_DAY, STATE_1_YEAR, STATE_1_YEAR_LWS, STATE_1_HOUR, + STATE_1_MINUTE, STATE_1_MINUTE_LWS, STATE_1_AP, + STATE_1_APM, STATE_1_LESS, STATE_1_D, STATE_1_DI, + STATE_1_DIR, STATE_1_SIZE, + STATE_2_SIZE, STATE_2_SIZE_LWS, STATE_2_ATTRIB, + STATE_2_D, STATE_2_DI, STATE_2_DIR_LWS, + STATE_2_MONTH, STATE_2_DAY, STATE_2_YEAR, STATE_2_YEAR_LWS, + STATE_2_HOUR, STATE_2_MINUTE, + STATE_LWS_NAME, + STATE_ERROR + }; + + int nDigits = 0; + enum StateType eState = STATE_INIT_LWS; + for (const char *p = pBuffer; + eState != STATE_ERROR && *p; + ++p) + { + switch (eState) + { + case STATE_INIT_LWS: + if (*p >= '0' && *p <= '9') + { + nMonth = *p - '0'; + nDigits = 1; + eState = STATE_MONTH_OR_SIZE; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_MONTH_OR_SIZE: + if (*p >= '0' && *p <= '9') + { + nMonth = 10 * nMonth + (*p - '0'); + if (nDigits < 2) + ++nDigits; + else + { + nSize = nMonth; + nMonth = 0; + eState = STATE_2_SIZE; + } + } + else if (ascii_isWhitespace(*p)) + { + nSize = nMonth; + nMonth = 0; + eState = STATE_2_SIZE_LWS; + } + else if ((*p == '.' || *p == '-') && nMonth && nMonth <= 12) + { + nDigits = 0; + eState = STATE_1_DAY; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_DAY: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nDay = 10 * nDay + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if ((*p == '.' || *p == '-') && nDay && nDay <= 31) + { + nDigits = 0; + eState = STATE_1_YEAR; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_YEAR: + if (*p >= '0' && *p <= '9') + { + if (nDigits < 4) + { + nYear = 10 * nYear + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + } + else + { + if (ascii_isWhitespace(*p)) + eState = STATE_1_YEAR_LWS; + else + eState = STATE_ERROR; + } + break; + + case STATE_1_YEAR_LWS: + if (*p >= '0' && *p <= '9') + { + nHour = *p - '0'; + nDigits = 1; + eState = STATE_1_HOUR; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_1_HOUR: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nHour = 10 * nHour + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == ':' && nHour < 24) + { + nDigits = 0; + eState = STATE_1_MINUTE; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_MINUTE: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nMinute = 10 * nMinute + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if ((*p == 'a' || *p == 'A') && nMinute < 60) + if (nHour >= 1 && nHour <= 11) + eState = STATE_1_AP; + else if (nHour == 12) + { + nHour = 0; + eState = STATE_1_AP; + } + else + eState = STATE_ERROR; + else if ((*p == 'p' || *p == 'P') && nMinute < 60) + if (nHour >= 1 && nHour <= 11) + { + nHour += 12; + eState = STATE_1_AP; + } + else if (nHour == 12) + eState = STATE_1_AP; + else + eState = STATE_ERROR; + else if (ascii_isWhitespace(*p) && (nMinute < 60)) + eState = STATE_1_MINUTE_LWS; + else + eState = STATE_ERROR; + break; + + case STATE_1_MINUTE_LWS: + if (*p == 'a' || *p == 'A') + if (nHour >= 1 && nHour <= 11) + eState = STATE_1_AP; + else if (nHour == 12) + { + nHour = 0; + eState = STATE_1_AP; + } + else + eState = STATE_ERROR; + else if (*p == 'p' || *p == 'P') + if (nHour >= 1 && nHour <= 11) + { + nHour += 12; + eState = STATE_1_AP; + } + else if (nHour == 12) + eState = STATE_1_AP; + else + eState = STATE_ERROR; + else if (*p == '<') + eState = STATE_1_LESS; + else if (*p >= '0' && *p <= '9') + { + nSize = *p - '0'; + eState = STATE_1_SIZE; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_1_AP: + eState = *p == 'm' || *p == 'M' ? STATE_1_APM : STATE_ERROR; + break; + + case STATE_1_APM: + if (*p == '<') + eState = STATE_1_LESS; + else if (*p >= '0' && *p <= '9') + { + nSize = *p - '0'; + eState = STATE_1_SIZE; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_1_LESS: + eState = *p == 'd' || *p == 'D' ? STATE_1_D : STATE_ERROR; + break; + + case STATE_1_D: + eState = *p == 'i' || *p == 'I' ? STATE_1_DI : STATE_ERROR; + break; + + case STATE_1_DI: + eState = *p == 'r' || *p == 'R' ? STATE_1_DIR : STATE_ERROR; + break; + + case STATE_1_DIR: + if (*p == '>') + { + bDirectory = true; + eState = STATE_LWS_NAME; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_SIZE: + if (*p >= '0' && *p <= '9') + nSize = 10 * nSize + (*p - '0'); + else if (ascii_isWhitespace(*p)) + eState = STATE_LWS_NAME; + else + eState = STATE_ERROR; + break; + + case STATE_2_SIZE: + if (*p >= '0' && *p <= '9') + nSize = 10 * nSize + (*p - '0'); + else if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else + eState = STATE_ERROR; + break; + + case STATE_2_SIZE_LWS: + if (*p == 'd' || *p == 'D') + eState = STATE_2_D; + else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) + eState = STATE_2_ATTRIB; + else if (*p >= '0' && *p <= '9') + { + nMonth = *p - '0'; + nDigits = 1; + eState = STATE_2_MONTH; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_2_ATTRIB: + if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else if ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z')) + eState = STATE_ERROR; + break; + + case STATE_2_D: + if (*p == 'i' || *p == 'I') + eState = STATE_2_DI; + else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) + eState = STATE_2_ATTRIB; + else if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else + eState = STATE_ERROR; + break; + + case STATE_2_DI: + if (*p == 'r' || *p == 'R') + { + bDirectory = true; + eState = STATE_2_DIR_LWS; + } + else + { + if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) + eState = STATE_2_ATTRIB; + else if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else + eState = STATE_ERROR; + } + break; + + case STATE_2_DIR_LWS: + if (*p >= '0' && *p <= '9') + { + nMonth = *p - '0'; + nDigits = 1; + eState = STATE_2_MONTH; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_2_MONTH: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nMonth = 10 * nMonth + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == '-' && nMonth && nMonth <= 12) + { + nDigits = 0; + eState = STATE_2_DAY; + } + else + eState = STATE_ERROR; + break; + + case STATE_2_DAY: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nDay = 10 * nDay + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == '-' && nDay && nDay <= 31) + { + nDigits = 0; + eState = STATE_2_YEAR; + } + else + eState = STATE_ERROR; + break; + + case STATE_2_YEAR: + if (*p >= '0' && *p <= '9') + { + if (nDigits < 4) + { + nYear = 10 * nYear + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + } + else + { + if (ascii_isWhitespace(*p)) + eState = STATE_2_YEAR_LWS; + else + eState = STATE_ERROR; + } + break; + + case STATE_2_YEAR_LWS: + if (*p >= '0' && *p <= '9') + { + nHour = *p - '0'; + nDigits = 1; + eState = STATE_2_HOUR; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_2_HOUR: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nHour = 10 * nHour + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == ':' && nHour < 24) + { + nDigits = 0; + eState = STATE_2_MINUTE; + } + else + eState = STATE_ERROR; + break; + + case STATE_2_MINUTE: + if (*p >= '0' && *p <= '9') + { + if (nDigits < 2) + { + nMinute = 10 * nMinute + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + } + else + { + if (ascii_isWhitespace(*p) && (nMinute < 60)) + eState = STATE_LWS_NAME; + else + eState = STATE_ERROR; + } + break; + + case STATE_LWS_NAME: + if (!ascii_isWhitespace(*p)) + { + setPath (rEntry.m_aName, p); + if (bDirectory) + rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR; + rEntry.m_nSize = nSize; + + setYear (rEntry.m_aDate, nYear); + + rEntry.m_aDate.SetMonth(nMonth); + rEntry.m_aDate.SetDay(nDay); + rEntry.m_aDate.SetHour(nHour); + rEntry.m_aDate.SetMin(nMinute); + + return true; + } + break; + case STATE_ERROR: + break; + } + } + + return false; +} + +/* + * parseVMS. + * Directory entries may span one or two lines: + * + * entry: *lws name *1(*lws <NEWLINE>) 1*lws size 1*lws datetime rest + * + * name: filename "." filetype ";" version + * filename: 1*39fchar + * filetype: 1*39fchar + * version: non0digit *digit + * + * size: "0" / non0digit *digit + * + * datetime: date 1*lwsp time + * date: day "-" month "-" year + * day: (*1"0" non0digit) / ("1"-"2" digit) / ("3" "0"-"1") + * month: "JAN" / "FEB" / "MAR" / "APR" / "MAY" / "JUN" / "JUL" / "AUG" + * / "SEP" / "OCT" / "NOV" / "DEC" ; all case insensitive + * year: 2digit / 4digit + * time: hour ":" minute + * hour: ((*1"0" / "1") digit) / ("2" "0"-"3") + * minute: "0"-"5" digit + * + * rest: *1(lws *<ANY>) + * + * lws: <TAB> / <SPACE> + * non0digit: "1"-"9" + * digit: "0" / non0digit + * fchar: "A"-"Z" / "a"-"z" / digit / "-" / "_" / "$" + * + * For directories, the returned name is the <filename> part; for non- + * directory files, the returned name is the <filename "." filetype> part. + * An entry is a directory iff its filetype is "DIR" (ignoring case). + * + * The READ, WRITE, and ISLINK mode bits are not supported. + * + * The returned size is the <size> part, multiplied by 512, and with the high + * order bits truncated to fit into a sal_uInt32. + * + */ +bool FTPDirectoryParser::parseVMS ( + FTPDirentry &rEntry, + const char *pBuffer) +{ + static OUString aFirstLineName; + static bool bFirstLineDir = false; + + for (bool bFirstLine = true;; bFirstLine = false) + { + const char *p = pBuffer; + if (bFirstLine) + { + // Skip <*lws> part: + while (*p == '\t' || *p == ' ') + ++p; + + // Parse <filename "."> part: + const char *pFileName = p; + while ((*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || + (*p >= '0' && *p <= '9') || + *p == '-' || *p == '_' || *p == '$') + ++p; + + if (*p != '.' || p == pFileName || p - pFileName > 39) + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + + // Parse <filetype ";"> part: + const char *pFileType = ++p; + while ((*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || + (*p >= '0' && *p <= '9') || + *p == '-' || *p == '_' || *p == '$') + ++p; + + if (*p != ';' || p == pFileName || p - pFileName > 39) + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + ++p; + + // Set entry's name and mode (ISDIR flag): + if ((p - pFileType == 4) && + (pFileType[0] == 'D' || pFileType[0] == 'd') && + (pFileType[1] == 'I' || pFileType[1] == 'i') && + (pFileType[2] == 'R' || pFileType[2] == 'r') ) + { + setPath (rEntry.m_aName, pFileName, (pFileType - pFileName)); + rEntry.m_nMode = INETCOREFTP_FILEMODE_ISDIR; + } + else + { + setPath (rEntry.m_aName, pFileName, (p - pFileName)); + rEntry.m_nMode = 0; + } + + // Skip <version> part: + if (*p < '1' || *p > '9') + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + ++p; + while (*p >= '0' && *p <= '9') + ++p; + + // Parse <1*lws> or <*lws <NEWLINE>> part: + bool bLWS = false; + while (*p == '\t' || *p == ' ') + { + bLWS = true; + ++p; + } + if (*p) + { + if (!bLWS) + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + } + else + { + /* + * First line of entry spanning two lines, + * wait for second line. + */ + aFirstLineName = rEntry.m_aName; + bFirstLineDir = + ((rEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) != 0); + return false; + } + } + else + { + /* + * Second line of entry spanning two lines, + * restore entry's name and mode (ISDIR flag). + */ + rEntry.m_aName = aFirstLineName; + rEntry.m_nMode = (bFirstLineDir ? INETCOREFTP_FILEMODE_ISDIR : 0); + + // Skip <1*lws> part: + if (*p != '\t' && *p != ' ') + return false; + ++p; + while (*p == '\t' || *p == ' ') + ++p; + } + + // Parse <size> part and set entry's size: + if (*p < '0' || *p > '9') + return false; + sal_uInt32 nSize = *p - '0'; + if (*p++ != '0') + while (*p >= '0' && *p <= '9') + nSize = 10 * rEntry.m_nSize + (*p++ - '0'); + rEntry.m_nSize = 512 * nSize; + + // Skip <1*lws> part: + if (*p != '\t' && *p != ' ') + return false; + ++p; + while (*p == '\t' || *p == ' ') + ++p; + + // Parse <day "-"> part and set entry date's day: + sal_uInt16 nDay; + if (*p == '0') + { + ++p; + if (*p < '1' || *p > '9') + return false; + nDay = *p++ - '0'; + } + else if (*p == '1' || *p == '2') + { + nDay = *p++ - '0'; + if (*p >= '0' && *p <= '9') + nDay = 10 * nDay + (*p++ - '0'); + } + else if (*p == '3') + { + ++p; + nDay = (*p == '0' || *p == '1') ? 30 + (*p++ - '0') : 3; + } + else if (*p >= '4' && *p <= '9') + nDay = *p++ - '0'; + else + return false; + + rEntry.m_aDate.SetDay(nDay); + if (*p++ != '-') + return false; + + // Parse <month "-"> part and set entry date's month: + char const * pMonth = p; + sal_Int32 const monthLen = 3; + for (int i = 0; i < monthLen; ++i) + { + if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) + return false; + ++p; + } + if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "JAN", monthLen) == 0) + rEntry.m_aDate.SetMonth(1); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "FEB", monthLen) == 0) + rEntry.m_aDate.SetMonth(2); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "MAR", monthLen) == 0) + rEntry.m_aDate.SetMonth(3); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "APR", monthLen) == 0) + rEntry.m_aDate.SetMonth(4); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "MAY", monthLen) == 0) + rEntry.m_aDate.SetMonth(5); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "JUN", monthLen) == 0) + rEntry.m_aDate.SetMonth(6); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "JUL", monthLen) == 0) + rEntry.m_aDate.SetMonth(7); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "AUG", monthLen) == 0) + rEntry.m_aDate.SetMonth(8); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "SEP", monthLen) == 0) + rEntry.m_aDate.SetMonth(9); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "OCT", monthLen) == 0) + rEntry.m_aDate.SetMonth(10); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "NOV", monthLen) == 0) + rEntry.m_aDate.SetMonth(11); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "DEC", monthLen) == 0) + rEntry.m_aDate.SetMonth(12); + else + return false; + if (*p++ != '-') + return false; + + // Parse <year> part and set entry date's year: + sal_uInt16 nYear = 0; + for (int i = 0; i < 2; ++i) + { + if (*p < '0' || *p > '9') + return false; + nYear = 10 * nYear + (*p++ - '0'); + } + if (*p >= '0' && *p <= '9') + { + nYear = 10 * nYear + (*p++ - '0'); + if (*p < '0' || *p > '9') + return false; + nYear = 10 * nYear + (*p++ - '0'); + } + setYear (rEntry.m_aDate, nYear); + + // Skip <1*lws> part: + if (*p != '\t' && *p != ' ') + return false; + ++p; + while (*p == '\t' || *p == ' ') + ++p; + + // Parse <hour ":"> part and set entry time's hour: + sal_uInt16 nHour; + if (*p == '0' || *p == '1') + { + nHour = *p++ - '0'; + if (*p >= '0' && *p <= '9') + nHour = 10 * nHour + (*p++ - '0'); + } + else if (*p == '2') + { + ++p; + nHour = (*p >= '0' && *p <= '3') ? 20 + (*p++ - '0') : 2; + } + else if (*p >= '3' && *p <= '9') + nHour = *p++ - '0'; + else + return false; + + rEntry.m_aDate.SetHour(nHour); + if (*p++ != ':') + return false; + + /* + * Parse <minute> part and set entry time's minutes, + * seconds (0), and nanoseconds (0). + */ + if (*p < '0' || *p > '5') + return false; + + sal_uInt16 nMinute = *p++ - '0'; + if (*p < '0' || *p > '9') + return false; + + nMinute = 10 * nMinute + (*p++ - '0'); + rEntry.m_aDate.SetMin(nMinute); + rEntry.m_aDate.SetSec(0); + rEntry.m_aDate.SetNanoSec(0); + + // Skip <rest> part: + return !*p || *p == '\t' || *p == ' '; + } +} + +/* + * parseUNIX + */ +bool FTPDirectoryParser::parseUNIX ( + FTPDirentry &rEntry, + const char *pBuffer) +{ + const char *p1, *p2; + p1 = pBuffer; + + if (!((*p1 == '-') || (*p1 == 'd') || (*p1 == 'l'))) + return false; + + // 1st column: FileMode. + if (*p1 == 'd') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR; + + if (*p1 == 'l') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISLINK; + + // Skip to end of column and set rights by the way + while (*p1 && !ascii_isWhitespace(*p1)) { + if(*p1 == 'r') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_READ; + else if(*p1 == 'w') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_WRITE; + p1++; + } + + /* + * Scan for the sequence of size and date fields: + * *LWS 1*DIGIT 1*LWS 3CHAR 1*LWS 1*2DIGIT 1*LWS + * (4DIGIT / (1*2DIGIT ":" 2DIGIT)) 1*LWS + */ + enum Mode + { + FOUND_NONE, FOUND_SIZE, FOUND_MONTH, FOUND_DAY, FOUND_YEAR_TIME + }; + + const char *pDayStart = nullptr; + const char *pDayEnd = nullptr; + Mode eMode; + for (eMode = FOUND_NONE; *p1 && eMode != FOUND_YEAR_TIME; p1 = p2 + 1) + { + while (*p1 && ascii_isWhitespace(*p1)) + ++p1; + p2 = p1; + while (*p2 && !ascii_isWhitespace(*p2)) + ++p2; + + switch (eMode) + { + case FOUND_NONE: + if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_SIZE; + break; + + case FOUND_SIZE: + if (parseUNIX_isMonthField (p1, p2, rEntry.m_aDate)) + eMode = FOUND_MONTH; + else if (!parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_NONE; + break; + + case FOUND_MONTH: + if (parseUNIX_isDayField (p1, p2, rEntry.m_aDate)) + { + pDayStart = p1; + pDayEnd = p2; + eMode = FOUND_DAY; + } + else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_SIZE; + else + eMode = FOUND_NONE; + break; + + case FOUND_DAY: + if (parseUNIX_isYearTimeField (p1, p2, rEntry.m_aDate)) + eMode = FOUND_YEAR_TIME; + else if ( + parseUNIX_isSizeField ( + pDayStart, pDayEnd, rEntry.m_nSize) && + parseUNIX_isMonthField ( + p1, p2, rEntry.m_aDate)) + eMode = FOUND_MONTH; + else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_SIZE; + else + eMode = FOUND_NONE; + break; + // coverity[dead_error_begin] - following conditions exist to avoid compiler warning + case FOUND_YEAR_TIME: + break; + } + } + + if (eMode == FOUND_YEAR_TIME) + { + // 9th column: FileName (rest of line). + while (*p1 && ascii_isWhitespace(*p1)) p1++; + setPath (rEntry.m_aName, p1); + + // Done. + return true; + } + return false; +} + +/* + * parseUNIX_isSizeField. + */ +bool FTPDirectoryParser::parseUNIX_isSizeField ( + const char *pStart, + const char *pEnd, + sal_uInt32 &rSize) +{ + if (!*pStart || !*pEnd || pStart == pEnd) + return false; + + rSize = 0; + if (*pStart >= '0' && *pStart <= '9') + { + for (; pStart < pEnd; ++pStart) + if ((*pStart >= '0') && (*pStart <= '9')) + rSize = 10 * rSize + (*pStart - '0'); + else + return false; + return true; + } + else + { + /* + * For a combination of long group name and large file size, + * some FTPDs omit LWS between those two columns. + */ + int nNonDigits = 0; + int nDigits = 0; + + for (; pStart < pEnd; ++pStart) + if ((*pStart >= '1') && (*pStart <= '9')) + { + ++nDigits; + rSize = 10 * rSize + (*pStart - '0'); + } + else if ((*pStart == '0') && nDigits) + { + ++nDigits; + rSize *= 10; + } + else if ((*pStart > ' ') && (sal::static_int_cast<sal_uInt8>(*pStart) <= '\x7F')) + { + nNonDigits += nDigits + 1; + nDigits = 0; + rSize = 0; + } + else + return false; + return ((nNonDigits >= 9) && (nDigits >= 7)); + } +} + +/* + * parseUNIX_isMonthField. + */ +bool FTPDirectoryParser::parseUNIX_isMonthField ( + const char *pStart, + const char *pEnd, + DateTime &rDateTime) +{ + if (!*pStart || !*pEnd || pStart + 3 != pEnd) + return false; + + if ((pStart[0] == 'j' || pStart[0] == 'J') && + (pStart[1] == 'a' || pStart[1] == 'A') && + (pStart[2] == 'n' || pStart[2] == 'N') ) + { + rDateTime.SetMonth(1); + return true; + } + if ((pStart[0] == 'f' || pStart[0] == 'F') && + (pStart[1] == 'e' || pStart[1] == 'E') && + (pStart[2] == 'b' || pStart[2] == 'B') ) + { + rDateTime.SetMonth(2); + return true; + } + if ((pStart[0] == 'm' || pStart[0] == 'M') && + (pStart[1] == 'a' || pStart[1] == 'A') && + (pStart[2] == 'r' || pStart[2] == 'R') ) + { + rDateTime.SetMonth(3); + return true; + } + if ((pStart[0] == 'a' || pStart[0] == 'A') && + (pStart[1] == 'p' || pStart[1] == 'P') && + (pStart[2] == 'r' || pStart[2] == 'R') ) + { + rDateTime.SetMonth(4); + return true; + } + if ((pStart[0] == 'm' || pStart[0] == 'M') && + (pStart[1] == 'a' || pStart[1] == 'A') && + (pStart[2] == 'y' || pStart[2] == 'Y') ) + { + rDateTime.SetMonth(5); + return true; + } + if ((pStart[0] == 'j' || pStart[0] == 'J') && + (pStart[1] == 'u' || pStart[1] == 'U') && + (pStart[2] == 'n' || pStart[2] == 'N') ) + { + rDateTime.SetMonth(6); + return true; + } + if ((pStart[0] == 'j' || pStart[0] == 'J') && + (pStart[1] == 'u' || pStart[1] == 'U') && + (pStart[2] == 'l' || pStart[2] == 'L') ) + { + rDateTime.SetMonth(7); + return true; + } + if ((pStart[0] == 'a' || pStart[0] == 'A') && + (pStart[1] == 'u' || pStart[1] == 'U') && + (pStart[2] == 'g' || pStart[2] == 'G') ) + { + rDateTime.SetMonth(8); + return true; + } + if ((pStart[0] == 's' || pStart[0] == 'S') && + (pStart[1] == 'e' || pStart[1] == 'E') && + (pStart[2] == 'p' || pStart[2] == 'P') ) + { + rDateTime.SetMonth(9); + return true; + } + if ((pStart[0] == 'o' || pStart[0] == 'O') && + (pStart[1] == 'c' || pStart[1] == 'C') && + (pStart[2] == 't' || pStart[2] == 'T') ) + { + rDateTime.SetMonth(10); + return true; + } + if ((pStart[0] == 'n' || pStart[0] == 'N') && + (pStart[1] == 'o' || pStart[1] == 'O') && + (pStart[2] == 'v' || pStart[2] == 'V') ) + { + rDateTime.SetMonth(11); + return true; + } + if ((pStart[0] == 'd' || pStart[0] == 'D') && + (pStart[1] == 'e' || pStart[1] == 'E') && + (pStart[2] == 'c' || pStart[2] == 'C') ) + { + rDateTime.SetMonth(12); + return true; + } + return false; +} + +/* + * parseUNIX_isDayField. + */ +bool FTPDirectoryParser::parseUNIX_isDayField ( + const char *pStart, + const char *pEnd, + DateTime &rDateTime) +{ + if (!*pStart || !*pEnd || pStart == pEnd) + return false; + if (*pStart < '0' || *pStart > '9') + return false; + + sal_uInt16 nDay = *pStart - '0'; + if (pStart + 1 < pEnd) + { + if (pStart + 2 != pEnd || pStart[1] < '0' || pStart[1] > '9') + return false; + nDay = 10 * nDay + (pStart[1] - '0'); + } + if (!nDay || nDay > 31) + return false; + + rDateTime.SetDay(nDay); + return true; +} + +/* + * parseUNIX_isYearTimeField. + */ +bool FTPDirectoryParser::parseUNIX_isYearTimeField ( + const char *pStart, + const char *pEnd, + DateTime &rDateTime) +{ + if (!*pStart || !*pEnd || pStart == pEnd || + *pStart < '0' || *pStart > '9') + return false; + + sal_uInt16 nNumber = *pStart - '0'; + ++pStart; + + if (pStart == pEnd) + return false; + if (*pStart == ':') + return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime); + if (*pStart < '0' || *pStart > '9') + return false; + + nNumber = 10 * nNumber + (*pStart - '0'); + ++pStart; + + if (pStart == pEnd) + return false; + if (*pStart == ':') + return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime); + if (*pStart < '0' || *pStart > '9') + return false; + + nNumber = 10 * nNumber + (*pStart - '0'); + ++pStart; + + if (pStart == pEnd || *pStart < '0' || *pStart > '9') + return false; + + nNumber = 10 * nNumber + (*pStart - '0'); + if (pStart + 1 != pEnd || nNumber < 1970) + return false; + + rDateTime.SetYear(nNumber); + rDateTime.SetTime(); + return true; +} + +/* + * parseUNIX_isTime. + */ +bool FTPDirectoryParser::parseUNIX_isTime ( + const char *pStart, + const char *pEnd, + sal_uInt16 nHour, + DateTime &rDateTime) +{ + if ((nHour > 23 ) || (pStart + 3 != pEnd) || + (pStart[1] < '0') || (pStart[1] > '5') || + (pStart[2] < '0') || (pStart[2] > '9') ) + return false; + + sal_uInt16 nMin = 10 * (pStart[1] - '0') + (pStart[2] - '0'); + + rDateTime.SetHour (nHour); + rDateTime.SetMin (nMin); + rDateTime.SetSec (0); + rDateTime.SetNanoSec (0); + +// Date aCurDate; +// if (rDateTime.GetMonth() > aCurDate.GetMonth()) +// rDateTime.SetYear(aCurDate.GetYear() - 1); +// else +// rDateTime.SetYear(aCurDate.GetYear()); +// return sal_True; + + TimeValue aTimeVal; + osl_getSystemTime(&aTimeVal); + oslDateTime aCurrDateTime; + osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime); + + if (rDateTime.GetMonth() > aCurrDateTime.Month) + rDateTime.SetYear(aCurrDateTime.Year - 1); + else + rDateTime.SetYear(aCurrDateTime.Year); + return true; +} + +/* + * setYear. + * + * Two-digit years are taken as within 50 years back and 49 years forward + * (both ends inclusive) from the current year. The returned date is not + * checked for validity of the given day in the given month and year. + * + */ +void FTPDirectoryParser::setYear ( + DateTime &rDateTime, sal_uInt16 nYear) +{ + if (nYear < 100) + { + TimeValue aTimeVal; + osl_getSystemTime(&aTimeVal); + oslDateTime aCurrDateTime; + osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime); + sal_uInt16 nCurrentYear = aCurrDateTime.Year; +// sal_uInt16 nCurrentYear = Date().GetYear(); + sal_uInt16 nCurrentCentury = nCurrentYear / 100; + nCurrentYear %= 100; + if (nCurrentYear < 50) + if (nYear <= nCurrentYear) + nYear += nCurrentCentury * 100; + else if (nYear < nCurrentYear + 50) + nYear += nCurrentCentury * 100; + else + nYear += (nCurrentCentury - 1) * 100; + else + if (nYear >= nCurrentYear) + nYear += nCurrentCentury * 100; + else if (nYear >= nCurrentYear - 50) + nYear += nCurrentCentury * 100; + else + nYear += (nCurrentCentury + 1) * 100; + } + + rDateTime.SetYear(nYear); +} + +/* + * setPath. + */ +bool FTPDirectoryParser::setPath ( + OUString &rPath, const char *value, sal_Int32 length) +{ + if (value) + { + if (length < 0) + length = rtl_str_getLength (value); + rPath = OUString (value, length, RTL_TEXTENCODING_UTF8); + } + return (!!value); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |