1// Aseprite FLIC Library
2// Copyright (c) 2019-2020 Igara Studio S.A.
3// Copyright (c) 2015 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#include "flic.h"
9#include "flic_details.h"
10
11#undef assert
12#define assert(...)
13
14namespace flic {
15
16Decoder::Decoder(FileInterface* file)
17 : m_file(file)
18 , m_frameCount(0)
19 , m_offsetFrame1(0)
20 , m_offsetFrame2(0)
21{
22}
23
24bool Decoder::readHeader(Header& header)
25{
26 read32(); // file size
27 uint16_t magic = read16();
28
29 assert(magic == FLI_MAGIC_NUMBER || magic == FLC_MAGIC_NUMBER);
30 if (magic != FLI_MAGIC_NUMBER &&
31 magic != FLC_MAGIC_NUMBER)
32 return false;
33
34 header.frames = read16();
35 header.width = read16();
36 header.height = read16();
37 read16(); // Color depth (it is interpreted as 8bpp anyway)
38 read16(); // Skip flags
39 header.speed = read32();
40 if (magic == FLI_MAGIC_NUMBER) {
41 if (header.speed == 0)
42 header.speed = 70;
43 else
44 header.speed = 1000 * header.speed / 70;
45 }
46
47 if (magic == FLC_MAGIC_NUMBER) {
48 // Offset to the first and second frame
49 m_file->seek(80);
50 m_offsetFrame1 = read32();
51 m_offsetFrame2 = read32();
52 }
53
54 if (header.width == 0) header.width = 320;
55 if (header.height == 0) header.height = 200;
56
57 m_width = header.width;
58 m_height = header.height;
59
60 // Skip padding
61 m_file->seek(128);
62 return true;
63}
64
65bool Decoder::readFrame(Frame& frame)
66{
67 switch (m_frameCount) {
68 case 0:
69 if (m_offsetFrame1)
70 m_file->seek(m_offsetFrame1);
71 break;
72 case 1:
73 if (m_offsetFrame2)
74 m_file->seek(m_offsetFrame2);
75 break;
76 }
77
78 uint32_t frameStartPos = m_file->tell();
79 uint32_t frameSize = read32();
80 uint16_t magic = read16();
81 assert(magic == FLI_FRAME_MAGIC_NUMBER);
82 (void)magic;
83
84 uint16_t chunks = read16();
85 for (int i=0; i<8; ++i) // Padding
86 m_file->read8();
87
88 for (uint16_t i=0; i!=chunks; ++i)
89 readChunk(frame);
90
91 m_file->seek(frameStartPos+frameSize);
92 ++m_frameCount;
93 return true;
94}
95
96void Decoder::readChunk(Frame& frame)
97{
98 uint32_t chunkStartPos = m_file->tell();
99 uint32_t chunkSize = read32();
100 uint16_t type = read16();
101
102 switch (type) {
103 case FLI_COLOR_256_CHUNK: readColorChunk(frame, false); break;
104 case FLI_DELTA_CHUNK: readDeltaChunk(frame); break;
105 case FLI_COLOR_64_CHUNK: readColorChunk(frame, true); break;
106 case FLI_LC_CHUNK: readLcChunk(frame); break;
107 case FLI_BLACK_CHUNK: readBlackChunk(frame); break;
108 case FLI_BRUN_CHUNK: readBrunChunk(frame); break;
109 case FLI_COPY_CHUNK: readCopyChunk(frame); break;
110 default:
111 // Ignore all other kind of chunks
112 break;
113 }
114
115 m_file->seek(chunkStartPos+chunkSize);
116}
117
118void Decoder::readBlackChunk(Frame& frame)
119{
120 std::fill(frame.pixels,
121 frame.pixels+frame.rowstride*m_height, 0);
122}
123
124void Decoder::readCopyChunk(Frame& frame)
125{
126 assert(m_width == 320 && m_height == 200);
127 if (m_width == 320 && m_height == 200) {
128 for (int y=0; y<200; ++y) {
129 uint8_t* it = frame.pixels + y*frame.rowstride;
130 for (int x=0; x<320; ++x, ++it)
131 *it = m_file->read8();
132 }
133 }
134}
135
136void Decoder::readColorChunk(Frame& frame, bool oldColorChunk)
137{
138 int npackets = read16();
139
140 // For each packet
141 int i = 0;
142 while (npackets--) {
143 i += m_file->read8(); // Colors to skip
144
145 int colors = m_file->read8();
146 if (colors == 0)
147 colors = 256;
148
149 for (int j=0; j<colors
150 // If i+j >= 256 it means that the color chunk is invalid,
151 // we check this to avoid an buffer overflow of frame.colormap[]
152 && i+j < 256;
153 ++j) {
154 Color& color = frame.colormap[i+j];
155 color.r = m_file->read8();
156 color.g = m_file->read8();
157 color.b = m_file->read8();
158 if (oldColorChunk) {
159 color.r = 255 * int(color.r) / 63;
160 color.g = 255 * int(color.g) / 63;
161 color.b = 255 * int(color.b) / 63;
162 }
163 }
164 }
165}
166
167void Decoder::readBrunChunk(Frame& frame)
168{
169 for (int y=0; y<m_height; ++y) {
170 uint8_t* it = frame.pixels+frame.rowstride*y;
171 int x = 0;
172 int npackets = m_file->read8(); // Use the number of packet to check integrity
173 while (m_file->ok() && npackets-- != 0 && x < m_width) {
174 int count = int(int8_t(m_file->read8()));
175 if (count >= 0) {
176 uint8_t color = m_file->read8();
177 while (count-- != 0 && x < m_width) {
178 *it = color;
179 ++it;
180 ++x;
181 }
182 }
183 else {
184 while (count++ != 0 && x < m_width) {
185 *it = m_file->read8();
186 ++it;
187 ++x;
188 }
189 }
190 }
191 }
192}
193
194void Decoder::readLcChunk(Frame& frame)
195{
196 int skipLines = read16();
197 int nlines = read16();
198
199 for (int y=skipLines; y<skipLines+nlines; ++y) {
200 // Break in case of invalid data
201 if (y < 0 || y >= m_height)
202 break;
203
204 uint8_t* it = frame.pixels+frame.rowstride*y;
205 int x = 0;
206 int npackets = m_file->read8();
207 while (npackets-- && x < m_width) {
208 int skip = m_file->read8();
209
210 x += skip;
211 it += skip;
212
213 int count = int(int8_t(m_file->read8()));
214 if (count >= 0) {
215 uint8_t* end = frame.pixels+frame.rowstride*m_height;
216 while (count-- != 0 && it < end) {
217 *it = m_file->read8();
218 ++it;
219 ++x;
220 }
221 // Broken file? More bytes than available buffer
222 if (it == end)
223 return;
224 }
225 else {
226 uint8_t color = m_file->read8();
227 while (count++ != 0 && x < m_width) {
228 *it = color;
229 ++it;
230 ++x;
231 }
232 }
233 }
234 }
235}
236
237void Decoder::readDeltaChunk(Frame& frame)
238{
239 int nlines = read16();
240 int y = 0;
241 while (nlines-- != 0) {
242 int npackets = 0;
243
244 while (m_file->ok()) {
245 int16_t word = read16();
246 if (word < 0) { // Has bit 15 (0x8000)
247 if (word & 0x4000) { // Has bit 14 (0x4000)
248 y += -word; // Skip lines
249 }
250 // Only last pixel has changed
251 else {
252 assert(y >= 0 && y < m_height);
253 if (y >= 0 && y < m_height) {
254 uint8_t* it = frame.pixels + y*frame.rowstride + m_width - 1;
255 *it = (word & 0xff);
256 }
257 ++y;
258 if (nlines-- == 0)
259 return; // We are done
260 }
261 }
262 else {
263 npackets = word;
264 break;
265 }
266 }
267
268 // Avoid invalid data to skip more lines than the availables.
269 if (y >= m_height)
270 break;
271
272 int x = 0;
273 while (npackets-- != 0) {
274 x += m_file->read8(); // Skip pixels
275 int8_t count = m_file->read8(); // Number of words
276
277 assert(y >= 0 && y < m_height && x >= 0 && x < m_width);
278 uint8_t* it = frame.pixels + y*frame.rowstride + x;
279
280 if (count >= 0) {
281 while (count-- != 0 && x < m_width) {
282 int color1 = m_file->read8();
283 int color2 = m_file->read8();
284
285 *it = color1;
286 ++it;
287 ++x;
288
289 if (x < m_width) {
290 *it = color2;
291 ++it;
292 ++x;
293 }
294 }
295 }
296 else {
297 int color1 = m_file->read8();
298 int color2 = m_file->read8();
299
300 while (count++ != 0 && x < m_width) {
301 *it = color1;
302 ++it;
303 ++x;
304
305 if (x < m_width) {
306 *it = color2;
307 ++it;
308 ++x;
309 }
310 }
311 }
312 }
313
314 ++y;
315 }
316}
317
318uint16_t Decoder::read16()
319{
320 int b1 = m_file->read8();
321 int b2 = m_file->read8();
322
323 if (m_file->ok()) {
324 return ((b2 << 8) | b1); // Little endian
325 }
326 else
327 return 0;
328}
329
330uint32_t Decoder::read32()
331{
332 int b1 = m_file->read8();
333 int b2 = m_file->read8();
334 int b3 = m_file->read8();
335 int b4 = m_file->read8();
336
337 if (m_file->ok()) {
338 // Little endian
339 return ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
340 }
341 else
342 return 0;
343}
344
345} // namespace flic
346