1 /*
2 ** wolfmapcommon.cpp
3 **
4 **---------------------------------------------------------------------------
5 ** Copyright 2013 Braden Obrzut
6 ** All rights reserved.
7 **
8 ** Redistribution and use in source and binary forms, with or without
9 ** modification, are permitted provided that the following conditions
10 ** are met:
11 **
12 ** 1. Redistributions of source code must retain the above copyright
13 **    notice, this list of conditions and the following disclaimer.
14 ** 2. Redistributions in binary form must reproduce the above copyright
15 **    notice, this list of conditions and the following disclaimer in the
16 **    documentation and/or other materials provided with the distribution.
17 ** 3. The name of the author may not be used to endorse or promote products
18 **    derived from this software without specific prior written permission.
19 **
20 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 **---------------------------------------------------------------------------
31 **
32 **
33 */
34 
35 #include "wolfmapcommon.h"
36 
37 // Only important thing to remember is that both
38 // Compression methods work on WORDs rather than bytes.
39 
ExpandCarmack(const unsigned char * in,unsigned char * out)40 void FMapLump::ExpandCarmack(const unsigned char* in, unsigned char* out)
41 {
42 	const unsigned char* const end = out + ReadLittleShort((const BYTE*)in);
43 	const unsigned char* const start = out;
44 	in += 2;
45 
46 	const unsigned char* copy;
47 	BYTE length;
48 	while(out < end)
49 	{
50 		length = *in++;
51 		if(length == 0 && (*in == CARMACK_NEARTAG || *in == CARMACK_FARTAG))
52 		{
53 			*out++ = in[1];
54 			*out++ = in[0];
55 			in += 2;
56 			continue;
57 		}
58 		else if(*in == CARMACK_NEARTAG)
59 		{
60 			copy = out-(in[1]*2);
61 			in += 2;
62 		}
63 		else if(*in == CARMACK_FARTAG)
64 		{
65 			copy = start+(ReadLittleShort((const BYTE*)(in+1))*2);
66 			in += 3;
67 		}
68 		else
69 		{
70 			*out++ = length;
71 			*out++ = *in++;
72 			continue;
73 		}
74 		if(out+(length*2) > end)
75 			break;
76 		while(length-- > 0)
77 		{
78 			*out++ = *copy++;
79 			*out++ = *copy++;
80 		}
81 	}
82 }
83 
ExpandRLEW(const unsigned char * in,unsigned char * out,const DWORD length,const WORD rlewTag)84 void FMapLump::ExpandRLEW(const unsigned char* in, unsigned char* out, const DWORD length, const WORD rlewTag)
85 {
86 	const unsigned char* const end = out+length;
87 
88 	while(out < end)
89 	{
90 		if(ReadLittleShort((const BYTE*)in) != rlewTag)
91 		{
92 			*out++ = *in++;
93 			*out++ = *in++;
94 		}
95 		else
96 		{
97 			WORD count = ReadLittleShort((const BYTE*)(in+2));
98 			WORD input = ReadLittleShort((const BYTE*)(in+4));
99 			in += 6;
100 			while(count-- > 0)
101 			{
102 				WriteLittleShort((BYTE*)out, input);
103 				out += 2;
104 			}
105 		}
106 	}
107 }
108 
FillCache()109 int FMapLump::FillCache()
110 {
111 	if(LumpSize == 0)
112 		return 1;
113 
114 	unsigned int PlaneSize = Header.Width*Header.Height*2;
115 
116 	Cache = new char[LumpSize];
117 	strcpy(Cache, "WDC3.1");
118 	WriteLittleShort((BYTE*)&Cache[10], rtlMap ? 4 : 3);
119 	WriteLittleShort((BYTE*)&Cache[12], 16);
120 	WriteLittleShort((BYTE*)&Cache[HEADERSIZE-4], Header.Width);
121 	WriteLittleShort((BYTE*)&Cache[HEADERSIZE-2], Header.Height);
122 	memcpy(&Cache[14], Header.Name, 16);
123 
124 	// Read map data and expand it
125 	unsigned char* output = reinterpret_cast<unsigned char*>(Cache+HEADERSIZE);
126 	for(unsigned int i = 0;i < PLANES;++i)
127 	{
128 		// ChaosEdit HACK: Likely in order to save a few bytes ChaosEdit sets
129 		// the second and third map plane offsets to be the same (since vanilla
130 		// doesn't use the data). If we see this we need to zero fill the plane.
131 		if(i == 2 && Header.PlaneOffset[1] == Header.PlaneOffset[2] && !rtlMap)
132 		{
133 			memset(output, 0, PlaneSize);
134 			output += PlaneSize;
135 			continue;
136 		}
137 
138 		unsigned char* input = new unsigned char[Header.PlaneLength[i]];
139 		Owner->Reader->Seek(Header.PlaneOffset[i], SEEK_SET);
140 		Owner->Reader->Read(input, Header.PlaneLength[i]);
141 
142 		if(carmackCompressed)
143 		{
144 			unsigned char* tempOut = new unsigned char[ReadLittleShort((BYTE*)input)];
145 			ExpandCarmack(input, tempOut);
146 			ExpandRLEW(tempOut+2, output, ReadLittleShort((const BYTE*)tempOut), rlewTag);
147 			delete[] tempOut;
148 		}
149 		else
150 			ExpandRLEW(input, output, PlaneSize, rlewTag);
151 
152 		delete[] input;
153 		output += PlaneSize;
154 
155 		// RTL maps don't have a floor/ceiling texture plane so insert one
156 		// We do this after the things plane has been read
157 		if(rtlMap && i == 1)
158 		{
159 			const WORD floorTex = ReadLittleShort((const BYTE*)(Cache+HEADERSIZE))-0xB4;
160 			const WORD ceilingTex = ReadLittleShort((const BYTE*)(Cache+HEADERSIZE+2))-0xC6;
161 			const WORD fill = (floorTex&0xFF)|((ceilingTex&0xFF)<<8);
162 			WORD *out = reinterpret_cast<WORD*>(output);
163 			for(unsigned int j = 0;j < PlaneSize/2;++j)
164 				*out++ = fill;
165 			output += PlaneSize;
166 		}
167 	}
168 	return 1;
169 }
170