Blender  V2.59
packedFile.c
Go to the documentation of this file.
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