1 /* wvWare
2  * Copyright (C) Caolan McNamara, Dom Lachowicz, and others
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include "wv.h"
29 
30 
31 void
wvReleaseEscher(escherstruct * item)32 wvReleaseEscher (escherstruct * item)
33 {
34     wvReleaseDggContainer (&item->dggcontainer);
35     wvReleaseDgContainer (&item->dgcontainer);
36 }
37 
38 void
wvInitEscher(escherstruct * item)39 wvInitEscher (escherstruct * item)
40 {
41     wvInitDggContainer (&item->dggcontainer);
42     wvInitDgContainer (&item->dgcontainer);
43 }
44 
45 void
wvGetEscher(escherstruct * item,U32 offset,U32 len,wvStream * fd,wvStream * delay)46 wvGetEscher (escherstruct * item, U32 offset, U32 len, wvStream * fd,
47 	     wvStream * delay)
48 {
49     U32 count = 0;
50     MSOFBH amsofbh;
51 
52     wvStream_goto (fd, offset);
53     wvTrace (("offset %x, len %d\n", offset, len));
54     wvInitEscher (item);
55     while (count < len)
56       {
57 	  count += wvGetMSOFBH (&amsofbh, fd);
58 	  wvTrace (
59 		   ("count is %x,len is %x, next len is %x\n", count, len,
60 		    amsofbh.cbLength));
61 	  wvTrace (("type is %x\n	", amsofbh.fbt));
62 	  switch (amsofbh.fbt)
63 	    {
64 	    case msofbtDggContainer:
65 		count +=
66 		    wvGetDggContainer (&item->dggcontainer, &amsofbh, fd,
67 				       delay);
68 		break;
69 	    case msofbtDgContainer:
70 		count += wvGetDgContainer (&item->dgcontainer, &amsofbh, fd);
71 		break;
72 	    default:
73 		wvError (("Not a container, panic (%x)\n", amsofbh.fbt));
74 		return;
75 		break;
76 	    }
77       }
78     wvTrace (("offset %x, len %d (pos %x)\n", offset, len, wvStream_tell (fd)));
79 }
80 
81 void
wvReleaseDggContainer(DggContainer * item)82 wvReleaseDggContainer (DggContainer * item)
83 {
84     wvReleaseSplitMenuColors (&item->splitmenucolors);
85     wvReleaseDgg (&item->dgg);
86     wvReleaseBstoreContainer (&item->bstorecontainer);
87 }
88 
89 void
wvInitDggContainer(DggContainer * item)90 wvInitDggContainer (DggContainer * item)
91 {
92     wvInitSplitMenuColors (&item->splitmenucolors);
93     wvInitDgg (&item->dgg);
94     wvInitBstoreContainer (&item->bstorecontainer);
95 }
96 
97 U32
wvGetDggContainer(DggContainer * item,MSOFBH * msofbh,wvStream * fd,wvStream * delay)98 wvGetDggContainer (DggContainer * item, MSOFBH * msofbh, wvStream * fd,
99 		   wvStream * delay)
100 {
101     MSOFBH amsofbh;
102     U32 count = 0;
103 
104     while (count < msofbh->cbLength)
105       {
106 	  count += wvGetMSOFBH (&amsofbh, fd);
107 	  wvTrace (
108 		   ("len is %x, type is %x, count %x,fullen %x\n",
109 		    amsofbh.cbLength, amsofbh.fbt, count, msofbh->cbLength));
110 	  wvTrace (("type is %x\n	", amsofbh.fbt));
111 	  switch (amsofbh.fbt)
112 	    {
113 	    case msofbtDgg:
114 		count += wvGetDgg (&item->dgg, &amsofbh, fd);
115 		break;
116 	    case msofbtSplitMenuColors:
117 		count +=
118 		    wvGetSplitMenuColors (&item->splitmenucolors, &amsofbh, fd);
119 		break;
120 	    case msofbtBstoreContainer:
121 		count +=
122 		    wvGetBstoreContainer (&item->bstorecontainer, &amsofbh,
123 					  fd, delay);
124 		wvTrace (
125 			 ("type is %d (number is %d\n",
126 			  item->bstorecontainer.blip[item->bstorecontainer.
127 						     no_fbse - 1].type,
128 			  item->bstorecontainer.no_fbse));
129 		break;
130 	    default:
131 		count += wvEatmsofbt (&amsofbh, fd);
132 		wvError (("Eating type 0x%x\n", amsofbh.fbt));
133 		break;
134 	    }
135       }
136     /*
137        For some reason I appear to have an extra byte associated either with
138        this or its wrapper, I will investigate further.
139      */
140     read_8ubit (fd);
141     count++;
142 
143     return (count);
144 }
145 
146 void
wvReleaseDgContainer(DgContainer * item)147 wvReleaseDgContainer (DgContainer * item)
148 {
149     U32 i;
150     for (i = 0; i < item->no_spgrcontainer; i++)
151 	wvReleaseSpgrContainer (&(item->spgrcontainer[i]));
152     wvFree (item->spgrcontainer);
153 
154     for (i = 0; i < item->no_spcontainer; i++)
155 	wvReleaseFSPContainer (&(item->spcontainer[i]));
156     wvFree (item->spcontainer);
157 }
158 
159 void
wvInitDgContainer(DgContainer * item)160 wvInitDgContainer (DgContainer * item)
161 {
162     item->no_spgrcontainer = 0;
163     item->spgrcontainer = NULL;
164 }
165 
166 void
wvReleaseBstoreContainer(BstoreContainer * item)167 wvReleaseBstoreContainer (BstoreContainer * item)
168 {
169     U32 i;
170     for (i = 0; i < item->no_fbse; i++)
171 	wvReleaseBlip (&item->blip[i]);
172     wvFree (item->blip);
173 }
174 
175 void
wvInitBstoreContainer(BstoreContainer * item)176 wvInitBstoreContainer (BstoreContainer * item)
177 {
178     item->no_fbse = 0;
179     item->blip = NULL;
180 }
181 
182 U32
wvGetBstoreContainer(BstoreContainer * item,MSOFBH * msofbh,wvStream * fd,wvStream * delay)183 wvGetBstoreContainer (BstoreContainer * item, MSOFBH * msofbh, wvStream * fd,
184 		      wvStream * delay)
185 {
186     MSOFBH amsofbh;
187     U32 count = 0;
188     while (count < msofbh->cbLength)
189       {
190 	  count += wvGetMSOFBH (&amsofbh, fd);
191 	  wvTrace (("type is %x\n	", amsofbh.fbt));
192 	  switch (amsofbh.fbt)
193 	    {
194 	    case msofbtBSE:
195 		wvTrace (("Blip at %x\n", wvStream_tell (fd)));
196 		item->no_fbse++;
197 		item->blip =
198 		    (Blip *) realloc (item->blip,
199 				      sizeof (Blip) * item->no_fbse);
200 		count +=
201 		    wvGetBlip ((&item->blip[item->no_fbse - 1]), fd, delay);
202 		wvTrace (
203 			 ("type is %d (number is %d\n",
204 			  item->blip[item->no_fbse - 1].type, item->no_fbse));
205 		break;
206 	    default:
207 		count += wvEatmsofbt (&amsofbh, fd);
208 		wvError (("Eating type 0x%x\n", amsofbh.fbt));
209 		break;
210 	    }
211       }
212     return (count);
213 }
214 
215 U32
wvGetDgContainer(DgContainer * item,MSOFBH * msofbh,wvStream * fd)216 wvGetDgContainer (DgContainer * item, MSOFBH * msofbh, wvStream * fd)
217 {
218     MSOFBH amsofbh;
219     U32 count = 0;
220 
221     item->spcontainer = NULL;
222     item->no_spcontainer = 0;
223 
224     while (count < msofbh->cbLength)
225       {
226 	  count += wvGetMSOFBH (&amsofbh, fd);
227 	  wvTrace (
228 		   ("len is %x, type is %x, count %x,fullen %x\n",
229 		    amsofbh.cbLength, amsofbh.fbt, count, msofbh->cbLength));
230 	  wvTrace (("type is %x\n	", amsofbh.fbt));
231 	  switch (amsofbh.fbt)
232 	    {
233 	    case msofbtDg:
234 		count += wvGetFDG (&item->fdg, fd);
235 		break;
236 	    case msofbtSpgrContainer:
237 		item->no_spgrcontainer++;
238 		item->spgrcontainer =
239 		    (SpgrContainer *) realloc (item->spgrcontainer,
240 					       sizeof (SpgrContainer) *
241 					       item->no_spgrcontainer);
242 		count +=
243 		    wvGetSpgrContainer (&
244 					(item->spgrcontainer
245 					 [item->no_spgrcontainer - 1]), &amsofbh, fd);
246 		break;
247 		case msofbtSpContainer:
248 	      	item->no_spcontainer++;
249 		item->spcontainer =
250 		    (FSPContainer *) realloc (item->spcontainer,
251 					       sizeof (FSPContainer) *
252 					       item->no_spcontainer);
253 		count +=
254 		    wvGetFSPContainer (&
255 	        			(item->spcontainer
256 					 [item->no_spcontainer - 1]), &amsofbh, fd);
257 		break;
258 	    default:
259 		count += wvEatmsofbt (&amsofbh, fd);
260 		wvError (("Eating type 0x%x\n", amsofbh.fbt));
261 		break;
262 	    }
263       }
264     return (count);
265 }
266 
267 FSPContainer *
wvFindSPID(SpgrContainer * item,S32 spid)268 wvFindSPID (SpgrContainer * item, S32 spid)
269 {
270     U32 i;
271     FSPContainer *t;
272     for (i = 0; i < item->no_spcontainer; i++)
273       {
274 	  /* FIXME: Cast below is to avoid compiler warnings, but having
275 	     to have it could be a sign of something wrong. */
276 	  if (item->spcontainer[i].fsp.spid == (U32) spid)
277 	    {
278 		wvTrace (("FOUND IT\n"));
279 		return (&(item->spcontainer[i]));
280 	    }
281       }
282     for (i = 0; i < item->no_spgrcontainer; i++)
283       {
284 	  t = wvFindSPID (&(item->spgrcontainer[i]), spid);
285 	  if (t)
286 	      return (t);
287       }
288     return (NULL);
289 }
290 
291 
292 void
wvReleaseSpgrContainer(SpgrContainer * item)293 wvReleaseSpgrContainer (SpgrContainer * item)
294 {
295     U32 i;
296     for (i = 0; i < item->no_spcontainer; i++)
297 	wvReleaseFSPContainer (&(item->spcontainer[i]));
298     wvFree (item->spcontainer);
299     for (i = 0; i < item->no_spgrcontainer; i++)
300 	wvReleaseSpgrContainer (&(item->spgrcontainer[i]));
301     wvFree (item->spgrcontainer);
302 }
303 
304 
305 U32
wvGetSpgrContainer(SpgrContainer * item,MSOFBH * msofbh,wvStream * fd)306 wvGetSpgrContainer (SpgrContainer * item, MSOFBH * msofbh, wvStream * fd)
307 {
308     MSOFBH amsofbh;
309     U32 count = 0;
310 
311     item->spgrcontainer = NULL;
312     item->no_spgrcontainer = 0;
313     item->spcontainer = NULL;
314     item->no_spcontainer = 0;
315 
316     while (count < msofbh->cbLength)
317       {
318 	  count += wvGetMSOFBH (&amsofbh, fd);
319 	  wvTrace (
320 		   ("len is %x, type is %x, count %x,fullen %x\n",
321 		    amsofbh.cbLength, amsofbh.fbt, count, msofbh->cbLength));
322 	  wvTrace (("type is %x\n	", amsofbh.fbt));
323 	  switch (amsofbh.fbt)
324 	    {
325 	    case msofbtSpContainer:
326 		item->no_spcontainer++;
327 		item->spcontainer =
328 		    realloc (item->spcontainer,
329 			     sizeof (FSPContainer) * item->no_spcontainer);
330 		count +=
331 		    wvGetFSPContainer (&
332 				       (item->spcontainer[item->no_spcontainer -
333 							  1]), &amsofbh, fd);
334 		break;
335 	    case msofbtSpgrContainer:
336 		item->no_spgrcontainer++;
337 		item->spgrcontainer =
338 		    realloc (item->spgrcontainer,
339 			     sizeof (SpgrContainer) * item->no_spgrcontainer);
340 		count +=
341 		    wvGetSpgrContainer (&
342 					(item->spgrcontainer
343 					 [item->no_spgrcontainer - 1]), &amsofbh, fd);
344 		break;
345 	    default:
346 		count += wvEatmsofbt (&amsofbh, fd);
347 		wvError (("Eating type 0x%x\n", amsofbh.fbt));
348 		break;
349 	    }
350       }
351     return (count);
352 }
353 
354 
355 U32
wvGetFDG(FDG * afdg,wvStream * fd)356 wvGetFDG (FDG * afdg, wvStream * fd)
357 {
358     afdg->csp = read_32ubit (fd);
359     afdg->spidCur = read_32ubit (fd);
360     wvTrace (
361 	     ("there are %d shapes here, the last is %x\n", afdg->csp,
362 	      afdg->spidCur));
363     return (8);
364 }
365 
366 
367 void
wvInitSplitMenuColors(SplitMenuColors * splitmenucolors)368 wvInitSplitMenuColors (SplitMenuColors * splitmenucolors)
369 {
370     splitmenucolors->noofcolors = 0;
371     splitmenucolors->colors = NULL;
372 }
373 
374 void
wvReleaseSplitMenuColors(SplitMenuColors * splitmenucolors)375 wvReleaseSplitMenuColors (SplitMenuColors * splitmenucolors)
376 {
377     wvFree (splitmenucolors->colors);
378 }
379 
380 U32
wvGetSplitMenuColors(SplitMenuColors * splitmenucolors,MSOFBH * amsofbh,wvStream * fd)381 wvGetSplitMenuColors (SplitMenuColors * splitmenucolors, MSOFBH * amsofbh,
382 		      wvStream * fd)
383 {
384     U32 i = 0;
385     splitmenucolors->noofcolors = amsofbh->cbLength / 4;
386     if (splitmenucolors->noofcolors)
387       {
388 	  splitmenucolors->colors =
389 	      (U32 *) wvMalloc (sizeof (U32) * splitmenucolors->noofcolors);
390 	  for (i = 0; i < splitmenucolors->noofcolors; i++)
391 	      splitmenucolors->colors[i] = read_32ubit (fd);
392       }
393     return (i * 4);
394 }
395 
396 void
wvReleaseDgg(Dgg * dgg)397 wvReleaseDgg (Dgg * dgg)
398 {
399     wvFree (dgg->fidcl);
400 }
401 
402 void
wvInitDgg(Dgg * dgg)403 wvInitDgg (Dgg * dgg)
404 {
405     dgg->fidcl = NULL;
406 }
407 
408 U32
wvGetDgg(Dgg * dgg,MSOFBH * amsofbh,wvStream * fd)409 wvGetDgg (Dgg * dgg, MSOFBH * amsofbh, wvStream * fd)
410 {
411     U32 count = 0;
412     U32 no;
413     U32 i;
414     count += wvGetFDGG (&dgg->fdgg, fd);
415     if (dgg->fdgg.cidcl != 0)
416       {
417 	  wvTrace (("There are %d bytes left\n", amsofbh->cbLength - count));
418 	  no = (amsofbh->cbLength - count) / 8;
419 	  if (no != dgg->fdgg.cidcl)
420 	    {
421 		wvWarning
422 		    ("Must be %d, not %d as specs, test algor gives %d\n", no,
423 		     dgg->fdgg.cidcl, dgg->fdgg.cspSaved - dgg->fdgg.cidcl);
424 	    }
425 	  if (no)
426 	    {
427 		dgg->fidcl = (FIDCL *) wvMalloc (sizeof (FIDCL) * no);
428 		for (i = 0; i < no; i++)
429 		    count += wvGetFIDCL (&(dgg->fidcl[i]), fd);
430 	    }
431       }
432     return (count);
433 }
434 
435 U32
wvGetFIDCL(FIDCL * afidcl,wvStream * fd)436 wvGetFIDCL (FIDCL * afidcl, wvStream * fd)
437 {
438     afidcl->dgid = read_32ubit (fd);
439     afidcl->cspidCur = read_32ubit (fd);
440     wvTrace (("dgid %d cspidCur %d\n", afidcl->dgid, afidcl->cspidCur));
441     return (8);
442 }
443 
444 
445 U32
wvGetFDGG(FDGG * afdgg,wvStream * fd)446 wvGetFDGG (FDGG * afdgg, wvStream * fd)
447 {
448     afdgg->spidMax = read_32ubit (fd);
449     afdgg->cidcl = read_32ubit (fd);
450     afdgg->cspSaved = read_32ubit (fd);
451     afdgg->cdgSaved = read_32ubit (fd);
452     wvTrace (
453 	     ("spidMax %d cidcl %d cspSaved %d cdgSaved %d\n", afdgg->spidMax,
454 	      afdgg->cidcl, afdgg->cspSaved, afdgg->cdgSaved));
455     return (16);
456 }
457 
458 
459 int
wv0x08(Blip * blip,S32 spid,wvParseStruct * ps)460 wv0x08 (Blip * blip, S32 spid, wvParseStruct * ps)
461 {
462     int ret = 0;
463     U32 i;
464     escherstruct item;
465     FSPContainer *answer = NULL;
466     wvTrace (("spid is %x\n", spid));
467     wvGetEscher (&item, ps->fib.fcDggInfo, ps->fib.lcbDggInfo, ps->tablefd,
468 		 ps->mainfd);
469 
470     for (i = 0; i < item.dgcontainer.no_spgrcontainer; i++)
471       {
472 	  answer = wvFindSPID (&(item.dgcontainer.spgrcontainer[i]), spid);
473 	  if (answer)
474 	      break;
475       }
476 
477     i = 0;
478     if (answer == NULL)
479 	wvError (("Damn found nothing\n"));
480     else if (answer->fopte)
481       {
482 	  while (answer->fopte[i].pid != 0)
483 	    {
484 		if (answer->fopte[i].pid == 260)
485 		  {
486 		      wvTrace (
487 			       ("has a blip reference of %d\n",
488 				answer->fopte[i].op));
489 		      wvTrace (
490 			       ("no blips is %d\n",
491 				item.dggcontainer.bstorecontainer.no_fbse));
492 		      wvTrace (
493 			       ("type is %d (number is %d\n",
494 				item.dggcontainer.bstorecontainer.blip[item.
495 								       dggcontainer.
496 								       bstorecontainer.
497 								       no_fbse -
498 								       1].type,
499 				item.dggcontainer.bstorecontainer.no_fbse));
500 		      if (answer->fopte[i].op <=
501 			  item.dggcontainer.bstorecontainer.no_fbse)
502 			{
503 			    wvTrace (("Copied Blip\n"));
504 			    wvCopyBlip (blip,
505 					&(item.dggcontainer.bstorecontainer.
506 					  blip[answer->fopte[i].op - 1]));
507 			    wvTrace (("type is %d\n", blip->type));
508 			    ret = 1;
509 			    break;
510 			}
511 		  }
512 		i++;
513 	    }
514       }
515     wvTrace (("spid is %x\n", spid));
516     wvReleaseEscher (&item);
517     return (ret);
518 }
519 
520 int
wv0x01(Blip * blip,wvStream * fd,U32 len)521 wv0x01 (Blip * blip, wvStream * fd, U32 len)
522 {
523     MSOFBH amsofbh;
524     FSPContainer item;
525     U32 count = 0;
526 /*    char test[3];*/
527     int ret = 0;
528 
529 
530     if (fd == NULL)
531 	return (0);
532 
533   /*lvm007@aha.ru fix hack as outdated look picf*/
534     /*
535        temp hack to test older included bmps in word 6 and 7,
536        should be wrapped in a modern escher strucure before getting
537        to here, and then handled as normal
538      */
539     /*test[2] = '\0';
540     test[0] = read_8ubit (fd);
541     test[1] = read_8ubit (fd);
542     wvStream_rewind (fd);
543     if (!(strcmp (test, "BM")))
544       {
545 	  blip->blip.bitmap.m_pvBits = fd;
546 	  blip->type = msoblipDIB;
547 	  return (1);
548       }
549 	*/
550     while (count < len)
551       {
552 	  wvTrace (("count is %x,len is %x\n", count, len));
553 	  count += wvGetMSOFBH (&amsofbh, fd);
554 	  wvTrace (("type is %x\n	", amsofbh.fbt));
555 	  switch (amsofbh.fbt)
556 	    {
557 	    case msofbtSpContainer:
558 		wvTrace (("Container at %x\n", wvStream_tell (fd)));
559 		count += wvGetFSPContainer (&item, &amsofbh, fd);
560 		wvReleaseFSPContainer (&item);
561 		break;
562 	    case msofbtBSE:
563 		wvTrace (("Blip at %x\n", wvStream_tell (fd)));
564 		count += wvGetBlip (blip, fd, NULL);
565 		ret = 1;
566 		break;
567 	    default:
568 		wvError (("Not a shape container\n"));
569 		return (0);
570 		break;
571 	    }
572       }
573     return (ret);
574 }
575 
576 U32
wvGetFSP(FSP * fsp,wvStream * fd)577 wvGetFSP (FSP * fsp, wvStream * fd)
578 {
579     fsp->spid = read_32ubit (fd);
580     wvTrace (("SPID is %x\n", fsp->spid));
581     fsp->grfPersistent = read_32ubit (fd);
582     return (8);
583 }
584 
585 
586 U32
wvGetFSPGR(FSPGR * item,wvStream * fd)587 wvGetFSPGR (FSPGR * item, wvStream * fd)
588 {
589     /* It is supposed to be a RECT, but its only 4 long so... */
590     item->rcgBounds.left = read_32ubit (fd);
591     item->rcgBounds.right = read_32ubit (fd);
592     item->rcgBounds.top = read_32ubit (fd);
593     item->rcgBounds.bottom = read_32ubit (fd);
594     return (16);
595 }
596 
597 void
wvReleaseFSPContainer(FSPContainer * item)598 wvReleaseFSPContainer (FSPContainer * item)
599 {
600     wvReleaseClientTextbox (&item->clienttextbox);
601     wvReleaseClientData (&item->clientdata);
602     wvReleaseFOPTEArray (&item->fopte);
603 }
604 
605 void
wvInitFSPContainer(FSPContainer * item)606 wvInitFSPContainer (FSPContainer * item)
607 {
608     wvInitFOPTEArray (&item->fopte);
609     wvInitClientData (&item->clientdata);
610     wvInitClientTextbox (&item->clienttextbox);
611 }
612 
613 U32
wvGetFSPContainer(FSPContainer * item,MSOFBH * msofbh,wvStream * fd)614 wvGetFSPContainer (FSPContainer * item, MSOFBH * msofbh, wvStream * fd)
615 {
616     MSOFBH amsofbh;
617     U32 count = 0;
618     wvInitFSPContainer (item);
619     while (count < msofbh->cbLength)
620       {
621 	  count += wvGetMSOFBH (&amsofbh, fd);
622 	  wvTrace (
623 		   ("len is %x, type is %x, count %x,fullen %x\n",
624 		    amsofbh.cbLength, amsofbh.fbt, count, msofbh->cbLength));
625 	  wvTrace (("type is %x\n	", amsofbh.fbt));
626 	  switch (amsofbh.fbt)
627 	    {
628 	    case msofbtSpgr:
629 		count += wvGetFSPGR (&item->fspgr, fd);
630 		break;
631 
632 	    case msofbtSp:
633 		wvTrace (("Getting an fsp\n"));
634 		count += wvGetFSP (&item->fsp, fd);
635 		break;
636 
637 	    case msofbtOPT:
638 		count += wvGetFOPTEArray (&item->fopte, &amsofbh, fd);
639 		break;
640 
641 	    case msofbtAnchor:
642 	    case msofbtChildAnchor:
643 	    case msofbtClientAnchor:
644 		count += wvGetFAnchor (&item->fanchor, fd);
645 		break;
646 
647 	    case msofbtClientData:
648 		count += wvGetClientData (&item->clientdata, &amsofbh, fd);
649 		break;
650 	    case msofbtClientTextbox:
651 		count +=
652 		    wvGetClientTextbox (&item->clienttextbox, &amsofbh, fd);
653 		break;
654 
655 	    case msofbtTextbox:
656 		wvError (("unimp\n"));
657 		break;
658 	    case msofbtOleObject:
659 		wvError (("unimp\n"));
660 		break;
661 
662 	    case msofbtDeletedPspl:
663 		wvError (("unimp\n"));
664 		break;
665 
666 	    default:
667 		count += wvEatmsofbt (&amsofbh, fd);
668 		wvError (("Eating type 0x%x\n", amsofbh.fbt));
669 		break;
670 	    }
671       }
672     return (count);
673 }
674 
675 void
wvInitClientData(ClientData * item)676 wvInitClientData (ClientData * item)
677 {
678     item->data = NULL;
679 }
680 
681 void
wvReleaseClientData(ClientData * item)682 wvReleaseClientData (ClientData * item)
683 {
684     wvFree (item->data);
685 }
686 
687 U32
wvGetClientData(ClientData * item,MSOFBH * msofbh,wvStream * fd)688 wvGetClientData (ClientData * item, MSOFBH * msofbh, wvStream * fd)
689 {
690     U32 i;
691     if (msofbh->cbLength)
692       {
693 	  item->data = (U8 *) wvMalloc (msofbh->cbLength);
694 	  for (i = 0; i < msofbh->cbLength; i++)
695 	      item->data[i] = read_8ubit (fd);
696       }
697     else
698 	item->data = NULL;
699     return (msofbh->cbLength);
700 }
701 
702 U32
wvGetMSOFBH(MSOFBH * amsofbh,wvStream * fd)703 wvGetMSOFBH (MSOFBH * amsofbh, wvStream * fd)
704 {
705     U16 dtemp = 0;
706     dtemp = read_16ubit (fd);
707 
708 #ifdef PURIFY
709     amsofbh->ver = 0;
710     amsofbh->inst = 0;
711 #endif
712 
713     amsofbh->ver = dtemp & 0x000F;
714     amsofbh->inst = dtemp >> 4;
715     amsofbh->fbt = read_16ubit (fd);
716     amsofbh->cbLength = read_32ubit (fd);
717     return (8);
718 }
719 
720 
721 U32
wvEatmsofbt(MSOFBH * amsofbh,wvStream * fd)722 wvEatmsofbt (MSOFBH * amsofbh, wvStream * fd)
723 {
724     wvStream_offset(fd, amsofbh->cbLength);
725     return amsofbh->cbLength;
726 }
727 
728 void
wvInitClientTextbox(ClientTextbox * item)729 wvInitClientTextbox (ClientTextbox * item)
730 {
731     item->textid = NULL;
732 }
733 
734 void
wvReleaseClientTextbox(ClientTextbox * item)735 wvReleaseClientTextbox (ClientTextbox * item)
736 {
737     wvFree (item->textid);
738 }
739 
740 U32
wvGetClientTextbox(ClientTextbox * item,MSOFBH * amsofbh,wvStream * fd)741 wvGetClientTextbox (ClientTextbox * item, MSOFBH * amsofbh, wvStream * fd)
742 {
743     item->textid = (U32 *) wvMalloc (amsofbh->cbLength);
744     *item->textid = read_32ubit (fd);
745     return (amsofbh->cbLength);
746 }
747