1 /*
2  * File:         model_load_save.c
3  *
4  * Description:  Abstracted interface to the different fmt readers and writers
5  *
6  * This source code is part of kludge3d, and is released under the
7  * GNU General Public License.
8  *
9  *
10  */
11 
12 /*
13  * Some code in this file is from:
14  *   - ME3D 3-D Modeler Program
15  *     the ME3D program is Copyright (C) 1998 Sam Revitch
16  *
17  */
18 
19 /* Document load/save code */
20 
21 #include <string.h>
22 
23 #include "undo.h"		/* for action_clear_stack(), etc */
24 #include "bottombar.h"
25 
26 #include "model_load_save.h"
27 
28 #ifdef MEMWATCH
29 #include "memwatch.h"
30 #endif
31 
32 extern struct doc_file_fmt fmt_ac3d;
33 extern struct doc_file_fmt fmt_f3ds;
34 extern struct doc_file_fmt fmt_quakemap;
35 extern struct doc_file_fmt fmt_md2;
36 extern struct doc_file_fmt fmt_wavefront;
37 
38 struct doc_file_fmt *fmt_list[] = {	/* KEEP ALPHABETICAL */
39     &fmt_ac3d,
40 #ifdef HAVE_LIB3DS
41     &fmt_f3ds,
42 #endif
43     &fmt_quakemap,
44 	&fmt_md2,
45     &fmt_wavefront,
46     NULL
47 };
48 
49 
50 
51 gint model_ls_examine_extension(const gchar *filename, gint load);
52 
53 
54 /*** Load Functions ***/
55 
model_load(const gchar * filename,gint fmt_idx)56 Model *model_load(const gchar *filename, gint fmt_idx)
57 {
58   struct fu_file *file;
59   Model *model = NULL;
60   gint ret;
61 
62   g_return_val_if_fail(filename != NULL, FALSE);
63   g_return_val_if_fail(fmt_idx >= -1, FALSE);
64 
65   if(fmt_idx == -1)
66     fmt_idx = model_ls_examine_extension(filename, TRUE);
67   if(fmt_idx == -1)
68     return NULL;
69 
70   file = fu_open(filename, FALSE);
71   if(file == NULL)
72     return NULL;
73 
74   model = model_new();
75 
76   action_clear_stack(model);
77   undo_disable(model);
78 
79   model_set_filename( model, (char*)filename );
80 
81   {
82   /* set the model name to be the basename */
83   char *basename = g_path_get_basename(filename);
84   model_set_name( model, basename );
85   g_free( basename );
86   }
87 
88   ret = (*(fmt_list[fmt_idx]->load_file))(file, model);
89   fu_close(file);
90   if(ret == FALSE) {
91 	model_delete( model );
92     return NULL;
93   }
94 
95   /* only set the format ID if there's a save function */
96   if(fmt_list[fmt_idx]->save_file != NULL)
97     model->fmt_idx = fmt_idx;
98   else
99     model->fmt_idx = -1;
100 
101   return model;
102 }
103 
104 
105 
106 /*** Save Functions ***/
107 
model_save(Model * doc,const gchar * filename,int overwrite,int * file_exists)108 gint model_save(Model *doc, const gchar *filename,
109 				int overwrite, int *file_exists )
110 {
111 	struct fu_file *file;
112 	gchar *old_fname = NULL;
113 	gint ret, name_changed = FALSE, old_fmt_idx;
114 
115 	g_return_val_if_fail(doc != NULL, FALSE);
116 
117 	if((filename == NULL) && (doc->fname == NULL))
118 		return FALSE;
119 
120 	*file_exists = FALSE;
121 
122 	if(filename != NULL) {
123 		if(doc->fname == NULL) {
124 			name_changed = TRUE;
125 		} else {
126 			if(strcmp(doc->fname, filename) != 0) {
127 				old_fname = strdup( doc->fname );
128 				name_changed = TRUE;
129 			}
130 		}
131 	} else {
132 		filename = doc->fname;
133 	}
134 
135 	old_fmt_idx = doc->fmt_idx;
136 	if(doc->fmt_idx == -1) {
137 		doc->fmt_idx = model_ls_examine_extension(filename, FALSE);
138 		if(doc->fmt_idx == -1)
139 			goto failed;		/* unknown file type */
140 	}
141 
142 	file = fu_open(filename, TRUE);
143 	if(file == NULL)
144 		goto failed;
145 
146 	/* check to see if file already exists */
147 	if(fu_file_size(file) > 0) {
148 		if(name_changed && !overwrite) {
149 			*file_exists = TRUE;
150 			goto failed;
151 		}
152 
153 		/* overwrite==TRUE means truncate and save to file */
154 		fu_truncate(file, 0);
155 	}
156 
157 	/* We need to set the model's filename before we try to call the
158 	   model's save function.  This is because some format-saving-functions
159 	   may make use of external libraries, and those libraries may expect a
160 	   filename rather than a file pointer when saving. */
161 	if( name_changed ) {
162 		char *basename = g_path_get_basename(filename);
163 		model_set_name( doc, basename );
164 		g_free( basename );
165 
166 		model_set_filename( doc, (char*)filename );
167 	}
168 
169 	ret = (*(fmt_list[doc->fmt_idx]->save_file))(file, doc);
170 
171 	fu_close(file);
172 	file = NULL;
173 
174 	if(ret) {
175 //		doc->unsaved_changes = FALSE;
176 //		doc_set_name(doc, bn);
177 	}
178 
179 	/* if the save failed, AND we changed the name before we tried to save,
180 	 then we should set the name back to what it was before */
181 	if(!ret && name_changed) {
182 		/* replace the name with the old one */
183 		char *basename = g_path_get_basename(old_fname);
184 		model_set_name( doc, basename );
185 		g_free( basename );
186 
187 		model_set_filename( doc, old_fname );
188 
189 		doc->fmt_idx = old_fmt_idx;
190 	}
191 
192 	if( old_fname != NULL )
193 		free( old_fname );
194 
195 	return ret;
196 
197 failed:
198 	if( file != NULL )
199 		fu_close( file );
200 	if( old_fname != NULL )
201 		free( old_fname );
202 	return FALSE;
203 }
204 
205 
model_ls_clean_miscdata(Model * doc)206 void model_ls_clean_miscdata(Model *doc)
207 {
208 	if( (doc->fmt_idx > -1) &&
209 		(fmt_list[doc->fmt_idx]->destroy_priv_data != NULL) )
210 	{
211 		(*(fmt_list[doc->fmt_idx]->destroy_priv_data))(doc);
212 	}
213 	doc->fmt_idx = -1;
214 }
215 
216 
model_ls_examine_extension(const gchar * filename,gint load)217 gint model_ls_examine_extension(const gchar *filename, gint load)
218 {
219   gint i, j, l, m;
220 
221   m = strlen(filename);
222   for(i = 0; (fmt_list[i] != NULL); i++)
223   {
224     if(load && (fmt_list[i]->load_file == NULL))
225        continue;
226     if(!load && (fmt_list[i]->save_file == NULL))
227        continue;
228 
229     l = strlen(fmt_list[i]->extension);
230     if(l >= m)
231       continue;
232 
233     for(j = 0; j < l; j++)
234     {
235       if(fmt_list[i]->extension[l - j] != filename[m - j])
236 	break;
237     }
238 
239     if((j == l) && (filename[m-l - 1] == '.'))
240       return i;
241   }
242   return -1;
243 }
244 
245