~ubuntu-branches/ubuntu/precise/p7zip/precise-updates

« back to all changes in this revision

Viewing changes to CPP/7zip/UI/FileManager/FSFolder.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mohammed Adnène Trojette
  • Date: 2009-02-14 20:12:27 UTC
  • mfrom: (1.1.11 upstream) (2.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090214201227-go63qxm9ozfdma60
Tags: 4.65~dfsg.1-1
* New upstream release.
* Remove wx2.8 Build-Depends added by mistakes (7zG is not yet
  intended to be built).
* Use dh_clean without -k.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// FSFolder.cpp
 
2
 
 
3
#include "StdAfx.h"
 
4
 
 
5
#include "FSFolder.h"
 
6
 
 
7
#include "Common/StringConvert.h"
 
8
#include "Common/UTFConvert.h"
 
9
#include "Common/ComTry.h"
 
10
 
 
11
#include "Windows/Defs.h"
 
12
#include "Windows/PropVariant.h"
 
13
#include "Windows/FileDir.h"
 
14
#include "Windows/FileIO.h"
 
15
 
 
16
#include "../../PropID.h"
 
17
 
 
18
#include "SysIconUtils.h"
 
19
#ifdef _WIN32
 
20
#include "FSDrives.h"
 
21
#include "NetFolder.h"
 
22
#endif
 
23
 
 
24
namespace NWindows {
 
25
namespace NFile {
 
26
 
 
27
bool GetLongPath(LPCWSTR path, UString &longPath);
 
28
 
 
29
}}
 
30
 
 
31
using namespace NWindows;
 
32
using namespace NFile;
 
33
using namespace NFind;
 
34
 
 
35
namespace NFsFolder {
 
36
 
 
37
static STATPROPSTG kProperties[] =
 
38
{
 
39
  { NULL, kpidName, VT_BSTR},
 
40
  // { NULL, kpidIsDir, VT_BOOL},
 
41
  { NULL, kpidSize, VT_UI8},
 
42
  { NULL, kpidMTime, VT_FILETIME},
 
43
  { NULL, kpidCTime, VT_FILETIME},
 
44
  { NULL, kpidATime, VT_FILETIME},
 
45
  { NULL, kpidAttrib, VT_UI4},
 
46
  { NULL, kpidPackSize, VT_UI8},
 
47
  { NULL, kpidComment, VT_BSTR},
 
48
  { NULL, kpidPrefix, VT_BSTR}
 
49
};
 
50
 
 
51
HRESULT CFSFolder::Init(const UString &path, IFolderFolder *parentFolder)
 
52
{
 
53
  _parentFolder = parentFolder;
 
54
  _path = path;
 
55
 
 
56
#ifdef _WIN32
 
57
  _findChangeNotification.FindFirst(_path, false,
 
58
      FILE_NOTIFY_CHANGE_FILE_NAME |
 
59
      FILE_NOTIFY_CHANGE_DIR_NAME |
 
60
      FILE_NOTIFY_CHANGE_ATTRIBUTES |
 
61
      FILE_NOTIFY_CHANGE_SIZE |
 
62
      FILE_NOTIFY_CHANGE_LAST_WRITE /*|
 
63
      FILE_NOTIFY_CHANGE_LAST_ACCESS |
 
64
      FILE_NOTIFY_CHANGE_CREATION |
 
65
      FILE_NOTIFY_CHANGE_SECURITY */);
 
66
  if (!_findChangeNotification.IsHandleAllocated())
 
67
  {
 
68
    DWORD lastError = GetLastError();
 
69
    CFindFile findFile;
 
70
    CFileInfoW fileInfo;
 
71
    if (!findFile.FindFirst(_path + UString(L"*"), fileInfo))
 
72
      return lastError;
 
73
  }
 
74
#endif
 
75
  return S_OK;
 
76
}
 
77
 
 
78
HRESULT GetFolderSize(const UString &path, UInt64 &numFolders, UInt64 &numFiles, UInt64 &size, IProgress *progress)
 
79
{
 
80
  RINOK(progress->SetCompleted(NULL));
 
81
  numFiles = numFolders = size = 0;
 
82
  CEnumeratorW enumerator(path + UString(WSTRING_PATH_SEPARATOR L"*"));
 
83
  CFileInfoW fileInfo;
 
84
  while (enumerator.Next(fileInfo))
 
85
  {
 
86
    if (fileInfo.IsDir())
 
87
    {
 
88
      UInt64 subFolders, subFiles, subSize;
 
89
      RINOK(GetFolderSize(path + UString(WSTRING_PATH_SEPARATOR) + fileInfo.Name, subFolders, subFiles, subSize, progress));
 
90
      numFolders += subFolders;
 
91
      numFolders++;
 
92
      numFiles += subFiles;
 
93
      size += subSize;
 
94
    }
 
95
    else
 
96
    {
 
97
      numFiles++;
 
98
      size += fileInfo.Size;
 
99
    }
 
100
  }
 
101
  return S_OK;
 
102
}
 
103
 
 
104
HRESULT CFSFolder::LoadSubItems(CDirItem &dirItem, const UString &path)
 
105
{
 
106
  {
 
107
    CEnumeratorW enumerator(path + L"*");
 
108
    CDirItem fileInfo;
 
109
    while (enumerator.Next(fileInfo))
 
110
    {
 
111
      fileInfo.CompressedSizeIsDefined = false;
 
112
      /*
 
113
      if (!GetCompressedFileSize(_path + fileInfo.Name,
 
114
      fileInfo.CompressedSize))
 
115
      fileInfo.CompressedSize = fileInfo.Size;
 
116
      */
 
117
      if (fileInfo.IsDir())
 
118
      {
 
119
        // fileInfo.Size = GetFolderSize(_path + fileInfo.Name);
 
120
        fileInfo.Size = 0;
 
121
      }
 
122
      dirItem.Files.Add(fileInfo);
 
123
    }
 
124
  }
 
125
  if (!_flatMode)
 
126
    return S_OK;
 
127
 
 
128
  for (int i = 0; i < dirItem.Files.Size(); i++)
 
129
  {
 
130
    CDirItem &item = dirItem.Files[i];
 
131
    if (item.IsDir())
 
132
      LoadSubItems(item, path + item.Name + WCHAR_PATH_SEPARATOR);
 
133
  }
 
134
  return S_OK;
 
135
}
 
136
 
 
137
void CFSFolder::AddRefs(CDirItem &dirItem)
 
138
{
 
139
  int i;
 
140
  for (i = 0; i < dirItem.Files.Size(); i++)
 
141
  {
 
142
    CDirItem &item = dirItem.Files[i];
 
143
    item.Parent = &dirItem;
 
144
    _refs.Add(&item);
 
145
  }
 
146
  if (!_flatMode)
 
147
    return;
 
148
  for (i = 0; i < dirItem.Files.Size(); i++)
 
149
  {
 
150
    CDirItem &item = dirItem.Files[i];
 
151
    if (item.IsDir())
 
152
      AddRefs(item);
 
153
  }
 
154
}
 
155
 
 
156
STDMETHODIMP CFSFolder::LoadItems()
 
157
{
 
158
  // OutputDebugString(TEXT("Start\n"));
 
159
  INT32 dummy;
 
160
  WasChanged(&dummy);
 
161
  Clear();
 
162
  RINOK(LoadSubItems(_root, _path));
 
163
  AddRefs(_root);
 
164
 
 
165
  // OutputDebugString(TEXT("Finish\n"));
 
166
  _commentsAreLoaded = false;
 
167
  return S_OK;
 
168
}
 
169
 
 
170
static const wchar_t *kDescriptionFileName = L"descript.ion";
 
171
 
 
172
bool CFSFolder::LoadComments()
 
173
{
 
174
  if (_commentsAreLoaded)
 
175
    return true;
 
176
  _comments.Clear();
 
177
  _commentsAreLoaded = true;
 
178
  NIO::CInFile file;
 
179
  if (!file.Open(_path + kDescriptionFileName))
 
180
    return false;
 
181
  UInt64 length;
 
182
  if (!file.GetLength(length))
 
183
    return false;
 
184
  if (length >= (1 << 28))
 
185
    return false;
 
186
  AString s;
 
187
  char *p = s.GetBuffer((int)((size_t)length + 1));
 
188
  UInt32 processedSize;
 
189
  file.Read(p, (UInt32)length, processedSize);
 
190
  p[length] = 0;
 
191
  s.ReleaseBuffer();
 
192
  if (processedSize != length)
 
193
    return false;
 
194
  file.Close();
 
195
  UString unicodeString;
 
196
  if (!ConvertUTF8ToUnicode(s, unicodeString))
 
197
    return false;
 
198
  return _comments.ReadFromString(unicodeString);
 
199
}
 
200
 
 
201
static bool IsAscii(const UString &testString)
 
202
{
 
203
  for (int i = 0; i < testString.Length(); i++)
 
204
    if (testString[i] >= 0x80)
 
205
      return false;
 
206
  return true;
 
207
}
 
208
 
 
209
bool CFSFolder::SaveComments()
 
210
{
 
211
  NIO::COutFile file;
 
212
  if (!file.Create(_path + kDescriptionFileName, true))
 
213
    return false;
 
214
  UString unicodeString;
 
215
  _comments.SaveToString(unicodeString);
 
216
  AString utfString;
 
217
  ConvertUnicodeToUTF8(unicodeString, utfString);
 
218
  UInt32 processedSize;
 
219
  if (!IsAscii(unicodeString))
 
220
  {
 
221
    Byte bom [] = { 0xEF, 0xBB, 0xBF, 0x0D, 0x0A };
 
222
    file.Write(bom , sizeof(bom), processedSize);
 
223
  }
 
224
  file.Write(utfString, utfString.Length(), processedSize);
 
225
  _commentsAreLoaded = false;
 
226
  return true;
 
227
}
 
228
 
 
229
STDMETHODIMP CFSFolder::GetNumberOfItems(UInt32 *numItems)
 
230
{
 
231
  *numItems = _refs.Size();
 
232
  return S_OK;
 
233
}
 
234
 
 
235
/*
 
236
STDMETHODIMP CFSFolder::GetNumberOfSubFolders(UInt32 *numSubFolders)
 
237
{
 
238
  UInt32 numSubFoldersLoc = 0;
 
239
  for (int i = 0; i < _files.Size(); i++)
 
240
    if (_files[i].IsDir())
 
241
      numSubFoldersLoc++;
 
242
  *numSubFolders = numSubFoldersLoc;
 
243
  return S_OK;
 
244
}
 
245
*/
 
246
 
 
247
#ifdef _WIN32
 
248
bool MyGetCompressedFileSizeW(LPCWSTR fileName, UInt64 &size)
 
249
{
 
250
  DWORD highPart;
 
251
  DWORD lowPart = ::GetCompressedFileSizeW(fileName, &highPart);
 
252
  if (lowPart == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR)
 
253
  {
 
254
    #ifdef WIN_LONG_PATH
 
255
    {
 
256
      UString longPath;
 
257
      if (GetLongPath(fileName, longPath))
 
258
        lowPart = ::GetCompressedFileSizeW(longPath, &highPart);
 
259
    }
 
260
    #endif
 
261
    if (lowPart == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR)
 
262
      return false;
 
263
  }
 
264
  size = (UInt64(highPart) << 32) | lowPart;
 
265
  return true;
 
266
}
 
267
#endif
 
268
 
 
269
STDMETHODIMP CFSFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)
 
270
{
 
271
  NCOM::CPropVariant prop;
 
272
  if (itemIndex >= (UInt32)_refs.Size())
 
273
    return E_INVALIDARG;
 
274
  CDirItem &fileInfo = *_refs[itemIndex];
 
275
  switch(propID)
 
276
  {
 
277
    case kpidIsDir:  prop = fileInfo.IsDir(); break;
 
278
    case kpidName:  prop = fileInfo.Name; break;
 
279
    case kpidSize:  if (!fileInfo.IsDir()) prop = fileInfo.Size; break;
 
280
    case kpidPackSize:
 
281
      if (!fileInfo.CompressedSizeIsDefined)
 
282
      {
 
283
        fileInfo.CompressedSizeIsDefined = true;
 
284
#ifdef _WIN32
 
285
        if (fileInfo.IsDir () ||
 
286
            !MyGetCompressedFileSizeW(_path + GetRelPath(fileInfo), fileInfo.CompressedSize))
 
287
#endif
 
288
          fileInfo.CompressedSize = fileInfo.Size;
 
289
      }
 
290
      prop = fileInfo.CompressedSize;
 
291
      break;
 
292
    case kpidAttrib: prop = (UInt32)fileInfo.Attrib; break;
 
293
    case kpidCTime: prop = fileInfo.CTime; break;
 
294
    case kpidATime: prop = fileInfo.ATime; break;
 
295
    case kpidMTime: prop = fileInfo.MTime; break;
 
296
    case kpidComment:
 
297
    {
 
298
      LoadComments();
 
299
      UString comment;
 
300
      if (_comments.GetValue(GetRelPath(fileInfo), comment))
 
301
        prop = comment;
 
302
      break;
 
303
    }
 
304
    case kpidPrefix:
 
305
    {
 
306
      if (_flatMode)
 
307
      {
 
308
        prop = GetPrefix(fileInfo);
 
309
      }
 
310
      break;
 
311
    }
 
312
  }
 
313
  prop.Detach(value);
 
314
  return S_OK;
 
315
}
 
316
 
 
317
HRESULT CFSFolder::BindToFolderSpec(const wchar_t *name, IFolderFolder **resultFolder)
 
318
{
 
319
  *resultFolder = 0;
 
320
  CFSFolder *folderSpec = new CFSFolder;
 
321
  CMyComPtr<IFolderFolder> subFolder = folderSpec;
 
322
  RINOK(folderSpec->Init(_path + name + UString(WCHAR_PATH_SEPARATOR), 0));
 
323
  *resultFolder = subFolder.Detach();
 
324
  return S_OK;
 
325
}
 
326
 
 
327
UString CFSFolder::GetPrefix(const CDirItem &item) const
 
328
{
 
329
  UString path;
 
330
  CDirItem *cur = item.Parent;
 
331
  while (cur->Parent != 0)
 
332
  {
 
333
    path = cur->Name + UString(WCHAR_PATH_SEPARATOR) + path;
 
334
    cur = cur->Parent;
 
335
  }
 
336
  return path;
 
337
}
 
338
 
 
339
UString CFSFolder::GetRelPath(const CDirItem &item) const
 
340
{
 
341
  return GetPrefix(item) + item.Name;
 
342
}
 
343
 
 
344
STDMETHODIMP CFSFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)
 
345
{
 
346
  *resultFolder = 0;
 
347
  const CDirItem &fileInfo = *_refs[index];
 
348
  if (!fileInfo.IsDir())
 
349
    return E_INVALIDARG;
 
350
  return BindToFolderSpec(GetRelPath(fileInfo), resultFolder);
 
351
}
 
352
 
 
353
STDMETHODIMP CFSFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)
 
354
{
 
355
  return BindToFolderSpec(name, resultFolder);
 
356
}
 
357
 
 
358
STDMETHODIMP CFSFolder::BindToParentFolder(IFolderFolder **resultFolder)
 
359
{
 
360
  *resultFolder = 0;
 
361
  if (_parentFolder)
 
362
  {
 
363
    CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
 
364
    *resultFolder = parentFolder.Detach();
 
365
    return S_OK;
 
366
  }
 
367
  if (_path.IsEmpty())
 
368
    return E_INVALIDARG;
 
369
  printf("CFSFolder::BindToParentFolder path='%ls'\n",(const wchar_t *)_path);
 
370
  int pos = _path.ReverseFind(WCHAR_PATH_SEPARATOR);
 
371
  if (pos < 0 || pos != _path.Length() - 1)
 
372
    return E_FAIL;
 
373
  UString parentPath = _path.Left(pos);
 
374
  printf("CFSFolder::BindToParentFolder parentPath='%ls'\n",(const wchar_t *)parentPath);
 
375
  pos = parentPath.ReverseFind(WCHAR_PATH_SEPARATOR);
 
376
  if (pos < 0)
 
377
  {
 
378
#ifdef _WIN32
 
379
    parentPath.Empty();
 
380
    CFSDrives *drivesFolderSpec = new CFSDrives;
 
381
    CMyComPtr<IFolderFolder> drivesFolder = drivesFolderSpec;
 
382
    drivesFolderSpec->Init();
 
383
    *resultFolder = drivesFolder.Detach();
 
384
#else
 
385
    parentPath = WSTRING_PATH_SEPARATOR;
 
386
    CFSFolder *parentFolderSpec = new CFSFolder;
 
387
    CMyComPtr<IFolderFolder> parentFolder = parentFolderSpec;
 
388
    printf("CFSFolder::BindToParentFolder Init-0 with parentPath='%ls'\n",(const wchar_t *)parentPath);
 
389
    RINOK(parentFolderSpec->Init(parentPath, 0));
 
390
    *resultFolder = parentFolder.Detach();
 
391
#endif
 
392
    return S_OK;
 
393
  }
 
394
  UString parentPathReduced = parentPath.Left(pos);
 
395
  parentPath = parentPath.Left(pos + 1);
 
396
  pos = parentPathReduced.ReverseFind(WCHAR_PATH_SEPARATOR);
 
397
  if (pos == 1)
 
398
  {
 
399
#ifdef _WIN32
 
400
    if (parentPath[0] != WCHAR_PATH_SEPARATOR)
 
401
      return E_FAIL;
 
402
    CNetFolder *netFolderSpec = new CNetFolder;
 
403
    CMyComPtr<IFolderFolder> netFolder = netFolderSpec;
 
404
    netFolderSpec->Init(parentPath);
 
405
    *resultFolder = netFolder.Detach();
 
406
#else
 
407
    parentPath = WSTRING_PATH_SEPARATOR;
 
408
    CFSFolder *parentFolderSpec = new CFSFolder;
 
409
    CMyComPtr<IFolderFolder> parentFolder = parentFolderSpec;
 
410
    printf("CFSFolder::BindToParentFolder Init-1 with parentPath='%ls'\n",(const wchar_t *)parentPath);
 
411
    RINOK(parentFolderSpec->Init(parentPath, 0));
 
412
    *resultFolder = parentFolder.Detach();
 
413
#endif // ifdef _WIN32
 
414
    return S_OK;
 
415
  }
 
416
  CFSFolder *parentFolderSpec = new CFSFolder;
 
417
  CMyComPtr<IFolderFolder> parentFolder = parentFolderSpec;
 
418
  printf("CFSFolder::BindToParentFolder Init-2 with parentPath='%ls'\n",(const wchar_t *)parentPath);
 
419
  RINOK(parentFolderSpec->Init(parentPath, 0));
 
420
  *resultFolder = parentFolder.Detach();
 
421
  return S_OK;
 
422
}
 
423
 
 
424
STDMETHODIMP CFSFolder::GetNumberOfProperties(UInt32 *numProperties)
 
425
{
 
426
  *numProperties = sizeof(kProperties) / sizeof(kProperties[0]);
 
427
  if (!_flatMode)
 
428
    (*numProperties)--;
 
429
  return S_OK;
 
430
}
 
431
 
 
432
STDMETHODIMP CFSFolder::GetPropertyInfo(UInt32 index,
 
433
    BSTR *name, PROPID *propID, VARTYPE *varType)
 
434
{
 
435
  if (index >= sizeof(kProperties) / sizeof(kProperties[0]))
 
436
    return E_INVALIDARG;
 
437
  const STATPROPSTG &prop = kProperties[index];
 
438
  *propID = prop.propid;
 
439
  *varType = prop.vt;
 
440
  *name = 0;
 
441
  return S_OK;
 
442
}
 
443
 
 
444
 
 
445
STDMETHODIMP CFSFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)
 
446
{
 
447
  COM_TRY_BEGIN
 
448
  NWindows::NCOM::CPropVariant prop;
 
449
  switch(propID)
 
450
  {
 
451
    case kpidType: prop = L"FSFolder"; break;
 
452
    case kpidPath: prop = _path; break;
 
453
  }
 
454
  prop.Detach(value);
 
455
  return S_OK;
 
456
  COM_TRY_END
 
457
}
 
458
 
 
459
STDMETHODIMP CFSFolder::WasChanged(INT32 *wasChanged)
 
460
{
 
461
  bool wasChangedMain = false;
 
462
#ifdef _WIN32
 
463
  for (;;)
 
464
  {
 
465
    if (!_findChangeNotification.IsHandleAllocated())
 
466
    {
 
467
      *wasChanged = BoolToInt(false);
 
468
      return S_OK;
 
469
    }
 
470
 
 
471
    DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0);
 
472
    bool wasChangedLoc = (waitResult == WAIT_OBJECT_0);
 
473
    if (wasChangedLoc)
 
474
    {
 
475
      _findChangeNotification.FindNext();
 
476
      wasChangedMain = true;
 
477
    }
 
478
    else
 
479
      break;
 
480
  }
 
481
#endif
 
482
  *wasChanged = BoolToInt(wasChangedMain);
 
483
  return S_OK;
 
484
}
 
485
 
 
486
STDMETHODIMP CFSFolder::Clone(IFolderFolder **resultFolder)
 
487
{
 
488
  CFSFolder *fsFolderSpec = new CFSFolder;
 
489
  CMyComPtr<IFolderFolder> folderNew = fsFolderSpec;
 
490
  fsFolderSpec->Init(_path, 0);
 
491
  *resultFolder = folderNew.Detach();
 
492
  return S_OK;
 
493
}
 
494
 
 
495
HRESULT CFSFolder::GetItemsFullSize(const UInt32 *indices, UInt32 numItems,
 
496
    UInt64 &numFolders, UInt64 &numFiles, UInt64 &size, IProgress *progress)
 
497
{
 
498
  numFiles = numFolders = size = 0;
 
499
  UInt32 i;
 
500
  for (i = 0; i < numItems; i++)
 
501
  {
 
502
    int index = indices[i];
 
503
    if (index >= _refs.Size())
 
504
      return E_INVALIDARG;
 
505
    const CDirItem &fileInfo = *_refs[index];
 
506
    if (fileInfo.IsDir())
 
507
    {
 
508
      UInt64 subFolders, subFiles, subSize;
 
509
      RINOK(GetFolderSize(_path + GetRelPath(fileInfo), subFolders, subFiles, subSize, progress));
 
510
      numFolders += subFolders;
 
511
      numFolders++;
 
512
      numFiles += subFiles;
 
513
      size += subSize;
 
514
    }
 
515
    else
 
516
    {
 
517
      numFiles++;
 
518
      size += fileInfo.Size;
 
519
    }
 
520
  }
 
521
  return S_OK;
 
522
}
 
523
 
 
524
HRESULT CFSFolder::GetItemFullSize(int index, UInt64 &size, IProgress *progress)
 
525
{
 
526
  const CDirItem &fileInfo = *_refs[index];
 
527
  if (fileInfo.IsDir())
 
528
  {
 
529
    /*
 
530
    CMyComPtr<IFolderFolder> subFolder;
 
531
    RINOK(BindToFolder(index, &subFolder));
 
532
    CMyComPtr<IFolderReload> aFolderReload;
 
533
    subFolder.QueryInterface(&aFolderReload);
 
534
    aFolderReload->Reload();
 
535
    UInt32 numItems;
 
536
    RINOK(subFolder->GetNumberOfItems(&numItems));
 
537
    CMyComPtr<IFolderGetItemFullSize> aGetItemFullSize;
 
538
    subFolder.QueryInterface(&aGetItemFullSize);
 
539
    for (UInt32 i = 0; i < numItems; i++)
 
540
    {
 
541
      UInt64 size;
 
542
      RINOK(aGetItemFullSize->GetItemFullSize(i, &size));
 
543
      *totalSize += size;
 
544
    }
 
545
    */
 
546
    UInt64 numFolders, numFiles;
 
547
    return GetFolderSize(_path + GetRelPath(fileInfo), numFolders, numFiles, size, progress);
 
548
  }
 
549
  size = fileInfo.Size;
 
550
  return S_OK;
 
551
}
 
552
 
 
553
STDMETHODIMP CFSFolder::GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress *progress)
 
554
{
 
555
  NCOM::CPropVariant prop;
 
556
  if (index >= (UInt32)_refs.Size())
 
557
    return E_INVALIDARG;
 
558
  UInt64 size = 0;
 
559
  HRESULT result = GetItemFullSize(index, size, progress);
 
560
  prop = size;
 
561
  prop.Detach(value);
 
562
  return result;
 
563
}
 
564
 
 
565
HRESULT CFSFolder::GetComplexName(const wchar_t *name, UString &resultPath)
 
566
{
 
567
  UString newName = name;
 
568
  resultPath = _path + newName;
 
569
  if (newName.Length() < 1)
 
570
    return S_OK;
 
571
  if (newName[0] == WCHAR_PATH_SEPARATOR)
 
572
  {
 
573
    resultPath = newName;
 
574
    return S_OK;
 
575
  }
 
576
  if (newName.Length() < 2)
 
577
    return S_OK;
 
578
  if (newName[1] == L':')
 
579
    resultPath = newName;
 
580
  return S_OK;
 
581
}
 
582
 
 
583
STDMETHODIMP CFSFolder::CreateFolder(const wchar_t *name, IProgress * /* progress */)
 
584
{
 
585
  UString processedName;
 
586
  RINOK(GetComplexName(name, processedName));
 
587
  if(NDirectory::MyCreateDirectory(processedName))
 
588
    return S_OK;
 
589
  if(::GetLastError() == ERROR_ALREADY_EXISTS)
 
590
    return ::GetLastError();
 
591
  if (!NDirectory::CreateComplexDirectory(processedName))
 
592
    return ::GetLastError();
 
593
  return S_OK;
 
594
}
 
595
 
 
596
STDMETHODIMP CFSFolder::CreateFile(const wchar_t *name, IProgress * /* progress */)
 
597
{
 
598
  UString processedName;
 
599
  RINOK(GetComplexName(name, processedName));
 
600
  NIO::COutFile outFile;
 
601
  if (!outFile.Create(processedName, false))
 
602
    return ::GetLastError();
 
603
  return S_OK;
 
604
}
 
605
 
 
606
STDMETHODIMP CFSFolder::Rename(UInt32 index, const wchar_t *newName, IProgress * /* progress */)
 
607
{
 
608
  const CDirItem &fileInfo = *_refs[index];
 
609
  const UString fullPrefix = _path + GetPrefix(fileInfo);
 
610
  if (!NDirectory::MyMoveFile(fullPrefix + fileInfo.Name, fullPrefix + newName))
 
611
    return GetLastError();
 
612
  return S_OK;
 
613
}
 
614
 
 
615
STDMETHODIMP CFSFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress)
 
616
{
 
617
#ifdef _WIN32
 
618
  RINOK(progress->SetTotal(numItems));
 
619
  for (UInt32 i = 0; i < numItems; i++)
 
620
  {
 
621
    const CDirItem &fileInfo = *_refs[indices[i]];
 
622
    const UString fullPath = _path + GetRelPath(fileInfo);
 
623
    bool result;
 
624
    if (fileInfo.IsDir())
 
625
      result = NDirectory::RemoveDirectoryWithSubItems(fullPath);
 
626
    else
 
627
      result = NDirectory::DeleteFileAlways(fullPath);
 
628
    if (!result)
 
629
      return GetLastError();
 
630
    UInt64 completed = i;
 
631
    RINOK(progress->SetCompleted(&completed));
 
632
  }
 
633
#endif
 
634
  return S_OK;
 
635
}
 
636
 
 
637
STDMETHODIMP CFSFolder::SetProperty(UInt32 index, PROPID propID,
 
638
    const PROPVARIANT *value, IProgress * /* progress */)
 
639
{
 
640
  if (index >= (UInt32)_refs.Size())
 
641
    return E_INVALIDARG;
 
642
  CDirItem &fileInfo = *_refs[index];
 
643
  if (fileInfo.Parent->Parent != 0)
 
644
    return E_NOTIMPL;
 
645
  switch(propID)
 
646
  {
 
647
    case kpidComment:
 
648
    {
 
649
      UString filename = fileInfo.Name;
 
650
      filename.Trim();
 
651
      if (value->vt == VT_EMPTY)
 
652
        _comments.DeletePair(filename);
 
653
      else if (value->vt == VT_BSTR)
 
654
      {
 
655
        CTextPair pair;
 
656
        pair.ID = filename;
 
657
        pair.ID.Trim();
 
658
        pair.Value = value->bstrVal;
 
659
        pair.Value.Trim();
 
660
        if (pair.Value.IsEmpty())
 
661
          _comments.DeletePair(filename);
 
662
        else
 
663
          _comments.AddPair(pair);
 
664
      }
 
665
      else
 
666
        return E_INVALIDARG;
 
667
      SaveComments();
 
668
      break;
 
669
    }
 
670
    default:
 
671
      return E_NOTIMPL;
 
672
  }
 
673
  return S_OK;
 
674
}
 
675
 
 
676
STDMETHODIMP CFSFolder::GetSystemIconIndex(UInt32 index, INT32 *iconIndex)
 
677
{
 
678
#ifdef _WIN32
 
679
  if (index >= (UInt32)_refs.Size())
 
680
    return E_INVALIDARG;
 
681
  const CDirItem &fileInfo = *_refs[index];
 
682
  *iconIndex = 0;
 
683
  int iconIndexTemp;
 
684
  if (GetRealIconIndex(_path + GetRelPath(fileInfo), fileInfo.Attributes, iconIndexTemp) != 0)
 
685
  {
 
686
    *iconIndex = iconIndexTemp;
 
687
    return S_OK;
 
688
  }
 
689
  return GetLastError();
 
690
#endif
 
691
  *iconIndex = 0;
 
692
    return S_OK;
 
693
}
 
694
 
 
695
STDMETHODIMP CFSFolder::SetFlatMode(Int32 flatMode)
 
696
{
 
697
  _flatMode = IntToBool(flatMode);
 
698
  return S_OK;
 
699
}
 
700
 
 
701
}