~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/modules/plugin/tools/XPIPackager/ZipCentralDir.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ZipCentralDir.cpp: implementation of the CZipCentralDir class.
 
2
//
 
3
////////////////////////////////////////////////////////////////////////////////
 
4
//  Copyright (C) 2000 Tadeusz Dracz.
 
5
//  For conditions of distribution and use, see copyright notice in ZipArchive.h
 
6
////////////////////////////////////////////////////////////////////////////////
 
7
 
 
8
 
 
9
#include "stdafx.h"
 
10
#include "ZipCentralDir.h"
 
11
#include "ZipArchive.h"
 
12
 
 
13
struct CZipAutoHandle
 
14
{
 
15
        HANDLE m_hFileMap;
 
16
        LPVOID m_pFileMap;
 
17
        CZipAutoHandle()
 
18
        {
 
19
                m_hFileMap = NULL;
 
20
                m_pFileMap = NULL;
 
21
        }
 
22
        bool CreateMapping(HANDLE hFile)
 
23
        {
 
24
                m_hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,
 
25
                        0, 0, _T("ZipArchive Mapping File"));
 
26
                if (!m_hFileMap)
 
27
                        return false;
 
28
                // Get pointer to memory representing file
 
29
                m_pFileMap = MapViewOfFile(m_hFileMap, FILE_MAP_WRITE, 0, 0, 0);
 
30
                return (m_pFileMap != NULL);
 
31
        }
 
32
        void RemoveMapping()
 
33
        {
 
34
                if (m_pFileMap)
 
35
                {
 
36
                        UnmapViewOfFile(m_pFileMap);
 
37
                        m_pFileMap = NULL;
 
38
                }
 
39
                if (m_hFileMap)
 
40
                {
 
41
                        CloseHandle(m_hFileMap);
 
42
                        m_hFileMap = NULL;
 
43
                }
 
44
                
 
45
        }
 
46
        ~CZipAutoHandle()
 
47
        {
 
48
                RemoveMapping();
 
49
        }
 
50
};
 
51
 
 
52
#define ZIPCENTRALDIRSIZE       22
 
53
 
 
54
//////////////////////////////////////////////////////////////////////
 
55
// Construction/Destruction
 
56
char CZipCentralDir::m_gszSignature[] = {0x50, 0x4b, 0x05, 0x06};
 
57
CZipCentralDir::CZipCentralDir()
 
58
{
 
59
        m_bConvertAfterOpen  = true;
 
60
        m_bFindFastEnabled = false;
 
61
        m_pStorage = NULL;
 
62
        m_pOpenedFile = NULL;
 
63
        m_iBufferSize = 32768;
 
64
        
 
65
}
 
66
 
 
67
void CZipCentralDir::Init()
 
68
{
 
69
        m_bOnDisk = false;
 
70
        m_uBytesBeforeZip = m_uCentrDirPos = 0;
 
71
        m_pOpenedFile = NULL;
 
72
        m_pszComment.Release();
 
73
}
 
74
 
 
75
CZipCentralDir::~CZipCentralDir()
 
76
{
 
77
        Clear();
 
78
}
 
79
 
 
80
void CZipCentralDir::Read()
 
81
{
 
82
        ASSERT(m_pStorage);
 
83
        WORD uCommentSize;
 
84
        m_uCentrDirPos = Locate();
 
85
        m_pStorage->m_pFile->Seek(m_uCentrDirPos, CFile::begin);
 
86
        CZipAutoBuffer buf(ZIPCENTRALDIRSIZE);
 
87
        DWORD uRead = m_pStorage->m_pFile->Read(buf, ZIPCENTRALDIRSIZE );
 
88
        if (uRead != ZIPCENTRALDIRSIZE)
 
89
                ThrowError(ZIP_BADZIPFILE);
 
90
        memcpy(&m_szSignature,          buf, 4);
 
91
        memcpy(&m_uThisDisk,            buf + 4, 2);
 
92
        memcpy(&m_uDiskWithCD,          buf + 6, 2);
 
93
        memcpy(&m_uDiskEntriesNo,       buf + 8, 2);
 
94
        memcpy(&m_uEntriesNumber,       buf + 10, 2);
 
95
        memcpy(&m_uSize,                        buf + 12, 4);
 
96
        memcpy(&m_uOffset,                      buf + 16, 4);
 
97
        memcpy(&uCommentSize,           buf + 20, 2);
 
98
        buf.Release();
 
99
 
 
100
 
 
101
        m_pStorage->UpdateSpanMode(m_uThisDisk);
 
102
        // if m_uThisDisk is not zero, it is enough to say that it is multi archive
 
103
        ASSERT((!m_uThisDisk && (m_uEntriesNumber == m_uDiskEntriesNo) && !m_uDiskWithCD) || m_uThisDisk);
 
104
 
 
105
                        
 
106
 
 
107
        if (!m_pStorage->IsSpanMode() && ((DWORD)m_uCentrDirPos < m_uOffset + m_uSize))
 
108
                ThrowError(ZIP_BADZIPFILE);
 
109
 
 
110
        if (uCommentSize)
 
111
        {
 
112
                m_pszComment.Allocate(uCommentSize);
 
113
                uRead = m_pStorage->m_pFile->Read(m_pszComment, uCommentSize);
 
114
                if (uRead != uCommentSize)
 
115
                        ThrowError(ZIP_BADZIPFILE);
 
116
        }
 
117
        
 
118
        m_uBytesBeforeZip = m_pStorage->IsSpanMode() ? 0 : m_uCentrDirPos - m_uSize - m_uOffset;
 
119
 
 
120
        if ((!m_uSize && m_uEntriesNumber) || (!m_uEntriesNumber && m_uSize))
 
121
                ThrowError(ZIP_BADZIPFILE);
 
122
 
 
123
        m_bOnDisk = true;
 
124
        m_pStorage->ChangeDisk(m_uDiskWithCD);
 
125
 
 
126
        if (!m_uSize)
 
127
                return;
 
128
 
 
129
        ReadHeaders();
 
130
}
 
131
 
 
132
// return the location of the beginning of the "end" record in the file
 
133
DWORD CZipCentralDir::Locate()
 
134
{
 
135
 
 
136
        // maximum size of end of central dir record
 
137
        long uMaxRecordSize = 0xffff + ZIPCENTRALDIRSIZE;
 
138
        DWORD uFileSize = m_pStorage->m_pFile->GetLength();
 
139
 
 
140
        if ((DWORD)uMaxRecordSize > uFileSize)
 
141
                uMaxRecordSize = uFileSize;
 
142
 
 
143
        CZipAutoBuffer buf(m_iBufferSize);
 
144
 
 
145
        long uPosInFile = 0;
 
146
        int uRead = 0;
 
147
        // backward reading
 
148
        while (uPosInFile < uMaxRecordSize)
 
149
        {
 
150
                uPosInFile = uRead + m_iBufferSize;
 
151
                if (uPosInFile > uMaxRecordSize)
 
152
                        uPosInFile = uMaxRecordSize;
 
153
 
 
154
                int iToRead = uPosInFile - uRead;
 
155
 
 
156
                m_pStorage->m_pFile->Seek(-uPosInFile, CFile::end);
 
157
                int iActuallyRead = m_pStorage->m_pFile->Read(buf, iToRead);
 
158
                if (iActuallyRead != iToRead)
 
159
                        ThrowError(ZIP_BADZIPFILE);
 
160
                // search from the very last bytes to prevent an error if inside archive 
 
161
                // there are packed other arhives
 
162
                for (int i = iToRead - 4; i >=0 ; i--)
 
163
                        if (!memcmp((char*)buf + i, m_gszSignature, 4)) 
 
164
                                return uFileSize - (uPosInFile - i);
 
165
 
 
166
                uRead += iToRead - 3;
 
167
 
 
168
        }
 
169
        
 
170
        ThrowError(ZIP_CDIR_NOTFOUND);
 
171
        return 0;
 
172
}
 
173
 
 
174
void CZipCentralDir::ThrowError(int err)
 
175
{
 
176
        AfxThrowZipException(err, m_pStorage->m_pFile->GetFilePath());
 
177
}
 
178
 
 
179
 
 
180
void CZipCentralDir::ReadHeaders()
 
181
{
 
182
        m_pStorage->m_pFile->Seek(m_uOffset + m_uBytesBeforeZip, CFile::begin);
 
183
        RemoveHeaders();
 
184
        for (int i = 0; i < m_uEntriesNumber; i++)
 
185
        {
 
186
                CZipFileHeader* pHeader = new CZipFileHeader;
 
187
                m_headers.Add(pHeader); // bezpoļæ½rednio nastļæ½puje w razie wyjļæ½tku
 
188
 
 
189
                if (!pHeader->Read(m_pStorage))
 
190
                        ThrowError(ZIP_BADZIPFILE);
 
191
                ConvertFileName(true, true, pHeader);
 
192
        }
 
193
        if (m_bFindFastEnabled)
 
194
                BuildFindFastArray();
 
195
 
 
196
}
 
197
 
 
198
// remove all headers from the central dir
 
199
void CZipCentralDir::Clear(bool bEverything)
 
200
{
 
201
        m_pOpenedFile = NULL;
 
202
        m_pLocalExtraField.Release();
 
203
 
 
204
        if (bEverything)
 
205
        {
 
206
                RemoveHeaders();
 
207
                m_findarray.RemoveAll();
 
208
                m_pszComment.Release();
 
209
                
 
210
        }
 
211
}
 
212
 
 
213
 
 
214
bool CZipCentralDir::IsValidIndex(WORD uIndex)
 
215
{
 
216
 
 
217
        bool ret = uIndex < m_headers.GetSize();
 
218
#ifdef _DEBUG
 
219
        if (!ret)
 
220
                        TRACE(_T("Not a valid index.\n"));
 
221
#endif 
 
222
        return ret;
 
223
}
 
224
 
 
225
// open the file for extracting
 
226
void CZipCentralDir::OpenFile(WORD uIndex)
 
227
{
 
228
        WORD uLocalExtraFieldSize;
 
229
        m_pOpenedFile = m_headers[uIndex];
 
230
        m_pStorage->ChangeDisk(m_pOpenedFile->m_uDiskStart);
 
231
        m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + m_uBytesBeforeZip, CFile::begin);  
 
232
        if (!m_pOpenedFile->ReadLocal(m_pStorage, uLocalExtraFieldSize))
 
233
                ThrowError(ZIP_BADZIPFILE);
 
234
 
 
235
 
 
236
        m_pLocalExtraField.Release(); // just in case
 
237
        if (uLocalExtraFieldSize)
 
238
        {
 
239
                int iCurrDsk = m_pStorage->GetCurrentDisk();
 
240
                m_pLocalExtraField.Allocate(uLocalExtraFieldSize);
 
241
                m_pStorage->Read(m_pLocalExtraField, uLocalExtraFieldSize, true);
 
242
                if (m_pStorage->GetCurrentDisk() != iCurrDsk)
 
243
                        ThrowError(ZIP_BADZIPFILE);
 
244
        }
 
245
        
 
246
}
 
247
 
 
248
void CZipCentralDir::CloseFile()
 
249
{
 
250
        if (!m_pOpenedFile)
 
251
                return;
 
252
        m_pLocalExtraField.Release();
 
253
        if (m_pOpenedFile->IsDataDescr())
 
254
        {
 
255
                CZipAutoBuffer buf(12);
 
256
                m_pStorage->Read(buf, 4, false);
 
257
                // in span mode, files that are divided between disks have bit 3 of flag set
 
258
                // which tell about the presence of the data descriptor after the compressed data
 
259
                // This signature may be in the disk spanning archive that is one volume only
 
260
                // (it is detected as a non disk spanning archive)
 
261
                if (memcmp(buf, CZipStorage::m_gszExtHeaderSignat, 4) != 0) // there is no signature
 
262
                                m_pStorage->m_pFile->Seek(-4, CFile::current);
 
263
 
 
264
                
 
265
                m_pStorage->Read(buf, 12, false);
 
266
                if (!m_pOpenedFile->CheckCrcAndSizes(buf))
 
267
                        ThrowError(ZIP_BADZIPFILE);
 
268
        }
 
269
        m_pOpenedFile = NULL;
 
270
}
 
271
 
 
272
// add new header using the argument as a template
 
273
void CZipCentralDir::AddNewFile(CZipFileHeader & header)
 
274
{
 
275
        CZipFileHeader* pHeader = new CZipFileHeader(header);
 
276
        m_pOpenedFile = pHeader;
 
277
        m_headers.Add(pHeader);
 
278
        if (m_bFindFastEnabled)
 
279
                InsertFindFastElement(pHeader, WORD(m_headers.GetSize() - 1)); // GetSize IS > 0, 'cos we've just added a header
 
280
        RemoveFromDisk();
 
281
        m_pStorage->m_pFile->SeekToEnd();
 
282
}
 
283
 
 
284
// called during adding or deleting files; remove the central dir from the disk
 
285
void CZipCentralDir::RemoveFromDisk()
 
286
{
 
287
        if (m_bOnDisk)
 
288
        {
 
289
                ASSERT(!m_pStorage->IsSpanMode()); // you can't add files to the existing disk span archive or to delete them from it
 
290
                m_pStorage->m_pFile->SetLength(m_uBytesBeforeZip + m_uOffset);
 
291
                m_bOnDisk = false;
 
292
        }
 
293
}
 
294
 
 
295
 
 
296
void CZipCentralDir::CloseNewFile()
 
297
{
 
298
        CZipAutoBuffer buf(12 + 4);
 
299
        short iToWrite = 0;
 
300
        bool bIsSpan = m_pStorage->IsSpanMode() != 0;
 
301
        bool bEncrypted = m_pOpenedFile->IsEncrypted();
 
302
        if (m_pOpenedFile->IsDataDescr())
 
303
        {
 
304
                if (bIsSpan || bEncrypted)
 
305
                {
 
306
                        memcpy(buf, m_pStorage->m_gszExtHeaderSignat, 4);
 
307
                        iToWrite += 4;
 
308
                }
 
309
        }
 
310
        else /*if (!IsSpan)*/
 
311
        {
 
312
                ASSERT(!bIsSpan && !bEncrypted);
 
313
                m_pStorage->Flush();
 
314
                m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + 14, CFile::begin);
 
315
                // we don't have to restore the pointer, because before adding a new file, 
 
316
                // the pointer is moved to the end
 
317
        }
 
318
 
 
319
        m_pOpenedFile->GetCrcAndSizes(buf + iToWrite);
 
320
        iToWrite += 12;
 
321
 
 
322
        // offset set during writting the local header
 
323
        m_pOpenedFile->m_uOffset -= m_uBytesBeforeZip;
 
324
        
 
325
        // write the data descriptor and a disk spanning signature at once
 
326
        m_pStorage->Write(buf, iToWrite, true);
 
327
        if (!bIsSpan && bEncrypted)
 
328
        {
 
329
                // write the information to the local header too
 
330
                m_pStorage->Flush();
 
331
                m_pStorage->m_pFile->Seek(m_pOpenedFile->m_uOffset + 14, CFile::begin);
 
332
                m_pStorage->Write(buf + 4, 12, true);
 
333
        }
 
334
 
 
335
        if (!bIsSpan)
 
336
                m_pStorage->Flush();
 
337
 
 
338
        m_pOpenedFile = NULL;
 
339
 
 
340
}
 
341
 
 
342
void CZipCentralDir::Write()
 
343
{
 
344
        if (m_bOnDisk)
 
345
                return;
 
346
        if (!m_pStorage->IsSpanMode())
 
347
        {
 
348
                m_pStorage->Flush();
 
349
                m_pStorage->m_pFile->SeekToEnd();
 
350
        }
 
351
        m_uEntriesNumber = (WORD)m_headers.GetSize();
 
352
        m_uSize = 0;
 
353
        bool bDontAllowDiskChange = false;
 
354
        // if there is a disk spanning archive in creation and it is only one-volume,
 
355
        //      (current disk is 0 so far, no bytes has been written so we know they are 
 
356
        //  all in the buffer)  make sure that it will be after writting central dir 
 
357
        // and make it a non disk spanning archive
 
358
        if (m_pStorage->IsSpanMode() && m_pStorage->GetCurrentDisk() == 0)
 
359
        {
 
360
                DWORD uVolumeFree = m_pStorage->VolumeLeft();
 
361
                // calculate the size of data descriptors already in the buffer or on the disk
 
362
                // (they will be removed in the non disk spanning archive):
 
363
                // multi span signature at the beginnig (4 bytes) + the size of the data 
 
364
                // descr. for each file (multi span signature + 12 bytes data)
 
365
                // the count of bytes to add: central dir size - total to remove;
 
366
                DWORD uToGrow = GetSize(true) - (4 + m_uEntriesNumber * (4 + 12)); 
 
367
                if (uVolumeFree >= uToGrow) 
 
368
                // lets make sure it will be one-disk archive
 
369
                {
 
370
                        // can the operation be done only in the buffer?
 
371
                        if (!m_pStorage->m_iBytesWritten && // no bytes on the disk yet
 
372
                                (m_pStorage->GetFreeInBuffer() >= uToGrow)) // is the buffer big enough?
 
373
                        {
 
374
                                        RemoveDataDescr(true);
 
375
                                        bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
 
376
                        }
 
377
                        else
 
378
                        {
 
379
                                m_pStorage->Flush();
 
380
                                m_pStorage->m_pFile->Flush();
 
381
                                if (RemoveDataDescr(false))
 
382
                                        bDontAllowDiskChange = true; // if the disk change occurs somehow, we'll throw an error later
 
383
                        }
 
384
                }
 
385
        }
 
386
 
 
387
        WriteHeaders();
 
388
        m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
 
389
        DWORD uSize = WriteCentralEnd();
 
390
        if (bDontAllowDiskChange && (m_pStorage->GetCurrentDisk() != 0))
 
391
                ThrowError(ZIP_BADZIPFILE);
 
392
        // if after adding a central directory there is a disk change, 
 
393
        // update the information and write it again
 
394
        if (m_uThisDisk != m_pStorage->GetCurrentDisk())
 
395
        {
 
396
                m_uThisDisk = (WORD)m_pStorage->GetCurrentDisk();
 
397
                if (m_uEntriesNumber)
 
398
                {
 
399
                        m_uDiskEntriesNo = 0;   
 
400
                }
 
401
                else
 
402
                {
 
403
                        m_uDiskWithCD = m_uThisDisk;
 
404
                        m_uOffset = 0;
 
405
                }
 
406
 
 
407
                if (m_pStorage->m_uBytesInWriteBuffer >= uSize)
 
408
                        // if the data is still in the buffer, simply remove it
 
409
                        m_pStorage->m_uBytesInWriteBuffer -= uSize;
 
410
                else
 
411
                {
 
412
                        m_pStorage->Flush();
 
413
                        m_pStorage->m_iBytesWritten -= uSize;
 
414
                        m_pStorage->m_pFile->SeekToBegin();     
 
415
                }
 
416
                
 
417
                WriteCentralEnd();
 
418
        }
 
419
 
 
420
}
 
421
 
 
422
void CZipCentralDir::WriteHeaders()
 
423
{
 
424
        m_uDiskEntriesNo = 0;
 
425
        m_uDiskWithCD = (WORD)m_pStorage->GetCurrentDisk();
 
426
        m_uOffset = m_pStorage->GetPosition() - m_uBytesBeforeZip;
 
427
        if (!m_uEntriesNumber)
 
428
                return;
 
429
 
 
430
        WORD iDisk = m_uDiskWithCD;
 
431
        for (int i = 0; i < m_uEntriesNumber; i++)
 
432
        {
 
433
                CZipFileHeader* pHeader = m_headers[i];
 
434
                ConvertFileName(false, true, pHeader);
 
435
                m_uSize += pHeader->Write(m_pStorage);
 
436
                if (m_pStorage->GetCurrentDisk() != iDisk)
 
437
                {
 
438
                        m_uDiskEntriesNo = 1;
 
439
                        iDisk = (WORD)m_pStorage->GetCurrentDisk();
 
440
                        // update the information about the offset and starting disk if the 
 
441
                        // first header was written on the new disk
 
442
                        if (i == 0)
 
443
                        {
 
444
                                m_uOffset = 0;
 
445
                                m_uDiskWithCD = iDisk;
 
446
                        }
 
447
                }
 
448
                else 
 
449
                        m_uDiskEntriesNo++;
 
450
        }
 
451
}
 
452
 
 
453
DWORD CZipCentralDir::WriteCentralEnd()
 
454
{
 
455
        DWORD uSize = GetSize();
 
456
        CZipAutoBuffer buf(uSize);
 
457
        WORD uCommentSize = (WORD)m_pszComment.GetSize();
 
458
        memcpy(buf, m_gszSignature, 4);
 
459
        memcpy(buf + 4, &m_uThisDisk, 2);
 
460
        memcpy(buf + 6, &m_uDiskWithCD, 2);
 
461
        memcpy(buf + 8, &m_uDiskEntriesNo, 2);
 
462
        memcpy(buf + 10, &m_uEntriesNumber, 2);
 
463
        memcpy(buf + 12, &m_uSize, 4);
 
464
        memcpy(buf + 16, &m_uOffset, 4);
 
465
        memcpy(buf + 20, &uCommentSize, 2);
 
466
        memcpy(buf + 22, m_pszComment, uCommentSize);
 
467
        m_pStorage->Write(buf, uSize, true);
 
468
        return uSize;
 
469
}
 
470
 
 
471
 
 
472
void CZipCentralDir::RemoveFile(WORD uIndex)
 
473
{
 
474
        CZipFileHeader* pHeader = m_headers[uIndex];
 
475
        if (m_bFindFastEnabled)
 
476
        {
 
477
                int i = FindFileNameIndex(pHeader->GetFileName(), true);
 
478
                ASSERT(i != -1);
 
479
                int uIndex = m_findarray[i].m_uIndex;
 
480
                m_findarray.RemoveAt(i);
 
481
                // shift down the indexes
 
482
                for (int j = 0; j < m_findarray.GetSize(); j++)
 
483
                {
 
484
                        if (m_findarray[j].m_uIndex > uIndex)
 
485
                                m_findarray[j].m_uIndex--;
 
486
                }
 
487
        }
 
488
        delete pHeader;
 
489
        m_headers.RemoveAt(uIndex);
 
490
}
 
491
 
 
492
 
 
493
DWORD CZipCentralDir::GetSize(bool bWhole)
 
494
{
 
495
        DWORD uHeaders = 0;
 
496
        if (bWhole)
 
497
        {
 
498
                for (int i = 0; i < m_headers.GetSize(); i++)
 
499
                        uHeaders += m_headers[i]->GetSize();
 
500
        }
 
501
        return ZIPCENTRALDIRSIZE + m_pszComment.GetSize() + uHeaders;
 
502
}
 
503
 
 
504
// remove data descriptors from the write buffer in the disk spanning volume
 
505
// that is one-disk only (do not remove from password encrypted files)
 
506
bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer)
 
507
{
 
508
        CZipAutoHandle ah;
 
509
        char* pFile = NULL;
 
510
        DWORD uSize;
 
511
        if (bFromBuffer)
 
512
        {
 
513
                uSize = m_pStorage->m_uBytesInWriteBuffer;
 
514
                pFile = m_pStorage->m_pWriteBuffer;
 
515
        }
 
516
        else
 
517
        {
 
518
                uSize = m_pStorage->m_pFile->GetLength();
 
519
                if (!ah.CreateMapping((HANDLE)m_pStorage->m_pFile->m_hFile))
 
520
                        return false;
 
521
                pFile = (char*)ah.m_pFileMap;
 
522
        }
 
523
 
 
524
        DWORD uOffsetToChange = 4;
 
525
        DWORD uToCopy = 0;
 
526
        DWORD uPosInBuffer = 0;
 
527
        DWORD uExtraHeaderLen;
 
528
        // this will work providing the order in the m_headers is the same as 
 
529
        // in the archive
 
530
        for (int i = 0; i < m_headers.GetSize(); i++)
 
531
        {
 
532
                // update the flag value in the local and central header
 
533
//              int uDataDescr = (m_headers[i]->m_uFlag & 8) ? (4 + 12) : 0;
 
534
 
 
535
                CZipFileHeader* pHeader = m_headers[i];
 
536
 
 
537
 
 
538
                char* pSour = pFile + pHeader->m_uOffset;
 
539
                
 
540
                if (!pHeader->IsEncrypted())
 
541
                {
 
542
                        // removing data descriptor
 
543
                        pHeader->m_uFlag &= ~8;
 
544
                        // update local header:
 
545
                        // write modified flag in the local header
 
546
                        memcpy(pSour + 6, &pHeader->m_uFlag, 2);
 
547
                        uExtraHeaderLen = 4/*ext. header signature*/ + 12/*data descriptor*/;
 
548
                }
 
549
                else
 
550
                        // do not remove data descriptors from encrypted files
 
551
                        uExtraHeaderLen = 0;
 
552
 
 
553
                // update crc32 and sizes' values
 
554
                pHeader->GetCrcAndSizes(pSour+ 14);
 
555
 
 
556
                uToCopy = (i == (m_headers.GetSize() - 1) ? uSize : m_headers[i + 1]->m_uOffset)
 
557
                        - pHeader->m_uOffset - uExtraHeaderLen;
 
558
 
 
559
                memmove(pFile + uPosInBuffer, pSour, uToCopy);
 
560
 
 
561
                uPosInBuffer += uToCopy;
 
562
                pHeader->m_uOffset -= uOffsetToChange;
 
563
                uOffsetToChange += uExtraHeaderLen;
 
564
        }
 
565
 
 
566
        if (bFromBuffer)
 
567
                m_pStorage->m_uBytesInWriteBuffer = uPosInBuffer;
 
568
        else
 
569
        {
 
570
                m_pStorage->m_iBytesWritten = uPosInBuffer;
 
571
                ah.RemoveMapping();
 
572
                m_pStorage->m_pFile->SetLength(uPosInBuffer);
 
573
        }
 
574
        return true;
 
575
}
 
576
 
 
577
void CZipCentralDir::RemoveHeaders()
 
578
{
 
579
                for (int i = 0; i < m_headers.GetSize(); i++)
 
580
                        delete m_headers[i];
 
581
                m_headers.RemoveAll();
 
582
}
 
583
 
 
584
void CZipCentralDir::ConvertAll()
 
585
{
 
586
        ASSERT(!m_bConvertAfterOpen);
 
587
        for (int i = 0; i < m_headers.GetSize(); i++)
 
588
                ConvertFileName(true, false, m_headers[i]);
 
589
        m_bConvertAfterOpen = true;
 
590
}
 
591
 
 
592
 
 
593
void CZipCentralDir::BuildFindFastArray()
 
594
{
 
595
        m_findarray.RemoveAll();// just in case
 
596
        for (int i = 0; i < m_headers.GetSize(); i++)
 
597
                InsertFindFastElement(m_headers[i], (WORD)i);
 
598
}
 
599
 
 
600
void CZipCentralDir::InsertFindFastElement(CZipFileHeader* pHeader, WORD uIndex)
 
601
{
 
602
        CString fileName = pHeader->GetFileName();
 
603
 
 
604
        
 
605
        int iSize = m_findarray.GetSize();
 
606
 
 
607
        //      Our initial binary search range encompasses the entire array of filenames:
 
608
        int start = 0;
 
609
        int end = iSize;
 
610
 
 
611
        //      Keep halving our search range until we find the right place
 
612
        //      to insert the new element:
 
613
        while ( start < end )
 
614
        {
 
615
                //      Find the midpoint of the search range:
 
616
                int midpoint = ( start + end ) / 2;
 
617
 
 
618
                //      Compare the filename with the filename at the midpoint of the current search range:
 
619
                int result = CompareElement(fileName, (WORD)midpoint, true);
 
620
 
 
621
                //      If our filename is larger, it must fall in the first half of the search range:
 
622
                if ( result > 0 )
 
623
                {
 
624
                        end = midpoint;
 
625
                }
 
626
 
 
627
                //      If it's smaller, it must fall in the last half:
 
628
                else if ( result < 0 )
 
629
                {
 
630
                        start = midpoint + 1;
 
631
                }
 
632
 
 
633
                //      If they're equal, we can go ahead and insert here:
 
634
                else
 
635
                {
 
636
                        start = midpoint; break;
 
637
                }
 
638
        }
 
639
        m_findarray.InsertAt(start, CZipFindFast(pHeader, WORD(uIndex == -1 ? iSize : uIndex /* just in case */))); 
 
640
}
 
641
 
 
642
int CZipCentralDir::FindFileNameIndex(LPCTSTR lpszFileName, bool bCaseSensitive)
 
643
{
 
644
        int start = 0;
 
645
        int end = m_findarray.GetUpperBound();
 
646
 
 
647
        //      Keep halving our search range until we find the given element:
 
648
        while ( start <= end )
 
649
        {
 
650
                //      Find the midpoint of the search range:
 
651
                int midpoint = ( start + end ) / 2;
 
652
 
 
653
                //      Compare the given filename with the filename at the midpoint of the search range:
 
654
                int result = CompareElement(lpszFileName, (WORD)midpoint, bCaseSensitive);
 
655
 
 
656
                //      If our filename is smaller, it must fall in the first half of the search range:
 
657
                if ( result > 0 )
 
658
                {
 
659
                        end = midpoint - 1;
 
660
                }
 
661
 
 
662
                //      If it's larger, it must fall in the last half:
 
663
                else if ( result < 0 )
 
664
                {
 
665
                        start = midpoint + 1;
 
666
                }
 
667
 
 
668
                //      If they're equal, return the result:
 
669
                else
 
670
                {
 
671
                        return midpoint;
 
672
                }
 
673
        }
 
674
 
 
675
        //      Signal failure:
 
676
        return -1;
 
677
}