|
Blender
V2.59
|
00001 /* 00002 * blenkernel/packedFile.c - (cleaned up mar-01 nzc) 00003 * 00004 * $Id: packedFile.c 35247 2011-02-27 20:40:57Z jesterking $ 00005 * 00006 * ***** BEGIN GPL LICENSE BLOCK ***** 00007 * 00008 * This program is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU General Public License 00010 * as published by the Free Software Foundation; either version 2 00011 * of the License, or (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00023 * All rights reserved. 00024 * 00025 * The Original Code is: all of this file. 00026 * 00027 * Contributor(s): none yet. 00028 * 00029 * ***** END GPL LICENSE BLOCK ***** 00030 */ 00031 00037 #include <stdio.h> 00038 #include <fcntl.h> 00039 #include <sys/stat.h> 00040 00041 #ifndef WIN32 00042 #include <unistd.h> 00043 #else 00044 #include <io.h> 00045 #endif 00046 #include <string.h> 00047 #include "MEM_guardedalloc.h" 00048 00049 #include "DNA_image_types.h" 00050 #include "DNA_sound_types.h" 00051 #include "DNA_vfont_types.h" 00052 #include "DNA_packedFile_types.h" 00053 00054 #include "BLI_blenlib.h" 00055 #include "BLI_utildefines.h" 00056 00057 #include "BKE_utildefines.h" 00058 #include "BKE_global.h" 00059 #include "BKE_main.h" 00060 #include "BKE_sound.h" 00061 #include "BKE_image.h" 00062 #include "BKE_packedFile.h" 00063 #include "BKE_report.h" 00064 00065 #ifdef _WIN32 00066 #define open _open 00067 #define close _close 00068 #define read _read 00069 #define write _write 00070 #endif 00071 00072 00073 int seekPackedFile(PackedFile *pf, int offset, int whence) 00074 { 00075 int oldseek = -1, seek = 0; 00076 00077 if (pf) { 00078 oldseek = pf->seek; 00079 switch(whence) { 00080 case SEEK_CUR: 00081 seek = oldseek + offset; 00082 break; 00083 case SEEK_END: 00084 seek = pf->size + offset; 00085 break; 00086 case SEEK_SET: 00087 seek = offset; 00088 break; 00089 default: 00090 oldseek = -1; 00091 } 00092 if (seek < 0) { 00093 seek = 0; 00094 } else if (seek > pf->size) { 00095 seek = pf->size; 00096 } 00097 pf->seek = seek; 00098 } 00099 00100 return(oldseek); 00101 } 00102 00103 void rewindPackedFile(PackedFile *pf) 00104 { 00105 seekPackedFile(pf, 0, SEEK_SET); 00106 } 00107 00108 int readPackedFile(PackedFile *pf, void *data, int size) 00109 { 00110 if ((pf != NULL) && (size >= 0) && (data != NULL)) { 00111 if (size + pf->seek > pf->size) { 00112 size = pf->size - pf->seek; 00113 } 00114 00115 if (size > 0) { 00116 memcpy(data, ((char *) pf->data) + pf->seek, size); 00117 } else { 00118 size = 0; 00119 } 00120 00121 pf->seek += size; 00122 } else { 00123 size = -1; 00124 } 00125 00126 return(size); 00127 } 00128 00129 int countPackedFiles(Main *bmain) 00130 { 00131 Image *ima; 00132 VFont *vf; 00133 bSound *sound; 00134 int count = 0; 00135 00136 // let's check if there are packed files... 00137 for(ima=bmain->image.first; ima; ima=ima->id.next) 00138 if(ima->packedfile) 00139 count++; 00140 00141 for(vf=bmain->vfont.first; vf; vf=vf->id.next) 00142 if(vf->packedfile) 00143 count++; 00144 00145 for(sound=bmain->sound.first; sound; sound=sound->id.next) 00146 if(sound->packedfile) 00147 count++; 00148 00149 return count; 00150 } 00151 00152 void freePackedFile(PackedFile *pf) 00153 { 00154 if(pf) { 00155 MEM_freeN(pf->data); 00156 MEM_freeN(pf); 00157 } 00158 else 00159 printf("freePackedFile: Trying to free a NULL pointer\n"); 00160 } 00161 00162 PackedFile *newPackedFileMemory(void *mem, int memlen) 00163 { 00164 PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile"); 00165 pf->data = mem; 00166 pf->size = memlen; 00167 00168 return pf; 00169 } 00170 00171 PackedFile *newPackedFile(ReportList *reports, const char *filename) 00172 { 00173 PackedFile *pf = NULL; 00174 int file, filelen; 00175 char name[FILE_MAXDIR+FILE_MAXFILE]; 00176 void *data; 00177 00178 /* render result has no filename and can be ignored 00179 * any other files with no name can be ignored too */ 00180 if(filename[0]=='\0') 00181 return NULL; 00182 00183 //XXX waitcursor(1); 00184 00185 // convert relative filenames to absolute filenames 00186 00187 strcpy(name, filename); 00188 BLI_path_abs(name, G.main->name); 00189 00190 // open the file 00191 // and create a PackedFile structure 00192 00193 file= open(name, O_BINARY|O_RDONLY); 00194 if (file <= 0) { 00195 BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path not found: \"%s\"", name); 00196 } else { 00197 filelen = BLI_filesize(file); 00198 00199 if (filelen == 0) { 00200 // MEM_mallocN complains about MEM_mallocN(0, "bla"); 00201 // we don't care.... 00202 data = MEM_mallocN(1, "packFile"); 00203 } else { 00204 data = MEM_mallocN(filelen, "packFile"); 00205 } 00206 if (read(file, data, filelen) == filelen) { 00207 pf = newPackedFileMemory(data, filelen); 00208 } 00209 00210 close(file); 00211 } 00212 00213 //XXX waitcursor(0); 00214 00215 return (pf); 00216 } 00217 00218 void packAll(Main *bmain, ReportList *reports) 00219 { 00220 Image *ima; 00221 VFont *vf; 00222 bSound *sound; 00223 00224 for(ima=bmain->image.first; ima; ima=ima->id.next) { 00225 if(ima->packedfile == NULL && ima->id.lib==NULL) { 00226 if(ima->source==IMA_SRC_FILE) { 00227 ima->packedfile = newPackedFile(reports, ima->name); 00228 } 00229 else if(ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { 00230 BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported.", ima->id.name+2); 00231 } 00232 } 00233 } 00234 00235 for(vf=bmain->vfont.first; vf; vf=vf->id.next) 00236 if(vf->packedfile == NULL && vf->id.lib==NULL && strcmp(vf->name, FO_BUILTIN_NAME) != 0) 00237 vf->packedfile = newPackedFile(reports, vf->name); 00238 00239 for(sound=bmain->sound.first; sound; sound=sound->id.next) 00240 if(sound->packedfile == NULL && sound->id.lib==NULL) 00241 sound->packedfile = newPackedFile(reports, sound->name); 00242 } 00243 00244 00245 /* 00246 00247 // attempt to create a function that generates an unique filename 00248 // this will work when all funtions in fileops.c understand relative filenames... 00249 00250 static char *find_new_name(char *name) 00251 { 00252 char tempname[FILE_MAXDIR + FILE_MAXFILE]; 00253 char *newname; 00254 00255 if (fop_exists(name)) { 00256 for (number = 1; number <= 999; number++) { 00257 sprintf(tempname, "%s.%03d", name, number); 00258 if (! fop_exists(tempname)) { 00259 break; 00260 } 00261 } 00262 } 00263 00264 newname = mallocN(strlen(tempname) + 1, "find_new_name"); 00265 strcpy(newname, tempname); 00266 00267 return(newname); 00268 } 00269 00270 */ 00271 00272 int writePackedFile(ReportList *reports, const char *filename, PackedFile *pf, int guimode) 00273 { 00274 int file, number, remove_tmp = FALSE; 00275 int ret_value = RET_OK; 00276 char name[FILE_MAXDIR + FILE_MAXFILE]; 00277 char tempname[FILE_MAXDIR + FILE_MAXFILE]; 00278 /* void *data; */ 00279 00280 if (guimode) {} //XXX waitcursor(1); 00281 00282 strcpy(name, filename); 00283 BLI_path_abs(name, G.main->name); 00284 00285 if (BLI_exists(name)) { 00286 for (number = 1; number <= 999; number++) { 00287 sprintf(tempname, "%s.%03d_", name, number); 00288 if (! BLI_exists(tempname)) { 00289 if (BLI_copy_fileops(name, tempname) == RET_OK) { 00290 remove_tmp = TRUE; 00291 } 00292 break; 00293 } 00294 } 00295 } 00296 00297 // make sure the path to the file exists... 00298 BLI_make_existing_file(name); 00299 00300 file = open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666); 00301 if (file >= 0) { 00302 if (write(file, pf->data, pf->size) != pf->size) { 00303 BKE_reportf(reports, RPT_ERROR, "Error writing file: %s", name); 00304 ret_value = RET_ERROR; 00305 } 00306 close(file); 00307 } else { 00308 BKE_reportf(reports, RPT_ERROR, "Error creating file: %s", name); 00309 ret_value = RET_ERROR; 00310 } 00311 00312 if (remove_tmp) { 00313 if (ret_value == RET_ERROR) { 00314 if (BLI_rename(tempname, name) != 0) { 00315 BKE_reportf(reports, RPT_ERROR, "Error restoring tempfile. Check files: '%s' '%s'", tempname, name); 00316 } 00317 } else { 00318 if (BLI_delete(tempname, 0, 0) != 0) { 00319 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname); 00320 } 00321 } 00322 } 00323 00324 if(guimode) {} //XXX waitcursor(0); 00325 00326 return (ret_value); 00327 } 00328 00329 /* 00330 00331 This function compares a packed file to a 'real' file. 00332 It returns an integer indicating if: 00333 00334 PF_EQUAL - the packed file and original file are identical 00335 PF_DIFFERENT - the packed file and original file differ 00336 PF_NOFILE - the original file doens't exist 00337 00338 */ 00339 00340 int checkPackedFile(const char *filename, PackedFile *pf) 00341 { 00342 struct stat st; 00343 int ret_val, i, len, file; 00344 char buf[4096]; 00345 char name[FILE_MAXDIR + FILE_MAXFILE]; 00346 00347 strcpy(name, filename); 00348 BLI_path_abs(name, G.main->name); 00349 00350 if (stat(name, &st)) { 00351 ret_val = PF_NOFILE; 00352 } else if (st.st_size != pf->size) { 00353 ret_val = PF_DIFFERS; 00354 } else { 00355 // we'll have to compare the two... 00356 00357 file = open(name, O_BINARY | O_RDONLY); 00358 if (file < 0) { 00359 ret_val = PF_NOFILE; 00360 } else { 00361 ret_val = PF_EQUAL; 00362 00363 for (i = 0; i < pf->size; i += sizeof(buf)) { 00364 len = pf->size - i; 00365 if (len > sizeof(buf)) { 00366 len = sizeof(buf); 00367 } 00368 00369 if (read(file, buf, len) != len) { 00370 // read error ... 00371 ret_val = PF_DIFFERS; 00372 break; 00373 } else { 00374 if (memcmp(buf, ((char *)pf->data) + i, len)) { 00375 ret_val = PF_DIFFERS; 00376 break; 00377 } 00378 } 00379 } 00380 00381 close(file); 00382 } 00383 } 00384 00385 return(ret_val); 00386 } 00387 00388 /* 00389 00390 unpackFile() looks at the existing files (abs_name, local_name) and a packed file. 00391 00392 It returns a char *to the existing file name / new file name or NULL when 00393 there was an error or when the user desides to cancel the operation. 00394 00395 */ 00396 00397 char *unpackFile(ReportList *reports, char *abs_name, char *local_name, PackedFile *pf, int how) 00398 { 00399 char *newname = NULL, *temp = NULL; 00400 00401 // char newabs[FILE_MAXDIR + FILE_MAXFILE]; 00402 // char newlocal[FILE_MAXDIR + FILE_MAXFILE]; 00403 00404 if (pf != NULL) { 00405 switch (how) { 00406 case -1: 00407 case PF_KEEP: 00408 break; 00409 case PF_REMOVE: 00410 temp= abs_name; 00411 break; 00412 case PF_USE_LOCAL: 00413 // if file exists use it 00414 if (BLI_exists(local_name)) { 00415 temp = local_name; 00416 break; 00417 } 00418 // else fall through and create it 00419 case PF_WRITE_LOCAL: 00420 if (writePackedFile(reports, local_name, pf, 1) == RET_OK) { 00421 temp = local_name; 00422 } 00423 break; 00424 case PF_USE_ORIGINAL: 00425 // if file exists use it 00426 if (BLI_exists(abs_name)) { 00427 temp = abs_name; 00428 break; 00429 } 00430 // else fall through and create it 00431 case PF_WRITE_ORIGINAL: 00432 if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) { 00433 temp = abs_name; 00434 } 00435 break; 00436 default: 00437 printf("unpackFile: unknown return_value %d\n", how); 00438 break; 00439 } 00440 00441 if (temp) { 00442 newname = MEM_mallocN(strlen(temp) + 1, "unpack_file newname"); 00443 strcpy(newname, temp); 00444 } 00445 } 00446 00447 return (newname); 00448 } 00449 00450 00451 int unpackVFont(ReportList *reports, VFont *vfont, int how) 00452 { 00453 char localname[FILE_MAXDIR + FILE_MAXFILE], fi[FILE_MAXFILE]; 00454 char *newname; 00455 int ret_value = RET_ERROR; 00456 00457 if (vfont != NULL) { 00458 strcpy(localname, vfont->name); 00459 BLI_splitdirstring(localname, fi); 00460 00461 sprintf(localname, "//fonts/%s", fi); 00462 00463 newname = unpackFile(reports, vfont->name, localname, vfont->packedfile, how); 00464 if (newname != NULL) { 00465 ret_value = RET_OK; 00466 freePackedFile(vfont->packedfile); 00467 vfont->packedfile = NULL; 00468 strcpy(vfont->name, newname); 00469 MEM_freeN(newname); 00470 } 00471 } 00472 00473 return (ret_value); 00474 } 00475 00476 int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how) 00477 { 00478 char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; 00479 char *newname; 00480 int ret_value = RET_ERROR; 00481 00482 if (sound != NULL) { 00483 strcpy(localname, sound->name); 00484 BLI_splitdirstring(localname, fi); 00485 sprintf(localname, "//sounds/%s", fi); 00486 00487 newname = unpackFile(reports, sound->name, localname, sound->packedfile, how); 00488 if (newname != NULL) { 00489 strcpy(sound->name, newname); 00490 MEM_freeN(newname); 00491 00492 freePackedFile(sound->packedfile); 00493 sound->packedfile = NULL; 00494 00495 sound_load(bmain, sound); 00496 00497 ret_value = RET_OK; 00498 } 00499 } 00500 00501 return(ret_value); 00502 } 00503 00504 int unpackImage(ReportList *reports, Image *ima, int how) 00505 { 00506 char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; 00507 char *newname; 00508 int ret_value = RET_ERROR; 00509 00510 if (ima != NULL) { 00511 strcpy(localname, ima->name); 00512 BLI_splitdirstring(localname, fi); 00513 sprintf(localname, "//textures/%s", fi); 00514 00515 newname = unpackFile(reports, ima->name, localname, ima->packedfile, how); 00516 if (newname != NULL) { 00517 ret_value = RET_OK; 00518 freePackedFile(ima->packedfile); 00519 ima->packedfile = NULL; 00520 strcpy(ima->name, newname); 00521 MEM_freeN(newname); 00522 BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); 00523 } 00524 } 00525 00526 return(ret_value); 00527 } 00528 00529 void unpackAll(Main *bmain, ReportList *reports, int how) 00530 { 00531 Image *ima; 00532 VFont *vf; 00533 bSound *sound; 00534 00535 for(ima=bmain->image.first; ima; ima=ima->id.next) 00536 if(ima->packedfile) 00537 unpackImage(reports, ima, how); 00538 00539 for(vf=bmain->vfont.first; vf; vf=vf->id.next) 00540 if(vf->packedfile) 00541 unpackVFont(reports, vf, how); 00542 00543 for(sound=bmain->sound.first; sound; sound=sound->id.next) 00544 if(sound->packedfile) 00545 unpackSound(bmain, reports, sound, how); 00546 } 00547