simplified calculations
[gnutls.git] / lib / opencdk / literal.c
blob7b0ec0da286c1bade27c2a5293d5756d70d7979b
1 /* literal.c - Literal packet filters
2 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
4 * Author: Timo Schulz
6 * This file is part of OpenCDK.
8 * The OpenCDK library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <stdio.h>
27 #include <opencdk.h>
28 #include <main.h>
29 #include <filters.h>
30 #include <gnutls_int.h>
31 #include <gnutls_str.h>
34 /* Duplicate the string @s but strip of possible
35 relative folder names of it. */
36 static char *
37 dup_trim_filename (const char *s)
39 char *p = NULL;
41 p = strrchr (s, '/');
42 if (!p)
43 p = strrchr (s, '\\');
44 if (!p)
45 return cdk_strdup (s);
46 return cdk_strdup (p + 1);
50 static cdk_error_t
51 literal_decode (void *data, FILE * in, FILE * out)
53 literal_filter_t *pfx = data;
54 cdk_stream_t si, so;
55 cdk_packet_t pkt;
56 cdk_pkt_literal_t pt;
57 byte buf[BUFSIZE];
58 ssize_t nread;
59 int bufsize;
60 cdk_error_t rc;
62 _cdk_log_debug ("literal filter: decode\n");
64 if (!pfx || !in || !out)
65 return CDK_Inv_Value;
67 rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si);
68 if (rc)
69 return rc;
71 cdk_pkt_new (&pkt);
72 rc = cdk_pkt_read (si, pkt);
73 if (rc || pkt->pkttype != CDK_PKT_LITERAL)
75 cdk_pkt_release (pkt);
76 cdk_stream_close (si);
77 return !rc ? CDK_Inv_Packet : rc;
80 rc = _cdk_stream_fpopen (out, STREAMCTL_WRITE, &so);
81 if (rc)
83 cdk_pkt_release (pkt);
84 cdk_stream_close (si);
85 return rc;
88 pt = pkt->pkt.literal;
89 pfx->mode = pt->mode;
91 if (pfx->filename && pt->namelen > 0)
93 /* The name in the literal packet is more authorative. */
94 cdk_free (pfx->filename);
95 pfx->filename = dup_trim_filename (pt->name);
97 else if (!pfx->filename && pt->namelen > 0)
98 pfx->filename = dup_trim_filename (pt->name);
99 else if (!pt->namelen && !pfx->filename && pfx->orig_filename)
101 /* In this case, we need to derrive the output file name
102 from the original name and cut off the OpenPGP extension.
103 If this is not possible, we return an error. */
104 if (!stristr (pfx->orig_filename, ".gpg") &&
105 !stristr (pfx->orig_filename, ".pgp") &&
106 !stristr (pfx->orig_filename, ".asc"))
108 cdk_pkt_release (pkt);
109 cdk_stream_close (si);
110 cdk_stream_close (so);
111 _cdk_log_debug
112 ("literal filter: no file name and no PGP extension\n");
113 return CDK_Inv_Mode;
115 _cdk_log_debug ("literal filter: derrive file name from original\n");
116 pfx->filename = dup_trim_filename (pfx->orig_filename);
117 pfx->filename[strlen (pfx->filename) - 4] = '\0';
120 while (!feof (in))
122 _cdk_log_debug ("literal_decode: part on %d size %lu\n",
123 (int) pfx->blkmode.on, (unsigned long)pfx->blkmode.size);
124 if (pfx->blkmode.on)
125 bufsize = pfx->blkmode.size;
126 else
127 bufsize = pt->len < DIM (buf) ? pt->len : DIM (buf);
128 nread = cdk_stream_read (pt->buf, buf, bufsize);
129 if (nread == EOF)
131 rc = CDK_File_Error;
132 break;
134 if (pfx->md_initialized)
135 _gnutls_hash (&pfx->md, buf, nread);
136 cdk_stream_write (so, buf, nread);
137 pt->len -= nread;
138 if (pfx->blkmode.on)
140 pfx->blkmode.size = _cdk_pkt_read_len (in, &pfx->blkmode.on);
141 if ((ssize_t) pfx->blkmode.size == EOF)
142 return CDK_Inv_Packet;
144 if (pt->len <= 0 && !pfx->blkmode.on)
145 break;
148 cdk_stream_close (si);
149 cdk_stream_close (so);
150 cdk_pkt_release (pkt);
151 return rc;
155 static char
156 intmode_to_char (int mode)
158 switch (mode)
160 case CDK_LITFMT_BINARY:
161 return 'b';
162 case CDK_LITFMT_TEXT:
163 return 't';
164 case CDK_LITFMT_UNICODE:
165 return 'u';
166 default:
167 return 'b';
170 return 'b';
174 static cdk_error_t
175 literal_encode (void *data, FILE * in, FILE * out)
177 literal_filter_t *pfx = data;
178 cdk_pkt_literal_t pt;
179 cdk_stream_t si;
180 cdk_packet_t pkt;
181 size_t filelen;
182 cdk_error_t rc;
184 _cdk_log_debug ("literal filter: encode\n");
186 if (!pfx || !in || !out)
187 return CDK_Inv_Value;
188 if (!pfx->filename)
190 pfx->filename = cdk_strdup ("_CONSOLE");
191 if (!pfx->filename)
192 return CDK_Out_Of_Core;
195 rc = _cdk_stream_fpopen (in, STREAMCTL_READ, &si);
196 if (rc)
197 return rc;
199 filelen = strlen (pfx->filename);
200 cdk_pkt_new (&pkt);
201 pt = pkt->pkt.literal = cdk_calloc (1, sizeof *pt + filelen);
202 pt->name = (char *) pt + sizeof (*pt);
203 if (!pt)
205 cdk_pkt_release (pkt);
206 cdk_stream_close (si);
207 return CDK_Out_Of_Core;
209 memcpy (pt->name, pfx->filename, filelen);
210 pt->namelen = filelen;
211 pt->name[pt->namelen] = '\0';
212 pt->timestamp = (u32) gnutls_time (NULL);
213 pt->mode = intmode_to_char (pfx->mode);
214 pt->len = cdk_stream_get_length (si);
215 pt->buf = si;
216 pkt->old_ctb = 1;
217 pkt->pkttype = CDK_PKT_LITERAL;
218 rc = _cdk_pkt_write_fp (out, pkt);
220 cdk_pkt_release (pkt);
221 cdk_stream_close (si);
222 return rc;
227 _cdk_filter_literal (void *data, int ctl, FILE * in, FILE * out)
229 if (ctl == STREAMCTL_READ)
230 return literal_decode (data, in, out);
231 else if (ctl == STREAMCTL_WRITE)
232 return literal_encode (data, in, out);
233 else if (ctl == STREAMCTL_FREE)
235 literal_filter_t *pfx = data;
236 if (pfx)
238 _cdk_log_debug ("free literal filter\n");
239 cdk_free (pfx->filename);
240 pfx->filename = NULL;
241 cdk_free (pfx->orig_filename);
242 pfx->orig_filename = NULL;
243 return 0;
246 return CDK_Inv_Mode;
250 static int
251 text_encode (void *data, FILE * in, FILE * out)
253 const char *s;
254 char buf[2048];
256 if (!in || !out)
257 return CDK_Inv_Value;
259 /* FIXME: This code does not work for very long lines. */
260 while (!feof (in))
262 /* give space for trim_string \r\n */
263 s = fgets (buf, DIM (buf) - 3, in);
264 if (!s)
265 break;
266 _cdk_trim_string (buf);
267 _gnutls_str_cat (buf, sizeof(buf), "\r\n");
268 fwrite (buf, 1, strlen (buf), out);
271 return 0;
275 static int
276 text_decode (void *data, FILE * in, FILE * out)
278 text_filter_t *tfx = data;
279 const char *s;
280 char buf[2048];
282 if (!tfx || !in || !out)
283 return CDK_Inv_Value;
285 while (!feof (in))
287 s = fgets (buf, DIM (buf) - 1, in);
288 if (!s)
289 break;
290 _cdk_trim_string (buf);
291 fwrite (buf, 1, strlen (buf), out);
292 fwrite (tfx->lf, 1, strlen (tfx->lf), out);
295 return 0;
300 _cdk_filter_text (void *data, int ctl, FILE * in, FILE * out)
302 if (ctl == STREAMCTL_READ)
303 return text_encode (data, in, out);
304 else if (ctl == STREAMCTL_WRITE)
305 return text_decode (data, in, out);
306 else if (ctl == STREAMCTL_FREE)
308 text_filter_t *tfx = data;
309 if (tfx)
311 _cdk_log_debug ("free text filter\n");
312 tfx->lf = NULL;
315 return CDK_Inv_Mode;