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