Exemplo n.º 1
0
 def load(filepath):
     reader = binary.BinaryReader(filename = filepath)
     tempName = filepath.split("//")[-1]
     if tempName == "":
         print("Warning: Invalid filename!")
         tempName = "NULL"
     return File(name=tempName, data=reader.data)
Exemplo n.º 2
0
    def load(self, data):
        def getBankString(reader, offsetString):
            bankString = {}
            reader.seek(offsetString)
            while reader.hasDataRemaining():
                index = reader.tell() - offsetString
                bankString[index] = reader.readNullTerminatedString(
                    'shift-jis')
                reader.seek(1, 1)
            return bankString

        def getBankOperand(reader, offsetOperands, countOperands, bankString):
            reader.seek(offsetOperands)
            bankOperands = {}
            for indexOperand in range(countOperands):
                tempOperandType = reader.readUInt(1)
                if tempOperandType == 0:
                    tempOperand = reader.readS4()
                elif tempOperandType == 1:
                    tempOperand = reader.readF4()
                elif tempOperandType == 2:
                    tempOperand = bankString[reader.readU4()]
                else:
                    tempOperand = reader.read(4)
                bankOperands[indexOperand] = Operand(tempOperandType,
                                                     tempOperand)
            return bankOperands

        def populateInstructionOperands(bankOperands):
            for command in self.commands:
                for indexInstruction in range(
                        command.indexOperandsStart,
                        command.indexOperandsStart + command.countOperands):
                    command.operands.append(bankOperands[indexInstruction])

        reader = binary.BinaryReader(data=data)
        if reader.read(4) == b'LSCR':
            countCommand = reader.readU2()
            countOperands = 0
            offsetHeader = reader.readU2()
            offsetOperands = reader.readU4()
            offsetString = reader.readU4()

            bankString = getBankString(reader, offsetString)

            reader.seek(offsetHeader)
            for indexCommand in range(countCommand):
                self.commands.append(FutureInstruction.fromData(
                    reader.read(8)))
                countOperands = max(
                    countOperands,
                    self.commands[indexCommand].indexOperandsStart +
                    self.commands[indexCommand].countOperands)

            bankOperand = getBankOperand(reader, offsetOperands, countOperands,
                                         bankString)
            populateInstructionOperands(bankOperand)
            return True
        return False
Exemplo n.º 3
0
    def compressRle(self, addHeader=False):
        writer = binary.BinaryWriter()
        reader = binary.BinaryReader(data = self.data)

        tempCompressedByte = b''
        tempCompressedByteLength = 0
        tempUncompressedSection = bytearray(b'')
        compressRepetition = False

        def getRleFlagByte(isCompressed, length):
            if isCompressed:
                return (0x80 | (length - 3)).to_bytes(1, byteorder = 'little')          # Enable MSB compression flag
            return (length - 1).to_bytes(1, byteorder = 'little')
        
        def writeData():
            if len(tempUncompressedSection) > 0:
                writer.write(getRleFlagByte(False, len(tempUncompressedSection)) + tempUncompressedSection)
            if tempCompressedByteLength > 0:
                writer.write(getRleFlagByte(True, tempCompressedByteLength) + tempCompressedByte)
        
        while reader.hasDataRemaining():
            tempByte = reader.read(1)
            if compressRepetition:
                if tempByte == tempCompressedByte:
                    tempCompressedByteLength += 1
                if tempCompressedByteLength == 130 or tempByte != tempCompressedByte:   # If max size has been reached or there's no more repetition
                    compressRepetition = False
                    if tempCompressedByteLength < 3:                                    # Free data if compression won't do much
                        tempUncompressedSection.extend((tempCompressedByte * tempCompressedByteLength) + tempByte)
                    else:                                                               # Else, write uncompressed section, then compressed data
                        writeData()
                        if tempByte == tempCompressedByte:                              # If the compression ended because the max block size was met,
                            tempUncompressedSection = bytearray(b'')                    #     reinitiate the uncompressed section.
                        else:
                            tempUncompressedSection = bytearray(tempByte)               # Else, continue the uncompressed section as normal.
                    tempCompressedByteLength = 0
            else:
                tempUncompressedSection.extend(tempByte)
                if len(tempUncompressedSection) == 128:                                 # Reinitiate block if max size met
                    writeData()
                    tempUncompressedSection = bytearray(b'')
                elif len(tempUncompressedSection) > 1 and tempUncompressedSection[-2] == tempUncompressedSection[-1]:
                    tempCompressedByte = tempByte
                    tempCompressedByteLength = 2
                    compressRepetition = True
                    tempUncompressedSection = tempUncompressedSection[0:-2]
        # Write anything left, as there may be blocks remaining after the reader ran out of data
        writeData()
        if addHeader:
            self.data = bytearray(File.LAYTON_1_COMPRESSION[File.COMP_RLE] + File.COMP_RLE + len(self.data).to_bytes(3, byteorder = 'little') + writer.data)
        else:
            self.data = bytearray(File.COMP_RLE + len(self.data).to_bytes(3, byteorder = 'little') + writer.data)
Exemplo n.º 4
0
    def decompressHuffman(self, offsetIn=0):
        reader = binary.BinaryReader(data = self.data)
        reader.seek(offsetIn)
        magic = reader.readUInt(1)
        if magic & 0xF0 != 0x20:
            return False
        elif magic & 0x0F == 0x04:
            useHalfByteBlocks = True
        else:
            useHalfByteBlocks = False

        tempFilesize = reader.readUInt(3)
        tempTreeLength = (reader.readUInt(1) * 2) + 1
        tree = _HuffmanTree.decode(reader, offsetIn, offsetIn + tempTreeLength + 5)
        reader.seek(offsetIn + tempTreeLength + 5)

        writer = binary.BinaryWriter()
        bitsLeft = 0
        currentNode = tree.root
        isMsbNibble = True
        while writer.tell() < tempFilesize:    # Ported from DsDecmp
            while currentNode.data == None:
                if bitsLeft == 0:
                    data = reader.readU4()
                    bitsLeft = 32
                bitsLeft-=1
                nextIsRight = (data & (1 << bitsLeft)) != 0
                if nextIsRight:
                    currentNode = currentNode.right
                else:
                    currentNode = currentNode.left
            
            if useHalfByteBlocks:
                if isMsbNibble:
                    tempIntData = int.from_bytes(currentNode.data, byteorder = 'little') << 4
                else:
                    tempIntData |= int.from_bytes(currentNode.data, byteorder = 'little')        
                    writer.writeInt(tempIntData, 1)
                isMsbNibble = not(isMsbNibble)
            else:
                writer.write(currentNode.data)
            currentNode = tree.root

        if useHalfByteBlocks and not(isMsbNibble):
            writer.writeInt(tempIntData, 1)
        self.data = writer.data[:tempFilesize]
        return True
Exemplo n.º 5
0
 def decompressRle(self, offsetIn=0):
     reader = binary.BinaryReader(data = self.data)
     reader.seek(offsetIn)
     if reader.readUInt(1) != File.COMP_RLE:
         return False
     tempFilesize = reader.readUInt(3)
     writer = binary.BinaryWriter()
     while writer.tell() < tempFilesize:
         flag = int.from_bytes(reader.read(1), byteorder = 'little')
         isCompressed = (flag & 0x80) > 0
         if isCompressed:
             decompressedLength = (flag & 0x7f) + 3
             decompressedData = reader.read(1)
             for _indexByte in range(decompressedLength):
                 writer.write(decompressedData)
         else:
             decompressedLength = (flag & 0x7f) + 1
             writer.write(reader.read(decompressedLength))
     self.data = writer.data
     return True
Exemplo n.º 6
0
    def load(self, data):
        reader = binary.BinaryReader(data = data)
        if reader.read(4) == b'LPC2':
            countFile = reader.readU4()
            offsetFile = reader.readU4()
            _lengthArchive = reader.readU4()
            offsetMetadata = reader.readU4()
            offsetName = reader.readU4()
            
            for indexFile in range(countFile):
                reader.seek(offsetMetadata + (12 * indexFile))
                fileOffsetName = reader.readU4()
                fileOffsetData = reader.readU4()
                fileLengthData = reader.readU4()

                reader.seek(offsetName + fileOffsetName)
                tempName = reader.readNullTerminatedString('shift-jis')
                reader.seek(offsetFile + fileOffsetData)
                tempData = reader.read(fileLengthData)
                self.files.append(File(tempName, data=tempData))

            return True

        return False
Exemplo n.º 7
0
    def load(self, data):
        reader = binary.BinaryReader(data=data)
        if reader.read(4) == b'LIMG':
            lengthHeader = reader.readU4()

            offsetSubImageData = reader.readU2()
            countSubImage = reader.readU2()

            offsetImageParam = reader.readU2()

            reader.seek(2, 1)  # UNK

            offsetTableTile = reader.readU2()
            lengthTableTile = reader.readU2()
            offsetTile = reader.readU2()
            countTile = reader.readU2()
            countPalette = reader.readU2()  # Always 1
            lengthPalette = reader.readU2()
            resolution = (reader.readU2(), reader.readU2())

            bpp = math.ceil(math.ceil(math.log(lengthPalette, 2)) / 4) * 4

            reader.seek(offsetSubImageData)
            for _subImageCount in range(countSubImage):
                self.subImageCropRegions.append(
                    (reader.readUInt(1) * 8, reader.readUInt(1) * 8,
                     reader.readUInt(1) * 8, reader.readUInt(1) * 8))
                reader.seek(4, 1)

            reader.seek(lengthHeader)
            palette = []
            for _indexColour in range(lengthPalette):
                palette.extend(Colour.fromInt(reader.readU2()).toList())

            self.imageAtlas = Image.new("P", resolution)
            self.imageAtlas.putpalette(palette)
            self.imageAtlas.paste(0, (0, 0, resolution[0], resolution[1]))

            reader.seek(offsetTile)
            tilePilMap = {}
            for index in range(countTile):
                tilePilMap[index] = Tile(data=reader.read(int((bpp * 64) /
                                                              8))).decodeToPil(
                                                                  palette, bpp)

            reader.seek(offsetTableTile)
            width, height = self.imageAtlas.size
            for y in range(height // 8):
                for x in range(width // 8):
                    tempSelectedTile = reader.readU2()
                    tileSelectedIndex = tempSelectedTile & (2**10 - 1)
                    tileSelectedFlipX = tempSelectedTile & (2**11)
                    tileSelectedFlipY = tempSelectedTile & (2**10)

                    if tileSelectedIndex < (2**10 - 1):
                        tileFocus = tilePilMap[tileSelectedIndex % countTile]
                        if tileSelectedFlipX:
                            tileFocus = tileFocus.transpose(
                                method=Image.FLIP_LEFT_RIGHT)
                        if tileSelectedFlipY:
                            tileFocus = tileFocus.transpose(
                                method=Image.FLIP_TOP_BOTTOM)
                        self.imageAtlas.paste(tileFocus, (x * 8, y * 8))
        else:
            print("Failed magic test!")
Exemplo n.º 8
0
                        "RGBA",
                        (command.operands[3].value, command.operands[4].value))
                    # TODO : Offset not implemented
                elif command.opcode == b'\xfe\x03':
                    targetSubImage = atlasesAsIndex[command.operands[
                        0].value].subImages[command.operands[1].value]
                    tempFrame.paste(
                        targetSubImage,
                        (command.operands[2].value, command.operands[3].value),
                        targetSubImage)
                    # TODO : Another UNK
                    # TODO : alpha_composite
                elif command.opcode == b'\xfd\x03':
                    self.frames[tempName] = tempFrame

    def export(self, filename):
        for frameName in list(self.frames.keys()):
            self.frames[frameName].save(
                path.splitext(filename)[0] + "_" + frameName + "." +
                EXPORT_EXTENSION)


if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        if sys.argv[1].split(".")[-1] == "cani":
            testImage = LaytonAnimatedImage()
        else:
            testImage = LaytonBackgroundImage()
        testImage.load(binary.BinaryReader(filename=sys.argv[1]).data)
        testImage.export(".".join(sys.argv[1].split(".")[:-1]))
Exemplo n.º 9
0
    def compressHuffman(self, useHalfByteBlocks = False, addHeader=False):
        reader = binary.BinaryReader(data = self.data)
        freqDict = {}
        while reader.hasDataRemaining():    # Build frequency table
            tempByte = [bytes(reader.read(1))]
            if useHalfByteBlocks:
                tempByte[0] = int.from_bytes(tempByte[0], byteorder = 'little')
                tempByte = [(tempByte[0] >> 4).to_bytes(1, byteorder = 'little'), (tempByte[0] & 0x0F).to_bytes(1, byteorder = 'little')]
            for block in tempByte:
                if block not in freqDict.keys():
                    freqDict[block] = _HuffmanCompressionNode(data = block)
                freqDict[block].weight += 1

        nodes = freqDict.values()
        if len(nodes) > 2**9:
            raise Exception("Huffman encode: Tree too long to be encoded!")

        while len(nodes) > 1:   # Build Huffman tree by grouping nodes
            nodes = sorted(nodes, key=lambda huffNode : huffNode.weight)
            newNode = _HuffmanCompressionNode(left = nodes[0], right = nodes[1], weight = nodes[0].weight + nodes[1].weight)
            newNode.left.parent = newNode
            newNode.right.parent = newNode
            nodes = nodes[2:]
            nodes.append(newNode)

        tree = _HuffmanTree(nodes[0])
        
        writer = binary.BinaryWriter()
        if useHalfByteBlocks:
            writer.writeInt(File.COMP_HUFFMAN_4_BIT, 1)
        else:
            writer.writeInt(File.COMP_HUFFMAN_8_BIT, 1)
        writer.writeInt(len(self.data), 3)
        writer.write(tree.encode())
        
        keyDict = {}
        for key in freqDict.keys():
            keyDict[freqDict[key].data] = freqDict[key].getBoolCode()
        
        reader.seek(0)
        compressionBlock = 0
        compressionBlockBitsRemaining = 32
        while reader.hasDataRemaining():    # Ported from DsDecmp
            tempByte = [reader.read(1)]
            if useHalfByteBlocks:
                tempByte[0] = int.from_bytes(tempByte[0], byteorder = 'little')
                tempByte = [(tempByte[0] >> 4).to_bytes(1, byteorder = 'little'), (tempByte[0] & 0x0F).to_bytes(1, byteorder = 'little')]
            for data in tempByte:
                for bit in keyDict[bytes(data)]:
                    if compressionBlockBitsRemaining == 0:
                        writer.writeU4(compressionBlock)
                        compressionBlock = 0
                        compressionBlockBitsRemaining = 32
                    compressionBlockBitsRemaining -= 1
                    if bit:
                        compressionBlock = compressionBlock | (1 << compressionBlockBitsRemaining)
        if compressionBlockBitsRemaining != 32:
            writer.writeU4(compressionBlock)
        writer.dsAlign(4, 4)

        if addHeader:
            if useHalfByteBlocks:
                self.data = File.LAYTON_1_COMPRESSION[File.COMP_HUFFMAN_4_BIT] + writer.data
            else:
                self.data = File.LAYTON_1_COMPRESSION[File.COMP_HUFFMAN_8_BIT] + writer.data
        else:
            self.data = writer.data
Exemplo n.º 10
0
 def setFromData(self, data):
     reader = binary.BinaryReader(data=data)
     self.opcode = reader.read(2)
     self.countOperands = reader.readU2()
     self.indexOperandsStart = reader.readU4()
Exemplo n.º 11
0
            for indexCommand in range(countCommand):
                self.commands.append(FutureInstruction.fromData(
                    reader.read(8)))
                countOperands = max(
                    countOperands,
                    self.commands[indexCommand].indexOperandsStart +
                    self.commands[indexCommand].countOperands)

            bankOperand = getBankOperand(reader, offsetOperands, countOperands,
                                         bankString)
            populateInstructionOperands(bankOperand)
            return True
        return False

    def __str__(self):
        output = ""
        for operation in debug.commands:
            output += "\n\n" + str(operation)
        return output


if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        debug = LaytonScript()
        debug.load(binary.BinaryReader(filename=sys.argv[1]).data)
        for operation in debug.commands:
            print(operation)
            print()
        exit = input("Return to exit...")