misc/libphysfs/lzma/CPP/7zip/Archive/7z/7zOut.cpp
changeset 13881 99b265e0d1d0
parent 13880 5f819b90d479
child 13882 b172a5d40eee
equal deleted inserted replaced
13880:5f819b90d479 13881:99b265e0d1d0
     1 // 7zOut.cpp
       
     2 
       
     3 #include "StdAfx.h"
       
     4 
       
     5 #include "../../../Common/AutoPtr.h"
       
     6 #include "../../Common/StreamObjects.h"
       
     7 
       
     8 #include "7zOut.h"
       
     9 
       
    10 extern "C" 
       
    11 { 
       
    12 #include "../../../../C/7zCrc.h"
       
    13 }
       
    14 
       
    15 static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size)
       
    16 {
       
    17   while (size > 0)
       
    18   {
       
    19     UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF);
       
    20     UInt32 processedSize;
       
    21     RINOK(stream->Write(data, curSize, &processedSize));
       
    22     if(processedSize == 0)
       
    23       return E_FAIL;
       
    24     data = (const void *)((const Byte *)data + processedSize);
       
    25     size -= processedSize;
       
    26   }
       
    27   return S_OK;
       
    28 }
       
    29 
       
    30 namespace NArchive {
       
    31 namespace N7z {
       
    32 
       
    33 HRESULT COutArchive::WriteDirect(const void *data, UInt32 size)
       
    34 {
       
    35   return ::WriteBytes(SeqStream, data, size);
       
    36 }
       
    37 
       
    38 UInt32 CrcUpdateUInt32(UInt32 crc, UInt32 value)
       
    39 {
       
    40   for (int i = 0; i < 4; i++, value >>= 8)
       
    41     crc = CRC_UPDATE_BYTE(crc, (Byte)value);
       
    42   return crc;
       
    43 }
       
    44 
       
    45 UInt32 CrcUpdateUInt64(UInt32 crc, UInt64 value)
       
    46 {
       
    47   for (int i = 0; i < 8; i++, value >>= 8)
       
    48     crc = CRC_UPDATE_BYTE(crc, (Byte)value);
       
    49   return crc;
       
    50 }
       
    51 
       
    52 HRESULT COutArchive::WriteDirectUInt32(UInt32 value)
       
    53 {
       
    54   for (int i = 0; i < 4; i++)
       
    55   {
       
    56     RINOK(WriteDirectByte((Byte)value));
       
    57     value >>= 8;
       
    58   }
       
    59   return S_OK;
       
    60 }
       
    61 
       
    62 HRESULT COutArchive::WriteDirectUInt64(UInt64 value)
       
    63 {
       
    64   for (int i = 0; i < 8; i++)
       
    65   {
       
    66     RINOK(WriteDirectByte((Byte)value));
       
    67     value >>= 8;
       
    68   }
       
    69   return S_OK;
       
    70 }
       
    71 
       
    72 HRESULT COutArchive::WriteSignature()
       
    73 {
       
    74   RINOK(WriteDirect(kSignature, kSignatureSize));
       
    75   RINOK(WriteDirectByte(kMajorVersion));
       
    76   return WriteDirectByte(2);
       
    77 }
       
    78 
       
    79 #ifdef _7Z_VOL
       
    80 HRESULT COutArchive::WriteFinishSignature()
       
    81 {
       
    82   RINOK(WriteDirect(kFinishSignature, kSignatureSize));
       
    83   CArchiveVersion av;
       
    84   av.Major = kMajorVersion;
       
    85   av.Minor = 2;
       
    86   RINOK(WriteDirectByte(av.Major));
       
    87   return WriteDirectByte(av.Minor);
       
    88 }
       
    89 #endif
       
    90 
       
    91 HRESULT COutArchive::WriteStartHeader(const CStartHeader &h)
       
    92 {
       
    93   UInt32 crc = CRC_INIT_VAL;
       
    94   crc = CrcUpdateUInt64(crc, h.NextHeaderOffset);
       
    95   crc = CrcUpdateUInt64(crc, h.NextHeaderSize);
       
    96   crc = CrcUpdateUInt32(crc, h.NextHeaderCRC);
       
    97   RINOK(WriteDirectUInt32(CRC_GET_DIGEST(crc)));
       
    98   RINOK(WriteDirectUInt64(h.NextHeaderOffset));
       
    99   RINOK(WriteDirectUInt64(h.NextHeaderSize));
       
   100   return WriteDirectUInt32(h.NextHeaderCRC);
       
   101 }
       
   102 
       
   103 #ifdef _7Z_VOL
       
   104 HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h)
       
   105 {
       
   106   CCRC crc;
       
   107   crc.UpdateUInt64(h.NextHeaderOffset);
       
   108   crc.UpdateUInt64(h.NextHeaderSize);
       
   109   crc.UpdateUInt32(h.NextHeaderCRC);
       
   110   crc.UpdateUInt64(h.ArchiveStartOffset);
       
   111   crc.UpdateUInt64(h.AdditionalStartBlockSize);
       
   112   RINOK(WriteDirectUInt32(crc.GetDigest()));
       
   113   RINOK(WriteDirectUInt64(h.NextHeaderOffset));
       
   114   RINOK(WriteDirectUInt64(h.NextHeaderSize));
       
   115   RINOK(WriteDirectUInt32(h.NextHeaderCRC));
       
   116   RINOK(WriteDirectUInt64(h.ArchiveStartOffset));
       
   117   return WriteDirectUInt64(h.AdditionalStartBlockSize);
       
   118 }
       
   119 #endif
       
   120 
       
   121 HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker)
       
   122 {
       
   123   Close();
       
   124   #ifdef _7Z_VOL
       
   125   // endMarker = false;
       
   126   _endMarker = endMarker;
       
   127   #endif
       
   128   SeqStream = stream;
       
   129   if (!endMarker)
       
   130   {
       
   131     SeqStream.QueryInterface(IID_IOutStream, &Stream);
       
   132     if (!Stream)
       
   133     {
       
   134       return E_NOTIMPL;
       
   135       // endMarker = true;
       
   136     }
       
   137   }
       
   138   #ifdef _7Z_VOL
       
   139   if (endMarker)
       
   140   {
       
   141     /*
       
   142     CStartHeader sh;
       
   143     sh.NextHeaderOffset = (UInt32)(Int32)-1;
       
   144     sh.NextHeaderSize = (UInt32)(Int32)-1;
       
   145     sh.NextHeaderCRC = 0;
       
   146     WriteStartHeader(sh);
       
   147     */
       
   148   }
       
   149   else
       
   150   #endif
       
   151   {
       
   152     if (!Stream)
       
   153       return E_FAIL;
       
   154     RINOK(WriteSignature());
       
   155     RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos));
       
   156   }
       
   157   return S_OK;
       
   158 }
       
   159 
       
   160 void COutArchive::Close()
       
   161 {
       
   162   SeqStream.Release();
       
   163   Stream.Release();
       
   164 }
       
   165 
       
   166 HRESULT COutArchive::SkeepPrefixArchiveHeader()
       
   167 {
       
   168   #ifdef _7Z_VOL
       
   169   if (_endMarker)
       
   170     return S_OK;
       
   171   #endif
       
   172   return Stream->Seek(24, STREAM_SEEK_CUR, NULL);
       
   173 }
       
   174 
       
   175 HRESULT COutArchive::WriteBytes(const void *data, size_t size)
       
   176 {
       
   177   if (_mainMode)
       
   178   {
       
   179     if (_dynamicMode)
       
   180       _dynamicBuffer.Write(data, size);
       
   181     else
       
   182       _outByte.WriteBytes(data, size);
       
   183     _crc = CrcUpdate(_crc, data, size);
       
   184   }
       
   185   else
       
   186   {
       
   187     if (_countMode)
       
   188       _countSize += size;
       
   189     else
       
   190       RINOK(_outByte2.Write(data, size));
       
   191   }
       
   192   return S_OK;
       
   193 }
       
   194 
       
   195 HRESULT COutArchive::WriteBytes(const CByteBuffer &data)
       
   196 {
       
   197   return WriteBytes(data, data.GetCapacity());
       
   198 }
       
   199 
       
   200 HRESULT COutArchive::WriteByte(Byte b)
       
   201 {
       
   202   return WriteBytes(&b, 1);
       
   203 }
       
   204 
       
   205 HRESULT COutArchive::WriteUInt32(UInt32 value)
       
   206 {
       
   207   for (int i = 0; i < 4; i++)
       
   208   {
       
   209     RINOK(WriteByte((Byte)value));
       
   210     value >>= 8;
       
   211   }
       
   212   return S_OK;
       
   213 }
       
   214 
       
   215 HRESULT COutArchive::WriteNumber(UInt64 value)
       
   216 {
       
   217   Byte firstByte = 0;
       
   218   Byte mask = 0x80;
       
   219   int i;
       
   220   for (i = 0; i < 8; i++)
       
   221   {
       
   222     if (value < ((UInt64(1) << ( 7  * (i + 1)))))
       
   223     {
       
   224       firstByte |= Byte(value >> (8 * i));
       
   225       break;
       
   226     }
       
   227     firstByte |= mask;
       
   228     mask >>= 1;
       
   229   }
       
   230   RINOK(WriteByte(firstByte));
       
   231   for (;i > 0; i--)
       
   232   {
       
   233     RINOK(WriteByte((Byte)value));
       
   234     value >>= 8;
       
   235   }
       
   236   return S_OK;
       
   237 }
       
   238 
       
   239 #ifdef _7Z_VOL
       
   240 static UInt32 GetBigNumberSize(UInt64 value)
       
   241 {
       
   242   int i;
       
   243   for (i = 0; i < 8; i++)
       
   244     if (value < ((UInt64(1) << ( 7  * (i + 1)))))
       
   245       break;
       
   246   return 1 + i;
       
   247 }
       
   248 
       
   249 UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props)
       
   250 {
       
   251   UInt32 result = GetBigNumberSize(dataSize) * 2 + 41;
       
   252   if (nameLength != 0)
       
   253   {
       
   254     nameLength = (nameLength + 1) * 2;
       
   255     result += nameLength + GetBigNumberSize(nameLength) + 2;
       
   256   }
       
   257   if (props)
       
   258   {
       
   259     result += 20;
       
   260   }
       
   261   if (result >= 128)
       
   262     result++;
       
   263   result += kSignatureSize + 2 + kFinishHeaderSize;
       
   264   return result;
       
   265 }
       
   266 
       
   267 UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props)
       
   268 {
       
   269   UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props);
       
   270   int testSize;
       
   271   if (volSize > headersSizeBase)
       
   272     testSize = volSize - headersSizeBase;
       
   273   else
       
   274     testSize = 1;
       
   275   UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props);
       
   276   UInt64 pureSize = 1;
       
   277   if (volSize > headersSize)
       
   278     pureSize = volSize - headersSize;
       
   279   return pureSize;
       
   280 }
       
   281 #endif
       
   282 
       
   283 HRESULT COutArchive::WriteFolder(const CFolder &folder)
       
   284 {
       
   285   RINOK(WriteNumber(folder.Coders.Size()));
       
   286   int i;
       
   287   for (i = 0; i < folder.Coders.Size(); i++)
       
   288   {
       
   289     const CCoderInfo &coder = folder.Coders[i];
       
   290     {
       
   291       size_t propertiesSize = coder.Properties.GetCapacity();
       
   292       
       
   293       UInt64 id = coder.MethodID; 
       
   294       int idSize;
       
   295       for (idSize = 1; idSize < sizeof(id); idSize++)
       
   296         if ((id >> (8 * idSize)) == 0)
       
   297           break;
       
   298       BYTE longID[15];
       
   299       for (int t = idSize - 1; t >= 0 ; t--, id >>= 8)
       
   300         longID[t] = (Byte)(id & 0xFF);
       
   301       Byte b;
       
   302       b = (Byte)(idSize & 0xF);
       
   303       bool isComplex = !coder.IsSimpleCoder();
       
   304       b |= (isComplex ? 0x10 : 0);
       
   305       b |= ((propertiesSize != 0) ? 0x20 : 0 );
       
   306       RINOK(WriteByte(b));
       
   307       RINOK(WriteBytes(longID, idSize));
       
   308       if (isComplex)
       
   309       {
       
   310         RINOK(WriteNumber(coder.NumInStreams));
       
   311         RINOK(WriteNumber(coder.NumOutStreams));
       
   312       }
       
   313       if (propertiesSize == 0)
       
   314         continue;
       
   315       RINOK(WriteNumber(propertiesSize));
       
   316       RINOK(WriteBytes(coder.Properties, propertiesSize));
       
   317     }
       
   318   }
       
   319   for (i = 0; i < folder.BindPairs.Size(); i++)
       
   320   {
       
   321     const CBindPair &bindPair = folder.BindPairs[i];
       
   322     RINOK(WriteNumber(bindPair.InIndex));
       
   323     RINOK(WriteNumber(bindPair.OutIndex));
       
   324   }
       
   325   if (folder.PackStreams.Size() > 1)
       
   326     for (i = 0; i < folder.PackStreams.Size(); i++)
       
   327     {
       
   328       RINOK(WriteNumber(folder.PackStreams[i]));
       
   329     }
       
   330   return S_OK;
       
   331 }
       
   332 
       
   333 HRESULT COutArchive::WriteBoolVector(const CBoolVector &boolVector)
       
   334 {
       
   335   Byte b = 0;
       
   336   Byte mask = 0x80;
       
   337   for(int i = 0; i < boolVector.Size(); i++)
       
   338   {
       
   339     if (boolVector[i])
       
   340       b |= mask;
       
   341     mask >>= 1;
       
   342     if (mask == 0)
       
   343     {
       
   344       RINOK(WriteByte(b));
       
   345       mask = 0x80;
       
   346       b = 0;
       
   347     }
       
   348   }
       
   349   if (mask != 0x80)
       
   350   {
       
   351     RINOK(WriteByte(b));
       
   352   }
       
   353   return S_OK;
       
   354 }
       
   355 
       
   356 
       
   357 HRESULT COutArchive::WriteHashDigests(
       
   358     const CRecordVector<bool> &digestsDefined,
       
   359     const CRecordVector<UInt32> &digests)
       
   360 {
       
   361   int numDefined = 0;
       
   362   int i;
       
   363   for(i = 0; i < digestsDefined.Size(); i++)
       
   364     if (digestsDefined[i])
       
   365       numDefined++;
       
   366   if (numDefined == 0)
       
   367     return S_OK;
       
   368 
       
   369   RINOK(WriteByte(NID::kCRC));
       
   370   if (numDefined == digestsDefined.Size())
       
   371   {
       
   372     RINOK(WriteByte(1));
       
   373   }
       
   374   else
       
   375   {
       
   376     RINOK(WriteByte(0));
       
   377     RINOK(WriteBoolVector(digestsDefined));
       
   378   }
       
   379   for(i = 0; i < digests.Size(); i++)
       
   380   {
       
   381     if(digestsDefined[i])
       
   382       RINOK(WriteUInt32(digests[i]));
       
   383   }
       
   384   return S_OK;
       
   385 }
       
   386 
       
   387 HRESULT COutArchive::WritePackInfo(
       
   388     UInt64 dataOffset,
       
   389     const CRecordVector<UInt64> &packSizes,
       
   390     const CRecordVector<bool> &packCRCsDefined,
       
   391     const CRecordVector<UInt32> &packCRCs)
       
   392 {
       
   393   if (packSizes.IsEmpty())
       
   394     return S_OK;
       
   395   RINOK(WriteByte(NID::kPackInfo));
       
   396   RINOK(WriteNumber(dataOffset));
       
   397   RINOK(WriteNumber(packSizes.Size()));
       
   398   RINOK(WriteByte(NID::kSize));
       
   399   for(int i = 0; i < packSizes.Size(); i++)
       
   400     RINOK(WriteNumber(packSizes[i]));
       
   401 
       
   402   RINOK(WriteHashDigests(packCRCsDefined, packCRCs));
       
   403   
       
   404   return WriteByte(NID::kEnd);
       
   405 }
       
   406 
       
   407 HRESULT COutArchive::WriteUnPackInfo(const CObjectVector<CFolder> &folders)
       
   408 {
       
   409   if (folders.IsEmpty())
       
   410     return S_OK;
       
   411 
       
   412   RINOK(WriteByte(NID::kUnPackInfo));
       
   413 
       
   414   RINOK(WriteByte(NID::kFolder));
       
   415   RINOK(WriteNumber(folders.Size()));
       
   416   {
       
   417     RINOK(WriteByte(0));
       
   418     for(int i = 0; i < folders.Size(); i++)
       
   419       RINOK(WriteFolder(folders[i]));
       
   420   }
       
   421   
       
   422   RINOK(WriteByte(NID::kCodersUnPackSize));
       
   423   int i;
       
   424   for(i = 0; i < folders.Size(); i++)
       
   425   {
       
   426     const CFolder &folder = folders[i];
       
   427     for (int j = 0; j < folder.UnPackSizes.Size(); j++)
       
   428       RINOK(WriteNumber(folder.UnPackSizes[j]));
       
   429   }
       
   430 
       
   431   CRecordVector<bool> unPackCRCsDefined;
       
   432   CRecordVector<UInt32> unPackCRCs;
       
   433   for(i = 0; i < folders.Size(); i++)
       
   434   {
       
   435     const CFolder &folder = folders[i];
       
   436     unPackCRCsDefined.Add(folder.UnPackCRCDefined);
       
   437     unPackCRCs.Add(folder.UnPackCRC);
       
   438   }
       
   439   RINOK(WriteHashDigests(unPackCRCsDefined, unPackCRCs));
       
   440 
       
   441   return WriteByte(NID::kEnd);
       
   442 }
       
   443 
       
   444 HRESULT COutArchive::WriteSubStreamsInfo(
       
   445     const CObjectVector<CFolder> &folders,
       
   446     const CRecordVector<CNum> &numUnPackStreamsInFolders,
       
   447     const CRecordVector<UInt64> &unPackSizes,
       
   448     const CRecordVector<bool> &digestsDefined,
       
   449     const CRecordVector<UInt32> &digests)
       
   450 {
       
   451   RINOK(WriteByte(NID::kSubStreamsInfo));
       
   452 
       
   453   int i;
       
   454   for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
       
   455   {
       
   456     if (numUnPackStreamsInFolders[i] != 1)
       
   457     {
       
   458       RINOK(WriteByte(NID::kNumUnPackStream));
       
   459       for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
       
   460         RINOK(WriteNumber(numUnPackStreamsInFolders[i]));
       
   461       break;
       
   462     }
       
   463   }
       
   464  
       
   465 
       
   466   bool needFlag = true;
       
   467   CNum index = 0;
       
   468   for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
       
   469     for (CNum j = 0; j < numUnPackStreamsInFolders[i]; j++)
       
   470     {
       
   471       if (j + 1 != numUnPackStreamsInFolders[i])
       
   472       {
       
   473         if (needFlag)
       
   474           RINOK(WriteByte(NID::kSize));
       
   475         needFlag = false;
       
   476         RINOK(WriteNumber(unPackSizes[index]));
       
   477       }
       
   478       index++;
       
   479     }
       
   480 
       
   481   CRecordVector<bool> digestsDefined2;
       
   482   CRecordVector<UInt32> digests2;
       
   483 
       
   484   int digestIndex = 0;
       
   485   for (i = 0; i < folders.Size(); i++)
       
   486   {
       
   487     int numSubStreams = (int)numUnPackStreamsInFolders[i];
       
   488     if (numSubStreams == 1 && folders[i].UnPackCRCDefined)
       
   489       digestIndex++;
       
   490     else
       
   491       for (int j = 0; j < numSubStreams; j++, digestIndex++)
       
   492       {
       
   493         digestsDefined2.Add(digestsDefined[digestIndex]);
       
   494         digests2.Add(digests[digestIndex]);
       
   495       }
       
   496   }
       
   497   RINOK(WriteHashDigests(digestsDefined2, digests2));
       
   498   return WriteByte(NID::kEnd);
       
   499 }
       
   500 
       
   501 HRESULT COutArchive::WriteTime(
       
   502     const CObjectVector<CFileItem> &files, Byte type)
       
   503 {
       
   504   /////////////////////////////////////////////////
       
   505   // CreationTime
       
   506   CBoolVector boolVector;
       
   507   boolVector.Reserve(files.Size());
       
   508   bool thereAreDefined = false;
       
   509   bool allDefined = true;
       
   510   int i;
       
   511   for(i = 0; i < files.Size(); i++)
       
   512   {
       
   513     const CFileItem &item = files[i];
       
   514     bool defined;
       
   515     switch(type)
       
   516     {
       
   517       case NID::kCreationTime:
       
   518         defined = item.IsCreationTimeDefined;
       
   519         break;
       
   520       case NID::kLastWriteTime:
       
   521         defined = item.IsLastWriteTimeDefined;
       
   522         break;
       
   523       case NID::kLastAccessTime:
       
   524         defined = item.IsLastAccessTimeDefined;
       
   525         break;
       
   526       default:
       
   527         throw 1;
       
   528     }
       
   529     boolVector.Add(defined);
       
   530     thereAreDefined = (thereAreDefined || defined);
       
   531     allDefined = (allDefined && defined);
       
   532   }
       
   533   if (!thereAreDefined)
       
   534     return S_OK;
       
   535   RINOK(WriteByte(type));
       
   536   size_t dataSize = 1 + 1;
       
   537     dataSize += files.Size() * 8;
       
   538   if (allDefined)
       
   539   {
       
   540     RINOK(WriteNumber(dataSize));
       
   541     WriteByte(1);
       
   542   }
       
   543   else
       
   544   {
       
   545     RINOK(WriteNumber(1 + (boolVector.Size() + 7) / 8 + dataSize));
       
   546     WriteByte(0);
       
   547     RINOK(WriteBoolVector(boolVector));
       
   548   }
       
   549   RINOK(WriteByte(0));
       
   550   for(i = 0; i < files.Size(); i++)
       
   551   {
       
   552     if (boolVector[i])
       
   553     {
       
   554       const CFileItem &item = files[i];
       
   555       CArchiveFileTime timeValue;
       
   556       timeValue.dwLowDateTime = 0;
       
   557       timeValue.dwHighDateTime = 0;
       
   558       switch(type)
       
   559       {
       
   560         case NID::kCreationTime:
       
   561           timeValue = item.CreationTime;
       
   562           break;
       
   563         case NID::kLastWriteTime:
       
   564           timeValue = item.LastWriteTime;
       
   565           break;
       
   566         case NID::kLastAccessTime:
       
   567           timeValue = item.LastAccessTime;
       
   568           break;
       
   569       }
       
   570       RINOK(WriteUInt32(timeValue.dwLowDateTime));
       
   571       RINOK(WriteUInt32(timeValue.dwHighDateTime));
       
   572     }
       
   573   }
       
   574   return S_OK;
       
   575 }
       
   576 
       
   577 HRESULT COutArchive::EncodeStream(
       
   578     DECL_EXTERNAL_CODECS_LOC_VARS
       
   579     CEncoder &encoder, const Byte *data, size_t dataSize,
       
   580     CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
       
   581 {
       
   582   CSequentialInStreamImp *streamSpec = new CSequentialInStreamImp;
       
   583   CMyComPtr<ISequentialInStream> stream = streamSpec;
       
   584   streamSpec->Init(data, dataSize);
       
   585   CFolder folderItem;
       
   586   folderItem.UnPackCRCDefined = true;
       
   587   folderItem.UnPackCRC = CrcCalc(data, dataSize);
       
   588   UInt64 dataSize64 = dataSize;
       
   589   RINOK(encoder.Encode(
       
   590       EXTERNAL_CODECS_LOC_VARS
       
   591       stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL))
       
   592   folders.Add(folderItem);
       
   593   return S_OK;
       
   594 }
       
   595 
       
   596 HRESULT COutArchive::EncodeStream(
       
   597     DECL_EXTERNAL_CODECS_LOC_VARS
       
   598     CEncoder &encoder, const CByteBuffer &data, 
       
   599     CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders)
       
   600 {
       
   601   return EncodeStream(
       
   602       EXTERNAL_CODECS_LOC_VARS
       
   603       encoder, data, data.GetCapacity(), packSizes, folders);
       
   604 }
       
   605 
       
   606 static void WriteUInt32ToBuffer(Byte *data, UInt32 value)
       
   607 {
       
   608   for (int i = 0; i < 4; i++)
       
   609   {
       
   610     *data++ = (Byte)value;
       
   611     value >>= 8;
       
   612   }
       
   613 }
       
   614 
       
   615 static void WriteUInt64ToBuffer(Byte *data, UInt64 value)
       
   616 {
       
   617   for (int i = 0; i < 8; i++)
       
   618   {
       
   619     *data++ = (Byte)value;
       
   620     value >>= 8;
       
   621   }
       
   622 }
       
   623 
       
   624 
       
   625 HRESULT COutArchive::WriteHeader(
       
   626     const CArchiveDatabase &database,
       
   627     const CHeaderOptions &headerOptions,
       
   628     UInt64 &headerOffset)
       
   629 {
       
   630   int i;
       
   631   
       
   632   /////////////////////////////////
       
   633   // Names
       
   634 
       
   635   CNum numDefinedNames = 0;
       
   636   size_t namesDataSize = 0;
       
   637   for(i = 0; i < database.Files.Size(); i++)
       
   638   {
       
   639     const UString &name = database.Files[i].Name;
       
   640     if (!name.IsEmpty())
       
   641       numDefinedNames++;
       
   642     namesDataSize += (name.Length() + 1) * 2;
       
   643   }
       
   644 
       
   645   CByteBuffer namesData;
       
   646   if (numDefinedNames > 0)
       
   647   {
       
   648     namesData.SetCapacity((size_t)namesDataSize);
       
   649     size_t pos = 0;
       
   650     for(int i = 0; i < database.Files.Size(); i++)
       
   651     {
       
   652       const UString &name = database.Files[i].Name;
       
   653       for (int t = 0; t < name.Length(); t++)
       
   654       {
       
   655         wchar_t c = name[t];
       
   656         namesData[pos++] = Byte(c);
       
   657         namesData[pos++] = Byte(c >> 8);
       
   658       }
       
   659       namesData[pos++] = 0;
       
   660       namesData[pos++] = 0;
       
   661     }
       
   662   }
       
   663 
       
   664   /////////////////////////////////
       
   665   // Write Attributes
       
   666   CBoolVector attributesBoolVector;
       
   667   attributesBoolVector.Reserve(database.Files.Size());
       
   668   int numDefinedAttributes = 0;
       
   669   for(i = 0; i < database.Files.Size(); i++)
       
   670   {
       
   671     bool defined = database.Files[i].AreAttributesDefined;
       
   672     attributesBoolVector.Add(defined);
       
   673     if (defined)
       
   674       numDefinedAttributes++;
       
   675   }
       
   676 
       
   677   CByteBuffer attributesData;
       
   678   if (numDefinedAttributes > 0)
       
   679   {
       
   680     attributesData.SetCapacity(numDefinedAttributes * 4);
       
   681     size_t pos = 0;
       
   682     for(i = 0; i < database.Files.Size(); i++)
       
   683     {
       
   684       const CFileItem &file = database.Files[i];
       
   685       if (file.AreAttributesDefined)
       
   686       {
       
   687         WriteUInt32ToBuffer(attributesData + pos, file.Attributes);
       
   688         pos += 4;
       
   689       }
       
   690     }
       
   691   }
       
   692 
       
   693   /////////////////////////////////
       
   694   // Write StartPos
       
   695   CBoolVector startsBoolVector;
       
   696   startsBoolVector.Reserve(database.Files.Size());
       
   697   int numDefinedStarts = 0;
       
   698   for(i = 0; i < database.Files.Size(); i++)
       
   699   {
       
   700     bool defined = database.Files[i].IsStartPosDefined;
       
   701     startsBoolVector.Add(defined);
       
   702     if (defined)
       
   703       numDefinedStarts++;
       
   704   }
       
   705 
       
   706   CByteBuffer startsData;
       
   707   if (numDefinedStarts > 0)
       
   708   {
       
   709     startsData.SetCapacity(numDefinedStarts * 8);
       
   710     size_t pos = 0;
       
   711     for(i = 0; i < database.Files.Size(); i++)
       
   712     {
       
   713       const CFileItem &file = database.Files[i];
       
   714       if (file.IsStartPosDefined)
       
   715       {
       
   716         WriteUInt64ToBuffer(startsData + pos, file.StartPos);
       
   717         pos += 8;
       
   718       }
       
   719     }
       
   720   }
       
   721   
       
   722   /////////////////////////////////
       
   723   // Write Last Write Time
       
   724   // /*
       
   725   CNum numDefinedLastWriteTimes = 0;
       
   726   for(i = 0; i < database.Files.Size(); i++)
       
   727     if (database.Files[i].IsLastWriteTimeDefined)
       
   728       numDefinedLastWriteTimes++;
       
   729 
       
   730   if (numDefinedLastWriteTimes > 0)
       
   731   {
       
   732     CByteBuffer lastWriteTimeData;
       
   733     lastWriteTimeData.SetCapacity(numDefinedLastWriteTimes * 8);
       
   734     size_t pos = 0;
       
   735     for(i = 0; i < database.Files.Size(); i++)
       
   736     {
       
   737       const CFileItem &file = database.Files[i];
       
   738       if (file.IsLastWriteTimeDefined)
       
   739       {
       
   740         WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwLowDateTime);
       
   741         pos += 4;
       
   742         WriteUInt32ToBuffer(lastWriteTimeData + pos, file.LastWriteTime.dwHighDateTime);
       
   743         pos += 4;
       
   744       }
       
   745     }
       
   746   }
       
   747   // */
       
   748   
       
   749 
       
   750   UInt64 packedSize = 0;
       
   751   for(i = 0; i < database.PackSizes.Size(); i++)
       
   752     packedSize += database.PackSizes[i];
       
   753 
       
   754   headerOffset = packedSize;
       
   755 
       
   756   _mainMode = true;
       
   757 
       
   758   _outByte.SetStream(SeqStream);
       
   759   _outByte.Init();
       
   760   _crc = CRC_INIT_VAL;
       
   761 
       
   762 
       
   763   RINOK(WriteByte(NID::kHeader));
       
   764 
       
   765   // Archive Properties
       
   766 
       
   767   if (database.Folders.Size() > 0)
       
   768   {
       
   769     RINOK(WriteByte(NID::kMainStreamsInfo));
       
   770     RINOK(WritePackInfo(0, database.PackSizes, 
       
   771         database.PackCRCsDefined,
       
   772         database.PackCRCs));
       
   773 
       
   774     RINOK(WriteUnPackInfo(database.Folders));
       
   775 
       
   776     CRecordVector<UInt64> unPackSizes;
       
   777     CRecordVector<bool> digestsDefined;
       
   778     CRecordVector<UInt32> digests;
       
   779     for (i = 0; i < database.Files.Size(); i++)
       
   780     {
       
   781       const CFileItem &file = database.Files[i];
       
   782       if (!file.HasStream)
       
   783         continue;
       
   784       unPackSizes.Add(file.UnPackSize);
       
   785       digestsDefined.Add(file.IsFileCRCDefined);
       
   786       digests.Add(file.FileCRC);
       
   787     }
       
   788 
       
   789     RINOK(WriteSubStreamsInfo(
       
   790         database.Folders,
       
   791         database.NumUnPackStreamsVector,
       
   792         unPackSizes,
       
   793         digestsDefined,
       
   794         digests));
       
   795     RINOK(WriteByte(NID::kEnd));
       
   796   }
       
   797 
       
   798   if (database.Files.IsEmpty())
       
   799   {
       
   800     RINOK(WriteByte(NID::kEnd));
       
   801     return _outByte.Flush();
       
   802   }
       
   803 
       
   804   RINOK(WriteByte(NID::kFilesInfo));
       
   805   RINOK(WriteNumber(database.Files.Size()));
       
   806 
       
   807   CBoolVector emptyStreamVector;
       
   808   emptyStreamVector.Reserve(database.Files.Size());
       
   809   int numEmptyStreams = 0;
       
   810   for(i = 0; i < database.Files.Size(); i++)
       
   811     if (database.Files[i].HasStream)
       
   812       emptyStreamVector.Add(false);
       
   813     else
       
   814     {
       
   815       emptyStreamVector.Add(true);
       
   816       numEmptyStreams++;
       
   817     }
       
   818   if (numEmptyStreams > 0)
       
   819   {
       
   820     RINOK(WriteByte(NID::kEmptyStream));
       
   821     RINOK(WriteNumber((emptyStreamVector.Size() + 7) / 8));
       
   822     RINOK(WriteBoolVector(emptyStreamVector));
       
   823 
       
   824     CBoolVector emptyFileVector, antiVector;
       
   825     emptyFileVector.Reserve(numEmptyStreams);
       
   826     antiVector.Reserve(numEmptyStreams);
       
   827     CNum numEmptyFiles = 0, numAntiItems = 0;
       
   828     for(i = 0; i < database.Files.Size(); i++)
       
   829     {
       
   830       const CFileItem &file = database.Files[i];
       
   831       if (!file.HasStream)
       
   832       {
       
   833         emptyFileVector.Add(!file.IsDirectory);
       
   834         if (!file.IsDirectory)
       
   835           numEmptyFiles++;
       
   836         antiVector.Add(file.IsAnti);
       
   837         if (file.IsAnti)
       
   838           numAntiItems++;
       
   839       }
       
   840     }
       
   841 
       
   842     if (numEmptyFiles > 0)
       
   843     {
       
   844       RINOK(WriteByte(NID::kEmptyFile));
       
   845       RINOK(WriteNumber((emptyFileVector.Size() + 7) / 8));
       
   846       RINOK(WriteBoolVector(emptyFileVector));
       
   847     }
       
   848 
       
   849     if (numAntiItems > 0)
       
   850     {
       
   851       RINOK(WriteByte(NID::kAnti));
       
   852       RINOK(WriteNumber((antiVector.Size() + 7) / 8));
       
   853       RINOK(WriteBoolVector(antiVector));
       
   854     }
       
   855   }
       
   856 
       
   857   if (numDefinedNames > 0)
       
   858   {
       
   859     /////////////////////////////////////////////////
       
   860     RINOK(WriteByte(NID::kName));
       
   861     {
       
   862       RINOK(WriteNumber(1 + namesData.GetCapacity()));
       
   863       RINOK(WriteByte(0));
       
   864       RINOK(WriteBytes(namesData));
       
   865     }
       
   866 
       
   867   }
       
   868 
       
   869   if (headerOptions.WriteCreated)
       
   870   {
       
   871     RINOK(WriteTime(database.Files, NID::kCreationTime));
       
   872   }
       
   873   if (headerOptions.WriteModified)
       
   874   {
       
   875     RINOK(WriteTime(database.Files, NID::kLastWriteTime));
       
   876   }
       
   877   if (headerOptions.WriteAccessed)
       
   878   {
       
   879     RINOK(WriteTime(database.Files, NID::kLastAccessTime));
       
   880   }
       
   881 
       
   882   if (numDefinedAttributes > 0)
       
   883   {
       
   884     RINOK(WriteByte(NID::kWinAttributes));
       
   885     size_t size = 2;
       
   886     if (numDefinedAttributes != database.Files.Size())
       
   887       size += (attributesBoolVector.Size() + 7) / 8 + 1;
       
   888       size += attributesData.GetCapacity();
       
   889 
       
   890     RINOK(WriteNumber(size));
       
   891     if (numDefinedAttributes == database.Files.Size())
       
   892     {
       
   893       RINOK(WriteByte(1));
       
   894     }
       
   895     else
       
   896     {
       
   897       RINOK(WriteByte(0));
       
   898       RINOK(WriteBoolVector(attributesBoolVector));
       
   899     }
       
   900 
       
   901     {
       
   902       RINOK(WriteByte(0));
       
   903       RINOK(WriteBytes(attributesData));
       
   904     }
       
   905   }
       
   906 
       
   907   if (numDefinedStarts > 0)
       
   908   {
       
   909     RINOK(WriteByte(NID::kStartPos));
       
   910     size_t size = 2;
       
   911     if (numDefinedStarts != database.Files.Size())
       
   912       size += (startsBoolVector.Size() + 7) / 8 + 1;
       
   913       size += startsData.GetCapacity();
       
   914 
       
   915     RINOK(WriteNumber(size));
       
   916     if (numDefinedStarts == database.Files.Size())
       
   917     {
       
   918       RINOK(WriteByte(1));
       
   919     }
       
   920     else
       
   921     {
       
   922       RINOK(WriteByte(0));
       
   923       RINOK(WriteBoolVector(startsBoolVector));
       
   924     }
       
   925 
       
   926     {
       
   927       RINOK(WriteByte(0));
       
   928       RINOK(WriteBytes(startsData));
       
   929     }
       
   930   }
       
   931 
       
   932   RINOK(WriteByte(NID::kEnd)); // for files
       
   933   RINOK(WriteByte(NID::kEnd)); // for headers
       
   934 
       
   935   return _outByte.Flush();
       
   936 }
       
   937 
       
   938 HRESULT COutArchive::WriteDatabase(
       
   939     DECL_EXTERNAL_CODECS_LOC_VARS
       
   940     const CArchiveDatabase &database,
       
   941     const CCompressionMethodMode *options, 
       
   942     const CHeaderOptions &headerOptions)
       
   943 {
       
   944   UInt64 headerOffset;
       
   945   UInt32 headerCRC;
       
   946   UInt64 headerSize;
       
   947   if (database.IsEmpty())
       
   948   {
       
   949     headerSize = 0;
       
   950     headerOffset = 0;
       
   951     headerCRC = CrcCalc(0, 0);
       
   952   }
       
   953   else
       
   954   {
       
   955     _dynamicBuffer.Init();
       
   956     _dynamicMode = false;
       
   957 
       
   958     if (options != 0)
       
   959       if (options->IsEmpty())
       
   960         options = 0;
       
   961     if (options != 0)
       
   962       if (options->PasswordIsDefined || headerOptions.CompressMainHeader)
       
   963         _dynamicMode = true;
       
   964     RINOK(WriteHeader(database, headerOptions, headerOffset));
       
   965 
       
   966     if (_dynamicMode)
       
   967     {
       
   968       CCompressionMethodMode encryptOptions;
       
   969       encryptOptions.PasswordIsDefined = options->PasswordIsDefined;
       
   970       encryptOptions.Password = options->Password;
       
   971       CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions);
       
   972       CRecordVector<UInt64> packSizes;
       
   973       CObjectVector<CFolder> folders;
       
   974       RINOK(EncodeStream(
       
   975           EXTERNAL_CODECS_LOC_VARS
       
   976           encoder, _dynamicBuffer, 
       
   977           _dynamicBuffer.GetSize(), packSizes, folders));
       
   978       _dynamicMode = false;
       
   979       _mainMode = true;
       
   980       
       
   981       _outByte.SetStream(SeqStream);
       
   982       _outByte.Init();
       
   983       _crc = CRC_INIT_VAL;
       
   984       
       
   985       if (folders.Size() == 0)
       
   986         throw 1;
       
   987 
       
   988       RINOK(WriteID(NID::kEncodedHeader));
       
   989       RINOK(WritePackInfo(headerOffset, packSizes, 
       
   990         CRecordVector<bool>(), CRecordVector<UInt32>()));
       
   991       RINOK(WriteUnPackInfo(folders));
       
   992       RINOK(WriteByte(NID::kEnd));
       
   993       for (int i = 0; i < packSizes.Size(); i++)
       
   994         headerOffset += packSizes[i];
       
   995       RINOK(_outByte.Flush());
       
   996     }
       
   997     headerCRC = CRC_GET_DIGEST(_crc);
       
   998     headerSize = _outByte.GetProcessedSize();
       
   999   }
       
  1000   #ifdef _7Z_VOL
       
  1001   if (_endMarker)
       
  1002   {
       
  1003     CFinishHeader h;
       
  1004     h.NextHeaderSize = headerSize;
       
  1005     h.NextHeaderCRC = headerCRC;
       
  1006     h.NextHeaderOffset = 
       
  1007         UInt64(0) - (headerSize + 
       
  1008         4 + kFinishHeaderSize);
       
  1009     h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset;
       
  1010     h.AdditionalStartBlockSize = 0;
       
  1011     RINOK(WriteFinishHeader(h));
       
  1012     return WriteFinishSignature();
       
  1013   }
       
  1014   else
       
  1015   #endif
       
  1016   {
       
  1017     CStartHeader h;
       
  1018     h.NextHeaderSize = headerSize;
       
  1019     h.NextHeaderCRC = headerCRC;
       
  1020     h.NextHeaderOffset = headerOffset;
       
  1021     RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL));
       
  1022     return WriteStartHeader(h);
       
  1023   }
       
  1024 }
       
  1025 
       
  1026 }}