1 /*
2  * saveas.c
3  * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
4  *
5  * Description:
6  * Functions to save the results as a textfile or a drawfile
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include "DeskLib:Menu.h"
12 #include "DeskLib:Save.h"
13 #include "DeskLib:Template.h"
14 #include "DeskLib:Window.h"
15 #include "drawfile.h"
16 #include "antiword.h"
17 
18 /* The window handle of the save window */
19 static window_handle	tSaveWindow = 0;
20 
21 /* Xfer_send box fields */
22 #define DRAG_SPRITE	3
23 #define OK_BUTTON	0
24 #define CANCEL_BUTTON	(-1)
25 #define FILENAME_ICON	2
26 
27 
28 /*
29  * saveas - a wrapper around Save_InitSaveWindowhandler
30  */
31 static void
saveas(int iFileType,char * szOutfile,size_t tEstSize,save_filesaver save_function,void * pvReference)32 saveas(int iFileType, char *szOutfile, size_t tEstSize,
33 	save_filesaver save_function, void *pvReference)
34 {
35 	TRACE_MSG("saveas");
36 
37 	if (tSaveWindow == 0) {
38 		tSaveWindow = Window_Create("xfer_send", template_TITLEMIN);
39 	}
40 	Icon_SetText(tSaveWindow, FILENAME_ICON, szOutfile);
41 	Window_Show(tSaveWindow, open_UNDERPOINTER);
42 	(void)Save_InitSaveWindowHandler(tSaveWindow, FALSE, TRUE, TRUE,
43 		DRAG_SPRITE, OK_BUTTON, CANCEL_BUTTON, FILENAME_ICON,
44 		save_function, NULL, NULL, tEstSize, iFileType, pvReference);
45 } /* end of saveas */
46 
47 static BOOL
bWrite2File(void * pvBytes,size_t tSize,FILE * pFile,const char * szFilename)48 bWrite2File(void *pvBytes, size_t tSize, FILE *pFile, const char *szFilename)
49 {
50 	if (fwrite(pvBytes, sizeof(char), tSize, pFile) != tSize) {
51 		werr(0, "I can't write to '%s'", szFilename);
52 		return FALSE;
53 	}
54 	return TRUE;
55 } /* end of bWrite2File */
56 
57 /*
58  * bText2File - Save the generated draw file to a Text file
59  */
60 static BOOL
bText2File(char * szFilename,void * pvHandle)61 bText2File(char *szFilename, void *pvHandle)
62 {
63 	FILE	*pFile;
64 	diagram_type	*pDiag;
65 	drawfile_object	*pObj;
66 	drawfile_text	*pText;
67 	const char	*pcTmp;
68 	int	iToGo, iX, iYtopPrev, iHeight, iLines;
69 	BOOL	bFirst, bIndent, bSuccess;
70 
71 	TRACE_MSG("bText2File");
72 
73 	fail(szFilename == NULL || szFilename[0] == '\0');
74 	fail(pvHandle == NULL);
75 
76 	DBG_MSG(szFilename);
77 
78 	pDiag = (diagram_type *)pvHandle;
79 	pFile = fopen(szFilename, "w");
80 	if (pFile == NULL) {
81 		werr(0, "I can't open '%s' for writing", szFilename);
82 		return FALSE;
83 	}
84 	bFirst = TRUE;
85 	iYtopPrev = 0;
86 	iHeight = (int)lWord2DrawUnits20(DEFAULT_FONT_SIZE);
87 	bSuccess = TRUE;
88 	fail(pDiag->tInfo.length < offsetof(drawfile_diagram, objects));
89 	iToGo = pDiag->tInfo.length - offsetof(drawfile_diagram, objects);
90 	DBG_DEC(iToGo);
91 	pcTmp = (const char *)pDiag->tInfo.data +
92 				offsetof(drawfile_diagram, objects);
93 	while (iToGo > 0 && bSuccess) {
94 		pObj = (drawfile_object *)pcTmp;
95 		switch (pObj->type) {
96 		case drawfile_TYPE_TEXT:
97 			pText = &pObj->data.text;
98 			/* Compute the number of lines */
99 			iLines = (iYtopPrev - pText->bbox.max.y +
100 					iHeight / 2) / iHeight;
101 			DBG_DEC_C(iLines < 0, iYtopPrev);
102 			DBG_DEC_C(iLines < 0, pText->bbox.max.y);
103 			fail(iLines < 0);
104 			bIndent = iLines > 0 || bFirst;
105 			bFirst = FALSE;
106 			/* Print the newlines */
107 			while (iLines > 0 && bSuccess) {
108 				bSuccess = bWrite2File("\n",
109 					1, pFile, szFilename);
110 				iLines--;
111 			}
112 			/* Print the indentation */
113 			if (bIndent && bSuccess) {
114 				for (iX = Drawfile_ScreenToDraw(8);
115 				     iX <= pText->bbox.min.x && bSuccess;
116 				     iX += Drawfile_ScreenToDraw(16)) {
117 					bSuccess = bWrite2File(" ",
118 						1, pFile, szFilename);
119 				}
120 			}
121 			if (!bSuccess) {
122 				break;
123 			}
124 			/* Print the text object */
125 			bSuccess = bWrite2File(pText->text,
126 				strlen(pText->text), pFile, szFilename);
127 			/* Setup for the next object */
128 			iYtopPrev = pText->bbox.max.y;
129 			iHeight = pText->bbox.max.y - pText->bbox.min.y;
130 			break;
131 		case drawfile_TYPE_FONT_TABLE:
132 		case drawfile_TYPE_PATH:
133 		case drawfile_TYPE_SPRITE:
134 		case drawfile_TYPE_JPEG:
135 			/* These are not relevant in a textfile */
136 			break;
137 		default:
138 			DBG_DEC(pObj->type);
139 			bSuccess = FALSE;
140 			break;
141 		}
142 		pcTmp += pObj->size;
143 		iToGo -= pObj->size;
144 	}
145 	DBG_DEC_C(iToGo != 0, iToGo);
146 	if (bSuccess) {
147 		bSuccess = bWrite2File("\n", 1, pFile, szFilename);
148 	}
149 	(void)fclose(pFile);
150 	if (bSuccess) {
151 		vSetFiletype(szFilename, FILETYPE_TEXT);
152 	} else {
153 		(void)remove(szFilename);
154 		werr(0, "Unable to save textfile '%s'", szFilename);
155 	}
156 	return bSuccess;
157 } /* end of bText2File */
158 
159 /*
160  * bSaveTextfile - save the diagram as a text file
161  */
162 BOOL
bSaveTextfile(event_pollblock * pEvent,void * pvReference)163 bSaveTextfile(event_pollblock *pEvent, void *pvReference)
164 {
165 	diagram_type	*pDiag;
166 	size_t	tRecLen, tNbrRecs, tEstSize;
167 
168 	TRACE_MSG("bSaveTextfile");
169 
170 	fail(pEvent == NULL);
171 	fail(pvReference == NULL);
172 
173 	pDiag = (diagram_type *)pvReference;
174 
175 	switch (pEvent->type) {
176 	case event_SEND:	/* From a menu */
177 		fail(pEvent->data.message.header.action != message_MENUWARN);
178 		if (menu_currentopen != pDiag->pSaveMenu ||
179 		    pEvent->data.message.data.menuwarn.selection[0] !=
180 							SAVEMENU_SAVETEXT) {
181 			return FALSE;
182 		}
183 		break;
184 	case event_KEY:		/* From a key short cut */
185 		if (pEvent->data.key.caret.window != pDiag->tMainWindow) {
186 			return FALSE;
187 		}
188 		break;
189 	default:
190 		DBG_DEC(pEvent->type);
191 		return FALSE;
192 	}
193 
194 	tRecLen = sizeof(drawfile_text) + DEFAULT_SCREEN_WIDTH * 2 / 3;
195 	tNbrRecs = pDiag->tInfo.length / tRecLen + 1;
196 	tEstSize = tNbrRecs * DEFAULT_SCREEN_WIDTH * 2 / 3;
197 	DBG_DEC(tEstSize);
198 
199 	saveas(FILETYPE_TEXT, "WordText", tEstSize, bText2File, pDiag);
200 	return TRUE;
201 } /* end of bSaveTextfile */
202 
203 /*
204  * bDraw2File - Save the generated draw file to a Draw file
205  *
206  * Remark: This is not a simple copy action. The origin of the
207  * coordinates (0,0) must move from the top-left corner to the
208  * bottom-left corner.
209  */
210 static BOOL
bDraw2File(char * szFilename,void * pvHandle)211 bDraw2File(char *szFilename, void *pvHandle)
212 {
213 	FILE		*pFile;
214 	diagram_type	*pDiagram;
215 	wimp_box	*pBbox;
216 	drawfile_object	*pObj;
217 	drawfile_text	*pText;
218 	drawfile_path	*pPath;
219 	drawfile_sprite	*pSprite;
220 	drawfile_jpeg	*pJpeg;
221 	int	*piPath;
222 	char	*pcTmp;
223 	int	iYadd, iToGo, iSize;
224 	BOOL	bSuccess;
225 
226 	TRACE_MSG("bDraw2File");
227 
228 	fail(szFilename == NULL || szFilename[0] == '\0');
229 	fail(pvHandle == NULL);
230 
231 	NO_DBG_MSG(szFilename);
232 
233 	pDiagram = (diagram_type *)pvHandle;
234 	pFile = fopen(szFilename, "wb");
235 	if (pFile == NULL) {
236 		werr(0, "I can't open '%s' for writing", szFilename);
237 		return FALSE;
238 	}
239 	iToGo = pDiagram->tInfo.length;
240 	DBG_DEC(iToGo);
241 	pcTmp = pDiagram->tInfo.data;
242 	bSuccess = bWrite2File(pcTmp,
243 			offsetof(drawfile_diagram, bbox), pFile, szFilename);
244 	if (bSuccess) {
245 	  	pcTmp += offsetof(drawfile_diagram, bbox);
246 		iToGo -= offsetof(drawfile_diagram, bbox);
247 		pBbox = (wimp_box *)pcTmp;
248 		iYadd = -pBbox->min.y;
249 		pBbox->min.y += iYadd;
250 		pBbox->max.y += iYadd;
251 		bSuccess = bWrite2File(pcTmp,
252 				sizeof(*pBbox), pFile, szFilename);
253 		iToGo -= sizeof(*pBbox);
254 		DBG_DEC(iToGo);
255 		pcTmp += sizeof(*pBbox);
256 	} else {
257 		iYadd = 0;
258 	}
259 	while (iToGo > 0 && bSuccess) {
260 		pObj = (drawfile_object *)pcTmp;
261 		iSize = pObj->size;
262 		switch (pObj->type) {
263 		case drawfile_TYPE_FONT_TABLE:
264 			bSuccess = bWrite2File(pcTmp,
265 					iSize, pFile, szFilename);
266 			pcTmp += iSize;
267 			iToGo -= iSize;
268 			break;
269 		case drawfile_TYPE_TEXT:
270 			pText = &pObj->data.text;
271 			/* First correct the coordinates */
272 			pText->bbox.min.y += iYadd;
273 			pText->bbox.max.y += iYadd;
274 			pText->base.y += iYadd;
275 			/* Now write the information to file */
276 			bSuccess = bWrite2File(pcTmp,
277 					iSize, pFile, szFilename);
278 			pcTmp += pObj->size;
279 			iToGo -= pObj->size;
280 			break;
281 		case drawfile_TYPE_PATH:
282 			pPath = &pObj->data.path;
283 			/* First correct the coordinates */
284 			pPath->bbox.min.y += iYadd;
285 			pPath->bbox.max.y += iYadd;
286 			/* Now write the information to file */
287 			bSuccess = bWrite2File(pPath,
288 				sizeof(*pPath), pFile, szFilename);
289 			pcTmp += sizeof(*pPath);
290 			iSize = pObj->size - sizeof(*pPath);
291 			fail(iSize < 14 * sizeof(int));
292 			/* Second correct the path coordinates */
293 			piPath = xmalloc(iSize);
294 			memcpy(piPath, pcTmp, iSize);
295 			piPath[ 2] += iYadd;
296 			piPath[ 5] += iYadd;
297 			piPath[ 8] += iYadd;
298 			piPath[11] += iYadd;
299 			if (bSuccess) {
300 				bSuccess = bWrite2File(piPath,
301 					iSize, pFile, szFilename);
302 				pcTmp += iSize;
303 			}
304 			piPath = xfree(piPath);
305 			iToGo -= pObj->size;
306 			break;
307 		case drawfile_TYPE_SPRITE:
308 			pSprite = &pObj->data.sprite;
309 			/* First correct the coordinates */
310 			pSprite->bbox.min.y += iYadd;
311 			pSprite->bbox.max.y += iYadd;
312 			/* Now write the information to file */
313 			bSuccess = bWrite2File(pcTmp,
314 					iSize, pFile, szFilename);
315 			pcTmp += pObj->size;
316 			iToGo -= pObj->size;
317 			break;
318 		case drawfile_TYPE_JPEG:
319 			pJpeg = &pObj->data.jpeg;
320 			/* First correct the coordinates */
321 			pJpeg->bbox.min.y += iYadd;
322 			pJpeg->bbox.max.y += iYadd;
323 			pJpeg->trfm.entries[2][1] += iYadd;
324 			/* Now write the information to file */
325 			bSuccess = bWrite2File(pcTmp,
326 					iSize, pFile, szFilename);
327 			pcTmp += pObj->size;
328 			iToGo -= pObj->size;
329 			break;
330 		default:
331 			DBG_DEC(pObj->type);
332 			bSuccess = FALSE;
333 			break;
334 		}
335 	}
336 	DBG_DEC_C(iToGo != 0, iToGo);
337 	(void)fclose(pFile);
338 	if (bSuccess) {
339 		vSetFiletype(szFilename, FILETYPE_DRAW);
340 	} else {
341 		(void)remove(szFilename);
342 		werr(0, "Unable to save drawfile '%s'", szFilename);
343 	}
344 	return bSuccess;
345 } /* end of bDraw2File */
346 
347 /*
348  * bSaveDrawfile - save the diagram as a draw file
349  */
350 BOOL
bSaveDrawfile(event_pollblock * pEvent,void * pvReference)351 bSaveDrawfile(event_pollblock *pEvent, void *pvReference)
352 {
353 	diagram_type	*pDiag;
354 	size_t		tEstSize;
355 
356 	TRACE_MSG("bSaveDrawfile");
357 
358 	fail(pEvent == NULL);
359 	fail(pvReference == NULL);
360 
361 	pDiag = (diagram_type *)pvReference;
362 
363 	switch (pEvent->type) {
364 	case event_SEND:	/* From a menu */
365 		fail(pEvent->data.message.header.action != message_MENUWARN);
366 		if (menu_currentopen != pDiag->pSaveMenu ||
367 		    pEvent->data.message.data.menuwarn.selection[0] !=
368 							SAVEMENU_SAVEDRAW) {
369 			return FALSE;
370 		}
371 		break;
372 	case event_KEY:		/* From a key short cut */
373 		if (pEvent->data.key.caret.window != pDiag->tMainWindow) {
374 			return FALSE;
375 		}
376 		break;
377 	default:
378 		DBG_DEC(pEvent->type);
379 		return FALSE;
380 	}
381 
382 	tEstSize = pDiag->tInfo.length;
383 	DBG_DEC(tEstSize);
384 
385 	saveas(FILETYPE_DRAW, "WordDraw", tEstSize, bDraw2File, pDiag);
386 	return TRUE;
387 } /* end of bSaveDrawfile */
388