MCPcopy Create free account
hub / github.com/OpenTTD/OpenTTD / DecodeSingleSprite

Function DecodeSingleSprite

src/spriteloader/grf.cpp:57–213  ·  view source on GitHub ↗

* Decode the image data of a single sprite. * @param[in,out] sprite Filled with the sprite image data. * @param file The file with the sprite data. * @param file_pos File position. * @param sprite_type Type of the sprite we're decoding. * @param num Size of the decompressed sprite. * @param type Type of the encoded sprite. * @param zoom_lvl Requested zoom level. * @param colour_fmt Colour

Source from the content-addressed store, hash-verified

55 * @return True if the sprite was successfully loaded.
56 */
57bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, int64_t num, uint8_t type, ZoomLevel zoom_lvl, SpriteComponents colour_fmt, uint8_t container_format)
58{
59 /*
60 * Original sprite height was max 255 pixels, with 4x extra zoom => 1020 pixels.
61 * Original maximum width for sprites was 640 pixels, with 4x extra zoom => 2560 pixels.
62 * Now up to 5 bytes per pixel => 1020 * 2560 * 5 => ~ 12.5 MiB.
63 *
64 * So, any sprite data more than 64 MiB is way larger that we would even expect; prevent allocating more memory!
65 */
66 if (num < 0 || num > 64 * 1024 * 1024) return WarnCorruptSprite(file, file_pos, __LINE__);
67
68 std::unique_ptr<uint8_t[]> dest_orig = std::make_unique<uint8_t[]>(num);
69 uint8_t *dest = dest_orig.get();
70 const int64_t dest_size = num;
71
72 /* Read the file, which has some kind of compression */
73 while (num > 0) {
74 int8_t code = file.ReadByte();
75
76 if (code >= 0) {
77 /* Plain bytes to read */
78 int size = (code == 0) ? 0x80 : code;
79 num -= size;
80 if (num < 0) return WarnCorruptSprite(file, file_pos, __LINE__);
81 for (; size > 0; size--) {
82 *dest = file.ReadByte();
83 dest++;
84 }
85 } else {
86 /* Copy bytes from earlier in the sprite */
87 const uint data_offset = ((code & 7) << 8) | file.ReadByte();
88 if (dest - data_offset < dest_orig.get()) return WarnCorruptSprite(file, file_pos, __LINE__);
89 int size = -(code >> 3);
90 num -= size;
91 if (num < 0) return WarnCorruptSprite(file, file_pos, __LINE__);
92 for (; size > 0; size--) {
93 *dest = *(dest - data_offset);
94 dest++;
95 }
96 }
97 }
98
99 if (num != 0) return WarnCorruptSprite(file, file_pos, __LINE__);
100
101 sprite->AllocateData(zoom_lvl, static_cast<size_t>(sprite->width) * sprite->height);
102
103 /* Convert colour depth to pixel size. */
104 int bpp = 0;
105 if (colour_fmt.Test(SpriteComponent::RGB)) bpp += 3; // Has RGB data.
106 if (colour_fmt.Test(SpriteComponent::Alpha)) bpp++; // Has alpha data.
107 if (colour_fmt.Test(SpriteComponent::Palette)) bpp++; // Has palette data.
108
109 /* When there are transparency pixels, this format has another trick.. decode it */
110 if (type & 0x08) {
111 for (int y = 0; y < sprite->height; y++) {
112 bool last_item = false;
113 /* Look up in the header-table where the real data is stored for this row */
114 int offset;

Callers 2

LoadSpriteV1Function · 0.85
LoadSpriteV2Function · 0.85

Calls 6

WarnCorruptSpriteFunction · 0.85
AllocateDataMethod · 0.80
TestMethod · 0.80
NeedsPaletteRemapMethod · 0.80
getMethod · 0.45
ReadByteMethod · 0.45

Tested by

no test coverage detected