summaryrefslogtreecommitdiff
path: root/lib/lvgl/src/libs/rle/lv_rle.c
blob: e715b7cc1794cf7f2fb1cea29f406312fc2331c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
 * @file lv_rle.c
 */

/*********************
 *      INCLUDES
 *********************/

#include "../../stdlib/lv_string.h"
#include "lv_rle.h"

#if LV_USE_RLE

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

uint32_t lv_rle_decompress(const uint8_t * input,
                           uint32_t input_buff_len, uint8_t * output,
                           uint32_t output_buff_len, uint8_t blk_size)
{
    uint32_t ctrl_byte;
    uint32_t rd_len = 0;
    uint32_t wr_len = 0;

    while(rd_len < input_buff_len) {
        ctrl_byte = input[0];
        rd_len++;
        input++;
        if(rd_len > input_buff_len)
            return 0;

        if(ctrl_byte & 0x80) {
            /* copy directly from input to output */
            uint32_t bytes = blk_size * (ctrl_byte & 0x7f);
            rd_len += bytes;
            if(rd_len > input_buff_len)
                return 0;

            wr_len += bytes;
            if(wr_len > output_buff_len) {
                if(wr_len > output_buff_len + blk_size)
                    return 0; /* Error */
                lv_memcpy(output, input, output_buff_len - (wr_len - bytes));
                return output_buff_len;
            }

            lv_memcpy(output, input, bytes);
            output += bytes;
            input += bytes;
        }
        else {
            rd_len += blk_size;
            if(rd_len > input_buff_len)
                return 0;

            wr_len += blk_size * ctrl_byte;
            if(wr_len > output_buff_len) {
                if(wr_len > output_buff_len + blk_size)
                    return 0; /* Error happened */

                /* Skip the last pixel, which could overflow output buffer.*/
                for(uint32_t i = 0; i < ctrl_byte - 1; i++) {
                    lv_memcpy(output, input, blk_size);
                    output += blk_size;
                }
                return output_buff_len;
            }

            if(blk_size == 1) {
                /* optimize the most common case. */
                lv_memset(output, input[0], ctrl_byte);
                output += ctrl_byte;
            }
            else {
                for(uint32_t i = 0; i < ctrl_byte; i++) {
                    lv_memcpy(output, input, blk_size);
                    output += blk_size;
                }
            }
            input += blk_size;
        }
    }

    return wr_len;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

#endif /*LV_USE_RLE*/