7zOut.cpp 24 KB

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