1 #include "rar.hpp"
2
SearchBlock(int BlockType)3 int Archive::SearchBlock(int BlockType)
4 {
5 int Size,Count=0;
6 while ((Size=ReadHeader())!=0 &&
7 (BlockType==ENDARC_HEAD || GetHeaderType()!=ENDARC_HEAD))
8 {
9 if ((++Count & 127)==0)
10 Wait();
11 if (GetHeaderType()==BlockType)
12 return(Size);
13 SeekToNext();
14 }
15 return(0);
16 }
17
18
SearchSubBlock(const char * Type)19 int Archive::SearchSubBlock(const char *Type)
20 {
21 int Size;
22 while ((Size=ReadHeader())!=0 && GetHeaderType()!=ENDARC_HEAD)
23 {
24 if (GetHeaderType()==NEWSUB_HEAD && SubHead.CmpName(Type))
25 return(Size);
26 SeekToNext();
27 }
28 return(0);
29 }
30
31
ReadHeader()32 int Archive::ReadHeader()
33 {
34 CurBlockPos=Tell();
35
36 #ifndef SFX_MODULE
37 if (OldFormat)
38 return(ReadOldHeader());
39 #endif
40
41 RawRead Raw(this);
42
43 bool Decrypt=Encrypted && CurBlockPos>=SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD;
44
45 if (Decrypt)
46 {
47 #if defined(SHELL_EXT) || defined(NOCRYPT)
48 return(0);
49 #else
50 if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE)
51 return(0);
52 if (*Cmd->Password==0)
53 #ifdef RARDLL
54 if (Cmd->Callback==NULL ||
55 Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LONG)Cmd->Password,sizeof(Cmd->Password))==-1)
56 {
57 Close();
58 ErrHandler.Exit(USER_BREAK);
59 }
60
61 #else
62 if (!GetPassword(PASSWORD_ARCHIVE,FileName,Cmd->Password,sizeof(Cmd->Password)))
63 {
64 Close();
65 ErrHandler.Exit(USER_BREAK);
66 }
67 #endif
68 HeadersCrypt.SetCryptKeys(Cmd->Password,HeadersSalt,false);
69 Raw.SetCrypt(&HeadersCrypt);
70 #endif
71 }
72
73 Raw.Read(SIZEOF_SHORTBLOCKHEAD);
74 if (Raw.Size()==0)
75 {
76 Int64 ArcSize=FileLength();
77 if (CurBlockPos>ArcSize || NextBlockPos>ArcSize)
78 {
79 #ifndef SHELL_EXT
80 Log(FileName,St(MLogUnexpEOF));
81 #endif
82 ErrHandler.SetErrorCode(WARNING);
83 }
84 return(0);
85 }
86
87 Raw.Get(ShortBlock.HeadCRC);
88 byte HeadType;
89 Raw.Get(HeadType);
90 ShortBlock.HeadType=(HEADER_TYPE)HeadType;
91 Raw.Get(ShortBlock.Flags);
92 Raw.Get(ShortBlock.HeadSize);
93 if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
94 {
95 #ifndef SHELL_EXT
96 Log(FileName,St(MLogFileHead),"???");
97 #endif
98 BrokenFileHeader=true;
99 ErrHandler.SetErrorCode(CRC_ERROR);
100 return(0);
101 }
102
103 if (ShortBlock.HeadType==COMM_HEAD)
104 Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
105 else
106 if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
107 Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
108 else
109 Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
110
111 NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
112
113 switch(ShortBlock.HeadType)
114 {
115 case MAIN_HEAD:
116 *(BaseBlock *)&NewMhd=ShortBlock;
117 Raw.Get(NewMhd.HighPosAV);
118 Raw.Get(NewMhd.PosAV);
119 break;
120 case ENDARC_HEAD:
121 *(BaseBlock *)&EndArcHead=ShortBlock;
122 if (EndArcHead.Flags & EARC_DATACRC)
123 Raw.Get(EndArcHead.ArcDataCRC);
124 if (EndArcHead.Flags & EARC_VOLNUMBER)
125 Raw.Get(EndArcHead.VolNumber);
126 break;
127 case FILE_HEAD:
128 case NEWSUB_HEAD:
129 {
130 FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
131 *(BaseBlock *)hd=ShortBlock;
132 Raw.Get(hd->PackSize);
133 Raw.Get(hd->UnpSize);
134 Raw.Get(hd->HostOS);
135 Raw.Get(hd->FileCRC);
136 Raw.Get(hd->FileTime);
137 Raw.Get(hd->UnpVer);
138 Raw.Get(hd->Method);
139 Raw.Get(hd->NameSize);
140 Raw.Get(hd->FileAttr);
141 if (hd->Flags & LHD_LARGE)
142 {
143 Raw.Get(hd->HighPackSize);
144 Raw.Get(hd->HighUnpSize);
145 }
146 else
147 {
148 hd->HighPackSize=hd->HighUnpSize=0;
149 if (hd->UnpSize==0xffffffff)
150 {
151 hd->UnpSize=int64to32(INT64MAX);
152 hd->HighUnpSize=int64to32(INT64MAX>>32);
153 }
154 }
155 hd->FullPackSize=int32to64(hd->HighPackSize,hd->PackSize);
156 hd->FullUnpSize=int32to64(hd->HighUnpSize,hd->UnpSize);
157
158 char FileName[NM*4];
159 int NameSize=Min(hd->NameSize,sizeof(FileName)-1);
160 Raw.Get((byte *)FileName,NameSize);
161 FileName[NameSize]=0;
162
163 strncpy(hd->FileName,FileName,sizeof(hd->FileName));
164 hd->FileName[sizeof(hd->FileName)-1]=0;
165
166 if (hd->HeadType==NEWSUB_HEAD)
167 {
168 int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD;
169 if (hd->Flags & LHD_SALT)
170 DataSize-=SALT_SIZE;
171 if (DataSize>0)
172 {
173 hd->SubData.Alloc(DataSize);
174 Raw.Get(&hd->SubData[0],DataSize);
175 if (hd->CmpName(SUBHEAD_TYPE_RR))
176 {
177 byte *D=&hd->SubData[8];
178 RecoverySectors=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
179 }
180 }
181 }
182 else
183 if (hd->HeadType==FILE_HEAD)
184 {
185 if (hd->Flags & LHD_UNICODE)
186 {
187 EncodeFileName NameCoder;
188 int Length=strlen(FileName)+1;
189 NameCoder.Decode(FileName,(byte *)FileName+Length,
190 hd->NameSize-Length,hd->FileNameW,
191 sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
192 if (*hd->FileNameW==0)
193 hd->Flags &= ~LHD_UNICODE;
194 }
195 else
196 *hd->FileNameW=0;
197 #ifndef SFX_MODULE
198 ConvertNameCase(hd->FileName);
199 ConvertNameCase(hd->FileNameW);
200 #endif
201 ConvertUnknownHeader();
202 }
203 if (hd->Flags & LHD_SALT)
204 Raw.Get(hd->Salt,SALT_SIZE);
205 hd->mtime.SetDos(hd->FileTime);
206 hd->ctime.Reset();
207 hd->atime.Reset();
208 hd->arctime.Reset();
209 if (hd->Flags & LHD_EXTTIME)
210 {
211 ushort Flags;
212 Raw.Get(Flags);
213 RarTime *tbl[4];
214 tbl[0]=&NewLhd.mtime;
215 tbl[1]=&NewLhd.ctime;
216 tbl[2]=&NewLhd.atime;
217 tbl[3]=&NewLhd.arctime;
218 for (int I=0;I<4;I++)
219 {
220 RarTime *CurTime=tbl[I];
221 uint rmode=Flags>>(3-I)*4;
222 if ((rmode & 8)==0)
223 continue;
224 if (I!=0)
225 {
226 uint DosTime;
227 Raw.Get(DosTime);
228 CurTime->SetDos(DosTime);
229 }
230 RarLocalTime rlt;
231 CurTime->GetLocal(&rlt);
232 if (rmode & 4)
233 rlt.Second++;
234 rlt.Reminder=0;
235 int count=rmode&3;
236 for (int J=0;J<count;J++)
237 {
238 byte CurByte;
239 Raw.Get(CurByte);
240 rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
241 }
242 CurTime->SetLocal(&rlt);
243 }
244 }
245 NextBlockPos+=hd->FullPackSize;
246 bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
247 HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
248 if (hd->HeadCRC!=HeaderCRC)
249 {
250 if (hd->HeadType==NEWSUB_HEAD)
251 strcat(hd->FileName,"- ???");
252 BrokenFileHeader=true;
253 ErrHandler.SetErrorCode(WARNING);
254 #ifndef SHELL_EXT
255 Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName));
256 Alarm();
257 #endif
258 }
259 }
260 break;
261 #ifndef SFX_MODULE
262 case COMM_HEAD:
263 *(BaseBlock *)&CommHead=ShortBlock;
264 Raw.Get(CommHead.UnpSize);
265 Raw.Get(CommHead.UnpVer);
266 Raw.Get(CommHead.Method);
267 Raw.Get(CommHead.CommCRC);
268 break;
269 case SIGN_HEAD:
270 *(BaseBlock *)&SignHead=ShortBlock;
271 Raw.Get(SignHead.CreationTime);
272 Raw.Get(SignHead.ArcNameSize);
273 Raw.Get(SignHead.UserNameSize);
274 break;
275 case AV_HEAD:
276 *(BaseBlock *)&AVHead=ShortBlock;
277 Raw.Get(AVHead.UnpVer);
278 Raw.Get(AVHead.Method);
279 Raw.Get(AVHead.AVVer);
280 Raw.Get(AVHead.AVInfoCRC);
281 break;
282 case PROTECT_HEAD:
283 *(BaseBlock *)&ProtectHead=ShortBlock;
284 Raw.Get(ProtectHead.DataSize);
285 Raw.Get(ProtectHead.Version);
286 Raw.Get(ProtectHead.RecSectors);
287 Raw.Get(ProtectHead.TotalBlocks);
288 Raw.Get(ProtectHead.Mark,8);
289 NextBlockPos+=ProtectHead.DataSize;
290 RecoverySectors=ProtectHead.RecSectors;
291 break;
292 case SUB_HEAD:
293 *(BaseBlock *)&SubBlockHead=ShortBlock;
294 Raw.Get(SubBlockHead.DataSize);
295 NextBlockPos+=SubBlockHead.DataSize;
296 Raw.Get(SubBlockHead.SubType);
297 Raw.Get(SubBlockHead.Level);
298 switch(SubBlockHead.SubType)
299 {
300 case UO_HEAD:
301 *(SubBlockHeader *)&UOHead=SubBlockHead;
302 Raw.Get(UOHead.OwnerNameSize);
303 Raw.Get(UOHead.GroupNameSize);
304 if (UOHead.OwnerNameSize>NM-1)
305 UOHead.OwnerNameSize=NM-1;
306 if (UOHead.GroupNameSize>NM-1)
307 UOHead.GroupNameSize=NM-1;
308 Raw.Get((byte *)UOHead.OwnerName,UOHead.OwnerNameSize);
309 Raw.Get((byte *)UOHead.GroupName,UOHead.GroupNameSize);
310 UOHead.OwnerName[UOHead.OwnerNameSize]=0;
311 UOHead.GroupName[UOHead.GroupNameSize]=0;
312 break;
313 case MAC_HEAD:
314 *(SubBlockHeader *)&MACHead=SubBlockHead;
315 Raw.Get(MACHead.fileType);
316 Raw.Get(MACHead.fileCreator);
317 break;
318 case EA_HEAD:
319 case BEEA_HEAD:
320 case NTACL_HEAD:
321 *(SubBlockHeader *)&EAHead=SubBlockHead;
322 Raw.Get(EAHead.UnpSize);
323 Raw.Get(EAHead.UnpVer);
324 Raw.Get(EAHead.Method);
325 Raw.Get(EAHead.EACRC);
326 break;
327 case STREAM_HEAD:
328 *(SubBlockHeader *)&StreamHead=SubBlockHead;
329 Raw.Get(StreamHead.UnpSize);
330 Raw.Get(StreamHead.UnpVer);
331 Raw.Get(StreamHead.Method);
332 Raw.Get(StreamHead.StreamCRC);
333 Raw.Get(StreamHead.StreamNameSize);
334 if (StreamHead.StreamNameSize>NM-1)
335 StreamHead.StreamNameSize=NM-1;
336 Raw.Get((byte *)StreamHead.StreamName,StreamHead.StreamNameSize);
337 StreamHead.StreamName[StreamHead.StreamNameSize]=0;
338 break;
339 }
340 break;
341 #endif
342 default:
343 if (ShortBlock.Flags & LONG_BLOCK)
344 {
345 uint DataSize;
346 Raw.Get(DataSize);
347 NextBlockPos+=DataSize;
348 }
349 break;
350 }
351 HeaderCRC=~Raw.GetCRC(false)&0xffff;
352 CurHeaderType=ShortBlock.HeadType;
353 if (Decrypt)
354 {
355 NextBlockPos+=Raw.PaddedSize()+SALT_SIZE;
356
357 if (ShortBlock.HeadCRC!=HeaderCRC)
358 {
359 bool Recovered=false;
360 if (ShortBlock.HeadType==ENDARC_HEAD && (EndArcHead.Flags & EARC_REVSPACE)!=0)
361 {
362 SaveFilePos SavePos(*this);
363 Int64 Length=Tell();
364 Seek(Length-7,SEEK_SET);
365 Recovered=true;
366 for (int J=0;J<7;J++)
367 if (GetByte()!=0)
368 Recovered=false;
369 }
370 if (!Recovered)
371 {
372 #ifndef SILENT
373 Log(FileName,St(MEncrBadCRC),FileName);
374 #endif
375 Close();
376
377 BrokenFileHeader=true;
378 ErrHandler.SetErrorCode(CRC_ERROR);
379 return(0);
380 // ErrHandler.Exit(CRC_ERROR);
381 }
382 }
383 }
384
385 if (NextBlockPos<=CurBlockPos)
386 {
387 #ifndef SHELL_EXT
388 Log(FileName,St(MLogFileHead),"???");
389 #endif
390 BrokenFileHeader=true;
391 ErrHandler.SetErrorCode(CRC_ERROR);
392 return(0);
393 }
394 return(Raw.Size());
395 }
396
397
398 #ifndef SFX_MODULE
ReadOldHeader()399 int Archive::ReadOldHeader()
400 {
401 RawRead Raw(this);
402 if (CurBlockPos<=SFXSize)
403 {
404 Raw.Read(SIZEOF_OLDMHD);
405 Raw.Get(OldMhd.Mark,4);
406 Raw.Get(OldMhd.HeadSize);
407 Raw.Get(OldMhd.Flags);
408 NextBlockPos=CurBlockPos+OldMhd.HeadSize;
409 CurHeaderType=MAIN_HEAD;
410 }
411 else
412 {
413 OldFileHeader OldLhd;
414 Raw.Read(SIZEOF_OLDLHD);
415 NewLhd.HeadType=FILE_HEAD;
416 Raw.Get(NewLhd.PackSize);
417 Raw.Get(NewLhd.UnpSize);
418 Raw.Get(OldLhd.FileCRC);
419 Raw.Get(NewLhd.HeadSize);
420 Raw.Get(NewLhd.FileTime);
421 Raw.Get(OldLhd.FileAttr);
422 Raw.Get(OldLhd.Flags);
423 Raw.Get(OldLhd.UnpVer);
424 Raw.Get(OldLhd.NameSize);
425 Raw.Get(OldLhd.Method);
426
427 NewLhd.Flags=OldLhd.Flags|LONG_BLOCK;
428 NewLhd.UnpVer=(OldLhd.UnpVer==2) ? 13 : 10;
429 NewLhd.Method=OldLhd.Method+0x30;
430 NewLhd.NameSize=OldLhd.NameSize;
431 NewLhd.FileAttr=OldLhd.FileAttr;
432 NewLhd.FileCRC=OldLhd.FileCRC;
433 NewLhd.FullPackSize=NewLhd.PackSize;
434 NewLhd.FullUnpSize=NewLhd.UnpSize;
435
436 NewLhd.mtime.SetDos(NewLhd.FileTime);
437 NewLhd.ctime.Reset();
438 NewLhd.atime.Reset();
439 NewLhd.arctime.Reset();
440
441 Raw.Read(OldLhd.NameSize);
442 Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize);
443 NewLhd.FileName[OldLhd.NameSize]=0;
444 ConvertNameCase(NewLhd.FileName);
445 *NewLhd.FileNameW=0;
446
447 if (Raw.Size()!=0)
448 NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize;
449 CurHeaderType=FILE_HEAD;
450 }
451 return(NextBlockPos>CurBlockPos ? Raw.Size():0);
452 }
453 #endif
454
455
ConvertNameCase(char * Name)456 void Archive::ConvertNameCase(char *Name)
457 {
458 if (Cmd->ConvertNames==NAMES_UPPERCASE)
459 {
460 IntToExt(Name,Name);
461 strupper(Name);
462 ExtToInt(Name,Name);
463 }
464 if (Cmd->ConvertNames==NAMES_LOWERCASE)
465 {
466 IntToExt(Name,Name);
467 strlower(Name);
468 ExtToInt(Name,Name);
469 }
470 }
471
472
473 #ifndef SFX_MODULE
ConvertNameCase(wchar * Name)474 void Archive::ConvertNameCase(wchar *Name)
475 {
476 if (Cmd->ConvertNames==NAMES_UPPERCASE)
477 strupperw(Name);
478 if (Cmd->ConvertNames==NAMES_LOWERCASE)
479 strlowerw(Name);
480 }
481 #endif
482
483
IsArcDir()484 bool Archive::IsArcDir()
485 {
486 return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY);
487 }
488
489
IsArcLabel()490 bool Archive::IsArcLabel()
491 {
492 return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8));
493 }
494
495
ConvertAttributes()496 void Archive::ConvertAttributes()
497 {
498 #if defined(_WIN_32) || defined(_EMX)
499 switch(NewLhd.HostOS)
500 {
501 case HOST_MSDOS:
502 case HOST_OS2:
503 case HOST_WIN32:
504 break;
505 case HOST_UNIX:
506 case HOST_BEOS:
507 if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
508 NewLhd.FileAttr=0x10;
509 else
510 NewLhd.FileAttr=0x20;
511 break;
512 default:
513 if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
514 NewLhd.FileAttr=0x10;
515 else
516 NewLhd.FileAttr=0x20;
517 break;
518 }
519 #endif
520 #ifdef _UNIX
521 static mode_t mask = (mode_t) -1;
522
523 if (mask == (mode_t) -1)
524 {
525 mask = umask(022);
526 umask(mask);
527 }
528 switch(NewLhd.HostOS)
529 {
530 case HOST_MSDOS:
531 case HOST_OS2:
532 case HOST_WIN32:
533 if (NewLhd.FileAttr & 0x10)
534 NewLhd.FileAttr=0x41ff & ~mask;
535 else
536 if (NewLhd.FileAttr & 1)
537 NewLhd.FileAttr=0x8124 & ~mask;
538 else
539 NewLhd.FileAttr=0x81b6 & ~mask;
540 break;
541 case HOST_UNIX:
542 case HOST_BEOS:
543 break;
544 default:
545 if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
546 NewLhd.FileAttr=0x41ff & ~mask;
547 else
548 NewLhd.FileAttr=0x81b6 & ~mask;
549 break;
550 }
551 #endif
552 }
553
554
ConvertUnknownHeader()555 void Archive::ConvertUnknownHeader()
556 {
557 if (NewLhd.UnpVer<20 && (NewLhd.FileAttr & 0x10))
558 NewLhd.Flags|=LHD_DIRECTORY;
559 if (NewLhd.HostOS>=HOST_MAX)
560 {
561 if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
562 NewLhd.FileAttr=0x10;
563 else
564 NewLhd.FileAttr=0x20;
565 }
566 for (char *s=NewLhd.FileName;*s!=0;s=charnext(s))
567 {
568 if (*s=='/' || *s=='\\')
569 *s=CPATHDIVIDER;
570 #if defined(_APPLE) && !defined(UNICODE_SUPPORTED)
571 if ((byte)*s<32 || (byte)*s>127)
572 *s='_';
573 #endif
574 }
575 for (wchar *s=NewLhd.FileNameW;*s!=0;s++)
576 if (*s=='/' || *s=='\\')
577 *s=CPATHDIVIDER;
578 }
579
580
581 #ifndef SHELL_EXT
ReadSubData(Array<byte> * UnpData,File * DestFile)582 bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
583 {
584 if (HeaderCRC!=SubHead.HeadCRC)
585 {
586 #ifndef SHELL_EXT
587 Log(FileName,St(MSubHeadCorrupt));
588 #endif
589 ErrHandler.SetErrorCode(CRC_ERROR);
590 return(false);
591 }
592 if (SubHead.Method<0x30 || SubHead.Method>0x35 || SubHead.UnpVer>PACK_VER)
593 {
594 #ifndef SHELL_EXT
595 Log(FileName,St(MSubHeadUnknown));
596 #endif
597 return(false);
598 }
599
600 if (SubHead.PackSize==0 && (SubHead.Flags & LHD_SPLIT_AFTER)==0)
601 return(true);
602
603 SubDataIO.Init();
604 Unpack Unpack(&SubDataIO);
605 Unpack.Init();
606
607 if (DestFile==NULL)
608 {
609 UnpData->Alloc(SubHead.UnpSize);
610 SubDataIO.SetUnpackToMemory(&(*UnpData)[0],SubHead.UnpSize);
611 }
612 if (SubHead.Flags & LHD_PASSWORD)
613 if (*Cmd->Password)
614 SubDataIO.SetEncryption(SubHead.UnpVer,Cmd->Password,
615 (SubHead.Flags & LHD_SALT) ? SubHead.Salt:NULL,false);
616 else
617 return(false);
618 SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
619 SubDataIO.EnableShowProgress(false);
620 SubDataIO.SetFiles(this,DestFile);
621 SubDataIO.UnpVolume=(SubHead.Flags & LHD_SPLIT_AFTER);
622 SubDataIO.SetSubHeader(&SubHead,NULL);
623 Unpack.SetDestSize(SubHead.UnpSize);
624 if (SubHead.Method==0x30)
625 CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
626 else
627 Unpack.DoUnpack(SubHead.UnpVer,false);
628
629 if (SubHead.FileCRC!=~SubDataIO.UnpFileCRC)
630 {
631 #ifndef SHELL_EXT
632 Log(FileName,St(MSubHeadDataCRC),SubHead.FileName);
633 #endif
634 ErrHandler.SetErrorCode(CRC_ERROR);
635 if (UnpData!=NULL)
636 UnpData->Reset();
637 return(false);
638 }
639 return(true);
640 }
641 #endif
642