I'm currently taking another look at those pesky XMA files from Electronic arts, namely from Battlefield: Hardline. ea_multi_xma.exe from HCS doesn't work on these so I tried to write my own parser but strangely it doesn't work.
So here's my work-in-progress. This is an example file: http://*USE_ANOTHER_FILEHOSTING*/3408d63 ... 78/test.7z
. For testing purposes I've manually split the file into the two streams that are present and began testing with the first one. The structure of these streams is fairly simple:
(big endian)
0x00 - 4800000C long
0x04 - channel count
0x06 - frequency short
0x08 - number of samples
0x0c - END - stream structure:
short: 0x4400 - new block marker, 0x4500 stop marker
short: length of block
longlong: dummy (or something else?)
length_of_block - 0xc: stream data
To parse the blocks you just write the stream data and fill the block up to the next 0x800 multiple with zeros to get a complete XMA2 block. Afterwards it should be parsable with xma_parse. However the parsing stops at around 63kb and this is where it gets interesting: This very block has a wrong size (8 bytes short) so I've coded in a workaround that writes the missing 8 bytes into the block but to no avail: parsing stops at this block, no matter if I leave the additional bytes or discard them.
Here is the in-progress script I wrote:
Code: Select all
idstring \x48\x0\x0\xC
endian big
get UNK short
get FREQ short
get UNK long
callfunction getlayers 1
set LAYERS 1
for k = 1 <= LAYERS
   log MEMORY_FILE 0 0
   set OFFSET 0xc
   for i = 1
      goto OFFSET
      get TEST short
      if   TEST == 0x4500 # end marker
         callfunction wrapup 1
      endif
      get SIZE short
      math SIZE -= 0xc
      get DUMMY longlong
      savepos OFFSET
      set BIAS 0
      set ADJUST OFFSET
      math ADJUST += SIZE
      goto ADJUST
      get TEST short
      if TEST == 0x4400
      elif TEST == 0x4500
      else
         goto ADJUST
         do
            get TEST byte
            get DUMMY2 threebyte
            savepos SIZE2
         while TEST != 0x44
         xmath BIAS "SIZE2 - 4 - OFFSET - SIZE"
      endif
      callfunction write 1
      #set GO i
      #math GO %= LAYERS
      #if GO == k
      #   callfunction write 1
      #elif GO == 0
      #   if k == LAYERS
      #      callfunction write 1   
      #   endif
      #endif
      math OFFSET += SIZE
      math OFFSET += BIAS
   next i
next k
startfunction getlayers
   savepos MYOFF
   get DUMMY long
   set i 0
   do
      math i += 1
      get TEST short
      get DUMMY short
   while TEST == 0
   math i -= 1
   set LAYERS i
   goto MYOFF
endfunction
startfunction write
   goto OFFSET
   append
      log MEMORY_FILE OFFSET SIZE
   append
   get MSIZE asize MEMORY_FILE
   math MSIZE x= 0x800
   math MSIZE -= 1
   putVarChr MEMORY_FILE MSIZE 0 # write 0 at end of block
endfunction
startfunction wrapup
   get SIZE asize MEMORY_FILE
   get NAME basename
   string NAME += ".uxma"
   log NAME 0 SIZE MEMORY_FILE
   cleanexit
endfunctionAs you can see, I'm currently treating files as single layer as I don't know how to distinguish between single- and multi-layer files (thus "set LAYERS 1"). Anyway the outcome is the same. The block-commented section ("set GO i" and so on) is for multilayer files and still work-in-progress.
Ok, this is what I got, now I'll need some help. You can parse the res files to uxma but pasing isn't possible.
Anybody has the time and patience to take a look at this? That would be wonderful!
