1 /*
2     RawSpeed - RAW file decoder.
3 
4     Copyright (C) 2009-2014 Klaus Post
5 
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Lesser General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10 
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Lesser General Public License for more details.
15 
16     You should have received a copy of the GNU Lesser General Public
17     License along with this library; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
21 #include "metadata/CameraMetaData.h"
22 #include "common/Common.h"                    // for uint32_t, trimSpaces
23 #include "metadata/Camera.h"                  // for Camera
24 #include "metadata/CameraMetadataException.h" // for ThrowCME
25 #include <algorithm>                          // for find_if
26 #include <map>                                // for _Rb_tree_iterator, map
27 #include <string>                             // for string, operator==
28 #include <utility>                            // for pair
29 #include <vector>                             // for vector
30 
31 #ifdef HAVE_PUGIXML
32 #include <pugixml.hpp> // for xml_document, xml_pars...
33 using pugi::xml_node;
34 using pugi::xml_document;
35 using pugi::xml_parse_result;
36 #endif
37 
38 using std::string;
39 
40 namespace rawspeed {
41 
42 #ifdef HAVE_PUGIXML
CameraMetaData(const char * docname)43 CameraMetaData::CameraMetaData(const char *docname) {
44   xml_document doc;
45 
46 #if defined(__unix__) || defined(__APPLE__)
47   xml_parse_result result = doc.load_file(docname);
48 #else
49   xml_parse_result result = doc.load_file(pugi::as_wide(docname).c_str());
50 #endif
51 
52   if (!result) {
53     ThrowCME(
54         "XML Document \"%s\" could not be parsed successfully. Error was: %s in %s",
55         docname, result.description(), doc.child("node").attribute("attr").value());
56   }
57 
58   for (xml_node camera : doc.child("Cameras").children("Camera")) {
59     const auto* cam = addCamera(std::make_unique<Camera>(camera));
60 
61     if (cam == nullptr)
62       continue;
63 
64     // Create cameras for aliases.
65     for (auto i = 0UL; i < cam->aliases.size(); i++) {
66       addCamera(std::make_unique<Camera>(cam, i));
67     }
68   }
69 }
70 #endif
71 
getId(const string & make,const string & model,const string & mode)72 static inline CameraId getId(const string& make, const string& model,
73                              const string& mode) {
74   CameraId id;
75   id.make = trimSpaces(make);
76   id.model = trimSpaces(model);
77   id.mode = trimSpaces(mode);
78 
79   return id;
80 }
81 
getCamera(const string & make,const string & model,const string & mode) const82 const Camera* CameraMetaData::getCamera(const string& make, const string& model,
83                                         const string& mode) const {
84   auto camera = cameras.find(getId(make, model, mode));
85   return camera == cameras.end() ? nullptr : camera->second.get();
86 }
87 
getCamera(const string & make,const string & model) const88 const Camera* CameraMetaData::getCamera(const string& make,
89                                         const string& model) const {
90   auto id = getId(make, model, "");
91 
92   auto iter = find_if(cameras.cbegin(), cameras.cend(),
93                       [&id](decltype(*cameras.cbegin())& i) -> bool {
94                         const auto& cid = i.first;
95                         return tie(id.make, id.model) ==
96                                tie(cid.make, cid.model);
97                       });
98 
99   if (iter == cameras.end())
100     return nullptr;
101 
102   return iter->second.get();
103 }
104 
hasCamera(const string & make,const string & model,const string & mode) const105 bool CameraMetaData::hasCamera(const string& make, const string& model,
106                                const string& mode) const {
107   return getCamera(make, model, mode);
108 }
109 
110 const Camera* __attribute__((pure))
getChdkCamera(uint32_t filesize) const111 CameraMetaData::getChdkCamera(uint32_t filesize) const {
112   auto camera = chdkCameras.find(filesize);
113   return camera == chdkCameras.end() ? nullptr : camera->second;
114 }
115 
116 bool __attribute__((pure))
hasChdkCamera(uint32_t filesize) const117 CameraMetaData::hasChdkCamera(uint32_t filesize) const {
118   return chdkCameras.end() != chdkCameras.find(filesize);
119 }
120 
addCamera(std::unique_ptr<Camera> cam)121 const Camera* CameraMetaData::addCamera(std::unique_ptr<Camera> cam) {
122   auto id = getId(cam->make, cam->model, cam->mode);
123   if (cameras.end() != cameras.find(id)) {
124     writeLog(
125         DEBUG_PRIO_WARNING,
126         "CameraMetaData: Duplicate entry found for camera: %s %s, Skipping!",
127         cam->make.c_str(), cam->model.c_str());
128     return nullptr;
129   }
130   cameras[id] = std::move(cam);
131 
132   if (string::npos != cameras[id]->mode.find("chdk")) {
133     auto filesize_hint = cameras[id]->hints.get("filesize", string());
134     if (filesize_hint.empty()) {
135       writeLog(DEBUG_PRIO_WARNING,
136                "CameraMetaData: CHDK camera: %s %s, no \"filesize\" hint set!",
137                cameras[id]->make.c_str(), cameras[id]->model.c_str());
138     } else {
139       chdkCameras[stoi(filesize_hint)] = cameras[id].get();
140       // writeLog(DEBUG_PRIO_WARNING, "CHDK camera: %s %s size:%u",
141       // cameras[id]->make.c_str(), cameras[id]->model.c_str(), size);
142     }
143   }
144   return cameras[id].get();
145 }
146 
disableMake(const string & make)147 void CameraMetaData::disableMake(const string &make) {
148   for (const auto& cam : cameras) {
149     if (cam.second->make == make)
150       cam.second->supported = false;
151   }
152 }
153 
disableCamera(const string & make,const string & model)154 void CameraMetaData::disableCamera(const string &make, const string &model) {
155   for (const auto& cam : cameras) {
156     if (cam.second->make == make && cam.second->model == model)
157       cam.second->supported = false;
158   }
159 }
160 
161 } // namespace rawspeed
162