1 /*
2  */
3 
4 /*
5 
6     Copyright (C) 2014 Ferrero Andrea
7 
8     This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12 
13     This program 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
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21 
22  */
23 
24 /*
25 
26     These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27 
28  */
29 
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <glibmm.h>
36 
37 #include <stdio.h>  /* defines FILENAME_MAX */
38 //#ifdef WINDOWS
39 #if defined(__MINGW32__) || defined(__MINGW64__)
40 #include <direct.h>
41 #include <shlobj.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
45 #define GetCurrentDir _getcwd
46 #else
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #include <unistd.h>
50 #define GetCurrentDir getcwd
51 #endif
52 
53 #if defined(__MINGW32__) || defined(__MINGW64__)
54   #include<windows.h>
55 #endif
56 
57 #if defined(__APPLE__) && defined (__MACH__)
58 #include <mach-o/dyld.h>
59 #endif
60 
61 #include "pf_mkstemp.hh"
62 #include "imageprocessor.hh"
63 #include "photoflow.hh"
64 #include "print_display_profile.hh"
65 
66 #include "../rt/rtengine/rtlensfun.h"
67 
68 #include "../vips/gmic/gmic/src/gmic.h"
69 
70 
71 #if defined(__MINGW32__) || defined(__MINGW64__)
_lf_get_database_dir()72 const char* _lf_get_database_dir()
73 {
74   std::string dbdir;
75   //if( getenv("LOCALAPPDATA") ) {
76   //  dbdir = getenv("LOCALAPPDATA");
77   if( getenv("PROGRAMDATA") ) {
78     dbdir = getenv("PROGRAMDATA");
79     dbdir += "\\lensfun\\version_1";
80   }
81   std::cout<<"LensFun database dir: "<<dbdir<<std::endl;
82   return dbdir.c_str();
83 }
84 #endif
85 
write_escaped(std::string const & s,std::string & s2)86 static void write_escaped(std::string const& s, std::string& s2) {
87   //s2 += '"';
88   for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
89     unsigned char c = *i;
90     if (' ' <= c and c <= '~' and c != '\\' and c != '"') {
91       s2 += c;
92     }
93     else {
94       s2 += '\\';
95       switch(c) {
96       case '"':  s2 += '"';  break;
97       case '\\': s2 += '\\'; break;
98       case '\t': s2 += 't';  break;
99       case '\r': s2 += 'r';  break;
100       case '\n': s2 += 'n';  break;
101       default:
102         char const* const hexdig = "0123456789ABCDEF";
103         s2 += 'x';
104         s2 += hexdig[c >> 4];
105         s2 += hexdig[c & 0xF];
106       }
107     }
108   }
109   //s2 += '"';
110 }
111 
PhotoFlow()112 PF::PhotoFlow::PhotoFlow():
113   active_image( NULL ), messanger( NULL ),
114   batch(true), plugin(false),
115   single_win_mode(true)
116 {
117   // Create the cache directory if possible
118   char fname[500];
119 
120   PF::print_display_profile();
121 
122 #if defined(__MINGW32__) || defined(__MINGW64__)
123   char fname2[500];
124   DWORD check = GetTempPath(499, fname);
125   if (0 != check) {
126     sprintf( fname2,"%s\\photoflow", fname );
127     int result = mkdir(fname2);
128     if( (result != 0) && (errno != EEXIST) ) {
129       perror("mkdir");
130       std::cout<<"Cannot create "<<fname2<<"    exiting."<<std::endl;
131       exit( 1 );
132     }
133     sprintf( fname2,"%s\\photoflow\\cache\\", fname );
134     result = mkdir(fname2);
135     if( (result != 0) && (errno != EEXIST) ) {
136       perror("mkdir");
137       std::cout<<"Cannot create "<<fname2<<"    exiting."<<std::endl;
138       exit( 1 );
139     }
140     cache_dir = fname2;
141   }
142 #else
143   if( getenv("HOME") ) {
144     sprintf( fname,"%s/.photoflow", getenv("HOME") );
145     int result = mkdir(fname, 0755);
146     if( (result == 0) || (errno == EEXIST) ) {
147       sprintf( fname,"%s/.photoflow/cache/", getenv("HOME") );
148       result = mkdir(fname, 0755);
149       if( (result != 0) && (errno != EEXIST) ) {
150 	perror("mkdir");
151 	std::cout<<"Cannot create "<<fname<<"    exiting."<<std::endl;
152 	exit( 1 );
153       }
154     } else {
155       perror("mkdir");
156       std::cout<<"Cannot create "<<fname<<" (result="<<result<<")   exiting."<<std::endl;
157       exit( 1 );
158     }
159     cache_dir = fname;
160   }
161 #endif
162 
163 #if defined(__MINGW32__) || defined(__MINGW64__)
164     WCHAR pathW[MAX_PATH] = {0};
165     char pathA[MAX_PATH];
166 
167     if (SHGetSpecialFolderPathW(NULL, pathW, CSIDL_LOCAL_APPDATA, false)) {
168       WideCharToMultiByte(CP_UTF8, 0, pathW, -1, pathA, MAX_PATH, 0, 0);
169       presets_dir = Glib::build_filename(Glib::ustring(pathA), "photoflow");
170       int result = mkdir(presets_dir.c_str());
171       if( (result == 0) || (errno == EEXIST) ) {
172         presets_dir = Glib::build_filename(presets_dir, "presets");
173         result = mkdir(presets_dir.c_str());
174         if( (result != 0) && (errno != EEXIST) ) {
175           perror("mkdir");
176           std::cout<<"Cannot create "<<presets_dir<<"    exiting."<<std::endl;
177           exit( 1 );
178         }
179       }
180     }
181 #else
182     if( getenv("HOME") ) {
183       sprintf( fname,"%s/.photoflow", getenv("HOME") );
184       int result = mkdir(fname, 0755);
185       if( (result == 0) || (errno == EEXIST) ) {
186         sprintf( fname,"%s/.photoflow/presets/", getenv("HOME") );
187         result = mkdir(fname, 0755);
188         if( (result != 0) && (errno != EEXIST) ) {
189           perror("mkdir");
190           std::cout<<"Cannot create "<<fname<<"    exiting."<<std::endl;
191           exit( 1 );
192         }
193       } else {
194         perror("mkdir");
195         std::cout<<"Cannot create "<<fname<<" (result="<<result<<")   exiting."<<std::endl;
196         exit( 1 );
197       }
198       presets_dir = fname;
199     }
200 #endif
201 
202 #if defined(__MINGW32__) || defined(__MINGW64__)
203     if (SHGetSpecialFolderPathW(NULL, pathW, CSIDL_LOCAL_APPDATA, false)) {
204       WideCharToMultiByte(CP_UTF8, 0, pathW, -1, pathA, MAX_PATH, 0, 0);
205       config_dir = Glib::build_filename(Glib::ustring(pathA), "photoflow");
206       int result = mkdir(config_dir.c_str());
207       if( (result == 0) || (errno == EEXIST) ) {
208         config_dir = Glib::build_filename(config_dir, "config");
209         result = mkdir(config_dir.c_str());
210         if( (result != 0) && (errno != EEXIST) ) {
211           perror("mkdir");
212           std::cout<<"Cannot create "<<config_dir<<"    exiting."<<std::endl;
213           exit( 1 );
214         }
215       }
216     }
217 #else
218     if( getenv("HOME") ) {
219       sprintf( fname,"%s/.photoflow", getenv("HOME") );
220       int result = mkdir(fname, 0755);
221       if( (result == 0) || (errno == EEXIST) ) {
222         sprintf( fname,"%s/.photoflow/config/", getenv("HOME") );
223         result = mkdir(fname, 0755);
224         if( (result != 0) && (errno != EEXIST) ) {
225           perror("mkdir");
226           std::cout<<"Cannot create "<<fname<<"    exiting."<<std::endl;
227           exit( 1 );
228         }
229       } else {
230         perror("mkdir");
231         std::cout<<"Cannot create "<<fname<<" (result="<<result<<")   exiting."<<std::endl;
232         exit( 1 );
233       }
234       config_dir = fname;
235     }
236 #endif
237 
238   char exname[512] = {0};
239   Glib::ustring exePath;
240   // get the path where the executable is stored
241 #ifdef WIN32
242   WCHAR exnameU[512] = {0};
243   GetModuleFileNameW (NULL, exnameU, 512);
244   WideCharToMultiByte(CP_UTF8,0,exnameU,-1,exname,512,0,0 );
245 #elif defined(__APPLE__) && defined (__MACH__)
246   char path[1024];
247   uint32_t size = sizeof(exname);
248   if (_NSGetExecutablePath(exname, &size) == 0)
249     printf("executable path is %s\n", exname);
250   else
251     printf("buffer too small; need size %u\n", size);
252 #else
253   if (readlink("/proc/self/exe", exname, 512) < 0) {
254     //strncpy(exname, argv[0], 512);
255     std::cout<<"Cannot determine full executable name."<<std::endl;
256     exname[0] = '\0';
257   }
258 #endif
259   exePath = Glib::path_get_dirname(exname);
260   std::cout<<"exePath: "<<exePath<<std::endl;
261 
262   Glib::ustring dataPath;
263 #if defined(__APPLE__) && defined (__MACH__)
264   char* dataPath_env = getenv("PF_DATA_DIR");
265   if( dataPath_env ) {
266     dataPath = Glib::ustring(dataPath_env) + "/photoflow/";
267   } else {
268     dataPath = exePath + "/../share/photoflow/";
269   }
270 #elif defined(WIN32)
271   //if( getenv("LOCALAPPDATA") ) {
272   //  dataPath = getenv("LOCALAPPDATA");
273   if( false && getenv("PROGRAMDATA") ) {
274     dataPath = getenv("PROGRAMDATA");
275     dataPath += "\\photoflow\\";
276     Glib::ustring testPath = dataPath + "\\gmic_def.gmic";
277     struct stat stat_buf;
278     if( stat(testPath.c_str(), &stat_buf) ) {
279       dataPath = exePath + "\\..\\share\\photoflow\\";
280     }
281   } else {
282     dataPath = exePath + "\\..\\share\\photoflow\\";
283   }
284 #else
285   char* dataPath_env = getenv("PF_DATA_DIR");
286   if( dataPath_env ) {
287     dataPath = Glib::ustring(dataPath_env) + "/photoflow/";
288   } else {
289     dataPath = Glib::ustring(INSTALL_PREFIX) + "/share/photoflow/";
290   }
291 #endif
292   std::cout<<"dataPath: "<<dataPath<<std::endl;
293 
294   std::string dataPathEscaped;
295   write_escaped(dataPath, dataPathEscaped);
296   Glib::setenv("GMIC_SYSTEM_PATH", dataPathEscaped.c_str(), 1);
297 
298   lensfun_db_dir = dataPath;
299 #if defined(WIN32)
300   lensfun_db_dir += "\\lensfun\\version_1\\";
301 #else
302   lensfun_db_dir += "/lensfun/version_1/";
303 #endif
304 
305   Glib::ustring localePath;
306 #if defined(__APPLE__) && defined (__MACH__)
307   if( dataPath_env ) {
308     localePath = Glib::ustring(dataPath_env) + "/locale";
309   } else {
310     localePath = exePath + "/../share/locale";
311   }
312 #elif defined(WIN32)
313   localePath = exePath + "\\..\\share\\locale\\";
314 #else
315   if( dataPath_env ) {
316     localePath = Glib::ustring(dataPath_env) + "/locale";
317   } else {
318     localePath = Glib::ustring(INSTALL_PREFIX) + "/share/locale";
319   }
320 #endif
321   std::cout<<"localePath: "<<localePath<<std::endl;
322 
323   gmic::init_rc();
324 
325   set_base_dir( exePath );
326   set_data_dir( dataPath );
327   set_locale_dir( localePath );
328 
329   Glib::ustring lfdb;
330 #if (BUNDLED_LENSFUN_DB == 1)
331   lfdb = get_lensfun_db_dir();
332 #endif
333   std::cout<<"Calling rtengine::LFDatabase::init(\""<<lfdb<<"\")"<<std::endl;
334   rtengine::LFDatabase::init( lfdb );
335 }
336 
337 
338 PF::PhotoFlow* PF::PhotoFlow::instance = NULL;
339 
Instance()340 PF::PhotoFlow& PF::PhotoFlow::Instance()
341 {
342   if(!PF::PhotoFlow::instance)
343     PF::PhotoFlow::instance = new PF::PhotoFlow();
344   return( *instance );
345 };
346 
347 
close()348 void PF::PhotoFlow::close()
349 {
350   //PF::ImageProcessor::Instance().join();
351 
352   //im_close_plugins();
353   //sleep(10);
354   std::cout<<"PhotoFlow::close(): calling vips shutdown"<<std::endl;
355   vips_shutdown();
356   std::cout<<"PhotoFlow::close(): vips shutdown done"<<std::endl;
357 
358   options.save();
359 /*
360 #if defined(__MINGW32__) || defined(__MINGW64__)
361   for (int i = 0; i < _getmaxstdio(); ++i) ::close (i);
362 #elif defined(__APPLE__) && defined(__MACH__)
363 #else
364   rlimit rlim;
365   //getrlimit(RLIMIT_NOFILE, &rlim);
366   if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
367     std::cout<<"rlim.rlim_max="<<rlim.rlim_max<<std::endl;
368     for (int i = 3; i < rlim.rlim_max; ++i) {
369       //std::cout<<"i="<<i<<std::endl;
370       //::close (i);
371     }
372   }
373 #endif
374 */
375   std::cout<<"PhotoFlow::close(): deleting cache files"<<std::endl;
376   std::list<std::string>::iterator fi;
377   for(fi = cache_files.begin(); fi != cache_files.end(); fi++) {
378     std::cout<<"  deleting "<<fi->c_str()<<std::endl;
379     unlink( fi->c_str() );
380     std::cout<<"  "<<fi->c_str()<<" deleted"<<std::endl;
381   }
382   std::cout<<"PhotoFlow::close(): cache files deleted"<<std::endl;
383 }
384 
385 
386 
obj_unref(GObject * obj,char * msg)387 void PF::PhotoFlow::obj_unref( GObject* obj, char* msg )
388 {
389 	if( PF::PhotoFlow::Instance().is_batch() ){
390 		PF_UNREF( obj, msg );
391 	} else {
392 		ProcessRequestInfo request;
393 		request.obj = obj;
394 		request.request = PF::OBJECT_UNREF;
395 		PF::ImageProcessor::Instance().submit_request( request );
396 	}
397 }
398 
399 
pf_object_ref(GObject * object,const char * msg)400 void PF::pf_object_ref(GObject* object, const char* msg)
401 {
402 #ifdef PF_VERBOSE_UNREF
403   std::cout<<"pf_object_ref()";
404 	if(msg) std::cout<<": "<<msg;
405 	std::cout<<std::endl;
406   std::cout<<"                   object="<<object<<std::endl;
407 #endif
408   if( !object ) {
409 #ifdef PF_VERBOSE_UNREF
410     std::cout<<"                   NULL object!!!"<<std::endl;
411 #endif
412     return;
413   }
414 #ifdef PF_VERBOSE_UNREF
415   std::cout<<"                   ref_count before: "<<object->ref_count<<std::endl;
416 #endif
417   g_object_ref( object );
418 #ifdef PF_VERBOSE_UNREF
419   std::cout<<"                   ref_count after:  "<<object->ref_count<<std::endl;
420 #endif
421 }
422 
423 
424 //#define PF_VERBOSE_UNREF 1
425 
pf_object_unref(GObject * object,const char * msg)426 void PF::pf_object_unref(GObject* object, const char* msg)
427 {
428 #ifdef PF_VERBOSE_UNREF
429   std::cout<<"pf_object_unref()";
430 	if(msg) std::cout<<": "<<msg;
431 	std::cout<<std::endl;
432   std::cout<<"                   object="<<object<<std::endl;
433 #endif
434   if( !object ) {
435 #ifdef PF_VERBOSE_UNREF
436     std::cout<<"                   NULL object!!!"<<std::endl;
437 #endif
438     return;
439   }
440 #ifdef PF_VERBOSE_UNREF
441   std::cout<<"                   ref_count before: "<<object->ref_count<<std::endl;
442 #endif
443   g_assert( object->ref_count > 0 );
444   g_object_unref( object );
445 #ifdef PF_VERBOSE_UNREF
446   std::cout<<"                   ref_count after:  "<<object->ref_count<<std::endl;
447 #endif
448 }
449