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