Unpack15.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. /*
  2. * Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
  3. * Original author: Edmund Wagner
  4. * Creation date: 21.06.2007
  5. *
  6. * the unrar licence applies to all junrar source and binary distributions
  7. * you are not allowed to use this source to re-create the RAR compression algorithm
  8. */
  9. using System;
  10. using System.IO;
  11. using SharpCompress.Compressors.Rar.UnpackV1.Decode;
  12. namespace SharpCompress.Compressors.Rar.UnpackV1
  13. {
  14. internal partial class Unpack
  15. {
  16. private int readBorder;
  17. private bool suspended;
  18. internal bool unpAllBuf;
  19. //private ComprDataIO unpIO;
  20. private Stream readStream;
  21. private Stream writeStream;
  22. internal bool unpSomeRead;
  23. private int readTop;
  24. private long destUnpSize;
  25. private byte[] window;
  26. private readonly int[] oldDist = new int[4];
  27. private int unpPtr, wrPtr;
  28. private int oldDistPtr;
  29. private readonly int[] ChSet = new int[256],
  30. ChSetA = new int[256],
  31. ChSetB = new int[256],
  32. ChSetC = new int[256];
  33. private readonly int[] Place = new int[256],
  34. PlaceA = new int[256],
  35. PlaceB = new int[256],
  36. PlaceC = new int[256];
  37. private readonly int[] NToPl = new int[256], NToPlB = new int[256], NToPlC = new int[256];
  38. private int FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3;
  39. private int Buf60, NumHuf, StMode, LCount, FlagsCnt;
  40. private int Nhfb, Nlzb, MaxDist3;
  41. private int lastDist, lastLength;
  42. private const int STARTL1 = 2;
  43. private static readonly int[] DecL1 =
  44. {
  45. 0x8000, 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf200
  46. , 0xffff
  47. };
  48. private static readonly int[] PosL1 = {0, 0, 0, 2, 3, 5, 7, 11, 16, 20, 24, 32, 32};
  49. private const int STARTL2 = 3;
  50. private static readonly int[] DecL2 =
  51. {
  52. 0xa000, 0xc000, 0xd000, 0xe000, 0xea00, 0xee00, 0xf000, 0xf200, 0xf240, 0xffff
  53. };
  54. private static readonly int[] PosL2 = {0, 0, 0, 0, 5, 7, 9, 13, 18, 22, 26, 34, 36};
  55. private const int STARTHF0 = 4;
  56. private static readonly int[] DecHf0 = {0x8000, 0xc000, 0xe000, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xffff};
  57. private static readonly int[] PosHf0 = {0, 0, 0, 0, 0, 8, 16, 24, 33, 33, 33, 33, 33};
  58. private const int STARTHF1 = 5;
  59. private static readonly int[] DecHf1 = {0x2000, 0xc000, 0xe000, 0xf000, 0xf200, 0xf200, 0xf7e0, 0xffff};
  60. private static readonly int[] PosHf1 = {0, 0, 0, 0, 0, 0, 4, 44, 60, 76, 80, 80, 127};
  61. private const int STARTHF2 = 5;
  62. private static readonly int[] DecHf2 = {0x1000, 0x2400, 0x8000, 0xc000, 0xfa00, 0xffff, 0xffff, 0xffff};
  63. private static readonly int[] PosHf2 = {0, 0, 0, 0, 0, 0, 2, 7, 53, 117, 233, 0, 0};
  64. private const int STARTHF3 = 6;
  65. private static readonly int[] DecHf3 = {0x800, 0x2400, 0xee00, 0xfe80, 0xffff, 0xffff, 0xffff};
  66. private static readonly int[] PosHf3 = {0, 0, 0, 0, 0, 0, 0, 2, 16, 218, 251, 0, 0};
  67. private const int STARTHF4 = 8;
  68. private static readonly int[] DecHf4 = {0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
  69. private static readonly int[] PosHf4 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0};
  70. private static readonly int[] ShortLen1 = {1, 3, 4, 4, 5, 6, 7, 8, 8, 4, 4, 5, 6, 6, 4, 0};
  71. private static readonly int[] ShortXor1 =
  72. {
  73. 0, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xc0, 0x80, 0x90, 0x98
  74. , 0x9c, 0xb0
  75. };
  76. private static readonly int[] ShortLen2 = {2, 3, 3, 3, 4, 4, 5, 6, 6, 4, 4, 5, 6, 6, 4, 0};
  77. private static readonly int[] ShortXor2 =
  78. {
  79. 0, 0x40, 0x60, 0xa0, 0xd0, 0xe0, 0xf0, 0xf8, 0xfc, 0xc0, 0x80, 0x90, 0x98
  80. , 0x9c, 0xb0
  81. };
  82. private void unpack15(bool solid)
  83. {
  84. if (suspended)
  85. {
  86. unpPtr = wrPtr;
  87. }
  88. else
  89. {
  90. UnpInitData(solid);
  91. oldUnpInitData(solid);
  92. unpReadBuf();
  93. if (!solid)
  94. {
  95. initHuff();
  96. unpPtr = 0;
  97. }
  98. else
  99. {
  100. unpPtr = wrPtr;
  101. }
  102. --destUnpSize;
  103. }
  104. if (destUnpSize >= 0)
  105. {
  106. getFlagsBuf();
  107. FlagsCnt = 8;
  108. }
  109. while (destUnpSize >= 0)
  110. {
  111. unpPtr &= PackDef.MAXWINMASK;
  112. if (inAddr > readTop - 30 && !unpReadBuf())
  113. {
  114. break;
  115. }
  116. if (((wrPtr - unpPtr) & PackDef.MAXWINMASK) < 270 && wrPtr != unpPtr)
  117. {
  118. oldUnpWriteBuf();
  119. if (suspended)
  120. {
  121. return;
  122. }
  123. }
  124. if (StMode != 0)
  125. {
  126. huffDecode();
  127. continue;
  128. }
  129. if (--FlagsCnt < 0)
  130. {
  131. getFlagsBuf();
  132. FlagsCnt = 7;
  133. }
  134. if ((FlagBuf & 0x80) != 0)
  135. {
  136. FlagBuf <<= 1;
  137. if (Nlzb > Nhfb)
  138. {
  139. longLZ();
  140. }
  141. else
  142. {
  143. huffDecode();
  144. }
  145. }
  146. else
  147. {
  148. FlagBuf <<= 1;
  149. if (--FlagsCnt < 0)
  150. {
  151. getFlagsBuf();
  152. FlagsCnt = 7;
  153. }
  154. if ((FlagBuf & 0x80) != 0)
  155. {
  156. FlagBuf <<= 1;
  157. if (Nlzb > Nhfb)
  158. {
  159. huffDecode();
  160. }
  161. else
  162. {
  163. longLZ();
  164. }
  165. }
  166. else
  167. {
  168. FlagBuf <<= 1;
  169. shortLZ();
  170. }
  171. }
  172. }
  173. oldUnpWriteBuf();
  174. }
  175. private bool unpReadBuf()
  176. {
  177. int dataSize = readTop - inAddr;
  178. if (dataSize < 0)
  179. {
  180. return (false);
  181. }
  182. if (inAddr > MAX_SIZE / 2)
  183. {
  184. if (dataSize > 0)
  185. {
  186. //memmove(InBuf,InBuf+InAddr,DataSize);
  187. // for (int i = 0; i < dataSize; i++) {
  188. // inBuf[i] = inBuf[inAddr + i];
  189. // }
  190. Array.Copy(InBuf, inAddr, InBuf, 0, dataSize);
  191. }
  192. inAddr = 0;
  193. readTop = dataSize;
  194. }
  195. else
  196. {
  197. dataSize = readTop;
  198. }
  199. //int readCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf);
  200. int readCode = readStream.Read(InBuf, dataSize, (MAX_SIZE - dataSize) & ~0xf);
  201. if (readCode > 0)
  202. {
  203. readTop += readCode;
  204. }
  205. readBorder = readTop - 30;
  206. return (readCode != -1);
  207. }
  208. private int getShortLen1(int pos)
  209. {
  210. return pos == 1 ? Buf60 + 3 : ShortLen1[pos];
  211. }
  212. private int getShortLen2(int pos)
  213. {
  214. return pos == 3 ? Buf60 + 3 : ShortLen2[pos];
  215. }
  216. private void shortLZ()
  217. {
  218. int Length, SaveLength;
  219. int LastDistance;
  220. int Distance;
  221. int DistancePlace;
  222. NumHuf = 0;
  223. int BitField = GetBits();
  224. if (LCount == 2)
  225. {
  226. AddBits(1);
  227. if (BitField >= 0x8000)
  228. {
  229. oldCopyString(lastDist, lastLength);
  230. return;
  231. }
  232. BitField <<= 1;
  233. LCount = 0;
  234. }
  235. BitField = Utility.URShift(BitField, 8);
  236. if (AvrLn1 < 37)
  237. {
  238. for (Length = 0;; Length++)
  239. {
  240. if (((BitField ^ ShortXor1[Length]) & (~(Utility.URShift(0xff, getShortLen1(Length))))) == 0)
  241. {
  242. break;
  243. }
  244. }
  245. AddBits(getShortLen1(Length));
  246. }
  247. else
  248. {
  249. for (Length = 0;; Length++)
  250. {
  251. if (((BitField ^ ShortXor2[Length]) & (~(0xff >> getShortLen2(Length)))) == 0)
  252. {
  253. break;
  254. }
  255. }
  256. AddBits(getShortLen2(Length));
  257. }
  258. if (Length >= 9)
  259. {
  260. if (Length == 9)
  261. {
  262. LCount++;
  263. oldCopyString(lastDist, lastLength);
  264. return;
  265. }
  266. if (Length == 14)
  267. {
  268. LCount = 0;
  269. Length = decodeNum(GetBits(), STARTL2, DecL2, PosL2) + 5;
  270. Distance = (GetBits() >> 1) | 0x8000;
  271. AddBits(15);
  272. lastLength = Length;
  273. lastDist = Distance;
  274. oldCopyString(Distance, Length);
  275. return;
  276. }
  277. LCount = 0;
  278. SaveLength = Length;
  279. Distance = oldDist[(oldDistPtr - (Length - 9)) & 3];
  280. Length = decodeNum(GetBits(), STARTL1, DecL1, PosL1) + 2;
  281. if (Length == 0x101 && SaveLength == 10)
  282. {
  283. Buf60 ^= 1;
  284. return;
  285. }
  286. if (Distance > 256)
  287. {
  288. Length++;
  289. }
  290. if (Distance >= MaxDist3)
  291. {
  292. Length++;
  293. }
  294. oldDist[oldDistPtr++] = Distance;
  295. oldDistPtr = oldDistPtr & 3;
  296. lastLength = Length;
  297. lastDist = Distance;
  298. oldCopyString(Distance, Length);
  299. return;
  300. }
  301. LCount = 0;
  302. AvrLn1 += Length;
  303. AvrLn1 -= (AvrLn1 >> 4);
  304. DistancePlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2) & 0xff;
  305. Distance = ChSetA[DistancePlace];
  306. if (--DistancePlace != -1)
  307. {
  308. PlaceA[Distance]--;
  309. LastDistance = ChSetA[DistancePlace];
  310. PlaceA[LastDistance]++;
  311. ChSetA[DistancePlace + 1] = LastDistance;
  312. ChSetA[DistancePlace] = Distance;
  313. }
  314. Length += 2;
  315. oldDist[oldDistPtr++] = ++Distance;
  316. oldDistPtr = oldDistPtr & 3;
  317. lastLength = Length;
  318. lastDist = Distance;
  319. oldCopyString(Distance, Length);
  320. }
  321. private void longLZ()
  322. {
  323. int Length;
  324. int Distance;
  325. int DistancePlace, NewDistancePlace;
  326. int OldAvr2, OldAvr3;
  327. NumHuf = 0;
  328. Nlzb += 16;
  329. if (Nlzb > 0xff)
  330. {
  331. Nlzb = 0x90;
  332. Nhfb = Utility.URShift(Nhfb, 1);
  333. }
  334. OldAvr2 = AvrLn2;
  335. int BitField = GetBits();
  336. if (AvrLn2 >= 122)
  337. {
  338. Length = decodeNum(BitField, STARTL2, DecL2, PosL2);
  339. }
  340. else
  341. {
  342. if (AvrLn2 >= 64)
  343. {
  344. Length = decodeNum(BitField, STARTL1, DecL1, PosL1);
  345. }
  346. else
  347. {
  348. if (BitField < 0x100)
  349. {
  350. Length = BitField;
  351. AddBits(16);
  352. }
  353. else
  354. {
  355. for (Length = 0; ((BitField << Length) & 0x8000) == 0; Length++)
  356. {
  357. ;
  358. }
  359. AddBits(Length + 1);
  360. }
  361. }
  362. }
  363. AvrLn2 += Length;
  364. AvrLn2 -= Utility.URShift(AvrLn2, 5);
  365. BitField = GetBits();
  366. if (AvrPlcB > 0x28ff)
  367. {
  368. DistancePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2);
  369. }
  370. else
  371. {
  372. if (AvrPlcB > 0x6ff)
  373. {
  374. DistancePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1);
  375. }
  376. else
  377. {
  378. DistancePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0);
  379. }
  380. }
  381. AvrPlcB += DistancePlace;
  382. AvrPlcB -= (AvrPlcB >> 8);
  383. while (true)
  384. {
  385. Distance = ChSetB[DistancePlace & 0xff];
  386. NewDistancePlace = NToPlB[Distance++ & 0xff]++;
  387. if ((Distance & 0xff) == 0)
  388. {
  389. corrHuff(ChSetB, NToPlB);
  390. }
  391. else
  392. {
  393. break;
  394. }
  395. }
  396. ChSetB[DistancePlace] = ChSetB[NewDistancePlace];
  397. ChSetB[NewDistancePlace] = Distance;
  398. Distance = Utility.URShift(((Distance & 0xff00) | (Utility.URShift(GetBits(), 8))), 1);
  399. AddBits(7);
  400. OldAvr3 = AvrLn3;
  401. if (Length != 1 && Length != 4)
  402. {
  403. if (Length == 0 && Distance <= MaxDist3)
  404. {
  405. AvrLn3++;
  406. AvrLn3 -= (AvrLn3 >> 8);
  407. }
  408. else
  409. {
  410. if (AvrLn3 > 0)
  411. {
  412. AvrLn3--;
  413. }
  414. }
  415. }
  416. Length += 3;
  417. if (Distance >= MaxDist3)
  418. {
  419. Length++;
  420. }
  421. if (Distance <= 256)
  422. {
  423. Length += 8;
  424. }
  425. if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40)
  426. {
  427. MaxDist3 = 0x7f00;
  428. }
  429. else
  430. {
  431. MaxDist3 = 0x2001;
  432. }
  433. oldDist[oldDistPtr++] = Distance;
  434. oldDistPtr = oldDistPtr & 3;
  435. lastLength = Length;
  436. lastDist = Distance;
  437. oldCopyString(Distance, Length);
  438. }
  439. private void huffDecode()
  440. {
  441. int CurByte, NewBytePlace;
  442. int Length;
  443. int Distance;
  444. int BytePlace;
  445. int BitField = GetBits();
  446. if (AvrPlc > 0x75ff)
  447. {
  448. BytePlace = decodeNum(BitField, STARTHF4, DecHf4, PosHf4);
  449. }
  450. else
  451. {
  452. if (AvrPlc > 0x5dff)
  453. {
  454. BytePlace = decodeNum(BitField, STARTHF3, DecHf3, PosHf3);
  455. }
  456. else
  457. {
  458. if (AvrPlc > 0x35ff)
  459. {
  460. BytePlace = decodeNum(BitField, STARTHF2, DecHf2, PosHf2);
  461. }
  462. else
  463. {
  464. if (AvrPlc > 0x0dff)
  465. {
  466. BytePlace = decodeNum(BitField, STARTHF1, DecHf1, PosHf1);
  467. }
  468. else
  469. {
  470. BytePlace = decodeNum(BitField, STARTHF0, DecHf0, PosHf0);
  471. }
  472. }
  473. }
  474. }
  475. BytePlace &= 0xff;
  476. if (StMode != 0)
  477. {
  478. if (BytePlace == 0 && BitField > 0xfff)
  479. {
  480. BytePlace = 0x100;
  481. }
  482. if (--BytePlace == -1)
  483. {
  484. BitField = GetBits();
  485. AddBits(1);
  486. if ((BitField & 0x8000) != 0)
  487. {
  488. NumHuf = StMode = 0;
  489. return;
  490. }
  491. Length = (BitField & 0x4000) != 0 ? 4 : 3;
  492. AddBits(1);
  493. Distance = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2);
  494. Distance = (Distance << 5) | (Utility.URShift(GetBits(), 11));
  495. AddBits(5);
  496. oldCopyString(Distance, Length);
  497. return;
  498. }
  499. }
  500. else
  501. {
  502. if (NumHuf++ >= 16 && FlagsCnt == 0)
  503. {
  504. StMode = 1;
  505. }
  506. }
  507. AvrPlc += BytePlace;
  508. AvrPlc -= Utility.URShift(AvrPlc, 8);
  509. Nhfb += 16;
  510. if (Nhfb > 0xff)
  511. {
  512. Nhfb = 0x90;
  513. Nlzb = Utility.URShift(Nlzb, 1);
  514. }
  515. window[unpPtr++] = (byte)(Utility.URShift(ChSet[BytePlace], 8));
  516. --destUnpSize;
  517. while (true)
  518. {
  519. CurByte = ChSet[BytePlace];
  520. NewBytePlace = NToPl[CurByte++ & 0xff]++;
  521. if ((CurByte & 0xff) > 0xa1)
  522. {
  523. corrHuff(ChSet, NToPl);
  524. }
  525. else
  526. {
  527. break;
  528. }
  529. }
  530. ChSet[BytePlace] = ChSet[NewBytePlace];
  531. ChSet[NewBytePlace] = CurByte;
  532. }
  533. private void getFlagsBuf()
  534. {
  535. int Flags, NewFlagsPlace;
  536. int FlagsPlace = decodeNum(GetBits(), STARTHF2, DecHf2, PosHf2);
  537. while (true)
  538. {
  539. Flags = ChSetC[FlagsPlace];
  540. FlagBuf = Utility.URShift(Flags, 8);
  541. NewFlagsPlace = NToPlC[Flags++ & 0xff]++;
  542. if ((Flags & 0xff) != 0)
  543. {
  544. break;
  545. }
  546. corrHuff(ChSetC, NToPlC);
  547. }
  548. ChSetC[FlagsPlace] = ChSetC[NewFlagsPlace];
  549. ChSetC[NewFlagsPlace] = Flags;
  550. }
  551. private void oldUnpInitData(bool Solid)
  552. {
  553. if (!Solid)
  554. {
  555. AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0;
  556. AvrPlc = 0x3500;
  557. MaxDist3 = 0x2001;
  558. Nhfb = Nlzb = 0x80;
  559. }
  560. FlagsCnt = 0;
  561. FlagBuf = 0;
  562. StMode = 0;
  563. LCount = 0;
  564. readTop = 0;
  565. }
  566. private void initHuff()
  567. {
  568. for (int I = 0; I < 256; I++)
  569. {
  570. Place[I] = PlaceA[I] = PlaceB[I] = I;
  571. PlaceC[I] = (~I + 1) & 0xff;
  572. ChSet[I] = ChSetB[I] = I << 8;
  573. ChSetA[I] = I;
  574. ChSetC[I] = ((~I + 1) & 0xff) << 8;
  575. }
  576. Utility.Fill(NToPl, 0); // memset(NToPl,0,sizeof(NToPl));
  577. Utility.Fill(NToPlB, 0); // memset(NToPlB,0,sizeof(NToPlB));
  578. Utility.Fill(NToPlC, 0); // memset(NToPlC,0,sizeof(NToPlC));
  579. corrHuff(ChSetB, NToPlB);
  580. }
  581. private void corrHuff(int[] CharSet, int[] NumToPlace)
  582. {
  583. int I, J, pos = 0;
  584. for (I = 7; I >= 0; I--)
  585. {
  586. for (J = 0; J < 32; J++, pos++)
  587. {
  588. CharSet[pos] = ((CharSet[pos] & ~0xff) | I); // *CharSet=(*CharSet
  589. // & ~0xff) | I;
  590. }
  591. }
  592. Utility.Fill(NumToPlace, 0); // memset(NumToPlace,0,sizeof(NToPl));
  593. for (I = 6; I >= 0; I--)
  594. {
  595. NumToPlace[I] = (7 - I) * 32;
  596. }
  597. }
  598. private void oldCopyString(int Distance, int Length)
  599. {
  600. destUnpSize -= Length;
  601. while ((Length--) != 0)
  602. {
  603. window[unpPtr] = window[(unpPtr - Distance) & PackDef.MAXWINMASK];
  604. unpPtr = (unpPtr + 1) & PackDef.MAXWINMASK;
  605. }
  606. }
  607. private int decodeNum(int Num, int StartPos, int[] DecTab, int[] PosTab)
  608. {
  609. int I;
  610. for (Num &= 0xfff0, I = 0; DecTab[I] <= Num; I++)
  611. {
  612. StartPos++;
  613. }
  614. AddBits(StartPos);
  615. return ((Utility.URShift((Num - (I != 0 ? DecTab[I - 1] : 0)), (16 - StartPos))) + PosTab[StartPos]);
  616. }
  617. private void oldUnpWriteBuf()
  618. {
  619. if (unpPtr != wrPtr)
  620. {
  621. unpSomeRead = true;
  622. }
  623. if (unpPtr < wrPtr)
  624. {
  625. writeStream.Write(window, wrPtr, -wrPtr & PackDef.MAXWINMASK);
  626. writeStream.Write(window, 0, unpPtr);
  627. unpAllBuf = true;
  628. }
  629. else
  630. {
  631. writeStream.Write(window, wrPtr, unpPtr - wrPtr);
  632. }
  633. wrPtr = unpPtr;
  634. }
  635. }
  636. }