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