Bug Summary

File:librosprite.c
Warning:line 407, column 2
Potential leak of memory pointed to by 'header'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name librosprite.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-librosprite -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I /var/lib/jenkins/workspace/scan-build-librosprite/include/ -D _ALIGNED=__attribute__((aligned)) -D STMTEXPR=1 -D DEBUG -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Og -Wwrite-strings -Wno-format-zero-length -Wno-error -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-librosprite -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-librosprite/clangScanBuildReports/2024-12-27-082950-3274889-1 -x c src/librosprite.c
1/*
2 * This file is part of librosprite.
3 * Licensed under the MIT License,
4 * http://www.opensource.org/licenses/mit-license.php
5 * Copyright 2008 James Shaw <js102@zepler.net>
6 */
7
8/**
9 * \file
10 */
11
12#include <assert.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <stdbool.h>
17#include <string.h>
18
19#include "librosprite.h"
20
21/**
22 * Reads four bytes, 00, 11, 22 and 33, of a byte array b to give 0x33221100.
23 */
24#define BTUINT(b)((unsigned)b[0] | ((unsigned)b[1] << 8) | ((unsigned)b[
2] << 16) | ((unsigned)b[3] << 24))
\
25 ((unsigned)b[0] | \
26 ((unsigned)b[1] << 8) | \
27 ((unsigned)b[2] << 16) | \
28 ((unsigned)b[3] << 24))
29
30/**
31 * Reverse the byte order of a word such that 0xAABBCCDD becomes 0xDDCCBBAA.
32 */
33#define BSWAP(word)(((word & (0x000000ff)) << 24) | ((word & 0x0000ff00
) << 8) | ((word & 0x00ff0000) >> 8) | ((word
& 0xff000000) >> 24))
(((word & (0x000000ff)) << 24) | ((word & 0x0000ff00) << 8) | ((word & 0x00ff0000) >> 8) | ((word & 0xff000000) >> 24))
34
35#define ERRCHK(x)do { rosprite_error err = x; if (err != ROSPRITE_OK) return err
; } while(0)
do { \
36 rosprite_error err = x; \
37 if (err != ROSPRITE_OK) return err; \
38} while(0)
39
40struct rosprite_header {
41 uint32_t width_words; /* width in words */
42 /* height defined in sprite struct */
43 uint32_t first_used_bit; /* old format only (spriteType = 0) */
44 uint32_t last_used_bit;
45
46 /**
47 * Image size in bytes
48 */
49 uint32_t image_size;
50
51 /**
52 * Mask size in bytes
53 */
54 uint32_t mask_size;
55};
56
57struct rosprite_mask_state {
58 uint32_t x;
59 uint32_t y;
60 uint32_t first_used_bit;
61 uint32_t row_max_bit;
62 uint32_t height;
63 uint32_t current_byte_index;
64 uint32_t current_word;
65 uint32_t bpp;
66};
67
68struct rosprite_file_context {
69 FILE* f;
70};
71
72struct rosprite_mem_context {
73 uint8_t* base;
74 unsigned long offset;
75 bool_Bool known_size;
76 unsigned long size;
77};
78
79static const struct rosprite_mode oldmodes[] = {
80/*0*/{ .colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
81/*1*/{ .colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB },
82/*2*/{ .colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 22, .ydpi = 45, .color_model = ROSPRITE_RGB },
83
84/*3*/{ .colorbpp = 0, .maskbpp = 0, .mask_width = 0, .xdpi = 0, .ydpi = 0, .color_model = ROSPRITE_RGB },
85
86/*4*/{ .colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB },
87/*5*/{ .colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 22, .ydpi = 45, .color_model = ROSPRITE_RGB },
88
89/*6*/{ .colorbpp = 0, .maskbpp = 0, .mask_width = 0, .xdpi = 0, .ydpi = 0, .color_model = ROSPRITE_RGB },
90/*7*/{ .colorbpp = 0, .maskbpp = 0, .mask_width = 0, .xdpi = 0, .ydpi = 0, .color_model = ROSPRITE_RGB },
91
92/*8*/{ .colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
93/*9*/{ .colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB },
94/*10*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 22, .ydpi = 45, .color_model = ROSPRITE_RGB },
95/*11*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
96/*12*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
97/*13*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB },
98/*14*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
99/*15*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
100/*16*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
101/*17*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
102/*18*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
103/*19*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
104/*20*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
105/*21*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
106/*22*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi =180, .ydpi = 90, .color_model = ROSPRITE_RGB },
107/*23*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
108/*24*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
109/*25*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
110/*26*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
111/*27*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
112/*28*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
113/*29*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
114/*30*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
115/*31*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
116/*32*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 90, .color_model = ROSPRITE_RGB },
117/*33*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
118/*34*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
119/*35*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
120/*36*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
121/*37*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
122/*38*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
123/*39*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
124/*40*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
125/*41*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
126/*42*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
127/*43*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
128/*44*/{.colorbpp = 1, .maskbpp = 1, .mask_width = 1, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
129/*45*/{.colorbpp = 2, .maskbpp = 1, .mask_width = 2, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
130/*46*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 90, .ydpi = 45, .color_model = ROSPRITE_RGB },
131/*47*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 45, .ydpi = 45, .color_model = ROSPRITE_RGB },
132/*48*/{.colorbpp = 4, .maskbpp = 1, .mask_width = 4, .xdpi = 45, .ydpi = 90, .color_model = ROSPRITE_RGB },
133/*49*/{.colorbpp = 8, .maskbpp = 1, .mask_width = 8, .xdpi = 45, .ydpi = 90, .color_model = ROSPRITE_RGB }
134};
135
136/* table for converting a 5bit channel into an 8bit channel (used for 16bpp to 32bpp conversion) */
137static const uint8_t sprite_16bpp_translate[] = {
138 0x00, 0x08, 0x10, 0x18, 0x20, 0x29, 0x31, 0x39,
139 0x41, 0x4a, 0x52, 0x5a, 0x62, 0x6a, 0x73, 0x7b,
140 0x83, 0x8b, 0x94, 0x9c, 0xa4, 0xac, 0xb4, 0xbd,
141 0xc5, 0xcd, 0xd5, 0xde, 0xe6, 0xee, 0xf6, 0xff
142};
143
144/* palettes generated with palette2c.c
145 * which in turn requires rosprite_load_palette(FILE* f)
146 * defined in this file
147 */
148static const uint32_t sprite_1bpp_palette[] = { 0xffffffff, 0xff };
149
150static const uint32_t sprite_2bpp_palette[] = { 0xffffffff, 0xbbbbbbff, 0x777777ff, 0xff };
151
152static const uint32_t sprite_4bpp_palette[] = {
1530xffffffff, 0xddddddff, 0xbbbbbbff, 0x999999ff,
1540x777777ff, 0x555555ff, 0x333333ff, 0xff,
1550x4499ff, 0xeeee00ff, 0xcc00ff, 0xdd0000ff,
1560xeeeebbff, 0x558800ff, 0xffbb00ff, 0xbbffff
157};
158
159static const uint32_t sprite_8bpp_palette[] = {
1600xff, 0x111111ff, 0x222222ff, 0x333333ff,
1610x440000ff, 0x551111ff, 0x662222ff, 0x773333ff,
1620x44ff, 0x111155ff, 0x222266ff, 0x333377ff,
1630x440044ff, 0x551155ff, 0x662266ff, 0x773377ff,
1640x880000ff, 0x991111ff, 0xaa2222ff, 0xbb3333ff,
1650xcc0000ff, 0xdd1111ff, 0xee2222ff, 0xff3333ff,
1660x880044ff, 0x991155ff, 0xaa2266ff, 0xbb3377ff,
1670xcc0044ff, 0xdd1155ff, 0xee2266ff, 0xff3377ff,
1680x4400ff, 0x115511ff, 0x226622ff, 0x337733ff,
1690x444400ff, 0x555511ff, 0x666622ff, 0x777733ff,
1700x4444ff, 0x115555ff, 0x226666ff, 0x337777ff,
1710x444444ff, 0x555555ff, 0x666666ff, 0x777777ff,
1720x884400ff, 0x995511ff, 0xaa6622ff, 0xbb7733ff,
1730xcc4400ff, 0xdd5511ff, 0xee6622ff, 0xff7733ff,
1740x884444ff, 0x995555ff, 0xaa6666ff, 0xbb7777ff,
1750xcc4444ff, 0xdd5555ff, 0xee6666ff, 0xff7777ff,
1760x8800ff, 0x119911ff, 0x22aa22ff, 0x33bb33ff,
1770x448800ff, 0x559911ff, 0x66aa22ff, 0x77bb33ff,
1780x8844ff, 0x119955ff, 0x22aa66ff, 0x33bb77ff,
1790x448844ff, 0x559955ff, 0x66aa66ff, 0x77bb77ff,
1800x888800ff, 0x999911ff, 0xaaaa22ff, 0xbbbb33ff,
1810xcc8800ff, 0xdd9911ff, 0xeeaa22ff, 0xffbb33ff,
1820x888844ff, 0x999955ff, 0xaaaa66ff, 0xbbbb77ff,
1830xcc8844ff, 0xdd9955ff, 0xeeaa66ff, 0xffbb77ff,
1840xcc00ff, 0x11dd11ff, 0x22ee22ff, 0x33ff33ff,
1850x44cc00ff, 0x55dd11ff, 0x66ee22ff, 0x77ff33ff,
1860xcc44ff, 0x11dd55ff, 0x22ee66ff, 0x33ff77ff,
1870x44cc44ff, 0x55dd55ff, 0x66ee66ff, 0x77ff77ff,
1880x88cc00ff, 0x99dd11ff, 0xaaee22ff, 0xbbff33ff,
1890xcccc00ff, 0xdddd11ff, 0xeeee22ff, 0xffff33ff,
1900x88cc44ff, 0x99dd55ff, 0xaaee66ff, 0xbbff77ff,
1910xcccc44ff, 0xdddd55ff, 0xeeee66ff, 0xffff77ff,
1920x88ff, 0x111199ff, 0x2222aaff, 0x3333bbff,
1930x440088ff, 0x551199ff, 0x6622aaff, 0x7733bbff,
1940xccff, 0x1111ddff, 0x2222eeff, 0x3333ffff,
1950x4400ccff, 0x5511ddff, 0x6622eeff, 0x7733ffff,
1960x880088ff, 0x991199ff, 0xaa22aaff, 0xbb33bbff,
1970xcc0088ff, 0xdd1199ff, 0xee22aaff, 0xff33bbff,
1980x8800ccff, 0x9911ddff, 0xaa22eeff, 0xbb33ffff,
1990xcc00ccff, 0xdd11ddff, 0xee22eeff, 0xff33ffff,
2000x4488ff, 0x115599ff, 0x2266aaff, 0x3377bbff,
2010x444488ff, 0x555599ff, 0x6666aaff, 0x7777bbff,
2020x44ccff, 0x1155ddff, 0x2266eeff, 0x3377ffff,
2030x4444ccff, 0x5555ddff, 0x6666eeff, 0x7777ffff,
2040x884488ff, 0x995599ff, 0xaa66aaff, 0xbb77bbff,
2050xcc4488ff, 0xdd5599ff, 0xee66aaff, 0xff77bbff,
2060x8844ccff, 0x9955ddff, 0xaa66eeff, 0xbb77ffff,
2070xcc44ccff, 0xdd55ddff, 0xee66eeff, 0xff77ffff,
2080x8888ff, 0x119999ff, 0x22aaaaff, 0x33bbbbff,
2090x448888ff, 0x559999ff, 0x66aaaaff, 0x77bbbbff,
2100x88ccff, 0x1199ddff, 0x22aaeeff, 0x33bbffff,
2110x4488ccff, 0x5599ddff, 0x66aaeeff, 0x77bbffff,
2120x888888ff, 0x999999ff, 0xaaaaaaff, 0xbbbbbbff,
2130xcc8888ff, 0xdd9999ff, 0xeeaaaaff, 0xffbbbbff,
2140x8888ccff, 0x9999ddff, 0xaaaaeeff, 0xbbbbffff,
2150xcc88ccff, 0xdd99ddff, 0xeeaaeeff, 0xffbbffff,
2160xcc88ff, 0x11dd99ff, 0x22eeaaff, 0x33ffbbff,
2170x44cc88ff, 0x55dd99ff, 0x66eeaaff, 0x77ffbbff,
2180xccccff, 0x11ddddff, 0x22eeeeff, 0x33ffffff,
2190x44ccccff, 0x55ddddff, 0x66eeeeff, 0x77ffffff,
2200x88cc88ff, 0x99dd99ff, 0xaaeeaaff, 0xbbffbbff,
2210xcccc88ff, 0xdddd99ff, 0xeeeeaaff, 0xffffbbff,
2220x88ccccff, 0x99ddddff, 0xaaeeeeff, 0xbbffffff,
2230xccccccff, 0xddddddff, 0xeeeeeeff, 0xffffffff
224};
225
226static inline rosprite_error rosprite_read_word(reader reader, void* ctx, uint32_t* result);
227static rosprite_error rosprite_get_mode(uint32_t spriteMode, struct rosprite_mode* result);
228static uint32_t rosprite_palette_lookup(struct rosprite* sprite, uint32_t pixel);
229static inline uint32_t rosprite_cmyk_to_rgb(uint32_t cmyk);
230static uint32_t rosprite_next_mask_pixel(uint8_t* mask, struct rosprite_mask_state* mask_state);
231static rosprite_error rosprite_load_high_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header);
232static rosprite_error rosprite_load_low_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header);
233rosprite_error rosprite_load_sprite(reader reader, void* ctx, struct rosprite** result);
234static rosprite_error rosprite_init_mask_state(struct rosprite* sprite, struct rosprite_header* header, uint8_t* mask, struct rosprite_mask_state** result);
235static uint32_t rosprite_upscale_color(uint32_t pixel, struct rosprite_mode* mode, bool_Bool* has_alpha_pixel_data);
236static inline void rosprite_fix_alpha(uint32_t* image, unsigned long pixels);
237
238rosprite_error rosprite_load(reader reader, void* ctx, struct rosprite_area** result)
239{
240 uint32_t firstSpriteOffset, firstFreeWordOffset;
241 int bytes_read;
242 uint32_t i;
243
244 struct rosprite_area* sprite_area = malloc(sizeof(struct rosprite_area));
245
246 ERRCHK(rosprite_read_word(reader, ctx, &(sprite_area->sprite_count)))do { rosprite_error err = rosprite_read_word(reader, ctx, &
(sprite_area->sprite_count)); if (err != ROSPRITE_OK) return
err; } while(0)
;
1
Taking false branch
2
Loop condition is false. Exiting loop
247
248 ERRCHK(rosprite_read_word(reader, ctx, &firstSpriteOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, &
firstSpriteOffset); if (err != ROSPRITE_OK) return err; } while
(0)
;
3
Taking false branch
4
Loop condition is false. Exiting loop
249 ERRCHK(rosprite_read_word(reader, ctx, &firstFreeWordOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, &
firstFreeWordOffset); if (err != ROSPRITE_OK) return err; } while
(0)
; /* TODO: use this for some sanity checking? */
5
Taking false branch
6
Loop condition is false. Exiting loop
250 sprite_area->extension_size = 16 - firstSpriteOffset;
251
252 sprite_area->extension_words = NULL((void*)0);
253 if (sprite_area->extension_size > 0) {
7
Assuming field 'extension_size' is <= 0
8
Taking false branch
254 sprite_area->extension_words = malloc(sprite_area->extension_size);
255 bytes_read = reader(sprite_area->extension_words, (size_t) (sprite_area->extension_size), ctx);
256 if (bytes_read < (signed long) sprite_area->extension_size) {
257 return ROSPRITE_EOF;
258 }
259 }
260
261 sprite_area->sprites = malloc(sizeof(struct rosprite*) * sprite_area->sprite_count); /* allocate array of pointers */
262 for (i = 0; i
8.1
'i' is < field 'sprite_count'
< sprite_area->sprite_count; i++) {
9
Loop condition is true. Entering loop body
263 struct rosprite* sprite;
264 ERRCHK(rosprite_load_sprite(reader, ctx, &sprite))do { rosprite_error err = rosprite_load_sprite(reader, ctx, &
sprite); if (err != ROSPRITE_OK) return err; } while(0)
;
10
Calling 'rosprite_load_sprite'
265 sprite_area->sprites[i] = sprite;
266 }
267
268 *result = sprite_area;
269
270 return ROSPRITE_OK;
271}
272
273void rosprite_destroy_sprite_area(struct rosprite_area* sprite_area)
274{
275 uint32_t i;
276 for (i = 0; i < sprite_area->sprite_count; i++) {
277 struct rosprite* sprite = sprite_area->sprites[i];
278 if (sprite->has_palette) free(sprite->palette);
279 free(sprite->image);
280 free(sprite);
281 }
282
283 free(sprite_area->sprites);
284 if (sprite_area->extension_size > 0) free(sprite_area->extension_words);
285 free(sprite_area);
286}
287
288rosprite_error rosprite_load_palette(reader reader, void* ctx, struct rosprite_palette** result)
289{
290 uint32_t c;
291 uint8_t b[6];
292 unsigned int bytesRead;
293
294 /* TODO: currently assume palette has linear entries (2nd byte in is 00, 01, 02 etc) */
295 struct rosprite_palette* palette = malloc(sizeof(struct rosprite_palette));
296
297 palette->palette = malloc(sizeof(uint32_t) * 256); /* allocate 256 whether we need them all or not */
298
299 c = 0;
300
301 bytesRead = reader(b, 6, ctx);
302 assert(bytesRead % 6 == 0)((bytesRead % 6 == 0) ? (void) (0) : __assert_fail ("bytesRead % 6 == 0"
, "src/librosprite.c", 302, __extension__ __PRETTY_FUNCTION__
))
;
303 while (bytesRead == 6) {
304 assert(b[0] == 19)((b[0] == 19) ? (void) (0) : __assert_fail ("b[0] == 19", "src/librosprite.c"
, 304, __extension__ __PRETTY_FUNCTION__))
; /* VDU 19 */
305
306 /* only process logical colours */
307 if (b[2] == 16) {
308 /*assert(c == b[1]);*/
309
310 uint32_t entry = (b[3] << 24) | (b[4] << 16) | (b[5] << 8) | 0xff; /* last byte is alpha */
311 palette->palette[c] = entry;
312
313 c++;
314 assert(c <= 256)((c <= 256) ? (void) (0) : __assert_fail ("c <= 256", "src/librosprite.c"
, 314, __extension__ __PRETTY_FUNCTION__))
;
315 }
316
317 bytesRead = reader(b, 6, ctx);
318 assert(bytesRead % 6 == 0)((bytesRead % 6 == 0) ? (void) (0) : __assert_fail ("bytesRead % 6 == 0"
, "src/librosprite.c", 318, __extension__ __PRETTY_FUNCTION__
))
;
319 }
320
321 palette->size = c;
322
323 *result = palette;
324
325 return ROSPRITE_OK;
326}
327
328void rosprite_destroy_palette(struct rosprite_palette* palette)
329{
330 free(palette->palette);
331 free(palette);
332}
333
334rosprite_error rosprite_create_file_context(FILE* f, struct rosprite_file_context** result)
335{
336 struct rosprite_file_context* ctx = malloc(sizeof(struct rosprite_file_context));
337 if (!ctx) return ROSPRITE_NOMEM;
338 ctx->f = f;
339 *result = ctx;
340
341 return ROSPRITE_OK;
342}
343
344void rosprite_destroy_file_context(struct rosprite_file_context* ctx)
345{
346 free(ctx);
347}
348
349int rosprite_file_reader(uint8_t* buf, size_t count, void* ctx)
350{
351 return fread(buf, 1 /*size*/, count, ((struct rosprite_file_context*) ctx)->f);
352}
353
354rosprite_error rosprite_create_mem_context(uint8_t* p, unsigned long total_size, struct rosprite_mem_context** result)
355{
356 struct rosprite_mem_context* ctx = malloc(sizeof(struct rosprite_mem_context));
357 if (!ctx) return ROSPRITE_NOMEM;
358
359 ctx->base = p;
360 ctx->offset = 0;
361 ctx->size = total_size;
362 *result = ctx;
363
364 return ROSPRITE_OK;
365}
366
367void rosprite_destroy_mem_context(struct rosprite_mem_context* ctx)
368{
369 free(ctx);
370}
371
372int rosprite_mem_reader(uint8_t* buf, size_t count, void* ctx)
373{
374 size_t copy_size;
375 struct rosprite_mem_context* memctx = ctx;
376
377 /* if we're asked for more memory than the block contains,
378 * only copy as much as we can
379 */
380 if ((memctx->offset + count) > memctx->size) {
381 copy_size = memctx->size - memctx->offset;
382 } else {
383 copy_size = count;
384 }
385 memcpy(buf, memctx->base + memctx->offset, copy_size);
386 memctx->offset += copy_size;
387 return copy_size;
388}
389
390/**
391 * Load a single sprite.
392 *
393 * \param[out] result
394 */
395rosprite_error rosprite_load_sprite(reader reader, void* ctx, struct rosprite** result)
396{
397 uint32_t nextSpriteOffset;
398 uint32_t imageOffset;
399 uint32_t maskOffset, spriteModeWord;
400 uint32_t paletteEntries;
401 uint8_t* image;
402 uint8_t* mask = NULL((void*)0);
403
404 struct rosprite* sprite = malloc(sizeof(struct rosprite));
405 struct rosprite_header* header = malloc(sizeof(struct rosprite_header));
11
Memory is allocated
406
407 ERRCHK(rosprite_read_word(reader, ctx, &nextSpriteOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, &
nextSpriteOffset); if (err != ROSPRITE_OK) return err; } while
(0)
;
12
Taking true branch
13
Potential leak of memory pointed to by 'header'
408
409 reader(sprite->name, 12, ctx);
410 sprite->name[12] = '\0';
411
412 ERRCHK(rosprite_read_word(reader, ctx, &header->width_words))do { rosprite_error err = rosprite_read_word(reader, ctx, &
header->width_words); if (err != ROSPRITE_OK) return err; }
while(0)
; /* file has width - 1 and height - 1 */
413 header->width_words += 1;
414 ERRCHK(rosprite_read_word(reader, ctx, &(sprite->height)))do { rosprite_error err = rosprite_read_word(reader, ctx, &
(sprite->height)); if (err != ROSPRITE_OK) return err; } while
(0)
;
415 sprite->height += 1;
416 ERRCHK(rosprite_read_word(reader, ctx, &(header->first_used_bit)))do { rosprite_error err = rosprite_read_word(reader, ctx, &
(header->first_used_bit)); if (err != ROSPRITE_OK) return err
; } while(0)
; /* old format only (spriteType = 0) */
417 ERRCHK(rosprite_read_word(reader, ctx, &(header->last_used_bit)))do { rosprite_error err = rosprite_read_word(reader, ctx, &
(header->last_used_bit)); if (err != ROSPRITE_OK) return err
; } while(0)
;
418
419 ERRCHK(rosprite_read_word(reader, ctx, &imageOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, &
imageOffset); if (err != ROSPRITE_OK) return err; } while(0)
;
420 assert(imageOffset >= 44)((imageOffset >= 44) ? (void) (0) : __assert_fail ("imageOffset >= 44"
, "src/librosprite.c", 420, __extension__ __PRETTY_FUNCTION__
))
; /* should never be smaller than the size of the header) */
421
422 ERRCHK(rosprite_read_word(reader, ctx, &maskOffset))do { rosprite_error err = rosprite_read_word(reader, ctx, &
maskOffset); if (err != ROSPRITE_OK) return err; } while(0)
;
423 ERRCHK(rosprite_read_word(reader, ctx, &spriteModeWord))do { rosprite_error err = rosprite_read_word(reader, ctx, &
spriteModeWord); if (err != ROSPRITE_OK) return err; } while(
0)
;
424
425 ERRCHK(rosprite_get_mode(spriteModeWord, &(sprite->mode)))do { rosprite_error err = rosprite_get_mode(spriteModeWord, &
(sprite->mode)); if (err != ROSPRITE_OK) return err; } while
(0)
;
426
427 /* TODO left-hand wastage */
428
429 assert((header->last_used_bit + 1) % sprite->mode.colorbpp == 0)(((header->last_used_bit + 1) % sprite->mode.colorbpp ==
0) ? (void) (0) : __assert_fail ("(header->last_used_bit + 1) % sprite->mode.colorbpp == 0"
, "src/librosprite.c", 429, __extension__ __PRETTY_FUNCTION__
))
;
430 /*assert(header->width_words % sprite->mode->colorbpp == 0);*/
431 sprite->width = (header->width_words * 32 - header->first_used_bit - (31 - header->last_used_bit)) / sprite->mode.colorbpp;
432
433 sprite->palettesize = imageOffset - 44;
434 sprite->has_palette = (sprite->palettesize > 0);
435
436 /* sprite has no mask if imageOffset == maskOffset */
437 if (imageOffset == maskOffset) {
438 sprite->has_mask = false0;
439 header->image_size = nextSpriteOffset - 44 - sprite->palettesize;
440 header->mask_size = 0;
441 } else {
442 sprite->has_mask = true1;
443 header->image_size = maskOffset - imageOffset;
444 header->mask_size = nextSpriteOffset - 44 - sprite->palettesize - header->image_size;
445 }
446
447 if (sprite->has_palette) {
448 uint32_t j, word1, word2, entry;
449 assert(sprite->palettesize % 8 == 0)((sprite->palettesize % 8 == 0) ? (void) (0) : __assert_fail
("sprite->palettesize % 8 == 0", "src/librosprite.c", 449
, __extension__ __PRETTY_FUNCTION__))
;
450 sprite->palette = malloc(sizeof(uint32_t) * sprite->palettesize);
451 paletteEntries = sprite->palettesize / 8;
452
453 /* Each palette entry is two words big
454 * The second word is a duplicate of the first
455 * I think this is in case you ever wanted flashing colours
456 * PRM1-730
457 */
458 for (j = 0; j < paletteEntries; j++) {
459 ERRCHK(rosprite_read_word(reader, ctx, &word1))do { rosprite_error err = rosprite_read_word(reader, ctx, &
word1); if (err != ROSPRITE_OK) return err; } while(0)
;
460 ERRCHK(rosprite_read_word(reader, ctx, &word2))do { rosprite_error err = rosprite_read_word(reader, ctx, &
word2); if (err != ROSPRITE_OK) return err; } while(0)
;
461 assert(word1 == word2)((word1 == word2) ? (void) (0) : __assert_fail ("word1 == word2"
, "src/librosprite.c", 461, __extension__ __PRETTY_FUNCTION__
))
; /* if they aren't equal, flashing colours are desired, which we don't support */
462
463 /* swap rr and bb parts -- PRM1-731 */
464 entry = ((word1 & 0xff000000) >> 16) | (word1 & 0x00ff0000) | ((word1 & 0x0000ff00) << 16) | 0xff;
465 sprite->palette[j] = entry;
466 }
467 }
468
469 image = malloc(header->image_size);
470 reader(image, header->image_size, ctx);
471
472 if (sprite->has_mask) {
473 mask = malloc(header->mask_size);
474 reader(mask, header->mask_size, ctx);
475 }
476
477 /* sanity check image_size */
478 assert((header->width_words) * 4 * (sprite->height) == header->image_size)(((header->width_words) * 4 * (sprite->height) == header
->image_size) ? (void) (0) : __assert_fail ("(header->width_words) * 4 * (sprite->height) == header->image_size"
, "src/librosprite.c", 478, __extension__ __PRETTY_FUNCTION__
))
;
479 /* TODO: sanity check mask_size */
480 if (sprite->mode.colorbpp > 8) {
481 ERRCHK(rosprite_load_high_color(image, mask, sprite, header))do { rosprite_error err = rosprite_load_high_color(image, mask
, sprite, header); if (err != ROSPRITE_OK) return err; } while
(0)
;
482 } else {
483 ERRCHK(rosprite_load_low_color(image, mask, sprite, header))do { rosprite_error err = rosprite_load_low_color(image, mask
, sprite, header); if (err != ROSPRITE_OK) return err; } while
(0)
;
484 }
485
486 free(image);
487 free(mask);
488 free(header);
489
490 *result = sprite;
491
492 return ROSPRITE_OK;
493}
494
495/**
496 * Determine the sprite_mode for the specified sprite_mode_word.
497 *
498 * \param[out] result
499 */
500static rosprite_error rosprite_get_mode(uint32_t sprite_mode_word, struct rosprite_mode* result)
501{
502 struct rosprite_mode mode;
503
504 uint32_t spriteType = (sprite_mode_word & (15 << 27)) >> 27; /* preserve bits 27-30 only */
505
506 if (spriteType != 0) {
507 bool_Bool hasEightBitAlpha = sprite_mode_word >> 31; /* bit 31 */
508 /* new modes have 1bpp masks (PRM5a-111)
509 * unless bit 31 is set (http://select.riscos.com/prm/graphics/sprites/alphachannel.html)
510 */
511 mode.maskbpp = (hasEightBitAlpha ? 8 : 1);
512 mode.mask_width = mode.maskbpp;
513 mode.xdpi = (sprite_mode_word & (8191 << 14)) >> 14; /* preserve bits 14-26 only */
514 mode.ydpi = (sprite_mode_word & (8191 << 1)) >> 1; /* preserve bits 1-13 only */
515
516 mode.color_model = ROSPRITE_RGB;
517 switch (spriteType) {
518 case 1:
519 mode.colorbpp = 1; break;
520 case 2:
521 mode.colorbpp = 2; break;
522 case 3:
523 mode.colorbpp = 4; break;
524 case 4:
525 mode.colorbpp = 8; break;
526 case 5:
527 mode.colorbpp = 16; break;
528 case 6:
529 mode.colorbpp = 32; break;
530 case 7:
531 mode.colorbpp = 32;
532 mode.color_model = ROSPRITE_CMYK;
533 break;
534 case 8:
535 mode.colorbpp = 24; break;
536 default:
537 return ROSPRITE_BADMODE;
538 }
539 } else {
540 assert(sprite_mode_word < 256)((sprite_mode_word < 256) ? (void) (0) : __assert_fail ("sprite_mode_word < 256"
, "src/librosprite.c", 540, __extension__ __PRETTY_FUNCTION__
))
; /* don't think you can have modes over 255? */
541
542 mode = oldmodes[sprite_mode_word];
543 }
544
545 /* illegal mode check */
546 if ((mode.colorbpp == 0) || (mode.xdpi == 0) || (mode.ydpi == 0)) {
547 return ROSPRITE_BADMODE;
548 }
549
550 memcpy(result, &mode, sizeof(struct rosprite_mode));
551
552 return ROSPRITE_OK;
553}
554
555/**
556 * Load a sprite image with 16 or more bpp.
557 *
558 * \param[out] sprite On exit, sprite.image will be populated
559 */
560static rosprite_error rosprite_load_high_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header)
561{
562 struct rosprite_mask_state* mask_state = NULL((void*)0);
563 uint32_t currentByteIndex = 0;
564 uint32_t j, x, y, x_pixels, pixel;
565 bool_Bool has_alpha_pixel_data = false0;
566 uint32_t b;
567 bool_Bool old_has_alpha;
568
569 if (sprite->has_mask) {
570 ERRCHK(rosprite_init_mask_state(sprite, header, mask, &mask_state))do { rosprite_error err = rosprite_init_mask_state(sprite, header
, mask, &mask_state); if (err != ROSPRITE_OK) return err;
} while(0)
;
571 }
572
573 sprite->image = malloc(sprite->width * sprite->height * 4); /* all image data is 32bpp going out */
574
575 /* Spec says that there must be no left-hand wastage */
576 assert(header->first_used_bit == 0)((header->first_used_bit == 0) ? (void) (0) : __assert_fail
("header->first_used_bit == 0", "src/librosprite.c", 576,
__extension__ __PRETTY_FUNCTION__))
;
577
578 {
579 const uint32_t bpp = sprite->mode.colorbpp;
580 const uint32_t bytesPerPixel = bpp / 8;
581 const uint32_t row_max_bit = header->width_words * 32 - (31 - header->last_used_bit); /* Last used bit in row */
582
583 for (y = 0; y < sprite->height; y++) {
584 x_pixels = 0;
585 for (x = 0; x < row_max_bit; x += bpp) {
586 pixel = 0;
587 for (j = 0; j < bytesPerPixel; j++) {
588 b = image_in[currentByteIndex++];
589 pixel = pixel | (b << (j * 8));
590 }
591
592 old_has_alpha = has_alpha_pixel_data;
593 pixel = rosprite_upscale_color(pixel, &(sprite->mode), &has_alpha_pixel_data);
594 if (old_has_alpha != has_alpha_pixel_data && (y > 0 || x_pixels > 0)) {
595 rosprite_fix_alpha(sprite->image, (y * sprite->width) + x_pixels - 1);
596 }
597 if (sprite->has_mask) {
598 uint8_t mask_pixel = rosprite_next_mask_pixel(mask, mask_state);
599 pixel = (pixel & 0xffffff00) | mask_pixel;
600 }
601 sprite->image[y*sprite->width + x_pixels] = pixel;
602 x_pixels++;
603 }
604
605 /* Ensure byte index is pointing at start of next row */
606 if (y + 1 < sprite->height) {
607 currentByteIndex = (currentByteIndex + 3) & ~3; /* Round up to next multiple of 4 */
608 }
609 }
610 }
611 if (sprite->has_mask) free(mask_state);
612 return ROSPRITE_OK;
613}
614
615/**
616 * Iterate over the specified number of pixels, starting at the image pointer,
617 * and set the alpha channel to 0x00.
618 */
619static inline void rosprite_fix_alpha(uint32_t* image, unsigned long pixels)
620{
621 uint32_t i;
622 for (i = 0; i <= pixels; i++) {
623 image[i] = image[i] & 0xffffff00;
624 }
625}
626
627/**
628 * Load a sprite image with 8 or fewer bpp.
629 *
630 * \param[out] sprite On exit, sprite.image will be populated
631 */
632static rosprite_error rosprite_load_low_color(uint8_t* image_in, uint8_t* mask, struct rosprite* sprite, struct rosprite_header* header)
633{
634 uint32_t current_byte_index, currentword;
635 uint32_t x, y, x_pixels, pixel;
636 uint8_t mask_pixel;
637
638 struct rosprite_mask_state* mask_state = NULL((void*)0);
639 if (sprite->has_mask) {
640 ERRCHK(rosprite_init_mask_state(sprite, header, mask, &mask_state))do { rosprite_error err = rosprite_init_mask_state(sprite, header
, mask, &mask_state); if (err != ROSPRITE_OK) return err;
} while(0)
;
641 }
642
643 sprite->image = malloc(sprite->width * sprite->height * 4); /* all image data is 32bpp going out */
644
645 {
646 const uint32_t bpp = sprite->mode.colorbpp;
647 const uint32_t row_max_bit = header->width_words * 32 - (31 - header->last_used_bit); /* Last used bit in row */
648 const uint32_t bitmask = (1 << bpp) - 1; /* creates a mask of 1s that is bpp bits wide */
649
650 current_byte_index = 0;
651 currentword = BTUINT((image_in + current_byte_index))((unsigned)(image_in + current_byte_index)[0] | ((unsigned)(image_in
+ current_byte_index)[1] << 8) | ((unsigned)(image_in +
current_byte_index)[2] << 16) | ((unsigned)(image_in +
current_byte_index)[3] << 24))
;
652 current_byte_index += 4;
653
654 for (y = 0; y < sprite->height; y++) {
655 x_pixels = 0;
656 for (x = header->first_used_bit; x < row_max_bit ; x += bpp) {
657 const uint32_t offset_into_word = x % 32;
658
659 pixel = (currentword & (bitmask << offset_into_word)) >> offset_into_word;
660 pixel = rosprite_palette_lookup(sprite, pixel); /* lookup returns 32bpp */
661 if (sprite->has_mask) {
662 mask_pixel = rosprite_next_mask_pixel(mask, mask_state);
663 pixel = (pixel & 0xffffff00) | mask_pixel;
664 }
665 sprite->image[y*sprite->width + x_pixels] = pixel;
666 x_pixels++;
667
668 /* If we're not at the end of the row and we've processed all of this word, fetch the next one */
669 if (x + bpp < row_max_bit && offset_into_word + bpp == 32) {
670 currentword = BTUINT((image_in + current_byte_index))((unsigned)(image_in + current_byte_index)[0] | ((unsigned)(image_in
+ current_byte_index)[1] << 8) | ((unsigned)(image_in +
current_byte_index)[2] << 16) | ((unsigned)(image_in +
current_byte_index)[3] << 24))
;
671 current_byte_index += 4;
672 }
673 }
674
675 /* Advance to first word of next row */
676 if (y + 1 < sprite->height) {
677 currentword = BTUINT((image_in + current_byte_index))((unsigned)(image_in + current_byte_index)[0] | ((unsigned)(image_in
+ current_byte_index)[1] << 8) | ((unsigned)(image_in +
current_byte_index)[2] << 16) | ((unsigned)(image_in +
current_byte_index)[3] << 24))
;
678 current_byte_index += 4;
679 }
680 }
681 }
682 if (sprite->has_mask) free(mask_state);
683
684 return ROSPRITE_OK;
685}
686
687static uint32_t rosprite_palette_lookup(struct rosprite* sprite, uint32_t pixel)
688{
689 uint32_t translated_pixel;
690 /* because we're dealing with 8bpp or less */
691 if (sprite->has_palette) {
692
693 if(pixel < (sprite->palettesize / 8)) {
694 translated_pixel = sprite->palette[pixel];
695 } else {
696 translated_pixel = sprite_8bpp_palette[pixel];
697 }
698 } else {
699 switch (sprite->mode.colorbpp) {
700 case 8:
701 assert(pixel < 256)((pixel < 256) ? (void) (0) : __assert_fail ("pixel < 256"
, "src/librosprite.c", 701, __extension__ __PRETTY_FUNCTION__
))
;
702 translated_pixel = sprite_8bpp_palette[pixel];
703 break;
704 case 4:
705 assert(pixel < 16)((pixel < 16) ? (void) (0) : __assert_fail ("pixel < 16"
, "src/librosprite.c", 705, __extension__ __PRETTY_FUNCTION__
))
;
706 translated_pixel = sprite_4bpp_palette[pixel];
707 break;
708 case 2:
709 assert(pixel < 4)((pixel < 4) ? (void) (0) : __assert_fail ("pixel < 4",
"src/librosprite.c", 709, __extension__ __PRETTY_FUNCTION__)
)
;
710 translated_pixel = sprite_2bpp_palette[pixel];
711 break;
712 case 1:
713 assert(pixel < 2)((pixel < 2) ? (void) (0) : __assert_fail ("pixel < 2",
"src/librosprite.c", 713, __extension__ __PRETTY_FUNCTION__)
)
;
714 translated_pixel = sprite_1bpp_palette[pixel];
715 break;
716 default:
717 translated_pixel = 0;
718 assert(false)((0) ? (void) (0) : __assert_fail ("false", "src/librosprite.c"
, 718, __extension__ __PRETTY_FUNCTION__))
;
719 }
720 }
721 return translated_pixel;
722}
723
724static rosprite_error rosprite_init_mask_state(struct rosprite* sprite, struct rosprite_header* header, uint8_t* mask, struct rosprite_mask_state** result)
725{
726 struct rosprite_mask_state* mask_state = malloc(sizeof(struct rosprite_mask_state));
727 if (!mask_state) return ROSPRITE_NOMEM;
728
729 mask_state->x = header->first_used_bit;
730 mask_state->y = 0;
731 mask_state->first_used_bit = header->first_used_bit;
732 mask_state->row_max_bit = sprite->width * sprite->mode.mask_width;
733 mask_state->height = sprite->height;
734 mask_state->bpp = sprite->mode.mask_width;
735 mask_state->current_word = BTUINT(mask)((unsigned)mask[0] | ((unsigned)mask[1] << 8) | ((unsigned
)mask[2] << 16) | ((unsigned)mask[3] << 24))
;
736 mask_state->current_byte_index = 4;
737
738 *result = mask_state;
739
740 return ROSPRITE_OK;
741}
742
743/**
744 * Get the next mask byte.
745 * A mask of 0xff denotes 100% opaque, 0x00 denotes 100% transparent.
746 *
747 * \param[in,out] mask_state
748 */
749static uint32_t rosprite_next_mask_pixel(uint8_t* mask, struct rosprite_mask_state* mask_state)
750{
751 /* a 1bpp mask (for new mode sprites), each row is word aligned (therefore potential righthand wastage */
752 const uint32_t bitmask = (1 << mask_state->bpp) - 1;
753 const uint32_t offset_into_word = mask_state->x % 32;
754 uint32_t pixel = (mask_state->current_word & (bitmask << offset_into_word)) >> offset_into_word;
755
756 if (mask_state->x + mask_state->bpp < mask_state->row_max_bit && offset_into_word + mask_state->bpp == 32) {
757 mask_state->current_word = BTUINT((mask + mask_state->current_byte_index))((unsigned)(mask + mask_state->current_byte_index)[0] | ((
unsigned)(mask + mask_state->current_byte_index)[1] <<
8) | ((unsigned)(mask + mask_state->current_byte_index)[2
] << 16) | ((unsigned)(mask + mask_state->current_byte_index
)[3] << 24))
;
758 mask_state->current_byte_index += 4;
759 }
760
761 mask_state->x += mask_state->bpp;
762 if (mask_state->x >= mask_state->row_max_bit) {
763 mask_state->x = mask_state->first_used_bit;
764
765 if (mask_state->y + 1 < mask_state->height) {
766 mask_state->current_word = BTUINT((mask + mask_state->current_byte_index))((unsigned)(mask + mask_state->current_byte_index)[0] | ((
unsigned)(mask + mask_state->current_byte_index)[1] <<
8) | ((unsigned)(mask + mask_state->current_byte_index)[2
] << 16) | ((unsigned)(mask + mask_state->current_byte_index
)[3] << 24))
;
767 mask_state->current_byte_index += 4;
768 }
769
770 mask_state->y++;
771 }
772
773 /*
774 * if the mask is 1bpp, make sure the whole byte is 0x00 or 0xff
775 */
776 if (mask_state->bpp < 8) {
777 pixel = (pixel & 1) ? 0xff : 0x00;
778 }
779
780 return pixel;
781}
782
783/**
784 * Upscale a 16, 24 or 32bpp sprite to the 0xRRGGBBAA representation.
785 * Do not call this function with a sprite with less than 16bpp,
786 * but use a palette lookup instead.
787 */
788static uint32_t rosprite_upscale_color(uint32_t pixel, struct rosprite_mode* mode, bool_Bool* has_alpha_pixel_data)
789{
790 uint8_t alpha;
791 switch (mode->colorbpp) {
792 case 32:
793 if (mode->color_model == ROSPRITE_RGB) {
794 /* swap from 0xAABBGGRR to 0xRRGGBBAA */
795 pixel = BSWAP(pixel)(((pixel & (0x000000ff)) << 24) | ((pixel & 0x0000ff00
) << 8) | ((pixel & 0x00ff0000) >> 8) | ((pixel
& 0xff000000) >> 24))
;
796 } else {
797 pixel = rosprite_cmyk_to_rgb(pixel);
798 }
799 break;
800 case 24:
801 /* reverse byte order */
802 pixel = BSWAP(pixel)(((pixel & (0x000000ff)) << 24) | ((pixel & 0x0000ff00
) << 8) | ((pixel & 0x00ff0000) >> 8) | ((pixel
& 0xff000000) >> 24))
;
803 break;
804 case 16:
805 /* incoming format is b_00000000000000000bbbbbgggggrrrrr */
806 {
807 uint8_t red = pixel & 31;
808 uint8_t green = (pixel & (31 << 5)) >> 5;
809 uint8_t blue = (pixel & (31 << 10)) >> 10;
810
811 /* sanity check */
812 assert(red < 32)((red < 32) ? (void) (0) : __assert_fail ("red < 32", "src/librosprite.c"
, 812, __extension__ __PRETTY_FUNCTION__))
;
813 assert(green < 32)((green < 32) ? (void) (0) : __assert_fail ("green < 32"
, "src/librosprite.c", 813, __extension__ __PRETTY_FUNCTION__
))
;
814 assert(blue < 32)((blue < 32) ? (void) (0) : __assert_fail ("blue < 32",
"src/librosprite.c", 814, __extension__ __PRETTY_FUNCTION__)
)
;
815
816 pixel = ((uint32_t)sprite_16bpp_translate[red] << 24)|
817 ((uint32_t)sprite_16bpp_translate[green] << 16)|
818 ((uint32_t)sprite_16bpp_translate[blue] << 8);
819 }
820 break;
821 case 8:
822 case 4:
823 case 2:
824 case 1:
825 assert(false)((0) ? (void) (0) : __assert_fail ("false", "src/librosprite.c"
, 825, __extension__ __PRETTY_FUNCTION__))
; /* shouldn't need to call for <= 8bpp, since a palette lookup will return 32bpp */
826 default:
827 assert(false)((0) ? (void) (0) : __assert_fail ("false", "src/librosprite.c"
, 827, __extension__ __PRETTY_FUNCTION__))
; /* unknown bpp */
828 }
829
830 alpha = pixel & 0xff;
831 if (alpha == 0x00) {
832 if (!(*has_alpha_pixel_data)) {
833 pixel = pixel | 0xff;
834 }
835 } else {
836 *has_alpha_pixel_data = true1;
837 }
838 return pixel;
839}
840
841static inline uint32_t rosprite_cmyk_to_rgb(uint32_t cmyk)
842{
843 uint8_t c = cmyk & 0xff;
844 uint8_t m = (cmyk & 0xff00) >> 8;
845 uint8_t y = (cmyk & 0xff0000) >> 16;
846 uint8_t k = cmyk >> 24;
847
848 /* Convert to CMY colourspace */
849 uint8_t C = c + k;
850 uint8_t M = m + k;
851 uint8_t Y = y + k;
852
853 /* And to RGB */
854 uint8_t r = 255 - C;
855 uint8_t g = 255 - M;
856 uint8_t b = 255 - Y;
857
858 return r << 24 | g << 16 | b << 8;
859}
860
861static inline rosprite_error rosprite_read_word(reader reader, void* ctx, uint32_t* result)
862{
863 unsigned char b[4];
864 if (reader(b, 4, ctx) < 4) {
865 return ROSPRITE_EOF;
866 }
867 *result = BTUINT(b)((unsigned)b[0] | ((unsigned)b[1] << 8) | ((unsigned)b[
2] << 16) | ((unsigned)b[3] << 24))
;
868 return ROSPRITE_OK;
869}