# Traveller's Tales games DAT files extractor (script 0.9.11a) # Lego Movie: The Video Game # LEGO Batman 1 # LEGO Batman 2 # LEGO Star Wars # LEGO Star Wars III # LEGO Indiana Jones # LEGO Harry Potter # LEGO Pirates of the Caribbean # LEGO Lord of the Rings # Transformers # LEGO Worlds # LEGO MARVELs Avengers # LEGO Dimensions # Lego Marvel Super Heroes # Lego Star Wars: The Force Awakens # Lego NinjaGO # others, check them on http://www.ttgames.com # # In case of problems with the extraction try setting NAMELESS to 1 # thanx to who fixed the handling of the names! # # Note that the script may not work with the compressed files of # Lego Movie for PS3, in case of crashes or other issues you can # extract only the non compressed files by setting # EXTRACT_COMPRESSED to 0. # # script for QuickBMS http://quickbms.aluigi.org math FORCE_CRC_BITS = 0 # use 32, 64 or 0 for auto-guess, just in case auto-guess fails quickbmsver "0.8.0" set NAMELESS long 0 # set to 1 to extract the files without names set EXTRACT_COMPRESSED long 1 # set to 0 to extract ONLY the non-compressed files math HAVE_CRCS = 0 math CRC_FNV_OFFSET = 0x811c9dc5 math CRC_FNV_PRIME = 0x199933 set SIGN_1234567a binary "\x7a\x56\x34\x12" getdstring SIGN 4 goto 0 if SIGN u== SIGN_1234567a goto 0 callfunction EXTRACT_1234567a 1 cleanexit endif string SIGN f SIGN math ONE_FILE = 0 if SIGN == "LZ2K" math ONE_FILE = 1 elif SIGN == "DFLT" math ONE_FILE = 1 elif SIGN == "ZLIB" # currently doesn't exist math ONE_FILE = 1 elif SIGN == "LZMA" # currently doesn't exist math ONE_FILE = 1 elif SIGN == "ZIPX" math ONE_FILE = 1 elif SIGN == "RFPK" math ONE_FILE = 1 elif SIGN == "RNC_" math ONE_FILE = 1 elif SIGN == "Defl" # "Deflate_v1.0" goto 0 math OFFSET = 0 get SIZE asize get NAME basename get EXT extension string NAME + "_unpack." string NAME + EXT callfunction DEFLATE_UNPACK 1 cleanexit endif if ONE_FILE != 0 math OFFSET = 0 get ZSIZE asize math SIZE = ZSIZE callfunction UNPACK log "" 0 SIZE MEMORY_FILE2 cleanexit endif get HDR_NAME basename string HDR_NAME += ".hdr" open FDSE HDR_NAME 1 EXISTS if EXISTS != 0 get NAME filename if NAME == HDR_NAME get NAME basename string NAME += ".dat" open FDSE NAME endif callfunction HANDLE_COMPRESSED_DAT 1 get HDR_SIZE asize 1 log MEMORY_FILE 0 HDR_SIZE 1 get DUMMY long MEMORY_FILE else callfunction HANDLE_COMPRESSED_DAT 1 get INFO_OFF long if INFO_OFF & 0x80000000 math INFO_OFF ^= 0xffffffff math INFO_OFF <<= 8 math INFO_OFF += 0x100 endif get INFO_SIZE long log MEMORY_FILE INFO_OFF INFO_SIZE endif get TYPE_BOH signed_long MEMORY_FILE get FILES long MEMORY_FILE math NEW_FORMAT = 1 if TYPE_BOH != 0x3443432e # game.hdr if TYPE_BOH != 0x2e434334 if FILES != 0x3443432e # game.dat if FILES != 0x2e434334 math NEW_FORMAT = 0 endif endif endif endif if NEW_FORMAT == 1 # ".CC400TAD" goto 0 MEMORY_FILE endian big get HDR_SIZE long MEMORY_FILE idstring MEMORY_FILE ".CC4" idstring MEMORY_FILE "0TAD" get TYPE_BOH signed_long MEMORY_FILE # -8 get NEW_FORMAT_VER long MEMORY_FILE # 1 get FILES long MEMORY_FILE get NAMES long MEMORY_FILE get NAMES_SIZE long MEMORY_FILE savepos NAMES_OFF MEMORY_FILE math OFFSET = NAMES_OFF math OFFSET + NAMES_SIZE goto OFFSET MEMORY_FILE putarray 10 NAMES "" # necessary and useful putarray 1 NAMES "" # necessary and useful get DUMMY long MEMORY_FILE math MYID = 0 xmath LAST_NAME_WORKAROUND "NAMES - 1" for i = 0 < NAMES get NAME_OFF long MEMORY_FILE get FOLDER_ID short MEMORY_FILE if NEW_FORMAT_VER >= 2 get DUMMY_ID short MEMORY_FILE endif get SOME_ID signed_short MEMORY_FILE get FILE_ID short MEMORY_FILE if NAME_OFF != 0xffffffff savepos TMP MEMORY_FILE math NAME_OFF + NAMES_OFF goto NAME_OFF MEMORY_FILE get NAME string MEMORY_FILE goto TMP MEMORY_FILE # I will find a solution another day maybe... if i == LAST_NAME_WORKAROUND math FILE_ID = MYID endif getarray PATH 1 FOLDER_ID string NAME p "%s\%s" PATH NAME if FILE_ID != 0 putarray 10 MYID NAME math MYID + 1 else putarray 1 i NAME endif endif next i get TYPE_BOH signed_long MEMORY_FILE # -8 get FILES long MEMORY_FILE # performance putarray 2 FILES 0 putarray 3 FILES 0 putarray 4 FILES 0 putarray 5 FILES 0 for i = 0 < FILES if TYPE_BOH <= -11 get OFFSET longlong MEMORY_FILE else get OFFSET long MEMORY_FILE endif get ZSIZE long MEMORY_FILE get SIZE long MEMORY_FILE if TYPE_BOH <= -10 math PACKED = SIZE math SIZE & 0x7fffffff math PACKED u>> 31 if PACKED != 0 math PACKED = 2 # useless, but we need & 2 endif else get PACKED byte MEMORY_FILE get ZERO short MEMORY_FILE get OFFSET2 byte MEMORY_FILE math OFFSET u<< 8 math OFFSET | OFFSET2 endif putarray 2 i OFFSET putarray 3 i ZSIZE putarray 4 i SIZE putarray 5 i PACKED next i callfunction GET_CRCS 1 get EXT extension if EXT & "DAT" # both DAT and DAT2 else open FDDE "DAT" # in case HDR has been opened endif for i = 0 < FILES getarray FULLNAME 10 i callfunction GET_NAME 1 getarray OFFSET 2 IDX getarray ZSIZE 3 IDX getarray SIZE 4 IDX getarray PACKED 5 IDX callfunction EXTRACT_FILE 1 next i else savepos INFO_OFF MEMORY_FILE math TMP = FILES math TMP *= 16 math NAME_INFO = INFO_OFF math NAME_INFO += TMP goto NAME_INFO MEMORY_FILE get NAMES long MEMORY_FILE savepos NAME_INFO MEMORY_FILE math NAME_FIELD_SIZE = 8 if TYPE_BOH <= -5 math NAME_FIELD_SIZE = 12 endif math TMP = NAMES math TMP *= NAME_FIELD_SIZE math NAME_OFF = NAME_INFO math NAME_OFF += TMP goto NAME_OFF MEMORY_FILE get NAMECRC_OFF long MEMORY_FILE savepos NAME_OFF MEMORY_FILE math NAMECRC_OFF += NAME_OFF goto NAMECRC_OFF MEMORY_FILE callfunction GET_CRCS 1 if TYPE_BOH <= -2 get DUMMY1 signed_long MEMORY_FILE get DUMMY2 long MEMORY_FILE endif # print "files: %FILES%" # print "names: %NAMES%" # print "info_off: %INFO_OFF%" # print "info_size: %INFO_SIZE%" # print "name_info: %NAME_INFO%" # print "name_off: %NAME_OFF%" # print "namecrc_off: %NAMECRC_OFF%" set NAMEZ long 0 set FULLNAME string "" set FULLPATH string "" for i = 0 < FILES callfunction SET_NAME 1 callfunction GET_NAME 1 math IDX *= 16 math IDX += INFO_OFF goto IDX MEMORY_FILE get OFFSET long MEMORY_FILE get ZSIZE long MEMORY_FILE get SIZE long MEMORY_FILE get PACKED threebyte MEMORY_FILE get OFFSET2 byte MEMORY_FILE if TYPE_BOH == -1 # do nothing else math OFFSET <<= 8 endif math OFFSET += OFFSET2 callfunction EXTRACT_FILE 1 next i endif startfunction GET_CRCS math HAVE_CRCS = 0 putarray 0 FILES 0 putarray 11 FILES 0 get TMP1 asize MEMORY_FILE savepos TMP2 MEMORY_FILE if TMP2 u< TMP1 xmath TMP4 "TMP2 + (FILES * 4)" xmath TMP8 "TMP2 + (FILES * 8)" savepos TMP MEMORY_FILE goto TMP4 MEMORY_FILE get ZERO long MEMORY_FILE if ZERO == 0 # this is just a test because there is no good way to guess if it's 64 or 32bit math TMP8 = TMP1 # disable 64bit false positives endif goto TMP MEMORY_FILE math CRC_BITS = 32 if TMP8 u< TMP1 && NEW_FORMAT_VER >= 2 # Lego NinjaGo math CRC_BITS = 64 endif if FORCE_CRC_BITS >= 32 math CRC_BITS = FORCE_CRC_BITS endif if CRC_BITS == 64 callfunction QUICKBMS_4GB_CHECK 1 math CRC_FNV_OFFSET = 0xcbf29ce484222325 math CRC_FNV_PRIME = 1099511628211 math HAVE_CRCS = 2 for i = 0 < FILES get CRC longlong MEMORY_FILE putarray 0 i CRC putarray 11 i 0 # file has been extracted? next i elif TMP4 u< TMP1 # no need to check CRC_BITS == 32 math HAVE_CRCS = 1 for i = 0 < FILES get CRC long MEMORY_FILE putarray 0 i CRC putarray 11 i 0 # file has been extracted? next i endif endif if HAVE_CRCS == 0 for i = 0 < FILES putarray 0 i 0 putarray 11 i 0 # file has been extracted? next i endif endfunction startfunction EXTRACT_FILE endian little # necessary, they are little endian on big endian archives too goto OFFSET getdstring SIGN 4 string SIGN f SIGN if SIGN == "LZ2K" set PACKED long 2 elif SIGN == "DFLT" set PACKED long 3 elif SIGN == "ZLIB" set PACKED long 3 elif SIGN == "LZMA" set PACKED long 3 elif SIGN == "ZIPX" set PACKED long 3 elif SIGN == "RFPK" set PACKED long 3 elif SIGN == "RNC_" set PACKED long 3 else set PACKED long 0 endif if PACKED & 2 # includes both 2 and 3 if EXTRACT_COMPRESSED != 0 callfunction UNPACK log FULLNAME 0 SIZE MEMORY_FILE2 endif else if SIZE != 0 if ZSIZE != 0 if SIZE != ZSIZE print "SIZE (%SIZE%) and ZSIZE (%ZSIZE%) differ at offset %OFFSET|x%, contact me" cleanexit endif endif endif log FULLNAME OFFSET SIZE endif endfunction startfunction SET_NAME do goto NAME_INFO MEMORY_FILE get NEXT signed_short MEMORY_FILE get PREV signed_short MEMORY_FILE get OFF signed_long MEMORY_FILE if TYPE_BOH <= -5 # if NAME_FIELD_SIZE >= 12 get DUMMY long MEMORY_FILE endif savepos NAME_INFO MEMORY_FILE if OFF < 0 set NAME string "" else math OFF += NAME_OFF goto OFF MEMORY_FILE get NAME string MEMORY_FILE endif # used only for LEGO the game if you don't use the hdr file getvarchr TMP0 NAME 0 if TMP0 >= 0xf0 set NAME string "" endif #string NAME u= NAME # needed for the crc check, but doesn't improve performances so much if PREV != 0 getarray FULLPATH 1 PREV endif putarray 1 NAMEZ FULLPATH # putarray 1 NAMEZ NAME if NEXT > 0 # folder getarray TMP 1 PREV if TMP != "" # long story to avoid things like 2foldername that gives problems to QuickBMS set OLDNAME string \ # do not use / string OLDNAME += TMP string OLDNAME += \ # do not use / string FULLPATH >>= OLDNAME endif if NAME != "" #string FULLPATH += \ # do not use / string FULLPATH += NAME string FULLPATH += \ # do not use / endif endif math NAMEZ += 1 while NEXT > 0 set FULLNAME string FULLPATH string FULLNAME += NAME endfunction startfunction GET_CURRENT_NAME for j = 0 < FILES getarray TMP 11 j if TMP == 0 # the first file not extracted yet math IDX = j break endif next j endfunction startfunction GET_NAME if HAVE_CRCS == 0 callfunction GET_CURRENT_NAME 1 else getvarchr TMP0 FULLNAME 0 if TMP0 == '\\' string FULLNAME <<= 1 endif math IDX = i if NAMELESS == 0 strlen NAMESZ FULLNAME string FULLNAME u= FULLNAME string FULLNAME R= / \ math CRC = CRC_FNV_OFFSET for j = 0 < NAMESZ getvarchr CHR FULLNAME j math CRC ^= CHR math CRC *= CRC_FNV_PRIME next j if HAVE_CRCS <= 1 math CRC &= 0xffffffff # quickbms_4gb_files endif for j = 0 < FILES getarray TMP 0 j # CRC database if CRC == TMP math IDX = j break endif next j if j >= FILES print "Alert: the crc of the file %FULLNAME% has not been found, I extract the current file" callfunction GET_CURRENT_NAME 1 endif else set FULLNAME string "" endif endif putarray 11 IDX 1 # the file has been extracted endfunction startfunction UNPACK putvarchr MEMORY_FILE2 SIZE 0 log MEMORY_FILE2 0 0 append for TMPSZ = 0 < ZSIZE goto OFFSET getdstring SIGN 4 string SIGN f SIGN if SIGN == "LZ2K" comtype lz2k get CHUNK_SIZE long get CHUNK_ZSIZE long elif SIGN == "DFLT" comtype dflt get CHUNK_ZSIZE long get CHUNK_SIZE long elif SIGN == "ZLIB" # currently doesn't exist comtype zlib get CHUNK_ZSIZE long get CHUNK_SIZE long elif SIGN == "LZMA" # currently doesn't exist comtype lzma get CHUNK_ZSIZE long get CHUNK_SIZE long elif SIGN == "ZIPX" comtype deflate # ??? not tested get CHUNK_ZSIZE long get CHUNK_SIZE long string TMP = CHUNK_ZSIZE encryption rc4 TMP "" 0 4 elif SIGN == "RFPK" comtype rfpk get CHUNK_ZSIZE long get CHUNK_SIZE long elif SIGN == "RNC_" comtype rnc math CHUNK_SIZE = SIZE math CHUNK_ZSIZE = ZSIZE goto OFFSET else print "Error: the compressing signature at offset %OFFSET% (%SIGN%) is not known, contact me" cleanexit endif savepos OFFSET if CHUNK_ZSIZE == CHUNK_SIZE log MEMORY_FILE2 OFFSET CHUNK_SIZE else clog MEMORY_FILE2 OFFSET CHUNK_ZSIZE CHUNK_SIZE endif encryption "" "" math OFFSET += CHUNK_ZSIZE savepos TMP MEMORY_FILE2 math TMPSZ += 12 math TMPSZ += CHUNK_ZSIZE next append endfunction startfunction HANDLE_COMPRESSED_DAT goto 0 getdstring TMP 16 if TMP == "CMP2CMP2CMP2CMP2" comtype lzma getdstring DAT_HASH 16 get DAT_SIZE longlong savepos DAT_OFFSET get DAT_ZSIZE asize math DAT_ZSIZE - DAT_OFFSET clog TEMPORARY_FILE DAT_OFFSET DAT_ZSIZE DAT_SIZE open "." TEMPORARY_FILE endif goto 0 endfunction startfunction EXTRACT_1234567a idstring "\x7a\x56\x34\x12" # 0x1234567a get FILES long get PAK_SIZE long get CRC long get ZERO long get ZERO long for i = 0 < FILES get NAME_OFF long get OFFSET long get SIZE long get DUMMY long # it's ever 4 in any case get ZERO long get CRC long get ZERO long savepos TMP_OFF goto NAME_OFF get NAME string goto OFFSET callfunction DEFLATE_UNPACK 1 goto TMP_OFF next i endfunction startfunction DEFLATE_UNPACK getdstring SIGN 0x20 if SIGN == "Deflate_v1.0" comtype dflt get XSIZE long math OFFSET + 0x24 math SIZE - 0x24 clog NAME OFFSET SIZE XSIZE else log NAME OFFSET SIZE endif endfunction startfunction QUICKBMS_4GB_CHECK math TMP64 = 0x10000000 math TMP64 * 16 if TMP64 == 0 print "you must use quickbms_4gb_files.exe with this archive" cleanexit endif endfunction