arccmt.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. static bool IsAnsiEscComment(const wchar *Data,size_t Size);
  2. bool Archive::GetComment(Array<wchar> *CmtData)
  3. {
  4. if (!MainComment)
  5. return false;
  6. int64 SavePos=Tell();
  7. bool Success=DoGetComment(CmtData);
  8. Seek(SavePos,SEEK_SET);
  9. return Success;
  10. }
  11. bool Archive::DoGetComment(Array<wchar> *CmtData)
  12. {
  13. #ifndef SFX_MODULE
  14. uint CmtLength;
  15. if (Format==RARFMT14)
  16. {
  17. Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
  18. CmtLength=GetByte();
  19. CmtLength+=(GetByte()<<8);
  20. }
  21. else
  22. #endif
  23. {
  24. if (MainHead.CommentInHeader)
  25. {
  26. // Old style (RAR 2.9) archive comment embedded into the main
  27. // archive header.
  28. Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
  29. if (!ReadHeader() || GetHeaderType()!=HEAD3_CMT)
  30. return false;
  31. }
  32. else
  33. {
  34. // Current (RAR 3.0+) version of archive comment.
  35. Seek(GetStartPos(),SEEK_SET);
  36. return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData);
  37. }
  38. #ifndef SFX_MODULE
  39. // Old style (RAR 2.9) comment header embedded into the main
  40. // archive header.
  41. if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
  42. {
  43. uiMsg(UIERROR_CMTBROKEN,FileName);
  44. return false;
  45. }
  46. CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD;
  47. #endif
  48. }
  49. #ifndef SFX_MODULE
  50. if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30)
  51. {
  52. if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35))
  53. return false;
  54. ComprDataIO DataIO;
  55. DataIO.SetTestMode(true);
  56. uint UnpCmtLength;
  57. if (Format==RARFMT14)
  58. {
  59. #ifdef RAR_NOCRYPT
  60. return false;
  61. #else
  62. UnpCmtLength=GetByte();
  63. UnpCmtLength+=(GetByte()<<8);
  64. if (CmtLength<2)
  65. return false;
  66. CmtLength-=2;
  67. DataIO.SetCmt13Encryption();
  68. CommHead.UnpVer=15;
  69. #endif
  70. }
  71. else
  72. UnpCmtLength=CommHead.UnpSize;
  73. DataIO.SetFiles(this,NULL);
  74. DataIO.EnableShowProgress(false);
  75. DataIO.SetPackedSizeToRead(CmtLength);
  76. DataIO.UnpHash.Init(HASH_CRC32,1);
  77. DataIO.SetNoFileHeader(true); // this->FileHead is not filled yet.
  78. Unpack CmtUnpack(&DataIO);
  79. CmtUnpack.Init(0x10000,false);
  80. CmtUnpack.SetDestSize(UnpCmtLength);
  81. CmtUnpack.DoUnpack(CommHead.UnpVer,false);
  82. if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC)
  83. {
  84. uiMsg(UIERROR_CMTBROKEN,FileName);
  85. return false;
  86. }
  87. else
  88. {
  89. byte *UnpData;
  90. size_t UnpDataSize;
  91. DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
  92. if (UnpDataSize>0)
  93. {
  94. #ifdef _WIN_ALL
  95. // If we ever decide to extend it to Android, we'll need to alloc
  96. // 4x memory for OEM to UTF-8 output here.
  97. OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
  98. #endif
  99. CmtData->Alloc(UnpDataSize+1);
  100. memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
  101. CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
  102. CmtData->Alloc(wcslen(CmtData->Addr(0)));
  103. }
  104. }
  105. }
  106. else
  107. {
  108. if (CmtLength==0)
  109. return false;
  110. Array<byte> CmtRaw(CmtLength);
  111. int ReadSize=Read(&CmtRaw[0],CmtLength);
  112. if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
  113. {
  114. CmtLength=ReadSize;
  115. CmtRaw.Alloc(CmtLength);
  116. }
  117. if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
  118. {
  119. uiMsg(UIERROR_CMTBROKEN,FileName);
  120. return false;
  121. }
  122. CmtData->Alloc(CmtLength+1);
  123. CmtRaw.Push(0);
  124. #ifdef _WIN_ALL
  125. // If we ever decide to extend it to Android, we'll need to alloc
  126. // 4x memory for OEM to UTF-8 output here.
  127. OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
  128. #endif
  129. CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
  130. CmtData->Alloc(wcslen(CmtData->Addr(0)));
  131. }
  132. #endif
  133. return CmtData->Size() > 0;
  134. }
  135. bool Archive::ReadCommentData(Array<wchar> *CmtData)
  136. {
  137. Array<byte> CmtRaw;
  138. if (!ReadSubData(&CmtRaw,NULL,false))
  139. return false;
  140. size_t CmtSize=CmtRaw.Size();
  141. CmtRaw.Push(0);
  142. CmtData->Alloc(CmtSize+1);
  143. if (Format==RARFMT50)
  144. UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
  145. else
  146. if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
  147. {
  148. RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
  149. (*CmtData)[CmtSize/2]=0;
  150. }
  151. else
  152. {
  153. CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
  154. }
  155. CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
  156. return true;
  157. }
  158. void Archive::ViewComment()
  159. {
  160. if (Cmd->DisableComment)
  161. return;
  162. Array<wchar> CmtBuf;
  163. if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments.
  164. {
  165. size_t CmtSize=CmtBuf.Size();
  166. wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
  167. if (ChPtr!=NULL)
  168. CmtSize=ChPtr-&CmtBuf[0];
  169. mprintf(L"\n");
  170. OutComment(&CmtBuf[0],CmtSize);
  171. }
  172. }