1 //*********************************************************************************
2 //                               Rendition.cc
3 //---------------------------------------------------------------------------------
4 //
5 //---------------------------------------------------------------------------------
6 // Hugo Mercier <hmercier31[at]gmail.com> (c) 2008
7 // Pino Toscano <pino@kde.org> (c) 2008
8 // Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 //*********************************************************************************
24 
25 #include <math.h>
26 #include "Rendition.h"
27 #include "FileSpec.h"
28 
MediaWindowParameters()29 MediaWindowParameters::MediaWindowParameters() {
30   // default values
31   type = windowEmbedded;
32   width = -1;
33   height = -1;
34   relativeTo = windowRelativeToDocument;
35   XPosition = 0.5;
36   YPosition = 0.5;
37   hasTitleBar = gTrue;
38   hasCloseButton = gTrue;
39   isResizeable = gTrue;
40 }
41 
~MediaWindowParameters()42 MediaWindowParameters::~MediaWindowParameters() {
43 }
44 
parseFWParams(Object * obj)45 void MediaWindowParameters::parseFWParams(Object* obj) {
46   Object tmp;
47 
48   if (obj->dictLookup("D", &tmp)->isArray()) {
49     Array * dim = tmp.getArray();
50 
51     if (dim->getLength() >= 2) {
52       Object dd;
53       if (dim->get(0, &dd)->isInt()) {
54 	width = dd.getInt();
55       }
56       dd.free();
57       if (dim->get(1, &dd)->isInt()) {
58 	height = dd.getInt();
59       }
60       dd.free();
61     }
62   }
63   tmp.free();
64 
65   if (obj->dictLookup("RT", &tmp)->isInt()) {
66     int t = tmp.getInt();
67     switch(t) {
68     case 0: relativeTo = windowRelativeToDocument; break;
69     case 1: relativeTo = windowRelativeToApplication; break;
70     case 2: relativeTo = windowRelativeToDesktop; break;
71     }
72   }
73   tmp.free();
74 
75   if (obj->dictLookup("P",&tmp)->isInt()) {
76     int t = tmp.getInt();
77 
78     switch(t) {
79     case 0: // Upper left
80       XPosition = 0.0;
81       YPosition = 0.0;
82       break;
83     case 1: // Upper Center
84       XPosition = 0.5;
85       YPosition = 0.0;
86       break;
87     case 2: // Upper Right
88       XPosition = 1.0;
89       YPosition = 0.0;
90       break;
91     case 3: // Center Left
92       XPosition = 0.0;
93       YPosition = 0.5;
94       break;
95     case 4: // Center
96       XPosition = 0.5;
97       YPosition = 0.5;
98       break;
99     case 5: // Center Right
100       XPosition = 1.0;
101       YPosition = 0.5;
102       break;
103     case 6: // Lower Left
104       XPosition = 0.0;
105       YPosition = 1.0;
106       break;
107     case 7: // Lower Center
108       XPosition = 0.5;
109       YPosition = 1.0;
110       break;
111     case 8: // Lower Right
112       XPosition = 1.0;
113       YPosition = 1.0;
114       break;
115     }
116   }
117   tmp.free();
118 
119   if (obj->dictLookup("T", &tmp)->isBool()) {
120     hasTitleBar = tmp.getBool();
121   }
122   tmp.free();
123   if (obj->dictLookup("UC", &tmp)->isBool()) {
124     hasCloseButton = tmp.getBool();
125   }
126   tmp.free();
127   if (obj->dictLookup("R", &tmp)->isInt()) {
128     isResizeable = (tmp.getInt() != 0);
129   }
130   tmp.free();
131 
132 }
133 
MediaParameters()134 MediaParameters::MediaParameters() {
135   // instanciate to default values
136 
137   volume = 100;
138   fittingPolicy = fittingUndefined;
139   autoPlay = gTrue;
140   repeatCount = 1.0;
141   opacity = 1.0;
142   showControls = gFalse;
143   duration = 0;
144 }
145 
~MediaParameters()146 MediaParameters::~MediaParameters() {
147 }
148 
parseMediaPlayParameters(Object * obj)149 void MediaParameters::parseMediaPlayParameters(Object* obj) {
150 
151   Object tmp;
152 
153   if (obj->dictLookup("V", &tmp)->isInt()) {
154     volume = tmp.getInt();
155   }
156   tmp.free();
157 
158   if (obj->dictLookup("C", &tmp)->isBool()) {
159     showControls = tmp.getBool();
160   }
161   tmp.free();
162 
163   if (obj->dictLookup("F", &tmp)->isInt()) {
164     int t = tmp.getInt();
165 
166     switch(t) {
167     case 0: fittingPolicy = fittingMeet; break;
168     case 1: fittingPolicy = fittingSlice; break;
169     case 2: fittingPolicy = fittingFill; break;
170     case 3: fittingPolicy = fittingScroll; break;
171     case 4: fittingPolicy = fittingHidden; break;
172     case 5: fittingPolicy = fittingUndefined; break;
173     }
174   }
175   tmp.free();
176 
177   // duration parsing
178   // duration's default value is set to 0, which means : intrinsinc media duration
179   if (obj->dictLookup("D", &tmp)->isDict()) {
180     Object oname, ddict, tmp2;
181     if (tmp.dictLookup("S", &oname)->isName()) {
182       char* name = oname.getName();
183       if (!strcmp(name, "F"))
184 	duration = -1; // infinity
185       else if (!strcmp(name, "T")) {
186 	if (tmp.dictLookup("T", &ddict)->isDict()) {
187 	  if (ddict.dictLookup("V", &tmp2)->isNum()) {
188 	    duration = Gulong(tmp2.getNum());
189 	  }
190 	  tmp2.free();
191 	}
192 	ddict.free();
193       }
194     }
195     oname.free();
196   }
197   tmp.free();
198 
199 
200   if (obj->dictLookup("A", &tmp)->isBool()) {
201     autoPlay = tmp.getBool();
202   }
203   tmp.free();
204 
205   if (obj->dictLookup("RC", &tmp)->isNum()) {
206     repeatCount = tmp.getNum();
207   }
208   tmp.free();
209 
210 }
211 
parseMediaScreenParameters(Object * obj)212 void MediaParameters::parseMediaScreenParameters(Object* obj) {
213   Object tmp;
214 
215   if (obj->dictLookup("W", &tmp)->isInt()) {
216     int t = tmp.getInt();
217 
218     switch(t) {
219     case 0: windowParams.type = MediaWindowParameters::windowFloating; break;
220     case 1: windowParams.type = MediaWindowParameters::windowFullscreen; break;
221     case 2: windowParams.type = MediaWindowParameters::windowHidden; break;
222     case 3: windowParams.type = MediaWindowParameters::windowEmbedded; break;
223     }
224   }
225   tmp.free();
226 
227   // background color
228   if (obj->dictLookup("B", &tmp)->isArray()) {
229     Array* color = tmp.getArray();
230 
231     Object component;
232 
233     color->get(0, &component);
234     bgColor.r = component.getNum();
235     component.free();
236 
237     color->get(1, &component);
238     bgColor.g = component.getNum();
239     component.free();
240 
241     color->get(2, &component);
242     bgColor.b = component.getNum();
243     component.free();
244   }
245   tmp.free();
246 
247 
248   // opacity
249   if (obj->dictLookup("O", &tmp)->isNum()) {
250     opacity = tmp.getNum();
251   }
252   tmp.free();
253 
254   if (windowParams.type == MediaWindowParameters::windowFloating) {
255     Object winDict;
256     if (obj->dictLookup("F",&winDict)->isDict()) {
257       windowParams.parseFWParams(&winDict);
258     }
259     winDict.free();
260   }
261 }
262 
~MediaRendition()263 MediaRendition::~MediaRendition() {
264   if (fileName)
265     delete fileName;
266   if (contentType)
267     delete contentType;
268 
269   if (embeddedStream && (!embeddedStream->decRef())) {
270     delete embeddedStream;
271   }
272 }
273 
MediaRendition(Object * obj)274 MediaRendition::MediaRendition(Object* obj) {
275   Object tmp, tmp2;
276   GBool hasClip = gFalse;
277 
278   ok = gTrue;
279   fileName = NULL;
280   contentType = NULL;
281   isEmbedded = gFalse;
282   embeddedStream = NULL;
283 
284   //
285   // Parse media clip data
286   //
287   if (obj->dictLookup("C", &tmp2)->isDict()) { // media clip
288     hasClip = gTrue;
289     if (tmp2.dictLookup("S", &tmp)->isName()) {
290       if (!strcmp(tmp.getName(), "MCD")) { // media clip data
291         Object obj1, obj2;
292 	if (tmp2.dictLookup("D", &obj1)->isDict()) {
293 	  if (obj1.dictLookup("F", &obj2)->isString()) {
294 	    fileName = obj2.getString()->copy();
295 	  }
296 	  obj2.free();
297 	  if (obj1.dictLookup("EF", &obj2)->isDict()) {
298 	    Object embedded;
299 	    if (obj2.dictLookup("F", &embedded)->isStream()) {
300 	      isEmbedded = gTrue;
301 	      embeddedStream = embedded.getStream();
302 	      // "copy" stream
303 	      embeddedStream->incRef();
304 	    }
305 	    embedded.free();
306 	  }
307 	  obj2.free();
308 
309 	  // TODO: D might be a form XObject too
310 	} else {
311 	  error (-1, "Invalid Media Clip Data");
312 	  ok = gFalse;
313 	}
314 	obj1.free();
315 
316 	// FIXME: ignore CT if D is a form XObject
317 	if (tmp2.dictLookup("CT", &obj1)->isString()) {
318 	  contentType = obj1.getString()->copy();
319 	}
320 	obj1.free();
321       } else if (!strcmp(tmp.getName(), "MCS")) { // media clip data
322         // TODO
323       }
324     } else {
325       error (-1, "Invalid Media Clip");
326       ok = gFalse;
327     }
328     tmp.free();
329   }
330   tmp2.free();
331 
332   if (!ok)
333     return;
334 
335   //
336   // parse Media Play Parameters
337   if (obj->dictLookup("P", &tmp2)->isDict()) { // media play parameters
338     Object params;
339     if (tmp2.dictLookup("MH", &params)->isDict()) {
340       MH.parseMediaPlayParameters(&params);
341     }
342     params.free();
343     if (tmp2.dictLookup("BE", &params)->isDict()) {
344       BE.parseMediaPlayParameters(&params);
345     }
346     params.free();
347   } else if (hasClip) {
348     error (-1, "Invalid Media Rendition");
349     ok = gFalse;
350   }
351   tmp2.free();
352 
353   //
354   // parse Media Screen Parameters
355   if (obj->dictLookup("SP", &tmp2)->isDict()) { // media screen parameters
356     Object params;
357     if (tmp2.dictLookup("MH", &params)->isDict()) {
358       MH.parseMediaScreenParameters(&params);
359     }
360     params.free();
361     if (tmp2.dictLookup("BE", &params)->isDict()) {
362       BE.parseMediaScreenParameters(&params);
363     }
364     params.free();
365   }
366   tmp2.free();
367 }
368 
outputToFile(FILE * fp)369 void MediaRendition::outputToFile(FILE* fp) {
370   if (!isEmbedded)
371     return;
372 
373   embeddedStream->reset();
374 
375   while (1) {
376     int c = embeddedStream->getChar();
377     if (c == EOF)
378       break;
379 
380     fwrite(&c, 1, 1, fp);
381   }
382 
383 }
384 
copy()385 MediaRendition *MediaRendition::copy() {
386   // call default copy constructor
387   MediaRendition* new_media = new MediaRendition(*this);
388 
389   if (contentType)
390     new_media->contentType = contentType->copy();
391   if (fileName)
392     new_media->fileName = fileName->copy();
393 
394   if (new_media->embeddedStream)
395     new_media->embeddedStream->incRef();
396 
397   return new_media;
398 }
399 
400 // TODO: SelectorRendition
401