Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2007 Blender Foundation 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Andrea Weikert. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <stdio.h> 00034 00035 #include "MEM_guardedalloc.h" 00036 00037 #include "BLI_blenlib.h" 00038 #include "BLI_md5.h" 00039 00040 #include "BKE_utildefines.h" 00041 00042 #include "IMB_imbuf_types.h" 00043 #include "IMB_imbuf.h" 00044 #include "IMB_thumbs.h" 00045 #include "IMB_metadata.h" 00046 00047 #include <ctype.h> 00048 #include <stdlib.h> 00049 #include <string.h> 00050 #include <time.h> 00051 #include <sys/types.h> 00052 #include <sys/stat.h> 00053 #include <stdio.h> 00054 00055 #ifdef WIN32 00056 #include <windows.h> /* need to include windows.h so _WIN32_IE is defined */ 00057 #ifndef _WIN32_IE 00058 #define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */ 00059 #endif 00060 #include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */ 00061 #include <process.h> /* getpid */ 00062 #include <direct.h> /* chdir */ 00063 #include "BLI_winstuff.h" 00064 #else 00065 #include <unistd.h> 00066 #endif 00067 00068 #define URI_MAX FILE_MAX*3 + 8 00069 00070 static int get_thumb_dir( char* dir , ThumbSize size) 00071 { 00072 #ifdef WIN32 00073 /* yes, applications shouldn't store data there, but so does GIMP :)*/ 00074 SHGetSpecialFolderPath(0, dir, CSIDL_PROFILE, 0); 00075 #else 00076 const char* home = getenv("HOME"); 00077 if (!home) return 0; 00078 BLI_strncpy(dir, home, FILE_MAX); 00079 #endif 00080 switch(size) { 00081 case THB_NORMAL: 00082 strcat(dir, "/.thumbnails/normal/"); 00083 break; 00084 case THB_LARGE: 00085 strcat(dir, "/.thumbnails/large/"); 00086 break; 00087 case THB_FAIL: 00088 strcat(dir, "/.thumbnails/fail/blender/"); 00089 break; 00090 default: 00091 return 0; /* unknown size */ 00092 } 00093 return 1; 00094 } 00095 00101 typedef enum { 00102 UNSAFE_ALL = 0x1, /* Escape all unsafe characters */ 00103 UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */ 00104 UNSAFE_PATH = 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */ 00105 UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */ 00106 UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */ 00107 } UnsafeCharacterSet; 00108 00109 static const unsigned char acceptable[96] = { 00110 /* A table of the ASCII chars from space (32) to DEL (127) */ 00111 /* ! " # $ % & ' ( ) * + , - . / */ 00112 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C, 00113 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 00114 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20, 00115 /* @ A B C D E F G H I J K L M N O */ 00116 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, 00117 /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 00118 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F, 00119 /* ` a b c d e f g h i j k l m n o */ 00120 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, 00121 /* p q r s t u v w x y z { | } ~ DEL */ 00122 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20 00123 }; 00124 00125 static const char hex[17] = "0123456789abcdef"; 00126 00127 /* Note: This escape function works on file: URIs, but if you want to 00128 * escape something else, please read RFC-2396 */ 00129 static void escape_uri_string (const char *string, char* escaped_string, int len,UnsafeCharacterSet mask) 00130 { 00131 #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) 00132 00133 const char *p; 00134 char *q; 00135 int c; 00136 UnsafeCharacterSet use_mask; 00137 use_mask = mask; 00138 00139 for (q = escaped_string, p = string; (*p != '\0') && len; p++) { 00140 c = (unsigned char) *p; 00141 len--; 00142 00143 if (!ACCEPTABLE (c)) { 00144 *q++ = '%'; /* means hex coming */ 00145 *q++ = hex[c >> 4]; 00146 *q++ = hex[c & 15]; 00147 } else { 00148 *q++ = *p; 00149 } 00150 } 00151 00152 *q = '\0'; 00153 } 00154 00155 static void to_hex_char(char* hexbytes, const unsigned char* bytes, int len) 00156 { 00157 const unsigned char *p; 00158 char *q; 00159 00160 for (q = hexbytes, p = bytes; len; p++) { 00161 const unsigned char c = (unsigned char) *p; 00162 len--; 00163 *q++ = hex[c >> 4]; 00164 *q++ = hex[c & 15]; 00165 } 00166 } 00167 00170 static int uri_from_filename( const char *path, char *uri ) 00171 { 00172 char orig_uri[URI_MAX]; 00173 const char* dirstart = path; 00174 00175 #ifdef WIN32 00176 { 00177 char vol[3]; 00178 00179 BLI_strncpy(orig_uri, "file:///", FILE_MAX); 00180 if (strlen(path) < 2 && path[1] != ':') { 00181 /* not a correct absolute path */ 00182 return 0; 00183 } 00184 /* on windows, using always uppercase drive/volume letter in uri */ 00185 vol[0] = (unsigned char)toupper(path[0]); 00186 vol[1] = ':'; 00187 vol[2] = '\0'; 00188 strcat(orig_uri, vol); 00189 dirstart += 2; 00190 } 00191 #else 00192 BLI_strncpy(orig_uri, "file://", FILE_MAX); 00193 #endif 00194 strcat(orig_uri, dirstart); 00195 BLI_char_switch(orig_uri, '\\', '/'); 00196 00197 #ifdef WITH_ICONV 00198 { 00199 char uri_utf8[FILE_MAX*3+8]; 00200 escape_uri_string(orig_uri, uri_utf8, FILE_MAX*3+8, UNSAFE_PATH); 00201 BLI_string_to_utf8(uri_utf8, uri, NULL); 00202 } 00203 #else 00204 escape_uri_string(orig_uri, uri, FILE_MAX*3+8, UNSAFE_PATH); 00205 #endif 00206 return 1; 00207 } 00208 00209 static void thumbname_from_uri(const char* uri, char* thumb, const int thumb_len) 00210 { 00211 char hexdigest[33]; 00212 unsigned char digest[16]; 00213 00214 md5_buffer( uri, strlen(uri), digest); 00215 hexdigest[0] = '\0'; 00216 to_hex_char(hexdigest, digest, 16); 00217 hexdigest[32] = '\0'; 00218 BLI_snprintf(thumb, thumb_len, "%s.png", hexdigest); 00219 } 00220 00221 static int thumbpath_from_uri(const char* uri, char* path, const int path_len, ThumbSize size) 00222 { 00223 char tmppath[FILE_MAX]; 00224 int rv = 0; 00225 00226 if (get_thumb_dir(tmppath, size)) { 00227 char thumb[40]; 00228 thumbname_from_uri(uri, thumb, sizeof(thumb)); 00229 BLI_snprintf(path, path_len, "%s%s", tmppath, thumb); 00230 rv = 1; 00231 } 00232 return rv; 00233 } 00234 00235 void IMB_thumb_makedirs(void) 00236 { 00237 char tpath[FILE_MAX]; 00238 if (get_thumb_dir(tpath, THB_NORMAL)) { 00239 BLI_dir_create_recursive(tpath); 00240 } 00241 if (get_thumb_dir(tpath, THB_FAIL)) { 00242 BLI_dir_create_recursive(tpath); 00243 } 00244 } 00245 00246 /* create thumbnail for file and returns new imbuf for thumbnail */ 00247 ImBuf* IMB_thumb_create(const char* path, ThumbSize size, ThumbSource source, ImBuf *img) 00248 { 00249 char uri[URI_MAX]= ""; 00250 char desc[URI_MAX+22]; 00251 char tpath[FILE_MAX]; 00252 char tdir[FILE_MAX]; 00253 char temp[FILE_MAX]; 00254 char mtime[40]= "0"; /* incase we can't stat the file */ 00255 char cwidth[40]= "0"; /* incase images have no data */ 00256 char cheight[40]= "0"; 00257 char thumb[40]; 00258 short tsize = 128; 00259 short ex, ey; 00260 float scaledx, scaledy; 00261 struct stat info; 00262 00263 switch(size) { 00264 case THB_NORMAL: 00265 tsize = 128; 00266 break; 00267 case THB_LARGE: 00268 tsize = 256; 00269 break; 00270 case THB_FAIL: 00271 tsize = 1; 00272 break; 00273 default: 00274 return NULL; /* unknown size */ 00275 } 00276 00277 /* exception, skip images over 100mb */ 00278 if(source == THB_SOURCE_IMAGE) { 00279 const size_t size= BLI_file_size(path); 00280 if(size != -1 && size > THUMB_SIZE_MAX) { 00281 // printf("file too big: %d, skipping %s\n", (int)size, path); 00282 return NULL; 00283 } 00284 } 00285 00286 uri_from_filename(path, uri); 00287 thumbname_from_uri(uri, thumb, sizeof(thumb)); 00288 if (get_thumb_dir(tdir, size)) { 00289 BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb); 00290 thumb[8] = '\0'; /* shorten for tempname, not needed anymore */ 00291 BLI_snprintf(temp, FILE_MAX, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb); 00292 if (BLI_path_ncmp(path, tdir, sizeof(tdir)) == 0) { 00293 return NULL; 00294 } 00295 if (size == THB_FAIL) { 00296 img = IMB_allocImBuf(1,1,32, IB_rect | IB_metadata); 00297 if (!img) return NULL; 00298 } else { 00299 if (THB_SOURCE_IMAGE == source || THB_SOURCE_BLEND == source) { 00300 00301 /* only load if we didnt give an image */ 00302 if(img==NULL) { 00303 if(THB_SOURCE_BLEND == source) { 00304 img = IMB_loadblend_thumb(path); 00305 } 00306 else { 00307 img = IMB_loadiffname(path, IB_rect | IB_metadata); 00308 } 00309 } 00310 00311 if (img != NULL) { 00312 stat(path, &info); 00313 BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime); 00314 BLI_snprintf(cwidth, sizeof(cwidth), "%d", img->x); 00315 BLI_snprintf(cheight, sizeof(cheight), "%d", img->y); 00316 } 00317 } else if (THB_SOURCE_MOVIE == source) { 00318 struct anim * anim = NULL; 00319 anim = IMB_open_anim(path, IB_rect | IB_metadata, 0); 00320 if (anim != NULL) { 00321 img = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE); 00322 if (img == NULL) { 00323 printf("not an anim; %s\n", path); 00324 } else { 00325 IMB_freeImBuf(img); 00326 img = IMB_anim_previewframe(anim); 00327 } 00328 IMB_free_anim(anim); 00329 } 00330 stat(path, &info); 00331 BLI_snprintf(mtime, sizeof(mtime), "%ld", (long int)info.st_mtime); 00332 } 00333 if (!img) return NULL; 00334 00335 if (img->x > img->y) { 00336 scaledx = (float)tsize; 00337 scaledy = ( (float)img->y/(float)img->x )*tsize; 00338 } 00339 else { 00340 scaledy = (float)tsize; 00341 scaledx = ( (float)img->x/(float)img->y )*tsize; 00342 } 00343 ex = (short)scaledx; 00344 ey = (short)scaledy; 00345 00346 /* save some time by only scaling byte buf */ 00347 if(img->rect_float) { 00348 if(img->rect == NULL) { 00349 IMB_rect_from_float(img); 00350 } 00351 00352 imb_freerectfloatImBuf(img); 00353 } 00354 00355 IMB_scaleImBuf(img, ex, ey); 00356 } 00357 BLI_snprintf(desc, sizeof(desc), "Thumbnail for %s", uri); 00358 IMB_metadata_change_field(img, "Description", desc); 00359 IMB_metadata_change_field(img, "Software", "Blender"); 00360 IMB_metadata_change_field(img, "Thumb::URI", uri); 00361 IMB_metadata_change_field(img, "Thumb::MTime", mtime); 00362 if (THB_SOURCE_IMAGE == source) { 00363 IMB_metadata_change_field(img, "Thumb::Image::Width", cwidth); 00364 IMB_metadata_change_field(img, "Thumb::Image::Height", cheight); 00365 } 00366 img->ftype = PNG; 00367 img->planes = 32; 00368 if (IMB_saveiff(img, temp, IB_rect | IB_metadata)) { 00369 #ifndef WIN32 00370 chmod(temp, S_IRUSR | S_IWUSR); 00371 #endif 00372 BLI_rename(temp, tpath); 00373 } 00374 00375 return img; 00376 } 00377 return img; 00378 } 00379 00380 /* read thumbnail for file and returns new imbuf for thumbnail */ 00381 ImBuf* IMB_thumb_read(const char* path, ThumbSize size) 00382 { 00383 char thumb[FILE_MAX]; 00384 char uri[FILE_MAX*3+8]; 00385 ImBuf *img = NULL; 00386 00387 if (!uri_from_filename(path,uri)) { 00388 return NULL; 00389 } 00390 if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) { 00391 img = IMB_loadiffname(thumb, IB_rect | IB_metadata); 00392 } 00393 00394 return img; 00395 } 00396 00397 /* delete all thumbs for the file */ 00398 void IMB_thumb_delete(const char* path, ThumbSize size) 00399 { 00400 char thumb[FILE_MAX]; 00401 char uri[FILE_MAX*3+8]; 00402 00403 if (!uri_from_filename(path ,uri)) { 00404 return; 00405 } 00406 if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) { 00407 if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) { 00408 return; 00409 } 00410 if (BLI_exists(thumb)) { 00411 BLI_delete(thumb, 0, 0); 00412 } 00413 } 00414 } 00415 00416 00417 /* create the thumb if necessary and manage failed and old thumbs */ 00418 ImBuf* IMB_thumb_manage(const char* path, ThumbSize size, ThumbSource source) 00419 { 00420 char thumb[FILE_MAX]; 00421 char uri[FILE_MAX*3+8]; 00422 struct stat st; 00423 ImBuf* img = NULL; 00424 00425 if (stat(path, &st)) { 00426 return NULL; 00427 } 00428 if (!uri_from_filename(path,uri)) { 00429 return NULL; 00430 } 00431 if (thumbpath_from_uri(uri, thumb, sizeof(thumb), THB_FAIL)) { 00432 /* failure thumb exists, don't try recreating */ 00433 if (BLI_exists(thumb)) { 00434 return NULL; 00435 } 00436 } 00437 00438 if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) { 00439 if (BLI_path_ncmp(path, thumb, sizeof(thumb)) == 0) { 00440 img = IMB_loadiffname(path, IB_rect); 00441 } else { 00442 img = IMB_loadiffname(thumb, IB_rect | IB_metadata); 00443 if (img) { 00444 char mtime[40]; 00445 if (!IMB_metadata_get_field(img, "Thumb::MTime", mtime, 40)) { 00446 /* illegal thumb, forget it! */ 00447 IMB_freeImBuf(img); 00448 img = NULL; 00449 } else { 00450 time_t t = atol(mtime); 00451 if (st.st_mtime != t) { 00452 /* recreate all thumbs */ 00453 IMB_freeImBuf(img); 00454 img = NULL; 00455 IMB_thumb_delete(path, THB_NORMAL); 00456 IMB_thumb_delete(path, THB_LARGE); 00457 IMB_thumb_delete(path, THB_FAIL); 00458 img = IMB_thumb_create(path, size, source, NULL); 00459 if(!img){ 00460 /* thumb creation failed, write fail thumb */ 00461 img = IMB_thumb_create(path, THB_FAIL, source, NULL); 00462 if (img) { 00463 /* we don't need failed thumb anymore */ 00464 IMB_freeImBuf(img); 00465 img = NULL; 00466 } 00467 } 00468 } 00469 } 00470 } else { 00471 img = IMB_thumb_create(path, size, source, NULL); 00472 if(!img){ 00473 /* thumb creation failed, write fail thumb */ 00474 img = IMB_thumb_create(path, THB_FAIL, source, NULL); 00475 if (img) { 00476 /* we don't need failed thumb anymore */ 00477 IMB_freeImBuf(img); 00478 img = NULL; 00479 } 00480 } 00481 } 00482 } 00483 } 00484 00485 return img; 00486 } 00487 00488