eficompress.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731
  1. /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
  2. * Use of this source code is governed by a BSD-style license that can be
  3. * found in the LICENSE file.
  4. */
  5. /*++
  6. Copyright (c) 2006, Intel Corporation
  7. All rights reserved. This program and the accompanying materials
  8. are licensed and made available under the terms and conditions of the BSD License
  9. which accompanies this distribution. The full text of the license may be found at
  10. http://opensource.org/licenses/bsd-license.php
  11. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  12. WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
  13. Module Name:
  14. EfiCompress.c
  15. Abstract:
  16. Compression routine. The compression algorithm is a mixture of
  17. LZ77 and Huffman coding. LZ77 transforms the source data into a
  18. sequence of Original Characters and Pointers to repeated strings.
  19. This sequence is further divided into Blocks and Huffman codings
  20. are applied to each Block.
  21. --*/
  22. #include <errno.h>
  23. #include <stdint.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <unistd.h>
  30. #include "eficompress.h"
  31. //
  32. // Macro Definitions
  33. //
  34. typedef INT16 NODE;
  35. #define UINT8_BIT 8
  36. #define THRESHOLD 3
  37. #define INIT_CRC 0
  38. #define WNDBIT 13
  39. #define WNDSIZ (1U << WNDBIT)
  40. #define MAXMATCH 256
  41. #define PERC_FLAG 0x8000U
  42. #define CODE_BIT 16
  43. #define NIL 0
  44. #define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
  45. #define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
  46. #define CRCPOLY 0xA001
  47. #define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
  48. //
  49. // C: the Char&Len Set; P: the Position Set; T: the exTra Set
  50. //
  51. #define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)
  52. #define CBIT 9
  53. #define NP (WNDBIT + 1)
  54. #define PBIT 4
  55. #define NT (CODE_BIT + 3)
  56. #define TBIT 5
  57. #if NT > NP
  58. #define NPT NT
  59. #else
  60. #define NPT NP
  61. #endif
  62. //
  63. // Function Prototypes
  64. //
  65. STATIC
  66. VOID
  67. PutDword(
  68. IN UINT32 Data
  69. );
  70. STATIC
  71. EFI_STATUS
  72. AllocateMemory (
  73. );
  74. STATIC
  75. VOID
  76. FreeMemory (
  77. );
  78. STATIC
  79. VOID
  80. InitSlide (
  81. );
  82. STATIC
  83. NODE
  84. Child (
  85. IN NODE q,
  86. IN UINT8 c
  87. );
  88. STATIC
  89. VOID
  90. MakeChild (
  91. IN NODE q,
  92. IN UINT8 c,
  93. IN NODE r
  94. );
  95. STATIC
  96. VOID
  97. Split (
  98. IN NODE Old
  99. );
  100. STATIC
  101. VOID
  102. InsertNode (
  103. );
  104. STATIC
  105. VOID
  106. DeleteNode (
  107. );
  108. STATIC
  109. VOID
  110. GetNextMatch (
  111. );
  112. STATIC
  113. EFI_STATUS
  114. Encode (
  115. );
  116. STATIC
  117. VOID
  118. CountTFreq (
  119. );
  120. STATIC
  121. VOID
  122. WritePTLen (
  123. IN INT32 n,
  124. IN INT32 nbit,
  125. IN INT32 Special
  126. );
  127. STATIC
  128. VOID
  129. WriteCLen (
  130. );
  131. STATIC
  132. VOID
  133. EncodeC (
  134. IN INT32 c
  135. );
  136. STATIC
  137. VOID
  138. EncodeP (
  139. IN UINT32 p
  140. );
  141. STATIC
  142. VOID
  143. SendBlock (
  144. );
  145. STATIC
  146. VOID
  147. Output (
  148. IN UINT32 c,
  149. IN UINT32 p
  150. );
  151. STATIC
  152. VOID
  153. HufEncodeStart (
  154. );
  155. STATIC
  156. VOID
  157. HufEncodeEnd (
  158. );
  159. STATIC
  160. VOID
  161. MakeCrcTable (
  162. );
  163. STATIC
  164. VOID
  165. PutBits (
  166. IN INT32 n,
  167. IN UINT32 x
  168. );
  169. STATIC
  170. INT32
  171. FreadCrc (
  172. OUT UINT8 *p,
  173. IN INT32 n
  174. );
  175. STATIC
  176. VOID
  177. InitPutBits (
  178. );
  179. STATIC
  180. VOID
  181. CountLen (
  182. IN INT32 i
  183. );
  184. STATIC
  185. VOID
  186. MakeLen (
  187. IN INT32 Root
  188. );
  189. STATIC
  190. VOID
  191. DownHeap (
  192. IN INT32 i
  193. );
  194. STATIC
  195. VOID
  196. MakeCode (
  197. IN INT32 n,
  198. IN UINT8 Len[],
  199. OUT UINT16 Code[]
  200. );
  201. STATIC
  202. INT32
  203. MakeTree (
  204. IN INT32 NParm,
  205. IN UINT16 FreqParm[],
  206. OUT UINT8 LenParm[],
  207. OUT UINT16 CodeParm[]
  208. );
  209. //
  210. // Global Variables
  211. //
  212. STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit;
  213. STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen;
  214. STATIC INT16 mHeap[NC + 1];
  215. STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN;
  216. STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc;
  217. STATIC UINT32 mCompSize, mOrigSize;
  218. STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1],
  219. mCrcTable[UINT8_MAX + 1], mCFreq[2 * NC - 1], mCCode[NC],
  220. mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1];
  221. STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL;
  222. //
  223. // functions
  224. //
  225. EFI_STATUS
  226. EfiCompress (
  227. IN UINT8 *SrcBuffer,
  228. IN UINT32 SrcSize,
  229. IN UINT8 *DstBuffer,
  230. IN OUT UINT32 *DstSize
  231. )
  232. /*++
  233. Routine Description:
  234. The main compression routine.
  235. Arguments:
  236. SrcBuffer - The buffer storing the source data
  237. SrcSize - The size of source data
  238. DstBuffer - The buffer to store the compressed data
  239. DstSize - On input, the size of DstBuffer; On output,
  240. the size of the actual compressed data.
  241. Returns:
  242. EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. In this case,
  243. DstSize contains the size needed.
  244. EFI_SUCCESS - Compression is successful.
  245. --*/
  246. {
  247. EFI_STATUS Status = EFI_SUCCESS;
  248. //
  249. // Initializations
  250. //
  251. mBufSiz = 0;
  252. mBuf = NULL;
  253. mText = NULL;
  254. mLevel = NULL;
  255. mChildCount = NULL;
  256. mPosition = NULL;
  257. mParent = NULL;
  258. mPrev = NULL;
  259. mNext = NULL;
  260. mSrc = SrcBuffer;
  261. mSrcUpperLimit = mSrc + SrcSize;
  262. mDst = DstBuffer;
  263. mDstUpperLimit = mDst + *DstSize;
  264. PutDword(0L);
  265. PutDword(0L);
  266. MakeCrcTable ();
  267. mOrigSize = mCompSize = 0;
  268. mCrc = INIT_CRC;
  269. //
  270. // Compress it
  271. //
  272. Status = Encode();
  273. if (EFI_ERROR (Status)) {
  274. return EFI_OUT_OF_RESOURCES;
  275. }
  276. //
  277. // Null terminate the compressed data
  278. //
  279. if (mDst < mDstUpperLimit) {
  280. *mDst++ = 0;
  281. }
  282. //
  283. // Fill in compressed size and original size
  284. //
  285. mDst = DstBuffer;
  286. PutDword(mCompSize+1);
  287. PutDword(mOrigSize);
  288. //
  289. // Return
  290. //
  291. if (mCompSize + 1 + 8 > *DstSize) {
  292. *DstSize = mCompSize + 1 + 8;
  293. return EFI_BUFFER_TOO_SMALL;
  294. } else {
  295. *DstSize = mCompSize + 1 + 8;
  296. return EFI_SUCCESS;
  297. }
  298. }
  299. STATIC
  300. VOID
  301. PutDword(
  302. IN UINT32 Data
  303. )
  304. /*++
  305. Routine Description:
  306. Put a dword to output stream
  307. Arguments:
  308. Data - the dword to put
  309. Returns: (VOID)
  310. --*/
  311. {
  312. if (mDst < mDstUpperLimit) {
  313. *mDst++ = (UINT8)(((UINT8)(Data )) & 0xff);
  314. }
  315. if (mDst < mDstUpperLimit) {
  316. *mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff);
  317. }
  318. if (mDst < mDstUpperLimit) {
  319. *mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff);
  320. }
  321. if (mDst < mDstUpperLimit) {
  322. *mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff);
  323. }
  324. }
  325. STATIC
  326. EFI_STATUS
  327. AllocateMemory ()
  328. /*++
  329. Routine Description:
  330. Allocate memory spaces for data structures used in compression process
  331. Argements: (VOID)
  332. Returns:
  333. EFI_SUCCESS - Memory is allocated successfully
  334. EFI_OUT_OF_RESOURCES - Allocation fails
  335. --*/
  336. {
  337. UINT32 i;
  338. mText = malloc (WNDSIZ * 2 + MAXMATCH);
  339. for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) {
  340. mText[i] = 0;
  341. }
  342. mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel));
  343. mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount));
  344. mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition));
  345. mParent = malloc (WNDSIZ * 2 * sizeof(*mParent));
  346. mPrev = malloc (WNDSIZ * 2 * sizeof(*mPrev));
  347. mNext = malloc ((MAX_HASH_VAL + 1) * sizeof(*mNext));
  348. mBufSiz = 16 * 1024U;
  349. while ((mBuf = malloc(mBufSiz)) == NULL) {
  350. mBufSiz = (mBufSiz / 10U) * 9U;
  351. if (mBufSiz < 4 * 1024U) {
  352. return EFI_OUT_OF_RESOURCES;
  353. }
  354. }
  355. mBuf[0] = 0;
  356. return EFI_SUCCESS;
  357. }
  358. VOID
  359. FreeMemory ()
  360. /*++
  361. Routine Description:
  362. Called when compression is completed to free memory previously allocated.
  363. Arguments: (VOID)
  364. Returns: (VOID)
  365. --*/
  366. {
  367. if (mText) {
  368. free (mText);
  369. }
  370. if (mLevel) {
  371. free (mLevel);
  372. }
  373. if (mChildCount) {
  374. free (mChildCount);
  375. }
  376. if (mPosition) {
  377. free (mPosition);
  378. }
  379. if (mParent) {
  380. free (mParent);
  381. }
  382. if (mPrev) {
  383. free (mPrev);
  384. }
  385. if (mNext) {
  386. free (mNext);
  387. }
  388. if (mBuf) {
  389. free (mBuf);
  390. }
  391. return;
  392. }
  393. STATIC
  394. VOID
  395. InitSlide ()
  396. /*++
  397. Routine Description:
  398. Initialize String Info Log data structures
  399. Arguments: (VOID)
  400. Returns: (VOID)
  401. --*/
  402. {
  403. NODE i;
  404. for (i = WNDSIZ; i <= WNDSIZ + UINT8_MAX; i++) {
  405. mLevel[i] = 1;
  406. mPosition[i] = NIL; /* sentinel */
  407. }
  408. for (i = WNDSIZ; i < WNDSIZ * 2; i++) {
  409. mParent[i] = NIL;
  410. }
  411. mAvail = 1;
  412. for (i = 1; i < WNDSIZ - 1; i++) {
  413. mNext[i] = (NODE)(i + 1);
  414. }
  415. mNext[WNDSIZ - 1] = NIL;
  416. for (i = WNDSIZ * 2; i <= MAX_HASH_VAL; i++) {
  417. mNext[i] = NIL;
  418. }
  419. }
  420. STATIC
  421. NODE
  422. Child (
  423. IN NODE q,
  424. IN UINT8 c
  425. )
  426. /*++
  427. Routine Description:
  428. Find child node given the parent node and the edge character
  429. Arguments:
  430. q - the parent node
  431. c - the edge character
  432. Returns:
  433. The child node (NIL if not found)
  434. --*/
  435. {
  436. NODE r;
  437. r = mNext[HASH(q, c)];
  438. mParent[NIL] = q; /* sentinel */
  439. while (mParent[r] != q) {
  440. r = mNext[r];
  441. }
  442. return r;
  443. }
  444. STATIC
  445. VOID
  446. MakeChild (
  447. IN NODE q,
  448. IN UINT8 c,
  449. IN NODE r
  450. )
  451. /*++
  452. Routine Description:
  453. Create a new child for a given parent node.
  454. Arguments:
  455. q - the parent node
  456. c - the edge character
  457. r - the child node
  458. Returns: (VOID)
  459. --*/
  460. {
  461. NODE h, t;
  462. h = (NODE)HASH(q, c);
  463. t = mNext[h];
  464. mNext[h] = r;
  465. mNext[r] = t;
  466. mPrev[t] = r;
  467. mPrev[r] = h;
  468. mParent[r] = q;
  469. mChildCount[q]++;
  470. }
  471. STATIC
  472. VOID
  473. Split (
  474. NODE Old
  475. )
  476. /*++
  477. Routine Description:
  478. Split a node.
  479. Arguments:
  480. Old - the node to split
  481. Returns: (VOID)
  482. --*/
  483. {
  484. NODE New, t;
  485. New = mAvail;
  486. mAvail = mNext[New];
  487. mChildCount[New] = 0;
  488. t = mPrev[Old];
  489. mPrev[New] = t;
  490. mNext[t] = New;
  491. t = mNext[Old];
  492. mNext[New] = t;
  493. mPrev[t] = New;
  494. mParent[New] = mParent[Old];
  495. mLevel[New] = (UINT8)mMatchLen;
  496. mPosition[New] = mPos;
  497. MakeChild(New, mText[mMatchPos + mMatchLen], Old);
  498. MakeChild(New, mText[mPos + mMatchLen], mPos);
  499. }
  500. STATIC
  501. VOID
  502. InsertNode ()
  503. /*++
  504. Routine Description:
  505. Insert string info for current position into the String Info Log
  506. Arguments: (VOID)
  507. Returns: (VOID)
  508. --*/
  509. {
  510. NODE q, r, j, t;
  511. UINT8 c, *t1, *t2;
  512. if (mMatchLen >= 4) {
  513. //
  514. // We have just got a long match, the target tree
  515. // can be located by MatchPos + 1. Travese the tree
  516. // from bottom up to get to a proper starting point.
  517. // The usage of PERC_FLAG ensures proper node deletion
  518. // in DeleteNode() later.
  519. //
  520. mMatchLen--;
  521. r = (INT16)((mMatchPos + 1) | WNDSIZ);
  522. while ((q = mParent[r]) == NIL) {
  523. r = mNext[r];
  524. }
  525. while (mLevel[q] >= mMatchLen) {
  526. r = q; q = mParent[q];
  527. }
  528. t = q;
  529. while (mPosition[t] < 0) {
  530. mPosition[t] = mPos;
  531. t = mParent[t];
  532. }
  533. if (t < WNDSIZ) {
  534. mPosition[t] = (NODE)(mPos | PERC_FLAG);
  535. }
  536. } else {
  537. //
  538. // Locate the target tree
  539. //
  540. q = (INT16)(mText[mPos] + WNDSIZ);
  541. c = mText[mPos + 1];
  542. if ((r = Child(q, c)) == NIL) {
  543. MakeChild(q, c, mPos);
  544. mMatchLen = 1;
  545. return;
  546. }
  547. mMatchLen = 2;
  548. }
  549. //
  550. // Traverse down the tree to find a match.
  551. // Update Position value along the route.
  552. // Node split or creation is involved.
  553. //
  554. for ( ; ; ) {
  555. if (r >= WNDSIZ) {
  556. j = MAXMATCH;
  557. mMatchPos = r;
  558. } else {
  559. j = mLevel[r];
  560. mMatchPos = (NODE)(mPosition[r] & ~PERC_FLAG);
  561. }
  562. if (mMatchPos >= mPos) {
  563. mMatchPos -= WNDSIZ;
  564. }
  565. t1 = &mText[mPos + mMatchLen];
  566. t2 = &mText[mMatchPos + mMatchLen];
  567. while (mMatchLen < j) {
  568. if (*t1 != *t2) {
  569. Split(r);
  570. return;
  571. }
  572. mMatchLen++;
  573. t1++;
  574. t2++;
  575. }
  576. if (mMatchLen >= MAXMATCH) {
  577. break;
  578. }
  579. mPosition[r] = mPos;
  580. q = r;
  581. if ((r = Child(q, *t1)) == NIL) {
  582. MakeChild(q, *t1, mPos);
  583. return;
  584. }
  585. mMatchLen++;
  586. }
  587. t = mPrev[r];
  588. mPrev[mPos] = t;
  589. mNext[t] = mPos;
  590. t = mNext[r];
  591. mNext[mPos] = t;
  592. mPrev[t] = mPos;
  593. mParent[mPos] = q;
  594. mParent[r] = NIL;
  595. //
  596. // Special usage of 'next'
  597. //
  598. mNext[r] = mPos;
  599. }
  600. STATIC
  601. VOID
  602. DeleteNode ()
  603. /*++
  604. Routine Description:
  605. Delete outdated string info. (The Usage of PERC_FLAG
  606. ensures a clean deletion)
  607. Arguments: (VOID)
  608. Returns: (VOID)
  609. --*/
  610. {
  611. NODE q, r, s, t, u;
  612. if (mParent[mPos] == NIL) {
  613. return;
  614. }
  615. r = mPrev[mPos];
  616. s = mNext[mPos];
  617. mNext[r] = s;
  618. mPrev[s] = r;
  619. r = mParent[mPos];
  620. mParent[mPos] = NIL;
  621. if (r >= WNDSIZ || --mChildCount[r] > 1) {
  622. return;
  623. }
  624. t = (NODE)(mPosition[r] & ~PERC_FLAG);
  625. if (t >= mPos) {
  626. t -= WNDSIZ;
  627. }
  628. s = t;
  629. q = mParent[r];
  630. while ((u = mPosition[q]) & PERC_FLAG) {
  631. u &= ~PERC_FLAG;
  632. if (u >= mPos) {
  633. u -= WNDSIZ;
  634. }
  635. if (u > s) {
  636. s = u;
  637. }
  638. mPosition[q] = (INT16)(s | WNDSIZ);
  639. q = mParent[q];
  640. }
  641. if (q < WNDSIZ) {
  642. if (u >= mPos) {
  643. u -= WNDSIZ;
  644. }
  645. if (u > s) {
  646. s = u;
  647. }
  648. mPosition[q] = (INT16)(s | WNDSIZ | PERC_FLAG);
  649. }
  650. s = Child(r, mText[t + mLevel[r]]);
  651. t = mPrev[s];
  652. u = mNext[s];
  653. mNext[t] = u;
  654. mPrev[u] = t;
  655. t = mPrev[r];
  656. mNext[t] = s;
  657. mPrev[s] = t;
  658. t = mNext[r];
  659. mPrev[t] = s;
  660. mNext[s] = t;
  661. mParent[s] = mParent[r];
  662. mParent[r] = NIL;
  663. mNext[r] = mAvail;
  664. mAvail = r;
  665. }
  666. STATIC
  667. VOID
  668. GetNextMatch ()
  669. /*++
  670. Routine Description:
  671. Advance the current position (read in new data if needed).
  672. Delete outdated string info. Find a match string for current position.
  673. Arguments: (VOID)
  674. Returns: (VOID)
  675. --*/
  676. {
  677. INT32 n;
  678. mRemainder--;
  679. if (++mPos == WNDSIZ * 2) {
  680. memmove(&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH);
  681. n = FreadCrc(&mText[WNDSIZ + MAXMATCH], WNDSIZ);
  682. mRemainder += n;
  683. mPos = WNDSIZ;
  684. }
  685. DeleteNode();
  686. InsertNode();
  687. }
  688. STATIC
  689. EFI_STATUS
  690. Encode ()
  691. /*++
  692. Routine Description:
  693. The main controlling routine for compression process.
  694. Arguments: (VOID)
  695. Returns:
  696. EFI_SUCCESS - The compression is successful
  697. EFI_OUT_0F_RESOURCES - Not enough memory for compression process
  698. --*/
  699. {
  700. EFI_STATUS Status;
  701. INT32 LastMatchLen;
  702. NODE LastMatchPos;
  703. Status = AllocateMemory();
  704. if (EFI_ERROR(Status)) {
  705. FreeMemory();
  706. return Status;
  707. }
  708. InitSlide();
  709. HufEncodeStart();
  710. mRemainder = FreadCrc(&mText[WNDSIZ], WNDSIZ + MAXMATCH);
  711. mMatchLen = 0;
  712. mPos = WNDSIZ;
  713. InsertNode();
  714. if (mMatchLen > mRemainder) {
  715. mMatchLen = mRemainder;
  716. }
  717. while (mRemainder > 0) {
  718. LastMatchLen = mMatchLen;
  719. LastMatchPos = mMatchPos;
  720. GetNextMatch();
  721. if (mMatchLen > mRemainder) {
  722. mMatchLen = mRemainder;
  723. }
  724. if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) {
  725. //
  726. // Not enough benefits are gained by outputting a pointer,
  727. // so just output the original character
  728. //
  729. Output(mText[mPos - 1], 0);
  730. } else {
  731. //
  732. // Outputting a pointer is beneficial enough, do it.
  733. //
  734. Output(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD),
  735. (mPos - LastMatchPos - 2) & (WNDSIZ - 1));
  736. while (--LastMatchLen > 0) {
  737. GetNextMatch();
  738. }
  739. if (mMatchLen > mRemainder) {
  740. mMatchLen = mRemainder;
  741. }
  742. }
  743. }
  744. HufEncodeEnd();
  745. FreeMemory();
  746. return EFI_SUCCESS;
  747. }
  748. STATIC
  749. VOID
  750. CountTFreq ()
  751. /*++
  752. Routine Description:
  753. Count the frequencies for the Extra Set
  754. Arguments: (VOID)
  755. Returns: (VOID)
  756. --*/
  757. {
  758. INT32 i, k, n, Count;
  759. for (i = 0; i < NT; i++) {
  760. mTFreq[i] = 0;
  761. }
  762. n = NC;
  763. while (n > 0 && mCLen[n - 1] == 0) {
  764. n--;
  765. }
  766. i = 0;
  767. while (i < n) {
  768. k = mCLen[i++];
  769. if (k == 0) {
  770. Count = 1;
  771. while (i < n && mCLen[i] == 0) {
  772. i++;
  773. Count++;
  774. }
  775. if (Count <= 2) {
  776. mTFreq[0] = (UINT16)(mTFreq[0] + Count);
  777. } else if (Count <= 18) {
  778. mTFreq[1]++;
  779. } else if (Count == 19) {
  780. mTFreq[0]++;
  781. mTFreq[1]++;
  782. } else {
  783. mTFreq[2]++;
  784. }
  785. } else {
  786. mTFreq[k + 2]++;
  787. }
  788. }
  789. }
  790. STATIC
  791. VOID
  792. WritePTLen (
  793. IN INT32 n,
  794. IN INT32 nbit,
  795. IN INT32 Special
  796. )
  797. /*++
  798. Routine Description:
  799. Outputs the code length array for the Extra Set or the Position Set.
  800. Arguments:
  801. n - the number of symbols
  802. nbit - the number of bits needed to represent 'n'
  803. Special - the special symbol that needs to be take care of
  804. Returns: (VOID)
  805. --*/
  806. {
  807. INT32 i, k;
  808. while (n > 0 && mPTLen[n - 1] == 0) {
  809. n--;
  810. }
  811. PutBits(nbit, n);
  812. i = 0;
  813. while (i < n) {
  814. k = mPTLen[i++];
  815. if (k <= 6) {
  816. PutBits(3, k);
  817. } else {
  818. PutBits(k - 3, (1U << (k - 3)) - 2);
  819. }
  820. if (i == Special) {
  821. while (i < 6 && mPTLen[i] == 0) {
  822. i++;
  823. }
  824. PutBits(2, (i - 3) & 3);
  825. }
  826. }
  827. }
  828. STATIC
  829. VOID
  830. WriteCLen ()
  831. /*++
  832. Routine Description:
  833. Outputs the code length array for Char&Length Set
  834. Arguments: (VOID)
  835. Returns: (VOID)
  836. --*/
  837. {
  838. INT32 i, k, n, Count;
  839. n = NC;
  840. while (n > 0 && mCLen[n - 1] == 0) {
  841. n--;
  842. }
  843. PutBits(CBIT, n);
  844. i = 0;
  845. while (i < n) {
  846. k = mCLen[i++];
  847. if (k == 0) {
  848. Count = 1;
  849. while (i < n && mCLen[i] == 0) {
  850. i++;
  851. Count++;
  852. }
  853. if (Count <= 2) {
  854. for (k = 0; k < Count; k++) {
  855. PutBits(mPTLen[0], mPTCode[0]);
  856. }
  857. } else if (Count <= 18) {
  858. PutBits(mPTLen[1], mPTCode[1]);
  859. PutBits(4, Count - 3);
  860. } else if (Count == 19) {
  861. PutBits(mPTLen[0], mPTCode[0]);
  862. PutBits(mPTLen[1], mPTCode[1]);
  863. PutBits(4, 15);
  864. } else {
  865. PutBits(mPTLen[2], mPTCode[2]);
  866. PutBits(CBIT, Count - 20);
  867. }
  868. } else {
  869. PutBits(mPTLen[k + 2], mPTCode[k + 2]);
  870. }
  871. }
  872. }
  873. STATIC
  874. VOID
  875. EncodeC (
  876. IN INT32 c
  877. )
  878. {
  879. PutBits(mCLen[c], mCCode[c]);
  880. }
  881. STATIC
  882. VOID
  883. EncodeP (
  884. IN UINT32 p
  885. )
  886. {
  887. UINT32 c, q;
  888. c = 0;
  889. q = p;
  890. while (q) {
  891. q >>= 1;
  892. c++;
  893. }
  894. PutBits(mPTLen[c], mPTCode[c]);
  895. if (c > 1) {
  896. PutBits(c - 1, p & (0xFFFFU >> (17 - c)));
  897. }
  898. }
  899. STATIC
  900. VOID
  901. SendBlock ()
  902. /*++
  903. Routine Description:
  904. Huffman code the block and output it.
  905. Argument: (VOID)
  906. Returns: (VOID)
  907. --*/
  908. {
  909. UINT32 i, k, Flags, Root, Pos, Size;
  910. Flags = 0;
  911. Root = MakeTree(NC, mCFreq, mCLen, mCCode);
  912. Size = mCFreq[Root];
  913. PutBits(16, Size);
  914. if (Root >= NC) {
  915. CountTFreq();
  916. Root = MakeTree(NT, mTFreq, mPTLen, mPTCode);
  917. if (Root >= NT) {
  918. WritePTLen(NT, TBIT, 3);
  919. } else {
  920. PutBits(TBIT, 0);
  921. PutBits(TBIT, Root);
  922. }
  923. WriteCLen();
  924. } else {
  925. PutBits(TBIT, 0);
  926. PutBits(TBIT, 0);
  927. PutBits(CBIT, 0);
  928. PutBits(CBIT, Root);
  929. }
  930. Root = MakeTree(NP, mPFreq, mPTLen, mPTCode);
  931. if (Root >= NP) {
  932. WritePTLen(NP, PBIT, -1);
  933. } else {
  934. PutBits(PBIT, 0);
  935. PutBits(PBIT, Root);
  936. }
  937. Pos = 0;
  938. for (i = 0; i < Size; i++) {
  939. if (i % UINT8_BIT == 0) {
  940. Flags = mBuf[Pos++];
  941. } else {
  942. Flags <<= 1;
  943. }
  944. if (Flags & (1U << (UINT8_BIT - 1))) {
  945. EncodeC(mBuf[Pos++] + (1U << UINT8_BIT));
  946. k = mBuf[Pos++] << UINT8_BIT;
  947. k += mBuf[Pos++];
  948. EncodeP(k);
  949. } else {
  950. EncodeC(mBuf[Pos++]);
  951. }
  952. }
  953. for (i = 0; i < NC; i++) {
  954. mCFreq[i] = 0;
  955. }
  956. for (i = 0; i < NP; i++) {
  957. mPFreq[i] = 0;
  958. }
  959. }
  960. STATIC
  961. VOID
  962. Output (
  963. IN UINT32 c,
  964. IN UINT32 p
  965. )
  966. /*++
  967. Routine Description:
  968. Outputs an Original Character or a Pointer
  969. Arguments:
  970. c - The original character or the 'String Length' element of a Pointer
  971. p - The 'Position' field of a Pointer
  972. Returns: (VOID)
  973. --*/
  974. {
  975. STATIC UINT32 CPos;
  976. if ((mOutputMask >>= 1) == 0) {
  977. mOutputMask = 1U << (UINT8_BIT - 1);
  978. if (mOutputPos >= mBufSiz - 3 * UINT8_BIT) {
  979. SendBlock();
  980. mOutputPos = 0;
  981. }
  982. CPos = mOutputPos++;
  983. mBuf[CPos] = 0;
  984. }
  985. mBuf[mOutputPos++] = (UINT8) c;
  986. mCFreq[c]++;
  987. if (c >= (1U << UINT8_BIT)) {
  988. mBuf[CPos] |= mOutputMask;
  989. mBuf[mOutputPos++] = (UINT8)(p >> UINT8_BIT);
  990. mBuf[mOutputPos++] = (UINT8) p;
  991. c = 0;
  992. while (p) {
  993. p >>= 1;
  994. c++;
  995. }
  996. mPFreq[c]++;
  997. }
  998. }
  999. STATIC
  1000. VOID
  1001. HufEncodeStart ()
  1002. {
  1003. INT32 i;
  1004. for (i = 0; i < NC; i++) {
  1005. mCFreq[i] = 0;
  1006. }
  1007. for (i = 0; i < NP; i++) {
  1008. mPFreq[i] = 0;
  1009. }
  1010. mOutputPos = mOutputMask = 0;
  1011. InitPutBits();
  1012. return;
  1013. }
  1014. STATIC
  1015. VOID
  1016. HufEncodeEnd ()
  1017. {
  1018. SendBlock();
  1019. //
  1020. // Flush remaining bits
  1021. //
  1022. PutBits(UINT8_BIT - 1, 0);
  1023. return;
  1024. }
  1025. STATIC
  1026. VOID
  1027. MakeCrcTable ()
  1028. {
  1029. UINT32 i, j, r;
  1030. for (i = 0; i <= UINT8_MAX; i++) {
  1031. r = i;
  1032. for (j = 0; j < UINT8_BIT; j++) {
  1033. if (r & 1) {
  1034. r = (r >> 1) ^ CRCPOLY;
  1035. } else {
  1036. r >>= 1;
  1037. }
  1038. }
  1039. mCrcTable[i] = (UINT16)r;
  1040. }
  1041. }
  1042. STATIC
  1043. VOID
  1044. PutBits (
  1045. IN INT32 n,
  1046. IN UINT32 x
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. Outputs rightmost n bits of x
  1051. Argments:
  1052. n - the rightmost n bits of the data is used
  1053. x - the data
  1054. Returns: (VOID)
  1055. --*/
  1056. {
  1057. UINT8 Temp;
  1058. if (n < mBitCount) {
  1059. mSubBitBuf |= x << (mBitCount -= n);
  1060. } else {
  1061. Temp = (UINT8)(mSubBitBuf | (x >> (n -= mBitCount)));
  1062. if (mDst < mDstUpperLimit) {
  1063. *mDst++ = Temp;
  1064. }
  1065. mCompSize++;
  1066. if (n < UINT8_BIT) {
  1067. mSubBitBuf = x << (mBitCount = UINT8_BIT - n);
  1068. } else {
  1069. Temp = (UINT8)(x >> (n - UINT8_BIT));
  1070. if (mDst < mDstUpperLimit) {
  1071. *mDst++ = Temp;
  1072. }
  1073. mCompSize++;
  1074. mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - n);
  1075. }
  1076. }
  1077. }
  1078. STATIC
  1079. INT32
  1080. FreadCrc (
  1081. OUT UINT8 *p,
  1082. IN INT32 n
  1083. )
  1084. /*++
  1085. Routine Description:
  1086. Read in source data
  1087. Arguments:
  1088. p - the buffer to hold the data
  1089. n - number of bytes to read
  1090. Returns:
  1091. number of bytes actually read
  1092. --*/
  1093. {
  1094. INT32 i;
  1095. for (i = 0; mSrc < mSrcUpperLimit && i < n; i++) {
  1096. *p++ = *mSrc++;
  1097. }
  1098. n = i;
  1099. p -= n;
  1100. mOrigSize += n;
  1101. while (--i >= 0) {
  1102. UPDATE_CRC(*p++);
  1103. }
  1104. return n;
  1105. }
  1106. STATIC
  1107. VOID
  1108. InitPutBits ()
  1109. {
  1110. mBitCount = UINT8_BIT;
  1111. mSubBitBuf = 0;
  1112. }
  1113. STATIC
  1114. VOID
  1115. CountLen (
  1116. IN INT32 i
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. Count the number of each code length for a Huffman tree.
  1121. Arguments:
  1122. i - the top node
  1123. Returns: (VOID)
  1124. --*/
  1125. {
  1126. STATIC INT32 Depth = 0;
  1127. if (i < mN) {
  1128. mLenCnt[(Depth < 16) ? Depth : 16]++;
  1129. } else {
  1130. Depth++;
  1131. CountLen(mLeft [i]);
  1132. CountLen(mRight[i]);
  1133. Depth--;
  1134. }
  1135. }
  1136. STATIC
  1137. VOID
  1138. MakeLen (
  1139. IN INT32 Root
  1140. )
  1141. /*++
  1142. Routine Description:
  1143. Create code length array for a Huffman tree
  1144. Arguments:
  1145. Root - the root of the tree
  1146. --*/
  1147. {
  1148. INT32 i, k;
  1149. UINT32 Cum;
  1150. for (i = 0; i <= 16; i++) {
  1151. mLenCnt[i] = 0;
  1152. }
  1153. CountLen(Root);
  1154. //
  1155. // Adjust the length count array so that
  1156. // no code will be generated longer than its designated length
  1157. //
  1158. Cum = 0;
  1159. for (i = 16; i > 0; i--) {
  1160. Cum += mLenCnt[i] << (16 - i);
  1161. }
  1162. while (Cum != (1U << 16)) {
  1163. mLenCnt[16]--;
  1164. for (i = 15; i > 0; i--) {
  1165. if (mLenCnt[i] != 0) {
  1166. mLenCnt[i]--;
  1167. mLenCnt[i+1] += 2;
  1168. break;
  1169. }
  1170. }
  1171. Cum--;
  1172. }
  1173. for (i = 16; i > 0; i--) {
  1174. k = mLenCnt[i];
  1175. while (--k >= 0) {
  1176. mLen[*mSortPtr++] = (UINT8)i;
  1177. }
  1178. }
  1179. }
  1180. STATIC
  1181. VOID
  1182. DownHeap (
  1183. IN INT32 i
  1184. )
  1185. {
  1186. INT32 j, k;
  1187. //
  1188. // priority queue: send i-th entry down heap
  1189. //
  1190. k = mHeap[i];
  1191. while ((j = 2 * i) <= mHeapSize) {
  1192. if (j < mHeapSize && mFreq[mHeap[j]] > mFreq[mHeap[j + 1]]) {
  1193. j++;
  1194. }
  1195. if (mFreq[k] <= mFreq[mHeap[j]]) {
  1196. break;
  1197. }
  1198. mHeap[i] = mHeap[j];
  1199. i = j;
  1200. }
  1201. mHeap[i] = (INT16)k;
  1202. }
  1203. STATIC
  1204. VOID
  1205. MakeCode (
  1206. IN INT32 n,
  1207. IN UINT8 Len[],
  1208. OUT UINT16 Code[]
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. Assign code to each symbol based on the code length array
  1213. Arguments:
  1214. n - number of symbols
  1215. Len - the code length array
  1216. Code - stores codes for each symbol
  1217. Returns: (VOID)
  1218. --*/
  1219. {
  1220. INT32 i;
  1221. UINT16 Start[18];
  1222. Start[1] = 0;
  1223. for (i = 1; i <= 16; i++) {
  1224. Start[i + 1] = (UINT16)((Start[i] + mLenCnt[i]) << 1);
  1225. }
  1226. for (i = 0; i < n; i++) {
  1227. Code[i] = Start[Len[i]]++;
  1228. }
  1229. }
  1230. STATIC
  1231. INT32
  1232. MakeTree (
  1233. IN INT32 NParm,
  1234. IN UINT16 FreqParm[],
  1235. OUT UINT8 LenParm[],
  1236. OUT UINT16 CodeParm[]
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. Generates Huffman codes given a frequency distribution of symbols
  1241. Arguments:
  1242. NParm - number of symbols
  1243. FreqParm - frequency of each symbol
  1244. LenParm - code length for each symbol
  1245. CodeParm - code for each symbol
  1246. Returns:
  1247. Root of the Huffman tree.
  1248. --*/
  1249. {
  1250. INT32 i, j, k, Avail;
  1251. //
  1252. // make tree, calculate len[], return root
  1253. //
  1254. mN = NParm;
  1255. mFreq = FreqParm;
  1256. mLen = LenParm;
  1257. Avail = mN;
  1258. mHeapSize = 0;
  1259. mHeap[1] = 0;
  1260. for (i = 0; i < mN; i++) {
  1261. mLen[i] = 0;
  1262. if (mFreq[i]) {
  1263. mHeap[++mHeapSize] = (INT16)i;
  1264. }
  1265. }
  1266. if (mHeapSize < 2) {
  1267. CodeParm[mHeap[1]] = 0;
  1268. return mHeap[1];
  1269. }
  1270. for (i = mHeapSize / 2; i >= 1; i--) {
  1271. //
  1272. // make priority queue
  1273. //
  1274. DownHeap(i);
  1275. }
  1276. mSortPtr = CodeParm;
  1277. do {
  1278. i = mHeap[1];
  1279. if (i < mN) {
  1280. *mSortPtr++ = (UINT16)i;
  1281. }
  1282. mHeap[1] = mHeap[mHeapSize--];
  1283. DownHeap(1);
  1284. j = mHeap[1];
  1285. if (j < mN) {
  1286. *mSortPtr++ = (UINT16)j;
  1287. }
  1288. k = Avail++;
  1289. mFreq[k] = (UINT16)(mFreq[i] + mFreq[j]);
  1290. mHeap[1] = (INT16)k;
  1291. DownHeap(1);
  1292. mLeft[k] = (UINT16)i;
  1293. mRight[k] = (UINT16)j;
  1294. } while (mHeapSize > 1);
  1295. mSortPtr = CodeParm;
  1296. MakeLen(k);
  1297. MakeCode(NParm, LenParm, CodeParm);
  1298. //
  1299. // return root
  1300. //
  1301. return k;
  1302. }
  1303. #ifndef FOR_LIBRARY
  1304. int main(int argc, char *argv[])
  1305. {
  1306. char *progname;
  1307. int retval = 1;
  1308. progname = strrchr(argv[0], '/');
  1309. if (progname)
  1310. progname++;
  1311. else
  1312. progname = argv[0];
  1313. if (argc != 3)
  1314. {
  1315. fprintf(stderr, "\nUsage: %s INFILE OUTFILE\n\n", progname);
  1316. exit(1);
  1317. }
  1318. char *infile = argv[1];
  1319. char *outfile = argv[2];
  1320. struct stat istat;
  1321. if (0 != stat(infile, &istat)) {
  1322. fprintf(stderr, "%s: can't stat %s: %s\n",
  1323. progname,
  1324. infile,
  1325. strerror(errno));
  1326. exit(1);
  1327. }
  1328. uint32_t isize = (uint32_t)istat.st_size;
  1329. printf("%s is %d bytes\n", infile, isize);
  1330. FILE *ifp = fopen(infile, "rb");
  1331. if (!ifp)
  1332. {
  1333. fprintf(stderr, "%s: can't read %s: %s\n",
  1334. progname,
  1335. infile,
  1336. strerror(errno));
  1337. exit(1);
  1338. }
  1339. // read input file into buffer
  1340. uint8_t *ibuf = malloc(isize);
  1341. if (!ibuf) {
  1342. fprintf(stderr, "%s: can't malloc %d bytes: %s\n",
  1343. progname,
  1344. isize,
  1345. strerror(errno));
  1346. goto done1;
  1347. }
  1348. if (1 != fread(ibuf, isize, 1, ifp)) {
  1349. fprintf(stderr, "%s: can't read %d bytes: %s\n",
  1350. progname,
  1351. isize,
  1352. strerror(errno));
  1353. goto done2;
  1354. }
  1355. // assume compression will actually work
  1356. uint32_t osize = isize;
  1357. uint8_t *obuf = malloc(osize);
  1358. if (!obuf) {
  1359. fprintf(stderr, "%s: can't allocate %d bytes: %s\n",
  1360. progname,
  1361. osize,
  1362. strerror(errno));
  1363. goto done2;
  1364. }
  1365. // try it and see
  1366. EFI_STATUS r = EfiCompress(ibuf, isize, obuf, &osize);
  1367. if (r != EFI_SUCCESS) {
  1368. fprintf(stderr, "%s: compression failed with code %d\n",
  1369. progname,
  1370. r);
  1371. goto done3;
  1372. }
  1373. printf("Compressed %d bytes to %d bytes\n", isize, osize);
  1374. // Write it out
  1375. FILE *ofp = fopen(outfile, "wb");
  1376. if (!ofp)
  1377. {
  1378. fprintf(stderr, "%s: can't open %s for writing: %s\n",
  1379. progname,
  1380. outfile,
  1381. strerror(errno));
  1382. goto done3;
  1383. }
  1384. if (1 != fwrite(obuf, osize, 1, ofp)) {
  1385. fprintf(stderr, "%s: can't write %d bytes: %s\n",
  1386. progname,
  1387. osize,
  1388. strerror(errno));
  1389. goto done4;
  1390. }
  1391. printf("wrote %d bytes to %s\n", osize, outfile);
  1392. retval = 0;
  1393. done4:
  1394. fclose(ofp);
  1395. done3:
  1396. free(obuf);
  1397. done2:
  1398. free(ibuf);
  1399. done1:
  1400. fclose(ifp);
  1401. return retval;
  1402. }
  1403. #endif // FOR_LIBRARY