Coverage Report

Created: 2025-01-09 06:48

/src/unrar/arcread.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "rar.hpp"
2
3
size_t Archive::ReadHeader()
4
161k
{
5
  // Once we failed to decrypt an encrypted block, there is no reason to
6
  // attempt to do it further. We'll never be successful and only generate
7
  // endless errors.
8
161k
  if (FailedHeaderDecryption)
9
1
    return 0;
10
11
161k
  CurBlockPos=Tell();
12
13
  // Other developers asked us to initialize it to suppress "may be used
14
  // uninitialized" warning in code below in some compilers.
15
161k
  size_t ReadSize=0;
16
17
161k
  switch(Format)
18
161k
  {
19
0
#ifndef SFX_MODULE
20
6.13k
    case RARFMT14:
21
6.13k
      ReadSize=ReadHeader14();
22
6.13k
      break;
23
24.6k
    case RARFMT15:
24
24.6k
      ReadSize=ReadHeader15();
25
24.6k
      break;
26
0
#endif
27
130k
    case RARFMT50:
28
130k
      ReadSize=ReadHeader50();
29
130k
      break;
30
161k
  }
31
32
  // It is important to check ReadSize>0 here, because it is normal
33
  // for RAR2 and RAR3 archives without end of archive block to have
34
  // NextBlockPos==CurBlockPos after the end of archive has reached.
35
161k
  if (ReadSize>0 && NextBlockPos<=CurBlockPos)
36
249
  {
37
249
    BrokenHeaderMsg();
38
249
    ReadSize=0;
39
249
  }
40
41
161k
  if (ReadSize==0)
42
17.7k
    CurHeaderType=HEAD_UNKNOWN;
43
44
161k
  return ReadSize;
45
161k
}
46
47
48
size_t Archive::SearchBlock(HEADER_TYPE HeaderType)
49
0
{
50
0
  size_t Size,Count=0;
51
0
  while ((Size=ReadHeader())!=0 &&
52
0
         (HeaderType==HEAD_ENDARC || GetHeaderType()!=HEAD_ENDARC))
53
0
  {
54
0
    if ((++Count & 127)==0)
55
0
      Wait();
56
0
    if (GetHeaderType()==HeaderType)
57
0
      return Size;
58
0
    SeekToNext();
59
0
  }
60
0
  return 0;
61
0
}
62
63
64
size_t Archive::SearchSubBlock(const wchar *Type)
65
105
{
66
105
  size_t Size,Count=0;
67
3.67k
  while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC)
68
3.56k
  {
69
3.56k
    if ((++Count & 127)==0)
70
18
      Wait();
71
3.56k
    if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type))
72
0
      return Size;
73
3.56k
    SeekToNext();
74
3.56k
  }
75
105
  return 0;
76
105
}
77
78
79
size_t Archive::SearchRR()
80
0
{
81
  // If locator extra field is available for recovery record, let's utilize it.
82
0
  if (MainHead.Locator && MainHead.RROffset!=0)
83
0
  {
84
0
    uint64 CurPos=Tell();
85
0
    Seek(MainHead.RROffset,SEEK_SET);
86
0
    size_t Size=ReadHeader();
87
0
    if (Size!=0 && !BrokenHeader && GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(SUBHEAD_TYPE_RR))
88
0
      return Size;
89
0
    Seek(CurPos,SEEK_SET);
90
0
  }
91
  // Otherwise scan the entire archive to find the recovery record.
92
0
  return SearchSubBlock(SUBHEAD_TYPE_RR);
93
0
}
94
95
96
void Archive::UnexpEndArcMsg()
97
7.94k
{
98
7.94k
  int64 ArcSize=FileLength();
99
100
  // If block positions are equal to file size, this is not an error.
101
  // It can happen when we reached the end of older RAR 1.5 archive,
102
  // which did not have the end of archive block.
103
  // We can't replace this check by checking that read size is exactly 0
104
  // in the beginning of file header, because in this case the read position
105
  // still can be beyond the end of archive.
106
7.94k
  if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize)
107
7.79k
  {
108
7.79k
    uiMsg(UIERROR_UNEXPEOF,FileName);
109
7.79k
    if (CurHeaderType!=HEAD_FILE)
110
2.77k
      uiMsg(UIERROR_TRUNCSERVICE,FileName,SubHead.FileName);
111
112
7.79k
    ErrHandler.SetErrorCode(RARX_WARNING);
113
7.79k
  }
114
7.94k
}
115
116
117
void Archive::BrokenHeaderMsg()
118
130k
{
119
130k
  uiMsg(UIERROR_HEADERBROKEN,FileName);
120
130k
  BrokenHeader=true;
121
130k
  ErrHandler.SetErrorCode(RARX_CRC);
122
130k
}
123
124
125
void Archive::UnkEncVerMsg(const std::wstring &Name,const std::wstring &Info)
126
2.24k
{
127
2.24k
  uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
128
2.24k
  ErrHandler.SetErrorCode(RARX_FATAL);
129
2.24k
}
130
131
132
// Return f in case of signed integer overflow or negative parameters
133
// or v1+v2 otherwise. We use it for file offsets, which are signed
134
// for compatibility with off_t in POSIX file functions and third party code.
135
// Signed integer overflow is the undefined behavior according to
136
// C++ standard and it causes fuzzers to complain.
137
inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
138
130k
{
139
130k
  return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f;
140
130k
}
141
142
143
#ifndef SFX_MODULE
144
size_t Archive::ReadHeader15()
145
24.6k
{
146
24.6k
  RawRead Raw(this);
147
148
24.6k
  bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3;
149
150
24.6k
  if (Decrypt)
151
27
  {
152
#ifdef RAR_NOCRYPT // For rarext.dll, Setup.SFX and unrar_nocrypt.dll.
153
    return 0;
154
#else
155
27
    RequestArcPassword(NULL);
156
157
27
    byte Salt[SIZE_SALT30];
158
27
    if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
159
0
    {
160
0
      UnexpEndArcMsg();
161
0
      return 0;
162
0
    }
163
27
    HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL);
164
27
    Raw.SetCrypt(&HeadersCrypt);
165
27
#endif
166
27
  }
167
168
24.6k
  Raw.Read(SIZEOF_SHORTBLOCKHEAD);
169
24.6k
  if (Raw.Size()==0)
170
3.33k
  {
171
3.33k
    UnexpEndArcMsg();
172
3.33k
    return 0;
173
3.33k
  }
174
175
21.3k
  ShortBlock.HeadCRC=Raw.Get2();
176
177
21.3k
  ShortBlock.Reset();
178
179
21.3k
  uint HeaderType=Raw.Get1();
180
21.3k
  ShortBlock.Flags=Raw.Get2();
181
21.3k
  ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
182
21.3k
  ShortBlock.HeadSize=Raw.Get2();
183
184
21.3k
  ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
185
21.3k
  if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
186
4.35k
  {
187
4.35k
    BrokenHeaderMsg();
188
4.35k
    return 0;
189
4.35k
  }
190
191
  // For simpler further processing we map header types common
192
  // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
193
  // header types specific for RAR 1.5 - 4.x only.
194
16.9k
  switch(ShortBlock.HeaderType)
195
16.9k
  {
196
82
    case HEAD3_MAIN:    ShortBlock.HeaderType=HEAD_MAIN;     break;
197
22
    case HEAD3_FILE:    ShortBlock.HeaderType=HEAD_FILE;     break;
198
157
    case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE;  break;
199
6
    case HEAD3_ENDARC:  ShortBlock.HeaderType=HEAD_ENDARC;   break;
200
16.9k
  }
201
16.9k
  CurHeaderType=ShortBlock.HeaderType;
202
203
16.9k
  if (ShortBlock.HeaderType==HEAD3_CMT)
204
41
  {
205
    // Old style (up to RAR 2.9) comment header embedded into main
206
    // or file header. We must not read the entire ShortBlock.HeadSize here
207
    // to not break the comment processing logic later.
208
41
    Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
209
41
  }
210
16.8k
  else
211
16.8k
    if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
212
1.33k
    {
213
      // Old style (up to RAR 2.9) main archive comment embedded into
214
      // the main archive header found. While we can read the entire
215
      // ShortBlock.HeadSize here and remove this part of "if", it would be
216
      // waste of memory, because we'll read and process this comment data
217
      // in other function anyway and we do not need them here now.
218
1.33k
      Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
219
1.33k
    }
220
15.5k
    else
221
15.5k
      Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
222
223
16.9k
  NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
224
225
16.9k
  switch(ShortBlock.HeaderType)
226
16.9k
  {
227
8.38k
    case HEAD_MAIN:
228
8.38k
      MainHead.Reset();
229
8.38k
      MainHead.SetBaseBlock(ShortBlock);
230
8.38k
      MainHead.HighPosAV=Raw.Get2();
231
8.38k
      MainHead.PosAV=Raw.Get4();
232
233
8.38k
      Volume=(MainHead.Flags & MHD_VOLUME)!=0;
234
8.38k
      Solid=(MainHead.Flags & MHD_SOLID)!=0;
235
8.38k
      Locked=(MainHead.Flags & MHD_LOCK)!=0;
236
8.38k
      Protected=(MainHead.Flags & MHD_PROTECT)!=0;
237
8.38k
      Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
238
8.38k
      Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
239
8.38k
      MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
240
241
      // Only for encrypted 3.0+ archives. 2.x archives did not have this
242
      // flag, so for non-encrypted archives, we'll set it later based on
243
      // file attributes.
244
8.38k
      FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0;
245
246
8.38k
      NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0;
247
8.38k
      break;
248
5.04k
    case HEAD_FILE:
249
6.36k
    case HEAD_SERVICE:
250
6.36k
      {
251
6.36k
        bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
252
6.36k
        FileHeader *hd=FileBlock ? &FileHead:&SubHead;
253
6.36k
        hd->Reset();
254
255
6.36k
        hd->SetBaseBlock(ShortBlock);
256
257
6.36k
        hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
258
6.36k
        hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
259
6.36k
        hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
260
6.36k
        hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
261
        
262
        // RAR versions earlier than 2.0 do not set the solid flag
263
        // in file header. They use only a global solid archive flag.
264
6.36k
        hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
265
266
6.36k
        hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
267
6.36k
        hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
268
6.36k
        hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
269
6.36k
        hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
270
6.36k
        hd->Version=(hd->Flags & LHD_VERSION)!=0;
271
272
6.36k
        hd->DataSize=Raw.Get4();
273
6.36k
        uint LowUnpSize=Raw.Get4();
274
6.36k
        hd->HostOS=Raw.Get1();
275
276
6.36k
        hd->FileHash.Type=HASH_CRC32;
277
6.36k
        hd->FileHash.CRC32=Raw.Get4();
278
279
6.36k
        uint FileTime=Raw.Get4();
280
6.36k
        hd->UnpVer=Raw.Get1();
281
282
6.36k
        hd->Method=Raw.Get1()-0x30;
283
6.36k
        size_t NameSize=Raw.Get2();
284
6.36k
        hd->FileAttr=Raw.Get4();
285
286
        // RAR15 did not use the special dictionary size to mark dirs.
287
6.36k
        if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
288
211
          hd->Dir=true;
289
290
6.36k
        hd->CryptMethod=CRYPT_NONE;
291
6.36k
        if (hd->Encrypted)
292
1.30k
          switch(hd->UnpVer)
293
1.30k
          {
294
15
            case 13: hd->CryptMethod=CRYPT_RAR13; break;
295
16
            case 15: hd->CryptMethod=CRYPT_RAR15; break;
296
12
            case 20:
297
32
            case 26: hd->CryptMethod=CRYPT_RAR20; break;
298
1.24k
            default: hd->CryptMethod=CRYPT_RAR30; break;
299
1.30k
          }
300
301
6.36k
        hd->HSType=HSYS_UNKNOWN;
302
6.36k
        if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
303
719
          hd->HSType=HSYS_UNIX;
304
5.64k
        else
305
5.64k
          if (hd->HostOS<HOST_MAX)
306
1.47k
            hd->HSType=HSYS_WINDOWS;
307
308
6.36k
        hd->RedirType=FSREDIR_NONE;
309
310
        // RAR 4.x Unix symlink.
311
6.36k
        if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
312
374
        {
313
374
          hd->RedirType=FSREDIR_UNIXSYMLINK;
314
374
          hd->RedirName.clear();
315
374
        }
316
317
6.36k
        hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
318
319
6.36k
        hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
320
321
6.36k
        uint HighPackSize,HighUnpSize;
322
6.36k
        if (hd->LargeFile)
323
3.11k
        {
324
3.11k
          HighPackSize=Raw.Get4();
325
3.11k
          HighUnpSize=Raw.Get4();
326
3.11k
          hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
327
3.11k
        }
328
3.25k
        else
329
3.25k
        {
330
3.25k
          HighPackSize=HighUnpSize=0;
331
          // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
332
          // that we do not know the unpacked file size and must unpack it
333
          // until we find the end of file marker in compressed data.
334
3.25k
          hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
335
3.25k
        }
336
6.36k
        hd->PackSize=INT32TO64(HighPackSize,hd->DataSize);
337
6.36k
        hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize);
338
6.36k
        if (hd->UnknownUnpSize)
339
71
          hd->UnpSize=INT64NDF;
340
341
6.36k
        size_t ReadNameSize=Min(NameSize,MAXPATHSIZE);
342
6.36k
        std::string FileName(ReadNameSize,0);
343
6.36k
        Raw.GetB((byte *)&FileName[0],ReadNameSize);
344
345
6.36k
        if (FileBlock)
346
5.04k
        {
347
5.04k
          hd->FileName.clear();
348
5.04k
          if ((hd->Flags & LHD_UNICODE)!=0)
349
2.05k
          {
350
2.05k
            EncodeFileName NameCoder;
351
2.05k
            size_t Length=strlen(FileName.data());
352
2.05k
            Length++;
353
2.05k
            if (ReadNameSize>Length)
354
1.76k
              NameCoder.Decode(FileName.data(),ReadNameSize,
355
1.76k
                               (byte *)&FileName[Length],
356
1.76k
                               ReadNameSize-Length,hd->FileName);
357
2.05k
          }
358
359
5.04k
          if (hd->FileName.empty())
360
3.29k
            ArcCharToWide(FileName.data(),hd->FileName,ACTW_OEM);
361
362
5.04k
#ifndef SFX_MODULE
363
5.04k
          ConvertNameCase(hd->FileName);
364
5.04k
#endif
365
5.04k
          ConvertFileHeader(hd);
366
5.04k
        }
367
1.31k
        else
368
1.31k
        {
369
1.31k
          CharToWide(FileName.data(),hd->FileName);
370
371
          // Calculate the size of optional data.
372
1.31k
          int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
373
1.31k
          if ((hd->Flags & LHD_SALT)!=0)
374
333
            DataSize-=SIZE_SALT30;
375
376
1.31k
          if (DataSize>0)
377
302
          {
378
            // Here we read optional additional fields for subheaders.
379
            // They are stored after the file name and before salt.
380
302
            hd->SubData.resize(DataSize);
381
302
            Raw.GetB(hd->SubData.data(),DataSize);
382
383
302
          }
384
385
1.31k
          if (hd->CmpName(SUBHEAD_TYPE_CMT))
386
0
            MainComment=true;
387
1.31k
        }
388
389
6.36k
        if ((hd->Flags & LHD_SALT)!=0)
390
3.10k
          Raw.GetB(hd->Salt,SIZE_SALT30);
391
6.36k
        hd->mtime.SetDos(FileTime);
392
6.36k
        if ((hd->Flags & LHD_EXTTIME)!=0)
393
1.97k
        {
394
1.97k
          ushort Flags=Raw.Get2();
395
1.97k
          RarTime *tbl[4];
396
1.97k
          tbl[0]=&FileHead.mtime;
397
1.97k
          tbl[1]=&FileHead.ctime;
398
1.97k
          tbl[2]=&FileHead.atime;
399
1.97k
          tbl[3]=NULL; // Archive time is not used now.
400
9.87k
          for (int I=0;I<4;I++)
401
7.90k
          {
402
7.90k
            RarTime *CurTime=tbl[I];
403
7.90k
            uint rmode=Flags>>(3-I)*4;
404
7.90k
            if ((rmode & 8)==0 || CurTime==NULL)
405
7.76k
              continue;
406
134
            if (I!=0)
407
90
            {
408
90
              uint DosTime=Raw.Get4();
409
90
              CurTime->SetDos(DosTime);
410
90
            }
411
134
            RarLocalTime rlt;
412
134
            CurTime->GetLocal(&rlt);
413
134
            if (rmode & 4)
414
83
              rlt.Second++;
415
134
            rlt.Reminder=0;
416
134
            uint count=rmode&3;
417
375
            for (uint J=0;J<count;J++)
418
241
            {
419
241
              byte CurByte=Raw.Get1();
420
241
              rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
421
241
            }
422
            // Convert from 100ns RAR precision to REMINDER_PRECISION.
423
134
            rlt.Reminder*=RarTime::REMINDER_PRECISION/10000000;
424
134
            CurTime->SetLocal(&rlt);
425
134
          }
426
1.97k
        }
427
        // Set to 0 in case of overflow, so end of ReadHeader cares about it.
428
6.36k
        NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
429
430
6.36k
        bool CRCProcessedOnly=hd->CommentInHeader;
431
6.36k
        uint HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
432
6.36k
        if (hd->HeadCRC!=HeaderCRC)
433
6.35k
        {
434
6.35k
          BrokenHeader=true;
435
6.35k
          ErrHandler.SetErrorCode(RARX_WARNING);
436
437
          // If we have a broken encrypted header, we do not need to display
438
          // the error message here, because it will be displayed for such
439
          // headers later in this function. Also such headers are unlikely
440
          // to have anything sensible in file name field, so it is useless
441
          // to display the file name.
442
6.35k
          if (!Decrypt)
443
6.35k
            uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
444
6.35k
        }
445
6.36k
      }
446
0
      break;
447
270
    case HEAD_ENDARC:
448
270
      EndArcHead.SetBaseBlock(ShortBlock);
449
270
      EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
450
270
      EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
451
270
      EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
452
270
      EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
453
270
      if (EndArcHead.DataCRC)
454
22
        EndArcHead.ArcDataCRC=Raw.Get4();
455
270
      if (EndArcHead.StoreVolNumber)
456
16
        VolNumber=EndArcHead.VolNumber=Raw.Get2();
457
270
      break;
458
0
#ifndef SFX_MODULE
459
41
    case HEAD3_CMT:
460
41
      CommHead.SetBaseBlock(ShortBlock);
461
41
      CommHead.UnpSize=Raw.Get2();
462
41
      CommHead.UnpVer=Raw.Get1();
463
41
      CommHead.Method=Raw.Get1();
464
41
      CommHead.CommCRC=Raw.Get2();
465
41
      break;
466
54
    case HEAD3_PROTECT:
467
54
      ProtectHead.SetBaseBlock(ShortBlock);
468
54
      ProtectHead.DataSize=Raw.Get4();
469
54
      ProtectHead.Version=Raw.Get1();
470
54
      ProtectHead.RecSectors=Raw.Get2();
471
54
      ProtectHead.TotalBlocks=Raw.Get4();
472
54
      Raw.GetB(ProtectHead.Mark,8);
473
54
      NextBlockPos+=ProtectHead.DataSize;
474
54
      break;
475
136
    case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
476
136
      SubBlockHead.SetBaseBlock(ShortBlock);
477
136
      SubBlockHead.DataSize=Raw.Get4();
478
136
      NextBlockPos+=SubBlockHead.DataSize;
479
136
      SubBlockHead.SubType=Raw.Get2();
480
136
      SubBlockHead.Level=Raw.Get1();
481
136
      switch(SubBlockHead.SubType)
482
136
      {
483
6
        case NTACL_HEAD:
484
6
          *(SubBlockHeader *)&EAHead=SubBlockHead;
485
6
          EAHead.UnpSize=Raw.Get4();
486
6
          EAHead.UnpVer=Raw.Get1();
487
6
          EAHead.Method=Raw.Get1();
488
6
          EAHead.EACRC=Raw.Get4();
489
6
          break;
490
27
        case STREAM_HEAD:
491
27
          *(SubBlockHeader *)&StreamHead=SubBlockHead;
492
27
          StreamHead.UnpSize=Raw.Get4();
493
27
          StreamHead.UnpVer=Raw.Get1();
494
27
          StreamHead.Method=Raw.Get1();
495
27
          StreamHead.StreamCRC=Raw.Get4();
496
27
          StreamHead.StreamNameSize=Raw.Get2();
497
498
27
          const size_t MaxStreamName20=260; // Maximum allowed stream name in RAR 2.x format.
499
27
          if (StreamHead.StreamNameSize>MaxStreamName20)
500
15
            StreamHead.StreamNameSize=MaxStreamName20;
501
502
27
          StreamHead.StreamName.resize(StreamHead.StreamNameSize);
503
27
          Raw.GetB(&StreamHead.StreamName[0],StreamHead.StreamNameSize);
504
27
          break;
505
136
      }
506
136
      break;
507
136
#endif
508
1.68k
    default:
509
1.68k
      if (ShortBlock.Flags & LONG_BLOCK)
510
226
        NextBlockPos+=Raw.Get4();
511
1.68k
      break;
512
16.9k
  }
513
514
16.9k
  uint HeaderCRC=Raw.GetCRC15(false);
515
516
  // Old AV header does not have header CRC properly set.
517
  // Old Unix owners header didn't include string fields into header size,
518
  // but included them into CRC, so it couldn't be verified with generic
519
  // approach here.
520
16.9k
  if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
521
16.9k
      ShortBlock.HeaderType!=HEAD3_AV && 
522
16.9k
      (ShortBlock.HeaderType!=HEAD3_OLDSERVICE || SubBlockHead.SubType!=UO_HEAD))
523
16.8k
  {
524
16.8k
    bool Recovered=false;
525
16.8k
    if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace)
526
246
    {
527
      // Last 7 bytes of recovered volume can contain zeroes, because
528
      // REV files store its own information (volume number, etc.) here.
529
246
      int64 Length=Tell();
530
246
      Seek(Length-7,SEEK_SET);
531
246
      Recovered=true;
532
1.96k
      for (int J=0;J<7;J++)
533
1.72k
        if (GetByte()!=0)
534
1.65k
          Recovered=false;
535
246
    }
536
16.8k
    if (!Recovered)
537
16.8k
    {
538
16.8k
      BrokenHeader=true;
539
16.8k
      ErrHandler.SetErrorCode(RARX_CRC);
540
541
16.8k
      if (Decrypt)
542
0
      {
543
0
        uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
544
0
        FailedHeaderDecryption=true;
545
0
        return 0;
546
0
      }
547
16.8k
    }
548
16.8k
  }
549
550
16.9k
  return Raw.Size();
551
16.9k
}
552
#endif // #ifndef SFX_MODULE
553
554
555
size_t Archive::ReadHeader50()
556
130k
{
557
130k
  RawRead Raw(this);
558
559
130k
  bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5;
560
561
130k
  if (Decrypt)
562
66
  {
563
#if defined(RAR_NOCRYPT)
564
    return 0;
565
#else
566
567
66
    if (Cmd->SkipEncrypted)
568
0
    {
569
0
      uiMsg(UIMSG_SKIPENCARC,FileName);
570
0
      FailedHeaderDecryption=true; // Suppress error messages and quit quietly.
571
0
      return 0;
572
0
    }
573
574
66
    byte HeadersInitV[SIZE_INITV];
575
66
    if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
576
62
    {
577
62
      UnexpEndArcMsg();
578
62
      return 0;
579
62
    }
580
581
    // We repeat the password request only for manually entered passwords
582
    // and not for -p<pwd>. Wrong password can be intentionally provided
583
    // in -p<pwd> to not stop batch processing for encrypted archives.
584
4
    bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
585
586
4
    RarCheckPassword CheckPwd;
587
4
    if (CryptHead.UsePswCheck && !BrokenHeader)
588
0
      CheckPwd.Set(CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,CryptHead.PswCheck);
589
    
590
4
    while (true) // Repeat the password prompt for wrong passwords.
591
4
    {
592
4
      RequestArcPassword(CheckPwd.IsSet() ? &CheckPwd:NULL);
593
594
4
      byte PswCheck[SIZE_PSWCHECK];
595
4
      bool EncSet=HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
596
      // Verify password validity. If header is damaged, we cannot rely on
597
      // password check value, because it can be damaged too.
598
4
      if (EncSet && CryptHead.UsePswCheck && !BrokenHeader &&
599
4
          memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
600
0
      {
601
0
        if (GlobalPassword) // For -p<pwd> or Ctrl+P.
602
0
        {
603
          // This message is used by Android GUI to reset cached passwords.
604
          // Update appropriate code if changed.
605
0
          uiMsg(UIERROR_BADPSW,FileName,FileName);
606
0
          FailedHeaderDecryption=true;
607
0
          ErrHandler.SetErrorCode(RARX_BADPWD);
608
0
          return 0;
609
0
        }
610
0
        else // For passwords entered manually.
611
0
        {
612
          // This message is used by Android GUI and Windows GUI and SFX to
613
          // reset cached passwords. Update appropriate code if changed.
614
0
          uiMsg(UIWAIT_BADPSW,FileName,FileName);
615
0
          Cmd->Password.Clean();
616
0
        }
617
618
0
#ifdef RARDLL
619
        // Avoid new requests for unrar.dll to prevent the infinite loop
620
        // if app always returns the same password.
621
0
        ErrHandler.SetErrorCode(RARX_BADPWD);
622
0
        Cmd->DllError=ERAR_BAD_PASSWORD;
623
0
        ErrHandler.Exit(RARX_BADPWD);
624
#else
625
        continue; // Request a password again.
626
#endif
627
0
      }
628
4
      break;
629
4
    }
630
631
4
    Raw.SetCrypt(&HeadersCrypt);
632
4
#endif
633
4
  }
634
635
  // Header size must not occupy more than 3 variable length integer bytes
636
  // resulting in 2 MB maximum header size (MAX_HEADER_SIZE_RAR5),
637
  // so here we read 4 byte CRC32 followed by 3 bytes or less of header size.
638
130k
  const size_t FirstReadSize=7; // Smallest possible block size.
639
130k
  if (Raw.Read(FirstReadSize)<FirstReadSize)
640
3.90k
  {
641
3.90k
    UnexpEndArcMsg();
642
3.90k
    return 0;
643
3.90k
  }
644
645
126k
  ShortBlock.Reset();
646
126k
  ShortBlock.HeadCRC=Raw.Get4();
647
126k
  uint SizeBytes=Raw.GetVSize(4);
648
126k
  uint64 BlockSize=Raw.GetV();
649
650
126k
  if (BlockSize==0 || SizeBytes==0)
651
1.21k
  {
652
1.21k
    BrokenHeaderMsg();
653
1.21k
    return 0;
654
1.21k
  }
655
656
125k
  int SizeToRead=int(BlockSize);
657
125k
  SizeToRead-=int(FirstReadSize-SizeBytes-4); // Adjust overread size bytes if any.
658
125k
  uint HeaderSize=4+SizeBytes+(uint)BlockSize;
659
660
125k
  if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
661
233
  {
662
233
    BrokenHeaderMsg();
663
233
    return 0;
664
233
  }
665
666
125k
  Raw.Read(SizeToRead);
667
668
125k
  if (Raw.Size()<HeaderSize)
669
644
  {
670
644
    UnexpEndArcMsg();
671
644
    return 0;
672
644
  }
673
674
124k
  uint HeaderCRC=Raw.GetCRC50();
675
676
124k
  ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
677
124k
  ShortBlock.Flags=(uint)Raw.GetV();
678
124k
  ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
679
124k
  ShortBlock.HeadSize=HeaderSize;
680
681
124k
  CurHeaderType=ShortBlock.HeaderType;
682
683
124k
  bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
684
124k
  if (BadCRC)
685
124k
  {
686
124k
    BrokenHeaderMsg(); // Report, but attempt to process.
687
688
124k
    BrokenHeader=true;
689
124k
    ErrHandler.SetErrorCode(RARX_CRC);
690
691
124k
    if (Decrypt)
692
0
    {
693
0
      uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
694
0
      FailedHeaderDecryption=true;
695
0
      return 0;
696
0
    }
697
124k
  }
698
699
124k
  uint64 ExtraSize=0;
700
124k
  if ((ShortBlock.Flags & HFL_EXTRA)!=0)
701
27.5k
  {
702
27.5k
    ExtraSize=Raw.GetV();
703
27.5k
    if (ExtraSize>=ShortBlock.HeadSize)
704
210
    {
705
210
      BrokenHeaderMsg();
706
210
      return 0;
707
210
    }
708
27.5k
  }
709
710
124k
  uint64 DataSize=0;
711
124k
  if ((ShortBlock.Flags & HFL_DATA)!=0)
712
102k
    DataSize=Raw.GetV();
713
714
124k
  NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
715
  // Set to 0 in case of overflow, so end of ReadHeader cares about it.
716
124k
  NextBlockPos=SafeAdd(NextBlockPos,DataSize,0);
717
718
124k
  switch(ShortBlock.HeaderType)
719
124k
  {
720
138
    case HEAD_CRYPT:
721
138
      {
722
138
        CryptHead.SetBaseBlock(ShortBlock);
723
138
        uint CryptVersion=(uint)Raw.GetV();
724
138
        if (CryptVersion>CRYPT_VERSION)
725
66
        {
726
66
          UnkEncVerMsg(FileName,L"h" + std::to_wstring(CryptVersion));
727
66
          FailedHeaderDecryption=true;
728
66
          return 0;
729
66
        }
730
72
        uint EncFlags=(uint)Raw.GetV();
731
72
        CryptHead.UsePswCheck=(EncFlags & CHFL_CRYPT_PSWCHECK)!=0;
732
72
        CryptHead.Lg2Count=Raw.Get1();
733
72
        if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
734
4
        {
735
4
          UnkEncVerMsg(FileName,L"hc" + std::to_wstring(CryptHead.Lg2Count));
736
4
          FailedHeaderDecryption=true;
737
4
          return 0;
738
4
        }
739
740
68
        Raw.GetB(CryptHead.Salt,SIZE_SALT50);
741
68
        if (CryptHead.UsePswCheck)
742
8
        {
743
8
          Raw.GetB(CryptHead.PswCheck,SIZE_PSWCHECK);
744
745
8
          byte csum[SIZE_PSWCHECK_CSUM];
746
8
          Raw.GetB(csum,SIZE_PSWCHECK_CSUM);
747
748
// Exclude this code for rarext.dll, Setup.SFX and unrar_nocrypt.dll linked
749
// without sha256. But still set Encrypted=true for rarext.dll here,
750
// so it can recognize encrypted header archives in archive properties.
751
8
#ifndef RAR_NOCRYPT
752
8
          byte Digest[SHA256_DIGEST_SIZE];
753
8
          sha256_get(CryptHead.PswCheck, SIZE_PSWCHECK, Digest);
754
755
8
          CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
756
8
#endif
757
8
        }
758
68
        Encrypted=true;
759
68
      }
760
0
      break;
761
4.78k
    case HEAD_MAIN:
762
4.78k
      {
763
4.78k
        MainHead.Reset();
764
4.78k
        MainHead.SetBaseBlock(ShortBlock);
765
4.78k
        uint ArcFlags=(uint)Raw.GetV();
766
767
4.78k
        Volume=(ArcFlags & MHFL_VOLUME)!=0;
768
4.78k
        Solid=(ArcFlags & MHFL_SOLID)!=0;
769
4.78k
        Locked=(ArcFlags & MHFL_LOCK)!=0;
770
4.78k
        Protected=(ArcFlags & MHFL_PROTECT)!=0;
771
4.78k
        Signed=false;
772
4.78k
        NewNumbering=true;
773
774
4.78k
        if ((ArcFlags & MHFL_VOLNUMBER)!=0)
775
708
          VolNumber=(uint)Raw.GetV();
776
4.07k
        else
777
4.07k
          VolNumber=0;
778
4.78k
        FirstVolume=Volume && VolNumber==0;
779
780
4.78k
        if (ExtraSize!=0)
781
1.01k
          ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
782
783
4.78k
#ifdef USE_QOPEN
784
4.78k
        if (!ProhibitQOpen && MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
785
398
        {
786
          // We seek to QO block in the end of archive when processing
787
          // QOpen.Load, so we need to preserve current block positions
788
          // to not break normal archive processing by calling function.
789
398
          int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
790
398
          HEADER_TYPE SaveCurHeaderType=CurHeaderType;
791
792
398
          QOpen.Init(this,false);
793
398
          QOpen.Load(MainHead.QOpenOffset);
794
795
398
          CurBlockPos=SaveCurBlockPos;
796
398
          NextBlockPos=SaveNextBlockPos;
797
398
          CurHeaderType=SaveCurHeaderType;
798
398
        }
799
4.78k
#endif
800
4.78k
      }
801
4.78k
      break;
802
78.6k
    case HEAD_FILE:
803
95.1k
    case HEAD_SERVICE:
804
95.1k
      {
805
95.1k
        FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
806
95.1k
        hd->Reset(); // Clear hash, time fields and other stuff like flags.
807
95.1k
        *(BaseBlock *)hd=ShortBlock;
808
809
95.1k
        bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
810
811
95.1k
        hd->LargeFile=true;
812
813
95.1k
        hd->PackSize=DataSize;
814
95.1k
        hd->FileFlags=(uint)Raw.GetV();
815
95.1k
        hd->UnpSize=Raw.GetV();
816
817
95.1k
        hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
818
95.1k
        if (hd->UnknownUnpSize)
819
5.47k
          hd->UnpSize=INT64NDF;
820
821
95.1k
        hd->MaxSize=Max(hd->PackSize,hd->UnpSize);
822
95.1k
        hd->FileAttr=(uint)Raw.GetV();
823
95.1k
        if ((hd->FileFlags & FHFL_UTIME)!=0)
824
15.4k
          hd->mtime.SetUnix((time_t)Raw.Get4());
825
826
95.1k
        hd->FileHash.Type=HASH_NONE;
827
95.1k
        if ((hd->FileFlags & FHFL_CRC32)!=0)
828
3.27k
        {
829
3.27k
          hd->FileHash.Type=HASH_CRC32;
830
3.27k
          hd->FileHash.CRC32=Raw.Get4();
831
3.27k
        }
832
833
95.1k
        hd->RedirType=FSREDIR_NONE;
834
835
95.1k
        uint CompInfo=(uint)Raw.GetV();
836
95.1k
        hd->Method=(CompInfo>>7) & 7;
837
838
        // "+ 50" to not mix with old RAR format algorithms. For example,
839
        // we may need to use the compression algorithm 15 in the future,
840
        // but it was already used in RAR 1.5 and Unpack needs to distinguish
841
        // them.
842
95.1k
        uint UnpVer=(CompInfo & 0x3f);
843
95.1k
        if (UnpVer==0)
844
74.9k
          hd->UnpVer=VER_PACK5;
845
20.1k
        else
846
20.1k
          if (UnpVer==1)
847
3.81k
            hd->UnpVer=VER_PACK7;
848
16.3k
          else
849
16.3k
            hd->UnpVer=VER_UNKNOWN;
850
851
95.1k
        hd->HostOS=(byte)Raw.GetV();
852
95.1k
        size_t NameSize=(size_t)Raw.GetV();
853
95.1k
        hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0;
854
855
95.1k
        hd->HSType=HSYS_UNKNOWN;
856
95.1k
        if (hd->HostOS==HOST5_UNIX)
857
4.52k
          hd->HSType=HSYS_UNIX;
858
90.6k
        else
859
90.6k
          if (hd->HostOS==HOST5_WINDOWS)
860
73.4k
            hd->HSType=HSYS_WINDOWS;
861
862
95.1k
        hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0;
863
95.1k
        hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0;
864
95.1k
        hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
865
95.1k
        hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
866
95.1k
        hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
867
95.1k
        if (hd->Dir || UnpVer>1)
868
17.1k
          hd->WinSize=0;
869
77.9k
        else
870
77.9k
        {
871
77.9k
          hd->WinSize=0x20000ULL<<((CompInfo>>10)&(UnpVer==0 ? 0x0f:0x1f));
872
77.9k
          if (UnpVer==1)
873
3.77k
          {
874
3.77k
            hd->WinSize+=hd->WinSize/32*((CompInfo>>15)&0x1f);
875
876
            // RAR7 header with RAR5 compression. Needed to append RAR7 files
877
            // to RAR5 solid stream if new dictionary is larger than existing.
878
3.77k
            if ((CompInfo & FCI_RAR5_COMPAT)!=0)
879
263
              hd->UnpVer=VER_PACK5;
880
3.77k
            if (hd->WinSize>UNPACK_MAX_DICT)
881
24
              hd->UnpVer=VER_UNKNOWN;
882
3.77k
          }
883
77.9k
        }
884
885
95.1k
        size_t ReadNameSize=Min(NameSize,MAXPATHSIZE);
886
95.1k
        std::string FileName(ReadNameSize,0);
887
95.1k
        Raw.GetB((byte *)&FileName[0],ReadNameSize);
888
889
95.1k
        UtfToWide(FileName.data(),hd->FileName);
890
891
        // Should do it before converting names, because extra fields can
892
        // affect name processing, like in case of NTFS streams.
893
95.1k
        if (ExtraSize!=0)
894
18.2k
          ProcessExtra50(&Raw,(size_t)ExtraSize,hd);
895
896
95.1k
        if (FileBlock)
897
78.6k
        {
898
78.6k
#ifndef SFX_MODULE
899
78.6k
          ConvertNameCase(hd->FileName);
900
78.6k
#endif
901
78.6k
          ConvertFileHeader(hd);
902
78.6k
        }
903
904
95.1k
        if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
905
0
          MainComment=true;
906
907
908
95.1k
        if (BadCRC) // Add the file name to broken header message displayed above.
909
95.1k
          uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
910
95.1k
      }
911
95.1k
      break;
912
247
    case HEAD_ENDARC:
913
247
      {
914
247
        EndArcHead.SetBaseBlock(ShortBlock);
915
247
        uint ArcFlags=(uint)Raw.GetV();
916
247
        EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
917
247
        EndArcHead.StoreVolNumber=false;
918
247
        EndArcHead.DataCRC=false;
919
247
        EndArcHead.RevSpace=false;
920
247
      }
921
247
      break;
922
124k
  }
923
924
124k
  return Raw.Size();
925
124k
}
926
927
928
#if !defined(RAR_NOCRYPT)
929
void Archive::RequestArcPassword(RarCheckPassword *CheckPwd)
930
31
{
931
31
  if (!Cmd->Password.IsSet())
932
31
  {
933
31
#ifdef RARDLL
934
31
    if (Cmd->Callback!=NULL)
935
0
    {
936
0
      wchar PasswordW[MAXPASSWORD];
937
0
      *PasswordW=0;
938
0
      if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
939
0
        *PasswordW=0;
940
0
      if (*PasswordW==0)
941
0
      {
942
0
        char PasswordA[MAXPASSWORD];
943
0
        *PasswordA=0;
944
0
        if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
945
0
          *PasswordA=0;
946
0
        CharToWide(PasswordA,PasswordW,ASIZE(PasswordW));
947
0
        cleandata(PasswordA,sizeof(PasswordA));
948
0
      }
949
0
      Cmd->Password.Set(PasswordW);
950
0
      cleandata(PasswordW,sizeof(PasswordW));
951
0
    }
952
31
    if (!Cmd->Password.IsSet())
953
31
    {
954
31
      Close();
955
31
      Cmd->DllError=ERAR_MISSING_PASSWORD;
956
31
      ErrHandler.Exit(RARX_USERBREAK);
957
31
    }
958
#else
959
    if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password,CheckPwd))
960
    {
961
      Close();
962
      uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
963
      ErrHandler.Exit(RARX_USERBREAK);
964
    }
965
#endif
966
31
    Cmd->ManualPassword=true;
967
31
  }
968
31
}
969
#endif
970
971
972
void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb)
973
19.2k
{
974
  // Read extra data from the end of block skipping any fields before it.
975
19.2k
  size_t ExtraStart=Raw->Size()-ExtraSize;
976
19.2k
  if (ExtraStart<Raw->GetPos())
977
12.7k
    return;
978
6.51k
  Raw->SetPos(ExtraStart);
979
44.1k
  while (Raw->DataLeft()>=2)
980
43.5k
  {
981
43.5k
    int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative.
982
43.5k
    if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
983
5.81k
      break;
984
37.7k
    size_t NextPos=size_t(Raw->GetPos()+FieldSize);
985
37.7k
    uint64 FieldType=Raw->GetV();
986
987
37.7k
    FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields.
988
989
37.7k
    if (FieldSize<0) // FieldType is longer than expected extra field size.
990
179
      break;
991
992
37.6k
    if (bb->HeaderType==HEAD_MAIN)
993
8.94k
    {
994
8.94k
      MainHeader *hd=(MainHeader *)bb;
995
8.94k
      switch(FieldType)
996
8.94k
      {
997
4.39k
        case MHEXTRA_LOCATOR:
998
4.39k
          {
999
4.39k
            hd->Locator=true;
1000
4.39k
            uint Flags=(uint)Raw->GetV();
1001
4.39k
            if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
1002
4.27k
            {
1003
4.27k
              uint64 Offset=Raw->GetV();
1004
4.27k
              if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
1005
4.02k
                hd->QOpenOffset=Offset+CurBlockPos;
1006
4.27k
            }
1007
4.39k
            if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
1008
512
            {
1009
512
              uint64 Offset=Raw->GetV();
1010
512
              if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
1011
482
                hd->RROffset=Offset+CurBlockPos;
1012
512
            }
1013
4.39k
          }
1014
4.39k
          break;
1015
1.99k
        case MHEXTRA_METADATA:
1016
1.99k
          {
1017
1.99k
            uint Flags=(uint)Raw->GetV();
1018
1.99k
            if ((Flags & MHEXTRA_METADATA_NAME)!=0)
1019
184
            {
1020
184
              uint64 NameSize=Raw->GetV();
1021
184
              if (NameSize>0 && NameSize<MAXPATHSIZE) // Prevent excessive allocation.
1022
129
              {
1023
129
                std::string NameU((size_t)NameSize,0); // UTF-8 name.
1024
129
                Raw->GetB(&NameU[0],(size_t)NameSize);
1025
                // If starts from 0, the name was longer than reserved space
1026
                // when saving this extra field.
1027
129
                if (NameU[0]!=0)
1028
118
                  UtfToWide(&NameU[0],hd->OrigName);
1029
129
              }
1030
184
            }
1031
1.99k
            if ((Flags & MHEXTRA_METADATA_CTIME)!=0)
1032
1.84k
              if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0)
1033
120
                if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0)
1034
56
                  hd->OrigTime.SetUnixNS(Raw->Get8());
1035
64
                else
1036
64
                  hd->OrigTime.SetUnix((time_t)Raw->Get4());
1037
1.72k
              else
1038
1.72k
                hd->OrigTime.SetWin(Raw->Get8());
1039
1.99k
          }
1040
1.99k
          break;
1041
8.94k
      }
1042
8.94k
    }
1043
1044
37.6k
    if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
1045
28.6k
    {
1046
28.6k
      FileHeader *hd=(FileHeader *)bb;
1047
28.6k
      switch(FieldType)
1048
28.6k
      {
1049
0
#ifndef RAR_NOCRYPT // Except rarext.dll, Setup.SFX and unrar_nocrypt.dll.
1050
2.31k
        case FHEXTRA_CRYPT:
1051
2.31k
          {
1052
2.31k
            FileHeader *hd=(FileHeader *)bb;
1053
2.31k
            uint EncVersion=(uint)Raw->GetV();
1054
2.31k
            if (EncVersion>CRYPT_VERSION)
1055
2.15k
            {
1056
2.15k
              UnkEncVerMsg(hd->FileName,L"x" + std::to_wstring(EncVersion));
1057
2.15k
              hd->CryptMethod=CRYPT_UNKNOWN;
1058
2.15k
            }
1059
161
            else
1060
161
            {
1061
161
              uint Flags=(uint)Raw->GetV();
1062
161
              hd->Lg2Count=Raw->Get1();
1063
161
              if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
1064
28
              {
1065
28
                UnkEncVerMsg(hd->FileName,L"xc" + std::to_wstring(hd->Lg2Count));
1066
28
                hd->CryptMethod=CRYPT_UNKNOWN;
1067
28
              }
1068
133
              else
1069
133
              {
1070
133
                hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
1071
133
                hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
1072
1073
133
                Raw->GetB(hd->Salt,SIZE_SALT50);
1074
133
                Raw->GetB(hd->InitV,SIZE_INITV);
1075
133
                if (hd->UsePswCheck)
1076
104
                {
1077
104
                  Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
1078
1079
                  // It is important to know if password check data is valid.
1080
                  // If it is damaged and header CRC32 fails to detect it,
1081
                  // archiver would refuse to decompress a possibly valid file.
1082
                  // Since we want to be sure distinguishing a wrong password
1083
                  // or corrupt file data, we use 64-bit password check data
1084
                  // and to control its validity we use 32 bits of password
1085
                  // check data SHA-256 additionally to 32-bit header CRC32.
1086
104
                  byte csum[SIZE_PSWCHECK_CSUM];
1087
104
                  Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
1088
1089
104
                  byte Digest[SHA256_DIGEST_SIZE];
1090
104
                  sha256_get(hd->PswCheck, SIZE_PSWCHECK, Digest);
1091
1092
104
                  hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
1093
1094
                  // RAR 5.21 and earlier set PswCheck field in service records to 0
1095
                  // even if UsePswCheck was present.
1096
104
                  if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
1097
5
                    hd->UsePswCheck=0;
1098
104
                }
1099
133
                hd->SaltSet=true;
1100
133
                hd->CryptMethod=CRYPT_RAR50;
1101
133
                hd->Encrypted=true;
1102
133
              }
1103
161
            }
1104
2.31k
          }
1105
2.31k
          break;
1106
0
#endif
1107
3.25k
        case FHEXTRA_HASH:
1108
3.25k
          {
1109
3.25k
            FileHeader *hd=(FileHeader *)bb;
1110
3.25k
            uint Type=(uint)Raw->GetV();
1111
3.25k
            if (Type==FHEXTRA_HASH_BLAKE2)
1112
516
            {
1113
516
              hd->FileHash.Type=HASH_BLAKE2;
1114
516
              Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
1115
516
            }
1116
3.25k
          }
1117
3.25k
          break;
1118
11.1k
        case FHEXTRA_HTIME:
1119
11.1k
          if (FieldSize>=5)
1120
1.08k
          {
1121
1.08k
            byte Flags=(byte)Raw->GetV();
1122
1.08k
            bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0;
1123
1.08k
            if ((Flags & FHEXTRA_HTIME_MTIME)!=0)
1124
1.00k
              if (UnixTime)
1125
750
                hd->mtime.SetUnix(Raw->Get4());
1126
252
              else
1127
252
                hd->mtime.SetWin(Raw->Get8());
1128
1.08k
            if ((Flags & FHEXTRA_HTIME_CTIME)!=0)
1129
435
              if (UnixTime)
1130
191
                hd->ctime.SetUnix(Raw->Get4());
1131
244
              else
1132
244
                hd->ctime.SetWin(Raw->Get8());
1133
1.08k
            if ((Flags & FHEXTRA_HTIME_ATIME)!=0)
1134
245
              if (UnixTime)
1135
193
                hd->atime.SetUnix((time_t)Raw->Get4());
1136
52
              else
1137
52
                hd->atime.SetWin(Raw->Get8());
1138
1.08k
            if (UnixTime && (Flags & FHEXTRA_HTIME_UNIX_NS)!=0) // Add nanoseconds.
1139
214
            {
1140
214
              uint ns;
1141
214
              if ((Flags & FHEXTRA_HTIME_MTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1142
165
                hd->mtime.Adjust(ns);
1143
214
              if ((Flags & FHEXTRA_HTIME_CTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1144
156
                hd->ctime.Adjust(ns);
1145
214
              if ((Flags & FHEXTRA_HTIME_ATIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1146
157
                hd->atime.Adjust(ns);
1147
214
            }
1148
1.08k
          }
1149
11.1k
          break;
1150
873
        case FHEXTRA_VERSION:
1151
873
          if (FieldSize>=1)
1152
811
          {
1153
811
            Raw->GetV(); // Skip flags field.
1154
811
            uint Version=(uint)Raw->GetV();
1155
811
            if (Version!=0)
1156
771
            {
1157
771
              hd->Version=true;
1158
771
              hd->FileName += L';' + std::to_wstring(Version);
1159
771
            }
1160
811
          }
1161
873
          break;
1162
2.16k
        case FHEXTRA_REDIR:
1163
2.16k
          {
1164
2.16k
            FILE_SYSTEM_REDIRECT RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
1165
2.16k
            uint Flags=(uint)Raw->GetV();
1166
2.16k
            size_t NameSize=(size_t)Raw->GetV();
1167
1168
2.16k
            if (NameSize>0 && NameSize<MAXPATHSIZE)
1169
2.02k
            {
1170
2.02k
              std::string UtfName(NameSize,0);
1171
2.02k
              hd->RedirType=RedirType;
1172
2.02k
              hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
1173
2.02k
              Raw->GetB(&UtfName[0],NameSize);
1174
2.02k
              UtfToWide(&UtfName[0],hd->RedirName);
1175
#ifdef _WIN_ALL
1176
              UnixSlashToDos(hd->RedirName,hd->RedirName);
1177
#endif
1178
2.02k
            }
1179
2.16k
          }
1180
2.16k
          break;
1181
3.55k
        case FHEXTRA_UOWNER:
1182
3.55k
          {
1183
3.55k
            uint Flags=(uint)Raw->GetV();
1184
3.55k
            hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0;
1185
3.55k
            hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0;
1186
3.55k
            *hd->UnixOwnerName=*hd->UnixGroupName=0;
1187
3.55k
            if ((Flags & FHEXTRA_UOWNER_UNAME)!=0)
1188
468
            {
1189
468
              size_t Length=(size_t)Raw->GetV();
1190
468
              Length=Min(Length,ASIZE(hd->UnixOwnerName)-1);
1191
468
              Raw->GetB(hd->UnixOwnerName,Length);
1192
468
              hd->UnixOwnerName[Length]=0;
1193
468
            }
1194
3.55k
            if ((Flags & FHEXTRA_UOWNER_GNAME)!=0)
1195
3.46k
            {
1196
3.46k
              size_t Length=(size_t)Raw->GetV();
1197
3.46k
              Length=Min(Length,ASIZE(hd->UnixGroupName)-1);
1198
3.46k
              Raw->GetB(hd->UnixGroupName,Length);
1199
3.46k
              hd->UnixGroupName[Length]=0;
1200
3.46k
            }
1201
3.55k
#ifdef _UNIX
1202
3.55k
            if (hd->UnixOwnerNumeric)
1203
3.14k
              hd->UnixOwnerID=(uid_t)Raw->GetV();
1204
3.55k
            if (hd->UnixGroupNumeric)
1205
104
              hd->UnixGroupID=(gid_t)Raw->GetV();
1206
#else
1207
            // Need these fields in Windows too for 'list' command,
1208
            // but uid_t and gid_t are not defined.
1209
            if (hd->UnixOwnerNumeric)
1210
              hd->UnixOwnerID=(uint)Raw->GetV();
1211
            if (hd->UnixGroupNumeric)
1212
              hd->UnixGroupID=(uint)Raw->GetV();
1213
#endif
1214
3.55k
            hd->UnixOwnerSet=true;
1215
3.55k
          }
1216
3.55k
          break;
1217
602
        case FHEXTRA_SUBDATA:
1218
602
          {
1219
            // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than
1220
            // required. It did not hurt extraction, because UnRAR 5.21
1221
            // and earlier ignored this field and set FieldSize as data left
1222
            // in entire extra area. But now we set the correct field size
1223
            // and set FieldSize based on the actual extra record size,
1224
            // so we need to adjust it for those older archives here.
1225
            // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE
1226
            // and always is last in extra area. So since its size is by 1
1227
            // less than needed, we always have 1 byte left in extra area,
1228
            // which fact we use here to detect such archives.
1229
602
            if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1)
1230
5
              FieldSize++;
1231
1232
            // We cannot allocate too much memory here, because above
1233
            // we check FieldSize againt Raw size and we control that Raw size
1234
            // is sensible when reading headers.
1235
602
            hd->SubData.resize((size_t)FieldSize);
1236
602
            Raw->GetB(hd->SubData.data(),(size_t)FieldSize);
1237
602
          }
1238
602
          break;
1239
28.6k
      }
1240
28.6k
    }
1241
1242
37.6k
    Raw->SetPos(NextPos);
1243
37.6k
  }
1244
6.51k
}
1245
1246
1247
#ifndef SFX_MODULE
1248
size_t Archive::ReadHeader14()
1249
6.13k
{
1250
6.13k
  RawRead Raw(this);
1251
6.13k
  if (CurBlockPos<=(int64)SFXSize)
1252
1.91k
  {
1253
1.91k
    Raw.Read(SIZEOF_MAINHEAD14);
1254
1.91k
    MainHead.Reset();
1255
1.91k
    byte Mark[4];
1256
1.91k
    Raw.GetB(Mark,4);
1257
1.91k
    uint HeadSize=Raw.Get2();
1258
1.91k
    if (HeadSize<7)
1259
879
      return 0;
1260
1.03k
    byte Flags=Raw.Get1();
1261
1.03k
    NextBlockPos=CurBlockPos+HeadSize;
1262
1.03k
    CurHeaderType=HEAD_MAIN;
1263
1264
1.03k
    Volume=(Flags & MHD_VOLUME)!=0;
1265
1.03k
    Solid=(Flags & MHD_SOLID)!=0;
1266
1.03k
    Locked=(Flags & MHD_LOCK)!=0;
1267
1.03k
    MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
1268
1.03k
    MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
1269
1.03k
  }
1270
4.22k
  else
1271
4.22k
  {
1272
4.22k
    Raw.Read(SIZEOF_FILEHEAD14);
1273
4.22k
    FileHead.Reset();
1274
1275
4.22k
    FileHead.HeaderType=HEAD_FILE;
1276
4.22k
    FileHead.DataSize=Raw.Get4();
1277
4.22k
    FileHead.UnpSize=Raw.Get4();
1278
4.22k
    FileHead.FileHash.Type=HASH_RAR14;
1279
4.22k
    FileHead.FileHash.CRC32=Raw.Get2();
1280
4.22k
    FileHead.HeadSize=Raw.Get2();
1281
4.22k
    if (FileHead.HeadSize<21)
1282
2.54k
      return 0;
1283
1.67k
    uint FileTime=Raw.Get4();
1284
1.67k
    FileHead.FileAttr=Raw.Get1();
1285
1.67k
    FileHead.Flags=Raw.Get1()|LONG_BLOCK;
1286
1.67k
    FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
1287
1.67k
    size_t NameSize=Raw.Get1();
1288
1.67k
    FileHead.Method=Raw.Get1();
1289
1290
1.67k
    FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
1291
1.67k
    FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
1292
1.67k
    FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
1293
1.67k
    FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE;
1294
1295
1.67k
    FileHead.PackSize=FileHead.DataSize;
1296
1.67k
    FileHead.WinSize=0x10000;
1297
1.67k
    FileHead.Dir=(FileHead.FileAttr & 0x10)!=0;
1298
1299
1.67k
    FileHead.HostOS=HOST_MSDOS;
1300
1.67k
    FileHead.HSType=HSYS_WINDOWS;
1301
1302
1.67k
    FileHead.mtime.SetDos(FileTime);
1303
1304
1.67k
    Raw.Read(NameSize);
1305
1306
    // RAR 1.4 name size is stored in a single byte field and it can't
1307
    // exceed 255, so additional checks are not needed.
1308
1.67k
    std::string FileName(NameSize,0);
1309
1.67k
    Raw.GetB((byte *)&FileName[0],NameSize);
1310
1.67k
    std::string NameA;
1311
1.67k
    IntToExt(FileName,NameA);
1312
1.67k
    CharToWide(NameA,FileHead.FileName);
1313
1.67k
    ConvertNameCase(FileHead.FileName);
1314
1.67k
    ConvertFileHeader(&FileHead);
1315
1316
1.67k
    if (Raw.Size()!=0)
1317
1.67k
      NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
1318
1.67k
    CurHeaderType=HEAD_FILE;
1319
1.67k
  }
1320
2.71k
  return NextBlockPos>CurBlockPos ? Raw.Size() : 0;
1321
6.13k
}
1322
#endif
1323
1324
1325
#ifndef SFX_MODULE
1326
void Archive::ConvertNameCase(std::wstring &Name)
1327
85.3k
{
1328
85.3k
  if (Cmd->ConvertNames==NAMES_UPPERCASE)
1329
0
    wcsupper(Name);
1330
85.3k
  if (Cmd->ConvertNames==NAMES_LOWERCASE)
1331
0
    wcslower(Name);
1332
85.3k
}
1333
#endif
1334
1335
1336
bool Archive::IsArcDir()
1337
159k
{
1338
159k
  return FileHead.Dir;
1339
159k
}
1340
1341
1342
void Archive::ConvertAttributes()
1343
80.8k
{
1344
#ifdef _WIN_ALL
1345
  if (FileHead.HSType!=HSYS_WINDOWS)
1346
    FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
1347
#endif
1348
80.8k
#ifdef _UNIX
1349
  // umask defines which permission bits must not be set by default
1350
  // when creating a file or directory. The typical default value
1351
  // for the process umask is S_IWGRP | S_IWOTH (octal 022),
1352
  // resulting in 0644 mode for new files.
1353
  // Normally umask is applied automatically when creating a file,
1354
  // but we set attributes with chmod later, so we need to calculate
1355
  // resulting attributes here. We do it only for non-Unix archives.
1356
  // We restore native Unix attributes as is, because it can be backup.
1357
80.8k
  static mode_t mask = (mode_t) -1;
1358
1359
80.8k
  if (mask == (mode_t) -1)
1360
1
  {
1361
    // umask call returns the current umask value. Argument (022) is not
1362
    // really important here.
1363
1
    mask = umask(022);
1364
1365
    // Restore the original umask value, which was changed to 022 above.
1366
1
    umask(mask);
1367
1
  }
1368
1369
80.8k
  switch(FileHead.HSType)
1370
80.8k
  {
1371
60.5k
    case HSYS_WINDOWS:
1372
60.5k
      {
1373
        // Mapping MSDOS, OS/2 and Windows file attributes to Unix.
1374
1375
60.5k
        if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
1376
541
        {
1377
          // For directories we use 0777 mask.
1378
541
          FileHead.FileAttr=0777 & ~mask;
1379
541
        }
1380
60.0k
        else
1381
60.0k
          if (FileHead.FileAttr & 1)  // FILE_ATTRIBUTE_READONLY
1382
139
          {
1383
            // For read only files we use 0444 mask with 'w' bits turned off.
1384
139
            FileHead.FileAttr=0444 & ~mask;
1385
139
          }
1386
59.9k
          else
1387
59.9k
          {
1388
            // umask does not set +x for regular files, so we use 0666
1389
            // instead of 0777 as for directories.
1390
59.9k
            FileHead.FileAttr=0666 & ~mask;
1391
59.9k
          }
1392
60.5k
      }
1393
60.5k
      break;
1394
3.02k
    case HSYS_UNIX:
1395
3.02k
      break;
1396
17.2k
    default:
1397
17.2k
      if (FileHead.Dir)
1398
1.57k
        FileHead.FileAttr=0x41ff & ~mask;
1399
15.6k
      else
1400
15.6k
        FileHead.FileAttr=0x81b6 & ~mask;
1401
17.2k
      break;
1402
80.8k
  }
1403
80.8k
#endif
1404
80.8k
}
1405
1406
1407
void Archive::ConvertFileHeader(FileHeader *hd)
1408
85.3k
{
1409
/*
1410
  if (hd->HSType==HSYS_UNKNOWN)
1411
    if (hd->Dir)
1412
      hd->FileAttr=0x10;
1413
    else
1414
      hd->FileAttr=0x20;
1415
*/
1416
1417
#ifdef _WIN_ALL
1418
  if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
1419
    ConvertToPrecomposed(hd->FileName);
1420
#endif
1421
1422
24.7M
  for (uint I=0;I<hd->FileName.size();I++)
1423
24.6M
  {
1424
24.6M
    wchar *s=&hd->FileName[I];
1425
1426
24.6M
#ifdef _UNIX
1427
    // Backslash is the invalid character for Windows file headers,
1428
    // but it can present in Unix file names extracted in Unix.
1429
24.6M
    if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS)
1430
110
      *s='_';
1431
24.6M
#endif
1432
1433
#ifdef _WIN_ALL
1434
    // RAR 5.0 archives do not use '\' as path separator, so if we see it,
1435
    // it means that it is a part of Unix file name, which we cannot
1436
    // extract in Windows.
1437
    if (*s=='\\' && Format==RARFMT50)
1438
      *s='_';
1439
1440
    // ':' in file names is allowed in Unix, but not in Windows.
1441
    // Even worse, file data will be written to NTFS stream on NTFS,
1442
    // so automatic name correction on file create error in extraction
1443
    // routine does not work. In Windows and DOS versions we better
1444
    // replace ':' now.
1445
    if (*s==':')
1446
      *s='_';
1447
#endif
1448
1449
    // This code must be performed only after other path separator checks,
1450
    // because it produces backslashes illegal for some of checks above.
1451
    // Backslash is allowed in file names in Unix, but not in Windows.
1452
    // Still, RAR 4.x uses backslashes as path separator even in Unix.
1453
    // Forward slash is not allowed in both systems. In RAR 5.0 we use
1454
    // the forward slash as universal path separator.
1455
24.6M
    if (*s=='/' || *s=='\\' && Format!=RARFMT50)
1456
73.6k
      *s=CPATHDIVIDER;
1457
24.6M
  }
1458
1459
  // Zeroes inside might be possible in broken Unicode names decoded with EncodeFileName::Decode.
1460
85.3k
  TruncateAtZero(hd->FileName); // Ensure there are no zeroes inside of string.
1461
85.3k
}
1462
1463
1464
int64 Archive::GetStartPos()
1465
105
{
1466
105
  int64 StartPos=SFXSize+MarkHead.HeadSize;
1467
105
  if (Format==RARFMT15)
1468
105
    StartPos+=MainHead.HeadSize;
1469
0
  else // RAR 5.0.
1470
0
    StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize);
1471
105
  return StartPos;
1472
105
}
1473
1474
1475
bool Archive::ReadSubData(std::vector<byte> *UnpData,File *DestFile,bool TestMode)
1476
0
{
1477
0
  if (BrokenHeader)
1478
0
  {
1479
0
    uiMsg(UIERROR_SUBHEADERBROKEN,FileName);
1480
0
    ErrHandler.SetErrorCode(RARX_CRC);
1481
0
    return false;
1482
0
  }
1483
0
  if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK7:VER_UNPACK))
1484
0
  {
1485
0
    uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1486
0
    return false;
1487
0
  }
1488
1489
0
  if (SubHead.PackSize==0 && !SubHead.SplitAfter)
1490
0
    return true;
1491
1492
0
  SubDataIO.Init();
1493
0
  Unpack Unpack(&SubDataIO);
1494
0
  Unpack.Init(SubHead.WinSize,false);
1495
1496
0
  if (DestFile==NULL)
1497
0
  {
1498
0
    if (SubHead.UnpSize>0x1000000)
1499
0
    {
1500
      // Prevent the excessive allocation. When reading to memory, normally
1501
      // this function operates with reasonably small blocks, such as
1502
      // the archive comment, NTFS ACL or "Zone.Identifier" NTFS stream.
1503
0
      uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1504
0
      return false;
1505
0
    }
1506
0
    if (UnpData==NULL)
1507
0
      SubDataIO.SetTestMode(true);
1508
0
    else
1509
0
    {
1510
0
      UnpData->resize((size_t)SubHead.UnpSize);
1511
0
      SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
1512
0
    }
1513
0
  }
1514
0
  if (SubHead.Encrypted)
1515
0
    if (Cmd->Password.IsSet())
1516
0
      SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password,
1517
0
                SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV,
1518
0
                SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck);
1519
0
    else
1520
0
      return false;
1521
0
  SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1);
1522
0
  SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
1523
0
  SubDataIO.EnableShowProgress(false);
1524
0
  SubDataIO.SetFiles(this,DestFile);
1525
0
  SubDataIO.SetTestMode(TestMode);
1526
0
  SubDataIO.UnpVolume=SubHead.SplitAfter;
1527
0
  SubDataIO.SetSubHeader(&SubHead,NULL);
1528
0
  Unpack.SetDestSize(SubHead.UnpSize);
1529
0
  if (SubHead.Method==0)
1530
0
    CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
1531
0
  else
1532
0
    Unpack.DoUnpack(SubHead.UnpVer,false);
1533
1534
0
  if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL))
1535
0
  {
1536
0
    uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName);
1537
0
    ErrHandler.SetErrorCode(RARX_CRC);
1538
0
    if (UnpData!=NULL)
1539
0
      UnpData->clear();
1540
0
    return false;
1541
0
  }
1542
0
  return true;
1543
0
}