# Traveller's Tales games DAT files extractor (script 0.7b)
#  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
#  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

quickbmsver "0.5.16c"
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

getdstring SIGN 4
goto 0
math ONE_FILE = 0
if SIGN == "LZ2K"
    math ONE_FILE = 1
elif SIGN == "DFLT"
    math ONE_FILE = 1
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
    get HDR_SIZE asize 1
    log MEMORY_FILE 0 HDR_SIZE 1
    get DUMMY long MEMORY_FILE
else
    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 long MEMORY_FILE
get FILES long MEMORY_FILE
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 <= 0xfffffffb
    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
for i = 0 < FILES
    get CRC long MEMORY_FILE
    putarray 0 i CRC
next i

if TYPE_BOH <= -2
    get DUMMY1 long MEMORY_FILE
    get DUMMY2 long MEMORY_FILE
    if DUMMY1 > 0
        print "Error: positive DUMMY1 not implemented yet, contact me"
        cleanexit
    endif
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
    do
        goto NAME_INFO MEMORY_FILE
        get NEXT short MEMORY_FILE
        get PREV short MEMORY_FILE
        get OFF long MEMORY_FILE
        if TYPE_BOH <= 0xfffffffb   # if NAME_FIELD_SIZE >= 12
            get DUMMY long MEMORY_FILE
        endif
        savepos NAME_INFO MEMORY_FILE

        math OFF += NAME_OFF
        goto OFF MEMORY_FILE
        get NAME string MEMORY_FILE

		# 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 NEXT & 0x8000    # 16bit sign conversion
            math NEXT |= -0x10000
        endif

        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

	getvarchr TMP0 FULLNAME 0
	if TMP0 == '\\'
		string FULLNAME <<= 1
	endif
	
    if NAMELESS == 0
        math CRC = 0x811c9dc5
        strlen NAMESZ FULLNAME
        for j = 0 < NAMESZ
            getvarchr CHR FULLNAME j
            if CHR >= 0x61
                if CHR <= 0x7a
                    math CHR -= 0x20
                endif
            endif
            #if CHR == 0x2f      # /
            #    math CHR = 0x5c # \
            #endif
            math CRC ^= CHR
            math CRC *= 0x199933
        next j
        math CRC &= 0xffffffff
        for j = 0 < FILES
            getarray TMP 0 j
            if CRC == TMP
                break
            endif
        next j
        if j >= FILES
            print "Alert: the crc of the file %FULLNAME% has not been found, I extract the current file"
            #cleanexit
            # all wrongs!
            math j = i
            #math TMP = NEXT
            #math j = 0
            #math j -= NEXT
            #math j -= 1
        endif
        math TMP = j
    else
        math TMP = i
        set FULLNAME string ""
    endif

    math TMP *= 16
    math TMP += INFO_OFF
    goto TMP 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
    math OFFSET <<= 8
    math OFFSET += OFFSET2

    goto OFFSET
    getdstring SIGN 4
    if SIGN == "LZ2K"
        set PACKED long 2
    elif SIGN == "DFLT"
        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
next i


startfunction UNPACK
    putvarchr MEMORY_FILE2 SIZE 0
    log MEMORY_FILE2 0 0
    append
    for TMPSZ = 0 < ZSIZE
        goto OFFSET
        getdstring SIGN 4
        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
        else
            print "Error: the signature at offset %OFFSET% (%SIGN%) is not LZ2K, 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
        math OFFSET += CHUNK_ZSIZE
        savepos TMP MEMORY_FILE2
        math TMPSZ += 12
        math TMPSZ += CHUNK_ZSIZE
    next
    append
endfunction

