Commit bf44e21ad6728c825ed4e28fceba190a68435ab0

Authored by Charles Otto
1 parent 94463713

Update several c-api functions to take string buffers as input

Instead of returning references to static memory (which are invalidated by
subsequent or concurrent calls to the function), require users to input string
buffers to functions that return strings.

Affected functions:
br_get_filename
br_get_metadata_string
br_scratch_path
br_objects
br_most_recent_message

In some GUI functions, use C++ functions instead of going through the c api
add a c++ method correspondign to br_objects (which returns a stringlist
instead of merging the lines)

br_read_pipe and br_get_header also use static memory in a similar way, but
are not addressed in this commit.
app/br/br.cpp
... ... @@ -171,7 +171,11 @@ public:
171 171 // Do nothing because we checked for this flag prior to initialization
172 172 } else if (!strcmp(fun, "objects")) {
173 173 check(parc <= 2, "Incorrect parameter count for 'objects'.");
174   - printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*"));
  174 + int size = br_objects(NULL, 0, parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*");
  175 + char * temp = new char[size];
  176 + br_objects(temp, size, parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*");
  177 + printf("%s\n", temp);
  178 + delete [] temp;
175 179 } else if (!strcmp(fun, "about")) {
176 180 check(parc == 0, "No parameters expected for 'about'.");
177 181 printf("%s\n", br_about());
... ...
openbr/gui/algorithm.cpp
1 1 #include <QStringList>
2 2 #include <openbr/openbr.h>
  3 +#include <openbr/openbr_plugin.h>
3 4  
4 5 #include "algorithm.h"
5 6  
... ... @@ -18,7 +19,7 @@ bool br::Algorithm::addAlgorithm(const QString &amp;algorithm, const QString &amp;displa
18 19 {
19 20 static QStringList availableAlgorithms;
20 21 if (availableAlgorithms.isEmpty())
21   - availableAlgorithms = QString(br_objects("Abbreviation", ".*", false)).split("\n");
  22 + availableAlgorithms = br::Context::objects("Abbreviation", ".*", false);
22 23  
23 24 if (!availableAlgorithms.contains(algorithm))
24 25 return false;
... ...
openbr/gui/gallerytoolbar.cpp
... ... @@ -84,7 +84,7 @@ void br::GalleryToolBar::_enroll(const br::File &amp;input)
84 84 galleryLock.lock();
85 85 this->input = input;
86 86 if (input.suffix() == "gal") gallery = input.name + ".mem";
87   - else gallery = QString("%1/galleries/%2.gal[cache]").arg(br_scratch_path(), qPrintable(input.baseName()+input.hash()));
  87 + else gallery = QString("%1/galleries/%2.gal[cache]").arg(br::Globals->scratchPath(), qPrintable(input.baseName()+input.hash()));
88 88 files = br::Enroll(input.flat(), gallery.flat());
89 89 galleryLock.unlock();
90 90 }
... ... @@ -148,7 +148,7 @@ void br::GalleryToolBar::home()
148 148  
149 149 void br::GalleryToolBar::mean()
150 150 {
151   - const QString file = QString("%1/mean/%2.png").arg(br_scratch_path(), input.baseName()+input.hash());
  151 + const QString file = QString("%1/mean/%2.png").arg(br::Globals->scratchPath(), input.baseName()+input.hash());
152 152 br_set_property("CENTER_TRAIN_B", qPrintable(file));
153 153 br::File trainingFile = input;
154 154 br_train(qPrintable(trainingFile.flat()), "[algorithm=MedianFace]");
... ...
openbr/gui/progress.cpp
1 1 #include <openbr/openbr.h>
  2 +#include <openbr/openbr_plugin.h>
2 3  
3 4 #include "progress.h"
4 5  
... ... @@ -29,7 +30,7 @@ void br::Progress::checkProgress()
29 30 const bool visible = progress >= 0 && progress < 100;
30 31  
31 32 if (visible) {
32   - showMessage(br_most_recent_message());
  33 + showMessage(Globals->mostRecentMessage);
33 34 pbProgress.setValue(progress);
34 35 if (progress > 100) pbProgress.setMaximum(0);
35 36 else pbProgress.setMaximum(100);
... ...
openbr/gui/templateviewer.cpp
... ... @@ -72,7 +72,7 @@ void TemplateViewer::refreshImage()
72 72 if (file.isNull() || (format == "Photo")) {
73 73 setImage(file, true);
74 74 } else {
75   - const QString path = QString(br_scratch_path()) + "/thumbnails";
  75 + const QString path = QString(br::Globals->scratchPath()) + "/thumbnails";
76 76 const QString hash = file.hash()+format;
77 77 const QString processedFile = path+"/"+file.baseName()+hash+".png";
78 78 if (!QFileInfo(processedFile).exists()) {
... ...
openbr/gui/transformeditor.cpp
... ... @@ -24,7 +24,7 @@ using namespace br;
24 24 br::TransformEditor::TransformEditor(Transform *transform, QWidget *parent)
25 25 : QWidget(parent)
26 26 {
27   - name.addItems(QString(br_objects("Transform", ".*", false)).split('\n'));
  27 + name.addItems(br::Context::objects("Transform", ".*", false));
28 28 layout.addWidget(&name);
29 29 setLayout(&layout);
30 30  
... ...
openbr/openbr.cpp
... ... @@ -28,6 +28,21 @@
28 28  
29 29 using namespace br;
30 30  
  31 +static int partialCopy(const QString & string, char * buffer, int buffer_length)
  32 +{
  33 +
  34 + QByteArray byteArray = string.toLocal8Bit();
  35 +
  36 + int copyLength = std::min(buffer_length-1, byteArray.size());
  37 + if (copyLength < 0)
  38 + return byteArray.size() + 1;
  39 +
  40 + memcpy(buffer, byteArray.data(), copyLength);
  41 + buffer[copyLength] = '\0';
  42 +
  43 + return byteArray.size() + 1;
  44 +}
  45 +
31 46 const char *br_about()
32 47 {
33 48 static QMutex aboutLock;
... ... @@ -153,53 +168,14 @@ void br_make_pairwise_mask(const char *target_input, const char *query_input, co
153 168 BEE::makePairwiseMask(target_input, query_input, mask);
154 169 }
155 170  
156   -const char *br_most_recent_message()
  171 +int br_most_recent_message(char * buffer, int buffer_length)
157 172 {
158   - static QByteArray byteArray;
159   - byteArray = Globals->mostRecentMessage.toLocal8Bit();
160   - return byteArray.data();
  173 + return partialCopy(Globals->mostRecentMessage, buffer, buffer_length);
161 174 }
162 175  
163   -const char *br_objects(const char *abstractions, const char *implementations, bool parameters)
  176 +int br_objects(char * buffer, int buffer_length, const char *abstractions, const char *implementations, bool parameters)
164 177 {
165   - static QByteArray objects;
166   -
167   - QStringList objectList;
168   - QRegExp abstractionsRegExp(abstractions);
169   - QRegExp implementationsRegExp(implementations);
170   -
171   - if (abstractionsRegExp.exactMatch("Abbreviation"))
172   - foreach (const QString &name, Globals->abbreviations.keys())
173   - if (implementationsRegExp.exactMatch(name))
174   - objectList.append(name + (parameters ? "\t" + Globals->abbreviations[name] : ""));
175   -
176   - if (abstractionsRegExp.exactMatch("Distance"))
177   - foreach (const QString &name, Factory<Distance>::names())
178   - if (implementationsRegExp.exactMatch(name))
179   - objectList.append(name + (parameters ? "\t" + Factory<Distance>::parameters(name) : ""));
180   -
181   - if (abstractionsRegExp.exactMatch("Format"))
182   - foreach (const QString &name, Factory<Format>::names())
183   - if (implementationsRegExp.exactMatch(name))
184   - objectList.append(name + (parameters ? "\t" + Factory<Format>::parameters(name) : ""));
185   -
186   - if (abstractionsRegExp.exactMatch("Initializer"))
187   - foreach (const QString &name, Factory<Initializer>::names())
188   - if (implementationsRegExp.exactMatch(name))
189   - objectList.append(name + (parameters ? "\t" + Factory<Initializer>::parameters(name) : ""));
190   -
191   - if (abstractionsRegExp.exactMatch("Output"))
192   - foreach (const QString &name, Factory<Output>::names())
193   - if (implementationsRegExp.exactMatch(name))
194   - objectList.append(name + (parameters ? "\t" + Factory<Output>::parameters(name) : ""));
195   -
196   - if (abstractionsRegExp.exactMatch("Transform"))
197   - foreach (const QString &name, Factory<Transform>::names())
198   - if (implementationsRegExp.exactMatch(name))
199   - objectList.append(name + (parameters ? "\t" + Factory<Transform>::parameters(name) : ""));
200   -
201   - objects = objectList.join("\n").toLocal8Bit();
202   - return objects.data();
  178 + return partialCopy(br::Context::objects(abstractions, implementations, parameters).join('\n'), buffer, buffer_length);
203 179 }
204 180  
205 181 bool br_plot(int num_files, const char *files[], const char *destination, bool show)
... ... @@ -254,11 +230,9 @@ void br_read_pipe(const char *pipe, int *argc, char ***argv)
254 230 *argv = rawCharArrayList.data();
255 231 }
256 232  
257   -const char *br_scratch_path()
  233 +int br_scratch_path(char * buffer, int buffer_length)
258 234 {
259   - static QByteArray byteArray;
260   - byteArray = Context::scratchPath().toLocal8Bit();
261   - return byteArray.data();
  235 + return partialCopy(Context::scratchPath(), buffer, buffer_length);
262 236 }
263 237  
264 238 const char *br_sdk_path()
... ... @@ -387,11 +361,9 @@ bool br_img_is_empty(br_template tmpl)
387 361 return t->m().empty();
388 362 }
389 363  
390   -const char* br_get_filename(br_template tmpl)
  364 +int br_get_filename(br_template tmpl, char * buffer, int buffer_length)
391 365 {
392   - static QByteArray buffer;
393   - buffer = reinterpret_cast<Template*>(tmpl)->file.name.toLocal8Bit();
394   - return buffer.data();
  366 + return partialCopy(reinterpret_cast<Template*>(tmpl)->file.name, buffer, buffer_length);
395 367 }
396 368  
397 369 void br_set_filename(br_template tmpl, const char *filename)
... ... @@ -400,15 +372,11 @@ void br_set_filename(br_template tmpl, const char *filename)
400 372 t->file.name = filename;
401 373 }
402 374  
403   -const char* br_get_metadata_string(br_template tmpl, const char *key)
  375 +int br_get_metadata_string(br_template tmpl, const char *key, char * buffer, int buffer_length)
404 376 {
405 377 Template *t = reinterpret_cast<Template*>(tmpl);
406   - // need an object outside of this scope
407   - // so the char pointer is valid
408   - static QByteArray result;
409 378 QVariant qvar = t->file.value(key);
410   - result = QtUtils::toString(qvar).toUtf8();
411   - return result.data();
  379 + return partialCopy(QtUtils::toString(qvar), buffer, buffer_length);
412 380 }
413 381  
414 382 br_template_list br_enroll_template(br_template tmpl)
... ...
openbr/openbr.h
... ... @@ -41,6 +41,10 @@ extern &quot;C&quot; {
41 41 * \section managed_return_value Managed Return Value
42 42 * Memory for <tt>const char*</tt> return values is managed internally and guaranteed until the next call to the function.
43 43 *
  44 + * \section input_string_buffer Input String Buffer
  45 + * Users should input a char * buffer and the size of that buffer. String data will be copied into the buffer, if the buffer is too
  46 + * small, only part of the string will be copied. Returns the buffer size required to contain the complete string.
  47 + *
44 48 * \section examples Examples
45 49 * - \ref c_face_recognition_evaluation
46 50 *
... ... @@ -255,10 +259,10 @@ BR_EXPORT void br_make_pairwise_mask(const char *target_input, const char *query
255 259  
256 260 /*!
257 261 * \brief Returns the most recent line sent to stderr.
258   - * \note \ref managed_return_value
  262 + * \note \ref input_string_buffer
259 263 * \see br_progress br_time_remaining
260 264 */
261   -BR_EXPORT const char *br_most_recent_message();
  265 +BR_EXPORT int br_most_recent_message(char * buffer, int buffer_length);
262 266  
263 267 /*!
264 268 * \brief Returns names and parameters for the requested objects.
... ... @@ -267,10 +271,10 @@ BR_EXPORT const char *br_most_recent_message();
267 271 * \param abstractions Regular expression of the abstractions to search.
268 272 * \param implementations Regular expression of the implementations to search.
269 273 * \param parameters Include parameters after object name.
270   - * \note \ref managed_return_value
  274 + * \note \ref input_string_buffer
271 275 * \note This function uses Qt's <a href="http://doc.qt.digia.com/stable/qregexp.html">QRegExp</a> syntax.
272 276 */
273   -BR_EXPORT const char *br_objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true);
  277 +BR_EXPORT int br_objects(char * buffer, int buffer_length, const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true);
274 278  
275 279 /*!
276 280 * \brief Renders recognition performance figures for a set of <tt>.csv</tt> files created by \ref br_eval.
... ... @@ -375,9 +379,11 @@ BR_EXPORT void br_read_pipe(const char *pipe, int *argc, char ***argv);
375 379  
376 380 /*!
377 381 * \brief Wraps br::Context::scratchPath()
  382 + * \note \ref input_string_buffer
378 383 * \see br_version
379 384 */
380   -BR_EXPORT const char *br_scratch_path();
  385 +BR_EXPORT int br_scratch_path(char * buffer, int buffer_length);
  386 +
381 387  
382 388 /*!
383 389 * \brief Returns the full path to the root of the SDK.
... ... @@ -433,7 +439,6 @@ BR_EXPORT void br_train_n(int num_inputs, const char *inputs[], const char *mode
433 439  
434 440 /*!
435 441 * \brief Wraps br::Context::version()
436   - * \note \ref managed_return_value
437 442 * \see br_about br_scratch_path
438 443 */
439 444 BR_EXPORT const char *br_version();
... ... @@ -505,16 +510,18 @@ BR_EXPORT int br_img_channels(br_template tmpl);
505 510 BR_EXPORT bool br_img_is_empty(br_template tmpl);
506 511 /*!
507 512 * \brief Get the filename for a br::Template
  513 + * \note \ref input_string_buffer
508 514 */
509   -BR_EXPORT const char* br_get_filename(br_template tmpl);
  515 +BR_EXPORT int br_get_filename(br_template tmpl, char * buffer, int buffer_length);
510 516 /*!
511 517 * \brief Set the filename for a br::Template.
512 518 */
513 519 BR_EXPORT void br_set_filename(br_template tmpl, const char *filename);
514 520 /*!
515 521 * \brief Get metadata as a string for the given key in the given template.
  522 + * \note \ref input_string_buffer
516 523 */
517   -BR_EXPORT const char* br_get_metadata_string(br_template, const char *key);
  524 +BR_EXPORT int br_get_metadata_string(br_template, const char *key, char * buffer, int buffer_length);
518 525 /*!
519 526 * \brief Enroll a br::Template from the C API! Returns a pointer to a br::TemplateList
520 527 * \param tmpl Pointer to a br::Template.
... ...
openbr/openbr_plugin.cpp
... ... @@ -203,6 +203,13 @@ QList&lt;QRectF&gt; File::namedRects() const
203 203 const QVariant &variant = m_metadata[key];
204 204 if (variant.canConvert<QRectF>())
205 205 rects.append(variant.value<QRectF>());
  206 + else if(variant.canConvert<QList<QRectF> >()) {
  207 + QList<QRectF> list = variant.value<QList<QRectF> >();
  208 + for (int i=0;i < list.size();i++)
  209 + {
  210 + rects.append(list[i]);
  211 + }
  212 + }
206 213 }
207 214 return rects;
208 215 }
... ... @@ -1009,6 +1016,47 @@ QString br::Context::scratchPath()
1009 1016 return QString("%1/%2-%3.%4").arg(QDir::homePath(), PRODUCT_NAME, QString::number(PRODUCT_VERSION_MAJOR), QString::number(PRODUCT_VERSION_MINOR));
1010 1017 }
1011 1018  
  1019 +
  1020 +QStringList br::Context::objects(const char *abstractions, const char *implementations, bool parameters)
  1021 +{
  1022 + QStringList objectList;
  1023 + QRegExp abstractionsRegExp(abstractions);
  1024 + QRegExp implementationsRegExp(implementations);
  1025 +
  1026 + if (abstractionsRegExp.exactMatch("Abbreviation"))
  1027 + foreach (const QString &name, Globals->abbreviations.keys())
  1028 + if (implementationsRegExp.exactMatch(name))
  1029 + objectList.append(name + (parameters ? "\t" + Globals->abbreviations[name] : ""));
  1030 +
  1031 + if (abstractionsRegExp.exactMatch("Distance"))
  1032 + foreach (const QString &name, Factory<Distance>::names())
  1033 + if (implementationsRegExp.exactMatch(name))
  1034 + objectList.append(name + (parameters ? "\t" + Factory<Distance>::parameters(name) : ""));
  1035 +
  1036 + if (abstractionsRegExp.exactMatch("Format"))
  1037 + foreach (const QString &name, Factory<Format>::names())
  1038 + if (implementationsRegExp.exactMatch(name))
  1039 + objectList.append(name + (parameters ? "\t" + Factory<Format>::parameters(name) : ""));
  1040 +
  1041 + if (abstractionsRegExp.exactMatch("Initializer"))
  1042 + foreach (const QString &name, Factory<Initializer>::names())
  1043 + if (implementationsRegExp.exactMatch(name))
  1044 + objectList.append(name + (parameters ? "\t" + Factory<Initializer>::parameters(name) : ""));
  1045 +
  1046 + if (abstractionsRegExp.exactMatch("Output"))
  1047 + foreach (const QString &name, Factory<Output>::names())
  1048 + if (implementationsRegExp.exactMatch(name))
  1049 + objectList.append(name + (parameters ? "\t" + Factory<Output>::parameters(name) : ""));
  1050 +
  1051 + if (abstractionsRegExp.exactMatch("Transform"))
  1052 + foreach (const QString &name, Factory<Transform>::names())
  1053 + if (implementationsRegExp.exactMatch(name))
  1054 + objectList.append(name + (parameters ? "\t" + Factory<Transform>::parameters(name) : ""));
  1055 +
  1056 +
  1057 + return objectList;
  1058 +}
  1059 +
1012 1060 void br::Context::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
1013 1061 {
1014 1062 // Something about this method is not thread safe, and will lead to crashes if qDebug
... ...
openbr/openbr_plugin.h
... ... @@ -830,6 +830,18 @@ public:
830 830 */
831 831 static QString scratchPath();
832 832  
  833 + /*!
  834 + * \brief Returns names and parameters for the requested objects.
  835 + *
  836 + * Each object is \c \\n seperated. Arguments are seperated from the object name with a \c \\t.
  837 + * \param abstractions Regular expression of the abstractions to search.
  838 + * \param implementations Regular expression of the implementations to search.
  839 + * \param parameters Include parameters after object name.
  840 + * \note \ref managed_return_value
  841 + * \note This function uses Qt's <a href="http://doc.qt.digia.com/stable/qregexp.html">QRegExp</a> syntax.
  842 + */
  843 + static QStringList objects(const char *abstractions = ".*", const char *implementations = ".*", bool parameters = true);
  844 +
833 845 private:
834 846 static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
835 847 };
... ...