~ubuntu-branches/ubuntu/saucy/filezilla/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/02_fix-ftbfs.patch/src/engine/directorylistingparser.cpp

  • Committer: Package Import Robot
  • Author(s): Adrien Cunin
  • Date: 2012-12-07 17:17:17 UTC
  • mfrom: (1.1.31)
  • Revision ID: package-import@ubuntu.com-20121207171717-nt6as62u4pa1uv11
Tags: 3.6.0.2-1ubuntu1
* Merge from Debian experimental. Remaining Ubuntu change:
   - Added debian/patches/11_use-decimal-si-by-default.patch in order to
     comply with UnitsPolicy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <filezilla.h>
2
 
#include "directorylistingparser.h"
3
 
#include "ControlSocket.h"
4
 
 
5
 
#ifdef _DEBUG
6
 
#define new DEBUG_NEW
7
 
#endif
8
 
 
9
 
std::map<wxString, int> CDirectoryListingParser::m_MonthNamesMap;
10
 
 
11
 
//#define LISTDEBUG_MVS
12
 
//#define LISTDEBUG
13
 
#ifdef LISTDEBUG
14
 
static char data[][150]={
15
 
        "" // Has to be terminated with empty string
16
 
};
17
 
 
18
 
#endif
19
 
 
20
 
class CToken
21
 
{
22
 
protected:
23
 
        enum TokenInformation
24
 
        {
25
 
                Unknown,
26
 
                Yes,
27
 
                No
28
 
        };
29
 
 
30
 
public:
31
 
        CToken()
32
 
                : m_pToken()
33
 
                , m_len()
34
 
                , m_numeric(Unknown)
35
 
                , m_leftNumeric(Unknown)
36
 
                , m_rightNumeric(Unknown)
37
 
                , m_number(-1)
38
 
        {
39
 
        }
40
 
 
41
 
        enum t_numberBase
42
 
        {
43
 
                decimal,
44
 
                hex
45
 
        };
46
 
 
47
 
        CToken(const wxChar* p, unsigned int len)
48
 
                : m_pToken(p)
49
 
                , m_len(len)
50
 
                , m_numeric(Unknown)
51
 
                , m_leftNumeric(Unknown)
52
 
                , m_rightNumeric(Unknown)
53
 
                , m_number(-1)
54
 
        {}
55
 
 
56
 
        const wxChar* GetToken() const
57
 
        {
58
 
                return m_pToken;
59
 
        }
60
 
 
61
 
        unsigned int GetLength() const
62
 
        {
63
 
                return m_len;
64
 
        }
65
 
 
66
 
        wxString GetString(unsigned int type = 0)
67
 
        {
68
 
                if (!m_pToken)
69
 
                        return _T("");
70
 
 
71
 
                if (type > 2)
72
 
                        return _T("");
73
 
 
74
 
                if (!m_str[type].IsEmpty())
75
 
                        return m_str[type];
76
 
 
77
 
                if (!type)
78
 
                {
79
 
                        wxString str(m_pToken, m_len);
80
 
                        m_str[type] = str;
81
 
                        return str;
82
 
                }
83
 
                else if (type == 1)
84
 
                {
85
 
                        if (!IsRightNumeric() || IsNumeric())
86
 
                                return _T("");
87
 
 
88
 
                        int pos = m_len - 1;
89
 
                        while (m_pToken[pos] >= '0' && m_pToken[pos] <= '9')
90
 
                                --pos;
91
 
 
92
 
                        wxString str(m_pToken, pos + 1);
93
 
                        m_str[type] = str;
94
 
                        return str;
95
 
                }
96
 
                else if (type == 2)
97
 
                {
98
 
                        if (!IsLeftNumeric() || IsNumeric())
99
 
                                return _T("");
100
 
 
101
 
                        int pos = 0;
102
 
                        while (m_pToken[pos] >= '0' && m_pToken[pos] <= '9')
103
 
                                ++pos;
104
 
 
105
 
                        wxString str(m_pToken + pos, m_len - pos);
106
 
                        m_str[type] = str;
107
 
                        return str;
108
 
                }
109
 
 
110
 
                return _T("");
111
 
        }
112
 
 
113
 
        bool IsNumeric(t_numberBase base = decimal)
114
 
        {
115
 
                switch (base)
116
 
                {
117
 
                case decimal:
118
 
                default:
119
 
                        if (m_numeric == Unknown)
120
 
                        {
121
 
                                m_numeric = Yes;
122
 
                                for (unsigned int i = 0; i < m_len; ++i)
123
 
                                        if (m_pToken[i] < '0' || m_pToken[i] > '9')
124
 
                                        {
125
 
                                                m_numeric = No;
126
 
                                                break;
127
 
                                        }
128
 
                        }
129
 
                        return m_numeric == Yes;
130
 
                case hex:
131
 
                        for (unsigned int i = 0; i < m_len; ++i)
132
 
                        {
133
 
                                const char c = m_pToken[i];
134
 
                                if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f'))
135
 
                                        return false;
136
 
                        }
137
 
                        return true;
138
 
                }
139
 
        }
140
 
 
141
 
        bool IsNumeric(unsigned int start, unsigned int len)
142
 
        {
143
 
                for (unsigned int i = start; i < wxMin(start + len, m_len); ++i)
144
 
                        if (m_pToken[i] < '0' || m_pToken[i] > '9')
145
 
                                return false;
146
 
                return true;
147
 
        }
148
 
 
149
 
        bool IsLeftNumeric()
150
 
        {
151
 
                if (m_leftNumeric == Unknown)
152
 
                {
153
 
                        if (m_len < 2)
154
 
                                m_leftNumeric = No;
155
 
                        else if (m_pToken[0] < '0' || m_pToken[0] > '9')
156
 
                                m_leftNumeric = No;
157
 
                        else
158
 
                                m_leftNumeric = Yes;
159
 
                }
160
 
                return m_leftNumeric == Yes;
161
 
        }
162
 
 
163
 
        bool IsRightNumeric()
164
 
        {
165
 
                if (m_rightNumeric == Unknown)
166
 
                {
167
 
                        if (m_len < 2)
168
 
                                m_rightNumeric = No;
169
 
                        else if (m_pToken[m_len - 1] < '0' || m_pToken[m_len - 1] > '9')
170
 
                                m_rightNumeric = No;
171
 
                        else
172
 
                                m_rightNumeric = Yes;
173
 
                }
174
 
                return m_rightNumeric == Yes;
175
 
        }
176
 
 
177
 
        int Find(const wxChar* chr, int start = 0) const
178
 
        {
179
 
                if (!chr)
180
 
                        return -1;
181
 
 
182
 
                for (unsigned int i = start; i < m_len; ++i)
183
 
                {
184
 
                        for (int c = 0; chr[c]; ++c)
185
 
                        {
186
 
                                if (m_pToken[i] == chr[c])
187
 
                                        return i;
188
 
                        }
189
 
                }
190
 
                return -1;
191
 
        }
192
 
 
193
 
        int Find(wxChar chr, int start = 0) const
194
 
        {
195
 
                if (!m_pToken)
196
 
                        return -1;
197
 
 
198
 
                for (unsigned int i = start; i < m_len; ++i)
199
 
                        if (m_pToken[i] == chr)
200
 
                                return i;
201
 
 
202
 
                return -1;
203
 
        }
204
 
 
205
 
        wxLongLong GetNumber(unsigned int start, int len)
206
 
        {
207
 
                if (len == -1)
208
 
                        len = m_len - start;
209
 
                if (len < 1)
210
 
                        return -1;
211
 
 
212
 
                if (start + static_cast<unsigned int>(len) > m_len)
213
 
                        return -1;
214
 
 
215
 
                if (m_pToken[start] < '0' || m_pToken[start] > '9')
216
 
                        return -1;
217
 
 
218
 
                wxLongLong number = 0;
219
 
                for (unsigned int i = start; i < (start + len); ++i)
220
 
                {
221
 
                        if (m_pToken[i] < '0' || m_pToken[i] > '9')
222
 
                                break;
223
 
                        number *= 10;
224
 
                        number += m_pToken[i] - '0';
225
 
                }
226
 
                return number;
227
 
        }
228
 
 
229
 
        wxLongLong GetNumber(t_numberBase base = decimal)
230
 
        {
231
 
                switch (base)
232
 
                {
233
 
                default:
234
 
                case decimal:
235
 
                        if (m_number == -1)
236
 
                        {
237
 
                                if (IsNumeric() || IsLeftNumeric())
238
 
                                {
239
 
                                        m_number = 0;
240
 
                                        for (unsigned int i = 0; i < m_len; ++i)
241
 
                                        {
242
 
                                                if (m_pToken[i] < '0' || m_pToken[i] > '9')
243
 
                                                        break;
244
 
                                                m_number *= 10;
245
 
                                                m_number += m_pToken[i] - '0';
246
 
                                        }
247
 
                                }
248
 
                                else if (IsRightNumeric())
249
 
                                {
250
 
                                        m_number = 0;
251
 
                                        int start = m_len - 1;
252
 
                                        while (m_pToken[start - 1] >= '0' && m_pToken[start - 1] <= '9')
253
 
                                                --start;
254
 
                                        for (unsigned int i = start; i < m_len; ++i)
255
 
                                        {
256
 
                                                m_number *= 10;
257
 
                                                m_number += m_pToken[i] - '0';
258
 
                                        }
259
 
                                }
260
 
                        }
261
 
                        return m_number;
262
 
                case hex:
263
 
                        {
264
 
                                wxLongLong number = 0;
265
 
                                for (unsigned int i = 0; i < m_len; ++i)
266
 
                                {
267
 
                                        const wxChar& c = m_pToken[i];
268
 
                                        if (c >= '0' && c <= '9')
269
 
                                        {
270
 
                                                number *= 16;
271
 
                                                number += c - '0';
272
 
                                        }
273
 
                                        else if (c >= 'a' && c <= 'f')
274
 
                                        {
275
 
                                                number *= 16;
276
 
                                                number += c - '0' + 10;
277
 
                                        }
278
 
                                        else if (c >= 'A' && c <= 'F')
279
 
                                        {
280
 
                                                number *= 16;
281
 
                                                number += c - 'A' + 10;
282
 
                                        }
283
 
                                        else
284
 
                                                return -1;
285
 
                                }
286
 
                                return number;
287
 
                        }
288
 
                }
289
 
        }
290
 
 
291
 
        wxChar operator[](unsigned int n) const
292
 
        {
293
 
                if (n >= m_len)
294
 
                        return 0;
295
 
 
296
 
                return m_pToken[n];
297
 
        }
298
 
 
299
 
protected:
300
 
        const wxChar* m_pToken;
301
 
        unsigned int m_len;
302
 
 
303
 
        TokenInformation m_numeric;
304
 
        TokenInformation m_leftNumeric;
305
 
        TokenInformation m_rightNumeric;
306
 
        wxLongLong m_number;
307
 
        wxString m_str[3];
308
 
};
309
 
 
310
 
class CLine
311
 
{
312
 
public:
313
 
        CLine(wxChar* p, int len = -1, int trailing_whitespace = 0)
314
 
        {
315
 
                m_pLine = p;
316
 
                if (len != -1)
317
 
                        m_len = len;
318
 
                else
319
 
                        m_len = wxStrlen(p);
320
 
 
321
 
                m_parsePos = 0;
322
 
 
323
 
                m_Tokens.reserve(10);
324
 
                m_LineEndTokens.reserve(10);
325
 
                m_trailing_whitespace = trailing_whitespace;
326
 
        }
327
 
 
328
 
        ~CLine()
329
 
        {
330
 
                delete [] m_pLine;
331
 
 
332
 
                std::vector<CToken *>::iterator iter;
333
 
                for (iter = m_Tokens.begin(); iter != m_Tokens.end(); ++iter)
334
 
                        delete *iter;
335
 
                for (iter = m_LineEndTokens.begin(); iter != m_LineEndTokens.end(); ++iter)
336
 
                        delete *iter;
337
 
        }
338
 
 
339
 
        bool GetToken(unsigned int n, CToken &token, bool toEnd = false, bool include_whitespace = false)
340
 
        {
341
 
                if (!toEnd)
342
 
                {
343
 
                        if (m_Tokens.size() > n)
344
 
                        {
345
 
                                token = *(m_Tokens[n]);
346
 
                                return true;
347
 
                        }
348
 
 
349
 
                        int start = m_parsePos;
350
 
                        while (m_parsePos < m_len)
351
 
                        {
352
 
                                if (m_pLine[m_parsePos] == ' ' || m_pLine[m_parsePos] == '\t')
353
 
                                {
354
 
                                        CToken *pToken = new CToken(m_pLine + start, m_parsePos - start);
355
 
                                        m_Tokens.push_back(pToken);
356
 
 
357
 
                                        while ((m_pLine[m_parsePos] == ' ' || m_pLine[m_parsePos] == '\t') && m_parsePos < m_len)
358
 
                                                ++m_parsePos;
359
 
 
360
 
                                        if (m_Tokens.size() > n)
361
 
                                        {
362
 
                                                token = *(m_Tokens[n]);
363
 
                                                return true;
364
 
                                        }
365
 
 
366
 
                                        start = m_parsePos;
367
 
                                }
368
 
                                ++m_parsePos;
369
 
                        }
370
 
                        if (m_parsePos != start)
371
 
                        {
372
 
                                CToken *pToken = new CToken(m_pLine + start, m_parsePos - start);
373
 
                                        m_Tokens.push_back(pToken);
374
 
                        }
375
 
 
376
 
                        if (m_Tokens.size() > n)
377
 
                        {
378
 
                                token = *(m_Tokens[n]);
379
 
                                return true;
380
 
                        }
381
 
 
382
 
                        return false;
383
 
                }
384
 
                else
385
 
                {
386
 
                        if (include_whitespace)
387
 
                        {
388
 
                                const wxChar* p;
389
 
                                if (!n)
390
 
                                {
391
 
                                        CToken ref;
392
 
                                        if (!GetToken(n, ref))
393
 
                                                return false;
394
 
                                        p = ref.GetToken() + ref.GetLength() + 1;
395
 
                                }
396
 
                                else
397
 
                                {
398
 
                                        CToken ref;
399
 
                                        if (!GetToken(n - 1, ref))
400
 
                                                return false;
401
 
                                        p = ref.GetToken() + ref.GetLength() + 1;
402
 
                                }
403
 
 
404
 
                                token = CToken(p, m_len - (p - m_pLine));
405
 
                                return true;
406
 
                        }
407
 
 
408
 
                        if (m_LineEndTokens.size() > n)
409
 
                        {
410
 
                                token = *(m_LineEndTokens[n]);
411
 
                                return true;
412
 
                        }
413
 
 
414
 
                        if (m_Tokens.size() <= n)
415
 
                                if (!GetToken(n, token))
416
 
                                        return false;
417
 
 
418
 
                        for (unsigned int i = static_cast<unsigned int>(m_LineEndTokens.size()); i <= n; ++i)
419
 
                        {
420
 
                                const CToken *refToken = m_Tokens[i];
421
 
                                const wxChar* p = refToken->GetToken();
422
 
                                CToken *pToken = new CToken(p, m_len - (p - m_pLine) - m_trailing_whitespace);
423
 
                                m_LineEndTokens.push_back(pToken);
424
 
                        }
425
 
                        token = *(m_LineEndTokens[n]);
426
 
                        return true;
427
 
                }
428
 
        };
429
 
 
430
 
        CLine *Concat(const CLine *pLine) const
431
 
        {
432
 
                int newLen = m_len + pLine->m_len + 1;
433
 
                wxChar* p = new wxChar[newLen];
434
 
                memcpy(p, m_pLine, m_len * sizeof(wxChar));
435
 
                p[m_len] = ' ';
436
 
                memcpy(p + m_len + 1, pLine->m_pLine, pLine->m_len * sizeof(wxChar));
437
 
 
438
 
                return new CLine(p, m_len + pLine->m_len + 1, pLine->m_trailing_whitespace);
439
 
        }
440
 
 
441
 
protected:
442
 
        std::vector<CToken *> m_Tokens;
443
 
        std::vector<CToken *> m_LineEndTokens;
444
 
        int m_parsePos;
445
 
        int m_len;
446
 
        int m_trailing_whitespace;
447
 
        wxChar* m_pLine;
448
 
};
449
 
 
450
 
CDirectoryListingParser::CDirectoryListingParser(CControlSocket* pControlSocket, const CServer& server)
451
 
        : m_pControlSocket(pControlSocket), m_server(server)
452
 
{
453
 
        m_currentOffset = 0;
454
 
        m_prevLine = 0;
455
 
        m_fileListOnly = true;
456
 
        m_maybeMultilineVms = false;
457
 
 
458
 
        if (m_MonthNamesMap.empty())
459
 
        {
460
 
                //Fill the month names map
461
 
 
462
 
                //English month names
463
 
                m_MonthNamesMap[_T("jan")] = 1;
464
 
                m_MonthNamesMap[_T("feb")] = 2;
465
 
                m_MonthNamesMap[_T("mar")] = 3;
466
 
                m_MonthNamesMap[_T("apr")] = 4;
467
 
                m_MonthNamesMap[_T("may")] = 5;
468
 
                m_MonthNamesMap[_T("jun")] = 6;
469
 
                m_MonthNamesMap[_T("june")] = 6;
470
 
                m_MonthNamesMap[_T("jul")] = 7;
471
 
                m_MonthNamesMap[_T("july")] = 7;
472
 
                m_MonthNamesMap[_T("aug")] = 8;
473
 
                m_MonthNamesMap[_T("sep")] = 9;
474
 
                m_MonthNamesMap[_T("sept")] = 9;
475
 
                m_MonthNamesMap[_T("oct")] = 10;
476
 
                m_MonthNamesMap[_T("nov")] = 11;
477
 
                m_MonthNamesMap[_T("dec")] = 12;
478
 
 
479
 
                //Numerical values for the month
480
 
                m_MonthNamesMap[_T("1")] = 1;
481
 
                m_MonthNamesMap[_T("01")] = 1;
482
 
                m_MonthNamesMap[_T("2")] = 2;
483
 
                m_MonthNamesMap[_T("02")] = 2;
484
 
                m_MonthNamesMap[_T("3")] = 3;
485
 
                m_MonthNamesMap[_T("03")] = 3;
486
 
                m_MonthNamesMap[_T("4")] = 4;
487
 
                m_MonthNamesMap[_T("04")] = 4;
488
 
                m_MonthNamesMap[_T("5")] = 5;
489
 
                m_MonthNamesMap[_T("05")] = 5;
490
 
                m_MonthNamesMap[_T("6")] = 6;
491
 
                m_MonthNamesMap[_T("06")] = 6;
492
 
                m_MonthNamesMap[_T("7")] = 7;
493
 
                m_MonthNamesMap[_T("07")] = 7;
494
 
                m_MonthNamesMap[_T("8")] = 8;
495
 
                m_MonthNamesMap[_T("08")] = 8;
496
 
                m_MonthNamesMap[_T("9")] = 9;
497
 
                m_MonthNamesMap[_T("09")] = 9;
498
 
                m_MonthNamesMap[_T("10")] = 10;
499
 
                m_MonthNamesMap[_T("11")] = 11;
500
 
                m_MonthNamesMap[_T("12")] = 12;
501
 
 
502
 
                //German month names
503
 
                m_MonthNamesMap[_T("mrz")] = 3;
504
 
                m_MonthNamesMap[_T("m\xe4r")] = 3;
505
 
                m_MonthNamesMap[_T("m\xe4rz")] = 3;
506
 
                m_MonthNamesMap[_T("mai")] = 5;
507
 
                m_MonthNamesMap[_T("juni")] = 6;
508
 
                m_MonthNamesMap[_T("juli")] = 7;
509
 
                m_MonthNamesMap[_T("okt")] = 10;
510
 
                m_MonthNamesMap[_T("dez")] = 12;
511
 
 
512
 
                //Austrian month names
513
 
                m_MonthNamesMap[_T("j\xe4n")] = 1;
514
 
 
515
 
                //French month names
516
 
                m_MonthNamesMap[_T("janv")] = 1;
517
 
                m_MonthNamesMap[_T("f\xe9")_T("b")] = 1;
518
 
                m_MonthNamesMap[_T("f\xe9v")] = 2;
519
 
                m_MonthNamesMap[_T("fev")] = 2;
520
 
                m_MonthNamesMap[_T("f\xe9vr")] = 2;
521
 
                m_MonthNamesMap[_T("fevr")] = 2;
522
 
                m_MonthNamesMap[_T("mars")] = 3;
523
 
                m_MonthNamesMap[_T("mrs")] = 3;
524
 
                m_MonthNamesMap[_T("avr")] = 4;
525
 
                m_MonthNamesMap[_T("juin")] = 6;
526
 
                m_MonthNamesMap[_T("juil")] = 7;
527
 
                m_MonthNamesMap[_T("jui")] = 7;
528
 
                m_MonthNamesMap[_T("ao\xfb")] = 8;
529
 
                m_MonthNamesMap[_T("ao\xfbt")] = 8;
530
 
                m_MonthNamesMap[_T("aout")] = 8;
531
 
                m_MonthNamesMap[_T("d\xe9")_T("c")] = 12;
532
 
                m_MonthNamesMap[_T("dec")] = 12;
533
 
 
534
 
                //Italian month names
535
 
                m_MonthNamesMap[_T("gen")] = 1;
536
 
                m_MonthNamesMap[_T("mag")] = 5;
537
 
                m_MonthNamesMap[_T("giu")] = 6;
538
 
                m_MonthNamesMap[_T("lug")] = 7;
539
 
                m_MonthNamesMap[_T("ago")] = 8;
540
 
                m_MonthNamesMap[_T("set")] = 9;
541
 
                m_MonthNamesMap[_T("ott")] = 10;
542
 
                m_MonthNamesMap[_T("dic")] = 12;
543
 
 
544
 
                //Spanish month names
545
 
                m_MonthNamesMap[_T("ene")] = 1;
546
 
                m_MonthNamesMap[_T("fbro")] = 2;
547
 
                m_MonthNamesMap[_T("mzo")] = 3;
548
 
                m_MonthNamesMap[_T("ab")] = 4;
549
 
                m_MonthNamesMap[_T("abr")] = 4;
550
 
                m_MonthNamesMap[_T("agto")] = 8;
551
 
                m_MonthNamesMap[_T("sbre")] = 9;
552
 
                m_MonthNamesMap[_T("obre")] = 9;
553
 
                m_MonthNamesMap[_T("nbre")] = 9;
554
 
                m_MonthNamesMap[_T("dbre")] = 9;
555
 
 
556
 
                //Polish month names
557
 
                m_MonthNamesMap[_T("sty")] = 1;
558
 
                m_MonthNamesMap[_T("lut")] = 2;
559
 
                m_MonthNamesMap[_T("kwi")] = 4;
560
 
                m_MonthNamesMap[_T("maj")] = 5;
561
 
                m_MonthNamesMap[_T("cze")] = 6;
562
 
                m_MonthNamesMap[_T("lip")] = 7;
563
 
                m_MonthNamesMap[_T("sie")] = 8;
564
 
                m_MonthNamesMap[_T("wrz")] = 9;
565
 
                m_MonthNamesMap[_T("pa\x9f")] = 10;
566
 
                m_MonthNamesMap[_T("lis")] = 11;
567
 
                m_MonthNamesMap[_T("gru")] = 12;
568
 
 
569
 
                //Russian month names
570
 
                m_MonthNamesMap[_T("\xff\xed\xe2")] = 1;
571
 
                m_MonthNamesMap[_T("\xf4\xe5\xe2")] = 2;
572
 
                m_MonthNamesMap[_T("\xec\xe0\xf0")] = 3;
573
 
                m_MonthNamesMap[_T("\xe0\xef\xf0")] = 4;
574
 
                m_MonthNamesMap[_T("\xec\xe0\xe9")] = 5;
575
 
                m_MonthNamesMap[_T("\xe8\xfe\xed")] = 6;
576
 
                m_MonthNamesMap[_T("\xe8\xfe\xeb")] = 7;
577
 
                m_MonthNamesMap[_T("\xe0\xe2\xe3")] = 8;
578
 
                m_MonthNamesMap[_T("\xf1\xe5\xed")] = 9;
579
 
                m_MonthNamesMap[_T("\xee\xea\xf2")] = 10;
580
 
                m_MonthNamesMap[_T("\xed\xee\xff")] = 11;
581
 
                m_MonthNamesMap[_T("\xe4\xe5\xea")] = 12;
582
 
 
583
 
                //Dutch month names
584
 
                m_MonthNamesMap[_T("mrt")] = 3;
585
 
                m_MonthNamesMap[_T("mei")] = 5;
586
 
 
587
 
                //Portuguese month names
588
 
                m_MonthNamesMap[_T("out")] = 10;
589
 
 
590
 
                //Finnish month names
591
 
                m_MonthNamesMap[_T("tammi")] = 1;
592
 
                m_MonthNamesMap[_T("helmi")] = 2;
593
 
                m_MonthNamesMap[_T("maalis")] = 3;
594
 
                m_MonthNamesMap[_T("huhti")] = 4;
595
 
                m_MonthNamesMap[_T("touko")] = 5;
596
 
                m_MonthNamesMap[_T("kes\xe4")] = 6;
597
 
                m_MonthNamesMap[_T("hein\xe4")] = 7;
598
 
                m_MonthNamesMap[_T("elo")] = 8;
599
 
                m_MonthNamesMap[_T("syys")] = 9;
600
 
                m_MonthNamesMap[_T("loka")] = 10;
601
 
                m_MonthNamesMap[_T("marras")] = 11;
602
 
                m_MonthNamesMap[_T("joulu")] = 12;
603
 
 
604
 
                //Slovenian month names
605
 
                m_MonthNamesMap[_T("avg")] = 8;
606
 
 
607
 
                //Icelandic
608
 
#if wxUSE_UNICODE
609
 
                m_MonthNamesMap[_T("ma\x00ed")] = 5;
610
 
                m_MonthNamesMap[_T("j\x00fan")] = 6;
611
 
                m_MonthNamesMap[_T("j\x00fal")] = 7;
612
 
                m_MonthNamesMap[_T("\x00e1g")] = 8;
613
 
                m_MonthNamesMap[_T("n\x00f3v")] = 11;
614
 
#endif
615
 
                m_MonthNamesMap[_T("des")] = 12;
616
 
 
617
 
                //Lithuanian
618
 
                m_MonthNamesMap[_T("sau")] = 1;
619
 
                m_MonthNamesMap[_T("vas")] = 2;
620
 
                m_MonthNamesMap[_T("kov")] = 3;
621
 
                m_MonthNamesMap[_T("bal")] = 4;
622
 
                m_MonthNamesMap[_T("geg")] = 5;
623
 
                m_MonthNamesMap[_T("bir")] = 6;
624
 
                m_MonthNamesMap[_T("lie")] = 7;
625
 
                m_MonthNamesMap[_T("rgp")] = 8;
626
 
                m_MonthNamesMap[_T("rgs")] = 9;
627
 
                m_MonthNamesMap[_T("spa")] = 10;
628
 
                m_MonthNamesMap[_T("lap")] = 11;
629
 
                m_MonthNamesMap[_T("grd")] = 12;
630
 
 
631
 
                //There are more languages and thus month
632
 
                //names, but as long as nobody reports a
633
 
                //problem, I won't add them, there are way
634
 
                //too many languages
635
 
 
636
 
                // Some servers send a combination of month name and number,
637
 
                // Add corresponding numbers to the month names.
638
 
                std::map<wxString, int> combo;
639
 
                for (std::map<wxString, int>::iterator iter = m_MonthNamesMap.begin(); iter != m_MonthNamesMap.end(); ++iter)
640
 
                {
641
 
                        // January could be 1 or 0, depends how the server counts
642
 
                        combo[wxString::Format(_T("%s%02d"), iter->first.c_str(), iter->second)] = iter->second;
643
 
                        combo[wxString::Format(_T("%s%02d"), iter->first.c_str(), iter->second - 1)] = iter->second;
644
 
                        if (iter->second < 10)
645
 
                                combo[wxString::Format(_T("%s%d"), iter->first.c_str(), iter->second)] = iter->second;
646
 
                        else
647
 
                                combo[wxString::Format(_T("%s%d"), iter->first.c_str(), iter->second % 10)] = iter->second;
648
 
                        if (iter->second <= 10)
649
 
                                combo[wxString::Format(_T("%s%d"), iter->first.c_str(), iter->second - 1)] = iter->second;
650
 
                        else
651
 
                                combo[wxString::Format(_T("%s%d"), iter->first.c_str(), (iter->second - 1) % 10)] = iter->second;
652
 
                }
653
 
                m_MonthNamesMap.insert(combo.begin(), combo.end());
654
 
 
655
 
                m_MonthNamesMap[_T("1")] = 1;
656
 
                m_MonthNamesMap[_T("2")] = 2;
657
 
                m_MonthNamesMap[_T("3")] = 3;
658
 
                m_MonthNamesMap[_T("4")] = 4;
659
 
                m_MonthNamesMap[_T("5")] = 5;
660
 
                m_MonthNamesMap[_T("6")] = 6;
661
 
                m_MonthNamesMap[_T("7")] = 7;
662
 
                m_MonthNamesMap[_T("8")] = 8;
663
 
                m_MonthNamesMap[_T("9")] = 9;
664
 
                m_MonthNamesMap[_T("10")] = 10;
665
 
                m_MonthNamesMap[_T("11")] = 11;
666
 
                m_MonthNamesMap[_T("12")] = 12;
667
 
        }
668
 
 
669
 
#ifdef LISTDEBUG
670
 
        for (unsigned int i = 0; data[i][0]; ++i)
671
 
        {
672
 
                unsigned int len = (unsigned int)strlen(data[i]);
673
 
                char *pData = new char[len + 3];
674
 
                strcpy(pData, data[i]);
675
 
                strcat(pData, "\r\n");
676
 
                AddData(pData, len + 2);
677
 
        }
678
 
#endif
679
 
}
680
 
 
681
 
CDirectoryListingParser::~CDirectoryListingParser()
682
 
{
683
 
        for (std::list<t_list>::iterator iter = m_DataList.begin(); iter != m_DataList.end(); ++iter)
684
 
                delete [] iter->p;
685
 
 
686
 
        delete m_prevLine;
687
 
}
688
 
 
689
 
bool CDirectoryListingParser::ParseData(bool partial)
690
 
{
691
 
        bool error = false;
692
 
        CLine *pLine = GetLine(partial, error);
693
 
        while (pLine)
694
 
        {
695
 
                bool res = ParseLine(pLine, m_server.GetType(), false);
696
 
                if (!res)
697
 
                {
698
 
                        if (m_prevLine)
699
 
                        {
700
 
                                CLine* pConcatenatedLine = m_prevLine->Concat(pLine);
701
 
                                bool res = ParseLine(pConcatenatedLine, m_server.GetType(), true);
702
 
                                delete pConcatenatedLine;
703
 
                                delete m_prevLine;
704
 
 
705
 
                                if (res)
706
 
                                {
707
 
                                        delete pLine;
708
 
                                        m_prevLine = 0;
709
 
                                }
710
 
                                else
711
 
                                        m_prevLine = pLine;
712
 
                        }
713
 
                        else
714
 
                                m_prevLine = pLine;
715
 
                }
716
 
                else
717
 
                {
718
 
                        delete m_prevLine;
719
 
                        m_prevLine = 0;
720
 
                        delete pLine;
721
 
                }
722
 
                pLine = GetLine(partial, error);
723
 
        };
724
 
 
725
 
        return !error;
726
 
}
727
 
 
728
 
CDirectoryListing CDirectoryListingParser::Parse(const CServerPath &path)
729
 
{
730
 
        CDirectoryListing listing;
731
 
        listing.path = path;
732
 
        listing.m_firstListTime = CTimeEx::Now();
733
 
 
734
 
        if (!ParseData(false))
735
 
        {
736
 
                listing.m_failed = true;
737
 
                return listing;
738
 
        }
739
 
 
740
 
        if (!m_fileList.empty())
741
 
        {
742
 
                wxASSERT(m_entryList.empty());
743
 
 
744
 
                listing.SetCount(m_fileList.size());
745
 
                unsigned int i = 0;
746
 
                for (std::list<wxString>::const_iterator iter = m_fileList.begin(); iter != m_fileList.end(); ++iter, ++i)
747
 
                {
748
 
                        CDirentry entry;
749
 
                        entry.name = *iter;
750
 
                        entry.flags = 0;
751
 
                        entry.size = -1;
752
 
                        listing[i] = entry;
753
 
                }
754
 
        }
755
 
        else
756
 
        {
757
 
                listing.Assign(m_entryList);
758
 
        }
759
 
 
760
 
        return listing;
761
 
}
762
 
 
763
 
bool CDirectoryListingParser::ParseLine(CLine *pLine, const enum ServerType serverType, bool concatenated)
764
 
{
765
 
        CDirentry entry;
766
 
        bool res;
767
 
        int ires;
768
 
 
769
 
        if (serverType == ZVM)
770
 
        {
771
 
                res = ParseAsZVM(pLine, entry);
772
 
                if (res)
773
 
                        goto done;
774
 
        }
775
 
        else if (serverType == HPNONSTOP)
776
 
        {
777
 
                res = ParseAsHPNonstop(pLine, entry);
778
 
                if (res)
779
 
                        goto done;
780
 
        }
781
 
 
782
 
        ires = ParseAsMlsd(pLine, entry);
783
 
        if (ires == 1)
784
 
                goto done;
785
 
        else if (ires == 2)
786
 
                goto skip;
787
 
        res = ParseAsUnix(pLine, entry, true); // Common 'ls -l'
788
 
        if (res)
789
 
                goto done;
790
 
        res = ParseAsDos(pLine, entry);
791
 
        if (res)
792
 
                goto done;
793
 
        res = ParseAsEplf(pLine, entry);
794
 
        if (res)
795
 
                goto done;
796
 
        res = ParseAsVms(pLine, entry);
797
 
        if (res)
798
 
                goto done;
799
 
        res = ParseOther(pLine, entry);
800
 
        if (res)
801
 
                goto done;
802
 
        res = ParseAsIbm(pLine, entry);
803
 
        if (res)
804
 
                goto done;
805
 
        res = ParseAsWfFtp(pLine, entry);
806
 
        if (res)
807
 
                goto done;
808
 
        res = ParseAsIBM_MVS(pLine, entry);
809
 
        if (res)
810
 
                goto done;
811
 
        res = ParseAsIBM_MVS_PDS(pLine, entry);
812
 
        if (res)
813
 
                goto done;
814
 
        res = ParseAsOS9(pLine, entry);
815
 
        if (res)
816
 
                goto done;
817
 
#ifndef LISTDEBUG_MVS
818
 
        if (serverType == MVS)
819
 
#endif //LISTDEBUG_MVS
820
 
        {
821
 
                res = ParseAsIBM_MVS_Migrated(pLine, entry);
822
 
                if (res)
823
 
                        goto done;
824
 
                res = ParseAsIBM_MVS_PDS2(pLine, entry);
825
 
                if (res)
826
 
                        goto done;
827
 
                res = ParseAsIBM_MVS_Tape(pLine, entry);
828
 
                if (res)
829
 
                        goto done;
830
 
        }
831
 
        res = ParseAsUnix(pLine, entry, false); // 'ls -l' but without the date/time
832
 
        if (res)
833
 
                goto done;
834
 
 
835
 
        // Some servers just send a list of filenames. If a line could not be parsed,
836
 
        // check if it's a filename. If that's the case, store it for later, else clear
837
 
        // list of stored files.
838
 
        // If parsing finishes and no entries could be parsed and none of the lines
839
 
        // contained a space, assume it's a raw filelisting.
840
 
 
841
 
        if (!concatenated)
842
 
        {
843
 
                CToken token;
844
 
                if (!pLine->GetToken(0, token, true) || token.Find(' ') != -1)
845
 
                {
846
 
                        m_maybeMultilineVms = false;
847
 
                        m_fileList.clear();
848
 
                        m_fileListOnly = false;
849
 
                }
850
 
                else
851
 
                {
852
 
                        m_maybeMultilineVms = token.Find(';') != -1;
853
 
                        if (m_fileListOnly)
854
 
                                m_fileList.push_back(token.GetString());
855
 
                }
856
 
        }
857
 
        else
858
 
                m_maybeMultilineVms = false;
859
 
 
860
 
        return false;
861
 
done:
862
 
 
863
 
        m_maybeMultilineVms = false;
864
 
        m_fileList.clear();
865
 
        m_fileListOnly = false;
866
 
 
867
 
        // Don't add . or ..
868
 
        if (entry.name == _T(".") || entry.name == _T(".."))
869
 
                return true;
870
 
 
871
 
        if (serverType == VMS && entry.is_dir())
872
 
        {
873
 
                // Trim version information from directories
874
 
                int pos = entry.name.Find(';', true);
875
 
                if (pos > 0)
876
 
                        entry.name = entry.name.Left(pos);
877
 
        }
878
 
 
879
 
        {
880
 
                int offset = m_server.GetTimezoneOffset();
881
 
                if (offset && entry.has_time())
882
 
                {
883
 
                        // Apply timezone offset
884
 
                        wxTimeSpan span(0, offset, 0, 0);
885
 
                        entry.time.Add(span);
886
 
                }
887
 
        }
888
 
 
889
 
        m_entryList.push_back(entry);
890
 
 
891
 
skip:
892
 
        m_maybeMultilineVms = false;
893
 
        m_fileList.clear();
894
 
        m_fileListOnly = false;
895
 
 
896
 
        return true;
897
 
}
898
 
 
899
 
bool CDirectoryListingParser::ParseAsUnix(CLine *pLine, CDirentry &entry, bool expect_date)
900
 
{
901
 
        int index = 0;
902
 
        CToken token;
903
 
        if (!pLine->GetToken(index, token))
904
 
                return false;
905
 
 
906
 
        wxChar chr = token[0];
907
 
        if (chr != 'b' &&
908
 
                chr != 'c' &&
909
 
                chr != 'd' &&
910
 
                chr != 'l' &&
911
 
                chr != 'p' &&
912
 
                chr != 's' &&
913
 
                chr != '-')
914
 
                return false;
915
 
 
916
 
        entry.permissions = token.GetString();
917
 
 
918
 
        entry.flags = 0;
919
 
 
920
 
        if (chr == 'd' || chr == 'l')
921
 
                entry.flags |= CDirentry::flag_dir;
922
 
 
923
 
        if (chr == 'l')
924
 
                entry.flags |= CDirentry::flag_link;
925
 
 
926
 
        // Check for netware servers, which split the permissions into two parts
927
 
        bool netware = false;
928
 
        if (token.GetLength() == 1)
929
 
        {
930
 
                if (!pLine->GetToken(++index, token))
931
 
                        return false;
932
 
                entry.permissions += _T(" ") + token.GetString();
933
 
                netware = true;
934
 
        }
935
 
 
936
 
        int numOwnerGroup = 3;
937
 
        if (!netware)
938
 
        {
939
 
                // Filter out link count, we don't need it
940
 
                if (!pLine->GetToken(++index, token))
941
 
                        return false;
942
 
 
943
 
                if (!token.IsNumeric())
944
 
                        --index;
945
 
        }
946
 
 
947
 
        // Repeat until numOwnerGroup is 0 since not all servers send every possible field
948
 
        int startindex = index;
949
 
        do
950
 
        {
951
 
                // Reset index
952
 
                index = startindex;
953
 
 
954
 
                entry.ownerGroup.clear();
955
 
                for (int i = 0; i < numOwnerGroup; ++i)
956
 
                {
957
 
                        if (!pLine->GetToken(++index, token))
958
 
                                return false;
959
 
                        if (i)
960
 
                                entry.ownerGroup += _T(" ");
961
 
                        entry.ownerGroup += token.GetString();
962
 
                }
963
 
 
964
 
                if (!pLine->GetToken(++index, token))
965
 
                        return false;
966
 
 
967
 
                // Check for concatenated groupname and size fields
968
 
                if (!ParseComplexFileSize(token, entry.size))
969
 
                {
970
 
                        if (!token.IsRightNumeric())
971
 
                                continue;
972
 
                        entry.size = token.GetNumber();
973
 
                }
974
 
 
975
 
                // Append missing group to ownerGroup
976
 
                if (!token.IsNumeric() && token.IsRightNumeric())
977
 
                {
978
 
                        if (!entry.ownerGroup.IsEmpty())
979
 
                                entry.ownerGroup += _T(" ");
980
 
                        entry.ownerGroup += token.GetString(1);
981
 
                }
982
 
 
983
 
                if (expect_date)
984
 
                {
985
 
                        entry.flags &= ~CDirentry::flag_timestamp_mask;
986
 
                        if (!ParseUnixDateTime(pLine, index, entry))
987
 
                                continue;
988
 
                }
989
 
 
990
 
                // Get the filename
991
 
                if (!pLine->GetToken(++index, token, 1))
992
 
                        continue;
993
 
 
994
 
                entry.name = token.GetString();
995
 
 
996
 
                // Filter out cpecial chars at the end of the filenames
997
 
                chr = token[token.GetLength() - 1];
998
 
                if (chr == '/' ||
999
 
                        chr == '|' ||
1000
 
                        chr == '*')
1001
 
                        entry.name.RemoveLast();
1002
 
 
1003
 
                if (entry.is_link())
1004
 
                {
1005
 
                        int pos;
1006
 
                        if ((pos = entry.name.Find(_T(" -> "))) != -1)
1007
 
                        {
1008
 
                                entry.target = entry.name.Mid(pos + 4);
1009
 
                                entry.name = entry.name.Left(pos);
1010
 
                        }
1011
 
                }
1012
 
 
1013
 
                if (entry.has_time())
1014
 
                        entry.time.Add(m_timezoneOffset);
1015
 
 
1016
 
                return true;
1017
 
        }
1018
 
        while (numOwnerGroup--);
1019
 
 
1020
 
        return false;
1021
 
}
1022
 
 
1023
 
bool CDirectoryListingParser::ParseUnixDateTime(CLine *pLine, int &index, CDirentry &entry)
1024
 
{
1025
 
        bool mayHaveTime = true;
1026
 
        bool bHasYearAndTime = false;
1027
 
        bool hasTime = false;
1028
 
 
1029
 
        CToken token;
1030
 
 
1031
 
        // Get the month date field
1032
 
        CToken dateMonth;
1033
 
        if (!pLine->GetToken(++index, token))
1034
 
                return false;
1035
 
 
1036
 
        int year = 0;
1037
 
        int month = 0;
1038
 
        int day = 0;
1039
 
        long hour = 0;
1040
 
        long minute = 0;
1041
 
 
1042
 
        // Some servers use the following date formats:
1043
 
        // 26-05 2002, 2002-10-14, 01-jun-99 or 2004.07.15
1044
 
        // slashes instead of dashes are also possible
1045
 
        int pos = token.Find(_T("-/."));
1046
 
        if (pos != -1)
1047
 
        {
1048
 
                int pos2 = token.Find(_T("-/."), pos + 1);
1049
 
                if (pos2 == -1)
1050
 
                {
1051
 
                        if (token[pos] != '.')
1052
 
                        {
1053
 
                                // something like 26-05 2002
1054
 
                                day = token.GetNumber(pos + 1, token.GetLength() - pos - 1).GetLo();
1055
 
                                if (day < 1 || day > 31)
1056
 
                                        return false;
1057
 
                                dateMonth = CToken(token.GetToken(), pos);
1058
 
                        }
1059
 
                        else
1060
 
                                dateMonth = token;
1061
 
                }
1062
 
                else if (token[pos] != token[pos2])
1063
 
                        return false;
1064
 
                else
1065
 
                {
1066
 
                        if (!ParseShortDate(token, entry))
1067
 
                                return false;
1068
 
 
1069
 
                        if (token[pos] == '.')
1070
 
                                return true;
1071
 
 
1072
 
                        year = entry.time.GetYear();
1073
 
                        month = entry.time.GetMonth() - wxDateTime::Jan + 1;
1074
 
                        day = entry.time.GetDay();
1075
 
                }
1076
 
        }
1077
 
        else if (token.IsNumeric())
1078
 
        {
1079
 
                if (token.GetNumber() > 1000 && token.GetNumber() < 10000)
1080
 
                {
1081
 
                        // Two possible variants:
1082
 
                        // 1) 2005 3 13
1083
 
                        // 2) 2005 13 3
1084
 
                        // assume first one.
1085
 
                        year = token.GetNumber().GetLo();
1086
 
                        if (!pLine->GetToken(++index, dateMonth))
1087
 
                                return false;
1088
 
                        mayHaveTime = false;
1089
 
                }
1090
 
                else
1091
 
                        dateMonth = token;
1092
 
        }
1093
 
        else
1094
 
        {
1095
 
                if (token.IsLeftNumeric() && (unsigned int)token[token.GetLength() - 1] > 127 &&
1096
 
                        token.GetNumber() > 1000)
1097
 
                {
1098
 
                        if (token.GetNumber() > 10000)
1099
 
                                return false;
1100
 
 
1101
 
                        // Asian date format: 2005xxx 5xx 20xxx with some non-ascii characters following
1102
 
                        year = token.GetNumber().GetLo();
1103
 
                        if (!pLine->GetToken(++index, dateMonth))
1104
 
                                return false;
1105
 
                        mayHaveTime = false;
1106
 
                }
1107
 
                else
1108
 
                        dateMonth = token;
1109
 
        }
1110
 
 
1111
 
        if (!day)
1112
 
        {
1113
 
                // Get day field
1114
 
                if (!pLine->GetToken(++index, token))
1115
 
                        return false;
1116
 
 
1117
 
                int dateDay;
1118
 
 
1119
 
                // Check for non-numeric day
1120
 
                if (!token.IsNumeric() && !token.IsLeftNumeric())
1121
 
                {
1122
 
                        int offset = 0;
1123
 
                        if (dateMonth.GetString().Right(1) == _T("."))
1124
 
                                ++offset;
1125
 
                        if (!dateMonth.IsNumeric(0, dateMonth.GetLength() - offset))
1126
 
                                return false;
1127
 
                        dateDay = dateMonth.GetNumber(0, dateMonth.GetLength() - offset).GetLo();
1128
 
                        dateMonth = token;
1129
 
                }
1130
 
                else
1131
 
                {
1132
 
                        dateDay = token.GetNumber().GetLo();
1133
 
                        if (token[token.GetLength() - 1] == ',')
1134
 
                                bHasYearAndTime = true;
1135
 
                }
1136
 
 
1137
 
                if (dateDay < 1 || dateDay > 31)
1138
 
                        return false;
1139
 
                day = dateDay;
1140
 
        }
1141
 
 
1142
 
        if (!month)
1143
 
        {
1144
 
                wxString strMonth = dateMonth.GetString();
1145
 
                if (dateMonth.IsLeftNumeric() && (unsigned int)strMonth[strMonth.Length() - 1] > 127)
1146
 
                {
1147
 
                        // Most likely an Asian server sending some unknown language specific
1148
 
                        // suffix at the end of the monthname. Filter it out.
1149
 
                        int i;
1150
 
                        for (i = strMonth.Length() - 1; i > 0; --i)
1151
 
                        {
1152
 
                                if (strMonth[i] >= '0' && strMonth[i] <= '9')
1153
 
                                        break;
1154
 
                        }
1155
 
                        strMonth = strMonth.Left(i + 1);
1156
 
                }
1157
 
                // Check month name
1158
 
                while (strMonth.Right(1) == _T(",") || strMonth.Right(1) == _T("."))
1159
 
                        strMonth.RemoveLast();
1160
 
                if (!GetMonthFromName(strMonth, month))
1161
 
                        return false;
1162
 
        }
1163
 
 
1164
 
        // Get time/year field
1165
 
        if (!pLine->GetToken(++index, token))
1166
 
                return false;
1167
 
 
1168
 
        pos = token.Find(_T(":.-"));
1169
 
        if (pos != -1 && mayHaveTime)
1170
 
        {
1171
 
                // token is a time
1172
 
                if (!pos || static_cast<size_t>(pos) == (token.GetLength() - 1))
1173
 
                        return false;
1174
 
 
1175
 
                wxString str = token.GetString();
1176
 
                if (!str.Left(pos).ToLong(&hour))
1177
 
                        return false;
1178
 
                if (!str.Mid(pos + 1).ToLong(&minute))
1179
 
                        return false;
1180
 
 
1181
 
                if (hour < 0 || hour > 23)
1182
 
                        return false;
1183
 
                if (minute < 0 || minute > 59)
1184
 
                        return false;
1185
 
 
1186
 
                hasTime = true;
1187
 
 
1188
 
                // Some servers use times only for files newer than 6 months
1189
 
                if (!year)
1190
 
                {
1191
 
                        year = wxDateTime::Now().GetYear();
1192
 
                        int currentDayOfYear = wxDateTime::Now().GetDay() + 31 * (wxDateTime::Now().GetMonth() - wxDateTime::Jan);
1193
 
                        int fileDayOfYear = (month - 1) * 31 + day;
1194
 
 
1195
 
                        // We have to compare with an offset of one. In the worst case,
1196
 
                        // the server's timezone might be up to 24 hours ahead of the 
1197
 
                        // client.
1198
 
                        // Problem: Servers which do send the time but not the year even
1199
 
                        // one day away from getting 1 year old. This is far more uncommon
1200
 
                        // however.
1201
 
                        if ((currentDayOfYear + 1) < fileDayOfYear)
1202
 
                                year -= 1;
1203
 
                }
1204
 
        }
1205
 
        else if (!year)
1206
 
        {
1207
 
                // token is a year
1208
 
                if (!token.IsNumeric() && !token.IsLeftNumeric())
1209
 
                        return false;
1210
 
 
1211
 
                year = token.GetNumber().GetLo();
1212
 
 
1213
 
                if (year > 3000)
1214
 
                        return false;
1215
 
                if (year < 1000)
1216
 
                        year += 1900;
1217
 
 
1218
 
                if (bHasYearAndTime)
1219
 
                {
1220
 
                        if (!pLine->GetToken(++index, token))
1221
 
                                return false;
1222
 
 
1223
 
                        if (token.Find(':') == 2 && token.GetLength() == 5 && token.IsLeftNumeric() && token.IsRightNumeric())
1224
 
                        {
1225
 
                                int pos = token.Find(':');
1226
 
                                // token is a time
1227
 
                                if (!pos || static_cast<size_t>(pos) == (token.GetLength() - 1))
1228
 
                                        return false;
1229
 
 
1230
 
                                wxString str = token.GetString();
1231
 
 
1232
 
                                if (!str.Left(pos).ToLong(&hour))
1233
 
                                        return false;
1234
 
                                if (!str.Mid(pos + 1).ToLong(&minute))
1235
 
                                        return false;
1236
 
 
1237
 
                                if (hour < 0 || hour > 23)
1238
 
                                        return false;
1239
 
                                if (minute < 0 || minute > 59)
1240
 
                                        return false;
1241
 
 
1242
 
                                hasTime = true;
1243
 
                        }
1244
 
                        else
1245
 
                                --index;
1246
 
                }
1247
 
        }
1248
 
        else
1249
 
                --index;
1250
 
 
1251
 
        entry.time = wxDateTime();
1252
 
        if (!VerifySetDate(entry.time, year, (wxDateTime::Month)(wxDateTime::Jan + month - 1), day, hour, minute))
1253
 
                return false;
1254
 
 
1255
 
        entry.flags |= CDirentry::flag_timestamp_date;
1256
 
        if (hasTime)
1257
 
                entry.flags |= CDirentry::flag_timestamp_time;
1258
 
 
1259
 
        return true;
1260
 
}
1261
 
 
1262
 
bool CDirectoryListingParser::ParseShortDate(CToken &token, CDirentry &entry, bool saneFieldOrder /*=false*/)
1263
 
{
1264
 
        if (token.GetLength() < 1)
1265
 
                return false;
1266
 
 
1267
 
        bool gotYear = false;
1268
 
        bool gotMonth = false;
1269
 
        bool gotDay = false;
1270
 
        bool gotMonthName = false;
1271
 
 
1272
 
        int year = 0;
1273
 
        int month = 0;
1274
 
        int day = 0;
1275
 
 
1276
 
        int value = 0;
1277
 
 
1278
 
        int pos = token.Find(_T("-./"));
1279
 
        if (pos < 1)
1280
 
                return false;
1281
 
 
1282
 
        if (!token.IsNumeric(0, pos))
1283
 
        {
1284
 
                // Seems to be monthname-dd-yy
1285
 
 
1286
 
                // Check month name
1287
 
                wxString dateMonth = token.GetString().Mid(0, pos);
1288
 
                if (!GetMonthFromName(dateMonth, month))
1289
 
                        return false;
1290
 
                gotMonth = true;
1291
 
                gotMonthName = true;
1292
 
        }
1293
 
        else if (pos == 4)
1294
 
        {
1295
 
                // Seems to be yyyy-mm-dd
1296
 
                year = token.GetNumber(0, pos).GetLo();
1297
 
                if (year < 1900 || year > 3000)
1298
 
                        return false;
1299
 
                gotYear = true;
1300
 
        }
1301
 
        else if (pos <= 2)
1302
 
        {
1303
 
                wxLongLong value = token.GetNumber(0, pos);
1304
 
                if (token[pos] == '.')
1305
 
                {
1306
 
                        // Maybe dd.mm.yyyy
1307
 
                        if (value < 1 || value > 31)
1308
 
                                return false;
1309
 
                        day = value.GetLo();
1310
 
                        gotDay = true;
1311
 
                }
1312
 
                else
1313
 
                {
1314
 
                        if (saneFieldOrder)
1315
 
                        {
1316
 
                                year = value.GetLo();
1317
 
                                if (year < 50)
1318
 
                                        year += 2000;
1319
 
                                else
1320
 
                                        year += 1900;
1321
 
                                gotYear = true;
1322
 
                        }
1323
 
                        else
1324
 
                        {
1325
 
                                // Detect mm-dd-yyyy or mm/dd/yyyy and
1326
 
                                // dd-mm-yyyy or dd/mm/yyyy
1327
 
                                if (value < 1)
1328
 
                                        return false;
1329
 
                                if (value > 12)
1330
 
                                {
1331
 
                                        if (value > 31)
1332
 
                                                return false;
1333
 
 
1334
 
                                        day = value.GetLo();
1335
 
                                        gotDay = true;
1336
 
                                }
1337
 
                                else
1338
 
                                {
1339
 
                                        month = value.GetLo();
1340
 
                                        gotMonth = true;
1341
 
                                }
1342
 
                        }
1343
 
                }
1344
 
        }
1345
 
        else
1346
 
                return false;
1347
 
 
1348
 
        int pos2 = token.Find(_T("-./"), pos + 1);
1349
 
        if (pos2 == -1 || (pos2 - pos) == 1)
1350
 
                return false;
1351
 
        if (static_cast<size_t>(pos2) == (token.GetLength() - 1))
1352
 
                return false;
1353
 
 
1354
 
        // If we already got the month and the second field is not numeric,
1355
 
        // change old month into day and use new token as month
1356
 
        if (!token.IsNumeric(pos + 1, pos2 - pos - 1) && gotMonth)
1357
 
        {
1358
 
                if (gotMonthName)
1359
 
                        return false;
1360
 
 
1361
 
                if (gotDay)
1362
 
                        return false;
1363
 
 
1364
 
                gotDay = true;
1365
 
                gotMonth = false;
1366
 
                day = month;
1367
 
        }
1368
 
 
1369
 
        if (gotYear || gotDay)
1370
 
        {
1371
 
                // Month field in yyyy-mm-dd or dd-mm-yyyy
1372
 
                // Check month name
1373
 
                wxString dateMonth = token.GetString().Mid(pos + 1, pos2 - pos - 1);
1374
 
                if (!GetMonthFromName(dateMonth, month))
1375
 
                        return false;
1376
 
                gotMonth = true;
1377
 
        }
1378
 
        else
1379
 
        {
1380
 
                wxLongLong value = token.GetNumber(pos + 1, pos2 - pos - 1);
1381
 
                // Day field in mm-dd-yyyy
1382
 
                if (value < 1 || value > 31)
1383
 
                        return false;
1384
 
                day = value.GetLo();
1385
 
                gotDay = true;
1386
 
        }
1387
 
 
1388
 
        value = token.GetNumber(pos2 + 1, token.GetLength() - pos2 - 1).GetLo();
1389
 
        if (gotYear)
1390
 
        {
1391
 
                // Day field in yyy-mm-dd
1392
 
                if (!value || value > 31)
1393
 
                        return false;
1394
 
                day = value;
1395
 
                gotDay = true;
1396
 
        }
1397
 
        else
1398
 
        {
1399
 
                if (value < 0)
1400
 
                        return false;
1401
 
 
1402
 
                if (value < 50)
1403
 
                        value += 2000;
1404
 
                else if (value < 1000)
1405
 
                        value += 1900;
1406
 
                year = value;
1407
 
 
1408
 
                gotYear = true;
1409
 
        }
1410
 
 
1411
 
        if (!gotMonth || !gotDay || !gotYear)
1412
 
                return false;
1413
 
 
1414
 
        entry.time = wxDateTime();
1415
 
        if (!VerifySetDate(entry.time, year, (wxDateTime::Month)(wxDateTime::Jan + month - 1), day))
1416
 
                return false;
1417
 
        entry.flags |= CDirentry::flag_timestamp_date;
1418
 
 
1419
 
        return true;
1420
 
}
1421
 
 
1422
 
bool CDirectoryListingParser::ParseAsDos(CLine *pLine, CDirentry &entry)
1423
 
{
1424
 
        int index = 0;
1425
 
        CToken token;
1426
 
 
1427
 
        // Get first token, has to be a valid date
1428
 
        if (!pLine->GetToken(index, token))
1429
 
                return false;
1430
 
 
1431
 
        entry.flags = 0;
1432
 
 
1433
 
        if (!ParseShortDate(token, entry))
1434
 
                return false;
1435
 
 
1436
 
        // Extract time
1437
 
        if (!pLine->GetToken(++index, token))
1438
 
                return false;
1439
 
 
1440
 
        if (!ParseTime(token, entry))
1441
 
                return false;
1442
 
 
1443
 
        // If next token is <DIR>, entry is a directory
1444
 
        // else, it should be the filesize.
1445
 
        if (!pLine->GetToken(++index, token))
1446
 
                return false;
1447
 
 
1448
 
        if (token.GetString() == _T("<DIR>"))
1449
 
        {
1450
 
                entry.flags |= CDirentry::flag_dir;
1451
 
                entry.size = -1;
1452
 
        }
1453
 
        else if (token.IsNumeric() || token.IsLeftNumeric())
1454
 
        {
1455
 
                // Convert size, filter out separators
1456
 
                wxLongLong size = 0;
1457
 
                int len = token.GetLength();
1458
 
                for (int i = 0; i < len; ++i)
1459
 
                {
1460
 
                        char chr = token[i];
1461
 
                        if (chr == ',' || chr == '.')
1462
 
                                continue;
1463
 
                        if (chr < '0' || chr > '9')
1464
 
                                return false;
1465
 
 
1466
 
                        size *= 10;
1467
 
                        size += chr - '0';
1468
 
                }
1469
 
                entry.size = size;
1470
 
        }
1471
 
        else
1472
 
                return false;
1473
 
 
1474
 
        // Extract filename
1475
 
        if (!pLine->GetToken(++index, token, true))
1476
 
                return false;
1477
 
        entry.name = token.GetString();
1478
 
 
1479
 
        entry.target = _T("");
1480
 
        entry.ownerGroup = _T("");
1481
 
        entry.permissions = _T("");
1482
 
 
1483
 
        if (entry.has_time())
1484
 
                entry.time.Add(m_timezoneOffset);
1485
 
 
1486
 
        return true;
1487
 
}
1488
 
 
1489
 
bool CDirectoryListingParser::ParseTime(CToken &token, CDirentry &entry)
1490
 
{
1491
 
        if (!entry.has_date())
1492
 
                return false;
1493
 
 
1494
 
        int pos = token.Find(':');
1495
 
        if (pos < 1 || static_cast<unsigned int>(pos) >= (token.GetLength() - 1))
1496
 
                return false;
1497
 
 
1498
 
        wxLongLong hour = token.GetNumber(0, pos);
1499
 
        if (hour < 0 || hour > 23)
1500
 
                return false;
1501
 
 
1502
 
        // See if we got seconds
1503
 
        int pos2 = token.Find(':', pos + 1);
1504
 
        int len;
1505
 
        if (pos2 == -1)
1506
 
                len = -1;
1507
 
        else
1508
 
                len = pos2 - pos - 1;
1509
 
 
1510
 
        if (!len)
1511
 
                return false;
1512
 
 
1513
 
        wxLongLong minute = token.GetNumber(pos + 1, len);
1514
 
        if (minute < 0 || minute > 59)
1515
 
                return false;
1516
 
 
1517
 
        wxLongLong seconds;
1518
 
        bool hasSeconds = false;
1519
 
        if (pos2 == -1)
1520
 
                seconds = 0;
1521
 
        else
1522
 
        {
1523
 
                // Parse seconds
1524
 
                seconds = token.GetNumber(pos2 + 1, -1);
1525
 
                if (seconds < 0 || seconds > 59)
1526
 
                        return false;
1527
 
                hasSeconds = true;
1528
 
        }
1529
 
 
1530
 
        // Convert to 24h format
1531
 
        if (!token.IsRightNumeric())
1532
 
        {
1533
 
                if (token[token.GetLength() - 2] == 'P')
1534
 
                {
1535
 
                        if (hour < 12)
1536
 
                                hour += 12;
1537
 
                }
1538
 
                else
1539
 
                        if (hour == 12)
1540
 
                                hour = 0;
1541
 
        }
1542
 
 
1543
 
        wxTimeSpan span(hour.GetLo(), minute.GetLo(), seconds.GetLo());
1544
 
        entry.time.Add(span);
1545
 
 
1546
 
        entry.flags |= CDirentry::flag_timestamp_time;
1547
 
        if (hasSeconds)
1548
 
                entry.flags |= CDirentry::flag_timestamp_seconds;
1549
 
 
1550
 
        return true;
1551
 
}
1552
 
 
1553
 
bool CDirectoryListingParser::ParseAsEplf(CLine *pLine, CDirentry &entry)
1554
 
{
1555
 
        CToken token;
1556
 
        if (!pLine->GetToken(0, token, true))
1557
 
                return false;
1558
 
 
1559
 
        if (token[0] != '+')
1560
 
                return false;
1561
 
 
1562
 
        int pos = token.Find('\t');
1563
 
        if (pos == -1 || static_cast<size_t>(pos) == (token.GetLength() - 1))
1564
 
                return false;
1565
 
 
1566
 
        entry.name = token.GetString().Mid(pos + 1);
1567
 
 
1568
 
        entry.flags = 0;
1569
 
        entry.ownerGroup = _T("");
1570
 
        entry.permissions = _T("");
1571
 
        entry.size = -1;
1572
 
 
1573
 
        int fact = 1;
1574
 
        while (fact < pos)
1575
 
        {
1576
 
                int separator = token.Find(',', fact);
1577
 
                int len;
1578
 
                if (separator == -1)
1579
 
                        len = pos - fact;
1580
 
                else
1581
 
                        len = separator - fact;
1582
 
 
1583
 
                if (!len)
1584
 
                {
1585
 
                        ++fact;
1586
 
                        continue;
1587
 
                }
1588
 
 
1589
 
                char type = token[fact];
1590
 
 
1591
 
                if (type == '/')
1592
 
                        entry.flags |= CDirentry::flag_dir;
1593
 
                else if (type == 's')
1594
 
                        entry.size = token.GetNumber(fact + 1, len - 1);
1595
 
                else if (type == 'm')
1596
 
                {
1597
 
                        wxLongLong number = token.GetNumber(fact + 1, len - 1);
1598
 
                        if (number < 0)
1599
 
                                return false;
1600
 
                        entry.time = wxDateTime((time_t)number.GetValue());
1601
 
 
1602
 
                        entry.flags |= CDirentry::flag_timestamp_date | CDirentry::flag_timestamp_time | CDirentry::flag_timestamp_seconds;
1603
 
                }
1604
 
                else if (type == 'u' && len > 2 && token[fact + 1] == 'p')
1605
 
                        entry.permissions = token.GetString().Mid(fact + 2, len - 2);
1606
 
 
1607
 
                fact += len + 1;
1608
 
        }
1609
 
 
1610
 
        return true;
1611
 
}
1612
 
 
1613
 
wxString Unescape(const wxString& str, wxChar escape)
1614
 
{
1615
 
        wxString res;
1616
 
        for (unsigned int i = 0; i < str.Len(); ++i)
1617
 
        {
1618
 
                wxChar c = str[i];
1619
 
                if (c == escape)
1620
 
                {
1621
 
                        c = str[++i];
1622
 
                        if (!c)
1623
 
                                break;
1624
 
                }
1625
 
                res += c;
1626
 
        }
1627
 
 
1628
 
        return res;
1629
 
}
1630
 
 
1631
 
bool CDirectoryListingParser::ParseAsVms(CLine *pLine, CDirentry &entry)
1632
 
{
1633
 
        CToken token;
1634
 
        int index = 0;
1635
 
 
1636
 
        if (!pLine->GetToken(index, token))
1637
 
                return false;
1638
 
 
1639
 
        int pos = token.Find(';');
1640
 
        if (pos == -1)
1641
 
                return false;
1642
 
 
1643
 
        entry.flags = 0;
1644
 
 
1645
 
        if (pos > 4 && token.GetString().Mid(pos - 4, 4) == _T(".DIR"))
1646
 
        {
1647
 
                entry.flags |= CDirentry::flag_dir;
1648
 
                if (token.GetString().Mid(pos) == _T(";1"))
1649
 
                        entry.name = token.GetString().Left(pos - 4);
1650
 
                else
1651
 
                        entry.name = token.GetString().Left(pos - 4) + token.GetString().Mid(pos);
1652
 
        }
1653
 
        else
1654
 
                entry.name = token.GetString();
1655
 
 
1656
 
        // Some VMS servers escape special characters like additional dots with ^
1657
 
        entry.name = Unescape(entry.name, '^');
1658
 
 
1659
 
        if (!pLine->GetToken(++index, token))
1660
 
                return false;
1661
 
 
1662
 
        entry.ownerGroup = _T("");
1663
 
 
1664
 
        // This field can either be the filesize, a username (at least that's what I think) enclosed in [] or a date.
1665
 
        if (!token.IsNumeric() && !token.IsLeftNumeric())
1666
 
        {
1667
 
                // Must be username
1668
 
 
1669
 
                const int len = token.GetLength();
1670
 
                if (len < 3 || token[0] != '[' || token[len - 1] != ']')
1671
 
                        return false;
1672
 
                entry.ownerGroup = token.GetString().Mid(1, len - 2);
1673
 
 
1674
 
                if (!pLine->GetToken(++index, token))
1675
 
                        return false;
1676
 
                if (!token.IsNumeric() && !token.IsLeftNumeric())
1677
 
                        return false;
1678
 
        }
1679
 
 
1680
 
        // Current token is either size or date
1681
 
        bool gotSize = false;
1682
 
        pos = token.Find('/');
1683
 
        
1684
 
        if (!pos)
1685
 
                return false;
1686
 
 
1687
 
        if (token.IsNumeric() || (pos != -1 && token.Find('/', pos + 1) == -1))
1688
 
        {
1689
 
                // Definitely size
1690
 
 
1691
 
                CToken sizeToken;
1692
 
                if (pos == -1)
1693
 
                        sizeToken = token;
1694
 
                else
1695
 
                        sizeToken = CToken(token.GetToken(), pos);
1696
 
                if (!ParseComplexFileSize(sizeToken, entry.size, 512))
1697
 
                        return false;
1698
 
                gotSize = true;
1699
 
 
1700
 
                if (!pLine->GetToken(++index, token))
1701
 
                        return false;
1702
 
        }
1703
 
        else if (pos == -1 && token.IsLeftNumeric())
1704
 
        {
1705
 
                // Perhaps size
1706
 
                CToken sizeToken;
1707
 
                if (pos == -1)
1708
 
                        sizeToken = token;
1709
 
                else
1710
 
                        sizeToken = CToken(token.GetToken(), pos);
1711
 
                if (ParseComplexFileSize(sizeToken, entry.size, 512))
1712
 
                {
1713
 
                        gotSize = true;
1714
 
 
1715
 
                        if (!pLine->GetToken(++index, token))
1716
 
                                return false;
1717
 
                }
1718
 
        }
1719
 
 
1720
 
        // Get date
1721
 
        if (!ParseShortDate(token, entry))
1722
 
                return false;
1723
 
 
1724
 
        // Get time
1725
 
        if (!pLine->GetToken(++index, token))
1726
 
                return true;
1727
 
 
1728
 
        if (!ParseTime(token, entry))
1729
 
        {
1730
 
                int len = token.GetLength();
1731
 
                if (token[0] == '[' && token[len - 1] != ']')
1732
 
                        return false;
1733
 
                if (token[0] == '(' && token[len - 1] != ')')
1734
 
                        return false;
1735
 
                if (token[0] != '[' && token[len - 1] == ']')
1736
 
                        return false;
1737
 
                if (token[0] != '(' && token[len - 1] == ')')
1738
 
                        return false;
1739
 
                --index;
1740
 
        }
1741
 
 
1742
 
        if (!gotSize)
1743
 
        {
1744
 
                // Get size
1745
 
                if (!pLine->GetToken(++index, token))
1746
 
                        return false;
1747
 
 
1748
 
                if (!token.IsNumeric() && !token.IsLeftNumeric())
1749
 
                        return false;
1750
 
 
1751
 
                int pos = token.Find('/');
1752
 
                if (!pos)
1753
 
                        return false;
1754
 
 
1755
 
                CToken sizeToken;
1756
 
                if (pos == -1)
1757
 
                        sizeToken = token;
1758
 
                else
1759
 
                        sizeToken = CToken(token.GetToken(), pos);
1760
 
                if (!ParseComplexFileSize(sizeToken, entry.size, 512))
1761
 
                        return false;
1762
 
        }
1763
 
 
1764
 
        // Owner / group and permissions
1765
 
        entry.permissions = _T("");
1766
 
        while (pLine->GetToken(++index, token))
1767
 
        {
1768
 
                const int len = token.GetLength();
1769
 
                if (len > 2 && token[0] == '(' && token[len - 1] == ')')
1770
 
                {
1771
 
                        if (!entry.permissions.IsEmpty())
1772
 
                                entry.permissions += _T(" ");
1773
 
                        entry.permissions += token.GetString().Mid(1, len - 2);
1774
 
                }
1775
 
                else if (len > 2 && token[0] == '[' && token[len - 1] == ']')
1776
 
                {
1777
 
                        if (!entry.ownerGroup.IsEmpty())
1778
 
                                entry.ownerGroup += _T(" ");
1779
 
                        entry.ownerGroup += token.GetString().Mid(1, len - 2);
1780
 
                }
1781
 
                else
1782
 
                {
1783
 
                        if (!entry.permissions.IsEmpty())
1784
 
                                entry.permissions += _T(" ");
1785
 
                        entry.ownerGroup += token.GetString();
1786
 
                }
1787
 
        }
1788
 
 
1789
 
        if (entry.has_time())
1790
 
                entry.time.Add(m_timezoneOffset);
1791
 
 
1792
 
        return true;
1793
 
}
1794
 
 
1795
 
bool CDirectoryListingParser::ParseAsIbm(CLine *pLine, CDirentry &entry)
1796
 
{
1797
 
        int index = 0;
1798
 
        CToken token;
1799
 
 
1800
 
        // Get owner
1801
 
        if (!pLine->GetToken(index, token))
1802
 
                return false;
1803
 
 
1804
 
        entry.ownerGroup = token.GetString();
1805
 
 
1806
 
        // Get size
1807
 
        if (!pLine->GetToken(++index, token))
1808
 
                return false;
1809
 
 
1810
 
        if (!token.IsNumeric())
1811
 
                return false;
1812
 
 
1813
 
        entry.size = token.GetNumber();
1814
 
 
1815
 
        // Get date
1816
 
        if (!pLine->GetToken(++index, token))
1817
 
                return false;
1818
 
 
1819
 
        entry.flags = 0;
1820
 
 
1821
 
        if (!ParseShortDate(token, entry))
1822
 
                return false;
1823
 
 
1824
 
        // Get time
1825
 
        if (!pLine->GetToken(++index, token))
1826
 
                return false;
1827
 
 
1828
 
        if (!ParseTime(token, entry))
1829
 
                return false;
1830
 
 
1831
 
        // Get filename
1832
 
        if (!pLine->GetToken(index + 2, token, 1))
1833
 
                return false;
1834
 
 
1835
 
        entry.name = token.GetString();
1836
 
        if (token[token.GetLength() - 1] == '/')
1837
 
        {
1838
 
                entry.name.RemoveLast();
1839
 
                entry.flags |= CDirentry::flag_dir;
1840
 
        }
1841
 
        
1842
 
        if (entry.has_time())
1843
 
                entry.time.Add(m_timezoneOffset);
1844
 
 
1845
 
        return true;
1846
 
}
1847
 
 
1848
 
bool CDirectoryListingParser::ParseOther(CLine *pLine, CDirentry &entry)
1849
 
{
1850
 
        int index = 0;
1851
 
        CToken firstToken;
1852
 
 
1853
 
        if (!pLine->GetToken(index, firstToken))
1854
 
                return false;
1855
 
 
1856
 
        if (!firstToken.IsNumeric())
1857
 
                return false;
1858
 
 
1859
 
        // Possible formats: Numerical unix, VShell or OS/2
1860
 
 
1861
 
        CToken token;
1862
 
        if (!pLine->GetToken(++index, token))
1863
 
                return false;
1864
 
 
1865
 
        entry.flags = 0;
1866
 
 
1867
 
        // If token is a number, than it's the numerical Unix style format,
1868
 
        // else it's the VShell, OS/2 or nortel.VxWorks format
1869
 
        if (token.IsNumeric())
1870
 
        {
1871
 
                entry.permissions = firstToken.GetString();
1872
 
                if (firstToken.GetLength() >= 2 && firstToken[1] == '4')
1873
 
                        entry.flags |= CDirentry::flag_dir;
1874
 
 
1875
 
                entry.ownerGroup += token.GetString();
1876
 
 
1877
 
                if (!pLine->GetToken(++index, token))
1878
 
                        return false;
1879
 
 
1880
 
                entry.ownerGroup += _T(" ") + token.GetString();
1881
 
 
1882
 
                // Get size
1883
 
                if (!pLine->GetToken(++index, token))
1884
 
                        return false;
1885
 
 
1886
 
                if (!token.IsNumeric())
1887
 
                        return false;
1888
 
 
1889
 
                entry.size = token.GetNumber();
1890
 
 
1891
 
                // Get date/time
1892
 
                if (!pLine->GetToken(++index, token))
1893
 
                        return false;
1894
 
 
1895
 
                wxLongLong number = token.GetNumber();
1896
 
                if (number < 0)
1897
 
                        return false;
1898
 
                entry.time = wxDateTime((time_t)number.GetValue());
1899
 
 
1900
 
                entry.flags |= CDirentry::flag_timestamp_date | CDirentry::flag_timestamp_time | CDirentry::flag_timestamp_seconds;
1901
 
 
1902
 
                // Get filename
1903
 
                if (!pLine->GetToken(++index, token, true))
1904
 
                        return false;
1905
 
 
1906
 
                entry.name = token.GetString();
1907
 
 
1908
 
                entry.target = _T("");
1909
 
        }
1910
 
        else
1911
 
        {
1912
 
                // Possible conflict with multiline VMS listings
1913
 
                if (m_maybeMultilineVms)
1914
 
                        return false;
1915
 
 
1916
 
                // VShell, OS/2 or nortel.VxWorks style format
1917
 
                entry.size = firstToken.GetNumber();
1918
 
 
1919
 
                // Get date
1920
 
                wxString dateMonth = token.GetString();
1921
 
                int month = 0;
1922
 
                if (!GetMonthFromName(dateMonth, month))
1923
 
                {
1924
 
                        // OS/2 or nortel.VxWorks
1925
 
                        int skippedCount = 0;
1926
 
                        do
1927
 
                        {
1928
 
                                if (token.GetString() == _T("DIR"))
1929
 
                                        entry.flags |= CDirentry::flag_dir;
1930
 
                                else if (token.Find(_T("-/.")) != -1)
1931
 
                                        break;
1932
 
 
1933
 
                                ++skippedCount;
1934
 
 
1935
 
                                if (!pLine->GetToken(++index, token))
1936
 
                                        return false;
1937
 
                        } while (true);
1938
 
 
1939
 
                        if (!ParseShortDate(token, entry))
1940
 
                                return false;
1941
 
 
1942
 
                        // Get time
1943
 
                        if (!pLine->GetToken(++index, token))
1944
 
                                return false;
1945
 
 
1946
 
                        if (!ParseTime(token, entry))
1947
 
                                return false;
1948
 
 
1949
 
                        // Get filename
1950
 
                        if (!pLine->GetToken(++index, token, true))
1951
 
                                return false;
1952
 
 
1953
 
                        entry.name = token.GetString();
1954
 
                        wxString type = entry.name.Right(5);
1955
 
                        MakeLowerAscii(type);
1956
 
                        if (!skippedCount && type == _T("<dir>"))
1957
 
                        {
1958
 
                                entry.flags |= CDirentry::flag_dir;
1959
 
                                entry.name = entry.name.Left(entry.name.Length() - 5);
1960
 
                                while (entry.name.Last() == ' ')
1961
 
                                        entry.name.RemoveLast();
1962
 
                        }
1963
 
                }
1964
 
                else
1965
 
                {
1966
 
                        // Get day
1967
 
                        if (!pLine->GetToken(++index, token))
1968
 
                                return false;
1969
 
 
1970
 
                        if (!token.IsNumeric() && !token.IsLeftNumeric())
1971
 
                                return false;
1972
 
 
1973
 
                        wxLongLong day = token.GetNumber();
1974
 
                        if (day < 0 || day > 31)
1975
 
                                return false;
1976
 
 
1977
 
                        // Get Year
1978
 
                        if (!pLine->GetToken(++index, token))
1979
 
                                return false;
1980
 
 
1981
 
                        if (!token.IsNumeric())
1982
 
                                return false;
1983
 
 
1984
 
                        wxLongLong year = token.GetNumber();
1985
 
                        if (year < 50)
1986
 
                                year += 2000;
1987
 
                        else if (year < 1000)
1988
 
                                year += 1900;
1989
 
 
1990
 
                        entry.time = wxDateTime();
1991
 
                        if (!VerifySetDate(entry.time, year.GetLo(), (wxDateTime::Month)(month - 1), day.GetLo()))
1992
 
                                return false;
1993
 
 
1994
 
                        entry.flags |= CDirentry::flag_timestamp_date;
1995
 
 
1996
 
                        // Get time
1997
 
                        if (!pLine->GetToken(++index, token))
1998
 
                                return false;
1999
 
 
2000
 
                        if (!ParseTime(token, entry))
2001
 
                                return false;
2002
 
 
2003
 
                        // Get filename
2004
 
                        if (!pLine->GetToken(++index, token, 1))
2005
 
                                return false;
2006
 
 
2007
 
                        entry.name = token.GetString();
2008
 
                        char chr = token[token.GetLength() - 1];
2009
 
                        if (chr == '/' || chr == '\\')
2010
 
                        {
2011
 
                                entry.flags |= CDirentry::flag_dir;
2012
 
                                entry.name.RemoveLast();
2013
 
                        }
2014
 
                }
2015
 
                entry.target = _T("");
2016
 
                entry.ownerGroup = _T("");
2017
 
                entry.permissions = _T("");
2018
 
 
2019
 
                if (entry.has_time())
2020
 
                        entry.time.Add(m_timezoneOffset);
2021
 
        }
2022
 
 
2023
 
        return true;
2024
 
}
2025
 
 
2026
 
bool CDirectoryListingParser::AddData(char *pData, int len)
2027
 
{
2028
 
        t_list item;
2029
 
        item.p = pData;
2030
 
        item.len = len;
2031
 
 
2032
 
        m_DataList.push_back(item);
2033
 
 
2034
 
        return ParseData(true);
2035
 
}
2036
 
 
2037
 
bool CDirectoryListingParser::AddLine(const wxChar* pLine)
2038
 
{
2039
 
        if (m_pControlSocket)
2040
 
                m_pControlSocket->LogMessageRaw(RawList, pLine);
2041
 
 
2042
 
        while (*pLine == ' ' || *pLine == '\t')
2043
 
                ++pLine;
2044
 
 
2045
 
        if (!*pLine)
2046
 
                return false;
2047
 
 
2048
 
        const int len = wxStrlen(pLine);
2049
 
 
2050
 
        wxChar* p = new wxChar[len + 1];
2051
 
 
2052
 
        wxStrcpy(p, pLine);
2053
 
 
2054
 
        CLine line(p, len);
2055
 
 
2056
 
        ParseLine(&line, m_server.GetType(), false);
2057
 
 
2058
 
        return true;
2059
 
}
2060
 
 
2061
 
CLine *CDirectoryListingParser::GetLine(bool breakAtEnd /*=false*/, bool &error)
2062
 
{
2063
 
        while (!m_DataList.empty())
2064
 
        {
2065
 
                // Trim empty lines and spaces
2066
 
                std::list<t_list>::iterator iter = m_DataList.begin();
2067
 
                int len = iter->len;
2068
 
                while (iter->p[m_currentOffset]=='\r' || iter->p[m_currentOffset]=='\n' || iter->p[m_currentOffset]==' ' || iter->p[m_currentOffset]=='\t')
2069
 
                {
2070
 
                        ++m_currentOffset;
2071
 
                        if (m_currentOffset >= len)
2072
 
                        {
2073
 
                                delete [] iter->p;
2074
 
                                ++iter;
2075
 
                                m_currentOffset = 0;
2076
 
                                if (iter == m_DataList.end())
2077
 
                                {
2078
 
                                        m_DataList.clear();
2079
 
                                        return 0;
2080
 
                                }
2081
 
                                len = iter->len;
2082
 
                        }
2083
 
                }
2084
 
                m_DataList.erase(m_DataList.begin(), iter);
2085
 
                iter = m_DataList.begin();
2086
 
 
2087
 
                // Remember start offset and find next linebreak
2088
 
                int startpos = m_currentOffset;
2089
 
                int reslen = 0;
2090
 
 
2091
 
                int emptylen = 0;
2092
 
 
2093
 
                int currentOffset = m_currentOffset;
2094
 
                while ((iter->p[currentOffset] != '\n') && (iter->p[currentOffset] != '\r'))
2095
 
                {
2096
 
                        if (iter->p[currentOffset] == ' ' || iter->p[currentOffset] == '\t')
2097
 
                                ++emptylen;
2098
 
                        else
2099
 
                                emptylen = 0;
2100
 
                        ++reslen;
2101
 
 
2102
 
                        ++currentOffset;
2103
 
                        if (currentOffset >= len)
2104
 
                        {
2105
 
                                ++iter;
2106
 
                                if (iter == m_DataList.end())
2107
 
                                {
2108
 
                                        if (reslen > 10000)
2109
 
                                        {
2110
 
                                                m_pControlSocket->LogMessage(::Error, _("Received a line exceeding 10000 characters, aborting."));
2111
 
                                                error = true;
2112
 
                                                return 0;
2113
 
                                        }
2114
 
                                        if (breakAtEnd)
2115
 
                                                return 0;
2116
 
                                        break;
2117
 
                                }
2118
 
                                len = iter->len;
2119
 
                                currentOffset = 0;
2120
 
                        }
2121
 
                }
2122
 
 
2123
 
                if (reslen > 10000)
2124
 
                {
2125
 
                        m_pControlSocket->LogMessage(::Error, _("Received a line exceeding 10000 characters, aborting."));
2126
 
                        error = true;
2127
 
                        return 0;
2128
 
                }
2129
 
                m_currentOffset = currentOffset;
2130
 
 
2131
 
                // Reslen is now the length of the line, including any terminating whitespace
2132
 
                char *res = new char[reslen + 1];
2133
 
                res[reslen] = 0;
2134
 
 
2135
 
                int     respos = 0;
2136
 
 
2137
 
                // Copy line data
2138
 
                std::list<t_list>::iterator i = m_DataList.begin();
2139
 
                while (i != iter && reslen)
2140
 
                {
2141
 
                        int copylen = i->len - startpos;
2142
 
                        if (copylen > reslen)
2143
 
                                copylen = reslen;
2144
 
                        memcpy(&res[respos], &i->p[startpos], copylen);
2145
 
                        reslen -= copylen;
2146
 
                        respos += i->len - startpos;
2147
 
                        startpos = 0;
2148
 
 
2149
 
                        delete [] i->p;
2150
 
                        ++i;
2151
 
                }
2152
 
 
2153
 
                // Copy last chunk
2154
 
                if (iter != m_DataList.end() && reslen)
2155
 
                {
2156
 
                        int copylen = m_currentOffset-startpos;
2157
 
                        if (copylen > reslen)
2158
 
                                copylen = reslen;
2159
 
                        memcpy(&res[respos], &iter->p[startpos], copylen);
2160
 
                        if (reslen >= iter->len)
2161
 
                        {
2162
 
                                delete [] iter->p;
2163
 
                                m_DataList.erase(m_DataList.begin(), ++iter);
2164
 
                        }
2165
 
                        else
2166
 
                                m_DataList.erase(m_DataList.begin(), iter);
2167
 
                }
2168
 
                else
2169
 
                        m_DataList.erase(m_DataList.begin(), iter);
2170
 
 
2171
 
                wxChar* buffer;
2172
 
                if (m_pControlSocket)
2173
 
                {
2174
 
                        buffer = m_pControlSocket->ConvToLocalBuffer(res);
2175
 
                        m_pControlSocket->LogMessageRaw(RawList, buffer);
2176
 
                }
2177
 
                else
2178
 
                {
2179
 
                        wxString str(res, wxConvUTF8);
2180
 
                        if (str.IsEmpty())
2181
 
                        {
2182
 
                                str = wxString(res, wxConvLocal);
2183
 
                                if (str.IsEmpty())
2184
 
                                        str = wxString(res, wxConvISO8859_1);
2185
 
                        }
2186
 
                        buffer = new wxChar[str.Len() + 1];
2187
 
                        wxStrcpy(buffer, str.c_str());
2188
 
                }
2189
 
                delete [] res;
2190
 
 
2191
 
                if (!buffer)
2192
 
                {
2193
 
                        // Line contained no usable data, start over
2194
 
                        continue;
2195
 
                }
2196
 
 
2197
 
                return new CLine(buffer, -1, emptylen);
2198
 
        }
2199
 
 
2200
 
        return 0;
2201
 
}
2202
 
 
2203
 
bool CDirectoryListingParser::ParseAsWfFtp(CLine *pLine, CDirentry &entry)
2204
 
{
2205
 
        int index = 0;
2206
 
        CToken token;
2207
 
 
2208
 
        // Get filename
2209
 
        if (!pLine->GetToken(index++, token))
2210
 
                return false;
2211
 
 
2212
 
        entry.name = token.GetString();
2213
 
 
2214
 
        // Get filesize
2215
 
        if (!pLine->GetToken(index++, token))
2216
 
                return false;
2217
 
 
2218
 
        if (!token.IsNumeric())
2219
 
                return false;
2220
 
 
2221
 
        entry.size = token.GetNumber();
2222
 
 
2223
 
        entry.flags = 0;
2224
 
 
2225
 
        // Parse date
2226
 
        if (!pLine->GetToken(index++, token))
2227
 
                return false;
2228
 
 
2229
 
        if (!ParseShortDate(token, entry))
2230
 
                return false;
2231
 
 
2232
 
        // Unused token
2233
 
        if (!pLine->GetToken(index++, token))
2234
 
                return false;
2235
 
 
2236
 
        if (token.GetString().Right(1) != _T("."))
2237
 
                return false;
2238
 
 
2239
 
        // Parse time
2240
 
        if (!pLine->GetToken(index++, token, true))
2241
 
                return false;
2242
 
 
2243
 
        if (!ParseTime(token, entry))
2244
 
                return false;
2245
 
 
2246
 
        entry.ownerGroup = _T("");
2247
 
        entry.permissions = _T("");
2248
 
 
2249
 
        if (entry.has_time())
2250
 
                entry.time.Add(m_timezoneOffset);
2251
 
 
2252
 
        return true;
2253
 
}
2254
 
 
2255
 
bool CDirectoryListingParser::ParseAsIBM_MVS(CLine *pLine, CDirentry &entry)
2256
 
{
2257
 
        int index = 0;
2258
 
        CToken token;
2259
 
 
2260
 
        // volume
2261
 
        if (!pLine->GetToken(index++, token))
2262
 
                return false;
2263
 
 
2264
 
        // unit
2265
 
        if (!pLine->GetToken(index++, token))
2266
 
                return false;
2267
 
 
2268
 
        // Referred date
2269
 
        if (!pLine->GetToken(index++, token))
2270
 
                return false;
2271
 
 
2272
 
        entry.flags = 0;
2273
 
        if (token.GetString() != _T("**NONE**") && !ParseShortDate(token, entry))
2274
 
        {
2275
 
                // Perhaps of the following type:
2276
 
                // TSO004 3390 VSAM FOO.BAR
2277
 
                if (token.GetString() != _T("VSAM"))
2278
 
                        return false;
2279
 
 
2280
 
                if (!pLine->GetToken(index++, token))
2281
 
                        return false;
2282
 
 
2283
 
                entry.name = token.GetString();
2284
 
                if (entry.name.Find(' ') != -1)
2285
 
                        return false;
2286
 
 
2287
 
                entry.size = -1;
2288
 
                entry.ownerGroup = _T("");
2289
 
                entry.permissions = _T("");
2290
 
 
2291
 
                return true;
2292
 
        }
2293
 
 
2294
 
        // ext
2295
 
        if (!pLine->GetToken(index++, token))
2296
 
                return false;
2297
 
        if (!token.IsNumeric())
2298
 
                return false;
2299
 
 
2300
 
        int prevLen = token.GetLength();
2301
 
 
2302
 
        // used
2303
 
        if (!pLine->GetToken(index++, token))
2304
 
                return false;
2305
 
        if (token.IsNumeric() || token.GetString() == _T("????") || token.GetString() == _T("++++") )
2306
 
        {
2307
 
                // recfm
2308
 
                if (!pLine->GetToken(index++, token))
2309
 
                        return false;
2310
 
                if (token.IsNumeric())
2311
 
                        return false;
2312
 
        }
2313
 
        else
2314
 
        {
2315
 
                if (prevLen < 6)
2316
 
                        return false;
2317
 
        }
2318
 
 
2319
 
        // lrecl
2320
 
        if (!pLine->GetToken(index++, token))
2321
 
                return false;
2322
 
        if (!token.IsNumeric())
2323
 
                return false;
2324
 
 
2325
 
        // blksize
2326
 
        if (!pLine->GetToken(index++, token))
2327
 
                return false;
2328
 
        if (!token.IsNumeric())
2329
 
                return false;
2330
 
 
2331
 
        // dsorg
2332
 
        if (!pLine->GetToken(index++, token))
2333
 
                return false;
2334
 
 
2335
 
        if (token.GetString() == _T("PO") || token.GetString() == _T("PO-E"))
2336
 
        {
2337
 
                entry.flags |= CDirentry::flag_dir;
2338
 
                entry.size = -1;
2339
 
        }
2340
 
        else
2341
 
                entry.size = 100;
2342
 
 
2343
 
        // name of dataset or sequential file
2344
 
        if (!pLine->GetToken(index++, token, true))
2345
 
                return false;
2346
 
 
2347
 
        entry.name = token.GetString();
2348
 
 
2349
 
        entry.ownerGroup = _T("");
2350
 
        entry.permissions = _T("");
2351
 
 
2352
 
        return true;
2353
 
}
2354
 
 
2355
 
bool CDirectoryListingParser::ParseAsIBM_MVS_PDS(CLine *pLine, CDirentry &entry)
2356
 
{
2357
 
        int index = 0;
2358
 
        CToken token;
2359
 
 
2360
 
        // pds member name
2361
 
        if (!pLine->GetToken(index++, token))
2362
 
                return false;
2363
 
        entry.name = token.GetString();
2364
 
 
2365
 
        // vv.mm
2366
 
        if (!pLine->GetToken(index++, token))
2367
 
                return false;
2368
 
 
2369
 
        entry.flags = 0;
2370
 
 
2371
 
        // creation date
2372
 
        if (!pLine->GetToken(index++, token))
2373
 
                return false;
2374
 
        if (!ParseShortDate(token, entry))
2375
 
                return false;
2376
 
 
2377
 
        // modification date
2378
 
        if (!pLine->GetToken(index++, token))
2379
 
                return false;
2380
 
        if (!ParseShortDate(token, entry))
2381
 
                return false;
2382
 
 
2383
 
        // modification time
2384
 
        if (!pLine->GetToken(index++, token))
2385
 
                return false;
2386
 
        if (!ParseTime(token, entry))
2387
 
                return false;
2388
 
 
2389
 
        // size
2390
 
        if (!pLine->GetToken(index++, token))
2391
 
                return false;
2392
 
        if (!token.IsNumeric())
2393
 
                return false;
2394
 
        entry.size = token.GetNumber();
2395
 
 
2396
 
        // init
2397
 
        if (!pLine->GetToken(index++, token))
2398
 
                return false;
2399
 
        if (!token.IsNumeric())
2400
 
                return false;
2401
 
 
2402
 
        // mod
2403
 
        if (!pLine->GetToken(index++, token))
2404
 
                return false;
2405
 
        if (!token.IsNumeric())
2406
 
                return false;
2407
 
 
2408
 
        // id
2409
 
        if (!pLine->GetToken(index++, token, true))
2410
 
                return false;
2411
 
 
2412
 
        entry.ownerGroup = _T("");
2413
 
        entry.permissions = _T("");
2414
 
 
2415
 
        if (entry.has_time())
2416
 
                entry.time.Add(m_timezoneOffset);
2417
 
 
2418
 
        return true;
2419
 
}
2420
 
 
2421
 
bool CDirectoryListingParser::ParseAsIBM_MVS_Migrated(CLine *pLine, CDirentry &entry)
2422
 
{
2423
 
        // Migrated MVS file
2424
 
        // "Migrated                            SOME.NAME"
2425
 
 
2426
 
        int index = 0;
2427
 
        CToken token;
2428
 
        if (!pLine->GetToken(index, token))
2429
 
                return false;
2430
 
 
2431
 
        if (token.GetString().CmpNoCase(_T("Migrated")))
2432
 
                return false;
2433
 
 
2434
 
        if (!pLine->GetToken(++index, token))
2435
 
                return false;
2436
 
 
2437
 
        entry.name = token.GetString();
2438
 
 
2439
 
        entry.flags = 0;
2440
 
        entry.ownerGroup = _T("");
2441
 
        entry.permissions = _T("");
2442
 
        entry.size = -1;
2443
 
 
2444
 
        if (pLine->GetToken(++index, token))
2445
 
                return false;
2446
 
 
2447
 
        return true;
2448
 
}
2449
 
 
2450
 
bool CDirectoryListingParser::ParseAsIBM_MVS_PDS2(CLine *pLine, CDirentry &entry)
2451
 
{
2452
 
        int index = 0;
2453
 
        CToken token;
2454
 
        if (!pLine->GetToken(index, token))
2455
 
                return false;
2456
 
 
2457
 
        entry.name = token.GetString();
2458
 
 
2459
 
        entry.flags = 0;
2460
 
        entry.ownerGroup = _T("");
2461
 
        entry.permissions = _T("");
2462
 
        entry.size = -1;
2463
 
 
2464
 
        if (!pLine->GetToken(++index, token))
2465
 
                return true;
2466
 
 
2467
 
        entry.size = token.GetNumber(CToken::hex);
2468
 
        if (entry.size == -1)
2469
 
                return false;
2470
 
 
2471
 
        // Unused hexadecimal token
2472
 
        if (!pLine->GetToken(++index, token))
2473
 
                return false;
2474
 
        if (!token.IsNumeric(CToken::hex))
2475
 
                return false;
2476
 
 
2477
 
        // Unused numeric token
2478
 
        if (!pLine->GetToken(++index, token))
2479
 
                return false;
2480
 
        if (!token.IsNumeric())
2481
 
                return false;
2482
 
 
2483
 
        int start = ++index;
2484
 
        while (pLine->GetToken(index, token))
2485
 
        {
2486
 
                ++index;
2487
 
        }
2488
 
        if ((index - start < 2))
2489
 
                return false;
2490
 
        --index;
2491
 
 
2492
 
        pLine->GetToken(index, token);
2493
 
        if (!token.IsNumeric() && (token.GetString() != _T("ANY")))
2494
 
                return false;
2495
 
 
2496
 
        pLine->GetToken(index - 1, token);
2497
 
        if (!token.IsNumeric() && (token.GetString() != _T("ANY")))
2498
 
                return false;
2499
 
 
2500
 
        for (int i = start; i < index - 1; ++i)
2501
 
        {
2502
 
                pLine->GetToken(i, token);
2503
 
                int len = token.GetLength();
2504
 
                for (int j = 0; j < len; ++j)
2505
 
                        if (token[j] < 'A' || token[j] > 'Z')
2506
 
                                return false;
2507
 
        }
2508
 
 
2509
 
        return true;
2510
 
}
2511
 
 
2512
 
bool CDirectoryListingParser::ParseAsIBM_MVS_Tape(CLine *pLine, CDirentry &entry)
2513
 
{
2514
 
        int index = 0;
2515
 
        CToken token;
2516
 
 
2517
 
        // volume
2518
 
        if (!pLine->GetToken(index++, token))
2519
 
                return false;
2520
 
 
2521
 
        // unit
2522
 
        if (!pLine->GetToken(index++, token))
2523
 
                return false;
2524
 
 
2525
 
        if (token.GetString().CmpNoCase(_T("Tape")))
2526
 
                return false;
2527
 
 
2528
 
        // dsname
2529
 
        if (!pLine->GetToken(index++, token))
2530
 
                return false;
2531
 
 
2532
 
        entry.name = token.GetString();
2533
 
        entry.flags = 0;
2534
 
        entry.ownerGroup = _T("");
2535
 
        entry.permissions = _T("");
2536
 
        entry.size = -1;
2537
 
        
2538
 
        if (pLine->GetToken(index++, token))
2539
 
                return false;
2540
 
 
2541
 
        return true;
2542
 
}
2543
 
 
2544
 
bool CDirectoryListingParser::ParseComplexFileSize(CToken& token, wxLongLong& size, int blocksize /*=-1*/)
2545
 
{
2546
 
        if (token.IsNumeric())
2547
 
        {
2548
 
                size = token.GetNumber();
2549
 
                if (blocksize != -1)
2550
 
                        size *= blocksize;
2551
 
 
2552
 
                return true;
2553
 
        }
2554
 
 
2555
 
        int len = token.GetLength();
2556
 
 
2557
 
        char last = token[len - 1];
2558
 
        if (last == 'B' || last == 'b')
2559
 
        {
2560
 
                if (len == 1)
2561
 
                        return false;
2562
 
 
2563
 
                char c = token[--len - 1];
2564
 
                if (c < '0' || c > '9')
2565
 
                {
2566
 
                        --len;
2567
 
                        last = c;
2568
 
                }
2569
 
                else
2570
 
                        last = 0;
2571
 
        }
2572
 
        else if (last >= '0' && last <= '9')
2573
 
                last = 0;
2574
 
        else
2575
 
        {
2576
 
                if (--len == 0)
2577
 
                        return false;
2578
 
        }
2579
 
 
2580
 
        size = 0;
2581
 
 
2582
 
        int dot = -1;
2583
 
        for (int i = 0; i < len; ++i)
2584
 
        {
2585
 
                char c = token[i];
2586
 
                if (c >= '0' && c <= '9')
2587
 
                {
2588
 
                        size *= 10;
2589
 
                        size += c - '0';
2590
 
                }
2591
 
                else if (c == '.')
2592
 
                {
2593
 
                        if (dot != -1)
2594
 
                                return false;
2595
 
                        dot = len - i - 1;
2596
 
                }
2597
 
                else
2598
 
                        return false;
2599
 
        }
2600
 
        switch (last)
2601
 
        {
2602
 
        case 'k':
2603
 
        case 'K':
2604
 
                size *= 1024;
2605
 
                break;
2606
 
        case 'm':
2607
 
        case 'M':
2608
 
                size *= 1024 * 1024;
2609
 
                break;
2610
 
        case 'g':
2611
 
        case 'G':
2612
 
                size *= 1024 * 1024 * 1024;
2613
 
                break;
2614
 
        case 't':
2615
 
        case 'T':
2616
 
                size *= 1024 * 1024;
2617
 
                size *= 1024 * 1024;
2618
 
                break;
2619
 
        case 'b':
2620
 
        case 'B':
2621
 
                break;
2622
 
        case 0:
2623
 
                if (blocksize != -1)
2624
 
                        size *= blocksize;
2625
 
                break;
2626
 
        default:
2627
 
                return false;
2628
 
        }
2629
 
        while (dot-- > 0)
2630
 
                size /= 10;
2631
 
 
2632
 
        return true;
2633
 
}
2634
 
 
2635
 
int CDirectoryListingParser::ParseAsMlsd(CLine *pLine, CDirentry &entry)
2636
 
{
2637
 
        // MLSD format as described here: http://www.ietf.org/internet-drafts/draft-ietf-ftpext-mlst-16.txt
2638
 
 
2639
 
        // Parsing is done strict, abort on slightest error.
2640
 
 
2641
 
        CToken token;
2642
 
 
2643
 
        if (!pLine->GetToken(0, token))
2644
 
                return 0;
2645
 
 
2646
 
        wxString facts = token.GetString();
2647
 
        if (facts.IsEmpty())
2648
 
                return 0;
2649
 
 
2650
 
        entry.flags = 0;
2651
 
        entry.size = -1;
2652
 
        entry.ownerGroup = _T("");
2653
 
        entry.permissions = _T("");
2654
 
 
2655
 
        wxString owner, group, uid, gid;
2656
 
 
2657
 
        while (!facts.IsEmpty())
2658
 
        {
2659
 
                int delim = facts.Find(';');
2660
 
                if (delim < 3)
2661
 
                {
2662
 
                        if (delim != -1)
2663
 
                                return 0;
2664
 
                        else
2665
 
                                delim = facts.Len();
2666
 
                }
2667
 
 
2668
 
                int pos = facts.Find('=');
2669
 
                if (pos < 1 || pos > delim)
2670
 
                        return 0;
2671
 
 
2672
 
                wxString factname = facts.Left(pos);
2673
 
                MakeLowerAscii(factname);
2674
 
                wxString value = facts.Mid(pos + 1, delim - pos - 1);
2675
 
                if (factname == _T("type"))
2676
 
                {
2677
 
                        if (!value.CmpNoCase(_T("dir")))
2678
 
                                entry.flags |= CDirentry::flag_dir;
2679
 
                        else if (!value.Left(13).CmpNoCase(_T("OS.unix=slink")))
2680
 
                        {
2681
 
                                entry.flags |= CDirentry::flag_dir | CDirentry::flag_link;
2682
 
                                if (value[13] == ':' && value[14] != 0)
2683
 
                                        entry.target = value.Mid(14);
2684
 
                        }
2685
 
                        else if (!value.CmpNoCase(_T("cdir")) ||
2686
 
                                         !value.CmpNoCase(_T("pdir")))
2687
 
                                return 2;
2688
 
                }
2689
 
                else if (factname == _T("size"))
2690
 
                {
2691
 
                        entry.size = 0;
2692
 
 
2693
 
                        for (unsigned int i = 0; i < value.Len(); ++i)
2694
 
                        {
2695
 
                                if (value[i] < '0' || value[i] > '9')
2696
 
                                        return 0;
2697
 
                                entry.size *= 10;
2698
 
                                entry.size += value[i] - '0';
2699
 
                        }
2700
 
                }
2701
 
                else if (factname == _T("modify") ||
2702
 
                        (!entry.has_date() && factname == _T("create")))
2703
 
                {
2704
 
                        wxDateTime dateTime;
2705
 
                        const wxChar* time = dateTime.ParseFormat(value, _T("%Y%m%d"));
2706
 
 
2707
 
                        if (!time)
2708
 
                                return 0;
2709
 
 
2710
 
                        if (*time)
2711
 
                        {
2712
 
                                if (!dateTime.ParseFormat(time, _T("%H%M%S"), dateTime))
2713
 
                                        return 0;
2714
 
                                entry.flags |= CDirentry::flag_timestamp_date | CDirentry::flag_timestamp_time | CDirentry::flag_timestamp_seconds;
2715
 
                        }
2716
 
                        else
2717
 
                                entry.flags |= CDirentry::flag_timestamp_date;
2718
 
 
2719
 
                        entry.time = dateTime.FromTimezone(wxDateTime::GMT0);
2720
 
                }
2721
 
                else if (factname == _T("perm"))
2722
 
                {
2723
 
                        if (!value.empty())
2724
 
                        {
2725
 
                                if (!entry.permissions.empty())
2726
 
                                        entry.permissions = value + _T(" (") + entry.permissions + _T(")");
2727
 
                                else
2728
 
                                        entry.permissions = value;
2729
 
                        }
2730
 
                }
2731
 
                else if (factname == _T("unix.mode"))
2732
 
                {
2733
 
                        if (!entry.permissions.empty())
2734
 
                                entry.permissions = entry.permissions + _T(" (") + value + _T(")");
2735
 
                        else
2736
 
                                entry.permissions = value;
2737
 
                }
2738
 
                else if (factname == _T("unix.owner") || factname == _T("unix.user"))
2739
 
                        owner = value;
2740
 
                else if (factname == _T("unix.group"))
2741
 
                        group = value;
2742
 
                else if (factname == _T("unix.uid"))
2743
 
                        uid = value;
2744
 
                else if (factname == _T("unix.gid"))
2745
 
                        gid = value;
2746
 
 
2747
 
                facts = facts.Mid(delim + 1);
2748
 
        }
2749
 
 
2750
 
        // The order of the facts is undefined, so assemble ownerGroup in correct
2751
 
        // order
2752
 
        if (!owner.empty())
2753
 
                entry.ownerGroup += owner;
2754
 
        else if (!uid.empty())
2755
 
                entry.ownerGroup += uid;
2756
 
        if (!group.empty())
2757
 
                entry.ownerGroup += _T(" ") + group;
2758
 
        else if (!gid.empty())
2759
 
                entry.ownerGroup += _T(" ") + gid;
2760
 
 
2761
 
        if (!pLine->GetToken(1, token, true, true))
2762
 
                return 0;
2763
 
 
2764
 
        entry.name = token.GetString();
2765
 
 
2766
 
        return 1;
2767
 
}
2768
 
 
2769
 
bool CDirectoryListingParser::ParseAsOS9(CLine *pLine, CDirentry &entry)
2770
 
{
2771
 
        int index = 0;
2772
 
        CToken token;
2773
 
 
2774
 
        // Get owner
2775
 
        if (!pLine->GetToken(index++, token))
2776
 
                return false;
2777
 
 
2778
 
        // Make sure it's number.number
2779
 
        int pos = token.Find('.');
2780
 
        if (pos == -1 || !pos || pos == ((int)token.GetLength() - 1))
2781
 
                return false;
2782
 
 
2783
 
        if (!token.IsNumeric(0, pos))
2784
 
                return false;
2785
 
 
2786
 
        if (!token.IsNumeric(pos + 1, token.GetLength() - pos - 1))
2787
 
                return false;
2788
 
 
2789
 
        entry.ownerGroup = token.GetString();
2790
 
 
2791
 
        entry.flags = 0;
2792
 
 
2793
 
        // Get date
2794
 
        if (!pLine->GetToken(index++, token))
2795
 
                return false;
2796
 
 
2797
 
        if (!ParseShortDate(token, entry, true))
2798
 
                return false;
2799
 
 
2800
 
        // Unused token
2801
 
        if (!pLine->GetToken(index++, token))
2802
 
                return false;
2803
 
 
2804
 
        // Get perms
2805
 
        if (!pLine->GetToken(index++, token))
2806
 
                return false;
2807
 
 
2808
 
        entry.permissions = token.GetString();
2809
 
 
2810
 
        if (token[0] == 'd')
2811
 
                entry.flags |= CDirentry::flag_dir;
2812
 
 
2813
 
        // Unused token
2814
 
        if (!pLine->GetToken(index++, token))
2815
 
                return false;
2816
 
 
2817
 
        // Get Size
2818
 
        if (!pLine->GetToken(index++, token))
2819
 
                return false;
2820
 
 
2821
 
        if (!token.IsNumeric())
2822
 
                return false;
2823
 
 
2824
 
        entry.size = token.GetNumber();
2825
 
 
2826
 
        // Filename
2827
 
        if (!pLine->GetToken(index++, token, true))
2828
 
                return false;
2829
 
 
2830
 
        entry.name = token.GetString();
2831
 
 
2832
 
        return true;
2833
 
}
2834
 
 
2835
 
void CDirectoryListingParser::Reset()
2836
 
{
2837
 
        for (std::list<t_list>::iterator iter = m_DataList.begin(); iter != m_DataList.end(); ++iter)
2838
 
                delete [] iter->p;
2839
 
        m_DataList.clear();
2840
 
 
2841
 
        delete m_prevLine;
2842
 
        m_prevLine = 0;
2843
 
 
2844
 
        m_entryList.clear();
2845
 
        m_fileList.clear();
2846
 
        m_currentOffset = 0;
2847
 
        m_fileListOnly = true;
2848
 
        m_maybeMultilineVms = false;
2849
 
}
2850
 
 
2851
 
bool CDirectoryListingParser::ParseAsZVM(CLine* pLine, CDirentry &entry)
2852
 
{
2853
 
        int index = 0;
2854
 
        CToken token;
2855
 
 
2856
 
        // Get name
2857
 
        if (!pLine->GetToken(index, token))
2858
 
                return false;
2859
 
 
2860
 
        entry.name = token.GetString();
2861
 
 
2862
 
        // Get filename extension
2863
 
        if (!pLine->GetToken(++index, token))
2864
 
                return false;
2865
 
        entry.name += _T(".") + token.GetString();
2866
 
 
2867
 
        // File format. Unused
2868
 
        if (!pLine->GetToken(++index, token))
2869
 
                return false;
2870
 
        wxString format = token.GetString();
2871
 
        if (format != _T("V") && format != _T("F"))
2872
 
                return false;
2873
 
 
2874
 
        // Record length
2875
 
        if (!pLine->GetToken(++index, token))
2876
 
                return false;
2877
 
 
2878
 
        if (!token.IsNumeric())
2879
 
                return false;
2880
 
 
2881
 
        entry.size = token.GetNumber();
2882
 
 
2883
 
        // Number of records
2884
 
        if (!pLine->GetToken(++index, token))
2885
 
                return false;
2886
 
 
2887
 
        if (!token.IsNumeric())
2888
 
                return false;
2889
 
 
2890
 
        entry.size *= token.GetNumber();
2891
 
 
2892
 
        // Unused (Block size?)
2893
 
        if (!pLine->GetToken(++index, token))
2894
 
                return false;
2895
 
 
2896
 
        if (!token.IsNumeric())
2897
 
                return false;
2898
 
 
2899
 
        entry.flags = 0;
2900
 
 
2901
 
        // Date
2902
 
        if (!pLine->GetToken(++index, token))
2903
 
                return false;
2904
 
 
2905
 
        if (!ParseShortDate(token, entry, true))
2906
 
                return false;
2907
 
 
2908
 
        // Time
2909
 
        if (!pLine->GetToken(++index, token))
2910
 
                return false;
2911
 
 
2912
 
        if (!ParseTime(token, entry))
2913
 
                return false;
2914
 
 
2915
 
        // Owner
2916
 
        if (!pLine->GetToken(++index, token))
2917
 
                return false;
2918
 
 
2919
 
        entry.ownerGroup = token.GetString();
2920
 
 
2921
 
        // No further token!
2922
 
        if (pLine->GetToken(++index, token))
2923
 
                return false;
2924
 
 
2925
 
        entry.permissions = _T("");
2926
 
        entry.target = _T("");
2927
 
 
2928
 
        if (entry.has_time())
2929
 
                entry.time.Add(m_timezoneOffset);
2930
 
 
2931
 
        return true;
2932
 
}
2933
 
 
2934
 
bool CDirectoryListingParser::ParseAsHPNonstop(CLine *pLine, CDirentry &entry)
2935
 
{
2936
 
        int index = 0;
2937
 
        CToken token;
2938
 
 
2939
 
        // Get name
2940
 
        if (!pLine->GetToken(index, token))
2941
 
                return false;
2942
 
 
2943
 
        entry.name = token.GetString();
2944
 
 
2945
 
        // File code, numeric, unsuded
2946
 
        if (!pLine->GetToken(++index, token))
2947
 
                return false;
2948
 
        if (!token.IsNumeric())
2949
 
                return false;
2950
 
 
2951
 
        // Size
2952
 
        if (!pLine->GetToken(++index, token))
2953
 
                return false;
2954
 
        if (!token.IsNumeric())
2955
 
                return false;
2956
 
 
2957
 
        entry.size = token.GetNumber();
2958
 
 
2959
 
        entry.flags = 0;
2960
 
 
2961
 
        // Date
2962
 
        if (!pLine->GetToken(++index, token))
2963
 
                return false;
2964
 
        if (!ParseShortDate(token, entry, false))
2965
 
                return false;
2966
 
 
2967
 
        // Time
2968
 
        if (!pLine->GetToken(++index, token))
2969
 
                return false;
2970
 
        if (!ParseTime(token, entry))
2971
 
                return false;
2972
 
 
2973
 
        // Owner
2974
 
        if (!pLine->GetToken(++index, token))
2975
 
                return false;
2976
 
        entry.ownerGroup = token.GetString();
2977
 
 
2978
 
        if (token[token.GetLength() - 1] == ',')
2979
 
        {
2980
 
                // Owner, part 2
2981
 
                if (!pLine->GetToken(++index, token))
2982
 
                        return false;
2983
 
                entry.ownerGroup += _T(" ") + token.GetString();
2984
 
        }
2985
 
 
2986
 
        // Permissions
2987
 
        if (!pLine->GetToken(++index, token))
2988
 
                return false;
2989
 
        entry.permissions = token.GetString();
2990
 
 
2991
 
        // Nothing
2992
 
        if (pLine->GetToken(++index, token))
2993
 
                return false;
2994
 
 
2995
 
        return true;
2996
 
}
2997
 
 
2998
 
bool CDirectoryListingParser::GetMonthFromName(const wxString& name, int &month)
2999
 
{
3000
 
        std::map<wxString, int>::iterator iter = m_MonthNamesMap.find(name.Lower());
3001
 
        if (iter == m_MonthNamesMap.end())
3002
 
        {
3003
 
                wxString lower(name);
3004
 
                MakeLowerAscii(lower);
3005
 
                iter = m_MonthNamesMap.find(lower);
3006
 
                if (iter == m_MonthNamesMap.end())
3007
 
                        return false;
3008
 
        }
3009
 
        
3010
 
        month = iter->second;
3011
 
        
3012
 
        return true;
3013
 
}