15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# coding: utf-8
35f9996aaSopenharmony_ci# Copyright (c) 2022 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport sys
175f9996aaSopenharmony_ciimport os
185f9996aaSopenharmony_ciimport hashlib
195f9996aaSopenharmony_ciimport errno
205f9996aaSopenharmony_ciimport stat
215f9996aaSopenharmony_ciimport datetime
225f9996aaSopenharmony_ci
235f9996aaSopenharmony_ci
245f9996aaSopenharmony_cidef usage():
255f9996aaSopenharmony_ci    print('\n Usage: imgcovert.py <cmd> <input> <output>')
265f9996aaSopenharmony_ci    print('         <cmd>: sparse or unsparse')
275f9996aaSopenharmony_ci    print('         <input>: input image file')
285f9996aaSopenharmony_ci    print('         <output>: ouput image file\n')
295f9996aaSopenharmony_ci    return
305f9996aaSopenharmony_ci
315f9996aaSopenharmony_ci
325f9996aaSopenharmony_cidef get_fill_cnt(inputfile: str, blocksize: int) -> int:
335f9996aaSopenharmony_ci    flags = os.O_WRONLY
345f9996aaSopenharmony_ci    modes = stat.S_IWUSR | stat.S_IRUSR
355f9996aaSopenharmony_ci    size = os.path.getsize(inputfile)
365f9996aaSopenharmony_ci    fill_cnt = 0
375f9996aaSopenharmony_ci    if size % blocksize != 0:
385f9996aaSopenharmony_ci        fill_cnt = blocksize - size % blocksize
395f9996aaSopenharmony_ci    indata = os.fdopen(os.open(inputfile, flags, modes), 'a')
405f9996aaSopenharmony_ci    for _ in range(fill_cnt):
415f9996aaSopenharmony_ci        indata.write("\0")
425f9996aaSopenharmony_ci    indata.close()
435f9996aaSopenharmony_ci    return fill_cnt
445f9996aaSopenharmony_ci
455f9996aaSopenharmony_ci
465f9996aaSopenharmony_cidef get_gap_blocksize(length: int, size: int) -> int:
475f9996aaSopenharmony_ci    if length < size:
485f9996aaSopenharmony_ci        cnt = 2
495f9996aaSopenharmony_ci    elif length < (size * 2):
505f9996aaSopenharmony_ci        cnt = 3
515f9996aaSopenharmony_ci    else:
525f9996aaSopenharmony_ci        cnt = 4
535f9996aaSopenharmony_ci    return cnt
545f9996aaSopenharmony_ci
555f9996aaSopenharmony_ci
565f9996aaSopenharmony_cidef get_block_cnt(inputfile: str, blocksize: int) -> int:
575f9996aaSopenharmony_ci    size = os.path.getsize(inputfile)
585f9996aaSopenharmony_ci    if blocksize != 0:
595f9996aaSopenharmony_ci        totalblocks = size / blocksize
605f9996aaSopenharmony_ci    else:
615f9996aaSopenharmony_ci        sys.exit(1)
625f9996aaSopenharmony_ci    if (size % blocksize) != 0:
635f9996aaSopenharmony_ci        print("len is not eq n * blocksize: ", size, totalblocks)
645f9996aaSopenharmony_ci    return totalblocks
655f9996aaSopenharmony_ci
665f9996aaSopenharmony_ci
675f9996aaSopenharmony_cidef get_crc_value(inputfile: str, blocksize: int):
685f9996aaSopenharmony_ci    totalblocks = get_block_cnt(inputfile, blocksize)
695f9996aaSopenharmony_ci    with open(inputfile, 'rb') as indata:
705f9996aaSopenharmony_ci        ind = 0
715f9996aaSopenharmony_ci        md5 = hashlib.md5()
725f9996aaSopenharmony_ci        while (ind < totalblocks):
735f9996aaSopenharmony_ci            md5.update(indata.read(blocksize))
745f9996aaSopenharmony_ci            ind += 1
755f9996aaSopenharmony_ci    return md5.hexdigest()
765f9996aaSopenharmony_ci
775f9996aaSopenharmony_ci
785f9996aaSopenharmony_cidef unsparse(sparseimagefile: str, imagefile: str):
795f9996aaSopenharmony_ci    with open(sparseimagefile, 'r') as header:
805f9996aaSopenharmony_ci        magic_mumber = header.readline()
815f9996aaSopenharmony_ci        version = header.readline()
825f9996aaSopenharmony_ci        blocksize = int(header.readline())
835f9996aaSopenharmony_ci        total_blocks = int(header.readline())
845f9996aaSopenharmony_ci        crc_value = header.readline()
855f9996aaSopenharmony_ci        input_crc_value = header.readline()
865f9996aaSopenharmony_ci        table_numbers = int(header.readline())
875f9996aaSopenharmony_ci        table = []
885f9996aaSopenharmony_ci        flags = os.O_CREAT | os.O_RDWR
895f9996aaSopenharmony_ci        modes = stat.S_IWUSR | stat.S_IRUSR
905f9996aaSopenharmony_ci        i = 0
915f9996aaSopenharmony_ci        while (i < table_numbers):
925f9996aaSopenharmony_ci            start = int(header.readline())
935f9996aaSopenharmony_ci            end = int(header.readline())
945f9996aaSopenharmony_ci            table.append([start, end])
955f9996aaSopenharmony_ci            i += 1
965f9996aaSopenharmony_ci        fill_cnt = int(header.readline())
975f9996aaSopenharmony_ci        length = header.tell()
985f9996aaSopenharmony_ci    with open(sparseimagefile, 'rb') as inputrow:
995f9996aaSopenharmony_ci        inputrow.seek(get_gap_blocksize(length, blocksize) * blocksize)
1005f9996aaSopenharmony_ci        output = os.fdopen(os.open(imagefile, flags, modes), 'wb')
1015f9996aaSopenharmony_ci        output.truncate(total_blocks * blocksize)
1025f9996aaSopenharmony_ci        md5 = hashlib.md5()
1035f9996aaSopenharmony_ci        for block in table:
1045f9996aaSopenharmony_ci            cnt = block[1] - block[0]
1055f9996aaSopenharmony_ci            output.seek(block[0] * blocksize)
1065f9996aaSopenharmony_ci            indata = inputrow.read(cnt * blocksize)
1075f9996aaSopenharmony_ci            md5.update(indata)
1085f9996aaSopenharmony_ci            output.write(indata)
1095f9996aaSopenharmony_ci        output.close()
1105f9996aaSopenharmony_ci    print("RawFileCRC: ", get_crc_value(imagefile, blocksize), crc_value)
1115f9996aaSopenharmony_ci    print("SparseCRC: ", md5.hexdigest(), input_crc_value)
1125f9996aaSopenharmony_ci    with open(imagefile, 'r+') as output:
1135f9996aaSopenharmony_ci        output.truncate(total_blocks * blocksize - fill_cnt)
1145f9996aaSopenharmony_ci    return
1155f9996aaSopenharmony_ci
1165f9996aaSopenharmony_ci
1175f9996aaSopenharmony_cidef is_empty_block(buff: list, size: int) -> bool:
1185f9996aaSopenharmony_ci    ind = 0
1195f9996aaSopenharmony_ci    while (ind < size):
1205f9996aaSopenharmony_ci        if buff[ind] != 0:
1215f9996aaSopenharmony_ci            return False
1225f9996aaSopenharmony_ci        ind += 1
1235f9996aaSopenharmony_ci    return True
1245f9996aaSopenharmony_ci
1255f9996aaSopenharmony_ci
1265f9996aaSopenharmony_cidef process_block(inputrow, blocksize, outputtemp, blockid, total_blocks) -> int:
1275f9996aaSopenharmony_ci    ind = 0
1285f9996aaSopenharmony_ci    start = -1
1295f9996aaSopenharmony_ci    table_numbers = 0
1305f9996aaSopenharmony_ci    while (ind < total_blocks):
1315f9996aaSopenharmony_ci        indata = inputrow.read(blocksize)
1325f9996aaSopenharmony_ci        if len(indata) != blocksize:
1335f9996aaSopenharmony_ci            print("error Block", ind, len(indata))
1345f9996aaSopenharmony_ci        if is_empty_block(indata, blocksize):
1355f9996aaSopenharmony_ci            if start != -1:
1365f9996aaSopenharmony_ci                blockid.append([start, ind])
1375f9996aaSopenharmony_ci                table_numbers += 1
1385f9996aaSopenharmony_ci                start = -1
1395f9996aaSopenharmony_ci        else:
1405f9996aaSopenharmony_ci            outputtemp.write(indata)
1415f9996aaSopenharmony_ci            if start == -1:
1425f9996aaSopenharmony_ci                start = ind
1435f9996aaSopenharmony_ci        ind += 1
1445f9996aaSopenharmony_ci    if start != -1:
1455f9996aaSopenharmony_ci        blockid.append([start, ind])
1465f9996aaSopenharmony_ci        table_numbers += 1
1475f9996aaSopenharmony_ci        start = -1
1485f9996aaSopenharmony_ci    return table_numbers
1495f9996aaSopenharmony_ci
1505f9996aaSopenharmony_ci
1515f9996aaSopenharmony_cidef get_raw_datafile(imagefile: str, blockid, total_blocks: int, blocksize: int) -> int:
1525f9996aaSopenharmony_ci    temp_file = imagefile + ".tempfile"
1535f9996aaSopenharmony_ci    flags = os.O_CREAT | os.O_RDWR
1545f9996aaSopenharmony_ci    modes = stat.S_IWUSR | stat.S_IRUSR
1555f9996aaSopenharmony_ci    table_numbers = 0
1565f9996aaSopenharmony_ci    with open(imagefile, 'rb') as inputrow, os.fdopen(os.open(temp_file, flags, modes), 'wb') as outputtemp:
1575f9996aaSopenharmony_ci        table_numbers = process_block(inputrow, blocksize, outputtemp, blockid, total_blocks)
1585f9996aaSopenharmony_ci    return table_numbers
1595f9996aaSopenharmony_ci
1605f9996aaSopenharmony_ci
1615f9996aaSopenharmony_cidef sparse(imagefile: str, sparseimagefile: str):
1625f9996aaSopenharmony_ci    temp_file = imagefile + ".tempfile"
1635f9996aaSopenharmony_ci    magic_number = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
1645f9996aaSopenharmony_ci    version = 1.0
1655f9996aaSopenharmony_ci    blocksize = 4096
1665f9996aaSopenharmony_ci    table_numbers = 0
1675f9996aaSopenharmony_ci    blockid = []
1685f9996aaSopenharmony_ci    flags = os.O_CREAT | os.O_RDWR
1695f9996aaSopenharmony_ci    modes = stat.S_IWUSR | stat.S_IRUSR
1705f9996aaSopenharmony_ci
1715f9996aaSopenharmony_ci    fill_cnt = get_fill_cnt(imagefile, blocksize)
1725f9996aaSopenharmony_ci    total_blocks = get_block_cnt(imagefile, blocksize)
1735f9996aaSopenharmony_ci    table_numbers = get_raw_datafile(imagefile, blockid, total_blocks, blocksize)
1745f9996aaSopenharmony_ci
1755f9996aaSopenharmony_ci#   save the header
1765f9996aaSopenharmony_ci    outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'w')
1775f9996aaSopenharmony_ci    outputrow.write("%s\n" % (magic_number))
1785f9996aaSopenharmony_ci    outputrow.write("%s\n" % (version))
1795f9996aaSopenharmony_ci    outputrow.write("%s\n" % (blocksize))
1805f9996aaSopenharmony_ci    outputrow.write("%s\n" % (int(total_blocks)))
1815f9996aaSopenharmony_ci    outputrow.write("%s\n" % (get_crc_value(imagefile, blocksize)))
1825f9996aaSopenharmony_ci    outputrow.write("%s\n" % (get_crc_value(temp_file, blocksize)))
1835f9996aaSopenharmony_ci    outputrow.write("%s\n" % (table_numbers))
1845f9996aaSopenharmony_ci    for block in blockid:
1855f9996aaSopenharmony_ci        outputrow.write("%s\n" % (block[0]))
1865f9996aaSopenharmony_ci        outputrow.write("%s\n" % (block[1]))
1875f9996aaSopenharmony_ci    outputrow.write("%s\n" % (int(fill_cnt)))
1885f9996aaSopenharmony_ci    outputrow.truncate(get_gap_blocksize(outputrow.tell(), blocksize) * blocksize)
1895f9996aaSopenharmony_ci    outputrow.close()
1905f9996aaSopenharmony_ci
1915f9996aaSopenharmony_ci#   append the raw data
1925f9996aaSopenharmony_ci    outputrow = os.fdopen(os.open(sparseimagefile, flags, modes), 'ab')
1935f9996aaSopenharmony_ci    outputtemp = os.fdopen(os.open(temp_file, flags, modes), 'rb')
1945f9996aaSopenharmony_ci    blocknum = get_block_cnt(temp_file, blocksize)
1955f9996aaSopenharmony_ci    i = 0
1965f9996aaSopenharmony_ci    while (i < blocknum):
1975f9996aaSopenharmony_ci        outputrow.write(outputtemp.read(blocksize))
1985f9996aaSopenharmony_ci        i += 1
1995f9996aaSopenharmony_ci    outputtemp.close()
2005f9996aaSopenharmony_ci    outputrow.close()
2015f9996aaSopenharmony_ci    os.remove(temp_file)
2025f9996aaSopenharmony_ci    with open(imagefile, 'r+') as output:
2035f9996aaSopenharmony_ci        output.truncate(int(total_blocks) * int(blocksize) - int(fill_cnt))
2045f9996aaSopenharmony_ci
2055f9996aaSopenharmony_ci
2065f9996aaSopenharmony_ciif __name__ == '__main__':
2075f9996aaSopenharmony_ci    if len(sys.argv) != 4:
2085f9996aaSopenharmony_ci        usage()
2095f9996aaSopenharmony_ci        sys.exit()
2105f9996aaSopenharmony_ci    CMD = str(sys.argv[1])
2115f9996aaSopenharmony_ci    INPUT_FILE = str(sys.argv[2])
2125f9996aaSopenharmony_ci    OUTPUT_FILE = str(sys.argv[3])
2135f9996aaSopenharmony_ci    if CMD == 'unsparse':
2145f9996aaSopenharmony_ci        unsparse(INPUT_FILE, OUTPUT_FILE)
2155f9996aaSopenharmony_ci    elif CMD == 'sparse':
2165f9996aaSopenharmony_ci        sparse(INPUT_FILE, OUTPUT_FILE)
2175f9996aaSopenharmony_ci    else:
2185f9996aaSopenharmony_ci        usage()