home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / pclcomp / part02 < prev    next >
Text File  |  1992-05-23  |  35KB  |  1,310 lines

  1. Newsgroups: comp.sources.misc
  2. From: tony@sdd.hp.com (Tony Parkhurst)
  3. Subject:  v30i018:  pclcomp - HP-PCL Compression Filter, Part02/02
  4. Message-ID: <1992May23.181623.19262@sparky.imd.sterling.com>
  5. X-Md4-Signature: b1595abd728d7f6e5225722881b29620
  6. Date: Sat, 23 May 1992 18:16:23 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tony@sdd.hp.com (Tony Parkhurst)
  10. Posting-number: Volume 30, Issue 18
  11. Archive-name: pclcomp/part02
  12. Environment: LaserJet
  13. Supersedes: pclcomp: Volume 25, Issue 10-11
  14.  
  15. #!/bin/sh
  16. # this is PP.02 (part 2 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file pclcomp.c continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 2; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping pclcomp.c'
  34. else
  35. echo 'x - continuing file pclcomp.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'pclcomp.c' &&
  37. **  fourth plane as <esc>*b0W to terminate the row, instead of the recommended
  38. **  'W' as the 3rd plane.  This routine handles the extra without disturbing
  39. **  the mode 3 seed rows.
  40. **
  41. **  In the future, this routine could be used to strip out the 4th plane.
  42. */
  43. X
  44. Process_extra(bytes, terminator)
  45. int    bytes;
  46. char    terminator;
  47. {
  48. X    int  i;
  49. X
  50. X    /* toss any excess data */
  51. X
  52. X    for(i = 0; i < bytes; i++)
  53. X       getchar();
  54. X
  55. X    /* last plane? force move down to next row */
  56. X
  57. X    if(terminator == 'W')
  58. X    {
  59. X        /* <esc>*b has already been output */
  60. X        printf("0W");
  61. X
  62. X        firstrow = FALSE;        /* not on first row anymore */
  63. X
  64. X    }
  65. X
  66. }
  67. X
  68. /*
  69. **  ChangeMode() simply outputs the sequence to change compression modes.
  70. */
  71. X
  72. ChangeMode(newmode)
  73. int newmode;
  74. {
  75. X    /*
  76. X    **  <esc>*b have already been output.
  77. X    **  terminator is 'm' instead of 'M' since will be followed by 'W'
  78. X    */
  79. X    printf("%1dm", newmode);
  80. X    outmode = newmode;
  81. }
  82. X
  83. X
  84. /*-----------------------------------------------------------------------*\
  85. X |                                                                       |
  86. X |  Function Name: Uncompress_0                                       |
  87. X |                                                                       |
  88. X |  Description:                                                         |
  89. X |                                                                       |
  90. X |  This is the routine that handles a Mode 0 graphics block transfer    |
  91. X |  to the Formatter Module.                                             |
  92. X |                                                                       |
  93. \*-----------------------------------------------------------------------*/
  94. X
  95. /* FUNCTION */
  96. X
  97. Uncompress_0(input_bytes, output_bytes, address)
  98. X
  99. unsigned int
  100. X   input_bytes,                 /* Count of bytes to be read. */
  101. X   output_bytes;                /* Count of bytes to be stored. */
  102. X
  103. unsigned char
  104. X   *address;                    /* Pointer to where to store bytes. */
  105. X
  106. {
  107. X   /* LOCAL VARIABLES */
  108. X
  109. X   unsigned char
  110. X      *store_ptr;               /* Pointer to where to store the byte. */
  111. X
  112. X   unsigned int
  113. X      read_bytes,               /* Local copy of input_bytes. */
  114. X      write_bytes;              /* Local copy of output_bytes. */
  115. X
  116. X   /* CODE */
  117. X
  118. X   /* Initialize the local variables. */
  119. X
  120. X   read_bytes = input_bytes;
  121. X   write_bytes = output_bytes;
  122. X   store_ptr = address;
  123. X   
  124. X
  125. X   /* transfer the lesser of available bytes or available room */
  126. X
  127. X     Transfer_Block( MIN(write_bytes,read_bytes), store_ptr);
  128. X
  129. X   /* now zero fill or throw excess data away */
  130. X
  131. X   if ( read_bytes > write_bytes )
  132. X      Discard_Block(read_bytes - write_bytes);        /* throw excess */
  133. X   else {
  134. X      store_ptr += read_bytes;                /* adjust pointer */
  135. X      write_bytes -= read_bytes;            /* zero fill count */
  136. X
  137. X      memset(store_ptr, 0, write_bytes);
  138. X   }
  139. X
  140. X   return ( input_bytes );
  141. }
  142. X
  143. X
  144. /*-----------------------------------------------------------------------*\
  145. X |                                                                       |
  146. X |  Function Name: Uncompress_1                                       |
  147. X |                                                                       |
  148. X |  Description:                                                         |
  149. X |                                                                       |
  150. X |  This is the routine that handles a Mode 1 graphics block transfer    |
  151. X |  to the Formatter Module.  Mode 1 graphics is a compacted mode.       |
  152. X |  The data in Mode 1 is in pairs.  The first byte is a replicate       |
  153. X |  count and the second byte is the data.  The data byte is stored      |
  154. X |  then replicated the replicate count.  Therefore a replicate count    |
  155. X |  of 0 means the data byte is stored once.  The input byte count       |
  156. X |  must be an even amount for the data to be in byte pairs.             |
  157. X |                                                                       |
  158. \*-----------------------------------------------------------------------*/
  159. X
  160. /* FUNCTION */
  161. X
  162. Uncompress_1(input_bytes, output_bytes, address)
  163. X
  164. unsigned int
  165. X   input_bytes,                 /* Count of bytes to be read. */
  166. X   output_bytes;                /* Count of bytes to be stored. */
  167. X
  168. unsigned char
  169. X   *address;                    /* Pointer to where to store bytes. */
  170. X
  171. {
  172. X   /* LOCAL VARIABLES */
  173. X
  174. X   unsigned char
  175. X      *store_ptr,               /* Pointer to where to store the byte. */
  176. X      input_char;               /* Byte to be replicated. */
  177. X
  178. X   unsigned int
  179. X      read_bytes,               /* Local copy of input_bytes. */
  180. X      write_bytes;              /* Local copy of output_bytes. */
  181. X
  182. X   int
  183. X      replicate_count;          /* Number of times to replicate data. */
  184. X
  185. X   /* CODE */
  186. X
  187. X   /* Initialize the local variables. */
  188. X
  189. X   read_bytes = input_bytes;
  190. X   write_bytes = output_bytes;
  191. X   store_ptr = address;
  192. X   
  193. X   /* Check for an even input count. */
  194. X
  195. X   if ((read_bytes % 2) == 0)
  196. X   {
  197. X      /* Even so input data is in pairs as required. So store the data. */
  198. X   
  199. X      while ((read_bytes != 0) && (write_bytes != 0))
  200. X      {
  201. X         /* First get the replicate count and the byte to store. */
  202. X
  203. X         replicate_count = (unsigned char) Get_Character();
  204. X         input_char = Get_Character();
  205. X         read_bytes -= 2;
  206. X      
  207. X         /* Since write_bytes was 0 there is room to store the byte. */
  208. X
  209. X         *store_ptr++ = input_char;
  210. X         write_bytes--;
  211. X         
  212. X         /* Now make sure there is room for the replicated data. */
  213. X
  214. X         if (replicate_count > write_bytes)
  215. X         {
  216. X            /* Too much so limit to the room available. */
  217. X
  218. X            replicate_count = write_bytes;
  219. X         }
  220. X            
  221. X         /* Update the amount to be written. */
  222. X
  223. X         write_bytes -= replicate_count;
  224. X
  225. X         /* Then replicate it. */
  226. X
  227. X         while (replicate_count != 0)
  228. X         {
  229. X            /* Store the byte the decrement the count. */
  230. X
  231. X            *store_ptr++ = input_char;
  232. X         
  233. X            replicate_count--;
  234. X         }
  235. X      }
  236. X
  237. X   }
  238. X   /* Discard any left over input. */
  239. X    /* OR */
  240. X   /* Discard all of the input data as odd byte count. */
  241. X
  242. X   Discard_Block(read_bytes);
  243. X
  244. X   read_bytes = store_ptr - address;  /* how much was done? */
  245. X
  246. X   /* zero fill if needed */
  247. X   memset(store_ptr, 0, write_bytes);
  248. X         
  249. X   return(read_bytes);
  250. }
  251. X
  252. X
  253. /*-----------------------------------------------------------------------*\
  254. X |                                                                       |
  255. X |  Function Name: Uncompress_2                                       |
  256. X |                                                                       |
  257. X |  Description:                                                         |
  258. X |                                                                       |
  259. X |  This is the routine that handles a Mode 2 graphics block transfer    |
  260. X |  to the Formatter Module.  Mode 2 graphics is a compacted mode.       |
  261. X |  The data in Mode 2 is of one of two types.  The first type is a      |
  262. X |  class type and the second type is a data type.  The class type is    |
  263. X |  a single byte which is a combination of replicate count and a sub    |
  264. X |  mode.  There are two sub modes within mode 2, sub mode 0 and sub     |
  265. X |  mode 1.  These sub modes are flagged by the MSB of the class type    |
  266. X |  byte.  If the MSB = 0 then the replicate count is the value of the   |
  267. X |  class type byte.  In sub mode 0 the replicate count ranges from 1    |
  268. X |  to 127.  In sub mode 0 the next byte and then the replicate count    |
  269. X |  of bytes are of the data type and stored.  If the MSB = 1 then the   |
  270. X |  sub mode is 1 and the replicate count is the negative value of the   |
  271. X |  class type.  In sub mode 1 the replicate count is stored in 2s       |
  272. X |  compliment form and ranges from -1 to -127.  In sub mode 1 the       |
  273. X |  next byte is of the data type and is stored.  That data byte is      |
  274. X |  then replicated and stored the replicate count.  If the class type   |
  275. X |  byte is 128 then there is no data type byte.                         |
  276. X |                                                                       |
  277. \*-----------------------------------------------------------------------*/
  278. X
  279. /* FUNCTION */
  280. X
  281. Uncompress_2(input_bytes, output_bytes, address)
  282. X
  283. unsigned int
  284. X   input_bytes,                 /* Count of bytes to be read. */
  285. X   output_bytes;                /* Count of bytes to be stored. */
  286. X
  287. unsigned char
  288. X   *address;                    /* Pointer to where to store bytes. */
  289. X
  290. {
  291. X   /* LOCAL VARIABLES */
  292. X
  293. X   unsigned char
  294. X      *store_ptr,               /* Pointer to where to store the byte. */
  295. X      input_char,               /* Byte to be replicated. */
  296. X      sub_mode;                 /* Flag if sub mode is 0 or 1. */
  297. X
  298. X   unsigned int
  299. X      read_bytes,               /* Local copy of input_bytes. */
  300. X      write_bytes;              /* Local copy of output_bytes. */
  301. X
  302. X   int
  303. X      replicate_count;          /* Number of times to replicate data. */
  304. X
  305. X   /* CODE */
  306. X
  307. X   /* Initialize the local variables. */
  308. X
  309. X   read_bytes = input_bytes;
  310. X   write_bytes = output_bytes;
  311. X   store_ptr = address;
  312. X   
  313. X   while ((read_bytes > 1) && (write_bytes != 0))
  314. X   {
  315. X      /* First get the class type byte and the first data type byte. */
  316. X
  317. X      replicate_count = Get_Character();
  318. X
  319. X      /* First check that this not an ignore class type. */
  320. X
  321. X      if (replicate_count != 128)
  322. X      {
  323. X         /* Not ignore so get the data class byte. */
  324. X
  325. X         input_char = Get_Character();
  326. X         read_bytes -= 2;
  327. X         
  328. X        /* Since write_bytes wasn't 0 there is room to store the byte. */
  329. X
  330. X         *store_ptr++ = input_char;
  331. X         write_bytes--;
  332. X
  333. X         /* Determine the sub mode. */
  334. X   
  335. X         if (replicate_count > 128)
  336. X         {
  337. X            /* Sub mode 1. */
  338. X   
  339. X            sub_mode = 1;
  340. X            /* replicate count was unsigned char */
  341. X            replicate_count = 256 - replicate_count;
  342. X         }
  343. X         else
  344. X         {
  345. X            /* Sub mode 0. */
  346. X   
  347. X            sub_mode = 0;
  348. X
  349. X            /* See if there is enoungh input left for the data byte count. */
  350. X
  351. X            if (replicate_count > read_bytes)
  352. X            {
  353. X               /* Too many data bytes so limit to the input left. */
  354. X
  355. X               replicate_count = read_bytes;
  356. X            }
  357. X         }
  358. X            
  359. X         /* Now make sure there is room for the replicated data. */
  360. X   
  361. X         if (replicate_count > write_bytes)
  362. X         {
  363. X            /* Too much so limit to the room available. */
  364. X   
  365. X            replicate_count = write_bytes;
  366. X         }
  367. X               
  368. X         /* Update the amount to be written. */
  369. X   
  370. X         write_bytes -= replicate_count;
  371. X   
  372. X         /* Then replicate it. */
  373. X   
  374. X         if (sub_mode == 0)
  375. X         {
  376. X            /* Sub mode 0 so get the replicate count of data bytes. */
  377. X   
  378. X              Transfer_Block(replicate_count, store_ptr);
  379. X
  380. X            read_bytes -= replicate_count;
  381. X            
  382. X            /* Find the last byte stored. */
  383. X   
  384. X            store_ptr += replicate_count;
  385. X         }
  386. X         else
  387. X         {
  388. X            /* Sub mode 1 so just duplicate the original byte. */
  389. X   
  390. X            while (replicate_count != 0)
  391. X            {
  392. X               /* Store the byte the decrement the count. */
  393. X   
  394. X               *store_ptr++ = input_char;
  395. X            
  396. X               replicate_count--;
  397. X            }
  398. X         }
  399. X      }
  400. X      else
  401. X      {
  402. X         /* Ignore class so don't get the data class byte. */
  403. X
  404. X         read_bytes--;
  405. X      }
  406. X   }
  407. X
  408. X   /* Now discard any left over input. */
  409. X
  410. X   Discard_Block(read_bytes);
  411. X
  412. X   read_bytes = store_ptr - address;
  413. X
  414. X   /* zero fill if needed */
  415. X   memset(store_ptr, 0, write_bytes);
  416. X         
  417. X   
  418. X   return(read_bytes);
  419. }
  420. X
  421. X
  422. /*-----------------------------------------------------------------------*\
  423. X |                                                                       |
  424. X |  Function Name: Uncompress_3                                       |
  425. X |                                                                       |
  426. X |  Description:                                                         |
  427. X |                                                                       |
  428. X |  This is the routine that handles a Mode 3 graphics block transfer    |
  429. X |  to the Formatter Module.  Mode 3 graphics is a compacted mode.       |
  430. X |  Mode 3 data is a difference from one row to the next.  In order to   |
  431. X |  work, each row must be saved to be a seed for the next.  This        |
  432. X |  mode is used in conjuction with other compaction modes when the      |
  433. X |  data remains fairly constant between pairs of rows.                  |
  434. X |  The data is in the form:                                             |
  435. X |  <command byte>[<optional offset bytes>]<1 to 8 replacement bytes>    |
  436. X |  The command byte is in the form:                                     |
  437. X |    Bits 5-7: Number of bytes to replace (1 - 8)                       |
  438. X |    Bits 0-4: Relative offset from last byte.                          |
  439. X |       (If the offset is 31, then add the following bytes for offset   |
  440. X |       until an offset byte of less then 255 (but inclusive)           |
  441. X |                                                                       |
  442. \*-----------------------------------------------------------------------*/
  443. X
  444. /* FUNCTION */
  445. X
  446. Uncompress_3(input_bytes, output_bytes, address)
  447. X
  448. unsigned int
  449. X   input_bytes,                 /* Count of bytes to be read. */
  450. X   output_bytes;                /* Count of bytes to be stored. */
  451. X
  452. unsigned char
  453. X   *address;                    /* Pointer to where to store bytes. */
  454. X
  455. {
  456. X    /* LOCAL VARIABLES */
  457. X
  458. X    unsigned char
  459. X    *store_ptr;             /* Pointer to where to store the byte. */
  460. X
  461. X    unsigned int
  462. X    read_bytes,             /* Local copy of input_bytes. */
  463. X    write_bytes;            /* Local copy of output_bytes. */
  464. X
  465. X    unsigned int
  466. X    replace,        /* number of bytes to replace, 1-8 */
  467. X    offset;            /* relative offset */
  468. X
  469. X    unsigned char    command;
  470. X
  471. X    /* CODE */
  472. X
  473. X    /* Initialize the local variables. */
  474. X
  475. X    read_bytes = input_bytes;
  476. X    write_bytes = output_bytes;
  477. X    store_ptr = address;
  478. X
  479. X    /* 
  480. X    **  read_bytes has to be at least 2 to be valid
  481. X    */
  482. X
  483. X    while ( read_bytes > 1 && write_bytes > 0 )
  484. X    {
  485. X
  486. X        /* start by getting the command byte */
  487. X
  488. X        command = Get_Character();
  489. X
  490. X            replace = (command >> 5) + 1;
  491. X            offset = command & 0x1f;
  492. X
  493. X        read_bytes--;
  494. X
  495. X        /*
  496. X        **  Sometimes offsets go past the end.  If so, bail.
  497. X        */
  498. X
  499. X        if ( offset >= write_bytes )
  500. X            break;
  501. X
  502. X        write_bytes -= offset;
  503. X        store_ptr += offset;
  504. X
  505. X        /*
  506. X        **  If the first offset value is 31, then we must
  507. X        **  get more offsets until we encounter a byte value
  508. X        **  less than 255 (even if it's 0).
  509. X        */
  510. X
  511. X        if ( offset == 31 )        /* get more offsets */
  512. X
  513. X            do{
  514. X                offset = Get_Character();
  515. X
  516. X                read_bytes--;
  517. X
  518. X                /*
  519. X                **  Check for pre-mature finish
  520. X                */
  521. X
  522. X                if ( read_bytes == 0 )
  523. X                    return;
  524. X
  525. X                /*
  526. X                **  Check for excessive offset.
  527. X                */
  528. X
  529. X                if ( offset >= write_bytes )
  530. X                {
  531. X                    /*
  532. X                    **  Resetting write_bytes is needed
  533. X                    **  to get out of outer loop so
  534. X                    **  that the call to Discard_Block()
  535. X                    **  is made at the end.
  536. X                    */
  537. X
  538. X                    write_bytes = 0;
  539. X                    break;
  540. X                }
  541. X
  542. X                write_bytes -= offset;
  543. X                store_ptr += offset;
  544. X
  545. X            } while (offset == 255);    /* 255 = keep going */
  546. X
  547. X        /* now do the byte replacement */
  548. X
  549. X        while ( replace-- && write_bytes > 0 && read_bytes > 0 )
  550. X        {
  551. X            *store_ptr++ = Get_Character();
  552. X            read_bytes--;
  553. X            write_bytes--;
  554. X        }
  555. X    }
  556. X   
  557. X    /*
  558. X    **  Don't do any zero fill with mode 3,
  559. X    **  and discard any leftover input.
  560. X    */
  561. X
  562. X    Discard_Block(read_bytes);
  563. X
  564. X    return;
  565. }
  566. X
  567. X
  568. Discard_Block(count)
  569. unsigned int count;
  570. {
  571. X    while ( count-- )
  572. X        getchar();
  573. }
  574. X
  575. Transfer_Block( count, dest )
  576. unsigned int count;
  577. unsigned char *dest;
  578. {
  579. X    fread(dest, 1, count, stdin);
  580. }
  581. X
  582. X
  583. /*
  584. **  Compress_0() does mode 0 compression (which is a no compression).
  585. */
  586. X
  587. Compress_0(src, dest, count)
  588. unsigned char *src, *dest;
  589. int count;
  590. {
  591. X    memcpy(dest, src, count);
  592. X
  593. X    if ( zerostrip )
  594. X        while ( count && dest[count-1] == 0 )
  595. X            count--;
  596. X
  597. X    return(count);
  598. X
  599. }
  600. X
  601. X
  602. X
  603. /*
  604. ******************************************************************************
  605. **
  606. **       Compress_1() does PCL compression mode 1 on the data. 
  607. **       This mode is run length encoding.
  608. **
  609. **       Given an input byte count of n, then the worst case output size
  610. **       would be  2 * n.
  611. **
  612. ******************************************************************************
  613. */
  614. X
  615. Compress_1(src, dest, count)
  616. unsigned char *src, *dest;
  617. register int count;
  618. {
  619. X    unsigned char *outptr = dest, *inptr = src;
  620. X
  621. X    unsigned char data;        /* data values to match */
  622. X
  623. X    unsigned char temp;
  624. X
  625. X    int    repcount;        /* repeat count */
  626. X
  627. X
  628. X    /*
  629. X    **  "count" is the number of bytes in "src" to compress
  630. X    **  into "dest".
  631. X    */
  632. X
  633. X    while ( count )
  634. X    {
  635. X        data = *inptr++;    /* get value to work with */
  636. X        count--;
  637. X
  638. X        repcount = 0;        /* no repeats yet */
  639. X
  640. X        /*
  641. X        **  Look for successive bytes that match "data".
  642. X        */
  643. X
  644. X        while ( count && *inptr == data )
  645. X        {
  646. X            repcount++;
  647. X            inptr++;
  648. X            count--;
  649. X        }
  650. X
  651. X        /*
  652. X        **  Now if we are out of data (count == 0), then
  653. X        **  if the repeated byte was zero, then we can ignore it
  654. X        **  unless the user disabled zero stripping.
  655. X        */
  656. X
  657. X        if ( count == 0 && data == 0 && zerostrip )
  658. X            break;                    /* done */
  659. X
  660. X        /*
  661. X        **  Now output the repeat count and the value.
  662. X        **
  663. X        **  If the repeat count exceeds 255, then we must send
  664. X        **  more repeat-value pairs.
  665. X        **
  666. X        **  Each time thru the loop, repcount needs to be decremented
  667. X        **  to keep in sync.  That is, if repcount == 256, then the
  668. X        **  first time thru the loop, <255> <data> are output, then
  669. X        **  repcount is now 1.  So the next time thru the loop, 
  670. X        **  repcount needs to be adjusted to 0 so that the next pair
  671. X        **  is <0> <data>.  Thus, 1 data plus 255 repeats of data
  672. X        **  plus 1 data + 0 repeats of data ==> 257 total bytes
  673. X        **  of "data", which is what a repcount of 256 means.
  674. X        */ 
  675. X
  676. X        do
  677. X        {
  678. X            temp = MIN(repcount, 255);
  679. X
  680. X            *outptr++ = temp;
  681. X
  682. X            repcount -= temp;
  683. X
  684. X            *outptr++ = data;
  685. X
  686. X        } while ( repcount-- );
  687. X    }
  688. X
  689. X    return ( outptr - dest );    /* size of compressed data */
  690. }
  691. X
  692. X
  693. /*
  694. ******************************************************************************
  695. **
  696. **       Compress_2() does PCL compression mode 2 on the data. 
  697. **       This mode is a combination of modes 0 and 1.
  698. **
  699. **       Given an input byte count of n, then the worst case output size
  700. **       would be  n + (n + 127)/128.
  701. **
  702. ******************************************************************************
  703. */
  704. X
  705. Compress_2(src, dest, count)
  706. unsigned char *src, *dest;
  707. register int count;
  708. {
  709. X    unsigned char    *outptr, *inptr;
  710. X    unsigned char    *saveptr;
  711. X
  712. X    unsigned char    data;            /* data byte */
  713. X    unsigned char    lastbyte;        /* last byte */
  714. X    int        repcount;        /* repeat count */
  715. X    int        litcount;        /* literal count */
  716. X
  717. X    /*
  718. X    **  src points to the input data.
  719. X    **  dest points to the output buffer.
  720. X    **  count is the number of input bytes.
  721. X    */
  722. X
  723. X    inptr = src;
  724. X    outptr = dest;
  725. X
  726. X    /*
  727. X    **  Start loop thru data.  Check for possible repeat at beginning.
  728. X    */
  729. X
  730. X    while ( count )
  731. X    {
  732. X        data = *inptr++;    /* get value to work with */
  733. X        count--;
  734. X
  735. X        repcount = 0;        /* no repeat count yet */
  736. X
  737. X
  738. X        /* 
  739. X        **  Check for repeat, since we are not in the middle
  740. X        **  of a literal run, it does not have to be more than
  741. X        **  two bytes of similar data.
  742. X        */
  743. X
  744. X        while ( count && *inptr == data )
  745. X        {
  746. X            repcount++;
  747. X            inptr++;
  748. X            count--;
  749. X        }
  750. X
  751. X        /*
  752. X        **  Now, if we are out of data (count == 0), then
  753. X        **  if the repeated byte was zero, then ignore it
  754. X        **  completely (don't bother outputing the trailing zeros).
  755. X        **
  756. X        **  To always strip zero's, simply remove the "zerostrip"
  757. X        **  from the test.
  758. X        */
  759. X
  760. X        if ( count == 0 && data == 0 && zerostrip)
  761. X            break;            /* done */
  762. X
  763. X
  764. X        /*
  765. X        **  If there was a repeat (repcount > 0), then we
  766. X        **  can output the command here, otherwise, we
  767. X        **  need to go into literal run mode.
  768. X        **
  769. X        **  Note:  This is a while loop because the repeat count
  770. X        **  may actually be greater than 127.
  771. X        */
  772. X
  773. X        if ( repcount >= 1 )        /* repeat mode */
  774. X        {
  775. X            while (repcount > 127)
  776. X            {
  777. X                *outptr++ = 129;        /* count 127 */
  778. X                *outptr++ = data;        /* value */
  779. X                repcount-= 128;            /* offset */
  780. X            }
  781. X
  782. X            if (repcount > 0)
  783. X            {
  784. X                *outptr++ = 256 - repcount;    /* count */
  785. X                *outptr++ = data;        /* value */
  786. X
  787. X                /*
  788. X                **  Now pop to the top of the loop 
  789. X                **  looking for more repeat counts.
  790. X                */
  791. X
  792. X                continue;            /* top of loop */
  793. X            }
  794. X
  795. X            /*
  796. X            **  Special case:  If we have arrived at this point,
  797. X            **  then repcount is now equal to 0.  This means
  798. X            **  that when we entered this section, repcount
  799. X            **  was a multiple of 128 (i.e. 128 :-).
  800. X            **
  801. X            **  This means that there were 129 identical bytes,
  802. X            **  so the output does a replicate of 127 which
  803. X            **  gives 128 bytes, and we now have one byte left
  804. X            **  over which should NOT be output as a repeat
  805. X            **  run, rather it should be merged into the following
  806. X            **  literal run (if it exists).
  807. X            **
  808. X            **  So, we will simply fall thru to the next section
  809. X            **  of code which assumes that we are working on 
  810. X            **  a literal run.
  811. X            */
  812. X
  813. X        }
  814. X
  815. X        /*
  816. X        **  Literal run:  At this point, the current data byte
  817. X        **  does NOT match the following byte.  We will transfer
  818. X        **  these non-identical bytes until:
  819. X        **
  820. X        **       1)  we run out of input data (count == 0).
  821. X        **       2)  we run out of room in this output block (128)
  822. X        **       3)  we come across a value which occurs at least
  823. X        **           three times in a row.  A value occuring only
  824. X        **           twice in a row does NOT justify dropping
  825. X        **           out of a literal run.
  826. X        **
  827. X        **  Special case:  If we run out of room in the output block
  828. X        **  (which is 128 bytes), the last two values are the same,
  829. X        **  AND there is more input, it makes sense to restart
  830. X        **  the repeat detector in case the following bytes are
  831. X        **  repeats of the two.  A simple check of the following
  832. X        **  byte will determine this.
  833. X        **  (This case falls out with the test for triples below).
  834. X        **
  835. X        **  Special case:  If we run out of room in the output block
  836. X        **  (which is 128 bytes), the last value is the same as
  837. X        **  the next one on the input, then it is better to let
  838. X        **  that byte be used in a possible replicate run following
  839. X        **  the literal run.  If the last byte matches ONLY the
  840. X        **  following byte, (and not the one after that,) it is
  841. X        **  a wash, but for best results, we will test the
  842. X        **  following two bytes.
  843. X        **
  844. X        */
  845. X
  846. X        litcount = 0;
  847. X        saveptr = outptr++;    /* save location of the command byte */
  848. X
  849. X        *outptr++ = data;    /* save the first byte. */
  850. X
  851. X        lastbyte = data;    /* remember for testing */
  852. X
  853. X        while ( count && litcount < 127 )
  854. X        {
  855. X            data = *inptr++;
  856. X            count--;
  857. X            litcount++;
  858. X            *outptr++ = data;
  859. X
  860. X            /*
  861. X            **  Test to see if this byte matched the last one.
  862. X            **  If so, check the next one for a triple.
  863. X            */
  864. X
  865. X            if ( lastbyte == data && count && *inptr == data )
  866. X            {
  867. X                /*
  868. X                **  We have a triple, adjust accordingly.
  869. X                **
  870. X                **  Add two bytes back onto the input.
  871. X                */
  872. X
  873. X                count += 2;
  874. X                inptr -= 2;
  875. X                outptr -= 2;
  876. X                litcount -= 2;
  877. X
  878. X                break;        /* out of loop */
  879. X            }
  880. X
  881. X            lastbyte = data;    /* save data byte */
  882. X        }
  883. X
  884. X        /*
  885. X        **  Check the special case number 2 above.
  886. X        */
  887. X
  888. X        if ( litcount == 127  &&  count > 1  &&  data == *inptr
  889. X            &&  data == inptr[1] )
  890. X        {
  891. X            /*  Restore the last byte to the input stream */
  892. X
  893. X            count += 1;
  894. X            inptr -= 1;
  895. X            outptr -= 1;
  896. X            litcount -= 1;
  897. X        }
  898. X
  899. X
  900. X        /*
  901. X        **  Save the literal run count.
  902. X        */
  903. X
  904. X        *saveptr = litcount;
  905. X
  906. X        /*
  907. X        **  Now go back to the top and look for repeats.
  908. X        */
  909. X    }
  910. X
  911. X    count = outptr - dest;        /* for return value */
  912. X
  913. X    return ( count );
  914. }
  915. X
  916. X
  917. X
  918. /*
  919. ******************************************************************************
  920. **
  921. **       Compress_3() does PCL compression mode 3 on the data. 
  922. **       This mode is delta row encoding.
  923. **
  924. **       Given an input byte count of n, then the worst case output size
  925. **       would be  n + (n + 7)/8
  926. **
  927. ******************************************************************************
  928. */
  929. X
  930. Compress_3(seed, new, dest, count)
  931. unsigned char *seed, *new, *dest;
  932. register int count;
  933. {
  934. X    unsigned char *sptr=seed, *nptr=new, *dptr=dest;
  935. X    unsigned char *saveptr;
  936. X
  937. X    int    delta, xfer;
  938. X    unsigned char    command;
  939. X
  940. X
  941. X    /*
  942. X    **  "count" is the number of bytes of data in "new" that need to
  943. X    **  be compressed into "dest" using "seed" as the basis for diffs.
  944. X    */
  945. X
  946. X    while ( count > 0 )
  947. X    {
  948. X        delta = 0;        /* position counter */
  949. X
  950. X        /*
  951. X        **  Hunt through the data until the new data is different
  952. X        **  from the seed data.
  953. X        */
  954. X
  955. X        while ( *sptr == *nptr && delta < count )
  956. X        {
  957. X            delta++;
  958. X            sptr++;
  959. X            nptr++;
  960. X        }
  961. X
  962. X        /*
  963. X        **  Either a difference has been found, or we ran out of data.
  964. X        */
  965. X
  966. X        if ( delta >= count )    /* too far */
  967. X            break;        /* done */
  968. X
  969. X        count -= delta;
  970. X        
  971. X        /*
  972. X        **  Now set up the output with the command byte[s].
  973. X        **  (leaving the actual byte copy count till last.)
  974. X        */
  975. X
  976. X        /*
  977. X        **  The first command byte can only hold up to 31.
  978. X        **  If the delta is larger, then following bytes will
  979. X        **  be needed.
  980. X        */
  981. X
  982. X        saveptr = dptr++;    /* save the address for command byte */
  983. X
  984. X        command = MIN(delta, 31);
  985. X
  986. X        /*
  987. X        **  Any remaining count follows.
  988. X        **
  989. X        **  If count is 31, then a following byte must be given,
  990. X        **  even if 0.  Same holds if 255 is given in succesive bytes.
  991. X        */
  992. X
  993. X        if ( command == 31 )
  994. X        {
  995. X            delta -= command;    /* adjust for first count */
  996. X
  997. X            do {
  998. X                xfer = MIN(delta,255);
  999. X
  1000. X                delta -= xfer;
  1001. X
  1002. X                *dptr++ = xfer;
  1003. X
  1004. X            } while ( xfer == 255 );
  1005. X
  1006. X
  1007. X        }
  1008. X
  1009. X
  1010. X        /*
  1011. X        **  Now transfer up to 8 bytes, stopping when the new byte
  1012. X        **  matches the seed byte.  One could make a case for
  1013. X        **  transfering a matching byte too (if stuck in the middle
  1014. X        **  of the 8 bytes), but it does not impact the worst case,
  1015. X        **  and in the long run, the compression will not be as good.
  1016. X        **  Also, we need to make sure that we don't overrun count.
  1017. X        **  ("count" is checked first so we don't reference past the
  1018. X        **  end of the memory block).
  1019. X        */
  1020. X
  1021. X        for ( xfer = 0; 
  1022. X            count && *sptr != *nptr && xfer < 8;
  1023. X                xfer++)
  1024. X        {
  1025. X            *dptr++ = *nptr++;    /* transfer byte */
  1026. X            sptr++;            /* bump seed pointer too */
  1027. X            count--;
  1028. X        }
  1029. X
  1030. X        /*
  1031. X        **  Now xfer is the number of bytes transfered, but the
  1032. X        **  number range is 3 bits (0-7), so decrement and merge
  1033. X        **  it into the command byte and put it in the data.
  1034. X        */
  1035. X
  1036. X        command += ((xfer - 1) << 5);
  1037. X
  1038. X        *saveptr = command;
  1039. X
  1040. X    }
  1041. X
  1042. X    return ( dptr - dest );
  1043. }
  1044. X
  1045. X
  1046. /*----------------------------------------------------------------------*\
  1047. X * This is here in case <ESC>*rU is sent after <ESC>*r#A, in which case *
  1048. X * we must deallocate the memory to provide for a different amount of   *
  1049. X * planes when graphics are sent.                                       *
  1050. \*----------------------------------------------------------------------*/
  1051. X
  1052. free_mem()    
  1053. {
  1054. X    int r;
  1055. X
  1056. X
  1057. X    if ( !memflag )
  1058. X        return;        /* no memory to free */
  1059. X
  1060. X    free(new_row);
  1061. X
  1062. X    for(r = MAXMODES -1; r >= 0; r--)
  1063. X        free(out_row[r]);
  1064. X
  1065. X    for(r = num_planes - 1; r >= 0; r--)
  1066. X        free(seed_row[r]);
  1067. X
  1068. X    memflag = FALSE;
  1069. }
  1070. X
  1071. /*
  1072. **  Get_Frac() simply gets the fractional part of a value.  This is here
  1073. **  because scanf() will consume a trailing 'e' or 'E', which is a problem
  1074. **  in PCL.
  1075. */
  1076. X
  1077. static float    Get_Frac()
  1078. {
  1079. X    float    result = 0.0;
  1080. X    int    c;
  1081. X    float    position = 10.0;
  1082. X
  1083. X    while ( (c = getchar()) != EOF )
  1084. X    {
  1085. X        /*
  1086. X        **  Do we have a digit?
  1087. X        */
  1088. X
  1089. X        if ( !isdigit(c) )        /* not a digit */
  1090. X        {
  1091. X            ungetc( c, stdin );    /* put it back */
  1092. X            break;            /* quit */
  1093. X        }
  1094. X
  1095. X        result += ((c - '0') / position);
  1096. X
  1097. X        position *= 10.0;
  1098. X    }
  1099. X
  1100. X    return ( result );
  1101. }
  1102. SHAR_EOF
  1103. echo 'File pclcomp.c is complete' &&
  1104. chmod 0444 pclcomp.c ||
  1105. echo 'restore of pclcomp.c failed'
  1106. Wc_c="`wc -c < 'pclcomp.c'`"
  1107. test 70635 -eq "$Wc_c" ||
  1108.     echo 'pclcomp.c: original size 70635, current size' "$Wc_c"
  1109. rm -f _shar_wnt_.tmp
  1110. fi
  1111. # ============= pclcomp.man ==============
  1112. if test -f 'pclcomp.man' -a X"$1" != X"-c"; then
  1113.     echo 'x - skipping pclcomp.man (File already exists)'
  1114.     rm -f _shar_wnt_.tmp
  1115. else
  1116. > _shar_wnt_.tmp
  1117. echo 'x - extracting pclcomp.man (Text)'
  1118. sed 's/^X//' << 'SHAR_EOF' > 'pclcomp.man' &&
  1119. X
  1120. X
  1121. X
  1122. X     PCLCOMP(1)                         PCLCOMP(1)
  1123. X
  1124. X
  1125. X
  1126. X     NAME
  1127. X      pclcomp - Compress PCL graphics files.
  1128. X
  1129. X     SYNOPSIS
  1130. X      pclcomp [ -0123drsvxz ] [ -n num ] [ infile [ outfile ]]
  1131. X
  1132. X     DESCRIPTION
  1133. X      Pclcomp compresses (or decompresses) HP-PCL (Printer Control
  1134. X      Language) graphics data.  The supported compression modes
  1135. X      are 0 (uncompressed), 1, 2 and 3.  Pclcomp will read files
  1136. X      using any of the modes 0 through 3, and will output using
  1137. X      the modes which will give the best compression.  This
  1138. X      compressed version of the file may be sent directly to a PCL
  1139. X      compatible printer, thus reducing I/O bandwidth.  Pictures
  1140. X      may also be saved in compressed form, reducing disk usage.
  1141. X      In addition, PCL "imaging" files for the PaintJet XL are
  1142. X      also supported.
  1143. X
  1144. X      The options to pclcomp control the compression modes.  By
  1145. X      default, pclcomp will use modes 0, 2 and 3, but the user may
  1146. X      restrict which output modes it uses by specifying them on
  1147. X      the command line with the -0, -1, -2 and -3 options.    To
  1148. X      decompress a file, simply specify -0 as the only mode to use
  1149. X      for output.  Mode 0 ( -0 ) should always be allowed since
  1150. X      modes 1, 2 and 3 cannot be guaranteed to be better than mode
  1151. X      0 for all types of pictures.
  1152. X
  1153. X      The -z option disables the zero "strip" feature.  Since most
  1154. X      printers do zero "filling", pclcomp, by default, "strips"
  1155. X      the trailing zeros of each row (or plane) of data.  Some
  1156. X      printers or programs may require that zero "stripping" be
  1157. X      disabled.
  1158. X
  1159. X      By default, pclcomp expects the input raster width to be
  1160. X      2400 pixels (8" at 300 dpi), and if it is different (e.g.
  1161. X      PaintJet), then the raster width should be specified by the
  1162. X      Source Raster Width escape sequence (<esc>*r#S). However,
  1163. X      many applications do not set the width and assume a default,
  1164. X      therefore, the user may use the -n option to pclcomp to
  1165. X      specify a new default raster width.  For PaintJet (8" at 180
  1166. X      dpi), the number should be 1440.  If the PCL file contains
  1167. X      the Source Raster Width escape sequence, it will override
  1168. X      this default.  If pclcomp thinks that more data is coming in
  1169. X      than the specified width, it will generate a warning, and
  1170. X      continue processing (and perhaps truncating) data.
  1171. X
  1172. X      The -x option will cause pclcomp to remove any horizontal
  1173. X      offset sequences from the data.  Only use this option if
  1174. X      white is defined to be zero (as with LaserJets).  This will
  1175. X      shrink the data more if modes 2 or 3 are used.
  1176. X
  1177. X      The -r option causes pclcomp to append a reset sequence
  1178. X
  1179. X
  1180. X
  1181. X                   - 1 -    Formatted:    April 20, 1992
  1182. X
  1183. X
  1184. X
  1185. X
  1186. X
  1187. X
  1188. X     PCLCOMP(1)                         PCLCOMP(1)
  1189. X
  1190. X
  1191. X
  1192. X      (<esc>E) to the end of the job.
  1193. X
  1194. X      Use the -d option to pclcomp if the output is to be sent to
  1195. X      a DeskJet printer.
  1196. X
  1197. X      Some applications erroneously send <esc>*rB and <esc>*rA
  1198. X      sequences between every row of graphics data.  The -s option
  1199. X      to pclcomp will "strip" all <esc>*rB sequences, and all
  1200. X      <esc>*rA sequences after the first occurrence of this
  1201. X      sequence. In addition, text and control characters residing
  1202. X      between <esc>*rA and <esc>*rB sequences will be discarded.
  1203. X      While this will work well for many jobs, it may have
  1204. X      problems on multi-page or complex jobs.
  1205. X
  1206. X      The -v option simply gives statistics to stderr about which
  1207. X      compression modes were used.
  1208. X
  1209. X     EXAMPLES
  1210. X      To compress a PCL file for LaserJet III, use:
  1211. X           pclcomp infile outfile
  1212. X
  1213. X      To compress a PCL file for the PaintJet (A size page at 180 dpi), use:
  1214. X           pclcomp -01 -n 1440 infile outfile
  1215. X
  1216. X      To compress a PCL file for DeskJet, use:
  1217. X           pclcomp -d012 infile outfile
  1218. X
  1219. X      To fully decompress a PCL file, use:
  1220. X           pclcomp -0z < infile > outfile
  1221. X
  1222. X     WARNINGS
  1223. X      The -z option can cause the output to be larger than the
  1224. X      input.
  1225. X
  1226. X      The -s option is useful, but it can cause erroneous output.
  1227. X
  1228. X      The -x option can cause black areas on the left side of the
  1229. X      picture on color printers.
  1230. X
  1231. X     AUTHOR
  1232. X      Tony Parkhurst, Hewlett-Packard, San Diego Division
  1233. X      (tony@sdd.hp.com)
  1234. X
  1235. X
  1236. X
  1237. X
  1238. X
  1239. X
  1240. X
  1241. X
  1242. X
  1243. X
  1244. X
  1245. X
  1246. X
  1247. X                   - 2 -    Formatted:    April 20, 1992
  1248. X
  1249. X
  1250. X
  1251. SHAR_EOF
  1252. chmod 0664 pclcomp.man ||
  1253. echo 'restore of pclcomp.man failed'
  1254. Wc_c="`wc -c < 'pclcomp.man'`"
  1255. test 4053 -eq "$Wc_c" ||
  1256.     echo 'pclcomp.man: original size 4053, current size' "$Wc_c"
  1257. rm -f _shar_wnt_.tmp
  1258. fi
  1259. # ============= printer.note ==============
  1260. if test -f 'printer.note' -a X"$1" != X"-c"; then
  1261.     echo 'x - skipping printer.note (File already exists)'
  1262.     rm -f _shar_wnt_.tmp
  1263. else
  1264. > _shar_wnt_.tmp
  1265. echo 'x - extracting printer.note (Text)'
  1266. sed 's/^X//' << 'SHAR_EOF' > 'printer.note' &&
  1267. X
  1268. X
  1269. Here is a list of HP printers and the compression modes they support:
  1270. X
  1271. X
  1272. X
  1273. Printer            Modes
  1274. -------            -----
  1275. X
  1276. LaserJet        0
  1277. LaserJet+        0
  1278. LaserJet 500        0
  1279. LaserJet 2000        0
  1280. LaserJet II        0
  1281. LaserJet IID        0
  1282. LaserJet IIP        0 1 2
  1283. LaserJet III        0 1 2 3
  1284. LaserJet IIID        0 1 2 3
  1285. LaserJet IIISi        0 1 2 3
  1286. LaserJet IIIP        0 1 2 3 5  (Method 5 is not supported by pclcomp)
  1287. X
  1288. DeskJet            0 1 2
  1289. DeskJet+        0 1 2
  1290. DeskJet 500        0 1 2 3
  1291. DeskJet 500 C        0 1 2 3 9  (Method 9 is not supported by pclcomp)
  1292. X
  1293. PaintJet        0 1
  1294. PaintJet XL        0 1 2 3
  1295. X
  1296. X
  1297. Mode 0 is uncompressed graphics data.
  1298. SHAR_EOF
  1299. chmod 0664 printer.note ||
  1300. echo 'restore of printer.note failed'
  1301. Wc_c="`wc -c < 'printer.note'`"
  1302. test 546 -eq "$Wc_c" ||
  1303.     echo 'printer.note: original size 546, current size' "$Wc_c"
  1304. rm -f _shar_wnt_.tmp
  1305. fi
  1306. rm -f _shar_seq_.tmp
  1307. echo You have unpacked the last part
  1308. exit 0
  1309. exit 0 # Just in case...
  1310.