C++ wrapper: Fix use-after-free issue in List::find_all()
[libftdi] / ftdipp / ftdi.cpp
CommitLineData
cdf448f6
TJ
1/***************************************************************************
2 ftdi.cpp - C++ wraper for libftdi
3 -------------------
4 begin : Mon Oct 13 2008
5 copyright : (C) 2008 by Marek Vavruša
6 email : opensource@intra2net.com and marek@vavrusa.com
7 ***************************************************************************/
3ab8f642
TJ
8/*
9Copyright (C) 2008 by Marek Vavruša
cdf448f6 10
3ab8f642
TJ
11The software in this package is distributed under the GNU General
12Public License version 2 (with a special exception described below).
13
14A copy of GNU General Public License (GPL) is included in this distribution,
15in the file COPYING.GPL.
16
17As a special exception, if other files instantiate templates or use macros
18or inline functions from this file, or you compile this file and link it
19with other works to produce a work based on this file, this file
20does not by itself cause the resulting work to be covered
21by the GNU General Public License.
22
23However the source code for this file must still be made available
24in accordance with section (3) of the GNU General Public License.
cdf448f6 25
3ab8f642
TJ
26This exception does not invalidate any other reasons why a work based
27on this file might be covered by the GNU General Public License.
28*/
20b1459a 29#include "ftdi.hpp"
b790d38e 30#include "ftdi_i.h"
20b1459a
TJ
31#include "ftdi.h"
32
33namespace Ftdi
34{
35
36class Context::Private
37{
cdf448f6
TJ
38public:
39 Private()
d5c91348 40 : open(false), ftdi(0), dev(0)
cdf448f6 41 {
cfceadbc
MV
42 ftdi = ftdi_new();
43 }
44
45 ~Private()
46 {
22d12cda 47 if (open)
cfceadbc
MV
48 ftdi_usb_close(ftdi);
49
50 ftdi_free(ftdi);
cdf448f6
TJ
51 }
52
53 bool open;
54
55 struct ftdi_context* ftdi;
579b006f 56 struct libusb_device* dev;
cdf448f6
TJ
57
58 std::string vendor;
59 std::string description;
60 std::string serial;
20b1459a
TJ
61};
62
63/*! \brief Constructor.
64 */
65Context::Context()
cdf448f6 66 : d( new Private() )
20b1459a 67{
20b1459a
TJ
68}
69
70/*! \brief Destructor.
71 */
72Context::~Context()
73{
20b1459a
TJ
74}
75
76bool Context::is_open()
77{
cdf448f6 78 return d->open;
20b1459a
TJ
79}
80
58cce2d4 81int Context::open(int vendor, int product)
20b1459a 82{
2f6b4bb6 83 // Open device
58cce2d4 84 int ret = ftdi_usb_open(d->ftdi, vendor, product);
20b1459a 85
2f6b4bb6
MV
86 if (ret < 0)
87 return ret;
20b1459a 88
58cce2d4
GE
89 return get_strings_and_reopen();
90}
2f6b4bb6 91
58cce2d4
GE
92int Context::open(int vendor, int product, const std::string& description, const std::string& serial, unsigned int index)
93{
94 // translate empty strings to NULL
95 // -> do not use them to find the device (vs. require an empty string to be set in the EEPROM)
96 const char* c_description=NULL;
97 const char* c_serial=NULL;
98 if (!description.empty())
99 c_description=description.c_str();
100 if (!serial.empty())
101 c_serial=serial.c_str();
20b1459a 102
58cce2d4
GE
103 int ret = ftdi_usb_open_desc_index(d->ftdi, vendor, product, c_description, c_serial, index);
104
105 if (ret < 0)
106 return ret;
107
108 return get_strings_and_reopen();
109}
110
111int Context::open(const std::string& description)
112{
113 int ret = ftdi_usb_open_string(d->ftdi, description.c_str());
114
115 if (ret < 0)
116 return ret;
117
118 return get_strings_and_reopen();
20b1459a
TJ
119}
120
579b006f 121int Context::open(struct libusb_device *dev)
20b1459a 122{
cdf448f6
TJ
123 if (dev != 0)
124 d->dev = dev;
125
126 if (d->dev == 0)
127 return -1;
20b1459a 128
58cce2d4 129 return get_strings_and_reopen();
20b1459a
TJ
130}
131
132int Context::close()
133{
cdf448f6 134 d->open = false;
9330b120 135 d->dev = 0;
cdf448f6 136 return ftdi_usb_close(d->ftdi);
20b1459a
TJ
137}
138
139int Context::reset()
140{
cdf448f6 141 return ftdi_usb_reset(d->ftdi);
20b1459a
TJ
142}
143
144int Context::flush(int mask)
145{
cdf448f6 146 int ret = 1;
20b1459a 147
cdf448f6
TJ
148 if (mask & Input)
149 ret &= ftdi_usb_purge_rx_buffer(d->ftdi);
150 if (mask & Output)
151 ret &= ftdi_usb_purge_tx_buffer(d->ftdi);
152
153 return ret;
20b1459a
TJ
154}
155
156int Context::set_interface(enum ftdi_interface interface)
157{
cdf448f6 158 return ftdi_set_interface(d->ftdi, interface);
20b1459a
TJ
159}
160
579b006f 161void Context::set_usb_device(struct libusb_device_handle *dev)
20b1459a 162{
cdf448f6 163 ftdi_set_usbdev(d->ftdi, dev);
579b006f 164 d->dev = libusb_get_device(dev);
20b1459a
TJ
165}
166
167int Context::set_baud_rate(int baudrate)
168{
cdf448f6 169 return ftdi_set_baudrate(d->ftdi, baudrate);
20b1459a
TJ
170}
171
172int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity)
173{
cdf448f6 174 return ftdi_set_line_property(d->ftdi, bits, sbit, parity);
20b1459a
TJ
175}
176
177int Context::set_line_property(enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, enum ftdi_break_type break_type)
178{
cdf448f6 179 return ftdi_set_line_property2(d->ftdi, bits, sbit, parity, break_type);
20b1459a
TJ
180}
181
182int Context::read(unsigned char *buf, int size)
183{
cdf448f6 184 return ftdi_read_data(d->ftdi, buf, size);
20b1459a
TJ
185}
186
187int Context::set_read_chunk_size(unsigned int chunksize)
188{
cdf448f6 189 return ftdi_read_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
190}
191
192int Context::read_chunk_size()
193{
cdf448f6
TJ
194 unsigned chunk = -1;
195 if (ftdi_read_data_get_chunksize(d->ftdi, &chunk) < 0)
196 return -1;
20b1459a 197
cdf448f6
TJ
198 return chunk;
199}
20b1459a
TJ
200
201int Context::write(unsigned char *buf, int size)
202{
cdf448f6 203 return ftdi_write_data(d->ftdi, buf, size);
20b1459a
TJ
204}
205
206int Context::set_write_chunk_size(unsigned int chunksize)
207{
cdf448f6 208 return ftdi_write_data_set_chunksize(d->ftdi, chunksize);
20b1459a
TJ
209}
210
211int Context::write_chunk_size()
212{
cdf448f6
TJ
213 unsigned chunk = -1;
214 if (ftdi_write_data_get_chunksize(d->ftdi, &chunk) < 0)
215 return -1;
20b1459a 216
cdf448f6 217 return chunk;
20b1459a
TJ
218}
219
220int Context::set_flow_control(int flowctrl)
221{
cdf448f6 222 return ftdi_setflowctrl(d->ftdi, flowctrl);
20b1459a
TJ
223}
224
225int Context::set_modem_control(int mask)
226{
cdf448f6
TJ
227 int dtr = 0, rts = 0;
228
229 if (mask & Dtr)
230 dtr = 1;
231 if (mask & Rts)
232 rts = 1;
20b1459a 233
cdf448f6 234 return ftdi_setdtr_rts(d->ftdi, dtr, rts);
20b1459a
TJ
235}
236
237int Context::set_dtr(bool state)
238{
cdf448f6 239 return ftdi_setdtr(d->ftdi, state);
20b1459a
TJ
240}
241
242int Context::set_rts(bool state)
243{
cdf448f6 244 return ftdi_setrts(d->ftdi, state);
20b1459a
TJ
245}
246
247int Context::set_latency(unsigned char latency)
248{
cdf448f6 249 return ftdi_set_latency_timer(d->ftdi, latency);
20b1459a
TJ
250}
251
252unsigned Context::latency()
253{
cdf448f6
TJ
254 unsigned char latency = 0;
255 ftdi_get_latency_timer(d->ftdi, &latency);
256 return latency;
20b1459a
TJ
257}
258
259unsigned short Context::poll_modem_status()
260{
cdf448f6
TJ
261 unsigned short status = 0;
262 ftdi_poll_modem_status(d->ftdi, &status);
263 return status;
20b1459a
TJ
264}
265
20b1459a
TJ
266int Context::set_event_char(unsigned char eventch, unsigned char enable)
267{
cdf448f6 268 return ftdi_set_event_char(d->ftdi, eventch, enable);
20b1459a
TJ
269}
270
271int Context::set_error_char(unsigned char errorch, unsigned char enable)
272{
cdf448f6 273 return ftdi_set_error_char(d->ftdi, errorch, enable);
20b1459a
TJ
274}
275
20b1459a
TJ
276int Context::set_bitmode(unsigned char bitmask, unsigned char mode)
277{
c2ed8c4e 278 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
58cce2d4
GE
279}
280
281int Context::set_bitmode(unsigned char bitmask, enum ftdi_mpsse_mode mode)
282{
cdf448f6 283 return ftdi_set_bitmode(d->ftdi, bitmask, mode);
20b1459a
TJ
284}
285
2d790e37
TJ
286int Context::bitbang_disable()
287{
288 return ftdi_disable_bitbang(d->ftdi);
289}
290
20b1459a
TJ
291int Context::read_pins(unsigned char *pins)
292{
cdf448f6 293 return ftdi_read_pins(d->ftdi, pins);
20b1459a
TJ
294}
295
296char* Context::error_string()
297{
cdf448f6 298 return ftdi_get_error_string(d->ftdi);
20b1459a
TJ
299}
300
301int Context::get_strings()
302{
cdf448f6
TJ
303 // Prepare buffers
304 char vendor[512], desc[512], serial[512];
305
306 int ret = ftdi_usb_get_strings(d->ftdi, d->dev, vendor, 512, desc, 512, serial, 512);
307
308 if (ret < 0)
309 return -1;
20b1459a 310
cdf448f6
TJ
311 d->vendor = vendor;
312 d->description = desc;
313 d->serial = serial;
20b1459a 314
cdf448f6 315 return 1;
20b1459a
TJ
316}
317
58cce2d4
GE
318int Context::get_strings_and_reopen()
319{
d3af9b2c
PS
320 if ( d->dev == 0 )
321 {
322 d->dev = libusb_get_device(d->ftdi->usb_dev);
323 }
324
58cce2d4
GE
325 // Get device strings (closes device)
326 int ret=get_strings();
327 if (ret < 0)
328 {
329 d->open = 0;
330 return ret;
331 }
332
333 // Reattach device
334 ret = ftdi_usb_open_dev(d->ftdi, d->dev);
335 d->open = (ret >= 0);
336
337 return ret;
338}
339
1bbaf1ce 340/*! \brief Device strings properties.
20b1459a
TJ
341 */
342const std::string& Context::vendor()
343{
cdf448f6 344 return d->vendor;
20b1459a
TJ
345}
346
1bbaf1ce
JP
347/*! \brief Device strings properties.
348 */
20b1459a
TJ
349const std::string& Context::description()
350{
cdf448f6 351 return d->description;
20b1459a
TJ
352}
353
1bbaf1ce
JP
354/*! \brief Device strings properties.
355 */
20b1459a
TJ
356const std::string& Context::serial()
357{
cdf448f6 358 return d->serial;
20b1459a
TJ
359}
360
361void Context::set_context(struct ftdi_context* context)
362{
cdf448f6
TJ
363 ftdi_free(d->ftdi);
364 d->ftdi = context;
20b1459a
TJ
365}
366
579b006f 367void Context::set_usb_device(struct libusb_device *dev)
20b1459a 368{
cdf448f6 369 d->dev = dev;
20b1459a
TJ
370}
371
372struct ftdi_context* Context::context()
373{
cdf448f6 374 return d->ftdi;
20b1459a
TJ
375}
376
377class Eeprom::Private
378{
cdf448f6
TJ
379public:
380 Private()
381 : context(0)
382 {}
20b1459a 383
cdf448f6
TJ
384 struct ftdi_eeprom eeprom;
385 struct ftdi_context* context;
20b1459a
TJ
386};
387
388Eeprom::Eeprom(Context* parent)
cdf448f6 389 : d ( new Private() )
20b1459a 390{
cdf448f6 391 d->context = parent->context();
20b1459a
TJ
392}
393
394Eeprom::~Eeprom()
395{
20b1459a
TJ
396}
397
f14f84d3 398int Eeprom::init_defaults(char* manufacturer, char *product, char * serial)
20b1459a 399{
74e8e79d 400 return ftdi_eeprom_initdefaults(d->context, manufacturer, product, serial);
20b1459a
TJ
401}
402
20b1459a
TJ
403int Eeprom::chip_id(unsigned int *chipid)
404{
cdf448f6 405 return ftdi_read_chipid(d->context, chipid);
20b1459a
TJ
406}
407
408int Eeprom::build(unsigned char *output)
409{
a35aa9bd 410 return ftdi_eeprom_build(d->context);
20b1459a
TJ
411}
412
413int Eeprom::read(unsigned char *eeprom)
414{
a35aa9bd 415 return ftdi_read_eeprom(d->context);
20b1459a
TJ
416}
417
418int Eeprom::write(unsigned char *eeprom)
419{
a35aa9bd 420 return ftdi_write_eeprom(d->context);
20b1459a
TJ
421}
422
449c87a9
TJ
423int Eeprom::read_location(int eeprom_addr, unsigned short *eeprom_val)
424{
425 return ftdi_read_eeprom_location(d->context, eeprom_addr, eeprom_val);
426}
427
428int Eeprom::write_location(int eeprom_addr, unsigned short eeprom_val)
429{
430 return ftdi_write_eeprom_location(d->context, eeprom_addr, eeprom_val);
431}
432
20b1459a
TJ
433int Eeprom::erase()
434{
cdf448f6 435 return ftdi_erase_eeprom(d->context);
20b1459a
TJ
436}
437
438class List::Private
439{
cdf448f6 440public:
6b22a054
MV
441 Private(struct ftdi_device_list* _devlist)
442 : devlist(_devlist)
cdf448f6 443 {}
20b1459a 444
cfceadbc
MV
445 ~Private()
446 {
6b22a054
MV
447 if(devlist)
448 ftdi_list_free(&devlist);
cfceadbc
MV
449 }
450
6b22a054
MV
451 std::list<Context> list;
452 struct ftdi_device_list* devlist;
20b1459a
TJ
453};
454
455List::List(struct ftdi_device_list* devlist)
6b22a054 456 : d( new Private(devlist) )
20b1459a 457{
cdf448f6
TJ
458 if (devlist != 0)
459 {
460 // Iterate list
6b22a054 461 for (; devlist != 0; devlist = devlist->next)
cdf448f6 462 {
cfceadbc 463 Context c;
6b22a054 464 c.set_usb_device(devlist->dev);
cfceadbc 465 c.get_strings();
6b22a054 466 d->list.push_back(c);
cdf448f6 467 }
cdf448f6 468 }
20b1459a
TJ
469}
470
471List::~List()
472{
20b1459a
TJ
473}
474
a14193ac
TJ
475/**
476* Return begin iterator for accessing the contained list elements
477* @return Iterator
478*/
479List::iterator List::begin()
6b22a054 480{
a14193ac 481 return d->list.begin();
6b22a054
MV
482}
483
a14193ac
TJ
484/**
485* Return end iterator for accessing the contained list elements
486* @return Iterator
487*/
488List::iterator List::end()
489{
490 return d->list.end();
491}
492
493/**
494* Return begin iterator for accessing the contained list elements
495* @return Const iterator
496*/
497List::const_iterator List::begin() const
6b22a054 498{
a14193ac 499 return d->list.begin();
6b22a054
MV
500}
501
a14193ac
TJ
502/**
503* Return end iterator for accessing the contained list elements
504* @return Const iterator
505*/
506List::const_iterator List::end() const
507{
508 return d->list.end();
509}
6b22a054 510
a14193ac
TJ
511/**
512* Return begin reverse iterator for accessing the contained list elements
513* @return Reverse iterator
514*/
515List::reverse_iterator List::rbegin()
6b22a054 516{
a14193ac 517 return d->list.rbegin();
6b22a054
MV
518}
519
a14193ac
TJ
520/**
521* Return end reverse iterator for accessing the contained list elements
522* @return Reverse iterator
523*/
524List::reverse_iterator List::rend()
525{
526 return d->list.rend();
527}
528
529/**
530* Return begin reverse iterator for accessing the contained list elements
531* @return Const reverse iterator
532*/
533List::const_reverse_iterator List::rbegin() const
534{
535 return d->list.rbegin();
536}
537
538/**
539* Return end reverse iterator for accessing the contained list elements
540* @return Const reverse iterator
541*/
542List::const_reverse_iterator List::rend() const
543{
544 return d->list.rend();
545
546}
547
548/**
549* Get number of elements stored in the list
550* @return Number of elements
551*/
552List::ListType::size_type List::size() const
553{
554 return d->list.size();
555}
556
557/**
558* Check if list is empty
559* @return True if empty, false otherwise
560*/
561bool List::empty() const
562{
563 return d->list.empty();
564}
565
566/**
567 * Removes all elements. Invalidates all iterators.
568 * Do it in a non-throwing way and also make
569 * sure we really free the allocated memory.
570 */
6b22a054
MV
571void List::clear()
572{
a14193ac 573 ListType().swap(d->list);
6b22a054
MV
574
575 // Free device list
a14193ac
TJ
576 if (d->devlist)
577 {
578 ftdi_list_free(&d->devlist);
579 d->devlist = 0;
580 }
6b22a054
MV
581}
582
a14193ac
TJ
583/**
584 * Appends a copy of the element as the new last element.
585 * @param element Value to copy and append
586*/
587void List::push_back(const Context& element)
6b22a054 588{
a14193ac 589 d->list.push_back(element);
6b22a054
MV
590}
591
a14193ac
TJ
592/**
593 * Adds a copy of the element as the new first element.
594 * @param element Value to copy and add
595*/
596void List::push_front(const Context& element)
6b22a054 597{
a14193ac 598 d->list.push_front(element);
6b22a054
MV
599}
600
a14193ac
TJ
601/**
602 * Erase one element pointed by iterator
603 * @param pos Element to erase
604 * @return Position of the following element (or end())
605*/
606List::iterator List::erase(iterator pos)
607{
608 return d->list.erase(pos);
609}
610
611/**
612 * Erase a range of elements
613 * @param beg Begin of range
614 * @param end End of range
615 * @return Position of the element after the erased range (or end())
616*/
617List::iterator List::erase(iterator beg, iterator end)
618{
619 return d->list.erase(beg, end);
620}
6b22a054 621
7c21beca 622List* List::find_all(Context &context, int vendor, int product)
20b1459a 623{
cdf448f6 624 struct ftdi_device_list* dlist = 0;
7c21beca 625 ftdi_usb_find_all(context.context(), &dlist, vendor, product);
cdf448f6 626 return new List(dlist);
20b1459a
TJ
627}
628
629}