]> git.ipfire.org Git - thirdparty/cups.git/blame - examples/ppdx.c
Import CUPS v1.7.1
[thirdparty/cups.git] / examples / ppdx.c
CommitLineData
a29fd7dd 1/*
61515785 2 * "$Id: ppdx.c 3833 2012-05-23 22:51:18Z msweet $"
a29fd7dd
MS
3 *
4 * Example code for encoding and decoding large amounts of data in a PPD file.
5 * This would typically be used in a driver to save configuration/state
6 * information that could be used by an application.
7 *
8 * Copyright 2012 by Apple Inc.
9 *
10 * These coded instructions, statements, and computer programs are the
11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
15 *
16 * This file is subject to the Apple OS-Developed Software exception.
17 *
18 * Contents:
19 *
20 * ppdxReadData() - Read encoded data from a ppd_file_t *.
21 * ppdxWriteData() - Writes encoded data to stderr using PPD: messages.
22 */
23
24/*
25 * Include necessary headers...
26 */
27
28#include "ppdx.h"
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <zlib.h> /* For compression of the data */
33
34
35/*
36 * Constants...
37 */
38
39#define PPDX_MAX_VALUE (PPD_MAX_LINE - PPD_MAX_NAME - 4)
40 /* Max value length with delimiters + nul */
41#define PPDX_MAX_CHUNK (PPDX_MAX_VALUE * 3 / 4)
42 /* Max length of each chunk when Base64-encoded */
43
44
45/*
46 * 'ppdxReadData()' - Read encoded data from a ppd_file_t *.
47 *
48 * Reads chunked data in the PPD file "ppd" using the prefix "name". Returns
49 * an allocated pointer to the data (which is nul-terminated for convenience)
50 * along with the length of the data in the variable pointed to by "datasize",
51 * which can be NULL to indicate the caller doesn't need the length.
52 *
53 * Returns NULL if no data is present in the PPD with the prefix.
54 */
55
56void * /* O - Data or NULL */
57ppdxReadData(ppd_file_t *ppd, /* I - PPD file */
58 const char *name, /* I - Keyword prefix */
59 size_t *datasize) /* O - Size of data or NULL for don't care */
60{
61 char keyword[PPD_MAX_NAME], /* Keyword name */
62 decoded[PPDX_MAX_CHUNK + 1];
63 /* Decoded string */
64 unsigned chunk = 0; /* Current chunk number */
65 int len; /* Length of current chunk */
66 ppd_attr_t *attr; /* Keyword/value from PPD file */
67 Bytef *data; /* Pointer to data */
68 size_t alloc_size; /* Allocated size of data buffer */
69 z_stream decomp; /* Decompressor stream */
70 int error; /* Error/status from inflate() */
71
72
73 /*
74 * Range check input...
75 */
76
77 if (datasize)
78 *datasize = 0;
79
80 if (!ppd || !name)
81 return (NULL);
82
83 /*
84 * First see if there are any instances of the named keyword in the PPD...
85 */
86
87 snprintf(keyword, sizeof(keyword), "%s%04x", name, chunk);
88 if ((attr = ppdFindAttr(ppd, keyword, NULL)) == NULL)
89 return (NULL);
90
91 /*
92 * Allocate some memory and start decoding...
93 */
94
95 data = malloc(257);
96 alloc_size = 256;
97
98 memset(&decomp, 0, sizeof(decomp));
99 decomp.next_out = data;
100 decomp.avail_out = 256;
101
102 inflateInit(&decomp);
103
104 do
105 {
106 /*
107 * Grab the data from the current attribute and decode it...
108 */
109
110 len = sizeof(decoded);
111 if (!httpDecode64_2(decoded, &len, attr->value) || len == 0)
112 break;
113
114// printf("chunk %04x has length %d\n", chunk, len);
115
116 /*
117 * Decompress this chunk...
118 */
119
120 decomp.next_in = decoded;
121 decomp.avail_in = len;
122
123 do
124 {
125 Bytef *temp; /* Temporary pointer */
126 size_t temp_size; /* Temporary allocation size */
127
128// printf("Before inflate: avail_in=%d, avail_out=%d\n", decomp.avail_in,
129// decomp.avail_out);
130
131 if ((error = inflate(&decomp, Z_NO_FLUSH)) < Z_OK)
132 {
133 fprintf(stderr, "ERROR: inflate returned %d (%s)\n", error, decomp.msg);
134 break;
135 }
136
137// printf("After inflate: avail_in=%d, avail_out=%d, error=%d\n",
138// decomp.avail_in, decomp.avail_out, error);
139
140 if (decomp.avail_out == 0)
141 {
142 if (alloc_size < 2048)
143 temp_size = alloc_size * 2;
144 else if (alloc_size < PPDX_MAX_DATA)
145 temp_size = alloc_size + 2048;
146 else
147 break;
148
149 if ((temp = realloc(data, temp_size + 1)) == NULL)
150 {
151 free(data);
152 return (NULL);
153 }
154
155 decomp.next_out = temp + (decomp.next_out - data);
156 decomp.avail_out = temp_size - alloc_size;
157 data = temp;
158 alloc_size = temp_size;
159 }
160 }
161 while (decomp.avail_in > 0);
162
163 chunk ++;
164 snprintf(keyword, sizeof(keyword), "%s%04x", name, chunk);
165 }
166 while ((attr = ppdFindAttr(ppd, keyword, NULL)) != NULL);
167
168 inflateEnd(&decomp);
169
170 /*
171 * Nul-terminate the data (usually a string)...
172 */
173
174 *(decomp.next_out) = '\0';
175
176 if (datasize)
177 *datasize = decomp.next_out - data;
178
179 return (data);
180}
181
182
183/*
184 * 'ppdxWriteData()' - Writes encoded data to stderr using PPD: messages.
185 *
186 * Writes chunked data to the PPD file using PPD: messages sent to stderr for
187 * cupsd. "name" must be a valid PPD keyword string whose length is less than
188 * 37 characters to allow for chunk numbering. "data" provides a pointer to the
189 * data to be written, and "datasize" provides the length.
190 */
191
192extern void
193ppdxWriteData(const char *name, /* I - Base name of keyword */
194 const void *data, /* I - Data to write */
195 size_t datasize) /* I - Number of bytes in data */
196{
197 char buffer[PPDX_MAX_CHUNK], /* Chunk buffer */
198 encoded[PPDX_MAX_VALUE + 1],
199 /* Encoded data */
200 pair[PPD_MAX_LINE], /* name=value pair */
201 line[PPDX_MAX_STATUS], /* Line buffer */
202 *lineptr, /* Current position in line buffer */
203 *lineend; /* End of line buffer */
204 unsigned chunk = 0; /* Current chunk number */
205 int len; /* Length of current chunk */
206 z_stream comp; /* Compressor stream */
207 int error; /* Error/status from deflate() */
208
209
210 /*
211 * Range check input...
212 */
213
214 if (!name || (!data && datasize > 0) || datasize > PPDX_MAX_DATA)
215 return;
216
217 strlcpy(line, "PPD:", sizeof(line));
218 lineptr = line + 4;
219 lineend = line + sizeof(line) - 2;
220
221 if (datasize > 0)
222 {
223 /*
224 * Compress and encode output...
225 */
226
227 memset(&comp, 0, sizeof(comp));
228 comp.next_in = (Bytef *)data;
229 comp.avail_in = datasize;
230
231 deflateInit(&comp, 9);
232
233 do
234 {
235 /*
236 * Compress a chunk...
237 */
238
239 comp.next_out = buffer;
240 comp.avail_out = sizeof(buffer);
241
242 if ((error = deflate(&comp, Z_FINISH)) < Z_OK)
243 {
244 fprintf(stderr, "ERROR: deflate returned %d (%s)\n", error, comp.msg);
245 break;
246 }
247
248 /*
249 * Write a chunk...
250 */
251
252 len = sizeof(buffer) - comp.avail_out;
253 httpEncode64_2(encoded, sizeof(encoded), buffer, len);
254
255 len = (int)snprintf(pair, sizeof(pair), " %s%04x=%s", name, chunk,
256 encoded);
257#ifdef DEBUG
258 fprintf(stderr, "DEBUG: *%s%04x: \"%s\"\n", name, chunk, encoded);
259#endif /* DEBUG */
260
261 if ((lineptr + len) >= lineend)
262 {
263 *lineptr++ = '\n';
264 *lineptr = '\0';
265
266 fputs(line, stderr);
267 lineptr = line + 4;
268 }
269
270 strlcpy(lineptr, pair, lineend - lineptr);
271 lineptr += len;
272
273 /*
274 * Setup for the next one...
275 */
276
277 chunk ++;
278 }
279 while (comp.avail_out == 0);
280 }
281
282 deflateEnd(&comp);
283
284 /*
285 * Write a trailing empty chunk to signal EOD...
286 */
287
288 len = (int)snprintf(pair, sizeof(pair), " %s%04x=\"\"", name, chunk);
289#ifdef DEBUG
290 fprintf(stderr, "DEBUG: *%s%04x: \"\"\n", name, chunk);
291#endif /* DEBUG */
292
293 if ((lineptr + len) >= lineend)
294 {
295 *lineptr++ = '\n';
296 *lineptr = '\0';
297
298 fputs(line, stderr);
299 lineptr = line + 4;
300 }
301
302 strlcpy(lineptr, pair, lineend - lineptr);
303 lineptr += len;
304
305 *lineptr++ = '\n';
306 *lineptr = '\0';
307
308 fputs(line, stderr);
309}
310
311
312/*
61515785 313 * End of "$Id: ppdx.c 3833 2012-05-23 22:51:18Z msweet $".
a29fd7dd 314 */