1 /*
2      PLIB - A Suite of Portable Game Libraries
3      Copyright (C) 1998,2002  Steve Baker
4 
5      This library is free software; you can redistribute it and/or
6      modify it under the terms of the GNU Library General Public
7      License as published by the Free Software Foundation; either
8      version 2 of the License, or (at your option) any later version.
9 
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Library General Public License for more details.
14 
15      You should have received a copy of the GNU Library General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 
19      For further information visit http://plib.sourceforge.net
20 
21      $Id: ssgLoadSSG.cxx 1568 2002-09-02 06:05:49Z sjbaker $
22 */
23 
24 // code for loading and writing .ssg files
25 
26 #include "ssgLocal.h"
27 
28 // used for reading only:
29 int _ssgFileVersionNumber = 0 ;
30 
31 // simple list of ssgBase derived objects:
32 class _ssgBaseList : public ssgSimpleList
33 {
34 public:
35 
_ssgBaseList()36   _ssgBaseList() : ssgSimpleList( sizeof(ssgBase *), 16 ) {}
37 
~_ssgBaseList()38   ~_ssgBaseList() {}
39 
get(unsigned n)40   ssgBase *get ( unsigned n )
41   {
42     return n < total ? ((ssgBase **) list) [ n ] : NULL;
43   }
44 
add(ssgBase * obj)45   void add ( ssgBase *obj )
46   {
47     sizeChk ( 1 ) ;
48     ((ssgBase **) list) [ total++ ] = obj ;
49   }
50 
find(ssgBase * obj)51   int find ( ssgBase *obj )
52   {
53     for ( unsigned i = 0 ; i < total ; i++ )
54       if ( ((ssgBase **) list) [ i ] == obj )
55 	return i ;
56     return -1 ;
57   }
58 
59 };
60 
61 // list of ssgBase objects for instance referencing:
62 static _ssgBaseList *_ssgInstanceList ;
63 
64 
_ssgLoadObject(FILE * f,ssgBase ** objp,int type_mask)65 int _ssgLoadObject ( FILE *f, ssgBase **objp, int type_mask )
66 {
67   int type = 0, key = 0;
68   ssgBase *obj;
69 
70   _ssgReadInt ( f, &type ) ;
71 
72   if ( type == _SSG_BACKWARDS_REFERENCE )
73   {
74     _ssgReadInt ( f, &key ) ;
75 
76     obj = _ssgInstanceList -> get ( key ) ;
77     if ( obj == NULL )
78     {
79       if ( key != 0 )
80       {
81 	ulSetError ( UL_WARNING,
82 		     "ssgLoadObject: Unexpected null object for key %d.", key ) ;
83 	return FALSE ;
84       }
85     }
86     else if ( ! obj -> isAKindOf ( type_mask ) )
87     {
88       ulSetError ( UL_WARNING, "ssgLoadObject: Bad type %#x (%s), expected %#x.",
89 		   obj -> getType (), obj -> getTypeName (), type_mask ) ;
90       return FALSE ;
91     }
92   }
93   else
94   {
95     if ( ( type & type_mask ) != type_mask )
96     {
97       ulSetError ( UL_WARNING, "ssgLoadObject: Bad type %#x, expected %#x.",
98 		   type, type_mask ) ;
99       return FALSE ;
100     }
101 
102     obj = ssgCreateOfType ( type ) ;
103     if ( obj == NULL )
104        return FALSE ;
105 
106     _ssgInstanceList -> add ( obj ) ;
107 
108     if ( ! obj -> load ( f ) )
109     {
110       ulSetError ( UL_DEBUG, "ssgLoadObject: Failed to load object of type %s.",
111 		   obj -> getTypeName () ) ;
112       return FALSE ;
113     }
114 
115     if ( obj -> isAKindOf ( ssgTypeEntity () ) )
116     {
117       ((ssgEntity *) obj) -> recalcBSphere () ;
118     }
119   }
120 
121   if ( _ssgReadError () )
122   {
123     ulSetError ( UL_WARNING, "ssgLoadObject: Read error." ) ;
124     return FALSE ;
125   }
126 
127   *objp = obj ;
128 
129   return TRUE ;
130 }
131 
132 
_ssgSaveObject(FILE * f,ssgBase * obj)133 int _ssgSaveObject ( FILE *f, ssgBase *obj )
134 {
135   int key = _ssgInstanceList -> find ( obj ) ;
136 
137   if ( key >= 0 )
138   {
139     _ssgWriteInt ( f, _SSG_BACKWARDS_REFERENCE ) ;
140     _ssgWriteInt ( f, key ) ;
141   }
142   else
143   {
144     _ssgWriteInt ( f, obj -> getType () ) ;
145 
146     _ssgInstanceList -> add ( obj ) ;
147 
148     if ( ! obj -> save ( f ) )
149     {
150       ulSetError ( UL_DEBUG, "ssgSaveObject: Failed to save object of type %s.",
151 		   obj -> getTypeName () ) ;
152       return FALSE ;
153     }
154   }
155 
156   if ( _ssgWriteError () )
157   {
158     ulSetError ( UL_WARNING, "ssgSaveObject: Write error." ) ;
159     return FALSE ;
160   }
161 
162   return TRUE ;
163 }
164 
165 
ssgLoadSSG(const char * fname,const ssgLoaderOptions * options)166 ssgEntity *ssgLoadSSG ( const char *fname, const ssgLoaderOptions* options )
167 {
168   ssgSetCurrentOptions ( (ssgLoaderOptions*)options ) ;
169   const ssgLoaderOptions* current_options = ssgGetCurrentOptions () ;
170 
171   char filename [ 1024 ] ;
172   current_options -> makeModelPath ( filename, fname ) ;
173 
174   FILE *fd = fopen ( filename, "rb" ) ;
175 
176   if ( fd == NULL )
177   {
178     perror ( filename ) ;
179     ulSetError ( UL_WARNING,
180 		 "ssgLoadSSG: Failed to open '%s' for reading.", filename ) ;
181     return NULL ;
182   }
183 
184   int magic ;
185   ssgEntity *kid ;
186 
187   _ssgReadInt ( fd, & magic ) ;
188 
189   if ( ( magic & 0xFFFFFF00 ) != ( SSG_FILE_MAGIC_NUMBER & 0xFFFFFF00 ) )
190   {
191     if (((magic & 0x0000FF)>> 0)==((SSG_FILE_MAGIC_NUMBER & 0xFF000000)>>24) &&
192         ((magic & 0x00FF00)>> 8)==((SSG_FILE_MAGIC_NUMBER & 0x00FF0000)>>16) &&
193         ((magic & 0xFF0000)>>16)==((SSG_FILE_MAGIC_NUMBER & 0x0000FF00)>> 8) )
194       ulSetError ( UL_WARNING, "ssgLoadSSG: File appears to be byte swapped!" ) ;
195     else
196       ulSetError ( UL_WARNING, "ssgLoadSSG: File has incorrect magic number!" ) ;
197 
198     return NULL ;
199   }
200 
201   /*
202     Save the old version number so we can do recursive loads
203   */
204 
205   int oldFileVersion = _ssgFileVersionNumber ;
206   _ssgFileVersionNumber = ( magic & 0xFF ) ;
207 
208   if ( _ssgFileVersionNumber == 0 )
209   {
210     ulSetError ( UL_WARNING,
211 		 "ssgLoadSSG: SSG file format version zero is no longer supported, sorry! For more, see the docs." ) ;
212     _ssgFileVersionNumber = oldFileVersion ;
213     return NULL ;
214   }
215 
216   if ( _ssgFileVersionNumber > SSG_FILE_VERSION )
217   {
218     ulSetError ( UL_WARNING,
219 		 "ssgLoadSSG: This version of SSG is too old to load this file!" ) ;
220     _ssgFileVersionNumber = oldFileVersion ;
221     return NULL ;
222   }
223 
224   _ssgBaseList *oldInstanceList = _ssgInstanceList ; // in case of recursive loads
225   _ssgInstanceList = new _ssgBaseList ;
226   _ssgInstanceList -> add ( NULL ) ; // index 0 --> NULL
227 
228   int success = _ssgLoadObject ( fd, (ssgBase **) &kid, ssgTypeEntity () ) ;
229 
230   if ( ! success )
231   {
232     ulSetError ( UL_WARNING, "ssgLoadSSG: Failed to load object." ) ;
233     kid = NULL ;
234   }
235 
236   delete _ssgInstanceList ;
237   _ssgInstanceList = oldInstanceList ;
238   _ssgFileVersionNumber = oldFileVersion ;
239 
240   fclose ( fd ) ;
241 
242   return kid ;
243 }
244 
245 
ssgSaveSSG(const char * filename,ssgEntity * ent)246 int ssgSaveSSG ( const char *filename, ssgEntity *ent )
247 {
248   FILE *fd = fopen ( filename, "wb" ) ;
249 
250   if ( fd == NULL )
251   {
252     perror ( filename ) ;
253     ulSetError ( UL_WARNING,
254 		 "ssgSaveSSG: Failed to open '%s' for writing.", filename ) ;
255     return FALSE ;
256   }
257 
258   _ssgBaseList *oldInstanceList = _ssgInstanceList ; // for recursive saves
259   _ssgInstanceList = new _ssgBaseList ;
260   _ssgInstanceList -> add ( NULL ) ; // index 0 --> NULL
261 
262   _ssgWriteInt ( fd, SSG_FILE_MAGIC_NUMBER ) ;
263 
264   int success = _ssgSaveObject ( fd, ent ) ;
265 
266   if ( ! success )
267     ulSetError ( UL_WARNING, "ssgSaveSSG: Failed to write object." ) ;
268 
269   delete _ssgInstanceList ;
270   _ssgInstanceList = oldInstanceList ;
271 
272   fclose ( fd ) ;
273 
274   return success ;
275 }
276 
277 
278