📄 ftpdirectoryparser.cpp
字号:
/* * Copyright (C) 2002 Cyrus Patel <cyp@fb14.uni-mainz.de> * (C) 2007 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */// This was originally Mozilla code, titled ParseFTPList.cpp// Original version of this file can currently be found at: http://mxr.mozilla.org/mozilla1.8/source/netwerk/streamconv/converters/ParseFTPList.cpp#include "config.h"#if ENABLE(FTPDIR)#include "FTPDirectoryParser.h"#if PLATFORM(QT)#include <QDateTime>// On Windows, use the threadsafe *_r functions provided by pthread.#elif PLATFORM(WIN_OS) && (USE(PTHREADS) || HAVE(PTHREAD_H))#include <pthread.h>#endif#include <wtf/ASCIICType.h>#include <stdio.h>using namespace WTF;namespace WebCore {#if PLATFORM(QT) && defined(Q_WS_WIN32)// Defined in FTPDirectoryDocument.cpp.struct tm gmtimeQt(const QDateTime &input);static struct tm *gmtimeQt(const time_t *const timep, struct tm *result){ const QDateTime dt(QDateTime::fromTime_t(*timep)); *result = WebCore::gmtimeQt(dt); return result;}#define gmtime_r(x, y) gmtimeQt(x, y)#elif PLATFORM(WIN_OS) && !defined(gmtime_r)#define gmtime_r(x, y) gmtime_s((y), (x))#endifFTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& result){ result.clear(); if (!line) return FTPJunkEntry; state.numLines++; /* carry buffer is only valid from one line to the next */ unsigned int carry_buf_len = state.carryBufferLength; state.carryBufferLength = 0; unsigned linelen = 0; /* strip leading whitespace */ while (*line == ' ' || *line == '\t') line++; /* line is terminated at first '\0' or '\n' */ const char* p = line; while (*p && *p != '\n') p++; linelen = p - line; if (linelen > 0 && *p == '\n' && *(p-1) == '\r') linelen--; /* DON'T strip trailing whitespace. */ if (linelen > 0) { static const char *month_names = "JanFebMarAprMayJunJulAugSepOctNovDec"; const char *tokens[16]; /* 16 is more than enough */ unsigned int toklen[(sizeof(tokens)/sizeof(tokens[0]))]; unsigned int linelen_sans_wsp; // line length sans whitespace unsigned int numtoks = 0; unsigned int tokmarker = 0; /* extra info for lstyle handler */ unsigned int month_num = 0; char tbuf[4]; int lstyle = 0; if (carry_buf_len) /* VMS long filename carryover buffer */ { tokens[0] = state.carryBuffer; toklen[0] = carry_buf_len; numtoks++; } unsigned int pos = 0; while (pos < linelen && numtoks < (sizeof(tokens)/sizeof(tokens[0])) ) { while (pos < linelen && (line[pos] == ' ' || line[pos] == '\t' || line[pos] == '\r')) pos++; if (pos < linelen) { tokens[numtoks] = &line[pos]; while (pos < linelen && (line[pos] != ' ' && line[pos] != '\t' && line[pos] != '\r')) pos++; if (tokens[numtoks] != &line[pos]) { toklen[numtoks] = (&line[pos] - tokens[numtoks]); numtoks++; } } } linelen_sans_wsp = &(tokens[numtoks-1][toklen[numtoks-1]]) - tokens[0]; if (numtoks == (sizeof(tokens)/sizeof(tokens[0])) ) { pos = linelen; while (pos > 0 && (line[pos-1] == ' ' || line[pos-1] == '\t')) pos--; linelen_sans_wsp = pos; } /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */#if defined(SUPPORT_EPLF) /* EPLF handling must come somewhere before /bin/dls handling. */ if (!lstyle && (!state.listStyle || state.listStyle == 'E')) { if (*line == '+' && linelen > 4 && numtoks >= 2) { pos = 1; while (pos < (linelen-1)) { p = &line[pos++]; if (*p == '/') result.type = FTPDirectoryEntry; /* its a dir */ else if (*p == 'r') result.type = FTPFileEntry; /* its a file */ else if (*p == 'm') { if (isASCIIDigit(line[pos])) { while (pos < linelen && isASCIIDigit(line[pos])) pos++; if (pos < linelen && line[pos] == ',') { unsigned long long seconds = 0; sscanf(p + 1, "%llu", &seconds); time_t t = static_cast<time_t>(seconds); // FIXME: This code has the year 2038 bug gmtime_r(&t, &result.modifiedTime); result.modifiedTime.tm_year += 1900; } } } else if (*p == 's') { if (isASCIIDigit(line[pos])) { while (pos < linelen && isASCIIDigit(line[pos])) pos++; if (pos < linelen && line[pos] == ',') result.fileSize = String(p + 1, &line[pos] - p + 1); } } else if (isASCIIAlpha(*p)) /* 'i'/'up' or unknown "fact" (property) */ { while (pos < linelen && *++p != ',') pos++; } else if (*p != '\t' || (p+1) != tokens[1]) { break; /* its not EPLF after all */ } else { state.parsedOne = true; state.listStyle = lstyle = 'E'; p = &(line[linelen_sans_wsp]); result.filename = tokens[1]; result.filenameLength = p - tokens[1]; if (!result.type) /* access denied */ { result.type = FTPFileEntry; /* is assuming 'f'ile correct? */ return FTPJunkEntry; /* NO! junk it. */ } return result.type; } if (pos >= (linelen-1) || line[pos] != ',') break; pos++; } /* while (pos < linelen) */ result.clear(); } /* if (*line == '+' && linelen > 4 && numtoks >= 2) */ } /* if (!lstyle && (!state.listStyle || state.listStyle == 'E')) */#endif /* SUPPORT_EPLF */ /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */#if defined(SUPPORT_VMS) if (!lstyle && (!state.listStyle || state.listStyle == 'V')) { /* try VMS Multinet/UCX/CMS server */ /* * Legal characters in a VMS file/dir spec are [A-Z0-9$.-_~]. * '$' cannot begin a filename and `-' cannot be used as the first * or last character. '.' is only valid as a directory separator * and <file>.<type> separator. A canonical filename spec might look * like this: DISK$VOL:[DIR1.DIR2.DIR3]FILE.TYPE;123 * All VMS FTP servers LIST in uppercase. * * We need to be picky about this in order to support * multi-line listings correctly. */ if (!state.parsedOne && (numtoks == 1 || (numtoks == 2 && toklen[0] == 9 && memcmp(tokens[0], "Directory", 9)==0 ))) { /* If no dirstyle has been detected yet, and this line is a * VMS list's dirname, then turn on VMS dirstyle. * eg "ACA:[ANONYMOUS]", "DISK$FTP:[ANONYMOUS]", "SYS$ANONFTP:" */ p = tokens[0]; pos = toklen[0]; if (numtoks == 2) { p = tokens[1]; pos = toklen[1]; } pos--; if (pos >= 3) { while (pos > 0 && p[pos] != '[') { pos--; if (p[pos] == '-' || p[pos] == '$') { if (pos == 0 || p[pos-1] == '[' || p[pos-1] == '.' || (p[pos] == '-' && (p[pos+1] == ']' || p[pos+1] == '.'))) break; } else if (p[pos] != '.' && p[pos] != '~' && !isASCIIDigit(p[pos]) && !isASCIIAlpha(p[pos])) break; else if (isASCIIAlpha(p[pos]) && p[pos] != toASCIIUpper(p[pos])) break; } if (pos > 0) { pos--; if (p[pos] != ':' || p[pos+1] != '[') pos = 0; } } if (pos > 0 && p[pos] == ':') { while (pos > 0) { pos--; if (p[pos] != '$' && p[pos] != '_' && p[pos] != '-' && p[pos] != '~' && !isASCIIDigit(p[pos]) && !isASCIIAlpha(p[pos])) break; else if (isASCIIAlpha(p[pos]) && p[pos] != toASCIIUpper(p[pos])) break; } if (pos == 0) { state.listStyle = 'V'; return FTPJunkEntry; /* its junk */ } } /* fallthrough */ } else if ((tokens[0][toklen[0]-1]) != ';') { if (numtoks == 1 && (state.listStyle == 'V' && !carry_buf_len)) lstyle = 'V'; else if (numtoks < 4) ; else if (toklen[1] >= 10 && memcmp(tokens[1], "%RMS-E-PRV", 10) == 0) lstyle = 'V'; else if ((&line[linelen] - tokens[1]) >= 22 && memcmp(tokens[1], "insufficient privilege", 22) == 0) lstyle = 'V'; else if (numtoks != 4 && numtoks != 6) ; else if (numtoks == 6 && ( toklen[5] < 4 || *tokens[5] != '(' || /* perms */ (tokens[5][toklen[5]-1]) != ')' )) ; else if ( (toklen[2] == 10 || toklen[2] == 11) && (tokens[2][toklen[2]-5]) == '-' && (tokens[2][toklen[2]-9]) == '-' && (((toklen[3]==4 || toklen[3]==5 || toklen[3]==7 || toklen[3]==8) && (tokens[3][toklen[3]-3]) == ':' ) || ((toklen[3]==10 || toklen[3]==11 ) && (tokens[3][toklen[3]-3]) == '.' ) ) && /* time in [H]H:MM[:SS[.CC]] format */ isASCIIDigit(*tokens[1]) && /* size */ isASCIIDigit(*tokens[2]) && /* date */ isASCIIDigit(*tokens[3]) /* time */ ) { lstyle = 'V'; } if (lstyle == 'V') { /* * MultiNet FTP: * LOGIN.COM;2 1 4-NOV-1994 04:09 [ANONYMOUS] (RWE,RWE,,) * PUB.DIR;1 1 27-JAN-1994 14:46 [ANONYMOUS] (RWE,RWE,RE,RWE) * README.FTP;1 %RMS-E-PRV, insufficient privilege or file protection violation * ROUSSOS.DIR;1 1 27-JAN-1994 14:48 [CS,ROUSSOS] (RWE,RWE,RE,R) * S67-50903.JPG;1 328 22-SEP-1998 16:19 [ANONYMOUS] (RWED,RWED,,) * UCX FTP: * CII-MANUAL.TEX;1 213/216 29-JAN-1996 03:33:12 [ANONYMOU,ANONYMOUS] (RWED,RWED,,) * CMU/VMS-IP FTP * [VMSSERV.FILES]ALARM.DIR;1 1/3 5-MAR-1993 18:09 * TCPware FTP * FOO.BAR;1 4 5-MAR-1993 18:09:01.12 * Long filename example: * THIS-IS-A-LONG-VMS-FILENAME.AND-THIS-IS-A-LONG-VMS-FILETYPE\r\n * 213[/nnn] 29-JAN-1996 03:33[:nn] [ANONYMOU,ANONYMOUS] (RWED,RWED,,) */ tokmarker = 0; p = tokens[0]; pos = 0; if (*p == '[' && toklen[0] >= 4) /* CMU style */ { if (p[1] != ']') { p++; pos++; } while (lstyle && pos < toklen[0] && *p != ']') { if (*p != '$' && *p != '.' && *p != '_' && *p != '-' && *p != '~' && !isASCIIDigit(*p) && !isASCIIAlpha(*p)) lstyle = 0; pos++; p++; } if (lstyle && pos < (toklen[0]-1) && *p == ']') { pos++; p++; tokmarker = pos; /* length of leading "[DIR1.DIR2.etc]" */ } } while (lstyle && pos < toklen[0] && *p != ';') { if (*p != '$' && *p != '.' && *p != '_' && *p != '-' && *p != '~' && !isASCIIDigit(*p) && !isASCIIAlpha(*p)) lstyle = 0; else if (isASCIIAlpha(*p) && *p != toASCIIUpper(*p)) lstyle = 0; p++; pos++; } if (lstyle && *p == ';') { if (pos == 0 || pos == (toklen[0]-1)) lstyle = 0; for (pos++;lstyle && pos < toklen[0];pos++) { if (!isASCIIDigit(tokens[0][pos])) lstyle = 0; } } pos = (p - tokens[0]); /* => fnlength sans ";####" */ pos -= tokmarker; /* => fnlength sans "[DIR1.DIR2.etc]" */ p = &(tokens[0][tokmarker]); /* offset of basename */ if (!lstyle || pos > 80) /* VMS filenames can't be longer than that */ { lstyle = 0; } else if (numtoks == 1) { /* if VMS has been detected and there is only one token and that * token was a VMS filename then this is a multiline VMS LIST entry. */ if (pos >= (sizeof(state.carryBuffer)-1)) pos = (sizeof(state.carryBuffer)-1); /* shouldn't happen */ memcpy( state.carryBuffer, p, pos ); state.carryBufferLength = pos; return FTPJunkEntry; /* tell caller to treat as junk */ } else if (isASCIIDigit(*tokens[1])) /* not no-privs message */ { for (pos = 0; lstyle && pos < (toklen[1]); pos++) { if (!isASCIIDigit((tokens[1][pos])) && (tokens[1][pos]) != '/') lstyle = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -