Commit bf44e21ad6728c825ed4e28fceba190a68435ab0
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.
Showing
10 changed files
with
113 additions
and
72 deletions
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 &algorithm, const QString &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 &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 "C" { |
| 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<QRectF> 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 | }; | ... | ... |