cpp: Add conveniance Data::toString
[gpgme.git] / lang / cpp / src / data.cpp
1 /*
2   data.cpp - wraps a gpgme data object
3   Copyright (C) 2003 Klarälvdalens Datakonsult AB
4
5   This file is part of GPGME++.
6
7   GPGME++ is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   GPGME++ is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with GPGME++; see the file COPYING.LIB.  If not, write to the
19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24  #include "config.h"
25 #endif
26
27 #include "data_p.h"
28 #include "context_p.h"
29 #include <error.h>
30 #include <interfaces/dataprovider.h>
31
32 #include <gpgme.h>
33
34 #ifndef NDEBUG
35 #include <iostream>
36 #endif
37
38 GpgME::Data::Private::~Private()
39 {
40     if (data) {
41         gpgme_data_release(data);
42     }
43 }
44
45 const GpgME::Data::Null GpgME::Data::null;
46
47 GpgME::Data::Data()
48 {
49     gpgme_data_t data;
50     const gpgme_error_t e = gpgme_data_new(&data);
51     d.reset(new Private(e ? 0 : data));
52 }
53
54 GpgME::Data::Data(const Null &)
55     : d(new Private(0))
56 {
57
58 }
59
60 GpgME::Data::Data(gpgme_data_t data)
61     : d(new Private(data))
62 {
63
64 }
65
66 GpgME::Data::Data(const char *buffer, size_t size, bool copy)
67 {
68     gpgme_data_t data;
69     const gpgme_error_t e = gpgme_data_new_from_mem(&data, buffer, size, int(copy));
70     std::string sizestr = std::to_string(size);
71     // Ignore errors as this is optional
72     gpgme_data_set_flag(data, "size-hint", sizestr.c_str());
73     d.reset(new Private(e ? 0 : data));
74 }
75
76 GpgME::Data::Data(const char *filename)
77 {
78     gpgme_data_t data;
79     const gpgme_error_t e = gpgme_data_new(&data);
80     d.reset(new Private(e ? 0 : data));
81     if (!e) {
82         setFileName(filename);
83     }
84 }
85
86 GpgME::Data::Data(const char *filename, off_t offset, size_t length)
87 {
88     gpgme_data_t data;
89     const gpgme_error_t e = gpgme_data_new_from_filepart(&data, filename, 0, offset, length);
90     d.reset(new Private(e ? 0 : data));
91 }
92
93 GpgME::Data::Data(FILE *fp)
94 {
95     gpgme_data_t data;
96     const gpgme_error_t e = gpgme_data_new_from_stream(&data, fp);
97     d.reset(new Private(e ? 0 : data));
98 }
99
100 GpgME::Data::Data(FILE *fp, off_t offset, size_t length)
101 {
102     gpgme_data_t data;
103     const gpgme_error_t e = gpgme_data_new_from_filepart(&data, 0, fp, offset, length);
104     d.reset(new Private(e ? 0 : data));
105 }
106
107 GpgME::Data::Data(int fd)
108 {
109     gpgme_data_t data;
110     const gpgme_error_t e = gpgme_data_new_from_fd(&data, fd);
111     d.reset(new Private(e ? 0 : data));
112 }
113
114 GpgME::Data::Data(DataProvider *dp)
115 {
116     d.reset(new Private);
117     if (!dp) {
118         return;
119     }
120     if (!dp->isSupported(DataProvider::Read)) {
121         d->cbs.read = 0;
122     }
123     if (!dp->isSupported(DataProvider::Write)) {
124         d->cbs.write = 0;
125     }
126     if (!dp->isSupported(DataProvider::Seek)) {
127         d->cbs.seek = 0;
128     }
129     if (!dp->isSupported(DataProvider::Release)) {
130         d->cbs.release = 0;
131     }
132     const gpgme_error_t e = gpgme_data_new_from_cbs(&d->data, &d->cbs, dp);
133     if (e) {
134         d->data = 0;
135     }
136     if (dp->isSupported(DataProvider::Seek)) {
137         off_t size = seek(0, SEEK_END);
138         seek(0, SEEK_SET);
139         std::string sizestr = std::to_string(size);
140         // Ignore errors as this is optional
141         gpgme_data_set_flag(d->data, "size-hint", sizestr.c_str());
142     }
143 #ifndef NDEBUG
144     //std::cerr << "GpgME::Data(): DataProvider supports: "
145     //    << ( d->cbs.read ? "read" : "no read" ) << ", "
146     //    << ( d->cbs.write ? "write" : "no write" ) << ", "
147     //    << ( d->cbs.seek ? "seek" : "no seek" ) << ", "
148     //    << ( d->cbs.release ? "release" : "no release" ) << std::endl;
149 #endif
150 }
151
152 bool GpgME::Data::isNull() const
153 {
154     return !d || !d->data;
155 }
156
157 GpgME::Data::Encoding GpgME::Data::encoding() const
158 {
159     switch (gpgme_data_get_encoding(d->data)) {
160     case GPGME_DATA_ENCODING_NONE:   return AutoEncoding;
161     case GPGME_DATA_ENCODING_BINARY: return BinaryEncoding;
162     case GPGME_DATA_ENCODING_BASE64: return Base64Encoding;
163     case GPGME_DATA_ENCODING_ARMOR:  return ArmorEncoding;
164     case GPGME_DATA_ENCODING_MIME:   return MimeEncoding;
165     case GPGME_DATA_ENCODING_URL:    return UrlEncoding;
166     case GPGME_DATA_ENCODING_URLESC: return UrlEscEncoding;
167     case GPGME_DATA_ENCODING_URL0:   return Url0Encoding;
168     }
169     return AutoEncoding;
170 }
171
172 GpgME::Error GpgME::Data::setEncoding(Encoding enc)
173 {
174     gpgme_data_encoding_t ge = GPGME_DATA_ENCODING_NONE;
175     switch (enc) {
176     case AutoEncoding:   ge = GPGME_DATA_ENCODING_NONE;   break;
177     case BinaryEncoding: ge = GPGME_DATA_ENCODING_BINARY; break;
178     case Base64Encoding: ge = GPGME_DATA_ENCODING_BASE64; break;
179     case ArmorEncoding:  ge = GPGME_DATA_ENCODING_ARMOR;  break;
180     case MimeEncoding:   ge = GPGME_DATA_ENCODING_MIME;  break;
181     case UrlEncoding:    ge = GPGME_DATA_ENCODING_URL; break;
182     case UrlEscEncoding: ge = GPGME_DATA_ENCODING_URLESC; break;
183     case Url0Encoding:   ge = GPGME_DATA_ENCODING_URL0; break;
184     }
185     return Error(gpgme_data_set_encoding(d->data, ge));
186 }
187
188 GpgME::Data::Type GpgME::Data::type() const
189 {
190     if (isNull()) {
191         return Invalid;
192     }
193     switch (gpgme_data_identify(d->data, 0)) {
194     case GPGME_DATA_TYPE_INVALID:       return Invalid;
195     case GPGME_DATA_TYPE_UNKNOWN:       return Unknown;
196     case GPGME_DATA_TYPE_PGP_SIGNED:    return PGPSigned;
197     case GPGME_DATA_TYPE_PGP_OTHER:     return PGPOther;
198     case GPGME_DATA_TYPE_PGP_KEY:       return PGPKey;
199     case GPGME_DATA_TYPE_CMS_SIGNED:    return CMSSigned;
200     case GPGME_DATA_TYPE_CMS_ENCRYPTED: return CMSEncrypted;
201     case GPGME_DATA_TYPE_CMS_OTHER:     return CMSOther;
202     case GPGME_DATA_TYPE_X509_CERT:     return X509Cert;
203     case GPGME_DATA_TYPE_PKCS12:        return PKCS12;
204     case GPGME_DATA_TYPE_PGP_ENCRYPTED: return PGPEncrypted;
205     case GPGME_DATA_TYPE_PGP_SIGNATURE: return PGPSignature;
206     }
207     return Invalid;
208 }
209
210 char *GpgME::Data::fileName() const
211 {
212     return gpgme_data_get_file_name(d->data);
213 }
214
215 GpgME::Error GpgME::Data::setFileName(const char *name)
216 {
217     return Error(gpgme_data_set_file_name(d->data, name));
218 }
219
220 ssize_t GpgME::Data::read(void *buffer, size_t length)
221 {
222     return gpgme_data_read(d->data, buffer, length);
223 }
224
225 ssize_t GpgME::Data::write(const void *buffer, size_t length)
226 {
227     return gpgme_data_write(d->data, buffer, length);
228 }
229
230 off_t GpgME::Data::seek(off_t offset, int whence)
231 {
232     return gpgme_data_seek(d->data, offset, whence);
233 }
234
235 std::vector<GpgME::Key> GpgME::Data::toKeys(Protocol proto) const
236 {
237     std::vector<GpgME::Key> ret;
238     if (isNull()) {
239         return ret;
240     }
241     auto ctx = GpgME::Context::createForProtocol(proto);
242     if (!ctx) {
243         return ret;
244     }
245
246     if (gpgme_op_keylist_from_data_start (ctx->impl()->ctx, d->data, 0)) {
247         return ret;
248     }
249
250     gpgme_key_t key;
251     while (!gpgme_op_keylist_next (ctx->impl()->ctx, &key)) {
252         ret.push_back(GpgME::Key(key, false));
253     }
254     delete ctx;
255     return ret;
256 }
257
258 std::string GpgME::Data::toString()
259 {
260   std::string ret;
261   char buf[4096];
262   size_t nread;
263   seek (0, SEEK_SET);
264   while ((nread = read (buf, 4096)) > 0)
265     {
266       ret += std::string (buf, nread);
267     }
268   seek (0, SEEK_SET);
269   return ret;
270 }