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 *pLength, EAS_I32 depth);
71 static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, 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     XMF_Pause,
91     XMF_Resume,
92     NULL,
93     XMF_SetData,
94     XMF_GetData,
95     NULL
96 };
97 
98 /*----------------------------------------------------------------------------
99  * XMF_CheckFileType()
100  *----------------------------------------------------------------------------
101  * Purpose:
102  * Check the file type to see if we can parse it
103  *
104  * Inputs:
105  * pEASData         - pointer to overall EAS data structure
106  * handle           - pointer to file handle
107  *
108  * Outputs:
109  *
110  *
111  * Side Effects:
112  *
113  *----------------------------------------------------------------------------
114 */
XMF_CheckFileType(S_EAS_DATA * pEASData,EAS_FILE_HANDLE fileHandle,EAS_VOID_PTR * ppHandle,EAS_I32 offset)115 static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
116 {
117     S_XMF_DATA *pXMFData;
118     EAS_RESULT result;
119     EAS_U32 temp;
120 
121     /* assume we don't recognize it initially */
122     *ppHandle = NULL;
123 
124     /* read the file identifier */
125     if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
126         return result;
127     if (temp != XMF_IDENTIFIER)
128         return EAS_SUCCESS;
129 
130     /* read the version */
131     if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE))  != EAS_SUCCESS)
132         return result;
133 
134     if (temp == XMF_VERSION_2_00)
135     {
136         /* read the file type */
137         result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE);
138         if (result != EAS_SUCCESS)
139             return result;
140 
141         if (temp != XMF_FILE_TYPE)
142         {
143             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR,
144                           "XMF file type was 0x%08x, expected 0x%08x\n", temp, XMF_FILE_TYPE); */ }
145             return EAS_SUCCESS;
146         }
147 
148         /* read the spec level */
149         result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE);
150         if (result != EAS_SUCCESS)
151             return result;
152 
153         if (temp != XMF_SPEC_LEVEL)
154         {
155             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR,
156                           "XMF file spec was 0x%08x, expected 0x%08x\n", temp, XMF_SPEC_LEVEL); */ }
157             return EAS_SUCCESS;
158         }
159     }
160     else if (temp != XMF_VERSION_1_00 && temp != XMF_VERSION_1_01)
161     {
162         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file version was 0x%08x\n", temp); */ }
163         return EAS_SUCCESS;
164     }
165 
166     /* check for static memory allocation */
167     if (pEASData->staticMemoryModel)
168         pXMFData = EAS_CMEnumData(EAS_CM_XMF_DATA);
169     else
170         pXMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_XMF_DATA));
171     if (!pXMFData)
172         return EAS_ERROR_MALLOC_FAILED;
173 
174     /* zero the memory to insure complete initialization */
175     EAS_HWMemSet((void *)pXMFData,0, sizeof(S_XMF_DATA));
176 
177     pXMFData->fileHandle = fileHandle;
178     pXMFData->fileOffset = offset;
179     *ppHandle = pXMFData;
180 
181     /* locate the SMF and DLS contents */
182     if ((result = XMF_FindFileContents(pEASData->hwInstData, pXMFData)) != EAS_SUCCESS)
183     {
184         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ }
185         return result;
186     }
187 
188     /* let the SMF parser take over */
189     if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pXMFData->midiOffset)) != EAS_SUCCESS)
190         return result;
191     return SMF_CheckFileType(pEASData, fileHandle, &pXMFData->pSMFData, pXMFData->midiOffset);
192 }
193 
194 /*----------------------------------------------------------------------------
195  * XMF_Prepare()
196  *----------------------------------------------------------------------------
197  * Purpose:
198  * Prepare to parse the file. Allocates instance data (or uses static allocation for
199  * static memory model).
200  *
201  * Inputs:
202  * pEASData         - pointer to overall EAS data structure
203  * handle           - pointer to file handle
204  *
205  * Outputs:
206  *
207  *
208  * Side Effects:
209  *
210  *----------------------------------------------------------------------------
211 */
XMF_Prepare(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)212 static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
213 {
214     S_XMF_DATA* pXMFData;
215     EAS_RESULT result;
216 
217     /* parse DLS collection */
218     pXMFData = (S_XMF_DATA*) pInstData;
219     if (pXMFData->dlsOffset != 0)
220     {
221         if ((result = DLSParser(pEASData->hwInstData, pXMFData->fileHandle, pXMFData->dlsOffset, &pXMFData->pDLS)) != EAS_SUCCESS)
222         {
223             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error converting XMF DLS data\n"); */ }
224             return result;
225         }
226     }
227 
228     /* Prepare the SMF parser */
229     if ((result = SMF_Prepare(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS)
230         return result;
231 
232     /* if no DLS file, skip this step */
233     if (pXMFData->pDLS == NULL)
234         return EAS_SUCCESS;
235 
236     /* tell the synth to use the DLS collection */
237     result = VMSetDLSLib(((S_SMF_DATA*) pXMFData->pSMFData)->pSynth, pXMFData->pDLS);
238     if (result == EAS_SUCCESS)
239     {
240         DLSAddRef(pXMFData->pDLS);
241         VMInitializeAllChannels(pEASData->pVoiceMgr, ((S_SMF_DATA*) pXMFData->pSMFData)->pSynth);
242     }
243     return result;
244 }
245 
246 /*----------------------------------------------------------------------------
247  * XMF_Time()
248  *----------------------------------------------------------------------------
249  * Purpose:
250  * Returns the time of the next event in msecs
251  *
252  * Inputs:
253  * pEASData         - pointer to overall EAS data structure
254  * handle           - pointer to file handle
255  * pTime            - pointer to variable to hold time of next event (in msecs)
256  *
257  * Outputs:
258  *
259  *
260  * Side Effects:
261  *
262  *----------------------------------------------------------------------------
263 */
XMF_Time(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_U32 * pTime)264 static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
265 {
266     return SMF_Time(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pTime);
267 }
268 
269 /*----------------------------------------------------------------------------
270  * XMF_Event()
271  *----------------------------------------------------------------------------
272  * Purpose:
273  * Parse the next event in the file
274  *
275  * Inputs:
276  * pEASData         - pointer to overall EAS data structure
277  * handle           - pointer to file handle
278  *
279  * Outputs:
280  *
281  *
282  * Side Effects:
283  *
284  *----------------------------------------------------------------------------
285 */
XMF_Event(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_INT parserMode)286 static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
287 {
288     return SMF_Event(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, parserMode);
289 }
290 
291 /*----------------------------------------------------------------------------
292  * XMF_State()
293  *----------------------------------------------------------------------------
294  * Purpose:
295  * Returns the current state of the stream
296  *
297  * Inputs:
298  * pEASData         - pointer to overall EAS data structure
299  * handle           - pointer to file handle
300  * pState           - pointer to variable to store state
301  *
302  * Outputs:
303  *
304  *
305  * Side Effects:
306  *
307  *----------------------------------------------------------------------------
308 */
XMF_State(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 * pState)309 static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
310 {
311     return SMF_State(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pState);
312 }
313 
314 /*----------------------------------------------------------------------------
315  * XMF_Close()
316  *----------------------------------------------------------------------------
317  * Purpose:
318  * Close the file and clean up
319  *
320  * Inputs:
321  * pEASData         - pointer to overall EAS data structure
322  * handle           - pointer to file handle
323  *
324  * Outputs:
325  *
326  *
327  * Side Effects:
328  *
329  *----------------------------------------------------------------------------
330 */
XMF_Close(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)331 static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
332 {
333     S_XMF_DATA* pXMFData;
334     EAS_RESULT result;
335 
336     pXMFData = (S_XMF_DATA *)pInstData;
337 
338     /* close the SMF stream, it will close the file handle */
339     if ((result = SMF_Close(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS)
340         return result;
341 
342     if (pXMFData->pDLS)
343         DLSCleanup(pEASData->hwInstData, pXMFData->pDLS);
344 
345     /* if using dynamic memory, free it */
346     if (!pEASData->staticMemoryModel)
347     {
348         /* free the instance data */
349         EAS_HWFree(pEASData->hwInstData, pXMFData);
350     }
351 
352     return EAS_SUCCESS;
353 }
354 
355 /*----------------------------------------------------------------------------
356  * XMF_Reset()
357  *----------------------------------------------------------------------------
358  * Purpose:
359  * Reset the sequencer. Used for locating backwards in the file.
360  *
361  * Inputs:
362  * pEASData         - pointer to overall EAS data structure
363  * handle           - pointer to file handle
364  *
365  * Outputs:
366  *
367  *
368  * Side Effects:
369  *
370  *----------------------------------------------------------------------------
371 */
XMF_Reset(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)372 static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
373 {
374     return SMF_Reset(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
375 }
376 
377 /*----------------------------------------------------------------------------
378  * XMF_Pause()
379  *----------------------------------------------------------------------------
380  * Purpose:
381  * Pauses the sequencer. Mutes all voices and sets state to pause.
382  *
383  * Inputs:
384  * pEASData         - pointer to overall EAS data structure
385  * handle           - pointer to file handle
386  *
387  * Outputs:
388  *
389  *
390  * Side Effects:
391  *
392  *----------------------------------------------------------------------------
393 */
XMF_Pause(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)394 static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
395 {
396     return SMF_Pause(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
397 }
398 
399 /*----------------------------------------------------------------------------
400  * XMF_Resume()
401  *----------------------------------------------------------------------------
402  * Purpose:
403  * Resume playing after a pause, sets state back to playing.
404  *
405  * Inputs:
406  * pEASData         - pointer to overall EAS data structure
407  * handle           - pointer to file handle
408  *
409  * Outputs:
410  *
411  *
412  * Side Effects:
413  *
414  *----------------------------------------------------------------------------
415 */
XMF_Resume(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)416 static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
417 {
418     return SMF_Resume(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData);
419 }
420 
421 /*----------------------------------------------------------------------------
422  * XMF_SetData()
423  *----------------------------------------------------------------------------
424  * Purpose:
425  * Sets the playback rate of the underlying SMF file
426  *
427  * Inputs:
428  * pEASData         - pointer to overall EAS data structure
429  * handle           - pointer to file handle
430  * rate             - rate (28-bit fraction)
431  *
432  * Outputs:
433  *
434  *
435  * Side Effects:
436  *
437  *----------------------------------------------------------------------------
438 */
XMF_SetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 value)439 static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
440 {
441     return SMF_SetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, value);
442 }
443 
444 /*----------------------------------------------------------------------------
445  * XMF_GetData()
446  *----------------------------------------------------------------------------
447  * Purpose:
448  * Gets the file type
449  *
450  * Inputs:
451  * pEASData         - pointer to overall EAS data structure
452  * handle           - pointer to file handle
453  * rate             - rate (28-bit fraction)
454  *
455  * Outputs:
456  *
457  *
458  * Side Effects:
459  *
460  *----------------------------------------------------------------------------
461 */
XMF_GetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 * pValue)462 static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
463 {
464     EAS_RESULT result;
465 
466     /* call SMF parser to get value */
467     if ((result = SMF_GetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, pValue)) != EAS_SUCCESS)
468         return result;
469 
470     /* special case for file type */
471     if (param == PARSER_DATA_FILE_TYPE)
472     {
473         if (*pValue == EAS_FILE_SMF0)
474             *pValue = EAS_FILE_XMF0;
475         else if (*pValue == EAS_FILE_SMF1)
476             *pValue = EAS_FILE_XMF1;
477     }
478 
479     return EAS_SUCCESS;
480 }
481 
482 /*----------------------------------------------------------------------------
483  * XMF_FindFileContents()
484  *----------------------------------------------------------------------------
485  * Purpose:
486  * Finds SMF data and DLS data in XMF file, and remembers offset for each.
487  * If more than one is found, uses the first one found of each.
488  * Makes assumptions about the format of a mobile XMF file
489  *
490  * Inputs:
491  * pEASData         - pointer to overall EAS data structure
492  * pXMFData         - pointer to XMF parser instance data
493  * handle           - pointer to file handle
494  *
495  * Outputs:
496  *
497  *
498  * Side Effects:
499  *
500  *----------------------------------------------------------------------------
501 */
XMF_FindFileContents(EAS_HW_DATA_HANDLE hwInstData,S_XMF_DATA * pXMFData)502 static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData)
503 {
504     EAS_RESULT result;
505     EAS_I32 value;
506     EAS_I32 length;
507     EAS_I32 node_depth = 0 ;
508 
509     /* initialize offsets */
510     pXMFData->dlsOffset = pXMFData->midiOffset = 0;
511 
512     /* read file length, ignore it for now */
513     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS)
514         return result;
515 
516     /* read MetaDataTypesTable length and skip over it */
517     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS)
518         return result;
519     if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, value)) != EAS_SUCCESS)
520         return result;
521 
522     /* get TreeStart offset and jump to it */
523     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS)
524         return result;
525     if ((result = XMF_ReadNode(hwInstData, pXMFData, value, &length, node_depth)) != EAS_SUCCESS)
526         return result;
527 
528     /* check for SMF data */
529     if (pXMFData->midiOffset == 0)
530     {
531         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ }
532         return EAS_ERROR_FILE_FORMAT;
533     }
534 
535     /* check for SFM in wrong order */
536     if ((pXMFData->dlsOffset > 0) && (pXMFData->midiOffset < pXMFData->dlsOffset))
537         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS data must precede SMF data in Mobile XMF file\n"); */ }
538 
539     return EAS_SUCCESS;
540 }
541 
542 /*----------------------------------------------------------------------------
543  * XMF_ReadNode()
544  *----------------------------------------------------------------------------
545  * Purpose:
546  *
547  * Inputs:
548  *
549  * Outputs:
550  *
551  *
552  * Side Effects:
553  *
554  *----------------------------------------------------------------------------
555 */
XMF_ReadNode(EAS_HW_DATA_HANDLE hwInstData,S_XMF_DATA * pXMFData,EAS_I32 nodeOffset,EAS_I32 * pLength,EAS_I32 depth)556 static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength, EAS_I32 depth)
557 {
558     EAS_RESULT result;
559     EAS_I32 refType;
560     EAS_I32 numItems;
561     EAS_I32 offset;
562     EAS_I32 length;
563     EAS_I32 headerLength;
564     EAS_U32 chunkType;
565 
566     /* check the depth of current node*/
567     if ( depth > 100 )
568         return EAS_ERROR_FILE_FORMAT;
569 
570     /* seek to start of node */
571     if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset)) != EAS_SUCCESS)
572         return result;
573 
574     /* get node length */
575     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, pLength)) != EAS_SUCCESS)
576         return result;
577 
578     /* get number of contained items */
579     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &numItems)) != EAS_SUCCESS)
580         return result;
581 
582     /* get node header length */
583     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &headerLength)) != EAS_SUCCESS)
584         return result;
585 
586     /* get metadata length */
587     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &length)) != EAS_SUCCESS)
588         return result;
589 
590     /* get the current location */
591     if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
592         return result;
593 
594     if (offset - nodeOffset > headerLength)
595         return EAS_FAILURE;
596 
597     /* skip to node contents */
598     if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset + headerLength)) != EAS_SUCCESS)
599         return result;
600 
601     /* get reference type */
602     if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &refType)) != EAS_SUCCESS)
603         return result;
604 
605     /* get the current location */
606     if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
607         return result;
608 
609     /* process file node */
610     if (numItems == 0)
611 
612     {
613         /* if in-file resource, find out where it is and jump to it */
614         if (refType == 2)
615         {
616             if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS)
617                 return result;
618             offset += pXMFData->fileOffset;
619             if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS)
620                 return result;
621         }
622 
623         /* or else it must be an inline resource */
624         else if (refType != 1)
625         {
626             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected reference type %d\n", refType); */ }
627             return EAS_ERROR_FILE_FORMAT;
628         }
629 
630         /* get the chunk type */
631         if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS)
632             return result;
633 
634         /* found a RIFF chunk, check for DLS type */
635         if (chunkType == XMF_RIFF_CHUNK)
636         {
637             /* skip length */
638             if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, sizeof(EAS_I32))) != EAS_SUCCESS)
639                 return result;
640 
641             /* get RIFF file type */
642             if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS)
643                 return result;
644             if (chunkType == XMF_RIFF_DLS)
645                 pXMFData->dlsOffset = offset;
646         }
647 
648         /* found an SMF chunk */
649         else if (chunkType == XMF_SMF_CHUNK)
650             pXMFData->midiOffset = offset;
651     }
652 
653     /* folder node, process the items in the list */
654     else
655     {
656         for ( ; numItems > 0; numItems--)
657         {
658             /* process this item */
659             if (offset <= nodeOffset) {
660                 ALOGE("b/36725407: parser did not advance");
661                 return EAS_ERROR_FILE_FORMAT;
662             }
663 
664             if ((result = XMF_ReadNode(hwInstData, pXMFData, offset, &length, depth+1)) != EAS_SUCCESS)
665                 return result;
666 
667             /* seek to start of next item */
668             offset += length;
669             if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS)
670                 return result;
671         }
672     }
673 
674     return EAS_SUCCESS;
675 }
676 
677 #if 0
678 /*----------------------------------------------------------------------------
679  * XMF_FindFileContents()
680  *----------------------------------------------------------------------------
681  * Purpose:
682  * Finds SMF data and DLS data in XMF file, and remembers offset for each.
683  * If more than one is found, uses the first one found of each.
684  * Makes assumptions about the format of a mobile XMF file
685  *
686  * Inputs:
687  * pEASData         - pointer to overall EAS data structure
688  * pXMFData         - pointer to XMF parser instance data
689  * handle           - pointer to file handle
690  *
691  * Outputs:
692  *
693  *
694  * Side Effects:
695  *
696  *----------------------------------------------------------------------------
697 */
698 static EAS_RESULT XMF_FindFileContents(S_EAS_DATA *pEASData, S_XMF_DATA *pXMFData, EAS_FILE_HANDLE fileHandle)
699 {
700     EAS_RESULT result;
701     EAS_I32 offset;
702     EAS_I32 value;
703     EAS_I32 numItems;
704     EAS_I32 length;
705     EAS_CHAR id[4];
706     EAS_I32 location;
707 
708     /* init dls offset, so that we know we haven't found a dls chunk yet */
709     pXMFData->dlsOffset = 0;
710 
711     /* read file length, ignore it for now */
712     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
713         return result;
714 
715     /* read MetaDataTypesTable length and skip over it */
716     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
717         return result;
718     if ((result = EAS_HWFileSeekOfs(pEASData, fileHandle, value)) != EAS_SUCCESS)
719         return result;
720 
721     /* get TreeStart offset and jump to it */
722     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &offset)) != EAS_SUCCESS)
723         return result;
724     if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS)
725         return result;
726 
727     /* read node length, ignore it for now */
728     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
729         return result;
730 
731     /* read number of contained items */
732     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &numItems)) != EAS_SUCCESS)
733         return result;
734 
735     /*read node header length */
736     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
737         return result;
738 
739     /*go to the node offset */
740     if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS)
741         return result;
742 
743     /* read Reference Type */
744     if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
745         return result;
746 
747     /* make sure it is an in-line resource, for now */
748     if (value != 1)
749     {
750         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file tree\n"); */ }
751         return EAS_FAILURE;
752     }
753 
754     /* parse through the list of items */
755     while (numItems > 0)
756     {
757         /*get current offset */
758         if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &offset)) != EAS_SUCCESS)
759             return result;
760 
761         /*read node length */
762         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &length)) != EAS_SUCCESS)
763             return result;
764 
765         /* read number of items */
766         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
767             return result;
768 
769         /* make sure not a folder */
770         if (value != 0)
771         {
772             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ }
773             return EAS_FAILURE;
774         }
775 
776         /* read offset to resource and jump to it */
777         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
778             return result;
779         if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS)
780             return result;
781 
782         /* read Reference Type */
783         if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS)
784             return result;
785 
786         /* make sure it is an in-line resource */
787         if (value != 1)
788         {
789             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ }
790             return EAS_FAILURE;
791         }
792 
793         /* get current offset as a possible location for SMF file or DLS file */
794         if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &location)) != EAS_SUCCESS)
795             return result;
796 
797         /* read four bytes */
798         if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, id, sizeof(id), &value)) != EAS_SUCCESS)
799             return result;
800 
801         /* check if DLS */
802         if (pXMFData->dlsOffset == 0 && id[0] == 'R' && id[1] == 'I' && id[2] == 'F' && id[3] == 'F')
803         {
804             //remember offset
805             pXMFData->dlsOffset = location;
806         }
807 
808         /* else check if SMF */
809         else if (id[0] == 'M' && id[1] == 'T' && id[2] == 'h' && id[3] == 'd')
810         {
811             //remember offset
812             pXMFData->midiOffset = location;
813 
814             //we are done
815             return EAS_SUCCESS;
816         }
817 
818         //one less item
819         numItems--;
820 
821         //if more data, go to the next item
822         if (numItems >0)
823         {
824             if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + length)) != EAS_SUCCESS)
825                 return result;
826         }
827     }
828 
829     return EAS_FAILURE;
830 
831 }
832 #endif
833 
834 /*----------------------------------------------------------------------------
835  * XMF_ReadVLQ()
836  *----------------------------------------------------------------------------
837  * Purpose:
838  * Reads a VLQ encoded value from the file referenced by fileHandle
839  *
840  * Inputs:
841  * pEASData         - pointer to overall EAS data structure
842  * fileHandle       - pointer to file handle
843  *
844  * Outputs:
845  * value            - pointer to the value decoded from the VLQ data
846  *
847  *
848  * Side Effects:
849  *
850  *----------------------------------------------------------------------------
851 */
XMF_ReadVLQ(EAS_HW_DATA_HANDLE hwInstData,EAS_FILE_HANDLE fileHandle,EAS_I32 * value)852 static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value)
853 {
854     EAS_RESULT result;
855     EAS_U8 c;
856 
857     *value = 0;
858 
859     if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
860         return result;
861 
862     while (c > 0x7F)
863     {
864         /*lint -e{703} shift for performance */
865         *value = (*value << 7) | (c & 0x7F);
866 
867         if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
868             return result;
869     }
870 
871     /*lint -e{703} shift for performance */
872     *value = (*value << 7) | c;
873 
874     return EAS_SUCCESS;
875 }
876 
877