Blender V2.61 - r43446

packedFile.c

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