• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*----------------------------------------------------------------------------
2  *
3  * File:
4  * eas_xmf.c
5  *  5
6  * Contents and purpose:
7  * XMF File Parser
8  *
9  * Copyright Sonic Network Inc. 2005
10 
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  *
23  *----------------------------------------------------------------------------
24  * Revision Control:
25  *   $Revision: 501 $
26  *   $Date: 2006-12-11 17:53:36 -0800 (Mon, 11 Dec 2006) $
27  *----------------------------------------------------------------------------
28 */
29 
30 #include <log/log.h>
31 
32 #include "eas_data.h"
33 #include "eas_miditypes.h"
34 #include "eas_parser.h"
35 #include "eas_report.h"
36 #include "eas_host.h"
37 #include "eas_midi.h"
38 #include "eas_xmf.h"
39 #include "eas_xmfdata.h"
40 #include "eas_config.h"
41 #include "eas_vm_protos.h"
42 #include "eas_mdls.h"
43 #include "eas_smf.h"
44 
45 
46 /* XMF header file type */
47 #define XMF_IDENTIFIER          0x584d465f
48 #define XMF_VERSION_1_00        0x312e3030
49 #define XMF_VERSION_1_01        0x312e3031
50 #define XMF_VERSION_2_00        0x322e3030
51 #define XMF_FILE_TYPE           0x00000002
52 #define XMF_SPEC_LEVEL          0x00000001
53 #define XMF_RIFF_CHUNK          0x52494646
54 #define XMF_RIFF_DLS            0x444c5320
55 #define XMF_SMF_CHUNK           0x4d546864
56 
57 /* local prototypes */
58 static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
59 static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
60 static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
61 static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
62 static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
63 static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
64 static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
65 static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
66 static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
67 static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
68 static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
69 static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData);
70 static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 endOffset, EAS_I32 *pLength, EAS_I32 depth);
71 static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *remainingBytes, EAS_I32 *value);
72 
73 
74 /*----------------------------------------------------------------------------
75  *
76  * XMF_Parser
77  *
78  * This structure contains the functional interface for the XMF parser
79  *----------------------------------------------------------------------------
80 */
81 const S_FILE_PARSER_INTERFACE EAS_XMF_Parser =
82 {
83     XMF_CheckFileType,
84     XMF_Prepare,
85     XMF_Time,
86     XMF_Event,
87     XMF_State,
88     XMF_Close,
89     XMF_Reset,
90 #ifdef JET_INTERFACE
91     XMF_Pause,
92     XMF_Resume,
93 #else
94     NULL,
95     NULL,
96 #endif
97     NULL,
98     XMF_SetData,
99     XMF_GetData,
100     NULL
101 };
102 
103 /*----------------------------------------------------------------------------
104  * XMF_CheckFileType()
105  *----------------------------------------------------------------------------
106  * Purpose:
107  * Check the file type to see if we can parse it
108  *
109  * Inputs:
110  * pEASData         - pointer to overall EAS data structure
111  * handle           - pointer to file handle
112  *
113  * Outputs:
114  *
115  *
116  * Side Effects:
117  *
118  *----------------------------------------------------------------------------
119 */
XMF_CheckFileType(S_EAS_DATA * pEASData,EAS_FILE_HANDLE fileHandle,EAS_VOID_PTR * ppHandle,EAS_I32 offset)120 static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
121 {
122     S_XMF_DATA *pXMFData;
123     EAS_RESULT result;
124     EAS_U32 temp;
125 
126     /* assume we don't recognize it initially */
127     *ppHandle = NULL;
128 
129     /* read the file identifier */
130     if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
131         return result;
132     if (temp != XMF_IDENTIFIER)
133         return EAS_SUCCESS;
134 
135     /* read the version */
136     if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
137         return result;
138 
139     if (temp == XMF_VERSION_2_00)
140     {
141         /* read the file type */
142         result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE);
143         if (result != EAS_SUCCESS)
144             return result;
145 
146         if (temp != XMF_FILE_TYPE)
147         {
148             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR,
149                           "XMF file type was 0x%08x, expected 0x%08x\n", temp, XMF_FILE_TYPE); */ }
150             return EAS_SUCCESS;
151         }
152 
153         /* read the spec level */
154         result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE);
155         if (result != EAS_SUCCESS)
156             return result;
157 
158         if (temp != XMF_SPEC_LEVEL)
159         {
160             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR,
161                           "XMF file spec was 0x%08x, expected 0x%08x\n", temp, XMF_SPEC_LEVEL); */ }
162             return EAS_SUCCESS;
163         }
164     }
165     else if (temp != XMF_VERSION_1_00 && temp != XMF_VERSION_1_01)
166     {
167         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file version was 0x%08x\n", temp); */ }
168         return EAS_SUCCESS;
169     }
170 
171     /* check for static memory allocation */
172     if (pEASData->staticMemoryModel)
173         pXMFData = EAS_CMEnumData(EAS_CM_XMF_DATA);
174     else
175         pXMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_XMF_DATA));
176     if (!pXMFData)
177         return EAS_ERROR_MALLOC_FAILED;
178 
179     /* zero the memory to insure complete initialization */
180     EAS_HWMemSet((void *)pXMFData,0, sizeof(S_XMF_DATA));
181 
182     pXMFData->fileHandle = fileHandle;
183     pXMFData->fileOffset = offset;
184 
185     /* locate the SMF and DLS contents */
186     if ((result = XMF_FindFileContents(pEASData->hwInstData, pXMFData)) != EAS_SUCCESS)
187     {
188         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ }
189         EAS_HWFree(pEASData->hwInstData, pXMFData);
190         return result;
191     }
192 
193     /* let the SMF parser take over */
194     if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pXMFData->midiOffset)) != EAS_SUCCESS) {
195         EAS_HWFree(pEASData->hwInstData, pXMFData);
196         return result;
197     }
198     if ((result = SMF_CheckFileType(pEASData, fileHandle, &pXMFData->pSMFData, pXMFData->midiOffset)) != EAS_SUCCESS) {
199         EAS_HWFree(pEASData->hwInstData, pXMFData);
200         return result;
201     }
202     *ppHandle = pXMFData;
203     return EAS_SUCCESS;
204 }
205 
206 /*----------------------------------------------------------------------------
207  * XMF_Prepare()
208  *----------------------------------------------------------------------------
209  * Purpose:
210  * Prepare to parse the file. Allocates instance data (or uses static allocation for
211  * static memory model).
212  *
213  * Inputs:
214  * pEASData         - pointer to overall EAS data structure
215  * handle           - pointer to file handle
216  *
217  * Outputs:
218  *
219  *
220  * Side Effects:
221  *
222  *----------------------------------------------------------------------------
223 */
XMF_Prepare(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)224 static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
225 {
226     S_XMF_DATA* pXMFData;
227     EAS_RESULT result;
228 
229     /* parse DLS collection */
230     pXMFData = (S_XMF_DATA*) pInstData;
231     if (pXMFData->dlsOffset != 0)
232     {
233         if ((result = DLSParser(pEASData->hwInstData, pXMFData->fileHandle, pXMFData->dlsOffset, &pXMFData->pDLS)) != EAS_SUCCESS)
234         {
235             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error converting XMF DLS data\n"); */ }
236             return result;
237         }
238     }
239 
240     /* Prepare the SMF parser */
241     if ((result = SMF_Prepare(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS)
242         return result;
243 
244     /* if no DLS file, skip this step */
245     if (pXMFData->pDLS == NULL)
246         return EAS_SUCCESS;
247 
248     /* tell the synth to use the DLS collection */
249     result = VMSetDLSLib(((S_SMF_DATA*) pXMFData->pSMFData)->pSynth, pXMFData->pDLS);
250     if (result == EAS_SUCCESS)
251     {
252         DLSAddRef(pXMFData->pDLS);
253         VMInitializeAllChannels(pEASData->pVoiceMgr, ((S_SMF_DATA*) pXMFData->pSMFData)->pSynth);
254     }
255     return result;
256 }
257 
258 /*----------------------------------------------------------------------------
259  * XMF_Time()
260  *----------------------------------------------------------------------------
261  * Purpose:
262  * Returns the time of the next event in msecs
263  *
264  * Inputs:
265  * pEASData         - pointer to overall EAS data structure
266  * handle           - pointer to file handle
267  * pTime            - pointer to variable to hold time of next event (in msecs)
268  *
269  * Outputs:
270  *
271  *
272  * Side Effects:
273  *
274  *----------------------------------------------------------------------------
275 */
XMF_Time(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_U32 * pTime)276 static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
277 {
278     return SMF_Time(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pTime);
279 }
280 
281 /*----------------------------------------------------------------------------
282  * XMF_Event()
283  *----------------------------------------------------------------------------
284  * Purpose:
285  * Parse the next event in the file
286  *
287  * Inputs:
288  * pEASData         - pointer to overall EAS data structure
289  * handle           - pointer to file handle
290  *
291  * Outputs:
292  *
293  *
294  * Side Effects:
295  *
296  *----------------------------------------------------------------------------
297 */
XMF_Event(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_INT parserMode)298 static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
299 {
300     return SMF_Event(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, parserMode);
301 }
302 
303 /*----------------------------------------------------------------------------
304  * XMF_State()
305  *----------------------------------------------------------------------------
306  * Purpose:
307  * Returns the current state of the stream
308  *
309  * Inputs:
310  * pEASData         - pointer to overall EAS data structure
311  * handle           - pointer to file handle
312  * pState           - pointer to variable to store state
313  *
314  * Outputs:
315  *
316  *
317  * Side Effects:
318  *
319  *----------------------------------------------------------------------------
320 */
XMF_State(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 * pState)321 static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
322 {
323     return SMF_State(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pState);
324 }
325 
326 /*----------------------------------------------------------------------------
327  * XMF_Close()
328  *----------------------------------------------------------------------------
329  * Purpose:
330  * Close the file and clean up
331  *
332  * Inputs:
333  * pEASData         - pointer to overall EAS data structure
334  * handle           - pointer to file handle
335  *
336  * Outputs:
337  *
338  *
339  * Side Effects:
340  *
341  *----------------------------------------------------------------------------
342 */
XMF_Close(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)343 static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
344 {
345     S_XMF_DATA* pXMFData;
346     EAS_RESULT result;
347 
348     pXMFData = (S_XMF_DATA *)pInstData;
349 
350     /* close the SMF stream, it will close the file handle */
351     if ((result = SMF_Close(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS)
352         return result;
353 
354     if (pXMFData->pDLS)
355         DLSCleanup(pEASData->hwInstData, pXMFData->pDLS);
356 
357     /* if using dynamic memory, free it */
358     if (!pEASData->staticMemoryModel)
359     {
360         /* free the instance data */
361         EAS_HWFree(pEASData->hwInstData, pXMFData);
362     }
363 
364     return EAS_SUCCESS;
365 }
366 
367 /*----------------------------------------------------------------------------
368  * XMF_Reset()
369  *----------------------------------------------------------------------------
370  * Purpose:
371  * Reset the sequencer. Used for locating backwards in the file.
372  *
373  * Inputs:
374  * pEASData         - pointer to overall EAS data structure
375  * handle           - pointer to file handle
376  *
377  * Outputs:
378  *
379  *
380  * Side Effects:
381  *
382  *----------------------------------------------------------------------------
383 */
XMF_Reset(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)384 static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
385 {
386     return SMF_Reset(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
387 }
388 
389 #ifdef JET_INTERFACE
390 /*----------------------------------------------------------------------------
391  * XMF_Pause()
392  *----------------------------------------------------------------------------
393  * Purpose:
394  * Pauses the sequencer. Mutes all voices and sets state to pause.
395  *
396  * Inputs:
397  * pEASData         - pointer to overall EAS data structure
398  * handle           - pointer to file handle
399  *
400  * Outputs:
401  *
402  *
403  * Side Effects:
404  *
405  *----------------------------------------------------------------------------
406 */
XMF_Pause(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)407 static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
408 {
409     return SMF_Pause(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
410 }
411 
412 /*----------------------------------------------------------------------------
413  * XMF_Resume()
414  *----------------------------------------------------------------------------
415  * Purpose:
416  * Resume playing after a pause, sets state back to playing.
417  *
418  * Inputs:
419  * pEASData         - pointer to overall EAS data structure
420  * handle           - pointer to file handle
421  *
422  * Outputs:
423  *
424  *
425  * Side Effects:
426  *
427  *----------------------------------------------------------------------------
428 */
XMF_Resume(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)429 static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
430 {
431     return SMF_Resume(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
432 }
433 #endif
434 
435 /*----------------------------------------------------------------------------
436  * XMF_SetData()
437  *----------------------------------------------------------------------------
438  * Purpose:
439  * Sets the playback rate of the underlying SMF file
440  *
441  * Inputs:
442  * pEASData         - pointer to overall EAS data structure
443  * handle           - pointer to file handle
444  * rate             - rate (28-bit fraction)
445  *
446  * Outputs:
447  *
448  *
449  * Side Effects:
450  *
451  *----------------------------------------------------------------------------
452 */
XMF_SetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 value)453 static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
454 {
455     return SMF_SetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, value);
456 }
457 
458 /*----------------------------------------------------------------------------
459  * XMF_GetData()
460  *----------------------------------------------------------------------------
461  * Purpose:
462  * Gets the file type
463  *
464  * Inputs:
465  * pEASData         - pointer to overall EAS data structure
466  * handle           - pointer to file handle
467  * rate             - rate (28-bit fraction)
468  *
469  * Outputs:
470  *
471  *
472  * Side Effects:
473  *
474  *----------------------------------------------------------------------------
475 */
XMF_GetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 * pValue)476 static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
477 {
478     EAS_RESULT result;
479 
480     /* call SMF parser to get value */
481     if ((result = SMF_GetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, pValue)) != EAS_SUCCESS)
482         return result;
483 
484     /* special case for file type */
485     if (param == PARSER_DATA_FILE_TYPE)
486     {
487         if (*pValue == EAS_FILE_SMF0)
488             *pValue = EAS_FILE_XMF0;
489         else if (*pValue == EAS_FILE_SMF1)
490             *pValue = EAS_FILE_XMF1;
491     }
492 
493     return EAS_SUCCESS;
494 }
495 
496 /*----------------------------------------------------------------------------
497  * XMF_FindFileContents()
498  *----------------------------------------------------------------------------
499  * Purpose:
500  * Finds SMF data and DLS data in XMF file, and remembers offset for each.
501  * If more than one is found, uses the first one found of each.
502  * Makes assumptions about the format of a mobile XMF file
503  *
504  * Inputs:
505  * pEASData         - pointer to overall EAS data structure
506  * pXMFData         - pointer to XMF parser instance data
507  * handle           - pointer to file handle
508  *
509  * Outputs:
510  *
511  *
512  * Side Effects:
513  *
514  *----------------------------------------------------------------------------
515 */
XMF_FindFileContents(EAS_HW_DATA_HANDLE hwInstData,S_XMF_DATA * pXMFData)516 static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData)
517 {
518     EAS_RESULT result;
519     EAS_I32 value;
520     EAS_I32 treeStart;
521     EAS_I32 treeEnd;
522     EAS_I32 length;
523     EAS_I32 node_depth = 0 ;
524     EAS_I32 fileLength;
525     EAS_U32 remainingBytes;
526 
527     /* initialize offsets */
528     pXMFData->dlsOffset = pXMFData->midiOffset = 0;
529 
530     /* read file length. We're arbitrarily limiting the size of this field to
531      * 16 bytes, since we don't yet have an actual limit. Once the field is
532      * read, we correct remainingBytes using the actual value that we had read.
533      * Since upon return from XMF_ReadVLQ(), remainingBytes represents how much
534      * is left unread, it will be set to (16 - size_of_field). Therefore, size
535      * of field is (16 - remainingBytes), which is what we need to subtract from
536      * the total size. */
537     const EAS_U32 kInitialRemainingBytes = 16;
538 
539     remainingBytes = kInitialRemainingBytes;
540     if ((result = XMF_ReadVLQ(hwInstData,
541                               pXMFData->fileHandle,
542                               &remainingBytes,
543                               &fileLength)) != EAS_SUCCESS)
544         return result;
545     if (fileLength < 0)
546         return EAS_ERROR_FILE_FORMAT;
547     remainingBytes = fileLength + remainingBytes - kInitialRemainingBytes;
548 
549     /* read MetaDataTypesTable length and skip over it */
550     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingBytes, &value)) != EAS_SUCCESS)
551         return result;
552     if (value > remainingBytes)
553         return EAS_ERROR_FILE_FORMAT;
554     if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, value)) != EAS_SUCCESS)
555         return result;
556     remainingBytes -= value;
557 
558     /* get TreeStart and TreeEnd offsets */
559     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingBytes, &treeStart)) != EAS_SUCCESS)
560         return result;
561     if (treeStart < 0)
562         return EAS_ERROR_FILE_FORMAT;
563 
564     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingBytes, &treeEnd)) != EAS_SUCCESS)
565         return result;
566     if (treeEnd < treeStart || treeEnd >= fileLength)
567         return EAS_ERROR_FILE_FORMAT;
568 
569     if ((result = XMF_ReadNode(hwInstData, pXMFData, treeStart, treeEnd + 1, &length, node_depth)) != EAS_SUCCESS)
570         return result;
571 
572     /* check for SMF data */
573     if (pXMFData->midiOffset == 0)
574     {
575         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ }
576         return EAS_ERROR_FILE_FORMAT;
577     }
578 
579     /* check for SFM in wrong order */
580     if ((pXMFData->dlsOffset > 0) && (pXMFData->midiOffset < pXMFData->dlsOffset))
581         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS data must precede SMF data in Mobile XMF file\n"); */ }
582 
583     return EAS_SUCCESS;
584 }
585 
586 /*----------------------------------------------------------------------------
587  * XMF_ReadNode()
588  *----------------------------------------------------------------------------
589  * Purpose:
590  *
591  * Inputs:
592  *
593  * Outputs:
594  *
595  *
596  * Side Effects:
597  *
598  *----------------------------------------------------------------------------
599 */
XMF_ReadNode(EAS_HW_DATA_HANDLE hwInstData,S_XMF_DATA * pXMFData,EAS_I32 nodeOffset,EAS_I32 endOffset,EAS_I32 * pLength,EAS_I32 depth)600 static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 endOffset, EAS_I32 *pLength, EAS_I32 depth)
601 {
602     EAS_RESULT result;
603     EAS_I32 refType;
604     EAS_I32 numItems;
605     EAS_I32 offset;
606     EAS_I32 length;
607     EAS_I32 headerLength;
608     EAS_U32 chunkType;
609     EAS_U32 remainingInlineBytes;
610     EAS_U32 deltaBytes;
611 
612     /* check the depth of current node*/
613     if ( depth > 100 )
614         return EAS_ERROR_FILE_FORMAT;
615 
616     /* this will be used to check we don't read past the node limits */
617     remainingInlineBytes = endOffset - nodeOffset;
618 
619     /* seek to start of node */
620     if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset)) != EAS_SUCCESS)
621         return result;
622 
623     /* get node length */
624     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingInlineBytes, pLength)) != EAS_SUCCESS)
625         return result;
626     if ((*pLength < 0) || (*pLength > endOffset - nodeOffset))
627         return EAS_ERROR_FILE_FORMAT;
628 
629     /* recalculate our end offset and remaining bytes. */
630     deltaBytes = endOffset - nodeOffset - *pLength;
631     if (remainingInlineBytes < deltaBytes)
632         return EAS_ERROR_FILE_FORMAT;
633 
634     remainingInlineBytes -= deltaBytes;
635     endOffset = nodeOffset + *pLength;
636 
637     /* get number of contained items */
638     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingInlineBytes, &numItems)) != EAS_SUCCESS)
639         return result;
640     if (numItems < 0)
641         return EAS_ERROR_FILE_FORMAT;
642 
643     /* get node header length */
644     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingInlineBytes, &headerLength)) != EAS_SUCCESS)
645         return result;
646     if (headerLength < 0 || headerLength > *pLength)
647         return EAS_ERROR_FILE_FORMAT;
648 
649     /* get metadata length */
650     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingInlineBytes, &length)) != EAS_SUCCESS)
651         return result;
652     if (length < 0)
653         return EAS_ERROR_FILE_FORMAT;
654 
655     /* get the current location */
656     if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
657         return result;
658 
659     /* check that we didn't go past the header. */
660     if (offset - nodeOffset > headerLength)
661         return EAS_FAILURE;
662 
663     /* skip to node contents */
664     if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset + headerLength)) != EAS_SUCCESS)
665         return result;
666     remainingInlineBytes = endOffset - (nodeOffset + headerLength);
667 
668     /* get reference type */
669     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingInlineBytes, &refType)) != EAS_SUCCESS)
670         return result;
671 
672     /* get the current location */
673     if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
674         return result;
675 
676     /* process file node */
677     if (numItems == 0)
678 
679     {
680         /* if in-file resource, find out where it is and jump to it */
681         if (refType == 2)
682         {
683             if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &remainingInlineBytes, &offset)) != EAS_SUCCESS)
684                 return result;
685             offset += pXMFData->fileOffset;
686             if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS)
687                 return result;
688         }
689 
690         /* or else it must be an inline resource */
691         else if (refType != 1)
692         {
693             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected reference type %d\n", refType); */ }
694             return EAS_ERROR_FILE_FORMAT;
695         }
696 
697         /* at this point we stop enforcing reading past the node. */
698 
699         /* get the chunk type */
700         if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS)
701             return result;
702 
703         /* found a RIFF chunk, check for DLS type */
704         if (chunkType == XMF_RIFF_CHUNK)
705         {
706             /* skip length */
707             if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, 4)) != EAS_SUCCESS)
708                 return result;
709 
710             /* get RIFF file type */
711             if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS)
712                 return result;
713             if (chunkType == XMF_RIFF_DLS)
714                 pXMFData->dlsOffset = offset;
715         }
716 
717         /* found an SMF chunk */
718         else if (chunkType == XMF_SMF_CHUNK)
719             pXMFData->midiOffset = offset;
720     }
721 
722     /* folder node, process the items in the list */
723     else
724     {
725         for ( ; numItems > 0; numItems--)
726         {
727             /* process this item */
728             if ((result = XMF_ReadNode(hwInstData, pXMFData, offset, endOffset, &length, depth+1)) != EAS_SUCCESS)
729                 return result;
730 
731             /* seek to start of next item */
732             offset += length;
733             if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS)
734                 return result;
735         }
736     }
737 
738     return EAS_SUCCESS;
739 }
740 
741 #if 0
742 /*----------------------------------------------------------------------------
743  * XMF_FindFileContents()
744  *----------------------------------------------------------------------------
745  * Purpose:
746  * Finds SMF data and DLS data in XMF file, and remembers offset for each.
747  * If more than one is found, uses the first one found of each.
748  * Makes assumptions about the format of a mobile XMF file
749  *
750  * Inputs:
751  * pEASData         - pointer to overall EAS data structure
752  * pXMFData         - pointer to XMF parser instance data
753  * handle           - pointer to file handle
754  *
755  * Outputs:
756  *
757  *
758  * Side Effects:
759  *
760  *----------------------------------------------------------------------------
761 */
762 static EAS_RESULT XMF_FindFileContents(S_EAS_DATA *pEASData, S_XMF_DATA *pXMFData, EAS_FILE_HANDLE fileHandle)
763 {
764     EAS_RESULT result;
765     EAS_I32 offset;
766     EAS_I32 value;
767     EAS_I32 numItems;
768     EAS_I32 length;
769     EAS_CHAR id[4];
770     EAS_I32 location;
771 
772     /* init dls offset, so that we know we haven't found a dls chunk yet */
773     pXMFData->dlsOffset = 0;
774 
775     /* read file length, ignore it for now */
776     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
777         return result;
778 
779     /* read MetaDataTypesTable length and skip over it */
780     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
781         return result;
782     if ((result = EAS_HWFileSeekOfs(pEASData, fileHandle, value)) != EAS_SUCCESS)
783         return result;
784 
785     /* get TreeStart offset and jump to it */
786     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &offset)) != EAS_SUCCESS)
787         return result;
788     if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS)
789         return result;
790 
791     /* read node length, ignore it for now */
792     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
793         return result;
794 
795     /* read number of contained items */
796     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &numItems)) != EAS_SUCCESS)
797         return result;
798 
799     /*read node header length */
800     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
801         return result;
802 
803     /*go to the node offset */
804     if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS)
805         return result;
806 
807     /* read Reference Type */
808     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
809         return result;
810 
811     /* make sure it is an in-line resource, for now */
812     if (value != 1)
813     {
814         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file tree\n"); */ }
815         return EAS_FAILURE;
816     }
817 
818     /* parse through the list of items */
819     while (numItems > 0)
820     {
821         /*get current offset */
822         if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &offset)) != EAS_SUCCESS)
823             return result;
824 
825         /*read node length */
826         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &length)) != EAS_SUCCESS)
827             return result;
828 
829         /* read number of items */
830         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
831             return result;
832 
833         /* make sure not a folder */
834         if (value != 0)
835         {
836             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ }
837             return EAS_FAILURE;
838         }
839 
840         /* read offset to resource and jump to it */
841         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
842             return result;
843         if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS)
844             return result;
845 
846         /* read Reference Type */
847         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
848             return result;
849 
850         /* make sure it is an in-line resource */
851         if (value != 1)
852         {
853             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ }
854             return EAS_FAILURE;
855         }
856 
857         /* get current offset as a possible location for SMF file or DLS file */
858         if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &location)) != EAS_SUCCESS)
859             return result;
860 
861         /* read four bytes */
862         if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, id, sizeof(id), &value)) != EAS_SUCCESS)
863             return result;
864 
865         /* check if DLS */
866         if (pXMFData->dlsOffset == 0 && id[0] == 'R' && id[1] == 'I' && id[2] == 'F' && id[3] == 'F')
867         {
868             //remember offset
869             pXMFData->dlsOffset = location;
870         }
871 
872         /* else check if SMF */
873         else if (id[0] == 'M' && id[1] == 'T' && id[2] == 'h' && id[3] == 'd')
874         {
875             //remember offset
876             pXMFData->midiOffset = location;
877 
878             //we are done
879             return EAS_SUCCESS;
880         }
881 
882         //one less item
883         numItems--;
884 
885         //if more data, go to the next item
886         if (numItems >0)
887         {
888             if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + length)) != EAS_SUCCESS)
889                 return result;
890         }
891     }
892 
893     return EAS_FAILURE;
894 
895 }
896 #endif
897 
898 /*----------------------------------------------------------------------------
899  * XMF_ReadVLQ()
900  *----------------------------------------------------------------------------
901  * Purpose:
902  * Reads a VLQ encoded value from the file referenced by fileHandle
903  *
904  * Inputs:
905  * pEASData         - pointer to overall EAS data structure
906  * fileHandle       - pointer to file handle
907  *
908  * Outputs:
909  * value            - pointer to the value decoded from the VLQ data
910  *
911  *
912  * Side Effects:
913  *
914  *----------------------------------------------------------------------------
915 */
XMF_ReadVLQ(EAS_HW_DATA_HANDLE hwInstData,EAS_FILE_HANDLE fileHandle,EAS_U32 * remainingBytes,EAS_I32 * value)916 static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *remainingBytes, EAS_I32 *value)
917 {
918     EAS_RESULT result;
919     EAS_U8 c;
920     *value = 0;
921 
922     if ((*remainingBytes)-- == 0)
923         return EAS_ERROR_FILE_FORMAT;
924 
925     if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
926         return result;
927 
928     while (c > 0x7F)
929     {
930         /*lint -e{703} shift for performance */
931         *value = (*value << 7) | (c & 0x7F);
932 
933         if ((*remainingBytes)-- == 0)
934             return EAS_ERROR_FILE_FORMAT;
935 
936         if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
937             return result;
938     }
939 
940     /*lint -e{703} shift for performance */
941     *value = (*value << 7) | c;
942 
943     return EAS_SUCCESS;
944 }
945 
946