"Fossies" - the Fresh Open Source Software Archive

Member "libgphoto2-2.5.27/libgphoto2/gphoto2-abilities-list.c" (31 Jan 2021, 16934 Bytes) of package /linux/privat/libgphoto2-2.5.27.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gphoto2-abilities-list.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.5.26_vs_2.5.27.

    1 /** \file gphoto2-abilities-list.c
    2  * \brief List of supported camera models including their abilities.
    3  *
    4  * \author Copyright 2000 Scott Fritzinger
    5  *
    6  * \par
    7  * This library is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU Lesser 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  * \par
   13  * This library is distributed in the hope that it will be useful,
   14  * but 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.
   17  *
   18  * \par
   19  * You should have received a copy of the GNU Lesser General Public
   20  * License along with this library; if not, write to the
   21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   22  * Boston, MA  02110-1301  USA
   23  */
   24 #define _DARWIN_C_SOURCE
   25 
   26 #include "config.h"
   27 #include <gphoto2/gphoto2-abilities-list.h>
   28 
   29 #include <stdlib.h>
   30 #include <stdio.h>
   31 #include <string.h>
   32 
   33 #include <ltdl.h>
   34 
   35 #include <gphoto2/gphoto2-result.h>
   36 #include <gphoto2/gphoto2-port-log.h>
   37 #include <gphoto2/gphoto2-library.h>
   38 
   39 #ifdef ENABLE_NLS
   40 #  include <libintl.h>
   41 #  undef _
   42 #  define _(String) dgettext (GETTEXT_PACKAGE, String)
   43 #  ifdef gettext_noop
   44 #    define N_(String) gettext_noop (String)
   45 #  else
   46 #    define N_(String) (String)
   47 #  endif
   48 #else
   49 #  define textdomain(String) (String)
   50 #  define gettext(String) (String)
   51 #  define dgettext(Domain,Message) (Message)
   52 #  define dcgettext(Domain,Message,Type) (Message)
   53 #  define bindtextdomain(Domain,Directory) (Domain)
   54 #  define bind_textdomain_codeset(Domain,Charset) (Domain)
   55 #  define _(String) (String)
   56 #  define N_(String) (String)
   57 #endif
   58 
   59 /** \internal */
   60 #define CHECK_RESULT(result) {int r = (result); if (r < 0) return (r);}
   61 
   62 /** \internal */
   63 struct _CameraAbilitiesList {
   64     int count;
   65     int maxcount;
   66     CameraAbilities *abilities;
   67 };
   68 
   69 /** \internal */
   70 static int gp_abilities_list_lookup_id (CameraAbilitiesList *, const char *);
   71 /** \internal */
   72 static int gp_abilities_list_sort      (CameraAbilitiesList *);
   73 
   74 /**
   75  * \brief Set the current character codeset libgphoto2 is operating in.
   76  *
   77  * Set the codeset for all messages returned by libgphoto2.
   78  * \param codeset New codeset for the messages. For instance "utf-8".
   79  * \return old codeset as returned from bind_textdomain_codeset().
   80  *
   81  * You would then call gp_abilities_list_load() in order to
   82  * populate it.
   83  */
   84 const char*
   85 gp_message_codeset (const char *codeset)
   86 {
   87     gp_port_message_codeset (codeset);
   88     return bind_textdomain_codeset (GETTEXT_PACKAGE, codeset);
   89 }
   90 
   91 /**
   92  * \brief Allocate the memory for a new abilities list.
   93  *
   94  * Function to allocate the memory for a new abilities list.
   95  * \param list CameraAbilitiesList object to initialize
   96  * \return gphoto2 error code
   97  *
   98  * You would then call gp_abilities_list_load() in order to
   99  * populate it.
  100  */
  101 int
  102 gp_abilities_list_new (CameraAbilitiesList **list)
  103 {
  104     C_PARAMS (list);
  105 
  106     /*
  107      * We do this here because everybody needs to call this function
  108      * first before accessing a camera. Pretty ugly, but I don't know
  109      * an other way without introducing a global initialization
  110      * function...
  111      */
  112     bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
  113 
  114     C_MEM (*list = calloc (1, sizeof (CameraAbilitiesList)));
  115 
  116     return (GP_OK);
  117 }
  118 
  119 /**
  120  * \brief Free the given CameraAbilitiesList object.
  121  *
  122  * \param list a CameraAbilitiesList
  123  * \return a gphoto2 error code
  124  */
  125 int
  126 gp_abilities_list_free (CameraAbilitiesList *list)
  127 {
  128     C_PARAMS (list);
  129 
  130     CHECK_RESULT (gp_abilities_list_reset (list));
  131 
  132     free (list);
  133 
  134     return (GP_OK);
  135 }
  136 
  137 
  138 typedef struct {
  139     CameraList *list;
  140     int result;
  141 } foreach_data_t;
  142 
  143 
  144 static int
  145 foreach_func (const char *filename, lt_ptr data)
  146 {
  147     foreach_data_t *fd = data;
  148     CameraList *list = fd->list;
  149 
  150     GP_LOG_D ("Found '%s'.", filename);
  151     fd->result = gp_list_append (list, filename, NULL);
  152 
  153     return ((fd->result == GP_OK)?0:1);
  154 }
  155 
  156 
  157 int
  158 gp_abilities_list_load_dir (CameraAbilitiesList *list, const char *dir,
  159                 GPContext *context)
  160 {
  161     CameraLibraryIdFunc id;
  162     CameraLibraryAbilitiesFunc ab;
  163     CameraText text;
  164     int ret, x, old_count, new_count;
  165     int i, p;
  166     const char *filename;
  167     CameraList *flist;
  168     int count;
  169     lt_dlhandle lh;
  170 
  171     C_PARAMS (list && dir);
  172 
  173     GP_LOG_D ("Using ltdl to load camera libraries from '%s'...", dir);
  174     CHECK_RESULT (gp_list_new (&flist));
  175     ret = gp_list_reset (flist);
  176     if (ret < GP_OK) {
  177         gp_list_free (flist);
  178         return ret;
  179     }
  180     if (1) { /* a new block in which we can define a temporary variable */
  181         foreach_data_t foreach_data = { NULL, GP_OK };
  182         foreach_data.list = flist;
  183         lt_dlinit ();
  184         lt_dladdsearchdir (dir);
  185         ret = lt_dlforeachfile (dir, foreach_func, &foreach_data);
  186         lt_dlexit ();
  187         if (ret != 0) {
  188             gp_list_free (flist);
  189             GP_LOG_E ("Internal error looking for camlibs (%d)", ret);
  190             gp_context_error (context,
  191                       _("Internal error looking for camlibs. "
  192                         "(path names too long?)"));
  193             return (foreach_data.result!=GP_OK)?foreach_data.result:GP_ERROR;
  194         }
  195     }
  196     count = gp_list_count (flist);
  197     if (count < GP_OK) {
  198         gp_list_free (flist);
  199         return ret;
  200     }
  201     GP_LOG_D ("Found %i camera drivers.", count);
  202     lt_dlinit ();
  203     p = gp_context_progress_start (context, count,
  204         _("Loading camera drivers from '%s'..."), dir);
  205     for (i = 0; i < count; i++) {
  206         ret = gp_list_get_name (flist, i, &filename);
  207         if (ret < GP_OK) {
  208             gp_list_free (flist);
  209             return ret;
  210         }
  211         lh = lt_dlopenext (filename);
  212         if (!lh) {
  213             GP_LOG_D ("Failed to load '%s': %s.", filename,
  214                 lt_dlerror ());
  215             continue;
  216         }
  217 
  218         /* camera_id */
  219         id = lt_dlsym (lh, "camera_id");
  220         if (!id) {
  221             GP_LOG_D ("Library '%s' does not seem to "
  222                 "contain a camera_id function: %s",
  223                 filename, lt_dlerror ());
  224             lt_dlclose (lh);
  225             continue;
  226         }
  227 
  228         /*
  229          * Make sure the camera driver hasn't been
  230          * loaded yet.
  231          */
  232         if (id (&text) != GP_OK) {
  233             lt_dlclose (lh);
  234             continue;
  235         }
  236         if (gp_abilities_list_lookup_id (list, text.text) >= 0) {
  237             lt_dlclose (lh);
  238             continue;
  239         }
  240 
  241         /* camera_abilities */
  242         ab = lt_dlsym (lh, "camera_abilities");
  243         if (!ab) {
  244             GP_LOG_D ("Library '%s' does not seem to "
  245                 "contain a camera_abilities function: "
  246                 "%s", filename, lt_dlerror ());
  247             lt_dlclose (lh);
  248             continue;
  249         }
  250 
  251         old_count = gp_abilities_list_count (list);
  252         if (old_count < 0) {
  253             lt_dlclose (lh);
  254             continue;
  255         }
  256 
  257         if (ab (list) != GP_OK) {
  258             lt_dlclose (lh);
  259             continue;
  260         }
  261 
  262         /* do not free the library in valgrind mode */
  263 #if !defined(VALGRIND)
  264         lt_dlclose (lh);
  265 #endif
  266 
  267         new_count = gp_abilities_list_count (list);
  268         if (new_count < 0)
  269             continue;
  270 
  271         /* Copy in the core-specific information */
  272         for (x = old_count; x < new_count; x++) {
  273             strcpy (list->abilities[x].id, text.text);
  274             strcpy (list->abilities[x].library, filename);
  275         }
  276 
  277         gp_context_progress_update (context, p, i);
  278         if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) {
  279             lt_dlexit ();
  280             gp_list_free (flist);
  281             return (GP_ERROR_CANCEL);
  282         }
  283     }
  284     gp_context_progress_stop (context, p);
  285     lt_dlexit ();
  286     gp_list_free (flist);
  287 
  288     return (GP_OK);
  289 }
  290 
  291 
  292 /**
  293  * \brief Scans the system for camera drivers.
  294  *
  295  * \param list a CameraAbilitiesList
  296  * \param context a GPContext
  297  * \return a gphoto2 error code
  298  *
  299  * All supported camera models will then be added to the list.
  300  *
  301  */
  302 int
  303 gp_abilities_list_load (CameraAbilitiesList *list, GPContext *context)
  304 {
  305     const char *camlib_env = getenv(CAMLIBDIR_ENV);
  306     const char *camlibs = (camlib_env != NULL)?camlib_env:CAMLIBS;
  307     C_PARAMS (list);
  308 
  309     CHECK_RESULT (gp_abilities_list_load_dir (list, camlibs, context));
  310     CHECK_RESULT (gp_abilities_list_sort (list));
  311 
  312     return (GP_OK);
  313 }
  314 
  315 
  316 static int
  317 gp_abilities_list_detect_usb (CameraAbilitiesList *list,
  318                   int *ability, GPPort *port)
  319 {
  320     int i, count, res = GP_ERROR_IO_USB_FIND;
  321 
  322     CHECK_RESULT (count = gp_abilities_list_count (list));
  323 
  324     /* Detect USB cameras */
  325     GP_LOG_D ("Auto-detecting USB cameras...");
  326     *ability = -1;
  327     for (i = 0; i < count; i++) {
  328         int v, p, c, s;
  329 
  330         if (!(list->abilities[i].port & port->type))
  331             continue;
  332 
  333         v = list->abilities[i].usb_vendor;
  334         p = list->abilities[i].usb_product;
  335         if (v) {
  336             res = gp_port_usb_find_device(port, v, p);
  337             if (res == GP_OK) {
  338                 GP_LOG_D ("Found '%s' (0x%x,0x%x)",
  339                     list->abilities[i].model, v, p);
  340                 *ability = i;
  341             } else if (res < 0 && res != GP_ERROR_IO_USB_FIND) {
  342                 /* another error occurred.
  343                  * perhaps we should better
  344                  * report this to the calling
  345                  * method?
  346                  */
  347                 GP_LOG_D (
  348                     "gp_port_usb_find_device(vendor=0x%x, "
  349                     "product=0x%x) returned %i, clearing "
  350                     "error message on port", v, p, res);
  351             }
  352 
  353             if (res != GP_ERROR_IO_USB_FIND)
  354                 return res;
  355         }
  356 
  357         c = list->abilities[i].usb_class;
  358         s = list->abilities[i].usb_subclass;
  359         p = list->abilities[i].usb_protocol;
  360         if (c) {
  361             res = gp_port_usb_find_device_by_class(port, c, s, p);
  362             if (res == GP_OK) {
  363                 GP_LOG_D ("Found '%s' (0x%x,0x%x,0x%x)",
  364                     list->abilities[i].model, c, s, p);
  365                 *ability = i;
  366             } else if (res < 0 && res != GP_ERROR_IO_USB_FIND) {
  367                 /* another error occurred.
  368                  * perhaps we should better
  369                  * report this to the calling
  370                  * method?
  371                  */
  372                 GP_LOG_D (
  373                     "gp_port_usb_find_device_by_class("
  374                     "class=0x%x, subclass=0x%x, "
  375                     "protocol=0x%x) returned %i, "
  376                     "clearing error message on port",
  377                     c, s, p, res);
  378             }
  379 
  380             if (res != GP_ERROR_IO_USB_FIND)
  381                 return res;
  382         }
  383     }
  384 
  385     return res;
  386 }
  387 
  388 
  389 /**
  390  * \param list a CameraAbilitiesList
  391  * \param info_list the GPPortInfoList of ports to use for detection
  392  * \param l a #CameraList that contains the autodetected cameras after the call
  393  * \param context a #GPContext
  394  *
  395  * Tries to detect any camera connected to the computer using the supplied
  396  * list of supported cameras and the supplied info_list of ports.
  397  *
  398  * \return a gphoto2 error code
  399  */
  400 int
  401 gp_abilities_list_detect (CameraAbilitiesList *list,
  402               GPPortInfoList *info_list, CameraList *l,
  403               GPContext *context)
  404 {
  405     GPPortInfo info;
  406     GPPort *port;
  407     int i, info_count;
  408 
  409     C_PARAMS (list && info_list && l);
  410 
  411     gp_list_reset (l);
  412 
  413     CHECK_RESULT (info_count = gp_port_info_list_count (info_list));
  414 
  415     CHECK_RESULT (gp_port_new (&port));
  416     for (i = 0; i < info_count; i++) {
  417         int res;
  418         char *xpath;
  419         GPPortType  type;
  420 
  421         CHECK_RESULT (gp_port_info_list_get_info (info_list, i, &info));
  422         CHECK_RESULT (gp_port_set_info (port, info));
  423         gp_port_info_get_type (info, &type);
  424         res = gp_port_info_get_path (info, &xpath);
  425         if (res <GP_OK)
  426             continue;
  427         switch (type) {
  428         case GP_PORT_USB:
  429         case GP_PORT_USB_SCSI:
  430         case GP_PORT_USB_DISK_DIRECT: {
  431             int ability;
  432 
  433             res = gp_abilities_list_detect_usb (list, &ability, port);
  434             if (res == GP_OK) {
  435                 gp_list_append(l,
  436                     list->abilities[ability].model,
  437                     xpath);
  438             } else if (res < 0)
  439                 gp_port_set_error (port, NULL);
  440 
  441             break;
  442         }
  443         case GP_PORT_DISK: {
  444             char    *s, path[1024];
  445             struct stat stbuf;
  446 
  447             s = strchr (xpath, ':');
  448             if (!s)
  449                 break;
  450             s++;
  451             snprintf (path, sizeof(path), "%s/DCIM", s);
  452             if (-1 == stat(path, &stbuf)) {
  453                 snprintf (path, sizeof(path), "%s/dcim", s);
  454                 if (-1 == stat(path, &stbuf))
  455                     continue;
  456             }
  457             gp_list_append (l, "Mass Storage Camera", xpath);
  458             break;
  459         }
  460         case GP_PORT_PTPIP: {
  461             char    *s;
  462 
  463             s = strchr (xpath, ':');
  464             if (!s) break;
  465             s++;
  466             if (!strlen(s)) break;
  467             gp_list_append (l, "PTP/IP Camera", xpath);
  468             break;
  469         }
  470         default:
  471             /*
  472              * We currently cannot detect any cameras on this
  473              * port
  474              */
  475             break;
  476         }
  477     }
  478 
  479     gp_port_free (port);
  480 
  481     return (GP_OK);
  482 }
  483 
  484 
  485 /**
  486  * \brief Remove first colon from string, if any. Replace it by a space.
  487  * \param str a char * string
  488  */
  489 static void
  490 remove_colon_from_string (char *str)
  491 {
  492     char *ch;
  493     ch = strchr(str, ':');
  494     if (ch) {
  495         *ch = ' ';
  496     }
  497 }
  498 
  499 
  500 /**
  501  * \brief Append the abilities to the list.
  502  * \param list  CameraAbilitiesList
  503  * \param abilities  CameraAbilities
  504  * \return a gphoto2 error code
  505  *
  506  * This function is called by a camera library on camera_abilities()
  507  * in order to inform libgphoto2 about a supported camera model.
  508  *
  509  */
  510 int
  511 gp_abilities_list_append (CameraAbilitiesList *list, CameraAbilities abilities)
  512 {
  513     C_PARAMS (list);
  514 
  515     if (list->count == list->maxcount) {
  516         C_MEM (list->abilities = realloc (list->abilities,
  517                 sizeof (CameraAbilities) * (list->maxcount + 100)));
  518         list->maxcount += 100;
  519     }
  520 
  521     memcpy (&(list->abilities [list->count]), &abilities,
  522         sizeof (CameraAbilities));
  523 
  524     /* FIXME: We replace the colon by a space in the model string
  525      *        This keeps backward compatibility until we have
  526      *        thought of and implemented something better.
  527      */
  528     remove_colon_from_string(list->abilities[list->count].model);
  529 
  530     list->count++;
  531 
  532     return (GP_OK);
  533 }
  534 
  535 
  536 /**
  537  * \brief Reset the list.
  538  * \param list a CameraAbilitiesList
  539  * \return a gphoto2 error code
  540  */
  541 int
  542 gp_abilities_list_reset (CameraAbilitiesList *list)
  543 {
  544     C_PARAMS (list);
  545 
  546     free (list->abilities);
  547     list->abilities = NULL;
  548     list->count = 0;
  549     list->maxcount = 0;
  550 
  551     return (GP_OK);
  552 }
  553 
  554 
  555 /**
  556  * \brief Count the entries in the supplied list.
  557  * \param list a #CameraAbilitiesList
  558  * \returns The number of entries or a gphoto2 error code
  559  */
  560 int
  561 gp_abilities_list_count (CameraAbilitiesList *list)
  562 {
  563     C_PARAMS (list);
  564 
  565     return (list->count);
  566 }
  567 
  568 static int
  569 cmp_abilities (const void *a, const void *b) {
  570     const CameraAbilities *ca = a;
  571     const CameraAbilities *cb = b;
  572 
  573     return strcasecmp (ca->model, cb->model);
  574 }
  575 
  576 static int
  577 gp_abilities_list_sort (CameraAbilitiesList *list)
  578 {
  579     C_PARAMS (list);
  580 
  581     qsort (list->abilities, list->count, sizeof(CameraAbilities), cmp_abilities);
  582     return (GP_OK);
  583 }
  584 
  585 
  586 static int
  587 gp_abilities_list_lookup_id (CameraAbilitiesList *list, const char *id)
  588 {
  589     int x;
  590 
  591     C_PARAMS (list && id);
  592 
  593     for (x = 0; x < list->count; x++)
  594         if (!strcmp (list->abilities[x].id, id))
  595             return (x);
  596 
  597     return (GP_ERROR);
  598 }
  599 
  600 
  601 /**
  602  * \brief Search the list for an entry of given model name
  603  * \param list a #CameraAbilitiesList
  604  * \param model a camera model name
  605  * \return Index of entry or gphoto2 error code
  606  */
  607 int
  608 gp_abilities_list_lookup_model (CameraAbilitiesList *list, const char *model)
  609 {
  610     int x;
  611 
  612     C_PARAMS (list && model);
  613 
  614     for (x = 0; x < list->count; x++) {
  615         if (!strcasecmp (list->abilities[x].model, model))
  616             return (x);
  617     }
  618 
  619     GP_LOG_E ("Could not find any driver for '%s'", model);
  620     return (GP_ERROR_MODEL_NOT_FOUND);
  621 }
  622 
  623 
  624 /**
  625  * \brief Retrieve the camera abilities of entry with supplied index number.
  626  *
  627  * \param list a CameraAbilitiesList
  628  * \param index index
  629  * \param abilities pointer to CameraAbilities for returned data.
  630  * \return a gphoto2 error code
  631  *
  632  * Retrieves the camera abilities of entry with supplied
  633  * index number. Typically, you would call gp_camera_set_abilities()
  634  * afterwards in order to prepare the initialization of a camera.
  635  */
  636 int
  637 gp_abilities_list_get_abilities (CameraAbilitiesList *list, int index,
  638                  CameraAbilities *abilities)
  639 {
  640     C_PARAMS (list && abilities);
  641     C_PARAMS (0 <= index && index < list->count);
  642 
  643     memcpy (abilities, &list->abilities[index], sizeof (CameraAbilities));
  644 
  645     return (GP_OK);
  646 }
  647 
  648 
  649 #ifdef _GPHOTO2_INTERNAL_CODE
  650 
  651 /* enum CameraOperation */
  652 const StringFlagItem gpi_camera_operation_map[] = {
  653     { "none",            GP_OPERATION_NONE },
  654     { "capture_image",   GP_OPERATION_CAPTURE_IMAGE },
  655     { "capture_video",   GP_OPERATION_CAPTURE_VIDEO },
  656     { "capture_audio",   GP_OPERATION_CAPTURE_AUDIO },
  657     { "capture_preview", GP_OPERATION_CAPTURE_PREVIEW },
  658     { "config",          GP_OPERATION_CONFIG },
  659     { NULL, 0 },
  660 };
  661 
  662 /* enum CameraFileOperation */
  663 const StringFlagItem gpi_file_operation_map[] = {
  664     { "none",    GP_FILE_OPERATION_NONE },
  665     { "delete",  GP_FILE_OPERATION_DELETE },
  666     { "preview", GP_FILE_OPERATION_PREVIEW },
  667     { "raw",     GP_FILE_OPERATION_RAW },
  668     { "audio",   GP_FILE_OPERATION_AUDIO },
  669     { "exif",    GP_FILE_OPERATION_EXIF },
  670     { NULL, 0 },
  671 };
  672 
  673 /* enum CameraFolderOperation */
  674 const StringFlagItem gpi_folder_operation_map[] = {
  675     { "none",       GP_FOLDER_OPERATION_NONE },
  676     { "delete_all", GP_FOLDER_OPERATION_DELETE_ALL },
  677     { "put_file",   GP_FOLDER_OPERATION_PUT_FILE },
  678     { "make_dir",   GP_FOLDER_OPERATION_MAKE_DIR },
  679     { "remove_dir", GP_FOLDER_OPERATION_REMOVE_DIR },
  680     { NULL, 0 },
  681 };
  682 
  683 /* enum GphotoDeviceType */
  684 const StringFlagItem gpi_gphoto_device_type_map[] = {
  685     { "still_camera", GP_DEVICE_STILL_CAMERA },
  686     { "audio_player", GP_DEVICE_AUDIO_PLAYER },
  687     { NULL, 0 },
  688 };
  689 
  690 /* enum CameraDriverStatus */
  691 const StringFlagItem gpi_camera_driver_status_map[] = {
  692     { "production",   GP_DRIVER_STATUS_PRODUCTION },
  693     { "testing",      GP_DRIVER_STATUS_TESTING },
  694     { "experimental", GP_DRIVER_STATUS_EXPERIMENTAL },
  695     { "deprecated",   GP_DRIVER_STATUS_DEPRECATED },
  696     { NULL, 0 },
  697 };
  698 
  699 #endif /* _GPHOTO2_INTERNAL_CODE */
  700 
  701 
  702 /*
  703  * Local Variables:
  704  * c-file-style:"linux"
  705  * indent-tabs-mode:t
  706  * End:
  707  */