Coverage Report

Created: 2025-04-22 06:30

/src/unrar/arcread.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "rar.hpp"
2
3
size_t Archive::ReadHeader()
4
156k
{
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
156k
  if (FailedHeaderDecryption)
9
1
    return 0;
10
11
156k
  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
156k
  size_t ReadSize=0;
16
17
156k
  switch(Format)
18
156k
  {
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
125k
    case RARFMT50:
28
125k
      ReadSize=ReadHeader50();
29
125k
      break;
30
156k
  }
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
156k
  if (ReadSize>0 && NextBlockPos<=CurBlockPos)
36
249
  {
37
249
    BrokenHeaderMsg();
38
249
    ReadSize=0;
39
249
  }
40
41
156k
  if (ReadSize==0)
42
17.7k
    CurHeaderType=HEAD_UNKNOWN;
43
44
156k
  return ReadSize;
45
156k
}
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 && CurHeaderType!=HEAD_UNKNOWN)
110
2.10k
      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
125k
{
119
125k
  uiMsg(UIERROR_HEADERBROKEN,FileName);
120
125k
  BrokenHeader=true;
121
125k
  ErrHandler.SetErrorCode(RARX_CRC);
122
125k
}
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
125k
{
139
125k
  return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f;
140
125k
}
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
125k
{
557
125k
  RawRead Raw(this);
558
559
125k
  bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5;
560
561
125k
  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
125k
  const size_t FirstReadSize=7; // Smallest possible block size.
639
125k
  if (Raw.Read(FirstReadSize)<FirstReadSize)
640
3.90k
  {
641
3.90k
    UnexpEndArcMsg();
642
3.90k
    return 0;
643
3.90k
  }
644
645
121k
  ShortBlock.Reset();
646
121k
  ShortBlock.HeadCRC=Raw.Get4();
647
121k
  uint SizeBytes=Raw.GetVSize(4);
648
121k
  uint64 BlockSize=Raw.GetV();
649
650
121k
  if (BlockSize==0 || SizeBytes==0)
651
1.21k
  {
652
1.21k
    BrokenHeaderMsg();
653
1.21k
    return 0;
654
1.21k
  }
655
656
120k
  int SizeToRead=int(BlockSize);
657
120k
  SizeToRead-=int(FirstReadSize-SizeBytes-4); // Adjust overread size bytes if any.
658
120k
  uint HeaderSize=4+SizeBytes+(uint)BlockSize;
659
660
120k
  if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
661
233
  {
662
233
    BrokenHeaderMsg();
663
233
    return 0;
664
233
  }
665
666
120k
  Raw.Read(SizeToRead);
667
668
120k
  if (Raw.Size()<HeaderSize)
669
643
  {
670
643
    UnexpEndArcMsg();
671
643
    return 0;
672
643
  }
673
674
119k
  uint HeaderCRC=Raw.GetCRC50();
675
676
119k
  ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
677
119k
  ShortBlock.Flags=(uint)Raw.GetV();
678
119k
  ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
679
119k
  ShortBlock.HeadSize=HeaderSize;
680
681
119k
  CurHeaderType=ShortBlock.HeaderType;
682
683
119k
  bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
684
119k
  if (BadCRC)
685
119k
  {
686
119k
    BrokenHeaderMsg(); // Report, but attempt to process.
687
688
119k
    BrokenHeader=true;
689
119k
    ErrHandler.SetErrorCode(RARX_CRC);
690
691
119k
    if (Decrypt)
692
0
    {
693
0
      uiMsg(UIERROR_CHECKSUMENC,FileName,FileName);
694
0
      FailedHeaderDecryption=true;
695
0
      return 0;
696
0
    }
697
119k
  }
698
699
119k
  uint64 ExtraSize=0;
700
119k
  if ((ShortBlock.Flags & HFL_EXTRA)!=0)
701
27.4k
  {
702
27.4k
    ExtraSize=Raw.GetV();
703
27.4k
    if (ExtraSize>=ShortBlock.HeadSize)
704
210
    {
705
210
      BrokenHeaderMsg();
706
210
      return 0;
707
210
    }
708
27.4k
  }
709
710
119k
  uint64 DataSize=0;
711
119k
  if ((ShortBlock.Flags & HFL_DATA)!=0)
712
97.8k
    DataSize=Raw.GetV();
713
714
119k
  NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
715
  // Set to 0 in case of overflow, so end of ReadHeader cares about it.
716
119k
  NextBlockPos=SafeAdd(NextBlockPos,DataSize,0);
717
718
119k
  switch(ShortBlock.HeaderType)
719
119k
  {
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.77k
    case HEAD_MAIN:
762
4.77k
      {
763
4.77k
        MainHead.Reset();
764
4.77k
        MainHead.SetBaseBlock(ShortBlock);
765
4.77k
        uint ArcFlags=(uint)Raw.GetV();
766
767
4.77k
        Volume=(ArcFlags & MHFL_VOLUME)!=0;
768
4.77k
        Solid=(ArcFlags & MHFL_SOLID)!=0;
769
4.77k
        Locked=(ArcFlags & MHFL_LOCK)!=0;
770
4.77k
        Protected=(ArcFlags & MHFL_PROTECT)!=0;
771
4.77k
        Signed=false;
772
4.77k
        NewNumbering=true;
773
774
4.77k
        if ((ArcFlags & MHFL_VOLNUMBER)!=0)
775
708
          VolNumber=(uint)Raw.GetV();
776
4.07k
        else
777
4.07k
          VolNumber=0;
778
4.77k
        FirstVolume=Volume && VolNumber==0;
779
780
4.77k
        if (ExtraSize!=0)
781
1.01k
          ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
782
783
4.77k
#ifdef USE_QOPEN
784
4.77k
        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.77k
#endif
800
4.77k
      }
801
4.77k
      break;
802
73.9k
    case HEAD_FILE:
803
90.4k
    case HEAD_SERVICE:
804
90.4k
      {
805
90.4k
        FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
806
90.4k
        hd->Reset(); // Clear hash, time fields and other stuff like flags.
807
90.4k
        *(BaseBlock *)hd=ShortBlock;
808
809
90.4k
        bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
810
811
90.4k
        hd->LargeFile=true;
812
813
90.4k
        hd->PackSize=DataSize;
814
90.4k
        hd->FileFlags=(uint)Raw.GetV();
815
90.4k
        hd->UnpSize=Raw.GetV();
816
817
90.4k
        hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
818
90.4k
        if (hd->UnknownUnpSize)
819
5.47k
          hd->UnpSize=INT64NDF;
820
821
90.4k
        hd->MaxSize=Max(hd->PackSize,hd->UnpSize);
822
90.4k
        hd->FileAttr=(uint)Raw.GetV();
823
90.4k
        if ((hd->FileFlags & FHFL_UTIME)!=0)
824
14.5k
          hd->mtime.SetUnix((time_t)Raw.Get4());
825
826
90.4k
        hd->FileHash.Type=HASH_NONE;
827
90.4k
        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
90.4k
        hd->RedirType=FSREDIR_NONE;
834
835
90.4k
        uint CompInfo=(uint)Raw.GetV();
836
90.4k
        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
90.4k
        uint UnpVer=(CompInfo & 0x3f);
843
90.4k
        if (UnpVer==0)
844
71.1k
          hd->UnpVer=VER_PACK5;
845
19.2k
        else
846
19.2k
          if (UnpVer==1)
847
3.81k
            hd->UnpVer=VER_PACK7;
848
15.4k
          else
849
15.4k
            hd->UnpVer=VER_UNKNOWN;
850
851
90.4k
        hd->HostOS=(byte)Raw.GetV();
852
90.4k
        size_t NameSize=(size_t)Raw.GetV();
853
90.4k
        hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0;
854
855
90.4k
        hd->HSType=HSYS_UNKNOWN;
856
90.4k
        if (hd->HostOS==HOST5_UNIX)
857
4.52k
          hd->HSType=HSYS_UNIX;
858
85.9k
        else
859
85.9k
          if (hd->HostOS==HOST5_WINDOWS)
860
69.6k
            hd->HSType=HSYS_WINDOWS;
861
862
90.4k
        hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0;
863
90.4k
        hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0;
864
90.4k
        hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
865
90.4k
        hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
866
90.4k
        hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
867
90.4k
        if (hd->Dir || UnpVer>1)
868
16.2k
          hd->WinSize=0;
869
74.2k
        else
870
74.2k
        {
871
74.2k
          hd->WinSize=0x20000ULL<<((CompInfo>>10)&(UnpVer==0 ? 0x0f:0x1f));
872
74.2k
          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
74.2k
        }
884
885
90.4k
        size_t ReadNameSize=Min(NameSize,MAXPATHSIZE);
886
90.4k
        std::string FileName(ReadNameSize,0);
887
90.4k
        Raw.GetB((byte *)&FileName[0],ReadNameSize);
888
889
90.4k
        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
90.4k
        if (ExtraSize!=0)
894
18.1k
          ProcessExtra50(&Raw,(size_t)ExtraSize,hd);
895
896
90.4k
        if (FileBlock)
897
73.9k
        {
898
73.9k
#ifndef SFX_MODULE
899
73.9k
          ConvertNameCase(hd->FileName);
900
73.9k
#endif
901
73.9k
          ConvertFileHeader(hd);
902
73.9k
        }
903
904
90.4k
        if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
905
0
          MainComment=true;
906
907
        // For RAR5 format we read the user specified recovery percent here.
908
90.4k
        if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.size()>0)
909
0
        {
910
          // It is stored as a single byte up to RAR 6.02 and as vint since
911
          // 6.10, where we extended the maximum RR size from 99% to 1000%.
912
0
          RawRead RawPercent;
913
0
          RawPercent.Read(hd->SubData.data(),hd->SubData.size());
914
0
          RecoveryPercent=(int)RawPercent.GetV();
915
916
0
        }
917
918
90.4k
        if (BadCRC) // Add the file name to broken header message displayed above.
919
90.4k
          uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
920
90.4k
      }
921
90.4k
      break;
922
247
    case HEAD_ENDARC:
923
247
      {
924
247
        EndArcHead.SetBaseBlock(ShortBlock);
925
247
        uint ArcFlags=(uint)Raw.GetV();
926
247
        EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
927
247
        EndArcHead.StoreVolNumber=false;
928
247
        EndArcHead.DataCRC=false;
929
247
        EndArcHead.RevSpace=false;
930
247
      }
931
247
      break;
932
119k
  }
933
934
119k
  return Raw.Size();
935
119k
}
936
937
938
#if !defined(RAR_NOCRYPT)
939
void Archive::RequestArcPassword(RarCheckPassword *CheckPwd)
940
31
{
941
31
  if (!Cmd->Password.IsSet())
942
31
  {
943
31
#ifdef RARDLL
944
31
    if (Cmd->Callback!=NULL)
945
0
    {
946
0
      wchar PasswordW[MAXPASSWORD];
947
0
      *PasswordW=0;
948
0
      if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
949
0
        *PasswordW=0;
950
0
      if (*PasswordW==0)
951
0
      {
952
0
        char PasswordA[MAXPASSWORD];
953
0
        *PasswordA=0;
954
0
        if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
955
0
          *PasswordA=0;
956
0
        CharToWide(PasswordA,PasswordW,ASIZE(PasswordW));
957
0
        cleandata(PasswordA,sizeof(PasswordA));
958
0
      }
959
0
      Cmd->Password.Set(PasswordW);
960
0
      cleandata(PasswordW,sizeof(PasswordW));
961
0
    }
962
31
    if (!Cmd->Password.IsSet())
963
31
    {
964
31
      Close();
965
31
      Cmd->DllError=ERAR_MISSING_PASSWORD;
966
31
      ErrHandler.Exit(RARX_USERBREAK);
967
31
    }
968
#else
969
    if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password,CheckPwd))
970
    {
971
      Close();
972
      uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
973
      ErrHandler.Exit(RARX_USERBREAK);
974
    }
975
#endif
976
31
    Cmd->ManualPassword=true;
977
31
  }
978
31
}
979
#endif
980
981
982
void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb)
983
19.1k
{
984
  // Read extra data from the end of block skipping any fields before it.
985
19.1k
  size_t ExtraStart=Raw->Size()-ExtraSize;
986
19.1k
  if (ExtraStart<Raw->GetPos())
987
12.7k
    return;
988
6.43k
  Raw->SetPos(ExtraStart);
989
44.0k
  while (Raw->DataLeft()>=2)
990
43.5k
  {
991
43.5k
    int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative.
992
43.5k
    if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
993
5.73k
      break;
994
37.7k
    size_t NextPos=size_t(Raw->GetPos()+FieldSize);
995
37.7k
    uint64 FieldType=Raw->GetV();
996
997
37.7k
    FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields.
998
999
37.7k
    if (FieldSize<0) // FieldType is longer than expected extra field size.
1000
179
      break;
1001
1002
37.6k
    if (bb->HeaderType==HEAD_MAIN)
1003
8.94k
    {
1004
8.94k
      MainHeader *hd=(MainHeader *)bb;
1005
8.94k
      switch(FieldType)
1006
8.94k
      {
1007
4.39k
        case MHEXTRA_LOCATOR:
1008
4.39k
          {
1009
4.39k
            hd->Locator=true;
1010
4.39k
            uint Flags=(uint)Raw->GetV();
1011
4.39k
            if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
1012
4.27k
            {
1013
4.27k
              uint64 Offset=Raw->GetV();
1014
4.27k
              if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
1015
4.02k
                hd->QOpenOffset=Offset+CurBlockPos;
1016
4.27k
            }
1017
4.39k
            if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
1018
512
            {
1019
512
              uint64 Offset=Raw->GetV();
1020
512
              if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
1021
482
                hd->RROffset=Offset+CurBlockPos;
1022
512
            }
1023
4.39k
          }
1024
4.39k
          break;
1025
1.99k
        case MHEXTRA_METADATA:
1026
1.99k
          {
1027
1.99k
            uint Flags=(uint)Raw->GetV();
1028
1.99k
            if ((Flags & MHEXTRA_METADATA_NAME)!=0)
1029
184
            {
1030
184
              uint64 NameSize=Raw->GetV();
1031
184
              if (NameSize>0 && NameSize<MAXPATHSIZE) // Prevent excessive allocation.
1032
129
              {
1033
129
                std::string NameU((size_t)NameSize,0); // UTF-8 name.
1034
129
                Raw->GetB(&NameU[0],(size_t)NameSize);
1035
                // If starts from 0, the name was longer than reserved space
1036
                // when saving this extra field.
1037
129
                if (NameU[0]!=0)
1038
118
                  UtfToWide(&NameU[0],hd->OrigName);
1039
129
              }
1040
184
            }
1041
1.99k
            if ((Flags & MHEXTRA_METADATA_CTIME)!=0)
1042
1.84k
              if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0)
1043
120
                if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0)
1044
56
                  hd->OrigTime.SetUnixNS(Raw->Get8());
1045
64
                else
1046
64
                  hd->OrigTime.SetUnix((time_t)Raw->Get4());
1047
1.72k
              else
1048
1.72k
                hd->OrigTime.SetWin(Raw->Get8());
1049
1.99k
          }
1050
1.99k
          break;
1051
8.94k
      }
1052
8.94k
    }
1053
1054
37.6k
    if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
1055
28.6k
    {
1056
28.6k
      FileHeader *hd=(FileHeader *)bb;
1057
28.6k
      switch(FieldType)
1058
28.6k
      {
1059
0
#ifndef RAR_NOCRYPT // Except rarext.dll, Setup.SFX and unrar_nocrypt.dll.
1060
2.31k
        case FHEXTRA_CRYPT:
1061
2.31k
          {
1062
2.31k
            FileHeader *hd=(FileHeader *)bb;
1063
2.31k
            uint EncVersion=(uint)Raw->GetV();
1064
2.31k
            if (EncVersion>CRYPT_VERSION)
1065
2.15k
            {
1066
2.15k
              UnkEncVerMsg(hd->FileName,L"x" + std::to_wstring(EncVersion));
1067
2.15k
              hd->CryptMethod=CRYPT_UNKNOWN;
1068
2.15k
            }
1069
161
            else
1070
161
            {
1071
161
              uint Flags=(uint)Raw->GetV();
1072
161
              hd->Lg2Count=Raw->Get1();
1073
161
              if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
1074
28
              {
1075
28
                UnkEncVerMsg(hd->FileName,L"xc" + std::to_wstring(hd->Lg2Count));
1076
28
                hd->CryptMethod=CRYPT_UNKNOWN;
1077
28
              }
1078
133
              else
1079
133
              {
1080
133
                hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
1081
133
                hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
1082
1083
133
                Raw->GetB(hd->Salt,SIZE_SALT50);
1084
133
                Raw->GetB(hd->InitV,SIZE_INITV);
1085
133
                if (hd->UsePswCheck)
1086
104
                {
1087
104
                  Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
1088
1089
                  // It is important to know if password check data is valid.
1090
                  // If it is damaged and header CRC32 fails to detect it,
1091
                  // archiver would refuse to decompress a possibly valid file.
1092
                  // Since we want to be sure distinguishing a wrong password
1093
                  // or corrupt file data, we use 64-bit password check data
1094
                  // and to control its validity we use 32 bits of password
1095
                  // check data SHA-256 additionally to 32-bit header CRC32.
1096
104
                  byte csum[SIZE_PSWCHECK_CSUM];
1097
104
                  Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
1098
1099
104
                  byte Digest[SHA256_DIGEST_SIZE];
1100
104
                  sha256_get(hd->PswCheck, SIZE_PSWCHECK, Digest);
1101
1102
104
                  hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
1103
1104
                  // RAR 5.21 and earlier set PswCheck field in service records to 0
1105
                  // even if UsePswCheck was present.
1106
104
                  if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0)
1107
5
                    hd->UsePswCheck=0;
1108
104
                }
1109
133
                hd->SaltSet=true;
1110
133
                hd->CryptMethod=CRYPT_RAR50;
1111
133
                hd->Encrypted=true;
1112
133
              }
1113
161
            }
1114
2.31k
          }
1115
2.31k
          break;
1116
0
#endif
1117
3.25k
        case FHEXTRA_HASH:
1118
3.25k
          {
1119
3.25k
            FileHeader *hd=(FileHeader *)bb;
1120
3.25k
            uint Type=(uint)Raw->GetV();
1121
3.25k
            if (Type==FHEXTRA_HASH_BLAKE2)
1122
514
            {
1123
514
              hd->FileHash.Type=HASH_BLAKE2;
1124
514
              Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
1125
514
            }
1126
3.25k
          }
1127
3.25k
          break;
1128
11.1k
        case FHEXTRA_HTIME:
1129
11.1k
          if (FieldSize>=5)
1130
1.08k
          {
1131
1.08k
            byte Flags=(byte)Raw->GetV();
1132
1.08k
            bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0;
1133
1.08k
            if ((Flags & FHEXTRA_HTIME_MTIME)!=0)
1134
1.00k
              if (UnixTime)
1135
750
                hd->mtime.SetUnix(Raw->Get4());
1136
252
              else
1137
252
                hd->mtime.SetWin(Raw->Get8());
1138
1.08k
            if ((Flags & FHEXTRA_HTIME_CTIME)!=0)
1139
435
              if (UnixTime)
1140
191
                hd->ctime.SetUnix(Raw->Get4());
1141
244
              else
1142
244
                hd->ctime.SetWin(Raw->Get8());
1143
1.08k
            if ((Flags & FHEXTRA_HTIME_ATIME)!=0)
1144
245
              if (UnixTime)
1145
193
                hd->atime.SetUnix((time_t)Raw->Get4());
1146
52
              else
1147
52
                hd->atime.SetWin(Raw->Get8());
1148
1.08k
            if (UnixTime && (Flags & FHEXTRA_HTIME_UNIX_NS)!=0) // Add nanoseconds.
1149
214
            {
1150
214
              uint ns;
1151
214
              if ((Flags & FHEXTRA_HTIME_MTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1152
165
                hd->mtime.Adjust(ns);
1153
214
              if ((Flags & FHEXTRA_HTIME_CTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1154
156
                hd->ctime.Adjust(ns);
1155
214
              if ((Flags & FHEXTRA_HTIME_ATIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000)
1156
157
                hd->atime.Adjust(ns);
1157
214
            }
1158
1.08k
          }
1159
11.1k
          break;
1160
873
        case FHEXTRA_VERSION:
1161
873
          if (FieldSize>=1)
1162
811
          {
1163
811
            Raw->GetV(); // Skip flags field.
1164
811
            uint Version=(uint)Raw->GetV();
1165
811
            if (Version!=0)
1166
771
            {
1167
771
              hd->Version=true;
1168
771
              hd->FileName += L';' + std::to_wstring(Version);
1169
771
            }
1170
811
          }
1171
873
          break;
1172
2.16k
        case FHEXTRA_REDIR:
1173
2.16k
          {
1174
2.16k
            FILE_SYSTEM_REDIRECT RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
1175
2.16k
            uint Flags=(uint)Raw->GetV();
1176
2.16k
            size_t NameSize=(size_t)Raw->GetV();
1177
1178
2.16k
            if (NameSize>0 && NameSize<MAXPATHSIZE)
1179
2.02k
            {
1180
2.02k
              std::string UtfName(NameSize,0);
1181
2.02k
              hd->RedirType=RedirType;
1182
2.02k
              hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
1183
2.02k
              Raw->GetB(&UtfName[0],NameSize);
1184
2.02k
              UtfToWide(&UtfName[0],hd->RedirName);
1185
#ifdef _WIN_ALL
1186
              UnixSlashToDos(hd->RedirName,hd->RedirName);
1187
#endif
1188
2.02k
            }
1189
2.16k
          }
1190
2.16k
          break;
1191
3.55k
        case FHEXTRA_UOWNER:
1192
3.55k
          {
1193
3.55k
            uint Flags=(uint)Raw->GetV();
1194
3.55k
            hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0;
1195
3.55k
            hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0;
1196
3.55k
            *hd->UnixOwnerName=*hd->UnixGroupName=0;
1197
3.55k
            if ((Flags & FHEXTRA_UOWNER_UNAME)!=0)
1198
468
            {
1199
468
              size_t Length=(size_t)Raw->GetV();
1200
468
              Length=Min(Length,ASIZE(hd->UnixOwnerName)-1);
1201
468
              Raw->GetB(hd->UnixOwnerName,Length);
1202
468
              hd->UnixOwnerName[Length]=0;
1203
468
            }
1204
3.55k
            if ((Flags & FHEXTRA_UOWNER_GNAME)!=0)
1205
3.46k
            {
1206
3.46k
              size_t Length=(size_t)Raw->GetV();
1207
3.46k
              Length=Min(Length,ASIZE(hd->UnixGroupName)-1);
1208
3.46k
              Raw->GetB(hd->UnixGroupName,Length);
1209
3.46k
              hd->UnixGroupName[Length]=0;
1210
3.46k
            }
1211
3.55k
#ifdef _UNIX
1212
3.55k
            if (hd->UnixOwnerNumeric)
1213
3.14k
              hd->UnixOwnerID=(uid_t)Raw->GetV();
1214
3.55k
            if (hd->UnixGroupNumeric)
1215
104
              hd->UnixGroupID=(gid_t)Raw->GetV();
1216
#else
1217
            // Need these fields in Windows too for 'list' command,
1218
            // but uid_t and gid_t are not defined.
1219
            if (hd->UnixOwnerNumeric)
1220
              hd->UnixOwnerID=(uint)Raw->GetV();
1221
            if (hd->UnixGroupNumeric)
1222
              hd->UnixGroupID=(uint)Raw->GetV();
1223
#endif
1224
3.55k
            hd->UnixOwnerSet=true;
1225
3.55k
          }
1226
3.55k
          break;
1227
602
        case FHEXTRA_SUBDATA:
1228
602
          {
1229
            // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than
1230
            // required. It did not hurt extraction, because UnRAR 5.21
1231
            // and earlier ignored this field and set FieldSize as data left
1232
            // in entire extra area. But now we set the correct field size
1233
            // and set FieldSize based on the actual extra record size,
1234
            // so we need to adjust it for those older archives here.
1235
            // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE
1236
            // and always is last in extra area. So since its size is by 1
1237
            // less than needed, we always have 1 byte left in extra area,
1238
            // which fact we use here to detect such archives.
1239
602
            if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1)
1240
5
              FieldSize++;
1241
1242
            // We cannot allocate too much memory here, because above
1243
            // we check FieldSize againt Raw size and we control that Raw size
1244
            // is sensible when reading headers.
1245
602
            hd->SubData.resize((size_t)FieldSize);
1246
602
            Raw->GetB(hd->SubData.data(),(size_t)FieldSize);
1247
602
          }
1248
602
          break;
1249
28.6k
      }
1250
28.6k
    }
1251
1252
37.6k
    Raw->SetPos(NextPos);
1253
37.6k
  }
1254
6.43k
}
1255
1256
1257
#ifndef SFX_MODULE
1258
size_t Archive::ReadHeader14()
1259
6.13k
{
1260
6.13k
  RawRead Raw(this);
1261
6.13k
  if (CurBlockPos<=(int64)SFXSize)
1262
1.91k
  {
1263
1.91k
    Raw.Read(SIZEOF_MAINHEAD14);
1264
1.91k
    MainHead.Reset();
1265
1.91k
    byte Mark[4];
1266
1.91k
    Raw.GetB(Mark,4);
1267
1.91k
    uint HeadSize=Raw.Get2();
1268
1.91k
    if (HeadSize<7)
1269
879
      return 0;
1270
1.03k
    byte Flags=Raw.Get1();
1271
1.03k
    NextBlockPos=CurBlockPos+HeadSize;
1272
1.03k
    CurHeaderType=HEAD_MAIN;
1273
1274
1.03k
    Volume=(Flags & MHD_VOLUME)!=0;
1275
1.03k
    Solid=(Flags & MHD_SOLID)!=0;
1276
1.03k
    Locked=(Flags & MHD_LOCK)!=0;
1277
1.03k
    MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
1278
1.03k
    MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
1279
1.03k
  }
1280
4.22k
  else
1281
4.22k
  {
1282
4.22k
    Raw.Read(SIZEOF_FILEHEAD14);
1283
4.22k
    FileHead.Reset();
1284
1285
4.22k
    FileHead.HeaderType=HEAD_FILE;
1286
4.22k
    FileHead.DataSize=Raw.Get4();
1287
4.22k
    FileHead.UnpSize=Raw.Get4();
1288
4.22k
    FileHead.FileHash.Type=HASH_RAR14;
1289
4.22k
    FileHead.FileHash.CRC32=Raw.Get2();
1290
4.22k
    FileHead.HeadSize=Raw.Get2();
1291
4.22k
    if (FileHead.HeadSize<21)
1292
2.54k
      return 0;
1293
1.67k
    uint FileTime=Raw.Get4();
1294
1.67k
    FileHead.FileAttr=Raw.Get1();
1295
1.67k
    FileHead.Flags=Raw.Get1()|LONG_BLOCK;
1296
1.67k
    FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
1297
1.67k
    size_t NameSize=Raw.Get1();
1298
1.67k
    FileHead.Method=Raw.Get1();
1299
1300
1.67k
    FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
1301
1.67k
    FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
1302
1.67k
    FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
1303
1.67k
    FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE;
1304
1305
1.67k
    FileHead.PackSize=FileHead.DataSize;
1306
1.67k
    FileHead.WinSize=0x10000;
1307
1.67k
    FileHead.Dir=(FileHead.FileAttr & 0x10)!=0;
1308
1309
1.67k
    FileHead.HostOS=HOST_MSDOS;
1310
1.67k
    FileHead.HSType=HSYS_WINDOWS;
1311
1312
1.67k
    FileHead.mtime.SetDos(FileTime);
1313
1314
1.67k
    Raw.Read(NameSize);
1315
1316
    // RAR 1.4 name size is stored in a single byte field and it can't
1317
    // exceed 255, so additional checks are not needed.
1318
1.67k
    std::string FileName(NameSize,0);
1319
1.67k
    Raw.GetB((byte *)&FileName[0],NameSize);
1320
1.67k
    std::string NameA;
1321
1.67k
    OemToExt(FileName,NameA);
1322
1.67k
    CharToWide(NameA,FileHead.FileName);
1323
1.67k
    ConvertNameCase(FileHead.FileName);
1324
1.67k
    ConvertFileHeader(&FileHead);
1325
1326
1.67k
    if (Raw.Size()!=0)
1327
1.67k
      NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
1328
1.67k
    CurHeaderType=HEAD_FILE;
1329
1.67k
  }
1330
2.71k
  return NextBlockPos>CurBlockPos ? Raw.Size() : 0;
1331
6.13k
}
1332
#endif
1333
1334
1335
#ifndef SFX_MODULE
1336
void Archive::ConvertNameCase(std::wstring &Name)
1337
80.6k
{
1338
80.6k
  if (Cmd->ConvertNames==NAMES_UPPERCASE)
1339
0
    wcsupper(Name);
1340
80.6k
  if (Cmd->ConvertNames==NAMES_LOWERCASE)
1341
0
    wcslower(Name);
1342
80.6k
}
1343
#endif
1344
1345
1346
bool Archive::IsArcDir()
1347
150k
{
1348
150k
  return FileHead.Dir;
1349
150k
}
1350
1351
1352
void Archive::ConvertAttributes()
1353
76.2k
{
1354
#ifdef _WIN_ALL
1355
  if (FileHead.HSType!=HSYS_WINDOWS)
1356
    FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
1357
#endif
1358
76.2k
#ifdef _UNIX
1359
  // umask defines which permission bits must not be set by default
1360
  // when creating a file or directory. The typical default value
1361
  // for the process umask is S_IWGRP | S_IWOTH (octal 022),
1362
  // resulting in 0644 mode for new files.
1363
  // Normally umask is applied automatically when creating a file,
1364
  // but we set attributes with chmod later, so we need to calculate
1365
  // resulting attributes here. We do it only for non-Unix archives.
1366
  // We restore native Unix attributes as is, because it can be backup.
1367
76.2k
  static mode_t mask = (mode_t) -1;
1368
1369
76.2k
  if (mask == (mode_t) -1)
1370
1
  {
1371
    // umask call returns the current umask value. Argument (022) is not
1372
    // really important here.
1373
1
    mask = umask(022);
1374
1375
    // Restore the original umask value, which was changed to 022 above.
1376
1
    umask(mask);
1377
1
  }
1378
1379
76.2k
  switch(FileHead.HSType)
1380
76.2k
  {
1381
56.8k
    case HSYS_WINDOWS:
1382
56.8k
      {
1383
        // Mapping MSDOS, OS/2 and Windows file attributes to Unix.
1384
1385
56.8k
        if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
1386
541
        {
1387
          // For directories we use 0777 mask.
1388
541
          FileHead.FileAttr=0777 & ~mask;
1389
541
        }
1390
56.2k
        else
1391
56.2k
          if (FileHead.FileAttr & 1)  // FILE_ATTRIBUTE_READONLY
1392
139
          {
1393
            // For read only files we use 0444 mask with 'w' bits turned off.
1394
139
            FileHead.FileAttr=0444 & ~mask;
1395
139
          }
1396
56.1k
          else
1397
56.1k
          {
1398
            // umask does not set +x for regular files, so we use 0666
1399
            // instead of 0777 as for directories.
1400
56.1k
            FileHead.FileAttr=0666 & ~mask;
1401
56.1k
          }
1402
56.8k
      }
1403
56.8k
      break;
1404
3.02k
    case HSYS_UNIX:
1405
3.02k
      break;
1406
16.3k
    default:
1407
16.3k
      if (FileHead.Dir)
1408
1.57k
        FileHead.FileAttr=0x41ff & ~mask;
1409
14.8k
      else
1410
14.8k
        FileHead.FileAttr=0x81b6 & ~mask;
1411
16.3k
      break;
1412
76.2k
  }
1413
76.2k
#endif
1414
76.2k
}
1415
1416
1417
void Archive::ConvertFileHeader(FileHeader *hd)
1418
80.6k
{
1419
/*
1420
  if (hd->HSType==HSYS_UNKNOWN)
1421
    if (hd->Dir)
1422
      hd->FileAttr=0x10;
1423
    else
1424
      hd->FileAttr=0x20;
1425
*/
1426
1427
#ifdef _WIN_ALL
1428
  if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed.
1429
    ConvertToPrecomposed(hd->FileName);
1430
#endif
1431
1432
24.7M
  for (uint I=0;I<hd->FileName.size();I++)
1433
24.6M
  {
1434
24.6M
    wchar *s=&hd->FileName[I];
1435
1436
24.6M
#ifdef _UNIX
1437
    // Backslash is the invalid character for Windows file headers,
1438
    // but it can present in Unix file names extracted in Unix.
1439
24.6M
    if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS)
1440
110
      *s='_';
1441
24.6M
#endif
1442
1443
#ifdef _WIN_ALL
1444
    // RAR 5.0 archives do not use '\' as path separator, so if we see it,
1445
    // it means that it is a part of Unix file name, which we cannot
1446
    // extract in Windows.
1447
    if (*s=='\\' && Format==RARFMT50)
1448
      *s='_';
1449
1450
    // ':' in file names is allowed in Unix, but not in Windows.
1451
    // Even worse, file data will be written to NTFS stream on NTFS,
1452
    // so automatic name correction on file create error in extraction
1453
    // routine does not work. In Windows and DOS versions we better
1454
    // replace ':' now.
1455
    if (*s==':')
1456
      *s='_';
1457
#endif
1458
1459
    // This code must be performed only after other path separator checks,
1460
    // because it produces backslashes illegal for some of checks above.
1461
    // Backslash is allowed in file names in Unix, but not in Windows.
1462
    // Still, RAR 4.x uses backslashes as path separator even in Unix.
1463
    // Forward slash is not allowed in both systems. In RAR 5.0 we use
1464
    // the forward slash as universal path separator.
1465
24.6M
    if (*s=='/' || *s=='\\' && Format!=RARFMT50)
1466
73.6k
      *s=CPATHDIVIDER;
1467
24.6M
  }
1468
1469
  // Zeroes inside might be possible in broken Unicode names decoded with EncodeFileName::Decode.
1470
80.6k
  TruncateAtZero(hd->FileName); // Ensure there are no zeroes inside of string.
1471
80.6k
}
1472
1473
1474
int64 Archive::GetStartPos()
1475
105
{
1476
105
  int64 StartPos=SFXSize+MarkHead.HeadSize;
1477
105
  if (Format==RARFMT15)
1478
105
    StartPos+=MainHead.HeadSize;
1479
0
  else // RAR 5.0.
1480
0
    StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize);
1481
105
  return StartPos;
1482
105
}
1483
1484
1485
bool Archive::ReadSubData(std::vector<byte> *UnpData,File *DestFile,bool TestMode)
1486
0
{
1487
0
  if (BrokenHeader)
1488
0
  {
1489
0
    uiMsg(UIERROR_SUBHEADERBROKEN,FileName);
1490
0
    ErrHandler.SetErrorCode(RARX_CRC);
1491
0
    return false;
1492
0
  }
1493
0
  if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK7:VER_UNPACK))
1494
0
  {
1495
0
    uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1496
0
    return false;
1497
0
  }
1498
1499
0
  if (SubHead.PackSize==0 && !SubHead.SplitAfter)
1500
0
    return true;
1501
1502
0
  SubDataIO.Init();
1503
0
  Unpack Unpack(&SubDataIO);
1504
0
  Unpack.Init(SubHead.WinSize,false);
1505
1506
0
  if (DestFile==NULL)
1507
0
  {
1508
0
    if (SubHead.UnpSize>0x1000000)
1509
0
    {
1510
      // Prevent the excessive allocation. When reading to memory, normally
1511
      // this function operates with reasonably small blocks, such as
1512
      // the archive comment, NTFS ACL or "Zone.Identifier" NTFS stream.
1513
0
      uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
1514
0
      return false;
1515
0
    }
1516
0
    if (UnpData==NULL)
1517
0
      SubDataIO.SetTestMode(true);
1518
0
    else
1519
0
    {
1520
0
      UnpData->resize((size_t)SubHead.UnpSize);
1521
0
      SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
1522
0
    }
1523
0
  }
1524
0
  if (SubHead.Encrypted)
1525
0
    if (Cmd->Password.IsSet())
1526
0
      SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password,
1527
0
                SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV,
1528
0
                SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck);
1529
0
    else
1530
0
      return false;
1531
0
  SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1);
1532
0
  SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
1533
0
  SubDataIO.EnableShowProgress(false);
1534
0
  SubDataIO.SetFiles(this,DestFile);
1535
0
  SubDataIO.SetTestMode(TestMode);
1536
0
  SubDataIO.UnpVolume=SubHead.SplitAfter;
1537
0
  SubDataIO.SetSubHeader(&SubHead,NULL);
1538
0
  Unpack.SetDestSize(SubHead.UnpSize);
1539
0
  if (SubHead.Method==0)
1540
0
    CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
1541
0
  else
1542
0
    Unpack.DoUnpack(SubHead.UnpVer,false);
1543
1544
0
  if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL))
1545
0
  {
1546
0
    uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName);
1547
0
    ErrHandler.SetErrorCode(RARX_CRC);
1548
0
    if (UnpData!=NULL)
1549
0
      UnpData->clear();
1550
0
    return false;
1551
0
  }
1552
0
  return true;
1553
0
}