1 
2 
3 #include "texception.h"
4 #include "tpropertytype.h"
5 //#include "timageinfo.h"
6 //#include "tlevel_io.h"
7 #include "tproperty.h"
8 #include "tiio.h"
9 
10 #if !defined(x64) && !defined(__LP64__) && !(defined(LINUX) || defined(FREEBSD)) && !(defined(__GNUC__) && defined(_WIN32))
11 
12 //*******************************************************************************
13 //    32-bit version
14 //*******************************************************************************
15 
16 #ifdef _WIN32
17 #ifdef _MSC_VER
18 #pragma warning(disable : 4996)
19 #endif
20 
21 #define list QuickTime_list
22 #define map QuickTime_map
23 #define iterator QuickTime_iterator
24 #define float_t QuickTime_float_t
25 #define GetProcessInformation QuickTime_GetProcessInformation
26 #define int_fast8_t QuickTime_int_fast8_t
27 #define int_fast16_t QuickTime_int_fast16_t
28 #define uint_fast16_t QuickTime_uint_fast16_t
29 
30 #include "QTML.h"
31 #include "Movies.h"
32 #include "Script.h"
33 #include "FixMath.h"
34 #include "Sound.h"
35 
36 #include "QuickTimeComponents.h"
37 #include "tquicktime.h"
38 
39 #undef list
40 #undef map
41 #undef iterator
42 #undef float_t
43 #undef GetProcessInformation
44 #undef int_fast8_t
45 #undef int_fast16_t
46 #undef uint_fast16_t
47 
48 #else
49 
50 #define list List
51 #define map Map
52 #define iterator Iterator
53 #define float_t Float_t
54 #include <Carbon/Carbon.h>
55 #include <QuickTime/Movies.h>
56 #include <QuickTime/ImageCompression.h>
57 #include <QuickTime/QuickTimeComponents.h>
58 
59 #undef list
60 #undef map
61 #undef iterator
62 #undef float_t
63 
64 #endif
65 /*
66 questo file gestisce il salvataggio in un .tnz e il caricamento dei setting dei
67 mov.
68 viene usato il popup fornito da quicktime, con tutti i suoi setting e i sotto
69 settings.
70 i setting sono memorizzati da quicktime in un componentInstance. Da qui, possono
71 essere convertiti in un atomContainer,
72 che e' una struttura simile alla nostra propertyGroup, ma con gli atomi
73 strutturati ad albero.
74 sono state scritte due funzioni di conversione da atomContainer a propertygroup
75 e viceversa
76 ogni atom ha un type, id, e numero figli. se numero figli=0 allora l'atomo e'una
77 foglia,
78 e quindi ha un buffer di dati di valori char.
79 
80 ogni atomo viene trasformato in una stringProperty. il nome della stringProperty
81 e'
82 "type id numeroFigli"
83 se numerofigli>0, allora la stringProperty ha un valore nullo, e le prossime
84 numerofigli property contengono i figli;
85 se numerofigli==0, allora il valore della property contiene il buffer di dati,
86 convertito in stringa.
87 ecco coem viene convertito il buffer in stringa:
88 se ad esempio il buffer e' composto di 3 bytes, buf[0] = 13 buf[1]=0 buf[2]=231
89 allora la strnga valore sara' "13 0 231"
90 se ci sono piu 0 consecutivi, vengono memorizzati per salvare spazio come "z
91 count" in cui count e' il numero di 0.
92 esempio:  buf[0] = 13 buf[1]=0 buf[2]=0 buf[3]=0 buf[4]=0 buf5]=231
93 allora str = "13 z 4 231"
94 */
95 
96 #include "movsettings.h"
97 
98 //------------------------------------------------
99 
visitAtoms(const QTAtomContainer & atoms,const QTAtom & parent,TPropertyGroup & pg)100 void visitAtoms(const QTAtomContainer &atoms, const QTAtom &parent,
101                 TPropertyGroup &pg) {
102   QTAtom curr = 0;
103 
104   do {
105     if (QTNextChildAnyType(atoms, parent, curr, &curr) != noErr) assert(false);
106 
107     if (curr == 0) break;
108     QTAtomType atomType;
109     QTAtomID id;
110 
111     QTGetAtomTypeAndID(atoms, curr, &atomType, &id);
112     int sonCount = QTCountChildrenOfType(atoms, curr, 0);
113 
114     char buffer[1024];
115     snprintf(buffer, sizeof(buffer), "%d %d %d",
116       (int)atomType, (int)id, sonCount);
117     string str(buffer);
118 
119     if (sonCount > 0) {
120       pg.add(new TStringProperty(str, TString()));
121       visitAtoms(atoms, curr, pg);
122     }
123 
124     else {
125       long size;
126       UCHAR *atomData;
127       if (QTGetAtomDataPtr(atoms, curr, &size, (char **)&atomData) != noErr)
128         assert(false);
129 
130       string strapp;
131       for (int i = 0; i < size; i++) {
132         string num;
133         if (atomData[i] == 0) {
134           int count = 1;
135           while ((i + 1) < size && atomData[i + 1] == 0) i++, count++;
136           if (count > 1) {
137             num    = std::to_string(count);
138             strapp = strapp + "z " + num + " ";
139             continue;
140           }
141         }
142         num = std::to_string(atomData[i]);
143 
144         strapp = strapp + string(num) + " ";
145       }
146 
147       // unsigned short*buffer = new unsigned short[size];
148       // buffer[size]=0;
149       // for (i=0; i<size; i++)
150       //  buffer[i] = atomData[i]+1;
151 
152       wstring data = ::to_wstring(strapp);
153 
154       pg.add(new TStringProperty(str, data));
155     }
156   } while (curr != 0);
157 }
158 
159 //------------------------------------------------
160 namespace {
compareAtoms(const QTAtomContainer & atoms1,QTAtom parent1,const QTAtomContainer & atoms2,QTAtom parent2)161 void compareAtoms(const QTAtomContainer &atoms1, QTAtom parent1,
162                   const QTAtomContainer &atoms2, QTAtom parent2) {
163   QTAtom curr1 = 0, curr2 = 0;
164 
165   assert(QTCountChildrenOfType(atoms1, parent1, 0) ==
166          QTCountChildrenOfType(atoms2, parent2, 0));
167 
168   do {
169     if (QTNextChildAnyType(atoms1, parent1, curr1, &curr1) != noErr)
170       assert(false);
171 
172     if (QTNextChildAnyType(atoms2, parent2, curr2, &curr2) != noErr)
173       assert(false);
174     assert((curr1 != 0 && curr2 != 0) || (curr1 == 0 && curr2 == 0));
175 
176     if (curr1 == 0 || curr2 == 0) break;
177 
178     QTAtomType atomType1, atomType2;
179     QTAtomID id1, id2;
180 
181     QTGetAtomTypeAndID(atoms1, curr1, &atomType1, &id1);
182     QTGetAtomTypeAndID(atoms2, curr2, &atomType2, &id2);
183     assert(atomType1 == atomType2);
184 
185     int sonCount1 = QTCountChildrenOfType(atoms1, curr1, 0);
186     int sonCount2 = QTCountChildrenOfType(atoms2, curr2, 0);
187     assert(sonCount1 == sonCount2);
188     if (sonCount1 > 0)
189       compareAtoms(atoms1, curr1, atoms2, curr2);
190     else {
191       long size1;
192       UCHAR *atomData1;
193       long size2;
194       UCHAR *atomData2;
195       if (QTGetAtomDataPtr(atoms1, curr1, &size1, (char **)&atomData1) != noErr)
196         assert(false);
197       if (QTGetAtomDataPtr(atoms2, curr2, &size2, (char **)&atomData2) != noErr)
198         assert(false);
199       assert(size1 == size2);
200       for (int i = 0; i < size1; i++) assert(atomData1[i] == atomData2[i]);
201     }
202   } while (curr1 != 0 && curr2 != 0);
203 }
204 }
205 
206 //------------------------------------------------
207 
fromAtomsToProperties(const QTAtomContainer & atoms,TPropertyGroup & pg)208 void fromAtomsToProperties(const QTAtomContainer &atoms, TPropertyGroup &pg) {
209   pg.clear();
210   visitAtoms(atoms, kParentAtomIsContainer, pg);
211 }
212 
213 //------------------------------------------------
visitprops(TPropertyGroup & pg,int & index,QTAtomContainer & atoms,QTAtom parent)214 void visitprops(TPropertyGroup &pg, int &index, QTAtomContainer &atoms,
215                 QTAtom parent) {
216   int count = pg.getPropertyCount();
217   while (index < count) {
218     TStringProperty *p = (TStringProperty *)pg.getProperty(index++);
219     string str0        = p->getName();
220     const char *buf    = str0.c_str();
221     int atomType, id, sonCount;
222     sscanf(buf, "%d %d %d", &atomType, &id, &sonCount);
223     QTAtom newAtom;
224     if (sonCount == 0) {
225       wstring appow   = p->getValue();
226       string appo     = ::to_string(appow);
227       const char *str = appo.c_str();
228 
229       vector<UCHAR> buf;
230       while (strlen(str) > 0) {
231         if (str[0] == 'z') {
232           int count = atoi(str + 1);
233           str += (count < 10) ? 4 : ((count < 100) ? 5 : 6);
234           while (count--) buf.push_back(0);
235         } else {
236           int val = atoi(str);
237           assert(val >= 0 && val < 256);
238 
239           str += (val < 10) ? 2 : ((val < 100) ? 3 : 4);
240           buf.push_back(val);
241         }
242       }
243       // const unsigned short*bufs = str1.c_str();
244       // UCHAR *bufc = new UCHAR[size];
245       // for (int i=0; i<size; i++)
246       // {
247       //	assert(bufs[i]<257);
248       //	bufc[i] = (UCHAR)(bufs[i]-1);
249       //	}
250       void *ptr = 0;
251       if (buf.size() != 0) {
252         ptr = &(buf[0]);
253       }
254       QTInsertChild(atoms, parent, (QTAtomType)atomType, (QTAtomID)id, 0,
255                     buf.size(), (void *)ptr, 0);
256     } else {
257       QTInsertChild(atoms, parent, (QTAtomType)atomType, (QTAtomID)id, 0, 0, 0,
258                     &newAtom);
259       visitprops(pg, index, atoms, newAtom);
260     }
261   }
262 }
263 
264 //------------------------------------------------
265 
fromPropertiesToAtoms(TPropertyGroup & pg,QTAtomContainer & atoms)266 void fromPropertiesToAtoms(TPropertyGroup &pg, QTAtomContainer &atoms) {
267   int index = 0;
268   visitprops(pg, index, atoms, kParentAtomIsContainer);
269 }
270 
271 //------------------------------------------------
272 /*
273 #ifdef MACOSX
274 
275 SCExtendedProcs gProcStruct, ptr;
276 
277 static Boolean QTCmpr_FilterProc
278       (DialogPtr theDialog, EventRecord *theEvent,
279                                     short *theItemHit, long theRefCon)
280 {
281 #pragma unused(theItemHit, theRefCon)
282    Boolean         myEventHandled = false;
283    WindowRef      myEventWindow = NULL;
284    WindowRef      myDialogWindow = NULL;
285 
286    myDialogWindow = GetDialogWindow(theDialog);
287 
288    switch (theEvent->what) {
289       case updateEvt:
290         myEventWindow = (WindowRef)theEvent->message;
291                 // Change the window class
292         HIWindowChangeClass(myEventWindow,kUtilityWindowClass);
293                 // Activate the window scope
294                 SetWindowActivationScope(myEventWindow,kWindowActivationScopeAll);
295                 // Set the brushed metal theme on the window
296                 SetThemeWindowBackground(myEventWindow,kThemeBrushUtilityWindowBackgroundActive,true);
297 
298                 break;
299    }
300 
301    return(myEventHandled);
302 }
303 
304 #endif
305 */
306 //------------------------------------------------
307 
openMovSettingsPopup(TPropertyGroup * props,bool macBringToFront)308 void openMovSettingsPopup(TPropertyGroup *props, bool macBringToFront) {
309 #ifdef _WIN32
310   if (InitializeQTML(0) != noErr) return;
311 #endif
312 
313   ComponentInstance ci =
314       OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
315 
316   QTAtomContainer atoms;
317   QTNewAtomContainer(&atoms);
318 
319   fromPropertiesToAtoms(*props, atoms);
320 
321   ComponentResult err;
322 
323   if ((err = SCSetSettingsFromAtomContainer(ci, atoms)) != noErr) {
324     CloseComponent(ci);
325     ci = OpenDefaultComponent(StandardCompressionType,
326                               StandardCompressionSubType);
327     assert(false);
328   }
329 
330   QTDisposeAtomContainer(atoms);
331 
332 #ifdef MACOSX
333 
334 // Install an external procedure to use a callback filter on the request
335 // settings dialog
336 // On MACOSX we need to change the dialog appearance in order to pop-up in front
337 // of the
338 // toonz main window.
339 /*
340 gProcStruct.filterProc = NewSCModalFilterUPP(QTCmpr_FilterProc);
341 // I don't install any hook
342 gProcStruct.hookProc = NULL;
343 gProcStruct.customName[0] = 0;
344 // I don't use refcon
345 gProcStruct.refcon = 0;
346 
347 // set the current extended procs
348 SCSetInfo(ci, scExtendedProcsType, &gProcStruct);
349 */
350 #endif
351 
352   err = SCRequestSequenceSettings(ci);
353   // assert(err==noErr);
354   QTAtomContainer atomsOut;
355 
356   if (SCGetSettingsAsAtomContainer(ci, &atomsOut) != noErr) assert(false);
357 
358   fromAtomsToProperties(atomsOut, *props);
359 
360   QTDisposeAtomContainer(atomsOut);
361   CloseComponent(ci);
362 
363   // int dataSize=0, numChildren = 0, numLevels=0;
364   // retrieveData(settings, kParentAtomIsContainer, dataSize, numChildren,
365   // numLevels);
366 }
367 
isQuicktimeInstalled()368 bool Tiio::isQuicktimeInstalled() {
369 #ifdef MACOSX
370   return true;
371 #else
372 
373   static int ret     = -1;
374   if (ret == -1) ret = (InitializeQTML(0) == noErr) ? 1 : 0;
375 
376   return (ret == 1);
377 
378 #endif
379 }
380 
381 #else  // x64
382 
383 //*******************************************************************************
384 //    64-bit proxied version
385 //*******************************************************************************
386 
387 // Toonz includes
388 #include "tfilepath.h"
389 #include "tstream.h"
390 
391 // tipc includes
392 #include "tipc.h"
393 #include "t32bitsrv_wrap.h"
394 
395 // MAC-Specific includes
396 #ifdef MACOSX
397 #include <ApplicationServices/ApplicationServices.h>
398 #endif
399 
400 #include "movsettings.h"
401 
402 //---------------------------------------------------------------------------
403 
404 // Using 32-bit background server correspondence to achieve the same result
openMovSettingsPopup(TPropertyGroup * props,bool unused)405 void openMovSettingsPopup(TPropertyGroup *props, bool unused) {
406   QLocalSocket socket;
407   if (!tipc::startSlaveConnection(&socket, t32bitsrv::srvName(), 3000,
408                                   t32bitsrv::srvCmdline(), "_main"))
409     return;
410 
411   // Send the appropriate commands to the server
412   tipc::Stream stream(&socket);
413   tipc::Message msg;
414 
415   // We'll communicate through temporary files.
416   stream << (msg << QString("$tmpfile_request") << QString("openMovSets"));
417   QString res(tipc::readMessage(stream, msg));
418 
419   QString fp;
420   msg >> fp;
421   assert(res == "ok" && !fp.isEmpty());
422 
423   TFilePath tfp(fp.toStdWString());
424   {
425     // Save the input props to the temporary file
426     TOStream os(tfp);
427     props->saveData(os);
428   }
429 
430   // Invoke the settings popup
431   stream << (msg << tipc::clr << QString("$openMovSettingsPopup") << fp);
432   res =
433       tipc::readMessageNB(stream, msg, -1, QEventLoop::ExcludeUserInputEvents);
434   assert(res == "ok");
435 
436 #ifdef MACOSX
437 
438   // Bring this application back to front
439   ProcessSerialNumber psn = {0, kCurrentProcess};
440   SetFrontProcess(&psn);
441 
442 #endif  // MACOSX
443 
444   props->clear();
445   {
446     // Save the input props to the temporary file
447     TIStream is(tfp);
448     props->loadData(is);
449   }
450 
451   // Release the temporary file
452   stream << (msg << tipc::clr << QString("$tmpfile_release")
453                  << QString("openMovSets"));
454   res = tipc::readMessage(stream, msg);
455   assert(res == "ok");
456 }
457 
458 //---------------------------------------------------------------------------
459 
isQuicktimeInstalled()460 bool Tiio::isQuicktimeInstalled() {
461   // NOTE: This is *NOT* the same function as IsQuickTimeInstalled(), which is
462   // implemented locally in the image lib and used there. This function here is
463   // actually NEVER USED throughout Toonz, so we're placing a dummy
464   // implementation here.
465 
466   assert(false);
467   return false;
468 }
469 
470 #endif  // else
471