1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4               2008 Ludwig Nussel
5 
6 This file is part of Quake III Arena source code.
7 
8 Quake III Arena source code is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12 
13 Quake III Arena source code is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Quake III Arena source code; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 ===========================================================================
22 */
23 
24 #include "tr_local.h"
25 
26 /*
27 ========================================================================
28 
29 PCX files are used for 8 bit images
30 
31 ========================================================================
32 */
33 
34 typedef struct {
35 	char	manufacturer;
36 	char	version;
37 	char	encoding;
38 	char	bits_per_pixel;
39 	unsigned short	xmin,ymin,xmax,ymax;
40 	unsigned short	hres,vres;
41 	unsigned char	palette[48];
42 	char	reserved;
43 	char	color_planes;
44 	unsigned short	bytes_per_line;
45 	unsigned short	palette_type;
46 	unsigned short	hscreensize, vscreensize;
47 	char	filler[54];
48 	unsigned char	data[];
49 } pcx_t;
50 
R_LoadPCX(const char * filename,byte ** pic,int * width,int * height)51 void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
52 {
53 	union {
54 		byte *b;
55 		void *v;
56 	} raw;
57 	byte	*end;
58 	pcx_t	*pcx;
59 	int		len;
60 	unsigned char	dataByte = 0, runLength = 0;
61 	byte	*out, *pix;
62 	unsigned short w, h;
63 	byte	*pic8;
64 	byte	*palette;
65 	int	i;
66 	unsigned size = 0;
67 
68 	if (width)
69 		*width = 0;
70 	if (height)
71 		*height = 0;
72 	*pic = NULL;
73 
74 	//
75 	// load the file
76 	//
77 	len = ri.FS_ReadFile( ( char * ) filename, &raw.v);
78 	if (!raw.b || len < 0) {
79 		return;
80 	}
81 
82 	if((unsigned)len < sizeof(pcx_t))
83 	{
84 		ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename);
85 		ri.FS_FreeFile (raw.v);
86 		return;
87 	}
88 
89 	//
90 	// parse the PCX file
91 	//
92 	pcx = (pcx_t *)raw.b;
93 	end = raw.b+len;
94 
95 	w = LittleShort(pcx->xmax)+1;
96 	h = LittleShort(pcx->ymax)+1;
97 	size = w*h;
98 
99 	if (pcx->manufacturer != 0x0a
100 		|| pcx->version != 5
101 		|| pcx->encoding != 1
102 		|| pcx->color_planes != 1
103 		|| pcx->bits_per_pixel != 8
104 		|| w >= 1024
105 		|| h >= 1024)
106 	{
107 		ri.Printf (PRINT_ALL, "Bad or unsupported pcx file %s (%dx%d@%d)\n", filename, w, h, pcx->bits_per_pixel);
108 		return;
109 	}
110 
111 	pix = pic8 = ri.Z_Malloc ( size );
112 
113 	raw.b = pcx->data;
114 	// FIXME: should use bytes_per_line but original q3 didn't do that either
115 	while(pix < pic8+size)
116 	{
117 		if(runLength > 0) {
118 			*pix++ = dataByte;
119 			--runLength;
120 			continue;
121 		}
122 
123 		if(raw.b+1 > end)
124 			break;
125 		dataByte = *raw.b++;
126 
127 		if((dataByte & 0xC0) == 0xC0)
128 		{
129 			if(raw.b+1 > end)
130 				break;
131 			runLength = dataByte & 0x3F;
132 			dataByte = *raw.b++;
133 		}
134 		else
135 			runLength = 1;
136 	}
137 
138 	if(pix < pic8+size)
139 	{
140 		ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
141 		ri.FS_FreeFile (pcx);
142 		ri.Free (pic8);
143 	}
144 
145 	if (raw.b-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
146 	{
147 		ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
148 		ri.FS_FreeFile (pcx);
149 		ri.Free (pic8);
150 		return;
151 	}
152 
153 	palette = end-768;
154 
155 	pix = out = ri.Z_Malloc(4 * size );
156 	for (i = 0 ; i < size ; i++)
157 	{
158 		unsigned char p = pic8[i];
159 		pix[0] = palette[p*3];
160 		pix[1] = palette[p*3 + 1];
161 		pix[2] = palette[p*3 + 2];
162 		pix[3] = 255;
163 		pix += 4;
164 	}
165 
166 	if (width)
167 		*width = w;
168 	if (height)
169 		*height = h;
170 
171 	*pic = out;
172 
173 	ri.FS_FreeFile (pcx);
174 	ri.Free (pic8);
175 }
176