Logo Search packages:      
Sourcecode: blender version File versions

readfile.c

/*
 * readfile.c
 *
 * .blend file reading
 *
 * $Id: readfile.c,v 1.99 2004/12/10 14:50:39 ton Exp $
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef WIN32
#include "winsock2.h"
#include "BLI_winstuff.h"
#endif

#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE
#include <stdlib.h> // for getenv atoi
#include <fcntl.h> // for open
#include <string.h> // for strcasecmp strrchr strncmp strstr
#include <math.h> // for fabs

#ifndef WIN32
    #include <unistd.h> // for read close
    #include <sys/param.h> // for MAXPATHLEN
#else
    #include <io.h> // for open close read
#endif

#include "nla.h"

#include "DNA_ID.h"
#include "DNA_packedFile_types.h"
#include "DNA_property_types.h"
#include "DNA_actuator_types.h"
#include "DNA_controller_types.h"
#include "DNA_sensor_types.h"
#include "DNA_sdna_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_ika_types.h"
#include "DNA_camera_types.h"
#include "DNA_lattice_types.h"
#include "DNA_texture_types.h"
#include "DNA_key_types.h"
#include "DNA_meta_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
#include "DNA_world_types.h"
#include "DNA_ipo_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_image_types.h"
#include "DNA_material_types.h"
#include "DNA_curve_types.h"
#include "DNA_vfont_types.h"
#include "DNA_effect_types.h"
#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_oops_types.h"
#include "DNA_group_types.h"
#include "DNA_userdef_types.h"
#include "DNA_fileglobal_types.h"
#include "DNA_constraint_types.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_nla_types.h"

#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_storage_types.h" // for relname flags

#include "BKE_bad_level_calls.h" // for reopen_text build_seqar (from WHILE_SEQ) open_plugin_seq set_rects_butspace check_imasel_copy

#include "BKE_constraint.h"
#include "BKE_utildefines.h" // SWITCH_INT WHILE_SEQ END_SEQ DATA ENDB DNA1 O_BINARY GLOB USER TEST REND
#include "BKE_main.h" // for Main
#include "BKE_global.h" // for G
#include "BKE_property.h" // for get_property
#include "BKE_library.h" // for wich_libbase
#include "BKE_texture.h" // for open_plugin_tex
#include "BKE_effect.h" // for give_parteff
#include "BKE_sca.h" // for init_actuator
#include "BKE_mesh.h" // for ME_ defines (patching)
#include "BKE_armature.h"     //    for precalc_bonelist_irestmats
#include "BKE_action.h"
#include "BKE_object.h"
#include "BKE_scene.h"

#include "BIF_butspace.h" // for do_versions, patching event codes

#include "BLO_readfile.h"
#include "BLO_undofile.h"
#include "readfile.h"

#include "genfile.h"

#include "BLO_readblenfile.h" // streaming read pipe, for BLO_readblenfile BLO_readblenfilememory

#include "mydevice.h"

/*
 Remark: still a weak point is the newadress() function, that doesnt solve reading from
 multiple files at the same time

 (added remark: oh, i thought that was solved? will look at that... (ton)

READ
- Existing Library (Main) push or free
- allocate new Main
- load file
- read SDNA
- for each LibBlock
      - read LibBlock
      - if a Library
            - make a new Main
            - attach ID's to it
      - else
            - read associated 'direct data'
            - link direct data (internal and to LibBlock)
- read FileGlobal
- read USER data, only when indicated (file is ~/.B.blend)
- free file
- per Library (per Main)
      - read file
      - read SDNA
      - find LibBlocks and attach IDs to Main
            - if external LibBlock
                  - search all Main's
                        - or it's already read,
                        - or not read yet
                        - or make new Main
      - per LibBlock
            - read recursive
            - read associated direct data
            - link direct data (internal and to LibBlock)
      - free file
- per Library with unread LibBlocks
      - read file
      - read SDNA
      - per LibBlock
               - read recursive
               - read associated direct data
               - link direct data (internal and to LibBlock)
        - free file
- join all Mains
- link all LibBlocks and indirect pointers to libblocks
- initialize FileGlobal and copy pointers to Global
*/

/* also occurs in library.c */
/* GS reads the memory pointed at in a specific ordering. There are,
 * however two definitions for it. I have jotted them down here, both,
 * but I think the first one is actually used. The thing is that
 * big-endian systems might read this the wrong way round. OTOH, we
 * constructed the IDs that are read out with this macro explicitly as
 * well. I expect we'll sort it out soon... */

/* from blendef: */
#define GS(a)     (*((short *)(a)))

/* from misc_util: flip the bytes from x  */
/*  #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */

// only used here in readfile.c
#define SWITCH_LONGINT(a) { \
    char s_i, *p_i; \
    p_i= (char *)&(a);  \
    s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
    s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
    s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
    s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
// only used here in readfile.c
#define SWITCH_SHORT(a) { \
    char s_i, *p_i; \
    p_i= (char *)&(a); \
    s_i=p_i[0]; p_i[0]=p_i[1]; p_i[1]=s_i; }


/***/

typedef struct OldNew {
      void *old, *newp;
      int nr;
} OldNew;

typedef struct OldNewMap {
      OldNew *entries;
      int nentries, entriessize;

      int lasthit;
} OldNewMap;

static OldNewMap *oldnewmap_new(void) {
      OldNewMap *onm= MEM_mallocN(sizeof(*onm), "OldNewMap");
      onm->lasthit= 0;
      onm->nentries= 0;
      onm->entriessize= 1024;
      onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");

      return onm;
}

static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr) {
      OldNew *entry;

      if (onm->nentries==onm->entriessize) {
            int osize= onm->entriessize;
            OldNew *oentries= onm->entries;

            onm->entriessize*= 2;
            onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");

            memcpy(onm->entries, oentries, sizeof(*oentries)*osize);
            MEM_freeN(oentries);
      }

      entry= &onm->entries[onm->nentries++];
      entry->old= oldaddr;
      entry->newp= newaddr;
      entry->nr= nr;
}

static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr) {
      int i;

      if (onm->lasthit<onm->nentries-1) {
            OldNew *entry= &onm->entries[++onm->lasthit];

            if (entry->old==addr) {
                  entry->nr++;
                  return entry->newp;
            }
      }

      for (i=0; i<onm->nentries; i++) {
            OldNew *entry= &onm->entries[i];

            if (entry->old==addr) {
                  onm->lasthit= i;

                  entry->nr++;
                  return entry->newp;
            }
      }

      return NULL;
}

static void *oldnewmap_liblookup_and_inc(OldNewMap *onm, void *addr, void *lib) {
      int i;

      if (onm->lasthit<onm->nentries-1) {
            OldNew *entry= &onm->entries[++onm->lasthit];

            if (entry->old==addr) {
                  ID *id= entry->newp;

                  if (id && (!lib || id->lib)) {
                        entry->nr++;

                        return entry->newp;
                  }
            }
      }

      for (i=0; i<onm->nentries; i++) {
            OldNew *entry= &onm->entries[i];

            if (entry->old==addr) {
                  ID *id= entry->newp;

                  if (id && (!lib || id->lib)) {
                        entry->nr++;

                        return entry->newp;
                  }
            }
      }

      return NULL;
}

static void *oldnewmap_typelookup_and_inc(OldNewMap *onm, void *addr, short type) {
      int i;

      if (onm->lasthit<onm->nentries-1) {
            OldNew *entry= &onm->entries[++onm->lasthit];

            if (entry->old==addr) {
                  ID *id= entry->newp;

                  if (id && (GS(id->name) == type)) {
                        entry->nr++;

                        return entry->newp;
                  }
            }
      }

      for (i=0; i<onm->nentries; i++) {
            OldNew *entry= &onm->entries[i];

            if (entry->old==addr) {
                  ID *id= entry->newp;

                  if (id && (GS(id->name) == type)) {
                        entry->nr++;

                        return entry->newp;
                  }
            }
      }

      return NULL;
}

static void oldnewmap_free_unused(OldNewMap *onm) {
      int i;

      for (i=0; i<onm->nentries; i++) {
            OldNew *entry= &onm->entries[i];
            if (entry->nr==0) {
                  MEM_freeN(entry->newp);
                  entry->newp= NULL;
            }
      }
}

static void oldnewmap_clear(OldNewMap *onm) {
      onm->nentries= 0;
      onm->lasthit= 0;
}

static void oldnewmap_free(OldNewMap *onm) {
      MEM_freeN(onm->entries);
      MEM_freeN(onm);
}

/***/

static void read_libraries(FileData *basefd, ListBase *mainlist);

/* ************ help functions ***************** */

static void add_main_to_main(Main *mainvar, Main *from)
{
      ListBase *lbarray[100], *fromarray[100];  // define in library.c too
      int a;

      a= set_listbasepointers(mainvar, lbarray);
      a= set_listbasepointers(from, fromarray);
      while(a--) {
            addlisttolist(lbarray[a], fromarray[a]);
      }
}

void blo_join_main(ListBase *mainlist)
{
      Main *tojoin, *mainl= mainlist->first;

      while ((tojoin= mainl->next)) {
            add_main_to_main(mainl, tojoin);
            BLI_remlink(mainlist, tojoin);
            MEM_freeN(tojoin);
      }
}

static void split_libdata(ListBase *lb, Main *first)
{
      ListBase *lbn;
      ID *id, *idnext;
      Main *mainvar;

      id= lb->first;
      while(id) {
            idnext= id->next;
            if(id->lib) {
                  mainvar= first;
                  while(mainvar) {
                        if(mainvar->curlib==id->lib) {
                              lbn= wich_libbase(mainvar, GS(id->name));
                              BLI_remlink(lb, id);
                              BLI_addtail(lbn, id);
                              break;
                        }
                        mainvar= mainvar->next;
                  }
                  if(mainvar==0) printf("error split_libdata\n");
            }
            id= idnext;
      }
}

void blo_split_main(ListBase *mainlist)
{
      Main *mainl= mainlist->first;
      ListBase *lbarray[30];
      Library *lib;
      int i;

      for (lib= mainl->library.first; lib; lib= lib->id.next) {
            Main *libmain= MEM_callocN(sizeof(*libmain), "libmain");
            libmain->curlib= lib;

            BLI_addtail(mainlist, libmain);
      }

      i= set_listbasepointers(mainl, lbarray);
      while(i--)
            split_libdata(lbarray[i], mainl->next);
}

static Main *blo_find_main(ListBase *mainlist, char *name)
{
      Main *m;
      Library *lib;
      char name1[FILE_MAXDIR+FILE_MAXFILE];
      char libname1[FILE_MAXDIR+FILE_MAXFILE];

      /* name can be stringcode too */
      strcpy(name1, name);
      BLI_convertstringcode(name1, G.sce, 0);

      for (m= mainlist->first; m; m= m->next) {
            char *libname= (m->curlib)?m->curlib->name:m->name;
            
            strcpy(libname1, libname);
            BLI_convertstringcode(libname1, G.sce, 0);
            
            if (BLI_streq(name1, libname1))
                  return m;
      }

      m= MEM_callocN(sizeof(*m), "find_main");
      BLI_addtail(mainlist, m);

      lib= alloc_libblock(&m->library, ID_LI, "lib");
      strcpy(lib->name, name);
      m->curlib= lib;

      return m;
}


/* ************ FILE PARSING ****************** */

static void switch_endian_bh4(BHead4 *bhead)
{
      /* the ID_.. codes */
      if((bhead->code & 0xFFFF)==0) bhead->code >>=16;

      if (bhead->code != ENDB) {
            SWITCH_INT(bhead->len);
            SWITCH_INT(bhead->SDNAnr);
            SWITCH_INT(bhead->nr);
      }
}

static void switch_endian_bh8(BHead8 *bhead)
{
      /* the ID_.. codes */
      if((bhead->code & 0xFFFF)==0) bhead->code >>=16;

      if (bhead->code != ENDB) {
            SWITCH_INT(bhead->len);
            SWITCH_INT(bhead->SDNAnr);
            SWITCH_INT(bhead->nr);
      }
}

static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, int do_endian_swap)
{
      BHead4 *bhead4 = (BHead4 *) bhead;
#if defined(WIN32) && !defined(FREE_WINDOWS)
      __int64 old;
#else
      long long old;
#endif

      bhead4->code= bhead8->code;
      bhead4->len= bhead8->len;

      if (bhead4->code != ENDB) {

            // why is this here ??
            if (do_endian_swap) {
                  SWITCH_LONGINT(bhead8->old);
            }

            /* this patch is to avoid a long long being read from not-eight aligned positions
               is necessary on SGI with -n32 compiling (no, is necessary on
               any modern 64bit architecture) */
            memcpy(&old, &bhead8->old, 8);
            bhead4->old = (int) (old >> 3);

            bhead4->SDNAnr= bhead8->SDNAnr;
            bhead4->nr= bhead8->nr;
      }
}

static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4)
{
      BHead8 *bhead8 = (BHead8 *) bhead;

      bhead8->code= bhead4->code;
      bhead8->len= bhead4->len;

      if (bhead8->code != ENDB) {
            bhead8->old= bhead4->old;
            bhead8->SDNAnr= bhead4->SDNAnr;
            bhead8->nr= bhead4->nr;
      }
}

static BHeadN *get_bhead(FileData *fd)
{
      BHead8 bhead8;
      BHead4 bhead4;
      BHead  bhead;
      BHeadN *new_bhead = 0;
      int readsize;

      if (fd) {
            if ( ! fd->eof) {

                  // First read the bhead structure.
                  // Depending on the platform the file was written on this can
                  // be a big or little endian BHead4 or BHead8 structure.

                  // As usual 'ENDB' (the last *partial* bhead of the file)
                  // needs some special handling. We don't want to EOF just yet.

                  if (fd->flags & FD_FLAGS_FILE_POINTSIZE_IS_4) {
                        bhead4.code = DATA;
                        readsize = fd->read(fd, &bhead4, sizeof(bhead4));

                        if (readsize == sizeof(bhead4) || bhead4.code == ENDB) {
                              if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
                                    switch_endian_bh4(&bhead4);
                              }

                              if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
                                    bh8_from_bh4(&bhead, &bhead4);
                              } else {
                                    memcpy(&bhead, &bhead4, sizeof(bhead));
                              }
                        } else {
                              fd->eof = 1;
                        }
                  } else {
                        bhead8.code = DATA;
                        readsize = fd->read(fd, &bhead8, sizeof(bhead8));

                        if (readsize == sizeof(bhead8) || bhead8.code == ENDB) {
                              if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
                                    switch_endian_bh8(&bhead8);
                              }

                              if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
                                    bh4_from_bh8(&bhead, &bhead8, (fd->flags & FD_FLAGS_SWITCH_ENDIAN));
                              } else {
                                    memcpy(&bhead, &bhead8, sizeof(bhead));
                              }
                        } else {
                              fd->eof = 1;
                        }
                  }

                  // bhead now contains the (converted) bhead structure. Now read
                  // the associated data and put everything in a BHeadN (creative naming !)

                  if ( ! fd->eof) {
                        new_bhead = MEM_mallocN(sizeof(BHeadN) + bhead.len, "new_bhead");
                        if (new_bhead) {
                              new_bhead->next = new_bhead->prev = 0;
                              new_bhead->bhead = bhead;

                              readsize = fd->read(fd, new_bhead + 1, bhead.len);

                              if (readsize != bhead.len) {
                                    fd->eof = 1;
                                    MEM_freeN(new_bhead);
                              }
                        } else {
                              fd->eof = 1;
                        }
                  }
            }
      }

      // We've read a new block. Now add it to the list
      // of blocks.

      if (new_bhead) {
            BLI_addtail(&fd->listbase, new_bhead);
      }

      return(new_bhead);
}

BHead *blo_firstbhead(FileData *fd)
{
      BHeadN *new_bhead;
      BHead *bhead = 0;

      // Rewind the file
      // Read in a new block if necessary

      new_bhead = fd->listbase.first;
      if (new_bhead == 0) {
            new_bhead = get_bhead(fd);
      }

      if (new_bhead) {
            bhead = &new_bhead->bhead;
      }

      return(bhead);
}

BHead *blo_prevbhead(FileData *fd, BHead *thisblock)
{
      BHeadN *bheadn= (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead));
      BHeadN *prev= bheadn->prev;

      return prev?&prev->bhead:NULL;
}

BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
{
      BHeadN *new_bhead = 0;
      BHead *bhead = 0;

      if (thisblock) {
            // bhead is actually a sub part of BHeadN
            // We calculate the BHeadN pointer from the BHead pointer below
            new_bhead = (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead));

            // get the next BHeadN. If it doesn't exist we read in the next one
            new_bhead = new_bhead->next;
            if (new_bhead == 0) {
                  new_bhead = get_bhead(fd);
            }
      }

      if (new_bhead) {
            // here we do the reverse:
            // go from the BHeadN pointer to the BHead pointer
            bhead = &new_bhead->bhead;
      }

      return(bhead);
}

static void decode_blender_header(FileData *fd)
{
      char header[SIZEOFBLENDERHEADER], num[4];
      int readsize;

      // read in the header data
      readsize = fd->read(fd, header, sizeof(header));

      if (readsize == sizeof(header)) {
            if(strncmp(header, "BLENDER", 7) == 0) {
                  int remove_this_endian_test= 1;

                  fd->flags |= FD_FLAGS_FILE_OK;

                  // what size are pointers in the file ?
                  if(header[7]=='_') {
                        fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4;
                        if (sizeof(void *) != 4) {
                              fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
                        }
                  } else {
                        if (sizeof(void *) != 8) {
                              fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
                        }
                  }

                  // is the file saved in a different endian
                  // than we need ?
                  if (((((char*)&remove_this_endian_test)[0]==1)?L_ENDIAN:B_ENDIAN) != ((header[8]=='v')?L_ENDIAN:B_ENDIAN)) {
                        fd->flags |= FD_FLAGS_SWITCH_ENDIAN;
                  }

                  // get the version number

                  memcpy(num, header+9, 3);
                  num[3] = 0;
                  fd->fileversion = atoi(num);
            }
      }
}

static int read_file_dna(FileData *fd)
{
      BHead *bhead;

      for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
            if (bhead->code==DNA1) {
                  int do_endian_swap= (fd->flags&FD_FLAGS_SWITCH_ENDIAN)?1:0;

                  fd->filesdna= dna_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
                  if (fd->filesdna)
                        fd->compflags= dna_get_structDNA_compareflags(fd->filesdna, fd->memsdna);

                  return 1;
            } else if (bhead->code==ENDB)
                  break;
      }

      return 0;
}
static int fd_read_from_file(FileData *filedata, void *buffer, int size)
{
      int readsize = read(filedata->filedes, buffer, size);

      if (readsize < 0) {
            readsize = EOF;
      } else {
            filedata->seek += readsize;
      }

      return (readsize);
}

static int fd_read_from_memory(FileData *filedata, void *buffer, int size)
{
            // don't read more bytes then there are available in the buffer
      int readsize = MIN2(size, filedata->buffersize - filedata->seek);

      memcpy(buffer, filedata->buffer + filedata->seek, readsize);
      filedata->seek += readsize;

      return (readsize);
}

static int fd_read_from_memfile(FileData *filedata, void *buffer, int size)
{
      static unsigned int seek= 1<<30;    /* the current position */
      static unsigned int offset= 0;            /* size of previous chunks */
      static MemFileChunk *chunk=NULL;
      
      if(size==0) return 0;
      
      if(seek != filedata->seek) {
            chunk= filedata->memfile->chunks.first;
            seek= 0;
            
            while(chunk) {
                  if(seek + chunk->size > filedata->seek) break;
                  seek+= chunk->size;
                  chunk= chunk->next;
            }
            offset= seek;
            seek= filedata->seek;
      }
      
      if(chunk) {
            /* first check if it's on the end if current chunk */
            if( seek-offset == chunk->size) {
                  offset+= chunk->size;
                  chunk= chunk->next;
            }
            
            /* debug, should never happen */
            if(chunk==NULL) {
                  printf("illegal read, chunk zero\n");
                  return 0;
            }
            else if( (seek-offset)+size > chunk->size) {
                  size= chunk->size - (seek-offset);
                  printf("chunk too large, clipped to %d\n", size);
            }
            
            memcpy(buffer, chunk->buf + (seek-offset), size);
            filedata->seek += size;
            seek+= size;
            
            return (size);
            
      }
      return 0;
}

static FileData *filedata_new(void)
{
      extern char DNAstr[];   /* DNA.c */
      extern int DNAlen;
      FileData *fd = MEM_callocN(sizeof(*fd), "FileData");

      fd->filedes = -1;

            /* XXX, this doesn't need to be done all the time,
             * but it keeps us reentrant,  remove once we have
             * a lib that provides a nice lock. - zr
             */
      fd->memsdna = dna_sdna_from_data(DNAstr,  DNAlen,  0);

      fd->datamap = oldnewmap_new();
      fd->globmap = oldnewmap_new();
      fd->libmap = oldnewmap_new();

      return fd;
}

FileData *blo_openblenderfile(char *name)
{
      int file;
      char name1[FILE_MAXDIR+FILE_MAXFILE];
      
      /* library files can have stringcodes */
      strcpy(name1, name);
      BLI_convertstringcode(name1, G.sce, 0);
      
      file= open(name1, O_BINARY|O_RDONLY);

      if (file == -1) {
            return NULL;
      } else {
            FileData *fd = filedata_new();
            fd->filedes = file;
            fd->buffersize = BLI_filesize(file);
            fd->read = fd_read_from_file;

            decode_blender_header(fd);

            if (fd->flags & FD_FLAGS_FILE_OK) {
                  if (!read_file_dna(fd)) {
                        blo_freefiledata(fd);
                        fd= NULL;
                  }
            } else {
                  blo_freefiledata(fd);
                  fd= NULL;
            }

            return fd;
      }
}

FileData *blo_openblendermemory(void *mem, int memsize)
{
      if (!mem || memsize<SIZEOFBLENDERHEADER) {
            return NULL;
      } else {
            FileData *fd= filedata_new();
            fd->buffer= mem;
            fd->buffersize= memsize;
            fd->read= fd_read_from_memory;
            fd->flags|= FD_FLAGS_NOT_MY_BUFFER;

            decode_blender_header(fd);

            if (fd->flags & FD_FLAGS_FILE_OK) {
                  if (!read_file_dna(fd)) {
                        blo_freefiledata(fd);
                        fd= NULL;
                  }
            } else {
                  blo_freefiledata(fd);
                  fd= NULL;
            }

            return fd;
      }
}

FileData *blo_openblendermemfile(MemFile *memfile)
{
      if (!memfile) {
            return NULL;
      } else {
            FileData *fd= filedata_new();
            fd->memfile= memfile;

            fd->read= fd_read_from_memfile;
            fd->flags|= FD_FLAGS_NOT_MY_BUFFER;

            decode_blender_header(fd);

            if (fd->flags & FD_FLAGS_FILE_OK) {
                  if (!read_file_dna(fd)) {
                        blo_freefiledata(fd);
                        fd= NULL;
                  }
            } else {
                  blo_freefiledata(fd);
                  fd= NULL;
            }

            return fd;
      }
}


void blo_freefiledata(FileData *fd)
{
      if (fd) {
            if (fd->filedes != -1) {
                  close(fd->filedes);
            }

            if (fd->buffer && !(fd->flags & FD_FLAGS_NOT_MY_BUFFER)) {
                  MEM_freeN(fd->buffer);
                  fd->buffer = 0;
            }

            // Free all BHeadN data blocks
            BLI_freelistN(&fd->listbase);

            if (fd->memsdna)
                  dna_freestructDNA(fd->memsdna);
            if (fd->filesdna)
                  dna_freestructDNA(fd->filesdna);
            if (fd->compflags)
                  MEM_freeN(fd->compflags);

            if (fd->datamap)
                  oldnewmap_free(fd->datamap);
            if (fd->globmap)
                  oldnewmap_free(fd->globmap);
            if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP))
                  oldnewmap_free(fd->libmap);

            MEM_freeN(fd);
      }
}

/* ************ DIV ****************** */

int BLO_has_bfile_extension(char *str)
{
      return (BLI_testextensie(str, ".ble") || BLI_testextensie(str, ".blend"));
}

/* ************** OLD POINTERS ******************* */

static void *newdataadr(FileData *fd, void *adr)            /* only direct databocks */
{
      return oldnewmap_lookup_and_inc(fd->datamap, adr);
}

static void *newglobadr(FileData *fd, void *adr)            /* direct datablocks with global linking */
{
      return oldnewmap_lookup_and_inc(fd->globmap, adr);
}

static void *newlibadr(FileData *fd, void *lib, void *adr)        /* only lib data */
{
      return oldnewmap_liblookup_and_inc(fd->libmap, adr, lib);
}

static void *newlibadr_us_type(FileData *fd, short type, void *adr)     /* only Lib data */
{
      ID *id= oldnewmap_typelookup_and_inc(fd->libmap, adr, type);

      if (id) {
            id->us++;
      }

      return id;
}

static void *newlibadr_us(FileData *fd, void *lib, void *adr)     /* increases user number */
{
      ID *id= newlibadr(fd, lib, adr);

      if(id) {
            id->us++;
      }

      return id;
}

static void change_libadr(FileData *fd, void *old, void *new)
{
      int i;

            /* changed one thing here, the old change_libadr
             * only remapped addresses that had an id->lib,
             * but that doesn't make sense to me... its an
             * old pointer, period, it needs to be remapped. - zr
             */

            /*
             * Ton seemed to think it was necessary to look
             * through all entries, and not return after finding
             * a match, leaving this cryptic comment,
             * // no return, maybe there can be more?
             *
             * That doesn't make sense to me either but I am
             * too scared to remove it... it only would make
             * sense if two distinct old address map to the
             * same new address - obviously that shouldn't happen
             * because memory addresses are unique.
             *
             * The only case it might happen is when two distinct
             * libraries are mapped using the same table... this
             * won't work to start with... At some point this
             * all needs to be made sense of and made understandable,
             * but I'm afraid I don't have time now. -zr
             *
             */
    /* the code is nasty, and needs a lot of energy to get into full understanding
       again... i now translate dutch comments, maybe that gives me more insight!
       But i guess it has to do with the assumption that 2 addresses can be allocated
       in different sessions, and therefore be the same... like the remark in the top
       of this c file (ton) */

      for (i=0; i<fd->libmap->nentries; i++) {
            OldNew *entry= &fd->libmap->entries[i];

            if (old==entry->newp) {
                  entry->newp= new;
                  break;
            }
      }
}


/* ********** END OLD POINTERS ****************** */
/* ********** READ FILE ****************** */

static void switch_endian_structs(struct SDNA *filesdna, BHead *bhead)
{
      int blocksize, nblocks;
      char *data;

      data= (char *)(bhead+1); /*  BHEAD+DATA dependancy */
      blocksize= filesdna->typelens[ filesdna->structs[bhead->SDNAnr][0] ];

      nblocks= bhead->nr;
      while(nblocks--) {
            dna_switch_endian_struct(filesdna, bhead->SDNAnr, data);

            data+= blocksize;
      }
}

static void *read_struct(FileData *fd, BHead *bh, char *blockname)
{
      void *temp= NULL;

      if (bh->len) {
            if (bh->SDNAnr && (fd->flags & FD_FLAGS_SWITCH_ENDIAN))
                  switch_endian_structs(fd->filesdna, bh);

            if (fd->compflags[bh->SDNAnr]) {    /* flag==0: doesn't exist anymore */
                  if(fd->compflags[bh->SDNAnr]==2) {
                        temp= dna_reconstruct(fd->memsdna, fd->filesdna, fd->compflags, bh->SDNAnr, bh->nr, (bh+1));
                  } else {
                        temp= MEM_mallocN(bh->len, blockname);
                        memcpy(temp, (bh+1), bh->len); /*  BHEAD+DATA dependancy */
                  }
            }
      }

      return temp;
}

static void link_list(FileData *fd, ListBase *lb)           /* only direct data */
{
      Link *ln, *prev;

      if(lb->first==0) return;

      lb->first= newdataadr(fd, lb->first);
      ln= lb->first;
      prev= 0;
      while(ln) {
            ln->next= newdataadr(fd, ln->next);
            ln->prev= prev;
            prev= ln;
            ln= ln->next;
      }
      lb->last= prev;
}

static void link_glob_list(FileData *fd, ListBase *lb)            /* for glob data */
{
      Link *ln, *prev;
      void *poin;

      if(lb->first==0) return;
      poin= newdataadr(fd, lb->first);
      if(lb->first) {
            oldnewmap_insert(fd->globmap, lb->first, poin, 0);
      }
      lb->first= poin;

      ln= lb->first;
      prev= 0;
      while(ln) {
            poin= newdataadr(fd, ln->next);
            if(ln->next) {
                  oldnewmap_insert(fd->globmap, ln->next, poin, 0);
            }
            ln->next= poin;
            ln->prev= prev;
            prev= ln;
            ln= ln->next;
      }
      lb->last= prev;
}

static void test_pointer_array(FileData *fd, void **mat)
{
#if defined(WIN32) && !defined(FREE_WINDOWS)
      __int64 *lpoin, *lmat;
#else
      long long *lpoin, *lmat;
#endif
      int len, *ipoin, *imat;

            /* manually convert the pointer array in
             * the old dna format to a pointer array in
             * the new dna format.
             */
      if(*mat) {
            len= MEM_allocN_len(*mat)/fd->filesdna->pointerlen;

            if(fd->filesdna->pointerlen==8 && fd->memsdna->pointerlen==4) {
                  ipoin=imat= MEM_mallocN( len*4, "newmatar");
                  lpoin= *mat;

                  while(len-- > 0) {
                        if((fd->flags & FD_FLAGS_SWITCH_ENDIAN))
                              SWITCH_LONGINT(*lpoin);
                        *ipoin= (int) ((*lpoin) >> 3);
                        ipoin++;
                        lpoin++;
                  }
                  MEM_freeN(*mat);
                  *mat= imat;
            }

            if(fd->filesdna->pointerlen==4 && fd->memsdna->pointerlen==8) {
                  lpoin=lmat= MEM_mallocN( len*8, "newmatar");
                  ipoin= *mat;

                  while(len-- > 0) {
                        *lpoin= *ipoin;
                        ipoin++;
                        lpoin++;
                  }
                  MEM_freeN(*mat);
                  *mat= lmat;
            }
      }
}

/* ************ READ PACKEDFILE *************** */

static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
{
      PackedFile *pf= newdataadr(fd, oldpf);

      if (pf) {
            pf->data= newdataadr(fd, pf->data);
      }

      return pf;
}

/* ************ READ SCRIPTLINK *************** */

static void lib_link_scriptlink(FileData *fd, ID *id, ScriptLink *slink)
{
      int i;

      for(i=0; i<slink->totscript; i++) {
            slink->scripts[i]= newlibadr(fd, id->lib, slink->scripts[i]);
      }
}

static void direct_link_scriptlink(FileData *fd, ScriptLink *slink)
{
      slink->scripts= newdataadr(fd, slink->scripts);
      slink->flag= newdataadr(fd, slink->flag);

      if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
            int a;

            for(a=0; a<slink->totscript; a++) {
                  SWITCH_SHORT(slink->flag[a]);
            }
      }
}

/* ************ READ IKA ***************** */

static void lib_link_ika(FileData *fd, Main *main)
{
      Ika *ika;
      int a;
      Deform *def;

      ika= main->ika.first;
      while(ika) {
            if(ika->id.flag & LIB_NEEDLINK) {

                  ika->parent= newlibadr(fd, ika->id.lib, ika->parent);

                  a= ika->totdef;
                  def= ika->def;
                  while(a--) {
                        def->ob=  newlibadr(fd, ika->id.lib, def->ob);
                        def++;
                  }
                  ika->id.flag -= LIB_NEEDLINK;
            }
            ika= ika->id.next;
      }
}

static void direct_link_ika(FileData *fd, Ika *ika)
{
      link_list(fd, &ika->limbbase);

      ika->def= newdataadr(fd, ika->def);

      /* error from V.138 and older */
      if(ika->def==0) ika->totdef= 0;
}

/* ************ READ ARMATURE ***************** */

static void lib_link_nlastrips(FileData *fd, ID *id, ListBase *striplist)
{
      bActionStrip *strip;

      for (strip=striplist->first; strip; strip=strip->next){
            strip->act = newlibadr_us(fd, id->lib, strip->act);
            strip->ipo = newlibadr(fd, id->lib, strip->ipo);
      };
}

static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbase)
{
      bConstraintChannel *chan;

      for (chan=chanbase->first; chan; chan=chan->next){
            chan->ipo = newlibadr_us(fd, id->lib, chan->ipo);
      }
}

static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
{
      bConstraint *con;

      for (con = conlist->first; con; con=con->next) {
            /*  patch for error introduced by changing constraints (dunno how) */
            if(con->data==NULL) {
                  con->type= CONSTRAINT_TYPE_NULL;
            }

            switch (con->type) {
            case CONSTRAINT_TYPE_ACTION:
                  {
                        bActionConstraint *data;
                        data= ((bActionConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                        data->act = newlibadr(fd, id->lib, data->act);
                  }
                  break;
            case CONSTRAINT_TYPE_LOCLIKE:
                  {
                        bLocateLikeConstraint *data;
                        data= ((bLocateLikeConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  };
                  break;
            case CONSTRAINT_TYPE_ROTLIKE:
                  {
                        bRotateLikeConstraint *data;
                        data= ((bRotateLikeConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  };
                  break;
            case CONSTRAINT_TYPE_KINEMATIC:
                  {
                        bKinematicConstraint *data;
                        data = ((bKinematicConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  }
                  break;
            case CONSTRAINT_TYPE_TRACKTO:
                  {
                        bTrackToConstraint *data;
                        data = ((bTrackToConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  }
                  break;
            case CONSTRAINT_TYPE_LOCKTRACK:
                  {
                        bLockTrackConstraint *data;
                        data= ((bLockTrackConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  };
                  break;
            case CONSTRAINT_TYPE_FOLLOWPATH:
                  {
                        bFollowPathConstraint *data;
                        data= ((bFollowPathConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  };
                  break;
            case CONSTRAINT_TYPE_DISTANCELIMIT:
                  {
                        bDistanceLimitConstraint *data;
                        data= ((bDistanceLimitConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  };
                  break;
            case CONSTRAINT_TYPE_STRETCHTO:
                  {
                        bStretchToConstraint *data;
                        data= ((bStretchToConstraint*)con->data);
                        data->tar = newlibadr(fd, id->lib, data->tar);
                  };
                  break;

            case CONSTRAINT_TYPE_NULL:
                  break;
            }
      }
}

static void direct_link_constraints(FileData *fd, ListBase *lb)
{
      bConstraint *cons;

      link_list(fd, lb);
      for (cons=lb->first; cons; cons=cons->next) {
            cons->data = newdataadr(fd, cons->data);
            switch (cons->type) {
            default:
                  break;
            }
            // Link data
      }
}

static void lib_link_bone(FileData *fd, ID *id, Bone *bone)
{
      Bone *curBone;

//    lib_link_constraints(fd, id, &bone->constraints);

      for (curBone=bone->childbase.first; curBone; curBone=curBone->next) {
            lib_link_bone(fd, id, curBone);
      }
}


static void lib_link_pose(FileData *fd, ID *id, bPose *pose)
{
      bPoseChannel *chan;

      if (!pose)
            return;

      for (chan = pose->chanbase.first; chan; chan=chan->next) {
            lib_link_constraints(fd, id, &chan->constraints);
      }
}

static void lib_link_armature(FileData *fd, Main *main)
{
      bArmature *arm;
      Bone *bone;

      arm= main->armature.first;

      while(arm) {
            if(arm->id.flag & LIB_NEEDLINK) {
                  arm->id.flag -= LIB_NEEDLINK;
            }

            for (bone=arm->bonebase.first; bone; bone=bone->next) {
                  lib_link_bone(fd, &arm->id, bone);
            }

            arm= arm->id.next;
      }
}

static void lib_link_action(FileData *fd, Main *main)
{
      bAction *act;
      bActionChannel *chan;

      act= main->action.first;
      while(act) {
            if(act->id.flag & LIB_NEEDLINK) {
                  act->id.flag -= LIB_NEEDLINK;

                  for (chan=act->chanbase.first; chan; chan=chan->next) {
                        chan->ipo= newlibadr_us(fd, act->id.lib, chan->ipo);
                        lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
                  }

            }
            act= act->id.next;
      }
}

static void direct_link_bones(FileData *fd, Bone* bone)
{
      Bone  *child;

      bone->parent= newdataadr(fd, bone->parent);

      link_list(fd, &bone->childbase);

      for (child=bone->childbase.first; child; child=child->next) {
            direct_link_bones(fd, child);
      }
}


static void direct_link_action(FileData *fd, bAction *act)
{
      bActionChannel *achan;

      link_list(fd, &act->chanbase);

      for (achan = act->chanbase.first; achan; achan=achan->next)
            link_list(fd, &achan->constraintChannels);

}

static void direct_link_armature(FileData *fd, bArmature *arm)
{
      Bone  *bone;

      link_list(fd, &arm->bonebase);

      bone=arm->bonebase.first;
      while (bone) {
            direct_link_bones(fd, bone);
            bone=bone->next;
      }
}

/* ************ READ CAMERA ***************** */

static void lib_link_camera(FileData *fd, Main *main)
{
      Camera *ca;

      ca= main->camera.first;
      while(ca) {
            if(ca->id.flag & LIB_NEEDLINK) {

                  ca->ipo= newlibadr_us(fd, ca->id.lib, ca->ipo);

                  lib_link_scriptlink(fd, &ca->id, &ca->scriptlink);

                  ca->id.flag -= LIB_NEEDLINK;
            }
            ca= ca->id.next;
      }
}

static void direct_link_camera(FileData *fd, Camera *ca)
{
      direct_link_scriptlink(fd, &ca->scriptlink);
}


/* ************ READ LATTICE ***************** */

static void lib_link_latt(FileData *fd, Main *main)
{
      Lattice *lt;

      lt= main->latt.first;
      while(lt) {
            if(lt->id.flag & LIB_NEEDLINK) {

                  lt->ipo= newlibadr_us(fd, lt->id.lib, lt->ipo);
                  lt->key= newlibadr_us(fd, lt->id.lib, lt->key);

                  lt->id.flag -= LIB_NEEDLINK;
            }
            lt= lt->id.next;
      }
}

static void direct_link_latt(FileData *fd, Lattice *lt)
{
      lt->def= newdataadr(fd, lt->def);
}

/* ************ READ LAMP ***************** */

static void lib_link_lamp(FileData *fd, Main *main)
{
      Lamp *la;
      MTex *mtex;
      int a;

      la= main->lamp.first;
      while(la) {
            if(la->id.flag & LIB_NEEDLINK) {

                  for(a=0; a<MAX_MTEX; a++) {
                        mtex= la->mtex[a];
                        if(mtex) {
                              mtex->tex= newlibadr_us(fd, la->id.lib, mtex->tex);
                              mtex->object= newlibadr(fd, la->id.lib, mtex->object);
                        }
                  }

                  la->ipo= newlibadr_us(fd, la->id.lib, la->ipo);

                  lib_link_scriptlink(fd, &la->id, &la->scriptlink);

                  la->id.flag -= LIB_NEEDLINK;
            }
            la= la->id.next;
      }
}

static void direct_link_lamp(FileData *fd, Lamp *la)
{
      int a;

      direct_link_scriptlink(fd, &la->scriptlink);

      for(a=0; a<MAX_MTEX; a++) {
            la->mtex[a]= newdataadr(fd, la->mtex[a]);
      }
}

/* ************ READ keys ***************** */

static void lib_link_key(FileData *fd, Main *main)
{
      Key *key;

      key= main->key.first;
      while(key) {
            if(key->id.flag & LIB_NEEDLINK) {

                  key->ipo= newlibadr_us(fd, key->id.lib, key->ipo);
                  key->from= newlibadr(fd, key->id.lib, key->from);

                  key->id.flag -= LIB_NEEDLINK;
            }
            key= key->id.next;
      }
}

static void switch_endian_keyblock(Key *key, KeyBlock *kb)
{
      int elemsize, a, b;
      char *data, *poin, *cp;

      elemsize= key->elemsize;
      data= kb->data;

      for(a=0; a<kb->totelem; a++) {

            cp= key->elemstr;
            poin= data;

            while( cp[0] ) {  /* cp[0]==amount */

                  switch(cp[1]) {         /* cp[1]= type */
                  case IPO_FLOAT:
                  case IPO_BPOINT:
                  case IPO_BEZTRIPLE:
                        b= cp[0];
                        while(b--) {
                              SWITCH_INT((*poin));
                              poin+= 4;
                        }
                        break;
                  }

                  cp+= 2;

            }
            data+= elemsize;
      }
}

static void direct_link_key(FileData *fd, Key *key)
{
      KeyBlock *kb;

      link_list(fd, &(key->block));

      key->refkey= newdataadr(fd, key->refkey);

      kb= key->block.first;
      while(kb) {

            kb->data= newdataadr(fd, kb->data);

            if(fd->flags & FD_FLAGS_SWITCH_ENDIAN)
                  switch_endian_keyblock(key, kb);

            kb= kb->next;
      }
}

/* ************ READ mball ***************** */

static void lib_link_mball(FileData *fd, Main *main)
{
      MetaBall *mb;
      int a;

      mb= main->mball.first;
      while(mb) {
            if(mb->id.flag & LIB_NEEDLINK) {

                  for(a=0; a<mb->totcol; a++) mb->mat[a]= newlibadr_us(fd, mb->id.lib, mb->mat[a]);

                  mb->ipo= newlibadr_us(fd, mb->id.lib, mb->ipo);

                  mb->id.flag -= LIB_NEEDLINK;
            }
            mb= mb->id.next;
      }
}

static void direct_link_mball(FileData *fd, MetaBall *mb)
{
      mb->mat= newdataadr(fd, mb->mat);
      test_pointer_array(fd, (void **)&mb->mat);

      link_list(fd, &(mb->elems));

      mb->disp.first= mb->disp.last= 0;

      mb->bb= 0;
}

/* ************ READ WORLD ***************** */

static void lib_link_world(FileData *fd, Main *main)
{
      World *wrld;
      MTex *mtex;
      int a;

      wrld= main->world.first;
      while(wrld) {
            if(wrld->id.flag & LIB_NEEDLINK) {

                  wrld->ipo= newlibadr_us(fd, wrld->id.lib, wrld->ipo);

                  for(a=0; a<MAX_MTEX; a++) {
                        mtex= wrld->mtex[a];
                        if(mtex) {
                              mtex->tex= newlibadr_us(fd, wrld->id.lib, mtex->tex);
                              mtex->object= newlibadr(fd, wrld->id.lib, mtex->object);
                        }
                  }

                  lib_link_scriptlink(fd, &wrld->id, &wrld->scriptlink);

                  wrld->id.flag -= LIB_NEEDLINK;
            }
            wrld= wrld->id.next;
      }
}

static void direct_link_world(FileData *fd, World *wrld)
{
      int a;

      direct_link_scriptlink(fd, &wrld->scriptlink);

      for(a=0; a<MAX_MTEX; a++) {
            wrld->mtex[a]= newdataadr(fd, wrld->mtex[a]);
      }
}


/* ************ READ IPO ***************** */

static void lib_link_ipo(FileData *fd, Main *main)
{
      Ipo *ipo;

      ipo= main->ipo.first;
      while(ipo) {
            if(ipo->id.flag & LIB_NEEDLINK) {

                  ipo->id.flag -= LIB_NEEDLINK;
            }
            ipo= ipo->id.next;
      }
}

static void direct_link_ipo(FileData *fd, Ipo *ipo)
{
      IpoCurve *icu;

      link_list(fd, &(ipo->curve));
      icu= ipo->curve.first;
      while(icu) {
            icu->bezt= newdataadr(fd, icu->bezt);
            icu->bp= newdataadr(fd, icu->bp);
            icu= icu->next;
      }
}

/* ************ READ VFONT ***************** */

static void lib_link_vfont(FileData *fd, Main *main)
{
      VFont *vf;

      vf= main->vfont.first;
      while(vf) {
            if(vf->id.flag & LIB_NEEDLINK) {
                  vf->id.flag -= LIB_NEEDLINK;
            }
            vf= vf->id.next;
      }
}

static void direct_link_vfont(FileData *fd, VFont *vf)
{
      vf->data= NULL;
      vf->packedfile= direct_link_packedfile(fd, vf->packedfile);
}

/* ************ READ TEXT ****************** */

static void lib_link_text(FileData *fd, Main *main)
{
      Text *text;

      text= main->text.first;
      while(text) {
            if(text->id.flag & LIB_NEEDLINK) {
                  text->id.flag -= LIB_NEEDLINK;
            }
            text= text->id.next;
      }
}

static void direct_link_text(FileData *fd, Text *text)
{
      TextLine *ln;

      text->name= newdataadr(fd, text->name);

      text->undo_pos= -1;
      text->undo_len= TXT_INIT_UNDO;
      text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");

      text->compiled= NULL;

/*
      if(text->flags & TXT_ISEXT) {
            reopen_text(text);
      } else {
*/

      link_list(fd, &text->lines);

      text->curl= newdataadr(fd, text->curl);
      text->sell= newdataadr(fd, text->sell);

      ln= text->lines.first;
      while(ln) {
            ln->line= newdataadr(fd, ln->line);

            if (ln->len != (int) strlen(ln->line)) {
                  printf("Error loading text, line lengths differ\n");
                  ln->len = strlen(ln->line);
            }

            ln= ln->next;
      }

      text->flags = (text->flags|TXT_ISTMP) & ~TXT_ISEXT;

      text->id.us= 1;
}

/* ************ READ IMAGE ***************** */

static void lib_link_image(FileData *fd, Main *main)
{
      Image *ima;

      ima= main->image.first;
      while (ima) {
            if(ima->id.flag & LIB_NEEDLINK) {

                  ima->id.flag -= LIB_NEEDLINK;
            }
            ima= ima->id.next;
      }
}

static void direct_link_image(FileData *fd, Image *ima)
{
      ima->ibuf= 0;
      ima->anim= 0;
      memset(ima->mipmap, 0, sizeof(ima->mipmap));
      ima->repbind= 0;
      ima->bindcode= 0;

      ima->packedfile = direct_link_packedfile(fd, ima->packedfile);

      ima->ok= 1;
}


/* ************ READ CURVE ***************** */

static void lib_link_curve(FileData *fd, Main *main)
{
      Curve *cu;
      int a;

      cu= main->curve.first;
      while(cu) {
            if(cu->id.flag & LIB_NEEDLINK) {

                  for(a=0; a<cu->totcol; a++) cu->mat[a]= newlibadr_us(fd, cu->id.lib, cu->mat[a]);

                  cu->bevobj= newlibadr(fd, cu->id.lib, cu->bevobj);
                  cu->taperobj= newlibadr(fd, cu->id.lib, cu->taperobj);
                  cu->textoncurve= newlibadr(fd, cu->id.lib, cu->textoncurve);
                  cu->vfont= newlibadr_us(fd, cu->id.lib, cu->vfont);

                  cu->ipo= newlibadr_us(fd, cu->id.lib, cu->ipo);
                  cu->key= newlibadr_us(fd, cu->id.lib, cu->key);

                  cu->id.flag -= LIB_NEEDLINK;
            }
            cu= cu->id.next;
      }
}


static void switch_endian_knots(Nurb *nu)
{
      int len;

      if(nu->knotsu) {
            len= KNOTSU(nu);
            while(len--) {
                  SWITCH_INT(nu->knotsu[len]);
            }
      }
      if(nu->knotsv) {
            len= KNOTSV(nu);
            while(len--) {
                  SWITCH_INT(nu->knotsv[len]);
            }
      }
}

static void direct_link_curve(FileData *fd, Curve *cu)
{
      Nurb *nu;

      cu->mat= newdataadr(fd, cu->mat);
      test_pointer_array(fd, (void **)&cu->mat);
      cu->str= newdataadr(fd, cu->str);

      if(cu->vfont==0) link_list(fd, &(cu->nurb));
      else {
            cu->nurb.first=cu->nurb.last= 0;
      }

      cu->bev.first=cu->bev.last= 0;
      cu->disp.first=cu->disp.last= 0;
      cu->path= 0;

      nu= cu->nurb.first;
      while(nu) {
            nu->bezt= newdataadr(fd, nu->bezt);
            nu->bp= newdataadr(fd, nu->bp);
            nu->knotsu= newdataadr(fd, nu->knotsu);
            nu->knotsv= newdataadr(fd, nu->knotsv);

            if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
                  switch_endian_knots(nu);
            }

            nu= nu->next;
      }
      cu->bb= 0;
}

/* ************ READ TEX ***************** */

static void lib_link_texture(FileData *fd, Main *main)
{
      Tex *tex;

      tex= main->tex.first;
      while(tex) {
            if(tex->id.flag & LIB_NEEDLINK) {

                  tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima);
                  tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo);
                  if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object);

                  tex->id.flag -= LIB_NEEDLINK;
            }
            tex= tex->id.next;
      }
}

static void direct_link_texture(FileData *fd, Tex *tex)
{
      tex->plugin= newdataadr(fd, tex->plugin);
      if(tex->plugin) {
            tex->plugin->handle= 0;
            open_plugin_tex(tex->plugin);
      }
      tex->coba= newdataadr(fd, tex->coba);
      tex->env= newdataadr(fd, tex->env);
      if(tex->env) {
            tex->env->ima= 0;
            memset(tex->env->cube, 0, 6*sizeof(void *));
            tex->env->ok= 0;
      }
}



/* ************ READ MATERIAL ***************** */

static void lib_link_material(FileData *fd, Main *main)
{
      Material *ma;
      MTex *mtex;
      int a;

      ma= main->mat.first;
      while(ma) {
            if(ma->id.flag & LIB_NEEDLINK) {

                  ma->ipo= newlibadr_us(fd, ma->id.lib, ma->ipo);

                  for(a=0; a<MAX_MTEX; a++) {
                        mtex= ma->mtex[a];
                        if(mtex) {
                              mtex->tex= newlibadr_us(fd, ma->id.lib, mtex->tex);
                              mtex->object= newlibadr(fd, ma->id.lib, mtex->object);
                        }
                  }
                  lib_link_scriptlink(fd, &ma->id, &ma->scriptlink);
                  ma->id.flag -= LIB_NEEDLINK;
            }
            ma= ma->id.next;
      }
}

static void direct_link_material(FileData *fd, Material *ma)
{
      int a;

      direct_link_scriptlink(fd, &ma->scriptlink);

      for(a=0; a<MAX_MTEX; a++) {
            ma->mtex[a]= newdataadr(fd, ma->mtex[a]);
      }

      ma->ramp_col= newdataadr(fd, ma->ramp_col);
      ma->ramp_spec= newdataadr(fd, ma->ramp_spec);
      
      ma->ren= NULL;    /* should not be needed, nevertheless... */
}

/* ************ READ MESH ***************** */

static void lib_link_mesh(FileData *fd, Main *main)
{
      Mesh *me;

      me= main->mesh.first;
      while(me) {
            if(me->id.flag & LIB_NEEDLINK) {
                  int i;

                  /* this check added for python created meshes */
                  if(me->mat) {
                        for(i=0; i<me->totcol; i++)
                              me->mat[i]= newlibadr_us(fd, me->id.lib, me->mat[i]);
                  }
                  else me->totcol= 0;

                  me->ipo= newlibadr_us(fd, me->id.lib, me->ipo);
                  me->key= newlibadr_us(fd, me->id.lib, me->key);
                  me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh);

                  if(me->tface) {
                        TFace *tfaces= me->tface;

                        for (i=0; i<me->totface; i++) {
                              TFace *tf= &tfaces[i];

                              tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
                              if(tf->tpage) {
                                    Image *ima= tf->tpage;
                                    if(ima->id.us==0)
                                          ima->id.us= 1;
                              }
                        }
                  }
                  me->id.flag -= LIB_NEEDLINK;
            }
            me= me->id.next;
      }
}

static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
{
      int   i, j;

      if (!mdverts)
            return;

      for (i=0; i<count; i++) {
            mdverts[i].dw=newdataadr(fd, mdverts[i].dw);
            if (!mdverts[i].dw)
                  mdverts[i].totweight=0;

            for (j=0; j< mdverts[i].totweight; j++) {
                  mdverts[i].dw[j].data = NULL; // not saved in file, clear pointer
            }
      }
}

static void direct_link_mesh(FileData *fd, Mesh *mesh)
{
      mesh->mat= newdataadr(fd, mesh->mat);
      test_pointer_array(fd, (void **)&mesh->mat);

      mesh->mvert= newdataadr(fd, mesh->mvert);
      mesh->medge= newdataadr(fd, mesh->medge);
      mesh->mface= newdataadr(fd, mesh->mface);
      mesh->tface= newdataadr(fd, mesh->tface);
      mesh->mcol= newdataadr(fd, mesh->mcol);
      mesh->msticky= newdataadr(fd, mesh->msticky);

      mesh->dvert= newdataadr(fd, mesh->dvert);
      direct_link_dverts(fd, mesh->totvert, mesh->dvert);

      mesh->disp.first= mesh->disp.last= NULL;
      mesh->bb= NULL;
      mesh->oc= 0;
      mesh->dface= NULL;
      mesh->orco= NULL;

      if (mesh->tface) {
            TFace *tfaces= mesh->tface;
            int i;

            for (i=0; i<mesh->totface; i++) {
                  TFace *tf= &tfaces[i];

                  if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
                        SWITCH_INT(tf->col[0]);
                        SWITCH_INT(tf->col[1]);
                        SWITCH_INT(tf->col[2]);
                        SWITCH_INT(tf->col[3]);
                  }
            }
      }
}

/* ************ READ OBJECT ***************** */

static void lib_link_object(FileData *fd, Main *main)
{
      Object *ob;
      bSensor *sens;
      bController *cont;
      bActuator *act;
      ObHook *hook;
      void *poin;
      int warn=0, a;

      ob= main->object.first;
      while(ob) {
            if(ob->id.flag & LIB_NEEDLINK) {

                  ob->parent= newlibadr(fd, ob->id.lib, ob->parent);
                  ob->track= newlibadr(fd, ob->id.lib, ob->track);
                  ob->ipo= newlibadr_us(fd, ob->id.lib, ob->ipo);
                  ob->action = newlibadr_us(fd, ob->id.lib, ob->action);

//                ob->activecon = newglobadr(fd, ob->activecon);

                  poin= ob->data;
                  ob->data= newlibadr_us(fd, ob->id.lib, ob->data);

                  if(ob->data==NULL && poin!=NULL) {
                        ob->type= OB_EMPTY;
                        warn= 1;
                        if(ob->id.lib) printf("Can't find obdata of %s lib %s\n", ob->id.name+2, ob->id.lib->name);
                        else printf("Object %s lost data. Lib:%x\n", ob->id.name+2, (unsigned int) ob->id.lib);
                  }
                  for(a=0; a<ob->totcol; a++) ob->mat[a]= newlibadr_us(fd, ob->id.lib, ob->mat[a]);

                  ob->id.flag -= LIB_NEEDLINK;
                  /* if id.us==0 a new base will be created later on */

                  /* WARNING! Also check expand_object(), should reflect the stuff below. */
                  lib_link_pose(fd, &ob->id, ob->pose);
                  lib_link_constraints(fd, &ob->id, &ob->constraints);
                  lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
                  lib_link_constraint_channels(fd, &ob->id, &ob->constraintChannels);


                  sens= ob->sensors.first;
                  while(sens) {
                        if(ob->id.lib==NULL) {  // done in expand_main
                              for(a=0; a<sens->totlinks; a++) {
                                    sens->links[a]= newglobadr(fd, sens->links[a]);
                              }
                        }
                        if(sens->type==SENS_TOUCH) {
                              bTouchSensor *ts= sens->data;
                              ts->ma= newlibadr(fd, ob->id.lib, ts->ma);
                        }
                        else if(sens->type==SENS_MESSAGE) {
                              bMessageSensor *ms= sens->data;
                              ms->fromObject=
                                  newlibadr(fd, ob->id.lib, ms->fromObject);
                        }
                        sens= sens->next;
                  }

                  cont= ob->controllers.first;
                  while(cont) {
                        if(ob->id.lib==NULL) {  // done in expand_main
                              for(a=0; a<cont->totlinks; a++) {
                                    cont->links[a]= newglobadr(fd, cont->links[a]);
                              }
                        }
                        if(cont->type==CONT_PYTHON) {
                              bPythonCont *pc= cont->data;
                              pc->text= newlibadr(fd, ob->id.lib, pc->text);
                        }
                        cont->slinks= NULL;
                        cont->totslinks= 0;

                        cont= cont->next;
                  }

                  act= ob->actuators.first;
                  while(act) {
                        if(act->type==ACT_SOUND) {
                              bSoundActuator *sa= act->data;
                              sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound);
                        }
                        else if(act->type==ACT_CD) {
                              /* bCDActuator *cda= act->data; */
                        }
                        else if(act->type==ACT_GAME) {
                              /* bGameActuator *ga= act->data; */
                        }
                        else if(act->type==ACT_CAMERA) {
                              bCameraActuator *ca= act->data;
                              ca->ob= newlibadr(fd, ob->id.lib, ca->ob);
                        }
                              /* leave this one, it's obsolete but necessary to read for conversion */
                        else if(act->type==ACT_ADD_OBJECT) {
                              bAddObjectActuator *eoa= act->data;
                              if(eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
                        }
                        else if(act->type==ACT_EDIT_OBJECT) {
                              bEditObjectActuator *eoa= act->data;
                              if(eoa==NULL) {
                                    init_actuator(act);
                              }
                              eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
                              eoa->me= newlibadr(fd, ob->id.lib, eoa->me);
                        }
                        else if(act->type==ACT_SCENE) {
                              bSceneActuator *sa= act->data;
                              sa->camera= newlibadr(fd, ob->id.lib, sa->camera);
                              sa->scene= newlibadr(fd, ob->id.lib, sa->scene);
                        }
                        else if(act->type==ACT_ACTION) {
                              bActionActuator *aa= act->data;
                              aa->act= newlibadr(fd, ob->id.lib, aa->act);
                        }
                        else if(act->type==ACT_PROPERTY) {
                              bPropertyActuator *pa= act->data;
                              pa->ob= newlibadr(fd, ob->id.lib, pa->ob);
                        }
                        else if(act->type==ACT_MESSAGE) {
                              bMessageActuator *ma= act->data;
                              ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject);
                        }
                        act= act->next;
                  }

                  lib_link_scriptlink(fd, &ob->id, &ob->scriptlink);
                  
                  for(hook= ob->hooks.first; hook; hook= hook->next) {
                        hook->parent= newlibadr(fd, ob->id.lib, hook->parent);
                  }
            }
            ob= ob->id.next;
      }

      if(warn) error("WARNING IN CONSOLE");
}


static void direct_link_pose(FileData *fd, bPose *pose) {

      bPoseChannel *chan;

      if (!pose)
            return;

      link_list(fd, &pose->chanbase);

      for (chan = pose->chanbase.first; chan; chan=chan->next) {
            direct_link_constraints(fd, &chan->constraints);
      }

}

static void direct_link_object(FileData *fd, Object *ob)
{
      PartEff *paf;
      bProperty *prop;
      bSensor *sens;
      bController *cont;
      bActuator *act;
      ObHook *hook;
      
      ob->disp.first=ob->disp.last= 0;

      ob->pose= newdataadr(fd, ob->pose);
      direct_link_pose(fd, ob->pose);

      link_list(fd, &ob->defbase);
      link_list(fd, &ob->nlastrips);
      link_list(fd, &ob->constraintChannels);

      ob->activecon = newdataadr(fd, ob->activecon);

      direct_link_scriptlink(fd, &ob->scriptlink);

      ob->mat= newdataadr(fd, ob->mat);
      test_pointer_array(fd, (void **)&ob->mat);
      link_list(fd, &ob->effect);
      paf= ob->effect.first;
      while(paf) {
            if(paf->type==EFF_PARTICLE) {
                  paf->keys= 0;
            }
            if(paf->type==EFF_WAVE) {

            }
            paf= paf->next;
      }

      ob->pd= newdataadr(fd, ob->pd);
      ob->soft= NULL;
      
      link_list(fd, &ob->prop);
      prop= ob->prop.first;
      while(prop) {
            prop->poin= newdataadr(fd, prop->poin);
            if(prop->poin==0) prop->poin= &prop->data;
            prop= prop->next;
      }

      link_list(fd, &ob->sensors);
      sens= ob->sensors.first;
      while(sens) {
            sens->data= newdataadr(fd, sens->data);
            sens->links= newdataadr(fd, sens->links);
            test_pointer_array(fd, (void **)&sens->links);
            sens= sens->next;
      }

      direct_link_constraints(fd, &ob->constraints);

      link_glob_list(fd, &ob->controllers);
      cont= ob->controllers.first;
      while(cont) {
            cont->data= newdataadr(fd, cont->data);
            cont->links= newdataadr(fd, cont->links);
            test_pointer_array(fd, (void **)&cont->links);
            cont= cont->next;
      }

      link_glob_list(fd, &ob->actuators);
      act= ob->actuators.first;
      while(act) {
            act->data= newdataadr(fd, act->data);
            act= act->next;
      }

      link_list(fd, &ob->hooks);
      for(hook= ob->hooks.first; hook; hook= hook->next) {
            hook->indexar= newdataadr(fd, hook->indexar);
            if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
                  int a;
                  for(a=0; a<hook->totindex; a++) {
                        SWITCH_INT(hook->indexar[a]);
                  }
            }
      }
      
      ob->bb= NULL;
}

/* ************ READ SCENE ***************** */

static void lib_link_scene(FileData *fd, Main *main)
{
      Scene *sce;
      Base *base, *next;
      Editing *ed;
      Sequence *seq;

      sce= main->scene.first;
      while(sce) {
            if(sce->id.flag & LIB_NEEDLINK) {
                  sce->id.us= 1;
                  sce->camera= newlibadr(fd, sce->id.lib, sce->camera);
                  sce->world= newlibadr_us(fd, sce->id.lib, sce->world);
                  sce->set= newlibadr(fd, sce->id.lib, sce->set);
                  sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima);
                  sce->group= newlibadr_us(fd, sce->id.lib, sce->group);

                  base= sce->base.first;
                  while(base) {
                        next= base->next;

                        /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */
                        base->object= newlibadr_us_type(fd, ID_OB, base->object);
                        
                        /* when save during radiotool, needs cleared */
                        base->flag &= ~OB_RADIO;
                        
                        if(base->object==0) {
                              printf("LIB ERROR: base removed\n");
                              BLI_remlink(&sce->base, base);
                              if(base==sce->basact) sce->basact= 0;
                              MEM_freeN(base);
                        }
                        base= next;
                  }

                  ed= sce->ed;
                  if(ed) {
                        WHILE_SEQ(&ed->seqbase) {
                              if(seq->ipo) seq->ipo= newlibadr_us(fd, sce->id.lib, seq->ipo);
                              if(seq->scene) seq->scene= newlibadr(fd, sce->id.lib, seq->scene);
                              if(seq->sound) {
                                    seq->sound= newlibadr(fd, sce->id.lib, seq->sound);
                                    if (seq->sound) {
                                          seq->sound->id.us++;
                                          seq->sound->flags |= SOUND_FLAGS_SEQUENCE;
                                    }
                              }
                              seq->anim= 0;
                        }
                        END_SEQ
                  }
                  
                  lib_link_scriptlink(fd, &sce->id, &sce->scriptlink);
                  
                  sce->id.flag -= LIB_NEEDLINK;
            }

            sce= sce->id.next;
      }
}

static void link_recurs_seq(FileData *fd, ListBase *lb)
{
      Sequence *seq;

      link_list(fd, lb);
      seq= lb->first;
      while(seq) {
            if(seq->seqbase.first) link_recurs_seq(fd, &seq->seqbase);
            seq= seq->next;
      }
}

static void direct_link_scene(FileData *fd, Scene *sce)
{
      Editing *ed;
      Sequence *seq;
      MetaStack *ms;
      StripElem *se;
      int a;

      link_list(fd, &(sce->base));

      sce->basact= newdataadr(fd, sce->basact);

      sce->radio= newdataadr(fd, sce->radio);

      sce->r.avicodecdata = newdataadr(fd, sce->r.avicodecdata);
      if (sce->r.avicodecdata) {
            sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat);
            sce->r.avicodecdata->lpParms = newdataadr(fd, sce->r.avicodecdata->lpParms);
      }

      sce->r.qtcodecdata = newdataadr(fd, sce->r.qtcodecdata);
      if (sce->r.qtcodecdata) {
            sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms);
      }

      if(sce->ed) {
            ed= sce->ed= newdataadr(fd, sce->ed);

            /* recursive link sequences, lb will be correctly initialized */
            link_recurs_seq(fd, &ed->seqbase);

            WHILE_SEQ(&ed->seqbase) {
                  seq->seq1= newdataadr(fd, seq->seq1);
                  seq->seq2= newdataadr(fd, seq->seq2);
                  seq->seq3= newdataadr(fd, seq->seq3);
                  /* a patch: after introduction of effects with 3 input strips */
                  if(seq->seq3==0) seq->seq3= seq->seq2;

                  seq->curelem= 0;

                  seq->plugin= newdataadr(fd, seq->plugin);
                  if(seq->plugin) open_plugin_seq(seq->plugin, seq->name+2);

                  seq->effectdata= newdataadr(fd, seq->effectdata);

                  seq->strip= newdataadr(fd, seq->strip);
                  if(seq->strip && seq->strip->done==0) {
                        seq->strip->done= 1;

                        /* standard: strips from effects/metas are not written, but are mallocced */

                        if(seq->type==SEQ_IMAGE) {
                              seq->strip->stripdata= newdataadr(fd, seq->strip->stripdata);
                              se= seq->strip->stripdata;
                              if(se) {
                                    for(a=0; a<seq->strip->len; a++, se++) {
                                          se->ok= 1;
                                          se->ibuf= 0;
                                    }
                              }
                        }
                        else if(seq->type==SEQ_MOVIE) {
                              /* only first stripelem is in file */
                              se= newdataadr(fd, seq->strip->stripdata);

                              if(se) {
                                    seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
                                    *seq->strip->stripdata= *se;
                                    MEM_freeN(se);

                                    se= seq->strip->stripdata;

                                    for(a=0; a<seq->strip->len; a++, se++) {
                                          se->ok= 1;
                                          se->ibuf= 0;
                                          se->nr= a + 1;
                                    }
                              }
                        }
                        else if(seq->type==SEQ_SOUND) {
                              /* only first stripelem is in file */
                              se= newdataadr(fd, seq->strip->stripdata);

                              if(se) {
                                    seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
                                    *seq->strip->stripdata= *se;
                                    MEM_freeN(se);

                                    se= seq->strip->stripdata;

                                    for(a=0; a<seq->strip->len; a++, se++) {
                                          se->ok= 2; /* why? */
                                          se->ibuf= 0;
                                          se->nr= a + 1;
                                    }
                              }
                        }
                        else if(seq->len>0)
                              seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");

                  }
            }
            END_SEQ
                  
            /* link metastack, slight abuse of structs here, have to restore pointer to internal part in struct */
            {
                  Sequence temp;
                  char *poin;
                  long offset;
                  int seted=0;
                  
                  offset= ((long)&(temp.seqbase)) - ((long)&temp);

                  /* root pointer */
                  poin= (char *)ed->seqbasep;
                  poin -= offset;
                  poin= newdataadr(fd, poin);
                  if(poin) ed->seqbasep= (ListBase *)(poin+offset);
                  else ed->seqbasep= &ed->seqbase;
                  
                  /* stack */
                  link_list(fd, &(ed->metastack));
                  
                  for(ms= ed->metastack.first; ms; ms= ms->next) {
                        ms->parseq= newdataadr(fd, ms->parseq);
                        
                        poin= (char *)ms->oldbasep;
                        poin -= offset;
                        poin= newdataadr(fd, poin);
                        if(poin) ms->oldbasep= (ListBase *)(poin+offset);
                        else ms->oldbasep= &ed->seqbase;
                  }
            }
      }

      direct_link_scriptlink(fd, &sce->scriptlink);
}

/* ************ READ SCREEN ***************** */

/* note: file read without screens option G_FILE_NO_UI; 
   check lib pointers in call below */
static void lib_link_screen(FileData *fd, Main *main)
{
      bScreen *sc;
      ScrArea *sa;

      sc= main->screen.first;
      while(sc) {
            if(sc->id.flag & LIB_NEEDLINK) {
                  sc->id.us= 1;
                  sc->scene= newlibadr(fd, sc->id.lib, sc->scene);

                  sa= sc->areabase.first;
                  while(sa) {
                        SpaceLink *sl;

                        sa->full= newlibadr(fd, sc->id.lib, sa->full);

                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if(sl->spacetype==SPACE_VIEW3D) {
                                    View3D *v3d= (View3D*) sl;

                                    v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);

                                    if(v3d->bgpic) {
                                          v3d->bgpic->ima= newlibadr_us(fd, sc->id.lib, v3d->bgpic->ima);
                                          v3d->bgpic->tex= newlibadr_us(fd, sc->id.lib, v3d->bgpic->tex);
                                          v3d->bgpic->rect= NULL;
                                    }
                                    if(v3d->localvd) {
                                          v3d->localvd->camera= newlibadr(fd, sc->id.lib, v3d->localvd->camera);
                                    }
                              }
                              else if(sl->spacetype==SPACE_IPO) {
                                    SpaceIpo *sipo= (SpaceIpo *)sl;
                                    sipo->editipo= 0;
                                    
                                    if(sipo->blocktype==ID_SEQ) sipo->from= NULL;   // no libdata
                                    else sipo->from= newlibadr(fd, sc->id.lib, sipo->from);
                                    
                                    sipo->ipokey.first= sipo->ipokey.last= 0;
                                    sipo->ipo= newlibadr(fd, sc->id.lib, sipo->ipo);
                              }
                              else if(sl->spacetype==SPACE_BUTS) {
                                    SpaceButs *sbuts= (SpaceButs *)sl;
                                    sbuts->rect= NULL;
                                    sbuts->lockpoin= NULL;
                                    if(main->versionfile<132) set_rects_butspace(sbuts);
                              }
                              else if(sl->spacetype==SPACE_FILE) {
                                    SpaceFile *sfile= (SpaceFile *)sl;

                                    sfile->filelist= 0;
                                    sfile->libfiledata= 0;
                                    sfile->returnfunc= 0;
                              }
                              else if(sl->spacetype==SPACE_IMASEL) {
                                    check_imasel_copy((SpaceImaSel *)sl);
                              }
                              else if(sl->spacetype==SPACE_ACTION) {
                                    SpaceAction *saction= (SpaceAction *)sl;
                                    saction->action = newlibadr(fd, sc->id.lib, saction->action);
                              }
                              else if(sl->spacetype==SPACE_IMAGE) {
                                    SpaceImage *sima= (SpaceImage *)sl;

                                    sima->image= newlibadr_us(fd, sc->id.lib, sima->image);
                              }
                              else if(sl->spacetype==SPACE_NLA){
                                    /* SpaceNla *snla= (SpaceNla *)sl;  */
                              }
                              else if(sl->spacetype==SPACE_TEXT) {
                                    SpaceText *st= (SpaceText *)sl;

                                    st->text= newlibadr(fd, sc->id.lib, st->text);

                              }
                              else if(sl->spacetype==SPACE_SCRIPT) {
                                    SpaceScript *sc= (SpaceScript *)sl;

                                    sc->script = NULL;
                              }
                              else if(sl->spacetype==SPACE_OOPS) {
                                    SpaceOops *so= (SpaceOops *)sl;
                                    Oops *oops;
                                    TreeStoreElem *tselem;
                                    int a;

                                    oops= so->oops.first;
                                    while(oops) {
                                          oops->id= newlibadr(fd, NULL, oops->id);
                                          oops= oops->next;
                                    }
                                    so->lockpoin= NULL;
                                    so->tree.first= so->tree.last= NULL;
                                    
                                    if(so->treestore) {
                                          tselem= so->treestore->data;
                                          for(a=0; a<so->treestore->usedelem; a++, tselem++) {
                                                tselem->id= newlibadr(fd, NULL, tselem->id);
                                          }
                                    }
                                    
                              }
                              else if(sl->spacetype==SPACE_SOUND) {
                                    SpaceSound *ssound= (SpaceSound *)sl;

                                    ssound->sound= newlibadr_us(fd, sc->id.lib, ssound->sound);
                              }
                        }
                        sa= sa->next;
                  }
                  sc->id.flag -= LIB_NEEDLINK;
            }
            sc= sc->id.next;
      }
}

static void *restore_pointer_by_name(Main *mainp, ID *id, int user)
{
      ListBase *lb;
      ID *idn=NULL;
            
      if(id) {
            lb= wich_libbase(mainp, GS(id->name));
            
            if(lb) {    // there's still risk of checking corrupt mem (freed Ids in oops)
                  idn= lb->first;
                  while(idn) {
                        if( strcmp(idn->name, id->name)==0) {
                              if(user && idn->us==0) idn->us++;
                              break;
                        }
                        idn= idn->next;
                  }
            }
      }
      return idn;
}

/* called from kernel/blender.c */
void lib_link_screen_restore(Main *newmain, char mode, Scene *curscene)
{
      bScreen *sc;
      ScrArea *sa;

      sc= newmain->screen.first;
      while(sc) {

            if(mode=='u') sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, 1);
            if(sc->scene==NULL || mode=='n') sc->scene= curscene;

            sa= sc->areabase.first;
            while(sa) {
                  SpaceLink *sl;

                  for (sl= sa->spacedata.first; sl; sl= sl->next) {
                        if(sl->spacetype==SPACE_VIEW3D) {
                              View3D *v3d= (View3D*) sl;
                              
                              if(mode=='u') v3d->camera= restore_pointer_by_name(newmain, (ID *)v3d->camera, 1);
                              if(v3d->camera==NULL || mode=='n') v3d->camera= sc->scene->camera;
                              
                              if(v3d->bgpic) {
                                    v3d->bgpic->ima= restore_pointer_by_name(newmain, (ID *)v3d->bgpic->ima, 1);
                                    v3d->bgpic->tex= restore_pointer_by_name(newmain, (ID *)v3d->bgpic->tex, 1);
                                    if(v3d->bgpic->rect) freeN(v3d->bgpic->rect);
                                    v3d->bgpic->rect= NULL;
                              }
                              if(v3d->localvd) {
                                    Base *base;
                                    if(mode=='u') v3d->localvd->camera= restore_pointer_by_name(newmain, (ID *)v3d->localvd->camera, 1);
                                    if(v3d->localvd->camera==NULL || mode=='n') v3d->localvd->camera= sc->scene->camera;
                                    
                                    /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
                                    for(base= sc->scene->base.first; base; base= base->next) {
                                          if(base->lay & v3d->lay) break;
                                    }
                                    if(base==NULL) {
                                          v3d->lay= v3d->localvd->lay;
                                          v3d->layact= v3d->localvd->layact;
                                          MEM_freeN(v3d->localvd);
                                          v3d->localvd= NULL;
                                          v3d->localview= 0;
                                    }
                              }
                              else if(v3d->scenelock) v3d->lay= sc->scene->lay;
                              
                        }
                        else if(sl->spacetype==SPACE_IPO) {
                              SpaceIpo *sipo= (SpaceIpo *)sl;
                              
                              if(sipo->blocktype==ID_SEQ) sipo->from= NULL;   // no libdata
                              else sipo->from= restore_pointer_by_name(newmain, (ID *)sipo->from, 0);
                              
                              // not free sipo->ipokey, creates dependency with src/
                              sipo->ipo= restore_pointer_by_name(newmain, (ID *)sipo->ipo, 0);
                              if(sipo->editipo) MEM_freeN(sipo->editipo);
                              sipo->editipo= NULL;
                        }
                        else if(sl->spacetype==SPACE_BUTS) {
                              SpaceButs *sbuts= (SpaceButs *)sl;
                              sbuts->lockpoin= NULL;
                              sbuts->cury= 0;   // we leave rect, for nicer redraws
                        }
                        else if(sl->spacetype==SPACE_FILE) {
                              SpaceFile *sfile= (SpaceFile *)sl;
                              if(sfile->libfiledata)  
                                    BLO_blendhandle_close(sfile->libfiledata);
                              sfile->libfiledata= 0;
                        }
                        else if(sl->spacetype==SPACE_IMASEL) {
                              ;
                        }
                        else if(sl->spacetype==SPACE_ACTION) {
                              SpaceAction *saction= (SpaceAction *)sl;
                              saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, 1);
                        }
                        else if(sl->spacetype==SPACE_IMAGE) {
                              SpaceImage *sima= (SpaceImage *)sl;

                              sima->image= restore_pointer_by_name(newmain, (ID *)sima->image, 1);
                        }
                        else if(sl->spacetype==SPACE_NLA){
                              /* SpaceNla *snla= (SpaceNla *)sl;  */
                        }
                        else if(sl->spacetype==SPACE_TEXT) {
                              SpaceText *st= (SpaceText *)sl;

                              st->text= restore_pointer_by_name(newmain, (ID *)st->text, 1);
                              if(st->text==NULL) st->text= newmain->text.first;
                        }
                        else if(sl->spacetype==SPACE_SCRIPT) {
                              SpaceScript *sc= (SpaceScript *)sl;

                              sc->script = NULL;
                        }
                        else if(sl->spacetype==SPACE_OOPS) {
                              SpaceOops *so= (SpaceOops *)sl;
                              Oops *oops;
                              
                              int a;
                              oops= so->oops.first;
                              while(oops) {
                                    oops->id= restore_pointer_by_name(newmain, (ID *)oops->id, 0);
                                    oops= oops->next;
                              }
                              so->lockpoin= NULL;
                              
                              if(so->treestore) {
                                    TreeStore *ts= so->treestore;
                                    TreeStoreElem *tselem=ts->data;
                                    for(a=0; a<ts->usedelem; a++, tselem++) {
                                          tselem->id= restore_pointer_by_name(newmain, tselem->id, 0);
                                    }
                              }
                        }
                        else if(sl->spacetype==SPACE_SOUND) {
                              SpaceSound *ssound= (SpaceSound *)sl;

                              ssound->sound= restore_pointer_by_name(newmain, (ID *)ssound->sound, 1);
                        }
                  }
                  sa= sa->next;
            }

            sc= sc->id.next;
      }

}

static void direct_link_screen(FileData *fd, bScreen *sc)
{
      ScrArea *sa;
      ScrVert *sv;
      ScrEdge *se;
      Oops *oops;

      link_list(fd, &(sc->vertbase));
      link_list(fd, &(sc->edgebase));
      link_list(fd, &(sc->areabase));
      sc->winakt= 0;

      /* edges */
      se= sc->edgebase.first;
      while(se) {
            se->v1= newdataadr(fd, se->v1);
            se->v2= newdataadr(fd, se->v2);
            if( (long)se->v1 > (long)se->v2) {
                  sv= se->v1;
                  se->v1= se->v2;
                  se->v2= sv;
            }

            if(se->v1==NULL) {
                  printf("error reading screen... file corrupt\n");
                  se->v1= se->v2;
            }
            se= se->next;
      }

      /* areas */
      sa= sc->areabase.first;
      while(sa) {
            Panel *pa;
            SpaceLink *sl;

            link_list(fd, &(sa->spacedata));
            link_list(fd, &(sa->panels));

            for(pa= sa->panels.first; pa; pa=pa->next) {
                  pa->paneltab= newdataadr(fd, pa->paneltab);
                  pa->active= 0;
                  pa->sortcounter= 0;
            }

            for (sl= sa->spacedata.first; sl; sl= sl->next) {
                  if (sl->spacetype==SPACE_VIEW3D) {
                        View3D *v3d= (View3D*) sl;
                        v3d->bgpic= newdataadr(fd, v3d->bgpic);
                        v3d->localvd= newdataadr(fd, v3d->localvd);
                  }
                  else if (sl->spacetype==SPACE_OOPS) {
                        SpaceOops *soops= (SpaceOops*) sl;
                        
                        link_list(fd, &(soops->oops));
                        oops= soops->oops.first;
                        while(oops) {
                              oops->link.first= oops->link.last= 0;
                              oops= oops->next;
                        }
                        
                        soops->treestore= newdataadr(fd, soops->treestore);
                        if(soops->treestore) {
                              soops->treestore->data= newdataadr(fd, soops->treestore->data);
                              /* we only saved what was used */
                              soops->treestore->totelem= soops->treestore->usedelem;
                              soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
                        }
                  }
            }

            sa->v1= newdataadr(fd, sa->v1);
            sa->v2= newdataadr(fd, sa->v2);
            sa->v3= newdataadr(fd, sa->v3);
            sa->v4= newdataadr(fd, sa->v4);

            sa->win= sa->headwin= 0;

            sa->uiblocks.first= sa->uiblocks.last= NULL;

            sa= sa->next;
      }
}

/* ********** READ LIBRARY *************** */


static void direct_link_library(FileData *fd, Library *lib)
{
      Main *newmain;

      /* new main */
      newmain= MEM_callocN(sizeof(Main), "directlink");
      BLI_addtail(&fd->mainlist, newmain);
      newmain->curlib= lib;
}

static void lib_link_library(FileData *fd, Main *main)
{
      Library *lib;

      lib= main->library.first;
      while(lib) {
            lib->id.us= 1;
            lib= lib->id.next;
      }
}

/* ************** READ SOUND ******************* */

static void direct_link_sound(FileData *fd, bSound *sound)
{
      sound->sample = NULL;
      sound->snd_sound = NULL;

      sound->packedfile = direct_link_packedfile(fd, sound->packedfile);
      sound->newpackedfile = direct_link_packedfile(fd, sound->newpackedfile);
}

static void lib_link_sound(FileData *fd, Main *main)
{
      bSound *sound;

      sound= main->sound.first;
      while(sound) {
            if(sound->id.flag & LIB_NEEDLINK) {
                  sound->id.flag -= LIB_NEEDLINK;
                  sound->ipo= newlibadr_us(fd, sound->id.lib, sound->ipo);
                  sound->stream = 0;
            }
            sound= sound->id.next;
      }
}
/* ***************** READ GROUP *************** */

static void direct_link_group(FileData *fd, Group *group)
{
      GroupObject *go;
      ObjectKey *ok;

      link_list(fd, &group->gobject);
      link_list(fd, &group->gkey);
      group->active= newdataadr(fd, group->active);

      go= group->gobject.first;
      while(go) {
            link_list(fd, &go->okey);
            ok= go->okey.first;
            while(ok) {
                  ok->gkey= newdataadr(fd, ok->gkey);
                  ok= ok->next;
            }
            go= go->next;
      }
}

static void lib_link_group(FileData *fd, Main *main)
{
      Group *group= main->group.first;
      GroupObject *go;
      ObjectKey *ok;

      while(group) {
            if(group->id.flag & LIB_NEEDLINK) {
                  group->id.flag -= LIB_NEEDLINK;

                  go= group->gobject.first;
                  while(go) {
                        go->ob= newlibadr(fd, group->id.lib, go->ob);
                        ok= go->okey.first;
                        while(ok) {
                              ok->parent= newlibadr(fd, group->id.lib, ok->parent);
                              ok->track= newlibadr(fd, group->id.lib, ok->track);
                              ok->ipo= newlibadr_us(fd, group->id.lib, ok->ipo);
                              ok= ok->next;
                        }
                        go= go->next;
                  }
            }
            group= group->id.next;
      }
}

/* ************** GENERAL & MAIN ******************** */

static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **id_r)
{
      /* this routine reads a libblock and its direct data. Use link functions
       * to connect it all
       */

      ID *id;
      ListBase *lb;
      char *str = NULL;

      if(bhead->code==ID_ID) {
            ID *linkedid= (ID *)(bhead + 1); /*  BHEAD+DATA dependancy */

            lb= wich_libbase(main, GS(linkedid->name));
      }
      else {
            lb= wich_libbase(main, bhead->code);
      }

      /* read libblock */
      id = read_struct(fd, bhead, "lib block");
      if (id_r)
            *id_r= id;
      if (!id)
            return blo_nextbhead(fd, bhead);

      oldnewmap_insert(fd->libmap, bhead->old, id, 1);
      BLI_addtail(lb, id);

      /* clear first 8 bits */
      id->flag= (id->flag & 0xFF00) | flag | LIB_NEEDLINK;
      id->lib= main->curlib;
      if(id->flag & LIB_FAKEUSER) id->us= 1;
      else id->us= 0;

      /* this case cannot be direct_linked: it's just the ID part */
      if(bhead->code==ID_ID) {
            return blo_nextbhead(fd, bhead);
      }

      bhead = blo_nextbhead(fd, bhead);

      switch( GS(id->name) ) {
      case ID_OB: str= "ID_OB"; break;
      case ID_SCE: str= "ID_SCE"; break;
      case ID_LI: str= "ID_LI"; break;
      case ID_ME: str= "ID_ME"; break;
      case ID_CU: str= "ID_CU"; break;
      case ID_MB: str= "ID_MB"; break;
      case ID_MA: str= "ID_MA"; break;
      case ID_TE: str= "ID_TE"; break;
      case ID_IM: str= "ID_IM"; break;
      case ID_IK: str= "ID_IK"; break;
      case ID_WV: str= "ID_WV"; break;
      case ID_LT: str= "ID_LT"; break;
      case ID_SE: str= "ID_SE"; break;
      case ID_LF: str= "ID_LF"; break;
      case ID_LA: str= "ID_LA"; break;
      case ID_CA: str= "ID_CA"; break;
      case ID_IP: str= "ID_IP"; break;
      case ID_KE: str= "ID_KE"; break;
      case ID_WO: str= "ID_WO"; break;
      case ID_SCR: str= "ID_SCR"; break;
      case ID_VF: str= "ID_VF"; break;
      case ID_TXT : str= "ID_TXT"; break;
      case ID_SO: str= "ID_SO"; break;
      case ID_SAMPLE: str= "ID_SAMPLE"; break;
      case ID_GR: str= "ID_GR"; break;
      case ID_ID: str= "ID_ID"; break;
      case ID_SEQ: str= "ID_SEQ"; break;
      case ID_AR: str= "ID_AR"; break;
      case ID_AC: str= "ID_AC"; break;
      case ID_SCRIPT: str= "ID_SCRIPT"; break;
      }
            /* read all data */
      while(bhead && bhead->code==DATA) {
            void *data= read_struct(fd, bhead, str);

            if (data) {
                  oldnewmap_insert(fd->datamap, bhead->old, data, 0);
            }

            bhead = blo_nextbhead(fd, bhead);
      }

      /* init pointers direct data */
      switch( GS(id->name) ) {
            case ID_SCR:
                  direct_link_screen(fd, (bScreen *)id);
                  break;
            case ID_SCE:
                  direct_link_scene(fd, (Scene *)id);
                  break;
            case ID_OB:
                  direct_link_object(fd, (Object *)id);
                  break;
            case ID_ME:
                  direct_link_mesh(fd, (Mesh *)id);
                  break;
            case ID_CU:
                  direct_link_curve(fd, (Curve *)id);
                  break;
            case ID_MB:
                  direct_link_mball(fd, (MetaBall *)id);
                  break;
            case ID_MA:
                  direct_link_material(fd, (Material *)id);
                  break;
            case ID_TE:
                  direct_link_texture(fd, (Tex *)id);
                  break;
            case ID_IM:
                  direct_link_image(fd, (Image *)id);
                  break;
            case ID_LA:
                  direct_link_lamp(fd, (Lamp *)id);
                  break;
            case ID_VF:
                  direct_link_vfont(fd, (VFont *)id);
                  break;
            case ID_TXT:
                  direct_link_text(fd, (Text *)id);
                  break;
            case ID_IP:
                  direct_link_ipo(fd, (Ipo *)id);
                  break;
            case ID_KE:
                  direct_link_key(fd, (Key *)id);
                  break;
            case ID_LT:
                  direct_link_latt(fd, (Lattice *)id);
                  break;
            case ID_IK:
                  direct_link_ika(fd, (Ika *)id);
                  break;
            case ID_WO:
                  direct_link_world(fd, (World *)id);
                  break;
            case ID_LI:
                  direct_link_library(fd, (Library *)id);
                  break;
            case ID_CA:
                  direct_link_camera(fd, (Camera *)id);
                  break;
            case ID_SO:
                  direct_link_sound(fd, (bSound *)id);
                  break;
            case ID_GR:
                  direct_link_group(fd, (Group *)id);
                  break;
            case ID_AR:
                  direct_link_armature(fd, (bArmature*)id);
                  break;
            case ID_AC:
                  direct_link_action(fd, (bAction*)id);
                  break;
      }

      oldnewmap_free_unused(fd->datamap);
      oldnewmap_clear(fd->datamap);

      return (bhead);
}

static void link_global(FileData *fd, BlendFileData *bfd, FileGlobal *fg)
{
      // this is nonsense... make it struct once (ton)
      bfd->winpos= fg->winpos;
      bfd->fileflags= fg->fileflags;
      bfd->displaymode= fg->displaymode;
      bfd->globalf= fg->globalf;
      bfd->curscreen= newlibadr(fd, 0, fg->curscreen);
      bfd->curscene= newlibadr(fd, 0, fg->curscene);
      // this happens in files older than 2.35
      if(bfd->curscene==NULL) {
            if(bfd->curscreen) bfd->curscene= bfd->curscreen->scene;
      }
}

static void vcol_to_fcol(Mesh *me)
{
      MFace *mface;
      unsigned int *mcol, *mcoln, *mcolmain;
      int a;

      if(me->totface==0 || me->mcol==0) return;

      mcoln= mcolmain= MEM_mallocN(4*sizeof(int)*me->totface, "mcoln");
      mcol = (unsigned int *)me->mcol;
      mface= me->mface;
      for(a=me->totface; a>0; a--, mface++) {
            mcoln[0]= mcol[mface->v1];
            mcoln[1]= mcol[mface->v2];
            mcoln[2]= mcol[mface->v3];
            mcoln[3]= mcol[mface->v4];
            mcoln+= 4;
      }

      MEM_freeN(me->mcol);
      me->mcol= (MCol *)mcolmain;
}

static int map_223_keybd_code_to_224_keybd_code(int code)
{
      switch (code) {
      case 312:   return F12KEY;
      case 159:   return PADSLASHKEY;
      case 161:   return PAD0;
      case 154:   return PAD1;
      case 150:   return PAD2;
      case 155:   return PAD3;
      case 151:   return PAD4;
      case 156:   return PAD5;
      case 152:   return PAD6;
      case 157:   return PAD7;
      case 153:   return PAD8;
      case 158:   return PAD9;
      default: return code;
      }
}

static void do_versions(Main *main)
{
      /* watch it: pointers from libdata have not been converted */

      if(main->versionfile == 100) {
            /* tex->extend and tex->imageflag have changed: */
            Tex *tex = main->tex.first;
            while(tex) {
                  if(tex->id.flag & LIB_NEEDLINK) {

                        if(tex->extend==0) {
                              if(tex->xrepeat || tex->yrepeat) tex->extend= TEX_REPEAT;
                              else {
                                    tex->extend= TEX_EXTEND;
                                    tex->xrepeat= tex->yrepeat= 1;
                              }
                        }

                        if(tex->imaflag & TEX_ANIM5) {
                              tex->imaflag |= TEX_MORKPATCH;
                              tex->imaflag |= TEX_ANTIALI;
                        }
                  }
                  tex= tex->id.next;
            }
      }
      if(main->versionfile <= 101) {
            /* frame mapping */
            Scene *sce = main->scene.first;
            while(sce) {
                  sce->r.framapto= 100;
                  sce->r.images= 100;
                  sce->r.framelen= 1.0;
                  sce= sce->id.next;
            }
      }
      if(main->versionfile <= 102) {
            /* init halo's at 1.0 */
            Material *ma = main->mat.first;
            while(ma) {
                  ma->add= 1.0;
                  ma= ma->id.next;
            }
      }
      if(main->versionfile <= 103) {
            /* new variable in object: colbits */
            Object *ob = main->object.first;
            int a;
            while(ob) {
                  ob->colbits= 0;
                  if(ob->totcol) {
                        for(a=0; a<ob->totcol; a++) {
                              if(ob->mat[a]) ob->colbits |= (1<<a);
                        }
                  }
                  ob= ob->id.next;
            }
      }
      if(main->versionfile <= 104) {
            /* timeoffs moved */
            Object *ob = main->object.first;
            while(ob) {
                  if(ob->transflag & 1) {
                        ob->transflag -= 1;
                        ob->ipoflag |= OB_OFFS_OB;
                  }
                  ob= ob->id.next;
            }
      }
      if(main->versionfile <= 105) {
            Object *ob = main->object.first;
            while(ob) {
                  ob->dupon= 1; ob->dupoff= 0;
                  ob->dupsta= 1; ob->dupend= 100;
                  ob= ob->id.next;
            }
      }
      if(main->versionfile <= 106) {
            /* mcol changed */
            Mesh *me = main->mesh.first;
            while(me) {
                  if(me->mcol) vcol_to_fcol(me);
                  me= me->id.next;
            }

      }
      if(main->versionfile <= 107) {
            Object *ob;
            Scene *sce = main->scene.first;
            while(sce) {
                  sce->r.mode |= R_GAMMA;
                  sce= sce->id.next;
            }
            ob= main->object.first;
            while(ob) {
                  ob->ipoflag |= OB_OFFS_PARENT;
                  if(ob->dt==0) ob->dt= 3;
                  ob= ob->id.next;
            }

      }
      if(main->versionfile <= 109) {
            /* new variable: gridlines */
            bScreen *sc = main->screen.first;
            while(sc) {
                  ScrArea *sa= sc->areabase.first;
                  while(sa) {
                        SpaceLink *sl= sa->spacedata.first;
                        while (sl) {
                              if (sl->spacetype==SPACE_VIEW3D) {
                                    View3D *v3d= (View3D*) sl;

                                    if (v3d->gridlines==0) v3d->gridlines= 20;
                              }
                              sl= sl->next;
                        }
                        sa= sa->next;
                  }
                  sc= sc->id.next;
            }
      }
      if(main->versionfile <= 112) {
            Mesh *me = main->mesh.first;
            while(me) {
                  me->cubemapsize= 1.0;
                  me= me->id.next;
            }
      }
      if(main->versionfile <= 113) {
            Material *ma = main->mat.first;
            while(ma) {
                  if(ma->flaresize==0.0) ma->flaresize= 1.0;
                  ma->subsize= 1.0;
                  ma->flareboost= 1.0;
                  ma= ma->id.next;
            }
      }
      if(main->versionfile <= 114) {
            Mesh *me= main->mesh.first;
            MFace *mface;
            int a_int;

            /* edge drawflags changed */
            while(me) {
                  a_int= me->totface;
                  mface= me->mface;
                  while(a_int--) {
                        if(mface->edcode & 16) {
                              mface->edcode -= 16;
                              mface->edcode |= ME_V3V1;
                        }
                        mface++;
                  }
                  me= me->id.next;
            }
      }


      if(main->versionfile <= 134) {
            Tex *tex = main->tex.first;
            while (tex) {
                  if ((tex->rfac == 0.0) &&
                      (tex->gfac == 0.0) &&
                      (tex->bfac == 0.0)) {
                        tex->rfac = 1.0;
                        tex->gfac = 1.0;
                        tex->bfac = 1.0;
                        tex->filtersize = 1.0;
                  }
                  tex = tex->id.next;
            }
      }
      if(main->versionfile <= 140) {
            /* r-g-b-fac in texure */
            Tex *tex = main->tex.first;
            while (tex) {
                  if ((tex->rfac == 0.0) &&
                      (tex->gfac == 0.0) &&
                      (tex->bfac == 0.0)) {
                        tex->rfac = 1.0;
                        tex->gfac = 1.0;
                        tex->bfac = 1.0;
                        tex->filtersize = 1.0;
                  }
                  tex = tex->id.next;
            }
      }
      if(main->versionfile <= 153) {
            Scene *sce = main->scene.first;
            while(sce) {
                  if(sce->r.blurfac==0.0) sce->r.blurfac= 1.0;
                  sce= sce->id.next;
            }
      }
      if(main->versionfile <= 163) {
            Scene *sce = main->scene.first;
            while(sce) {
                  if(sce->r.frs_sec==0) sce->r.frs_sec= 25;
                  sce= sce->id.next;
            }
      }
      if(main->versionfile <= 164) {
            Mesh *me= main->mesh.first;
            while(me) {
                  me->smoothresh= 30;
                  me= me->id.next;
            }
      }
      if(main->versionfile <= 165) {
            Mesh *me= main->mesh.first;
            TFace *tface;
            Ika *ika= main->ika.first;
            Deform *def;
            int nr;
            char *cp;

            while(ika) {
                  ika->xyconstraint= .5;

                  def= ika->def;
                  nr= ika->totdef;
                  while(nr--) {
                        if(def->fac==0.0) def->fac= 1.0;
                        def++;
                  }
                  ika= ika->id.next;
            }

            while(me) {
                  if(me->tface) {
                        nr= me->totface;
                        tface= me->tface;
                        while(nr--) {
                              cp= (char *)&tface->col[0];
                              if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
                              if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
                              if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
                              cp= (char *)&tface->col[1];
                              if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
                              if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
                              if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
                              cp= (char *)&tface->col[2];
                              if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
                              if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
                              if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
                              cp= (char *)&tface->col[3];
                              if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
                              if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
                              if(cp[3]>126) cp[3]= 255; else cp[3]*=2;

                              tface++;
                        }
                  }
                  me= me->id.next;
            }
      }

      if(main->versionfile <= 169) {
            Mesh *me= main->mesh.first;
            while(me) {
                  if(me->subdiv==0) me->subdiv= 3;
                  me= me->id.next;
            }
      }

      if(main->versionfile <= 169) {
            bScreen *sc= main->screen.first;
            while(sc) {
                  ScrArea *sa= sc->areabase.first;
                  while(sa) {
                        SpaceLink *sl= sa->spacedata.first;
                        while(sl) {
                              if(sl->spacetype==SPACE_IPO) {
                                    SpaceIpo *sipo= (SpaceIpo*) sl;
                                    sipo->v2d.max[0]= 15000.0;
                              }
                              sl= sl->next;
                        }
                        sa= sa->next;
                  }
                  sc= sc->id.next;
            }
      }

      if(main->versionfile <= 170) {
            Object *ob = main->object.first;
            PartEff *paf;
            while (ob) {
                  paf = give_parteff(ob);
                  if (paf) {
                        if (paf->staticstep == 0) {
                              paf->staticstep= 5;
                        }
                  }
                  ob = ob->id.next;
            }
      }

      if(main->versionfile <= 171) {
            bScreen *sc= main->screen.first;
            while(sc) {
                  ScrArea *sa= sc->areabase.first;
                  while(sa) {
                        SpaceLink *sl= sa->spacedata.first;
                        while(sl) {
                              if(sl->spacetype==SPACE_TEXT) {
                                    SpaceText *st= (SpaceText*) sl;
                                    if(st->font_id>1) {
                                          st->font_id= 0;
                                          st->lheight= 13;
                                    }
                              }
                              sl= sl->next;
                        }
                        sa= sa->next;
                  }
                  sc= sc->id.next;
            }
      }

      if(main->versionfile <= 173) {
            int a, b;
            Mesh *me= main->mesh.first;
            while(me) {
                  if(me->tface) {
                        TFace *tface= me->tface;
                        for(a=0; a<me->totface; a++, tface++) {
                              for(b=0; b<4; b++) {
                                    tface->uv[b][0]/= 32767.0;
                                    tface->uv[b][1]/= 32767.0;
                              }
                        }
                  }
                  me= me->id.next;
            }
      }

      if(main->versionfile <= 191) {
            bScreen *sc= main->screen.first;
            Object *ob= main->object.first;
            Material *ma = main->mat.first;

            /* let faces have default add factor of 0.0 */
            while(ma) {
              if (!(ma->mode & MA_HALO)) ma->add = 0.0;
              ma = ma->id.next;
            }

            while(ob) {
                  ob->mass= 1.0f;
                  ob->damping= 0.1f;
                  ob->quat[1]= 1.0f;
                  ob= ob->id.next;
            }

            while(sc) {
                  ScrArea *sa= sc->areabase.first;
                  while(sa) {
                        SpaceLink *sl= sa->spacedata.first;
                        while(sl) {
                              if(sl->spacetype==SPACE_BUTS) {
                                    SpaceButs *sbuts= (SpaceButs*) sl;
                                    sbuts->scaflag= BUTS_SENS_LINK|BUTS_SENS_ACT|BUTS_CONT_ACT|BUTS_ACT_ACT|BUTS_ACT_LINK;
                              }
                              sl= sl->next;
                        }
                        sa= sa->next;
                  }
                  sc= sc->id.next;
            }
      }

      if(main->versionfile <= 193) {
            Object *ob= main->object.first;
            while(ob) {
                  ob->inertia= 1.0f;
                  ob->rdamping= 0.1f;
                  ob= ob->id.next;
            }
      }

      if(main->versionfile <= 196) {
            Mesh *me= main->mesh.first;
            int a, b;
            while(me) {
                  if(me->tface) {
                        TFace *tface= me->tface;
                        for(a=0; a<me->totface; a++, tface++) {
                              for(b=0; b<4; b++) {
                                    tface->mode |= TF_DYNAMIC;
                                    tface->mode &= ~TF_INVISIBLE;
                              }
                        }
                  }
                  me= me->id.next;
            }
      }

      if(main->versionfile <= 200) {
            Object *ob= main->object.first;
            while(ob) {
                  ob->scaflag = ob->gameflag & (64+128+256+512+1024+2048);
                      /* 64 is do_fh */
                  ob->gameflag &= ~(128+256+512+1024+2048);
                  ob = ob->id.next;
            }
      }

      if(main->versionfile <= 201) {
            /* add-object + end-object are joined to edit-object actuator */
            Object *ob = main->object.first;
            bProperty *prop;
            bActuator *act;
            bIpoActuator *ia;
            bEditObjectActuator *eoa;
            bAddObjectActuator *aoa;
            while (ob) {
                  act = ob->actuators.first;
                  while (act) {
                        if(act->type==ACT_IPO) {
                              ia= act->data;
                              prop= get_property(ob, ia->name);
                              if(prop) {
                                    ia->type= ACT_IPO_FROM_PROP;
                              }
                        }
                        else if(act->type==ACT_ADD_OBJECT) {
                              aoa= act->data;
                              eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
                              eoa->type= ACT_EDOB_ADD_OBJECT;
                              eoa->ob= aoa->ob;
                              eoa->time= aoa->time;
                              MEM_freeN(aoa);
                              act->data= eoa;
                              act->type= act->otype= ACT_EDIT_OBJECT;
                        }
                        else if(act->type==ACT_END_OBJECT) {
                              eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
                              eoa->type= ACT_EDOB_END_OBJECT;
                              act->data= eoa;
                              act->type= act->otype= ACT_EDIT_OBJECT;
                        }
                        act= act->next;
                  }
                  ob = ob->id.next;
            }
      }

      if(main->versionfile <= 202) {
            /* add-object and end-object are joined to edit-object
             * actuator */
            Object *ob= main->object.first;
            bActuator *act;
            bObjectActuator *oa;
            while(ob) {
                  act= ob->actuators.first;
                  while(act) {
                        if(act->type==ACT_OBJECT) {
                              oa= act->data;
                              oa->flag &= ~(ACT_TORQUE_LOCAL|ACT_DROT_LOCAL);       /* this actuator didn't do local/glob rot before */
                        }
                        act= act->next;
                  }
                  ob= ob->id.next;
            }
      }

      if(main->versionfile <= 204) {
            /* patches for new physics */
            Object *ob= main->object.first;
            bActuator *act;
            bObjectActuator *oa;
            bSound *sound;
            while(ob) {

                  /* please check this for demo20 files like
                   * original Egypt levels etc.  converted
                   * rotation factor of 50 is not workable */
                  act= ob->actuators.first;
                  while(act) {
                        if(act->type==ACT_OBJECT) {
                              oa= act->data;

                              oa->forceloc[0]*= 25.0;
                              oa->forceloc[1]*= 25.0;
                              oa->forceloc[2]*= 25.0;

                              oa->forcerot[0]*= 10.0;
                              oa->forcerot[1]*= 10.0;
                              oa->forcerot[2]*= 10.0;
                        }
                        act= act->next;
                  }
                  ob= ob->id.next;
            }

            sound = main->sound.first;
            while (sound) {
                  if (sound->volume < 0.01) {
                        sound->volume = 1.0;
                  }
                  sound = sound->id.next;
            }
      }

      if(main->versionfile <= 205) {
            /* patches for new physics */
            Object *ob= main->object.first;
            bActuator *act;
            bSensor *sens;
            bEditObjectActuator *oa;
            bRaySensor *rs;
            bCollisionSensor *cs;
            while(ob) {
                /* Set anisotropic friction off for old objects,
                 * values to 1.0.  */
                  ob->gameflag &= ~OB_ANISOTROPIC_FRICTION;
                  ob->anisotropicFriction[0] = 1.0;
                  ob->anisotropicFriction[1] = 1.0;
                  ob->anisotropicFriction[2] = 1.0;

                  act= ob->actuators.first;
                  while(act) {
                        if(act->type==ACT_EDIT_OBJECT) {
                              /* Zero initial velocity for newly
                               * added objects */
                              oa= act->data;
                              oa->linVelocity[0] = 0.0;
                              oa->linVelocity[1] = 0.0;
                              oa->linVelocity[2] = 0.0;
                              oa->localflag = 0;
                        }
                        act= act->next;
                  }

                  sens= ob->sensors.first;
                  while (sens) {
                        /* Extra fields for radar sensors. */
                        if(sens->type == SENS_RADAR) {
                              bRadarSensor *s = sens->data;
                              s->range = 10000.0;
                        }

                        /* Pulsing: defaults for new sensors. */
                        if(sens->type != SENS_ALWAYS) {
                              sens->pulse = 0;
                              sens->freq = 0;
                        } else {
                              sens->pulse = 1;
                        }

                        /* Invert: off. */
                        sens->invert = 0;

                        /* Collision and ray: default = trigger
                         * on property. The material field can
                         * remain empty. */
                        if(sens->type == SENS_COLLISION) {
                              cs = (bCollisionSensor*) sens->data;
                              cs->mode = 0;
                        }
                        if(sens->type == SENS_RAY) {
                              rs = (bRaySensor*) sens->data;
                              rs->mode = 0;
                        }
                        sens = sens->next;
                  }
                  ob= ob->id.next;
            }
            /* have to check the exact multiplier */
      }

      if(main->versionfile <= 210) {
            Scene *sce= main->scene.first;

            while(sce) {
                  if(sce->r.postmul== 0.0) sce->r.postmul= 1.0;
                  if(sce->r.postgamma== 0.0) sce->r.postgamma= 1.0;
                  sce= sce->id.next;
            }
      }

      if(main->versionfile <= 211) {
            /* Render setting: per scene, the applicable gamma value
             * can be set. Default is 1.0, which means no
             * correction.  */
            bActuator *act;
            bObjectActuator *oa;
            Object *ob;
            Scene *sce= main->scene.first;
            while(sce) {
                  sce->r.gamma = 2.0;
                  sce= sce->id.next;
            }

            /* added alpha in obcolor */
            ob= main->object.first;
            while(ob) {
                  ob->col[3]= 1.0;
                  ob= ob->id.next;
            }

            /* added alpha in obcolor */
            ob= main->object.first;
            while(ob) {
                  act= ob->actuators.first;
                  while(act) {
                        if (act->type==ACT_OBJECT) {
                              /* multiply velocity with 50 in old files */
                              oa= act->data;
                              if (fabs(oa->linearvelocity[0]) >= 0.01f)
                                    oa->linearvelocity[0] *= 50.0;
                              if (fabs(oa->linearvelocity[1]) >= 0.01f)
                                    oa->linearvelocity[1] *= 50.0;
                              if (fabs(oa->linearvelocity[2]) >= 0.01f)
                                    oa->linearvelocity[2] *= 50.0;
                              if (fabs(oa->angularvelocity[0])>=0.01f)
                                    oa->angularvelocity[0] *= 50.0;
                              if (fabs(oa->angularvelocity[1])>=0.01f)
                                    oa->angularvelocity[1] *= 50.0;
                              if (fabs(oa->angularvelocity[2])>=0.01f)
                                    oa->angularvelocity[2] *= 50.0;
                        }
                        act= act->next;
                  }
                  ob= ob->id.next;
            }
      }

      if(main->versionfile <= 212) {

            bSound* sound;
            bProperty *prop;
            Object *ob;
            Mesh *me;

            sound = main->sound.first;
            while (sound)
            {
                  sound->max_gain = 1.0;
                  sound->min_gain = 0.0;
                  sound->distance = 1.0;

                  if (sound->attenuation > 0.0)
                        sound->flags |= SOUND_FLAGS_3D;
                  else
                        sound->flags &= ~SOUND_FLAGS_3D;

                  sound = sound->id.next;
            }

            ob = main->object.first;

            while (ob) {
                  prop= ob->prop.first;
                  while(prop) {
                        if (prop->type == PROP_TIME) {
                              // convert old PROP_TIME values from int to float
                              *((float *)&prop->data) = (float) prop->data;
                        }

                        prop= prop->next;
                  }
                  ob = ob->id.next;
            }

                  /* me->subdiv changed to reflect the actual reparametization
                   * better, and smeshes were removed - if it was a smesh make
                   * it a subsurf, and reset the subdiv level because subsurf
                   * takes a lot more work to calculate.
                   */
            for (me= main->mesh.first; me; me= me->id.next) {
                  if (me->flag&ME_SMESH) {
                        me->flag&= ~ME_SMESH;
                        me->flag|= ME_SUBSURF;

                        me->subdiv= 1;
                  } else {
                        if (me->subdiv<2)
                              me->subdiv= 1;
                        else
                              me->subdiv--;
                  }
            }
      }

      if(main->versionfile <= 220) {
            Object *ob;
            Mesh *me;
            bArmature *arm;

            ob = main->object.first;

            /* adapt form factor in order to get the 'old' physics
             * behaviour back...*/

            while (ob) {
                  /* in future, distinguish between different
                   * object bounding shapes */
                  ob->formfactor = 0.4f;
                  /* patch form factor , note that inertia equiv radius
                   * of a rotation symmetrical obj */
                  if (ob->inertia != 1.0) {
                        ob->formfactor /= ob->inertia * ob->inertia;
                  }
                  ob = ob->id.next;
            }

                  /* Precalculate rest position matrices for old armatures. -rvo
                   */
            for (arm= main->armature.first; arm; arm= arm->id.next) {
                  precalc_bonelist_irestmats (&arm->bonebase);
            }

                  /* Began using alpha component of vertex colors, but
                   * old file vertex colors are undefined, reset them
                   * to be fully opaque. -zr
                   */
            for (me= main->mesh.first; me; me= me->id.next) {
                  if (me->mcol) {
                        int i;

                        for (i=0; i<me->totface*4; i++) {
                              MCol *mcol= &me->mcol[i];
                              mcol->a= 255;
                        }
                  }
                  if (me->tface) {
                        int i, j;

                        for (i=0; i<me->totface; i++) {
                              TFace *tf= &((TFace*) me->tface)[i];

                              for (j=0; j<4; j++) {
                                    char *col= (char*) &tf->col[j];

                                    col[0]= 255;
                              }
                        }
                  }
            }
      }
      if(main->versionfile <= 221) {
            Scene *sce= main->scene.first;

            // new variables for std-alone player and runtime
            while(sce) {

                  sce->r.xplay= 640;
                  sce->r.yplay= 480;
                  sce->r.freqplay= 60;

                  sce= sce->id.next;
            }

      }
      if(main->versionfile <= 222) {
            Scene *sce= main->scene.first;

            // new variables for std-alone player and runtime
            while(sce) {

                  sce->r.depth= 32;

                  sce= sce->id.next;
            }
      }


      if(main->versionfile <= 223) {
            VFont *vf;
            Image *ima;
            Object *ob;

            for (vf= main->vfont.first; vf; vf= vf->id.next) {
                  if (BLI_streq(vf->name+strlen(vf->name)-6, ".Bfont")) {
                        strcpy(vf->name, "<builtin>");
                  }
            }

            /* Old textures animate at 25 FPS */
            for (ima = main->image.first; ima; ima=ima->id.next){
                  ima->animspeed = 25;
            }

                  /* Zr remapped some keyboard codes to be linear (stupid zr) */
            for (ob= main->object.first; ob; ob= ob->id.next) {
                  bSensor *sens;

                  for (sens= ob->sensors.first; sens; sens= sens->next) {
                        if (sens->type==SENS_KEYBOARD) {
                              bKeyboardSensor *ks= sens->data;

                              ks->key= map_223_keybd_code_to_224_keybd_code(ks->key);
                              ks->qual= map_223_keybd_code_to_224_keybd_code(ks->qual);
                              ks->qual2= map_223_keybd_code_to_224_keybd_code(ks->qual2);
                        }
                  }
            }
      }
      if(main->versionfile <= 224) {
            bSound* sound;
            Scene *sce;
            Mesh *me;
            bScreen *sc;
            Object *ob;

            for (sound=main->sound.first; sound; sound=sound->id.next)
            {
                  if (sound->packedfile) {
                        if (sound->newpackedfile == NULL) {
                              sound->newpackedfile = sound->packedfile;
                        }
                        sound->packedfile = NULL;
                  }
            }

            /* Clear some (now) unused pose flags */
            for (ob=main->object.first; ob; ob=ob->id.next){
                  if (ob->pose){
                        bPoseChannel *pchan;
                        for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next){
                              pchan->flag &= ~(POSE_UNUSED1|POSE_UNUSED2|POSE_UNUSED3|POSE_UNUSED4|POSE_UNUSED5);
                        }
                  }
            }

            /* Make sure that old subsurf meshes don't have zero subdivision level for rendering */
            for (me=main->mesh.first; me; me=me->id.next){
                  if ((me->flag & ME_SUBSURF) && (me->subdivr==0))
                        me->subdivr=me->subdiv;
            }

            for (sce= main->scene.first; sce; sce= sce->id.next) {
                  sce->r.stereomode = 1;  // no stereo
            }

                  /* some oldfile patch, moved from set_func_space */
            for (sc= main->screen.first; sc; sc= sc->id.next) {
                  ScrArea *sa;

                  for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;

                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if (sl->spacetype==SPACE_IPO) {
                                    SpaceSeq *sseq= (SpaceSeq*) sl;
                                    sseq->v2d.keeptot= 0;
                              }
                        }
                  }
            }

      }
      if(main->versionfile <= 225) {
            World *wo;
            /* Use Sumo for old games */
            for (wo = main->world.first; wo; wo= wo->id.next) {
                  wo->physicsEngine = 2;
            }

      }
      if(main->versionfile <= 227) {
            Scene *sce;
            Material *ma;
            bScreen *sc;
            Object *ob;


            /*  As of now, this insures that the transition from the old Track system
                to the new full constraint Track is painless for everyone. - theeth
            */
            ob = main->object.first;

            while (ob) {
                  ListBase *list;
                  list = &ob->constraints;

                  /* check for already existing TrackTo constraint
                     set their track and up flag correctly */

                  if (list){
                        bConstraint *curcon;
                        for (curcon = list->first; curcon; curcon=curcon->next){
                              if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
                                    bTrackToConstraint *data = curcon->data;
                                    data->reserved1 = ob->trackflag;
                                    data->reserved2 = ob->upflag;
                              }
                        }
                  }

                  if (ob->type == OB_ARMATURE) {
                        if (ob->pose){
                              bConstraint *curcon;
                              bPoseChannel *pchan;
                              for (pchan = ob->pose->chanbase.first;
                                     pchan; pchan=pchan->next){
                                    for (curcon = pchan->constraints.first;
                                           curcon; curcon=curcon->next){
                                          if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
                                                bTrackToConstraint *data = curcon->data;
                                                data->reserved1 = ob->trackflag;
                                                data->reserved2 = ob->upflag;
                                          }
                                    }
                              }
                }
                  }

                  /* Change Ob->Track in real TrackTo constraint */

                  if (ob->track){
                        bConstraint *con;
                        bTrackToConstraint *data;

                        list = &ob->constraints;
                        if (list)
                        {
                              con = MEM_callocN(sizeof(bConstraint), "constraint");
                              strcpy (con->name, "AutoTrack");
                              unique_constraint_name(con, list);
                              con->flag |= CONSTRAINT_EXPAND;
                              con->enforce=1.0F;
                              con->type = CONSTRAINT_TYPE_TRACKTO;
                              data = (bTrackToConstraint *)
                                    new_constraint_data(CONSTRAINT_TYPE_TRACKTO);

                              data->tar = ob->track;
                              data->reserved1 = ob->trackflag;
                              data->reserved2 = ob->upflag;
                              con->data= (void*) data;
                              BLI_addtail(list, con);
                        }
                        ob->track = 0;
                  }

                  ob = ob->id.next;
            }


            for (sce= main->scene.first; sce; sce= sce->id.next) {
                  sce->audio.mixrate = 44100;
                  sce->audio.flag |= AUDIO_SCRUB;
                  sce->r.mode |= R_ENVMAP;
            }
            // init new shader vars
            for (ma= main->mat.first; ma; ma= ma->id.next) {
                  ma->refrac= 4.0;
                  ma->roughness= 0.5;
                  ma->param[0]= 0.5;
                  ma->param[1]= 0.1;
                  ma->param[2]= 0.1;
                  ma->param[3]= 0.05;
            }
            // patch for old wrong max view2d settings, allows zooming out more
            for (sc= main->screen.first; sc; sc= sc->id.next) {
                  ScrArea *sa;

                  for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;

                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if (sl->spacetype==SPACE_ACTION) {
                                    SpaceAction *sac= (SpaceAction *) sl;
                                    sac->v2d.max[0]= 32000;
                              }
                              else if (sl->spacetype==SPACE_NLA) {
                                    SpaceNla *sla= (SpaceNla *) sl;
                                    sla->v2d.max[0]= 32000;
                              }
                        }
                  }
            }
      }
      if(main->versionfile <= 228) {
            Scene *sce;
            bScreen *sc;
            Object *ob;


            /*  As of now, this insures that the transition from the old Track system
                to the new full constraint Track is painless for everyone.*/
            ob = main->object.first;

            while (ob) {
                  ListBase *list;
                  list = &ob->constraints;

                  /* check for already existing TrackTo constraint
                     set their track and up flag correctly */

                  if (list){
                        bConstraint *curcon;
                        for (curcon = list->first; curcon; curcon=curcon->next){
                              if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
                                    bTrackToConstraint *data = curcon->data;
                                    data->reserved1 = ob->trackflag;
                                    data->reserved2 = ob->upflag;
                              }
                        }
                  }

                  if (ob->type == OB_ARMATURE) {
                        if (ob->pose){
                              bConstraint *curcon;
                              bPoseChannel *pchan;
                              for (pchan = ob->pose->chanbase.first;
                                     pchan; pchan=pchan->next){
                                    for (curcon = pchan->constraints.first;
                                           curcon; curcon=curcon->next){
                                          if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
                                                bTrackToConstraint *data = curcon->data;
                                                data->reserved1 = ob->trackflag;
                                                data->reserved2 = ob->upflag;
                                          }
                                    }
                              }
                }
                  }

                  ob = ob->id.next;
            }

            for (sce= main->scene.first; sce; sce= sce->id.next) {
                  sce->r.mode |= R_ENVMAP;
            }

            // convert old mainb values for new button panels
            for (sc= main->screen.first; sc; sc= sc->id.next) {
                  ScrArea *sa;

                  for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;

                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if (sl->spacetype==SPACE_BUTS) {
                                    SpaceButs *sbuts= (SpaceButs *) sl;

                                    sbuts->v2d.maxzoom= 1.2;

                                    if(sbuts->mainb==BUTS_LAMP) {
                                          sbuts->mainb= CONTEXT_SHADING;
                                          sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_LAMP;
                                    }
                                    else if(sbuts->mainb==BUTS_MAT) {
                                          sbuts->mainb= CONTEXT_SHADING;
                                          sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT;
                                    }
                                    else if(sbuts->mainb==BUTS_TEX) {
                                          sbuts->mainb= CONTEXT_SHADING;
                                          sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_TEX;
                                    }
                                    else if(sbuts->mainb==BUTS_ANIM) {
                                          sbuts->mainb= CONTEXT_OBJECT;
                                    }
                                    else if(sbuts->mainb==BUTS_WORLD) {
                                          sbuts->mainb= CONTEXT_SCENE;
                                          sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_WORLD;
                                    }
                                    else if(sbuts->mainb==BUTS_RENDER) {
                                          sbuts->mainb= CONTEXT_SCENE;
                                          sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_RENDER;
                                    }
                                    else if(sbuts->mainb==BUTS_GAME) {
                                          sbuts->mainb= CONTEXT_LOGIC;
                                    }
                                    else if(sbuts->mainb==BUTS_FPAINT) {
                                          sbuts->mainb= CONTEXT_EDITING;
                                    }
                                    else if(sbuts->mainb==BUTS_RADIO) {
                                          sbuts->mainb= CONTEXT_SHADING;
                                          sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_RAD;
                                    }
                                    else if(sbuts->mainb==BUTS_CONSTRAINT) {
                                          sbuts->mainb= CONTEXT_OBJECT;
                                    }
                                    else if(sbuts->mainb==BUTS_SCRIPT) {
                                          sbuts->mainb= CONTEXT_OBJECT;
                                    }
                                    else if(sbuts->mainb==BUTS_EDIT) {
                                          sbuts->mainb= CONTEXT_EDITING;
                                    }
                                    else sbuts->mainb= CONTEXT_SCENE;
                              }
                        }
                  }
            }
      }
      /* ton: made this 230 instead of 229,
         to be sure (tuho files) and this is a reliable check anyway
         nevertheless, we might need to think over a fitness (initialize)
         check apart from the do_versions() */

      if(main->versionfile <= 230) {
            bScreen *sc;

            // new variable blockscale, for panels in any area
            for (sc= main->screen.first; sc; sc= sc->id.next) {
                  ScrArea *sa;

                  for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;

                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if(sl->blockscale==0.0) sl->blockscale= 0.7;
                              /* added: 5x better zoom in for action */
                              if(sl->spacetype==SPACE_ACTION) {
                                    SpaceAction *sac= (SpaceAction *)sl;
                                    sac->v2d.maxzoom= 50;
                              }
                        }
                  }
            }
      }
      if(main->versionfile <= 231) {
            /* new bit flags for showing/hiding grid floor and axes */
            bScreen *sc = main->screen.first;
            while(sc) {
                  ScrArea *sa= sc->areabase.first;
                  while(sa) {
                        SpaceLink *sl= sa->spacedata.first;
                        while (sl) {
                              if (sl->spacetype==SPACE_VIEW3D) {
                                    View3D *v3d= (View3D*) sl;

                                    if (v3d->gridflag==0) {
                                          v3d->gridflag |= V3D_SHOW_X;
                                          v3d->gridflag |= V3D_SHOW_Y;
                                          v3d->gridflag |= V3D_SHOW_FLOOR;
                                          v3d->gridflag &= ~V3D_SHOW_Z;
                                    }
                              }
                              sl= sl->next;
                        }
                        sa= sa->next;
                  }
                  sc= sc->id.next;
            }
      }
      if(main->versionfile <= 231) {
            Material *ma= main->mat.first;
            bScreen *sc = main->screen.first;
            Scene *sce;
            Lamp *la;
            World *wrld;

            while(ma) {
                  if(ma->fresnel_tra_i==0.0) ma->fresnel_tra_i= 1.25;
                  if(ma->fresnel_mir_i==0.0) ma->fresnel_mir_i= 1.25;
                  if(ma->ang==0.0) {
                        ma->ang= 1.0;
                        ma->ray_depth= 2;
                        ma->ray_depth_tra= 2;
                        ma->fresnel_tra= 0.0;
                        ma->fresnel_mir= 0.0;
                  }
                  else if(ma->ang<1.0) {        // temporal, because of IOR & fresnel change
                        ma->ang= 1.0/ma->ang;
                        ma->fresnel_tra= ma->ang;
                        ma->fresnel_mir= ma->ang;
                  }
                  ma= ma->id.next;
            }
            sce= main->scene.first;
            while(sce) {
                  if(sce->r.gauss==0.0) sce->r.gauss= 1.0;
                  sce= sce->id.next;
            }
            la= main->lamp.first;
            while(la) {
                  if(la->k==0.0) la->k= 1.0;
                  if(la->ray_samp==0) la->ray_samp= 1;
                  if(la->ray_sampy==0) la->ray_sampy= 1;
                  if(la->ray_sampz==0) la->ray_sampz= 1;
                  if(la->area_size==0.0) la->area_size= 1.0;
                  if(la->area_sizey==0.0) la->area_sizey= 1.0;
                  if(la->area_sizez==0.0) la->area_sizez= 1.0;
                  la= la->id.next;
            }
            wrld= main->world.first;
            while(wrld) {
                  if(wrld->range==0.0) {
                        wrld->range= 1.0/wrld->exposure;
                  }
                  wrld= wrld->id.next;
            }

            /* new bit flags for showing/hiding grid floor and axes */

            while(sc) {
                  ScrArea *sa= sc->areabase.first;
                  while(sa) {
                        SpaceLink *sl= sa->spacedata.first;
                        while (sl) {
                              if (sl->spacetype==SPACE_VIEW3D) {
                                    View3D *v3d= (View3D*) sl;

                                    if (v3d->gridflag==0) {
                                          v3d->gridflag |= V3D_SHOW_X;
                                          v3d->gridflag |= V3D_SHOW_Y;
                                          v3d->gridflag |= V3D_SHOW_FLOOR;
                                          v3d->gridflag &= ~V3D_SHOW_Z;
                                    }
                              }
                              sl= sl->next;
                        }
                        sa= sa->next;
                  }
                  sc= sc->id.next;
            }
      }
      if(main->versionfile <= 232) {
            Tex *tex= main->tex.first;
            World *wrld= main->world.first;
            bScreen *sc;
            Scene *sce;

            while(tex) {
                  if((tex->flag & (TEX_CHECKER_ODD+TEX_CHECKER_EVEN))==0) {
                        tex->flag |= TEX_CHECKER_ODD;
                  }
                  /* copied from kernel texture.c */
                  if(tex->ns_outscale==0.0) {
                        /* musgrave */
                        tex->mg_H = 1.0;
                        tex->mg_lacunarity = 2.0;
                        tex->mg_octaves = 2.0;
                        tex->mg_offset = 1.0;
                        tex->mg_gain = 1.0;
                        tex->ns_outscale = 1.0;
                        /* distnoise */
                        tex->dist_amount = 1.0;
                        /* voronoi */
                        tex->vn_w1 = 1.0;
                        tex->vn_mexp = 2.5;
                  }
                  tex= tex->id.next;
            }

            while(wrld) {
                  if(wrld->aodist==0.0) {
                        wrld->aodist= 10.0;
                        wrld->aobias= 0.05;
                  }
                  if(wrld->aosamp==0.0) wrld->aosamp= 5;
                  if(wrld->aoenergy==0.0) wrld->aoenergy= 1.0;
                  wrld= wrld->id.next;
            }


            // new variable blockscale, for panels in any area, do again because new
            // areas didnt initialize it to 0.7 yet
            for (sc= main->screen.first; sc; sc= sc->id.next) {
                  ScrArea *sa;
                  for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;
                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if(sl->blockscale==0.0) sl->blockscale= 0.7;

                              /* added: 5x better zoom in for nla */
                              if(sl->spacetype==SPACE_NLA) {
                                    SpaceNla *snla= (SpaceNla *)sl;
                                    snla->v2d.maxzoom= 50;
                              }
                        }
                  }
            }
            sce= main->scene.first;
            while(sce) {
                  if(sce->r.ocres==0) sce->r.ocres= 64;
                  sce= sce->id.next;
            }

      }
      if(main->versionfile <= 233) {
            bScreen *sc;
            Material *ma= main->mat.first;
            Object *ob= main->object.first;
            
            while(ma) {
                  if(ma->rampfac_col==0.0) ma->rampfac_col= 1.0;
                  if(ma->rampfac_spec==0.0) ma->rampfac_spec= 1.0;
                  if(ma->pr_lamp==0) ma->pr_lamp= 3;
                  ma= ma->id.next;
            }
            
            /* this should have been done loooong before! */
            while(ob) {
                  if(ob->ipowin==0) ob->ipowin= ID_OB;
                  ob= ob->id.next;
            }
            
            for (sc= main->screen.first; sc; sc= sc->id.next) {
                  ScrArea *sa;
                  for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;
                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if(sl->spacetype==SPACE_VIEW3D) {
                                    View3D *v3d= (View3D *)sl;
                                    v3d->flag |= V3D_SELECT_OUTLINE;
                              }
                        }
                  }
            }
      }
      if(main->versionfile <= 234) {
            Scene *sce;
            World *wo;
            bScreen *sc;
            int set_zbuf_sel=0;
            
            // force sumo engine to be active
            for (wo = main->world.first; wo; wo= wo->id.next) {
                  if(wo->physicsEngine==0) wo->physicsEngine = 2;
            }
            
            for (sce= main->scene.first; sce; sce= sce->id.next) {
                  if(sce->selectmode==0) {
                        sce->selectmode= SCE_SELECT_VERTEX;
                        set_zbuf_sel= 1;
                  }
            }
            for (sc= main->screen.first; sc; sc= sc->id.next) {
                  ScrArea *sa;
                  for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;
                        for (sl= sa->spacedata.first; sl; sl= sl->next) {
                              if(sl->spacetype==SPACE_VIEW3D) {
                                    View3D *v3d= (View3D *)sl;
                                    if(set_zbuf_sel) v3d->flag |= V3D_ZBUF_SELECT;
                              }
                              else if(sl->spacetype==SPACE_TEXT) {
                                    SpaceText *st= (SpaceText *)sl;
                                    if(st->tabnumber==0) st->tabnumber= 2;
                              }
                        }
                  }
            }
      }
      if(main->versionfile <= 235) {
            Tex *tex= main->tex.first;
            
            while(tex) {
                  if(tex->nabla==0.0) tex->nabla= 0.025;
                  tex= tex->id.next;
            }
      }
      
      /* don't forget to set version number in blender.c! */
}

static void lib_link_all(FileData *fd, Main *main)
{
      lib_link_screen(fd, main);
      lib_link_scene(fd, main);
      lib_link_object(fd, main);
      lib_link_curve(fd, main);
      lib_link_mball(fd, main);
      lib_link_material(fd, main);
      lib_link_texture(fd, main);
      lib_link_image(fd, main);
      lib_link_ipo(fd, main);
      lib_link_key(fd, main);
      lib_link_world(fd, main);
      lib_link_lamp(fd, main);
      lib_link_latt(fd, main);
      lib_link_ika(fd, main);
      lib_link_text(fd, main);
      lib_link_camera(fd, main);
      lib_link_sound(fd, main);
      lib_link_group(fd, main);
      lib_link_armature(fd, main);
      lib_link_action(fd, main);
      lib_link_vfont(fd, main);

      lib_link_mesh(fd, main);      /* as last: tpage images with users at zero */

      lib_link_library(fd, main);   /* only init users */
}

static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
{
      Link *link;

      bfd->user= read_struct(fd, bhead, "user def");
      bfd->user->themes.first= bfd->user->themes.last= NULL;

      bhead = blo_nextbhead(fd, bhead);

            /* read all attached data */
      while(bhead && bhead->code==DATA) {
            link= read_struct(fd, bhead, "user def data");
            BLI_addtail(&bfd->user->themes, link);
            bhead = blo_nextbhead(fd, bhead);
      }

      return bhead;
}

BlendFileData *blo_read_file_internal(FileData *fd, BlendReadError *error_r)
{
      BHead *bhead= blo_firstbhead(fd);
      BlendFileData *bfd;
      FileGlobal *fg = (FileGlobal *)NULL;

      bfd= MEM_callocN(sizeof(*bfd), "blendfiledata");
      bfd->main= MEM_callocN(sizeof(*bfd->main), "main");
      BLI_addtail(&fd->mainlist, bfd->main);

      bfd->main->versionfile= fd->fileversion;

      while(bhead) {
            switch(bhead->code) {
            case GLOB:
            case DATA:
            case DNA1:
            case TEST:
            case REND:
                  if (bhead->code==GLOB) {
                        fg= read_struct(fd, bhead, "REND");
                  }
                  bhead = blo_nextbhead(fd, bhead);
                  break;
            case USER:
                  bhead= read_userdef(bfd, fd, bhead);
                  break;
            case ENDB:
                  bhead = NULL;
                  break;

            case ID_LI:
                  bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
                  break;
            case ID_ID:
                        /* always adds to the most recently loaded
                         * ID_LI block, see direct_link_library.
                         * this is part of the file format definition.
                         */
                  bhead = read_libblock(fd, fd->mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL);
                  break;

            default:
                  bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
            }
      }

      /* before read_libraries */
      do_versions(bfd->main);
      read_libraries(fd, &fd->mainlist);
      blo_join_main(&fd->mainlist);

      lib_link_all(fd, bfd->main);
      link_global(fd, bfd, fg);     /* as last */

      /* removed here: check for existance of curscreen/scene, moved to kernel setup_app */

      MEM_freeN(fg);

      return bfd;
}

/* ************* APPEND LIBRARY ************** */

static BHead *find_previous_lib(FileData *fd, BHead *bhead)
{
      for (; bhead; bhead= blo_prevbhead(fd, bhead))
            if (bhead->code==ID_LI)
                  break;

      return bhead;
}

static BHead *find_bhead(FileData *fd, void *old)
{
      BHead *bhead;

      if (!old)
            return NULL;

      for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead))
            if (bhead->old==old)
                  return bhead;

      return NULL;
}

static ID *is_yet_read(Main *mainvar, BHead *bhead)
{
      ListBase *lb;
      ID *idtest, *id;

      // BHEAD+DATA dependancy
      idtest= (ID *)(bhead +1);
      lb= wich_libbase(mainvar, GS(idtest->name));
      if(lb) {
            id= lb->first;
            while(id) {
                  if( strcmp(id->name, idtest->name)==0 ) return id;
                  id= id->next;
            }
      }
      return 0;
}

static void expand_doit(FileData *fd, Main *mainvar, void *old)
{
      BHead *bhead;
      ID *id;

      bhead= find_bhead(fd, old);
      if(bhead) {
                  /* from another library? */
            if(bhead->code==ID_ID) {
                  BHead *bheadlib= find_previous_lib(fd, bhead);

                  if(bheadlib) {
                        // BHEAD+DATA dependancy
                        Library *lib= (Library *)(bheadlib+1);
                        mainvar= blo_find_main(&fd->mainlist, lib->name);

                        id= is_yet_read(mainvar, bhead);

                        if(id==0) {
                              read_libblock(fd, mainvar, bhead, LIB_READ+LIB_INDIRECT, NULL);
                              printf("expand: other lib %s\n", lib->name);
                        }
                        else {
                              oldnewmap_insert(fd->libmap, bhead->old, id, 1);
                              printf("expand: already linked: %s lib: %s\n", id->name, lib->name);
                        }
                  }
            }
            else {
                  id= is_yet_read(mainvar, bhead);
                  if(id==0) {
                        // BHEAD+DATA dependancy
                        id= (ID *)(bhead+1);
                        read_libblock(fd, mainvar, bhead, LIB_TESTIND, NULL);
                  }
                  else {
                        oldnewmap_insert(fd->libmap, bhead->old, id, 1);
                        /* printf("expand: already read %s\n", id->name); */
                  }
            }
      }
}

static void expand_key(FileData *fd, Main *mainvar, Key *key)
{
      expand_doit(fd, mainvar, key->ipo);
}


static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
{
      expand_doit(fd, mainvar, tex->ima);
      expand_doit(fd, mainvar, tex->ipo);
}

static void expand_material(FileData *fd, Main *mainvar, Material *ma)
{
      int a;

      for(a=0; a<MAX_MTEX; a++) {
            if(ma->mtex[a]) {
                  expand_doit(fd, mainvar, ma->mtex[a]->tex);
                  expand_doit(fd, mainvar, ma->mtex[a]->object);
            }
      }
      expand_doit(fd, mainvar, ma->ipo);
}

static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la)
{
      int a;

      for(a=0; a<MAX_MTEX; a++) {
            if(la->mtex[a]) {
                  expand_doit(fd, mainvar, la->mtex[a]->tex);
                  expand_doit(fd, mainvar, la->mtex[a]->object);
            }
      }
      expand_doit(fd, mainvar, la->ipo);
}

static void expand_lattice(FileData *fd, Main *mainvar, Lattice *lt)
{
      expand_doit(fd, mainvar, lt->ipo);
      expand_doit(fd, mainvar, lt->key);
}


static void expand_world(FileData *fd, Main *mainvar, World *wrld)
{
      int a;

      for(a=0; a<MAX_MTEX; a++) {
            if(wrld->mtex[a]) {
                  expand_doit(fd, mainvar, wrld->mtex[a]->tex);
                  expand_doit(fd, mainvar, wrld->mtex[a]->object);
            }
      }
      expand_doit(fd, mainvar, wrld->ipo);
}


static void expand_mball(FileData *fd, Main *mainvar, MetaBall *mb)
{
      int a;

      for(a=0; a<mb->totcol; a++) {
            expand_doit(fd, mainvar, mb->mat[a]);
      }
}

static void expand_curve(FileData *fd, Main *mainvar, Curve *cu)
{
      int a;

      for(a=0; a<cu->totcol; a++) {
            expand_doit(fd, mainvar, cu->mat[a]);
      }
      expand_doit(fd, mainvar, cu->vfont);
      expand_doit(fd, mainvar, cu->key);
      expand_doit(fd, mainvar, cu->ipo);
      expand_doit(fd, mainvar, cu->bevobj);
      expand_doit(fd, mainvar, cu->taperobj);
      expand_doit(fd, mainvar, cu->textoncurve);
}

static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me)
{
      int a;
      TFace *tface;

      for(a=0; a<me->totcol; a++) {
            expand_doit(fd, mainvar, me->mat[a]);
      }

      expand_doit(fd, mainvar, me->key);
      expand_doit(fd, mainvar, me->texcomesh);

      if(me->tface) {
            tface= me->tface;
            a= me->totface;
            while(a--) {
                  if(tface->tpage) expand_doit(fd, mainvar, tface->tpage);
                  tface++;
            }
      }
}

static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
{
      bConstraint *curcon;

      for (curcon=lb->first; curcon; curcon=curcon->next) {
            switch (curcon->type) {
            case CONSTRAINT_TYPE_ACTION:
                  {
                        bActionConstraint *data = (bActionConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        expand_doit(fd, mainvar, data->act);
                  }
                  break;
            case CONSTRAINT_TYPE_LOCLIKE:
                  {
                        bLocateLikeConstraint *data = (bLocateLikeConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_ROTLIKE:
                  {
                        bRotateLikeConstraint *data = (bRotateLikeConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_KINEMATIC:
                  {
                        bKinematicConstraint *data = (bKinematicConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_TRACKTO:
                  {
                        bTrackToConstraint *data = (bTrackToConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_LOCKTRACK:
                  {
                        bLockTrackConstraint *data = (bLockTrackConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_FOLLOWPATH:
                  {
                        bFollowPathConstraint *data = (bFollowPathConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_DISTANCELIMIT:
                  {
                        bDistanceLimitConstraint *data = (bDistanceLimitConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_STRETCHTO:
                  {
                        bStretchToConstraint *data = (bStretchToConstraint*)curcon->data;
                        expand_doit(fd, mainvar, data->tar);
                        break;
                  }
            case CONSTRAINT_TYPE_NULL:
                  break;
            default:
                  break;
            }
      }
}

static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
{
      Bone *curBone;

//    expand_constraints(fd, main, &bone->constraints);

      for (curBone = bone->childbase.first; curBone; curBone=curBone->next) {
            expand_bones(fd, mainvar, curBone);
      }

}

static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
{
      bPoseChannel *chan;

      if (!pose)
            return;

      for (chan = pose->chanbase.first; chan; chan=chan->next) {
            expand_constraints(fd, mainvar, &chan->constraints);
      }
}

static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
{
      Bone *curBone;

      for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) {
            expand_bones(fd, mainvar, curBone);
      }
}

static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *chanbase)
{
      bConstraintChannel *chan;
      for (chan=chanbase->first; chan; chan=chan->next){
            expand_doit(fd, mainvar, chan->ipo);
      }
}

static void expand_action(FileData *fd, Main *mainvar, bAction *act)
{
      bActionChannel *chan;
      for (chan=act->chanbase.first; chan; chan=chan->next) {
            expand_doit(fd, mainvar, chan->ipo);
            expand_constraint_channels(fd, mainvar, &chan->constraintChannels);
      }
}

static void expand_object(FileData *fd, Main *mainvar, Object *ob)
{
      bSensor *sens;
      bController *cont;
      bActuator *act;
      bActionStrip *strip;
      int a;


      expand_doit(fd, mainvar, ob->data);
      expand_doit(fd, mainvar, ob->ipo);
      expand_doit(fd, mainvar, ob->action);

      expand_pose(fd, mainvar, ob->pose);
      expand_constraints(fd, mainvar, &ob->constraints);
      expand_constraint_channels(fd, mainvar, &ob->constraintChannels);

      for (strip=ob->nlastrips.first; strip; strip=strip->next){
            expand_doit(fd, mainvar, strip->act);
            expand_doit(fd, mainvar, strip->ipo);
      }

      for(a=0; a<ob->totcol; a++) {
            expand_doit(fd, mainvar, ob->mat[a]);
      }
      
      sens= ob->sensors.first;
      while(sens) {
            for(a=0; a<sens->totlinks; a++) {
                  sens->links[a]= newglobadr(fd, sens->links[a]);
            }
            if(sens->type==SENS_TOUCH) {
                  bTouchSensor *ts= sens->data;
                  expand_doit(fd, mainvar, ts->ma);
            }
            else if(sens->type==SENS_MESSAGE) {
                  bMessageSensor *ms= sens->data;
                  expand_doit(fd, mainvar, ms->fromObject);
            }
            sens= sens->next;
      }

      cont= ob->controllers.first;
      while(cont) {
            for(a=0; a<cont->totlinks; a++) {
                  cont->links[a]= newglobadr(fd, cont->links[a]);
            }
            if(cont->type==CONT_PYTHON) {
                  bPythonCont *pc= cont->data;
                  expand_doit(fd, mainvar, pc->text);
            }
            cont= cont->next;
      }

      act= ob->actuators.first;
      while(act) {
            if(act->type==ACT_SOUND) {
                  bSoundActuator *sa= act->data;
                  expand_doit(fd, mainvar, sa->sound);
            }
            else if(act->type==ACT_CAMERA) {
                  bCameraActuator *ca= act->data;
                  expand_doit(fd, mainvar, ca->ob);
            }
            else if(act->type==ACT_EDIT_OBJECT) {
                  bEditObjectActuator *eoa= act->data;
                  if(eoa) {
                        expand_doit(fd, mainvar, eoa->ob);
                        expand_doit(fd, mainvar, eoa->me);
                  }
            }
            else if(act->type==ACT_SCENE) {
                  bSceneActuator *sa= act->data;
                  expand_doit(fd, mainvar, sa->camera);
                  expand_doit(fd, mainvar, sa->scene);
            }
            else if(act->type==ACT_ACTION) {
                  bActionActuator *aa= act->data;
                  expand_doit(fd, mainvar, aa->act);
            }
            else if(act->type==ACT_PROPERTY) {
                  bPropertyActuator *pa= act->data;
                  expand_doit(fd, mainvar, pa->ob);
            }
            else if(act->type==ACT_MESSAGE) {
                  bMessageActuator *ma= act->data;
                  expand_doit(fd, mainvar, ma->toObject);
            }
            act= act->next;
      }
}

static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
{
      Base *base;

      base= sce->base.first;
      while(base) {
            expand_doit(fd, mainvar, base->object);
            base= base->next;
      }
      expand_doit(fd, mainvar, sce->camera);
      expand_doit(fd, mainvar, sce->world);
}

static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
{
      expand_doit(fd, mainvar, ca->ipo);
}

static void expand_sound(FileData *fd, Main *mainvar, bSound *snd)
{
      expand_doit(fd, mainvar, snd->ipo);
}


static void expand_main(FileData *fd, Main *mainvar)
{
      ListBase *lbarray[30];
      ID *id;
      int a, doit= 1;

      if(fd==0) return;

      while(doit) {
            doit= 0;

            a= set_listbasepointers(mainvar, lbarray);
            while(a--) {
                  id= lbarray[a]->first;

                  while(id) {
                        if(id->flag & LIB_TEST) {

                              switch(GS(id->name)) {

                              case ID_OB:
                                    expand_object(fd, mainvar, (Object *)id);
                                    break;
                              case ID_ME:
                                    expand_mesh(fd, mainvar, (Mesh *)id);
                                    break;
                              case ID_CU:
                                    expand_curve(fd, mainvar, (Curve *)id);
                                    break;
                              case ID_MB:
                                    expand_mball(fd, mainvar, (MetaBall *)id);
                                    break;
                              case ID_SCE:
                                    expand_scene(fd, mainvar, (Scene *)id);
                                    break;
                              case ID_MA:
                                    expand_material(fd, mainvar, (Material *)id);
                                    break;
                              case ID_TE:
                                    expand_texture(fd, mainvar, (Tex *)id);
                                    break;
                              case ID_WO:
                                    expand_world(fd, mainvar, (World *)id);
                                    break;
                              case ID_LT:
                                    expand_lattice(fd, mainvar, (Lattice *)id);
                                    break;
                              case ID_LA:
                                    expand_lamp(fd, mainvar,(Lamp *)id);
                                    break;
                              case ID_KE:
                                    expand_key(fd, mainvar, (Key *)id);
                                    break;
                              case ID_CA:
                                    expand_camera(fd, mainvar, (Camera *)id);
                                    break;
                              case ID_SO:
                                    expand_sound(fd, mainvar, (bSound *)id);
                                    break;
                              case ID_AR:
                                    expand_armature(fd, mainvar, (bArmature *)id);
                                    break;
                              case ID_AC:
                                    expand_action(fd, mainvar, (bAction *)id);
                                    break;
                              }

                              doit= 1;
                              id->flag -= LIB_TEST;

                        }
                        id= id->next;
                  }
            }
      }
}


static void give_base_to_objects(Scene *sce, ListBase *lb)
{
      Object *ob;
      Base *base;

      /* give all objects which are LIB_EXTERN and LIB_NEEDLINK a base */
      ob= lb->first;
      while(ob) {

            if(ob->id.us==0) {

                  if( ob->id.flag & LIB_INDIRECT ) {
                        base= MEM_callocN( sizeof(Base), "add_ext_base");
                        BLI_addtail(&(sce->base), base);
                        base->lay= ob->lay;
                        base->object= ob;
                        ob->id.us= 1;

                        ob->id.flag -= LIB_INDIRECT;
                        ob->id.flag |= LIB_EXTERN;

                  }
            }
            ob= ob->id.next;
      }
}


static void append_named_part(FileData *fd, Main *mainvar, Scene *scene, char *name, int idcode, short flag)
{
      Object *ob;
      Base *base;
      BHead *bhead;
      ID *id;
      int afbreek=0;

      bhead = blo_firstbhead(fd);
      while(bhead && afbreek==0) {

            if(bhead->code==ENDB) afbreek= 1;
            else if(bhead->code==idcode) {
                  // BHEAD+DATA dependancy
                  id= (ID *)(bhead+1);
                  if(strcmp(id->name+2, name)==0) {

                        id= is_yet_read(mainvar, bhead);
                        if(id==0) {
                              read_libblock(fd, mainvar, bhead, LIB_TESTEXT, NULL);
                        }
                        else {
                              printf("append: already linked\n");
                              oldnewmap_insert(fd->libmap, bhead->old, id, 1);
                              if(id->flag & LIB_INDIRECT) {
                                    id->flag -= LIB_INDIRECT;
                                    id->flag |= LIB_EXTERN;
                              }
                        }

                        if(idcode==ID_OB) {     /* loose object: give a base */
                              base= MEM_callocN( sizeof(Base), "app_nam_part");
                              BLI_addtail(&scene->base, base);

                              if(id==0) ob= mainvar->object.last;
                              else ob= (Object *)id;

                              if((flag & FILE_ACTIVELAY)) ob->lay = G.scene->lay;
                              base->lay= ob->lay;
                              base->object= ob;
                              ob->id.us++;
                              
                              if(flag & FILE_AUTOSELECT) { 
                                    base->flag |= SELECT;
                                    base->object->flag = base->flag;
                                    /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
                              }
                        }
                        afbreek= 1;
                  }
            }

            bhead = blo_nextbhead(fd, bhead);
      }
}

static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **id_r)
{
      BHead *bhead;

      for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
            if (bhead->code == GS(id->name)) {
                  ID *idread= (ID *)(bhead+1); /*  BHEAD+DATA dependancy */

                  if (BLI_streq(id->name, idread->name)) {
                        id->flag -= LIB_READ;
                        id->flag |= LIB_TEST;

                        read_libblock(fd, mainvar, bhead, id->flag, id_r);

                        break;
                  }
            } else if (bhead->code==ENDB)
                  break;
      }
}

/* this is a version of BLO_library_append needed by the BPython API, so
 * scripts can load data from .blend files -- see Blender.Library module.*/

/* append to G.scene */
void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, int idcode)
{
      ListBase mainlist;
      Main *mainl;
      FileData *fd = (FileData *)bh;

      mainlist.first= mainlist.last= G.main;
      G.main->next= NULL;

      /* make mains */
      blo_split_main(&mainlist);

      /* which one do we need? */
      mainl = blo_find_main(&mainlist, dir);

      append_named_part(fd, mainl, G.scene, name, idcode, 0);

      /* make main consistant */
      expand_main(fd, mainl);

      /* do this when expand found other libs */
      read_libraries(fd, &mainlist);

      blo_join_main(&mainlist);
      G.main= mainlist.first;

      lib_link_all(fd, G.main);
}

      /* append to G.scene */
void BLO_library_append(SpaceFile *sfile, char *dir, int idcode)
{
      FileData *fd= (FileData*) sfile->libfiledata;
      ListBase mainlist;
      Main *mainl;
      int a, totsel=0,count=0;
      float *curs,centerloc[3],vec[3],min[3],max[3];
      Base *centerbase;
      Object *ob;
      
      INIT_MINMAX(min, max);

      /* are there files selected? */
      for(a=0; a<sfile->totfile; a++) {
            if(sfile->filelist[a].flags & ACTIVE) {
                  totsel++;
            }
      }

      if(totsel==0) {
            /* is the indicated file in the filelist? */
            if(sfile->file[0]) {
                  for(a=0; a<sfile->totfile; a++) {
                        if( strcmp(sfile->filelist[a].relname, sfile->file)==0) break;
                  }
                  if(a==sfile->totfile) {
                        error("Wrong indicated name");
                        return;
                  }
            }
            else {
                  error("Nothing indicated");
                  return;
            }
      }
      /* now we have or selected, or an indicated file */
      
      if(sfile->flag & FILE_AUTOSELECT) scene_deselect_all(G.scene);

      mainlist.first= mainlist.last= G.main;
      G.main->next= NULL;

      /* make mains */
      blo_split_main(&mainlist);

      /* which one do we need? */
      mainl = blo_find_main(&mainlist, dir);
      mainl->versionfile= fd->fileversion;      // needed for do_version
      
      if(totsel==0) {
            append_named_part(fd, mainl, G.scene, sfile->file, idcode, sfile->flag);
      }
      else {
            for(a=0; a<sfile->totfile; a++) {
                  if(sfile->filelist[a].flags & ACTIVE) {
                        append_named_part(fd, mainl, G.scene, sfile->filelist[a].relname, idcode, sfile->flag);
                  }
            }
      }

      /* make main consistant */
      expand_main(fd, mainl);

      /* do this when expand found other libs */
      read_libraries(fd, &mainlist);

      blo_join_main(&mainlist);
      G.main= mainlist.first;

      lib_link_all(fd, G.main);

      /* give a base to loose objects */
      give_base_to_objects(G.scene, &(G.main->object));
      /* has been removed... erm, why? (ton) */
      /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */
      /* 20041208: put back. It only linked direct, not indirect objects (ton) */
      
      /* patch to prevent switch_endian happens twice */
      if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
            blo_freefiledata((FileData*) sfile->libfiledata);
            sfile->libfiledata= 0;
      }
      
      if(sfile->flag & FILE_STRINGCODE) BLI_makestringcode(G.sce, mainl->curlib->name);
      
      if(sfile->flag & FILE_ATCURSOR) {
            centerbase= (G.scene->base.first);
            while(centerbase) {
                  if(((centerbase)->flag & SELECT)) {
                        VECCOPY(vec, centerbase->object->loc);
                        DO_MINMAX(vec, min, max);
                        count++;
                  }
                  centerbase= centerbase->next;
            }
            if(count) {
                  centerloc[0]= (min[0]+max[0])/2;
                  centerloc[1]= (min[1]+max[1])/2;
                  centerloc[2]= (min[2]+max[2])/2;
                  curs = G.scene->cursor;
                  VECSUB(centerloc,curs,centerloc);
            
                  centerbase= (G.scene->base.first);
                  while(centerbase) {
                        if( ((centerbase)->flag & SELECT)) {
                              ob= centerbase->object;
                              ob->loc[0] += centerloc[0];
                              ob->loc[1] += centerloc[1];
                              ob->loc[2] += centerloc[2];
                        }
                        centerbase= centerbase->next;
                  }
            }
            
      }
}

/* ************* READ LIBRARY ************** */

static int mainvar_count_libread_blocks(Main *mainvar)
{
      ListBase *lbarray[30];
      int a, tot= 0;

      a= set_listbasepointers(mainvar, lbarray);
      while(a--) {
            ID *id= lbarray[a]->first;

            for (id= lbarray[a]->first; id; id= id->next)
                  if (id->flag & LIB_READ)
                        tot++;
      }
      return tot;
}

static void read_libraries(FileData *basefd, ListBase *mainlist)
{
      Main *mainl= mainlist->first;
      Main *mainptr;
      ListBase *lbarray[30];
      int a, doit= 1;

      while(doit) {
            doit= 0;

            /* test 1: read libdata */
            mainptr= mainl->next;

            while(mainptr) {
                  int tot= mainvar_count_libread_blocks(mainptr);

                  if(tot) {
                        FileData *fd= mainptr->curlib->filedata;

                        if(fd==0) {
                              printf("read lib %s\n", mainptr->curlib->name);
                              fd= blo_openblenderfile(mainptr->curlib->name);
                              if (fd) {
                                    if (fd->libmap)
                                          oldnewmap_free(fd->libmap);

                                    fd->libmap= basefd->libmap;
                                    fd->flags|= FD_FLAGS_NOT_MY_LIBMAP;
                              }

                              mainptr->curlib->filedata= fd;
                              mainptr->versionfile= fd->fileversion;

                              if (!fd)
                                    printf("ERROR: can't find lib %s \n", mainptr->curlib->name);
                        }
                        if(fd) {
                              doit= 1;
                              a= set_listbasepointers(mainptr, lbarray);
                              while(a--) {
                                    ID *id= lbarray[a]->first;

                                    while(id) {
                                          ID *idn= id->next;
                                          if(id->flag & LIB_READ) {
                                                ID *realid= NULL;
                                                BLI_remlink(lbarray[a], id);

                                                append_id_part(fd, mainptr, id, &realid);
                                                if (!realid)
                                                      printf("LIB ERROR: can't find %s\n", id->name);
                                                change_libadr(fd, id, realid);

                                                MEM_freeN(id);
                                          }
                                          id= idn;
                                    }
                              }

                              expand_main(fd, mainptr);
                        }
                  }

                  mainptr= mainptr->next;
            }
      }
      mainptr= mainl->next;
      while(mainptr) {
            /* test if there are unread libblocks */
            a= set_listbasepointers(mainptr, lbarray);
            while(a--) {
                  ID *id= lbarray[a]->first;
                  while(id) {
                        ID *idn= id->next;
                        if(id->flag & LIB_READ) {
                              BLI_remlink(lbarray[a], id);

                              printf("LIB ERROR: can't find %s\n", id->name);
                              change_libadr(basefd, id, 0);

                              MEM_freeN(id);
                        }
                        id= idn;
                  }
            }

            /* some mains still have to be read, then
             * versionfile is still zero! */
            if(mainptr->versionfile) do_versions(mainptr);

            if(mainptr->curlib->filedata) blo_freefiledata(mainptr->curlib->filedata);
            mainptr->curlib->filedata= 0;

            mainptr= mainptr->next;
      }
}

/* reading runtime */

BlendFileData *blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r) 
{
      BlendFileData *bfd = NULL;
      FileData *fd = filedata_new();
      fd->filedes = file;
      fd->buffersize = actualsize;
      fd->read = fd_read_from_file;

      decode_blender_header(fd);

      if (fd->flags & FD_FLAGS_FILE_OK) {
            if (!read_file_dna(fd)) {
                  blo_freefiledata(fd);
                  fd= NULL;
                  return NULL;
            }
      } else {
            blo_freefiledata(fd);
            fd= NULL;
            return NULL;
      }

      bfd= blo_read_file_internal(fd, error_r);
      blo_freefiledata(fd);

      return bfd;
}

Generated by  Doxygen 1.6.0   Back to index