1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "pcx.h"
23
24 #include "ifilesystem.h"
25
26 typedef unsigned char byte;
27
28 #include <stdlib.h>
29
30 #include "imagelib.h"
31 #include "bytestreamutils.h"
32
33 /*
34 =================================================================
35
36 PCX LOADING
37
38 =================================================================
39 */
40
41 typedef struct
42 {
43 unsigned char manufacturer;
44 unsigned char version;
45 unsigned char encoding;
46 unsigned char bits_per_pixel;
47 unsigned short xmin, ymin, xmax, ymax;
48 unsigned short hres, vres;
49 unsigned char palette[48];
50 unsigned char reserved;
51 unsigned char color_planes;
52 unsigned short bytes_per_line;
53 unsigned short palette_type;
54 unsigned char filler[58];
55 unsigned char data; // unbounded
56 } pcx_t;
57
58 /*
59 ==============
60 LoadPCX
61 ==============
62 */
63
64 struct PCXRLEPacket
65 {
66 byte data;
67 int length;
68 };
69
ByteStream_readPCXRLEPacket(PointerInputStream & inputStream,PCXRLEPacket & packet)70 inline void ByteStream_readPCXRLEPacket(PointerInputStream& inputStream, PCXRLEPacket& packet)
71 {
72 byte d;
73 inputStream.read(&d, 1);
74 if((d & 0xC0) == 0xC0)
75 {
76 packet.length = d & 0x3F;
77 inputStream.read(&packet.data, 1);
78 }
79 else
80 {
81 packet.length = 1;
82 packet.data = d;
83 }
84 }
85
LoadPCXBuff(byte * buffer,std::size_t len,byte ** pic,byte ** palette,int * width,int * height)86 void LoadPCXBuff(byte* buffer, std::size_t len, byte **pic, byte **palette, int *width, int *height )
87 {
88 *pic = 0;
89
90 pcx_t pcx;
91 int x, y, lsize;
92 byte *out, *pix;
93
94 /* parse the PCX file */
95
96 PointerInputStream inputStream(buffer);
97
98 pcx.manufacturer = istream_read_byte(inputStream);
99 pcx.version = istream_read_byte(inputStream);
100 pcx.encoding = istream_read_byte(inputStream);
101 pcx.bits_per_pixel = istream_read_byte(inputStream);
102 pcx.xmin = istream_read_int16_le(inputStream);
103 pcx.ymin = istream_read_int16_le(inputStream);
104 pcx.xmax = istream_read_int16_le(inputStream);
105 pcx.ymax = istream_read_int16_le(inputStream);
106 pcx.hres = istream_read_int16_le(inputStream);
107 pcx.vres = istream_read_int16_le(inputStream);
108 inputStream.read(pcx.palette, 48);
109 pcx.reserved = istream_read_byte(inputStream);
110 pcx.color_planes = istream_read_byte(inputStream);
111 pcx.bytes_per_line = istream_read_int16_le(inputStream);
112 pcx.palette_type = istream_read_int16_le(inputStream);
113 inputStream.read(pcx.filler, 58);
114
115
116 if (pcx.manufacturer != 0x0a
117 || pcx.version != 5
118 || pcx.encoding != 1
119 || pcx.bits_per_pixel != 8)
120 return;
121
122 if (width)
123 *width = pcx.xmax+1;
124 if (height)
125 *height = pcx.ymax+1;
126
127 if (!pic)
128 return;
129
130 out = (byte *)malloc ( (pcx.ymax+1) * (pcx.xmax+1) );
131
132 *pic = out;
133 pix = out;
134
135 /* RR2DO2: pcx fix */
136 lsize = pcx.color_planes * pcx.bytes_per_line;
137
138 /* go scanline by scanline */
139 for( y = 0; y <= pcx.ymax; y++, pix += pcx.xmax + 1 )
140 {
141 /* do a scanline */
142 for( x=0; x <= pcx.xmax; )
143 {
144 /* RR2DO2 */
145 PCXRLEPacket packet;
146 ByteStream_readPCXRLEPacket(inputStream, packet);
147
148 while(packet.length-- > 0)
149 {
150 pix[ x++ ] = packet.data;
151 }
152 }
153
154 /* RR2DO2: discard any other data */
155 PCXRLEPacket packet;
156 while( x < lsize )
157 {
158 ByteStream_readPCXRLEPacket(inputStream, packet);
159 x++;
160 }
161 while( packet.length-- > 0 )
162 {
163 x++;
164 }
165 }
166
167 /* validity check */
168 if( std::size_t(inputStream.get() - buffer) > len)
169 {
170 *pic = 0;
171 }
172
173 if (palette)
174 {
175 *palette = (byte *)malloc(768);
176 memcpy (*palette, buffer + len - 768, 768);
177 }
178 }
179
180 /*
181 ==============
182 LoadPCX32
183 ==============
184 */
LoadPCX32Buff(byte * buffer,std::size_t length)185 Image* LoadPCX32Buff(byte* buffer, std::size_t length)
186 {
187 byte *palette;
188 byte *pic8;
189 int i, c, p, width, height;
190 byte *pic32;
191
192 LoadPCXBuff(buffer, length, &pic8, &palette, &width, &height);
193 if (!pic8)
194 {
195 return 0;
196 }
197
198 RGBAImage* image = new RGBAImage(width, height);
199 c = (width) * (height);
200 pic32 = image->getRGBAPixels();
201 for (i = 0; i < c; i++)
202 {
203 p = pic8[i];
204 pic32[0] = palette[p * 3];
205 pic32[1] = palette[p * 3 + 1];
206 pic32[2] = palette[p * 3 + 2];
207 pic32[3] = 255;
208 pic32 += 4;
209 }
210
211 free (pic8);
212 free (palette);
213
214 return image;
215 }
216
LoadPCX32(ArchiveFile & file)217 Image* LoadPCX32(ArchiveFile& file)
218 {
219 ScopedArchiveBuffer buffer(file);
220 return LoadPCX32Buff(buffer.buffer, buffer.length);
221 }
222
223