xref: /plan9/sys/src/cmd/aux/antiword/asc85enc.c (revision f5736e95f14e1485b3a0291fa82d86cca323ab61)
1 /*
2  * asc85enc.c
3  * Copyright (C) 2000-2003 A.J. van Os; Released under GPL
4  *
5  * Description:
6  * Functions to for ASCII 85 encoding
7  *
8  *====================================================================
9  * This part of the software is based on:
10  * asc85ec.c - ASCII85 and Hex encoding for PostScript Level 2 and PDF
11  * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
12  *====================================================================
13  * The credit should go to him, but all the bugs are mine.
14  */
15 
16 #include <stdio.h>
17 #include "antiword.h"
18 
19 static const ULONG	aulPower85[5] = {
20 	1UL, 85UL, 85UL * 85, 85UL * 85 * 85, 85UL * 85 * 85 * 85,
21 };
22 static int	iOutBytes = 0;	/* Number of characters in an output line */
23 static char	cCharPrev = '\0';
24 
25 /*
26  * Two percent characters at the start of a line will cause trouble
27  * with some post-processing software. In order to avoid this, we
28  * simply insert a line break if we encounter two percent characters
29  * at the start of the line. Of course, this rather simplistic
30  * algorithm may lead to a large line count in pathological cases,
31  * but the chance for hitting such a case is very small, and even
32  * so it's only a cosmetic flaw and not a functional restriction.
33  */
34 
35 /*
36  * vOutputByte - output one byte
37  */
38 static void
vOutputByte(ULONG ulChar,FILE * pOutFile)39 vOutputByte(ULONG ulChar, FILE *pOutFile)
40 {
41 	if (iOutBytes == 1 && cCharPrev == '%' && ulChar == (ULONG)'%') {
42 		if (putc('\n', pOutFile) != EOF) {
43 			iOutBytes = 0;
44 		}
45 	}
46 	if (putc((int)ulChar, pOutFile) == EOF) {
47 		return;
48 	}
49 	iOutBytes++;
50 	if (iOutBytes > 63) {
51 		if (putc('\n', pOutFile) != EOF) {
52 			iOutBytes = 0;
53 		}
54 	}
55 	cCharPrev = (char)ulChar;
56 } /* end of vOutputByte */
57 
58 /*
59  * vASCII85EncodeByte - ASCII 85 encode a byte
60  */
61 void
vASCII85EncodeByte(FILE * pOutFile,int iByte)62 vASCII85EncodeByte(FILE *pOutFile, int iByte)
63 {
64 	static ULONG	ulBuffer[4] = { 0, 0, 0, 0 };
65 	static int	iInBuffer = 0;
66 	ULONG	ulValue, ulTmp;
67 	int	iIndex;
68 
69 	fail(pOutFile == NULL);
70 	fail(iInBuffer < 0);
71 	fail(iInBuffer > 3);
72 
73 	if (iByte == EOF) {
74 		/* End Of File, time to clean up */
75 		if (iInBuffer > 0 && iInBuffer < 4) {
76 			/* Encode the remaining bytes */
77 			ulValue = 0;
78 			for (iIndex = iInBuffer - 1; iIndex >= 0; iIndex--) {
79 				ulValue |=
80 					ulBuffer[iIndex] << (8 * (3 - iIndex));
81 			}
82 			for (iIndex = 4; iIndex >= 4 - iInBuffer; iIndex--) {
83 				ulTmp = ulValue / aulPower85[iIndex];
84 				vOutputByte(ulTmp + '!', pOutFile);
85 				ulValue -= ulTmp * aulPower85[iIndex];
86 			}
87 		}
88 		/* Add the End Of Data marker */
89 		(void)putc('~', pOutFile);
90 		(void)putc('>', pOutFile);
91 		(void)putc('\n', pOutFile);
92 		/* Reset the control variables */
93 		iInBuffer = 0;
94 		iOutBytes = 0;
95 		cCharPrev = '\0';
96 		return;
97 	}
98 
99 	ulBuffer[iInBuffer] = (ULONG)iByte & 0xff;
100 	iInBuffer++;
101 
102 	if (iInBuffer >= 4) {
103 		ulValue = (ulBuffer[0] << 24) | (ulBuffer[1] << 16) |
104 			(ulBuffer[2] << 8) | ulBuffer[3];
105 		if (ulValue == 0) {
106 			vOutputByte((ULONG)'z', pOutFile); /* Shortcut for 0 */
107 		} else {
108 			for (iIndex = 4; iIndex >= 0; iIndex--) {
109 				ulTmp = ulValue / aulPower85[iIndex];
110 				vOutputByte(ulTmp + '!', pOutFile);
111 				ulValue -= ulTmp * aulPower85[iIndex];
112 			}
113 		}
114 		/* Reset the buffer */
115 		iInBuffer = 0;
116 	}
117 } /* end of vASCII85EncodeByte */
118 
119 /*
120  * vASCII85EncodeArray - ASCII 85 encode a byte array
121  */
122 void
vASCII85EncodeArray(FILE * pInFile,FILE * pOutFile,size_t tLength)123 vASCII85EncodeArray(FILE *pInFile, FILE *pOutFile, size_t tLength)
124 {
125 	size_t	tCount;
126 	int	iByte;
127 
128 	fail(pInFile == NULL);
129 	fail(pOutFile == NULL);
130 
131 	DBG_DEC(tLength);
132 
133 	for (tCount = 0; tCount < tLength; tCount++) {
134 		iByte = iNextByte(pInFile);
135 		if (iByte == EOF) {
136 			break;
137 		}
138 		vASCII85EncodeByte(pOutFile, iByte);
139 	}
140 } /* end of vASCII85EncodeArray */
141 
142 /*
143  * vASCII85EncodeFile - ASCII 85 encode part of a file
144  */
145 void
vASCII85EncodeFile(FILE * pInFile,FILE * pOutFile,size_t tLength)146 vASCII85EncodeFile(FILE *pInFile, FILE *pOutFile, size_t tLength)
147 {
148 	fail(pInFile == NULL);
149 	fail(pOutFile == NULL);
150 	fail(tLength == 0);
151 
152 	vASCII85EncodeArray(pInFile, pOutFile, tLength);
153 	vASCII85EncodeByte(pOutFile, EOF);
154 } /* end of vASCII85EncodeFile */
155