mirror of
https://github.com/ZDoom/wadext.git
synced 2025-03-13 06:02:26 +00:00
- version 1.0.
Tested with Visual Studio 2013 and 2015 on Windows, other platforms may still need work.
This commit is contained in:
commit
2bafaae58e
12 changed files with 4865 additions and 0 deletions
131
CMakeLists.txt
Normal file
131
CMakeLists.txt
Normal file
|
@ -0,0 +1,131 @@
|
|||
cmake_minimum_required( VERSION 2.4 )
|
||||
if( COMMAND cmake_policy )
|
||||
cmake_policy( SET CMP0003 NEW )
|
||||
endif( COMMAND cmake_policy )
|
||||
|
||||
include( CheckFunctionExists )
|
||||
include( CheckCXXCompilerFlag )
|
||||
|
||||
project( WADEXT )
|
||||
|
||||
IF( NOT CMAKE_BUILD_TYPE )
|
||||
SET( CMAKE_BUILD_TYPE Debug CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE )
|
||||
ENDIF( NOT CMAKE_BUILD_TYPE )
|
||||
|
||||
set( SSE_MATTERS NO )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
set( GPROF 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
|
||||
set( PROFILE 0 CACHE INT "1=Generate profile coverage info, 2=Use it" )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
find_package( ZLIB )
|
||||
|
||||
if( MSVC )
|
||||
# Eliminate unreferenced functions and data
|
||||
# Perform identical COMDAT folding
|
||||
set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt" )
|
||||
|
||||
# String pooling
|
||||
# Function-level linking
|
||||
# Disable run-time type information
|
||||
set( ALL_C_FLAGS "/GF /Gy /GR-" )
|
||||
|
||||
# Avoid CRT DLL dependancies in release builds
|
||||
set( REL_C_FLAGS "/MT" )
|
||||
|
||||
# Disable warnings for unsecure CRT functions from VC8+
|
||||
if( MSVC_VERSION GREATER 1399 )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996" )
|
||||
endif( MSVC_VERSION GREATER 1399 )
|
||||
|
||||
# The CMake configurations set /GR and /MD by default, which conflict with our settings.
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL} )
|
||||
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} )
|
||||
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} )
|
||||
string(REPLACE "/MD " " " CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL} )
|
||||
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO} )
|
||||
string(REPLACE " /GR" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} )
|
||||
endif( MSVC )
|
||||
|
||||
if( CMAKE_COMPILER_IS_GNUCXX )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} -ffast-math -pipe" )
|
||||
if( GPROF )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} -pg -g" )
|
||||
else( GPROF )
|
||||
set( REL_C_FLAGS "${REL_C_FLAGS} -fomit-frame-pointer" )
|
||||
endif( GPROF )
|
||||
if( PROFILE EQUAL 1 )
|
||||
message( STATUS "Generating profile coverage information" )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} -fprofile-generate" )
|
||||
set( PROF_LIB "gcov" )
|
||||
elseif( PROFILE EQUAL 2 )
|
||||
message( STATUS "Using profile coverage information" )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} -fprofile-use" )
|
||||
endif( PROFILE EQUAL 1 )
|
||||
endif( CMAKE_COMPILER_IS_GNUCXX )
|
||||
|
||||
#if( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
# set( ALL_C_FLAGS "${ALL_C_FLAGS} -Wno-deprecated-declarations -Wno-format" )
|
||||
#endif( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
|
||||
if( ZLIB_FOUND )
|
||||
message( STATUS "Using system zlib" )
|
||||
else( ZLIB_FOUND )
|
||||
message( STATUS "Using internal zlib" )
|
||||
add_subdirectory( zlib )
|
||||
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib )
|
||||
set( ZLIB_LIBRARIES z )
|
||||
set( ZLIB_LIBRARY z )
|
||||
endif( ZLIB_FOUND )
|
||||
|
||||
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
|
||||
if( NOT STRICMP_EXISTS )
|
||||
add_definitions( -Dstricmp=strcasecmp )
|
||||
endif( NOT STRICMP_EXISTS )
|
||||
|
||||
CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS )
|
||||
if( NOT STRNICMP_EXISTS )
|
||||
add_definitions( -Dstrnicmp=strncasecmp )
|
||||
endif( NOT STRNICMP_EXISTS )
|
||||
|
||||
set( WADEXT_LIBS "${ZLIB_LIBRARIES}" )
|
||||
|
||||
set( HEADERS
|
||||
fileformat.h
|
||||
resourcefile.h
|
||||
tarray.h
|
||||
wadext.h
|
||||
wadman.h
|
||||
)
|
||||
|
||||
set( SOURCES
|
||||
convert.cpp
|
||||
fileformat.cpp
|
||||
main.cpp
|
||||
wadext.cpp
|
||||
wadfile.cpp
|
||||
)
|
||||
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${REL_LINKER_FLAGS}" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} ${REL_LINKER_FLAGS}" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} ${REL_LINKER_FLAGS}" )
|
||||
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ALL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
||||
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ALL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
|
||||
|
||||
add_executable( wadext ${SOURCES} ${HEADERS} )
|
||||
target_link_libraries( wadext ${WADEXT_LIBS} ${PROF_LIB} )
|
||||
include_directories( "${ZLIB_INCLUDE_DIR}" )
|
771
convert.cpp
Normal file
771
convert.cpp
Normal file
|
@ -0,0 +1,771 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Portions of this file from ZDoom under the following license:
|
||||
/*
|
||||
** m_png.cpp
|
||||
** Routines for manipulating PNG files.
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2002-2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include "zlib/zlib.h"
|
||||
#include "wadext.h"
|
||||
#include "ResourceFile.h"
|
||||
#include "fileformat.h"
|
||||
#include "tarray.h"
|
||||
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
const uint8_t doompal[]={
|
||||
0, 0, 0, 31, 23, 11, 23, 15, 7, 75, 75, 75,255,255,255, 27,
|
||||
27, 27, 19, 19, 19, 11, 11, 11, 7, 7, 7, 47, 55, 31, 35, 43,
|
||||
15, 23, 31, 7, 15, 23, 0, 79, 59, 43, 71, 51, 35, 63, 43, 27,
|
||||
255,183,183,247,171,171,243,163,163,235,151,151,231,143,143,223,
|
||||
135,135,219,123,123,211,115,115,203,107,107,199, 99, 99,191, 91,
|
||||
91,187, 87, 87,179, 79, 79,175, 71, 71,167, 63, 63,163, 59, 59,
|
||||
155, 51, 51,151, 47, 47,143, 43, 43,139, 35, 35,131, 31, 31,127,
|
||||
27, 27,119, 23, 23,115, 19, 19,107, 15, 15,103, 11, 11, 95, 7,
|
||||
7, 91, 7, 7, 83, 7, 7, 79, 0, 0, 71, 0, 0, 67, 0, 0,
|
||||
255,235,223,255,227,211,255,219,199,255,211,187,255,207,179,255,
|
||||
199,167,255,191,155,255,187,147,255,179,131,247,171,123,239,163,
|
||||
115,231,155,107,223,147, 99,215,139, 91,207,131, 83,203,127, 79,
|
||||
191,123, 75,179,115, 71,171,111, 67,163,107, 63,155, 99, 59,143,
|
||||
95, 55,135, 87, 51,127, 83, 47,119, 79, 43,107, 71, 39, 95, 67,
|
||||
35, 83, 63, 31, 75, 55, 27, 63, 47, 23, 51, 43, 19, 43, 35, 15,
|
||||
239,239,239,231,231,231,223,223,223,219,219,219,211,211,211,203,
|
||||
203,203,199,199,199,191,191,191,183,183,183,179,179,179,171,171,
|
||||
171,167,167,167,159,159,159,151,151,151,147,147,147,139,139,139,
|
||||
131,131,131,127,127,127,119,119,119,111,111,111,107,107,107, 99,
|
||||
99, 99, 91, 91, 91, 87, 87, 87, 79, 79, 79, 71, 71, 71, 67, 67,
|
||||
67, 59, 59, 59, 55, 55, 55, 47, 47, 47, 39, 39, 39, 35, 35, 35,
|
||||
119,255,111,111,239,103,103,223, 95, 95,207, 87, 91,191, 79, 83,
|
||||
175, 71, 75,159, 63, 67,147, 55, 63,131, 47, 55,115, 43, 47, 99,
|
||||
35, 39, 83, 27, 31, 67, 23, 23, 51, 15, 19, 35, 11, 11, 23, 7,
|
||||
191,167,143,183,159,135,175,151,127,167,143,119,159,135,111,155,
|
||||
127,107,147,123, 99,139,115, 91,131,107, 87,123, 99, 79,119, 95,
|
||||
75,111, 87, 67,103, 83, 63, 95, 75, 55, 87, 67, 51, 83, 63, 47,
|
||||
159,131, 99,143,119, 83,131,107, 75,119, 95, 63,103, 83, 51, 91,
|
||||
71, 43, 79, 59, 35, 67, 51, 27,123,127, 99,111,115, 87,103,107,
|
||||
79, 91, 99, 71, 83, 87, 59, 71, 79, 51, 63, 71, 43, 55, 63, 39,
|
||||
255,255,115,235,219, 87,215,187, 67,195,155, 47,175,123, 31,155,
|
||||
91, 19,135, 67, 7,115, 43, 0,255,255,255,255,219,219,255,187,
|
||||
187,255,155,155,255,123,123,255, 95, 95,255, 63, 63,255, 31, 31,
|
||||
255, 0, 0,239, 0, 0,227, 0, 0,215, 0, 0,203, 0, 0,191,
|
||||
0, 0,179, 0, 0,167, 0, 0,155, 0, 0,139, 0, 0,127, 0,
|
||||
0,115, 0, 0,103, 0, 0, 91, 0, 0, 79, 0, 0, 67, 0, 0,
|
||||
231,231,255,199,199,255,171,171,255,143,143,255,115,115,255, 83,
|
||||
83,255, 55, 55,255, 27, 27,255, 0, 0,255, 0, 0,227, 0, 0,
|
||||
203, 0, 0,179, 0, 0,155, 0, 0,131, 0, 0,107, 0, 0, 83,
|
||||
255,255,255,255,235,219,255,215,187,255,199,155,255,179,123,255,
|
||||
163, 91,255,143, 59,255,127, 27,243,115, 23,235,111, 15,223,103,
|
||||
15,215, 95, 11,203, 87, 7,195, 79, 0,183, 71, 0,175, 67, 0,
|
||||
255,255,255,255,255,215,255,255,179,255,255,143,255,255,107,255,
|
||||
255, 71,255,255, 35,255,255, 0,167, 63, 0,159, 55, 0,147, 47,
|
||||
0,135, 35, 0, 79, 59, 39, 67, 47, 27, 55, 35, 19, 47, 27, 11,
|
||||
0, 0, 83, 0, 0, 71, 0, 0, 59, 0, 0, 47, 0, 0, 35, 0,
|
||||
0, 23, 0, 0, 11, 0, 0, 0,255,159, 67,255,231, 75,255,123,
|
||||
255,255, 0,255,207, 0,207,159, 0,155,111, 0,107,167,107,107,
|
||||
};
|
||||
|
||||
const uint8_t hereticpal[]={
|
||||
2, 2, 2, 2, 2, 2, 16, 16, 16, 24, 24, 24, 31, 31, 31, 36,
|
||||
36, 36, 44, 44, 44, 48, 48, 48, 55, 55, 55, 63, 63, 63, 70, 70,
|
||||
70, 78, 78, 78, 86, 86, 86, 93, 93, 93,101,101,101,108,108,108,
|
||||
116,116,116,124,124,124,131,131,131,139,139,139,146,146,146,154,
|
||||
154,154,162,162,162,169,169,169,177,177,177,184,184,184,192,192,
|
||||
192,200,200,200,207,207,207,210,210,210,215,215,215,222,222,222,
|
||||
228,228,228,236,236,236,245,245,245,255,255,255, 50, 50, 50, 59,
|
||||
60, 59, 69, 72, 68, 78, 80, 77, 88, 93, 86, 97,100, 95,109,112,
|
||||
104,116,123,112,125,131,121,134,141,130,144,151,139,153,161,148,
|
||||
163,171,157,172,181,166,181,189,176,189,196,185, 20, 16, 36, 24,
|
||||
24, 44, 36, 36, 60, 52, 52, 80, 68, 68, 96, 88, 88,116,108,108,
|
||||
136,124,124,152,148,148,172,164,164,184,180,184,200,192,196,208,
|
||||
208,208,216,224,224,224, 27, 15, 8, 38, 20, 11, 49, 27, 14, 61,
|
||||
31, 14, 65, 35, 18, 74, 37, 19, 83, 43, 19, 87, 47, 23, 95, 51,
|
||||
27,103, 59, 31,115, 67, 35,123, 75, 39,131, 83, 47,143, 91, 51,
|
||||
151, 99, 59,160,108, 64,175,116, 74,180,126, 81,192,135, 91,204,
|
||||
143, 93,213,151,103,216,159,115,220,167,126,223,175,138,227,183,
|
||||
149,230,190,161,233,198,172,237,206,184,240,214,195, 62, 40, 11,
|
||||
75, 50, 16, 84, 59, 23, 95, 67, 30,103, 75, 38,110, 83, 47,123,
|
||||
95, 55,137,107, 62,150,118, 75,163,129, 84,171,137, 92,180,146,
|
||||
101,188,154,109,196,162,117,204,170,125,208,176,133, 37, 20, 4,
|
||||
47, 24, 4, 57, 28, 6, 68, 33, 4, 76, 36, 3, 84, 40, 0, 97,
|
||||
47, 2,114, 54, 0,125, 63, 6,141, 75, 9,155, 83, 17,162, 95,
|
||||
21,169,103, 26,180,113, 32,188,124, 20,204,136, 24,220,148, 28,
|
||||
236,160, 23,244,172, 47,252,187, 57,252,194, 70,251,201, 83,251,
|
||||
208, 97,251,214,110,251,221,123,250,228,136,157, 51, 4,170, 65,
|
||||
2,185, 86, 4,213,118, 4,236,164, 3,248,190, 3,255,216, 43,
|
||||
255,255, 0, 67, 0, 0, 79, 0, 0, 91, 0, 0,103, 0, 0,115,
|
||||
0, 0,127, 0, 0,139, 0, 0,155, 0, 0,167, 0, 0,179, 0,
|
||||
0,191, 0, 0,203, 0, 0,215, 0, 0,227, 0, 0,239, 0, 0,
|
||||
255, 0, 0,255, 52, 52,255, 74, 74,255, 95, 95,255,123,123,255,
|
||||
155,155,255,179,179,255,201,201,255,215,215, 60, 12, 88, 80, 8,
|
||||
108,104, 8,128,128, 0,144,152, 0,176,184, 0,224,216, 44,252,
|
||||
224,120,240, 37, 6,129, 60, 33,147, 82, 61,165,105, 88,183,128,
|
||||
116,201,151,143,219,173,171,237,196,198,255, 2, 4, 41, 2, 5,
|
||||
49, 6, 8, 57, 2, 5, 65, 2, 5, 79, 0, 4, 88, 0, 4, 96,
|
||||
0, 4,104, 2, 5,121, 2, 5,137, 6, 9,159, 12, 16,184, 32,
|
||||
40,200, 56, 60,220, 80, 80,253, 80,108,252, 80,136,252, 80,164,
|
||||
252, 80,196,252, 72,220,252, 80,236,252, 84,252,252,152,252,252,
|
||||
188,252,244, 11, 23, 7, 19, 35, 11, 23, 51, 15, 31, 67, 23, 39,
|
||||
83, 27, 47, 99, 35, 55,115, 43, 63,131, 47, 67,147, 55, 75,159,
|
||||
63, 83,175, 71, 91,191, 79, 95,207, 87,103,223, 95,111,239,103,
|
||||
119,255,111, 23, 31, 23, 27, 35, 27, 31, 43, 31, 35, 51, 35, 43,
|
||||
55, 43, 47, 63, 47, 51, 71, 51, 59, 75, 55, 63, 83, 59, 67, 91,
|
||||
67, 75, 95, 71, 79,103, 75, 87,111, 79, 91,115, 83, 95,123, 87,
|
||||
103,131, 95,255,223, 0,255,191, 0,255,159, 0,255,127, 0,255,
|
||||
95, 0,255, 63, 0,244, 14, 3, 55, 0, 0, 47, 0, 0, 39, 0,
|
||||
0, 23, 0, 0, 15, 15, 15, 11, 11, 11, 7, 7, 7,255,255,255,
|
||||
};
|
||||
|
||||
|
||||
|
||||
const uint8_t hexenpal[]={
|
||||
2, 2, 2, 4, 4, 4, 15, 15, 15, 19, 19, 19, 27, 27, 27, 28,
|
||||
28, 28, 33, 33, 33, 39, 39, 39, 45, 45, 45, 51, 51, 51, 57, 57,
|
||||
57, 63, 63, 63, 69, 69, 69, 75, 75, 75, 81, 81, 81, 86, 86, 86,
|
||||
92, 92, 92, 98, 98, 98,104,104,104,112,112,112,121,121,121,130,
|
||||
130,130,139,139,139,147,147,147,157,157,157,166,166,166,176,176,
|
||||
176,185,185,185,194,194,194,203,203,203,212,212,212,221,221,221,
|
||||
230,230,230, 29, 32, 29, 38, 40, 37, 50, 50, 50, 59, 60, 59, 69,
|
||||
72, 68, 78, 80, 77, 88, 93, 86, 97,100, 95,109,112,104,116,123,
|
||||
112,125,131,121,134,141,130,144,151,139,153,161,148,163,171,157,
|
||||
172,181,166,181,189,176,189,196,185, 22, 29, 22, 27, 36, 27, 31,
|
||||
43, 31, 35, 51, 35, 43, 55, 43, 47, 63, 47, 51, 71, 51, 59, 75,
|
||||
55, 63, 83, 59, 67, 91, 67, 75, 95, 71, 79,103, 75, 87,111, 79,
|
||||
91,115, 83, 95,123, 87,103,131, 95, 20, 16, 36, 30, 26, 46, 40,
|
||||
36, 57, 50, 46, 67, 59, 57, 78, 69, 67, 88, 79, 77, 99, 89, 87,
|
||||
109, 99, 97,120,109,107,130,118,118,141,128,128,151,138,138,162,
|
||||
148,148,172, 62, 40, 11, 75, 50, 16, 84, 59, 23, 95, 67, 30,103,
|
||||
75, 38,110, 83, 47,123, 95, 55,137,107, 62,150,118, 75,163,129,
|
||||
84,171,137, 92,180,146,101,188,154,109,196,162,117,204,170,125,
|
||||
208,176,133, 27, 15, 8, 38, 20, 11, 49, 27, 14, 61, 31, 14, 65,
|
||||
35, 18, 74, 37, 19, 83, 43, 19, 87, 47, 23, 95, 51, 27,103, 59,
|
||||
31,115, 67, 35,123, 75, 39,131, 83, 47,143, 91, 51,151, 99, 59,
|
||||
160,108, 64,175,116, 74,180,126, 81,192,135, 91,204,143, 93,213,
|
||||
151,103,216,159,115,220,167,126,223,175,138,227,183,149, 37, 20,
|
||||
4, 47, 24, 4, 57, 28, 6, 68, 33, 4, 76, 36, 3, 84, 40, 0,
|
||||
97, 47, 2,114, 54, 0,125, 63, 6,141, 75, 9,155, 83, 17,162,
|
||||
95, 21,169,103, 26,180,113, 32,188,124, 20,204,136, 24,220,148,
|
||||
28,236,160, 23,244,172, 47,252,187, 57,252,194, 70,251,201, 83,
|
||||
251,208, 97,251,221,123, 2, 4, 41, 2, 5, 49, 6, 8, 57, 2,
|
||||
5, 65, 2, 5, 79, 0, 4, 88, 0, 4, 96, 0, 4,104, 4, 6,
|
||||
121, 2, 5,137, 20, 23,152, 38, 41,167, 56, 59,181, 74, 77,196,
|
||||
91, 94,211,109,112,226,127,130,240,145,148,255, 31, 4, 4, 39,
|
||||
0, 0, 47, 0, 0, 55, 0, 0, 67, 0, 0, 79, 0, 0, 91, 0,
|
||||
0,103, 0, 0,115, 0, 0,127, 0, 0,139, 0, 0,155, 0, 0,
|
||||
167, 0, 0,185, 0, 0,202, 0, 0,220, 0, 0,237, 0, 0,255,
|
||||
0, 0,255, 46, 46,255, 91, 91,255,137,137,255,171,171, 20, 16,
|
||||
4, 13, 24, 9, 17, 33, 12, 21, 41, 14, 24, 50, 17, 28, 57, 20,
|
||||
32, 65, 24, 35, 73, 28, 39, 80, 31, 44, 86, 37, 46, 95, 38, 51,
|
||||
104, 43, 60,122, 51, 68,139, 58, 77,157, 66, 85,174, 73, 94,192,
|
||||
81,157, 51, 4,170, 65, 2,185, 86, 4,213,119, 6,234,147, 5,
|
||||
255,178, 6,255,195, 26,255,216, 45, 4,133, 4, 8,175, 8, 2,
|
||||
215, 2, 3,234, 3, 42,252, 42,121,255,121, 3, 3,184, 15, 41,
|
||||
220, 28, 80,226, 41,119,233, 54,158,239, 67,197,246, 80,236,252,
|
||||
244, 14, 3,255, 63, 0,255, 95, 0,255,127, 0,255,159, 0,255,
|
||||
195, 26,255,223, 0, 43, 13, 64, 61, 14, 89, 90, 15,122,120, 16,
|
||||
156,149, 16,189,178, 17,222,197, 74,232,215,129,243,234,169,253,
|
||||
61, 16, 16, 90, 36, 33,118, 56, 49,147, 77, 66,176, 97, 83,204,
|
||||
117, 99, 71, 53, 2, 81, 63, 6, 96, 72, 0,108, 80, 0,120, 88,
|
||||
0,128, 96, 0,149,112, 1,181,136, 3,212,160, 4,255,255,255,
|
||||
};
|
||||
|
||||
const uint8_t strifepal[]={
|
||||
0, 0, 0,231,227,227,223,219,219,215,211,211,207,203,203,199,
|
||||
195,195,191,191,191,183,183,183,179,175,175,171,167,167,163,159,
|
||||
159,155,151,151,147,147,147,139,139,139,131,131,131,123,123,123,
|
||||
119,115,115,111,111,111,103,103,103, 95, 95, 95, 87, 87, 87, 79,
|
||||
79, 79, 71, 71, 71, 67, 63, 63, 59, 59, 59, 51, 51, 51, 43, 43,
|
||||
43, 35, 35, 35, 27, 27, 27, 19, 19, 19, 11, 11, 11, 7, 7, 7,
|
||||
187,191,183,179,183,171,167,179,159,163,171,147,155,167,139,147,
|
||||
159,127,139,155,119,131,147,107,127,143,103,119,135, 91,115,131,
|
||||
83,107,123, 75,103,119, 67, 99,111, 63, 91,107, 55, 87, 99, 47,
|
||||
83, 95, 43, 75, 87, 35, 71, 83, 31, 67, 75, 27, 63, 71, 23, 59,
|
||||
63, 19, 51, 59, 15, 47, 51, 11, 43, 47, 7, 39, 43, 7, 31, 35,
|
||||
7, 27, 31, 0, 23, 23, 0, 15, 19, 0, 11, 11, 0, 7, 7, 0,
|
||||
219, 43, 43,203, 35, 35,191, 31, 31,175, 27, 27,163, 23, 23,147,
|
||||
19, 19,135, 15, 15,119, 11, 11,107, 7, 7, 91, 7, 7, 79, 0,
|
||||
0, 63, 0, 0, 51, 0, 0, 39, 0, 0, 23, 0, 0, 11, 0, 0,
|
||||
235,231, 0,231,211, 0,215,179, 0,199,151, 0,183,127, 0,167,
|
||||
103, 0,151, 83, 0,135, 63, 0,119, 47, 0,103, 35, 0, 87, 23,
|
||||
0, 71, 11, 0, 55, 7, 0, 39, 0, 0, 23, 0, 0, 11, 0, 0,
|
||||
183,231,127,163,215,111,143,199, 95,127,183, 79,107,171, 67, 91,
|
||||
155, 55, 75,139, 43, 63,123, 35, 47,111, 27, 35, 95, 19, 23, 79,
|
||||
11, 15, 67, 7, 7, 51, 7, 0, 35, 0, 0, 19, 0, 0, 7, 0,
|
||||
199,207,255,183,187,239,163,171,219,151,155,203,135,139,187,123,
|
||||
127,171,107,111,155, 95, 99,139, 83, 83,123, 67, 71,107, 55, 59,
|
||||
91, 47, 47, 75, 35, 35, 59, 23, 23, 43, 15, 15, 27, 0, 0, 11,
|
||||
199,191,147,179,171,131,167,155,119,155,139,111,143,127, 99,131,
|
||||
111, 91,119, 99, 79,107, 87, 71, 91, 71, 59, 79, 59, 51, 67, 47,
|
||||
43, 55, 39, 35, 43, 27, 27, 31, 19, 19, 19, 11, 11, 7, 7, 0,
|
||||
143,195,211,123,179,195,107,167,183, 91,155,167, 75,139,155, 59,
|
||||
127,139, 47,115,127, 35,103,115, 27, 91, 99, 19, 79, 87, 11, 67,
|
||||
71, 7, 55, 59, 0, 43, 43, 0, 31, 31, 0, 19, 19, 0, 7, 7,
|
||||
211,191,175,203,179,163,195,171,151,191,159,143,183,151,131,175,
|
||||
143,123,171,135,115,163,123,103,155,115, 95,151,107, 87,143, 99,
|
||||
79,139, 91, 71,131, 83, 67,123, 75, 59,119, 67, 51,111, 59, 47,
|
||||
103, 55, 39, 99, 47, 35, 91, 43, 31, 83, 35, 27, 79, 31, 23, 71,
|
||||
27, 19, 63, 19, 15, 59, 15, 11, 51, 11, 7, 43, 7, 7, 39, 7,
|
||||
0, 31, 0, 0, 27, 0, 0, 19, 0, 0, 11, 0, 0, 7, 0, 0,
|
||||
211,199,187,203,191,179,195,183,171,191,175,163,183,167,155,175,
|
||||
159,147,171,151,139,163,143,135,155,139,127,151,131,119,143,123,
|
||||
111,135,115,107,131,107, 99,123,103, 95,115, 95, 87,111, 87, 83,
|
||||
103, 83, 75, 95, 75, 71, 91, 67, 63, 83, 63, 59, 79, 55, 51, 71,
|
||||
51, 47, 63, 43, 43, 59, 39, 39, 51, 35, 31, 43, 27, 27, 39, 23,
|
||||
23, 31, 19, 19, 23, 15, 15, 19, 11, 11, 11, 7, 7, 7, 7, 0,
|
||||
239,239, 0,231,215, 0,227,191, 0,219,171, 0,215,151, 0,211,
|
||||
131, 0,203,111, 0,199, 91, 0,191, 75, 0,187, 59, 0,183, 43,
|
||||
0,255, 0, 0,223, 0, 0,191, 0, 0,159, 0, 0,127, 0, 0,
|
||||
0, 47, 47,139,199,103,107,171, 75, 79,143, 55, 55,115, 35, 35,
|
||||
87, 19, 19, 63, 11,215,223,255,187,203,247,143,167,219, 99,131,
|
||||
195, 63, 91,167,203,203,203,215,215,215,223,223,223,235,235,235,
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct IHDR
|
||||
{
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
uint8_t BitDepth;
|
||||
uint8_t ColorType;
|
||||
uint8_t Compression;
|
||||
uint8_t Filter;
|
||||
uint8_t Interlace;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
|
||||
uint8_t palette[768];
|
||||
const uint8_t *ppal = NULL;
|
||||
bool done;
|
||||
|
||||
const uint8_t *GetPalette(int flags)
|
||||
{
|
||||
if (ppal) return ppal;
|
||||
int pplump = mainwad->FindLump("PLAYPAL");
|
||||
if (pplump >= 0)
|
||||
{
|
||||
WadItemList w(pplump);
|
||||
memcpy(palette, w.Address(), 768);
|
||||
ppal = palette;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags&DO_HERETIC_PAL) ppal = hereticpal;
|
||||
else if (flags&DO_HEXEN_PAL) ppal = hexenpal;
|
||||
else if (flags&DO_STRIFE) ppal = strifepal;
|
||||
else ppal = doompal;
|
||||
}
|
||||
return ppal;
|
||||
}
|
||||
|
||||
inline uint32_t BigLong(uint32_t nLongNumber)
|
||||
{
|
||||
return (((nLongNumber & 0x000000FF) << 24) + ((nLongNumber & 0x0000FF00) << 8) +
|
||||
((nLongNumber & 0x00FF0000) >> 8) + ((nLongNumber & 0xFF000000) >> 24));
|
||||
}
|
||||
|
||||
inline const uint32_t *GetCRCTable() { return (const uint32_t *)get_crc_table(); }
|
||||
inline uint32_t CalcCRC32(const uint8_t *buf, unsigned int len)
|
||||
{
|
||||
return crc32(0, buf, len);
|
||||
}
|
||||
inline uint32_t AddCRC32(uint32_t crc, const uint8_t *buf, unsigned int len)
|
||||
{
|
||||
return crc32(crc, buf, len);
|
||||
}
|
||||
inline uint32_t CRC1(uint32_t crc, const uint8_t c, const uint32_t *crcTable)
|
||||
{
|
||||
return crcTable[(crc & 0xff) ^ c] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// M_AppendPNGChunk
|
||||
//
|
||||
// Writes a PNG-compliant chunk to the file.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool M_AppendPNGChunk(FILE *file, uint32_t chunkID, const void *_chunkData, uint32_t len)
|
||||
{
|
||||
const uint8_t *chunkData = (uint8_t*)_chunkData;
|
||||
uint32_t head[2] = { BigLong((unsigned int)len), chunkID };
|
||||
uint32_t crc;
|
||||
|
||||
if (fwrite(head, 1, 8, file) == 8 &&
|
||||
(len == 0 || fwrite(chunkData, 1, len, file) == len))
|
||||
{
|
||||
crc = CalcCRC32((uint8_t *)&head[1], 4);
|
||||
if (len != 0)
|
||||
{
|
||||
crc = AddCRC32(crc, chunkData, len);
|
||||
}
|
||||
crc = BigLong((unsigned int)crc);
|
||||
return fwrite(&crc, 1, 4, file) == 4;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// M_SaveBitmap
|
||||
//
|
||||
// Given a bitmap, creates one or more IDAT chunks in the given file.
|
||||
// Returns true on success.
|
||||
//
|
||||
//==========================================================================
|
||||
#define PNG_WRITE_SIZE 32768
|
||||
#define MAXWIDTH 8192
|
||||
|
||||
bool M_SaveBitmap(const uint8_t *from, int width, int height, int pitch, FILE *file)
|
||||
{
|
||||
uint8_t temprow[1][1 + MAXWIDTH * 3];
|
||||
uint8_t buffer[PNG_WRITE_SIZE];
|
||||
z_stream stream;
|
||||
int err;
|
||||
int y;
|
||||
|
||||
stream.next_in = Z_NULL;
|
||||
stream.avail_in = 0;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
err = deflateInit(&stream, 9);
|
||||
|
||||
if (err != Z_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
y = height;
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = sizeof(buffer);
|
||||
|
||||
temprow[0][0] = 0;
|
||||
|
||||
while (y-- > 0 && err == Z_OK)
|
||||
{
|
||||
memcpy(&temprow[0][1], from, width);
|
||||
// always use filter type 0 for paletted images
|
||||
stream.next_in = temprow[0];
|
||||
stream.avail_in = width + 1;
|
||||
|
||||
from += pitch;
|
||||
|
||||
err = deflate(&stream, (y == 0) ? Z_FINISH : 0);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (stream.avail_out == 0)
|
||||
{
|
||||
if (!M_AppendPNGChunk(file, MAKE_ID('I', 'D', 'A', 'T'), buffer, sizeof(buffer)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = sizeof(buffer);
|
||||
if (stream.avail_in != 0)
|
||||
{
|
||||
err = deflate(&stream, (y == 0) ? Z_FINISH : 0);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (err == Z_OK)
|
||||
{
|
||||
err = deflate(&stream, Z_FINISH);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (stream.avail_out == 0)
|
||||
{
|
||||
if (!M_AppendPNGChunk(file, MAKE_ID('I','D','A','T'), buffer, sizeof(buffer)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = sizeof(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
deflateEnd(&stream);
|
||||
|
||||
if (err != Z_STREAM_END)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return M_AppendPNGChunk(file, MAKE_ID('I', 'D', 'A', 'T'), buffer, sizeof(buffer) - stream.avail_out);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void WritePNG(const uint8_t *bufferRGBA, int width, int height, int leftofs, int topofs, const char *filename)
|
||||
{
|
||||
int numpix = width * height;
|
||||
bool hastrans = false;
|
||||
TMap<uint32_t, uint8_t> palmap;
|
||||
uint8_t *bufferPaletted = new uint8_t[numpix];
|
||||
uint8_t palette[768];
|
||||
for (int i = 0; i < numpix; i++)
|
||||
{
|
||||
if (bufferRGBA[i * 4 + 3] == 0)
|
||||
{
|
||||
hastrans = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int curcol = 0;
|
||||
if (hastrans)
|
||||
{
|
||||
palmap[0] = 0;
|
||||
palette[0] = palette[1] = palette[2] = 0;
|
||||
curcol++;
|
||||
}
|
||||
for (int i = 0; i < numpix; i++)
|
||||
{
|
||||
const uint8_t *pix = &bufferRGBA[i * 4];
|
||||
uint32_t rgba = pix[0] + 256 * pix[1] + 256 * 256 * pix[2] + 256 * 256 * 256 * pix[3];
|
||||
uint8_t *pIndex = palmap.CheckKey(rgba);
|
||||
uint8_t index;
|
||||
if (pIndex != NULL) index = *pIndex;
|
||||
else
|
||||
{
|
||||
palmap[rgba] = curcol;
|
||||
index = curcol;
|
||||
palette[curcol * 3] = pix[0];
|
||||
palette[curcol * 3+1] = pix[1];
|
||||
palette[curcol * 3+2] = pix[2];
|
||||
curcol++;
|
||||
}
|
||||
bufferPaletted[i] = index;
|
||||
}
|
||||
|
||||
FILE * f = fopen(filename, "wb");
|
||||
if (f == NULL) return;
|
||||
|
||||
const char sig[] = "\x89PNG\r\n\x1a\n";
|
||||
IHDR ihdr;
|
||||
|
||||
ihdr.Width = BigLong(width);
|
||||
ihdr.Height = BigLong(height);
|
||||
ihdr.BitDepth = 8;
|
||||
ihdr.ColorType = 3;
|
||||
ihdr.Compression = 0;
|
||||
ihdr.Filter = 0;
|
||||
ihdr.Interlace = 0;
|
||||
|
||||
fwrite(sig, 1, 8, f);
|
||||
M_AppendPNGChunk(f, MAKE_ID('I', 'H', 'D', 'R'), &ihdr, sizeof(ihdr));
|
||||
if (leftofs != 0 || topofs != 0)
|
||||
{
|
||||
uint32_t ofs[] = { BigLong(leftofs), BigLong(topofs) };
|
||||
M_AppendPNGChunk(f, MAKE_ID('g', 'r', 'A', 'b'), ofs, 8);
|
||||
}
|
||||
if (curcol > 0)
|
||||
{
|
||||
M_AppendPNGChunk(f, MAKE_ID('P', 'L', 'T', 'E'), palette, curcol * 3);
|
||||
}
|
||||
if (hastrans)
|
||||
{
|
||||
char nul = 0;
|
||||
M_AppendPNGChunk(f, MAKE_ID('t', 'R', 'N', 'S'), &nul, 1);
|
||||
}
|
||||
|
||||
M_SaveBitmap(bufferPaletted, width, height, width, f);
|
||||
|
||||
static const uint8_t iend[12] = { 0,0,0,0,73,69,78,68,174,66,96,130 };
|
||||
fwrite(iend, 1, 12, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
bool FlatToPng(int options, const uint8_t *data, int length, const char *pngpath)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
// This uses the same logic as ZDoom, except for the 320x200 case which is for Raven's fullscreen images
|
||||
switch (length)
|
||||
{
|
||||
default:
|
||||
case 64 * 64: width = height = 64; break;
|
||||
case 8 * 8: width = height = 8; break;
|
||||
case 16 * 16: width = height = 16; break;
|
||||
case 32 * 32: width = height = 32; break;
|
||||
case 128 * 128: width = height = 128; break;
|
||||
case 256 * 256: width = height = 256; break;
|
||||
case 64000: width = 320; height = 200; break;
|
||||
}
|
||||
|
||||
uint8_t *image = new uint8_t[width * height * 4];
|
||||
|
||||
const unsigned char *bytes = (const unsigned char *)data;
|
||||
const uint8_t *palette = GetPalette(options);
|
||||
|
||||
for (int y = 0; y<height; y++) for (int x = 0; x<width; x++)
|
||||
{
|
||||
const unsigned char data = bytes[x + y*width];
|
||||
unsigned char *ddata = &image[(x + y*width) * 4];
|
||||
|
||||
ddata[0] = palette[data * 3 + 0];
|
||||
ddata[1] = palette[data * 3 + 1];
|
||||
ddata[2] = palette[data * 3 + 2];
|
||||
ddata[3] = 255;
|
||||
}
|
||||
|
||||
WritePNG(image, width, height, 0, 0, pngpath);
|
||||
delete[]image;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************
|
||||
PatchToPng
|
||||
*****************************/
|
||||
|
||||
|
||||
bool IsHack(const uint8_t *data, int length)
|
||||
{
|
||||
// Check if this patch is likely to be a problem.
|
||||
// It must be 256 pixels tall, and all its columns must have exactly
|
||||
// one post, where each post has a supposed length of 0.
|
||||
const patch_t *realpatch = (const patch_t *)data;
|
||||
const uint32_t *cofs = realpatch->columnofs;
|
||||
int x, x2 = realpatch->width;
|
||||
|
||||
if (realpatch->height == 256)
|
||||
{
|
||||
for (x = 0; x < x2; ++x)
|
||||
{
|
||||
const column_t *col = (column_t*)((BYTE*)realpatch + cofs[x]);
|
||||
if (col->topdelta != 0 || col->length != 0)
|
||||
{
|
||||
return false; // It's not bad!
|
||||
}
|
||||
col = (column_t *)((BYTE *)col + 256 + 4);
|
||||
if (col->topdelta != 0xFF)
|
||||
{
|
||||
return false; // More than one post in a column!
|
||||
}
|
||||
}
|
||||
if (x == x2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PatchToPng(int options, const uint8_t *ldata, int length, const char *pngpath)
|
||||
{
|
||||
const unsigned char *palette = GetPalette(options);
|
||||
|
||||
const column_t *maxcol;
|
||||
int x;
|
||||
|
||||
const patch_t *patch = (const patch_t *)ldata;
|
||||
|
||||
int height = patch->height;
|
||||
int width = patch->width;
|
||||
uint8_t *image = new uint8_t[width * height * 4];
|
||||
memset(image, 0, width*height * 4);
|
||||
|
||||
maxcol = (const column_t *)((const BYTE *)patch + length - 3);
|
||||
|
||||
// detect broken patches
|
||||
if (IsHack(ldata, length))
|
||||
{
|
||||
// Draw the image to the buffer
|
||||
for (x = 0; x < width; ++x)
|
||||
{
|
||||
const BYTE *in = (const BYTE *)patch + patch->columnofs[x] + 3;
|
||||
|
||||
for (int y = height; y > 0; --y)
|
||||
{
|
||||
unsigned char *ddata = &image[(x + y*width) * 4];
|
||||
ddata[0] = palette[*in * 3 + 0];
|
||||
ddata[1] = palette[*in * 3 + 1];
|
||||
ddata[2] = palette[*in * 3 + 2];
|
||||
ddata[3] = 255;
|
||||
in++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Draw the image to the buffer
|
||||
for (x = 0; x < width; ++x)
|
||||
{
|
||||
const column_t *column = (const column_t *)((const BYTE *)patch + patch->columnofs[x]);
|
||||
int top = -1;
|
||||
|
||||
while (column < maxcol && column->topdelta != 0xFF)
|
||||
{
|
||||
if (column->topdelta <= top)
|
||||
{
|
||||
top += column->topdelta;
|
||||
}
|
||||
else
|
||||
{
|
||||
top = column->topdelta;
|
||||
}
|
||||
|
||||
int len = column->length;
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
if (top + len > height) // Clip posts that extend past the bottom
|
||||
{
|
||||
len = height - top;
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
const BYTE *in = (const BYTE *)column + 3;
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
unsigned char *ddata = &image[(x + (top+i)*width) * 4];
|
||||
ddata[0] = palette[in[i] * 3 + 0];
|
||||
ddata[1] = palette[in[i] * 3 + 1];
|
||||
ddata[2] = palette[in[i] * 3 + 2];
|
||||
ddata[3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
column = (const column_t *)((const BYTE *)column + column->length + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WritePNG(image, width, height, patch->leftoffset, patch->topoffset, pngpath);
|
||||
delete[]image;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct DoomSoundHead
|
||||
{
|
||||
unsigned short three;
|
||||
unsigned short samplerate;
|
||||
unsigned short samples;
|
||||
unsigned short zero;
|
||||
};
|
||||
|
||||
struct WavSoundHead
|
||||
{
|
||||
char riff[4];
|
||||
unsigned size;
|
||||
char wave[4];
|
||||
char fmt[4];
|
||||
unsigned x10;
|
||||
unsigned short x01;
|
||||
unsigned short channels;
|
||||
unsigned rate;
|
||||
unsigned bytesPerSecond;
|
||||
unsigned short bytesPerSample;
|
||||
unsigned short bitsPerSample;
|
||||
char data[4];
|
||||
unsigned length;
|
||||
|
||||
WavSoundHead()
|
||||
{
|
||||
riff[0] = 'R'; riff[1] = 'I'; riff[2] = 'F'; riff[3] = 'F';
|
||||
wave[0] = 'W'; wave[1] = 'A'; wave[2] = 'V'; wave[3] = 'E';
|
||||
fmt[0] = 'f'; fmt[1] = 'm'; fmt[2] = 't'; fmt[3] = ' ';
|
||||
x10 = 0x10; // length of format chunk
|
||||
x01 = 0x01;
|
||||
channels = 1;
|
||||
bytesPerSample = 1; // 8 bit mono
|
||||
bitsPerSample = 8; // 8 bit mono
|
||||
data[0] = 'd'; data[1] = 'a'; data[2] = 't'; data[3] = 'a';
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool DoomSndToWav(const uint8_t *data, int length, const char *filename)
|
||||
{
|
||||
|
||||
DoomSoundHead *head = (DoomSoundHead *)data;
|
||||
uint32_t headSize = sizeof(DoomSoundHead);
|
||||
uint32_t dataSize = length - headSize;
|
||||
|
||||
WavSoundHead wh;
|
||||
wh.length = dataSize;
|
||||
wh.size = dataSize + 36;
|
||||
wh.rate = wh.bytesPerSecond = head->samplerate;
|
||||
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (f != NULL)
|
||||
{
|
||||
fwrite(&wh, 1, sizeof(WavSoundHead), f);
|
||||
fwrite(data + headSize, 1, dataSize, f);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
674
copying.txt
Normal file
674
copying.txt
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
645
fileformat.cpp
Normal file
645
fileformat.cpp
Normal file
|
@ -0,0 +1,645 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include "wadext.h"
|
||||
#include "fileformat.h"
|
||||
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
struct Detector
|
||||
{
|
||||
bool(*checker)(const uint8_t *pbuffer, int len);
|
||||
FileType ret;
|
||||
};
|
||||
|
||||
bool IsMagic(const uint8_t *s, const char *magic, int len = 4)
|
||||
{
|
||||
return !memcmp(s, magic, len);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Doom patch detector
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isPatch(const uint8_t *data, int length)
|
||||
{
|
||||
if (length < 13) return false; // minimum length of a valid Doom patch
|
||||
|
||||
const patch_t *foo = (const patch_t *)data;
|
||||
|
||||
int height = foo->height;
|
||||
int width = foo->width;
|
||||
|
||||
if (height <= 4096 && width <= 4096 && width < length / 4 && abs(foo->leftoffset) < 4096 && abs(foo->topoffset) < 4096)
|
||||
{
|
||||
// The dimensions seem like they might be valid for a patch, so
|
||||
// check the column directory for extra security. At least one
|
||||
// column must begin exactly at the end of the column directory,
|
||||
// and none of them must point past the end of the patch.
|
||||
bool gapAtStart = true;
|
||||
int x;
|
||||
|
||||
for (x = 0; x < width; ++x)
|
||||
{
|
||||
uint32_t ofs = foo->columnofs[x];
|
||||
if (ofs == (uint32_t)width * 4 + 8)
|
||||
{
|
||||
gapAtStart = false;
|
||||
}
|
||||
else if (ofs >= (uint32_t)length) // Need one byte for an empty column (but there's patches that don't know that!)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !gapAtStart;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isPng(const uint8_t *data, int length)
|
||||
{
|
||||
const uint32_t *dwdata = (const uint32_t*)data;
|
||||
if (length < 16) return false;
|
||||
// Check up to the IHDR so that this rejects Apple's homegrown image format that masquerades as a PNG but isn't one.
|
||||
return
|
||||
dwdata[0] == MAKE_ID(137, 'P', 'N', 'G') &&
|
||||
dwdata[1] == MAKE_ID(13, 10, 26, 10) &&
|
||||
dwdata[2] == MAKE_ID(0, 0, 0, 13) &&
|
||||
dwdata[3] == MAKE_ID('I', 'H', 'D', 'R');
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isJpg(const uint8_t *data, int length)
|
||||
{
|
||||
return (*data == 0xff && IsMagic(data + 6, "JFIF"));
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isTGA(const uint8_t *data, int length)
|
||||
{
|
||||
const TGAHeader *hdr = (const TGAHeader *)data;
|
||||
if (length < sizeof(TGAHeader)) return false;
|
||||
|
||||
// Not much that can be done here because TGA does not have a proper
|
||||
// header to be identified with.
|
||||
if (hdr->has_cm != 0 && hdr->has_cm != 1) return false;
|
||||
if (hdr->width <= 0 || hdr->height <= 0) return false;
|
||||
if (hdr->bpp != 8 && hdr->bpp != 15 && hdr->bpp != 16 && hdr->bpp != 24 && hdr->bpp != 32) return false;
|
||||
if (hdr->img_type <= 0 || hdr->img_type > 11) return false;
|
||||
if (hdr->img_type >= 4 && hdr->img_type <= 8) return false;
|
||||
if ((hdr->img_desc & 16) != 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isPCX(const uint8_t *data, int length)
|
||||
{
|
||||
const PCXHeader *hdr = (const PCXHeader*)data;
|
||||
|
||||
if (length < sizeof(PCXHeader)) return false;
|
||||
|
||||
if (hdr->manufacturer != 10 || hdr->encoding != 1) return false;
|
||||
if (hdr->version != 0 && hdr->version != 2 && hdr->version != 3 && hdr->version != 4 && hdr->version != 5) return false;
|
||||
if (hdr->bitsPerPixel != 1 && hdr->bitsPerPixel != 8) return false;
|
||||
if (hdr->bitsPerPixel == 1 && hdr->numColorPlanes != 1 && hdr->numColorPlanes != 4) return false;
|
||||
if (hdr->bitsPerPixel == 8 && hdr->uint8_tsPerScanLine != ((hdr->xmax - hdr->xmin + 2)&~1)) return false;
|
||||
|
||||
for (int i = 0; i < 54; i++)
|
||||
{
|
||||
if (hdr->padding[i] != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isDDS(const uint8_t *data, int length)
|
||||
{
|
||||
const DDSFileHeader *Header = (const DDSFileHeader*)data;
|
||||
if (length < sizeof(DDSFileHeader)) return false;
|
||||
|
||||
return Header->Magic == ID_DDS &&
|
||||
(Header->Desc.Size == sizeof(DDSURFACEDESC2) || Header->Desc.Size == ID_DDS) &&
|
||||
Header->Desc.PixelFormat.Size == sizeof(DDPIXELFORMAT) &&
|
||||
(Header->Desc.Flags & (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT)) == (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT) &&
|
||||
Header->Desc.Width != 0 &&
|
||||
Header->Desc.Height != 0;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isImgz(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "IMGZ");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isMid(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "MThd");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isMus(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "MUS\x1a");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isIt(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "IMPM");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isS3m(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len >= 0x30 && IsMagic(pbuffer+0x3c, "SCRM");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isXt(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len >= 0x34 && IsMagic(pbuffer + 0x26, "FastTracker", 11);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isMod(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
if (len < 1084) return false;
|
||||
|
||||
const uint8_t *s = pbuffer + 1080;
|
||||
return (IsMagic(s, "M.K.") || IsMagic(s, "M!K!") || IsMagic(s, "M&K!") || IsMagic(s, "N.T.") ||
|
||||
IsMagic(s, "CD81") || IsMagic(s, "OKTA") || IsMagic(s, "16CN") || IsMagic(s, "32CN") ||
|
||||
((s[0] == 'F') && (s[1] == 'L') && (s[2] == 'T') && (s[3] >= '4') && (s[3] <= '9')) ||
|
||||
((s[0] >= '2') && (s[0] <= '9') && (s[1] == 'C') && (s[2] == 'H') && (s[3] == 'N')) ||
|
||||
((s[0] == '1') && (s[1] >= '0') && (s[1] <= '9') && (s[2] == 'C') && (s[3] == 'H')) ||
|
||||
((s[0] == '2') && (s[1] >= '0') && (s[1] <= '9') && (s[2] == 'C') && (s[3] == 'H')) ||
|
||||
((s[0] == '3') && (s[1] >= '0') && (s[1] <= '2') && (s[2] == 'C') && (s[3] == 'H')) ||
|
||||
((s[0] == 'T') && (s[1] == 'D') && (s[2] == 'Z') && (s[3] >= '4') && (s[3] <= '9'))
|
||||
);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isSpc(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len >= 27 && IsMagic(pbuffer, "SNES - SPC700 Sound File Data v0.30\x1A\x1A", 27);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isHmi(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len >= 12 && IsMagic(pbuffer, "HMI-MIDISONG", 12);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isHmp(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len >= 12 && IsMagic(pbuffer, "HMIMIDIP", 8);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isXmi(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len >= 12 &&
|
||||
(IsMagic(pbuffer, "FORM") && IsMagic(pbuffer + 8, "XDIR") ||
|
||||
IsMagic(pbuffer, "FORM") && IsMagic(pbuffer + 8, "XMID") ||
|
||||
IsMagic(pbuffer, "CAT ") && IsMagic(pbuffer + 8, "XMID"));
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Doom sound format has virtually no reliable features to identify.
|
||||
// All we can go by is to check if the little info in the header makes sense.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isDoomSound(const uint8_t *data, int len)
|
||||
{
|
||||
if (len < 8) return false;
|
||||
uint32_t dmxlen = GetInt(data + 4);
|
||||
int32_t freq = GetShort(data + 2) & 0xffff;
|
||||
return data[0] == 3 && data[1] == 0 /*&& (freq == 0 || freq == 11025 || freq == 22050 || freq == 44100)*/ && dmxlen <= unsigned(len - 8);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isWav(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len > 16 && IsMagic(pbuffer, "RIFF") && IsMagic(pbuffer + 8, "WAVE");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isAiff(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len > 12 && IsMagic(pbuffer, "FORM") && IsMagic(pbuffer+8, "AIFF");
|
||||
}
|
||||
|
||||
bool isAifc(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len > 12 && IsMagic(pbuffer, "FORM") && IsMagic(pbuffer + 8, "AIFC");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isFlac(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "fLaC");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isOgg(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "OggS");
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Almost nothing to check here, so this format is checked last of all.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isMP3(const uint8_t *data, int len)
|
||||
{
|
||||
if (IsMagic(data, "ID3\3")) return true;
|
||||
return data[0] == 0xff && ((data[1] & 0xfe) == 0xfa/*MPEG-1*/ || (data[1] & 0xfe) == 0xf2/*MPEG-2*/);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isVoc(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return len > 19 && IsMagic(pbuffer, "Creative Voice File", 19);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isFon1(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "FON1") && pbuffer[5] == 0 && pbuffer[7] == 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isFon2(const uint8_t *pbuffer, int len)
|
||||
{
|
||||
return IsMagic(pbuffer, "FON2") && pbuffer[5] == 0 && pbuffer[6] <= pbuffer[7];
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool isBmf(const uint8_t *data, int len)
|
||||
{
|
||||
return (data[0] == 0xE1 && data[1] == 0xE6 && data[2] == 0xD5 && data[3] == 0x1A);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool isKVX(const uint8_t *data, int length)
|
||||
{
|
||||
// This isn't reliable enough.
|
||||
return false;
|
||||
#if 0
|
||||
const kvxslab_t *slabs[MAXVOXMIPS];
|
||||
const uint8_t *rawmip;
|
||||
int mip, maxmipsize;
|
||||
int i, j, n;
|
||||
|
||||
const uint8_t *rawvoxel = data;
|
||||
int voxelsize = length - 1;
|
||||
|
||||
// Oh, KVX, why couldn't you have a proper header? We'll just go through
|
||||
// and collect each MIP level, doing lots of range checking, and if the
|
||||
// last one doesn't end exactly 768 uint8_ts before the end of the file,
|
||||
// we'll reject it.
|
||||
|
||||
for (mip = 0, rawmip = rawvoxel, maxmipsize = voxelsize - 768 - 4;
|
||||
mip < MAXVOXMIPS;
|
||||
mip++)
|
||||
{
|
||||
int numuint8_ts = GetInt(rawmip);
|
||||
if (numuint8_ts > maxmipsize || numuint8_ts < 24)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rawmip += 4;
|
||||
|
||||
FVoxelMipLevel mipl;
|
||||
|
||||
// Load header data.
|
||||
mipl.SizeX = GetInt(rawmip + 0);
|
||||
mipl.SizeY = GetInt(rawmip + 4);
|
||||
mipl.SizeZ = GetInt(rawmip + 8);
|
||||
if (mipl.SizeX > 255 || mipl.SizeY > 255 || mipl.SizeZ > 255) return false;
|
||||
|
||||
// How much space do we have for voxdata?
|
||||
int offsetsize = (mipl.SizeX + 1) * 4 + mipl.SizeX * (mipl.SizeY + 1) * 2;
|
||||
int voxdatasize = numuint8_ts - 24 - offsetsize;
|
||||
if (voxdatasize < 0)
|
||||
{ // Clearly, not enough.
|
||||
return false;
|
||||
}
|
||||
if (voxdatasize != 0)
|
||||
{ // This mip level is not empty.
|
||||
// Allocate slab data space.
|
||||
mipl.OffsetX = new int[(numuint8_ts - 24 + 3) / 4];
|
||||
mipl.OffsetXY = (short *)(mipl.OffsetX + mipl.SizeX + 1);
|
||||
mipl.SlabData = (uint8_t *)(mipl.OffsetXY + mipl.SizeX * (mipl.SizeY + 1));
|
||||
|
||||
// Load x offsets.
|
||||
for (i = 0, n = mipl.SizeX; i <= n; ++i)
|
||||
{
|
||||
// The X offsets stored in the KVX file are relative to the start of the
|
||||
// X offsets array. Make them relative to voxdata instead.
|
||||
mipl.OffsetX[i] = GetInt(rawmip + 24 + i * 4) - offsetsize;
|
||||
}
|
||||
|
||||
// The first X offset must be 0 (since we subtracted offsetsize), according to the spec:
|
||||
// NOTE: xoffset[0] = (xsiz+1)*4 + xsiz*(ysiz+1)*2 (ALWAYS)
|
||||
if (mipl.OffsetX[0] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// And the final X offset must point just past the end of the voxdata.
|
||||
if (mipl.OffsetX[mipl.SizeX] != voxdatasize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Load xy offsets.
|
||||
i = 24 + i * 4;
|
||||
for (j = 0, n *= mipl.SizeY + 1; j < n; ++j)
|
||||
{
|
||||
mipl.OffsetXY[j] = GetShort(rawmip + i + j * 2);
|
||||
}
|
||||
|
||||
// Ensure all offsets are within bounds.
|
||||
for (i = 0; i < (int)mipl.SizeX; ++i)
|
||||
{
|
||||
int xoff = mipl.OffsetX[i];
|
||||
for (j = 0; j < (int)mipl.SizeY; ++j)
|
||||
{
|
||||
int yoff = mipl.OffsetXY[(mipl.SizeY + 1) * i + j];
|
||||
if (unsigned(xoff + yoff) > unsigned(voxdatasize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record slab location for the end.
|
||||
slabs[mip] = (kvxslab_t *)(rawmip + 24 + offsetsize);
|
||||
}
|
||||
|
||||
// Time for the next mip Level.
|
||||
rawmip += numuint8_ts;
|
||||
maxmipsize -= numuint8_ts + 4;
|
||||
}
|
||||
// Did we get any mip levels, and if so, does the last one leave just
|
||||
// enough room for the palette after it?
|
||||
if (mip == 0 || rawmip != rawvoxel + voxelsize - 768)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// formats are listed in descending order of detection reliability, not grouped by types!
|
||||
static Detector detectors[] =
|
||||
{
|
||||
// format which have an identifier at the beginning of the file
|
||||
{ isPng,{ FT_PNG, ".PNG" } },
|
||||
{ isJpg,{ FT_JPG, ".JPG" }},
|
||||
{ isMid, { FT_MID, ".MID" }},
|
||||
{ isOgg, { FT_OGGBASE, ".OGG" }},
|
||||
{ isMus, { FT_MUS, ".MUS" }},
|
||||
{ isFlac,{ FT_FLAC, ".FLAC" }},
|
||||
{ isAiff, { FT_AIFF, ".AIF" }},
|
||||
{ isAifc, { FT_AIFF, ".AIFC" }},
|
||||
{ isIt,{ FT_AIFF, ".IT" } },
|
||||
{ isSpc,{ FT_SPC, ".SPC" } },
|
||||
{ isVoc,{ FT_VOC, ".VOC" }},
|
||||
{ isWav,{ FT_WAV, ".WAV" } },
|
||||
{ isImgz,{ FT_VOC, ".IMGZ" } },
|
||||
{ isHmi, { FT_HMI, ".HMI" }},
|
||||
{ isHmp,{ FT_HMP, ".HMP" } },
|
||||
{ isXmi,{ FT_XMI, ".XMI" } },
|
||||
{ isBmf,{ FT_BMF, ".BMF" } },
|
||||
{ isFon1,{ FT_FON1, ".FON1" } },
|
||||
{ isFon2,{ FT_FON2, ".FON2" } },
|
||||
|
||||
// formats which have an identifier near the beginning of a file
|
||||
{ isS3m, { FT_S3M, ".S3M" }},
|
||||
{ isXt, { FT_XM, ".XM" }},
|
||||
|
||||
// format which can only be detected by checking the header (MOD has an identifier in the middle, but too far from the start to be considered safe.)
|
||||
{ isTGA,{ FT_TGA, ".TGA" } },
|
||||
{ isPCX,{ FT_PCX, ".PCX" } },
|
||||
{ isDDS,{ FT_DDS, ".DDS" } },
|
||||
{ isMod,{ FT_MOD, ".MOD" } },
|
||||
{ isPatch,{ FT_DOOMGFX, ".GFX" } },
|
||||
|
||||
// formats which cannot easily be detected reliably
|
||||
{ isKVX, { FT_KVX, ".KVX" }},
|
||||
{ isDoomSound, { FT_DOOMSND, ".DMX" }},
|
||||
{ isMP3,{ FT_MP3BASE, ".MP3" } },
|
||||
};
|
||||
|
||||
|
||||
FileType resolveUnknown(FileType ft, const char *name, int length)
|
||||
{
|
||||
switch (ft.type)
|
||||
{
|
||||
case FT_OGGBASE:
|
||||
case FT_MP3BASE:
|
||||
// todo: Try to be a bit smarter about deciding whether this is a music or sound lump.
|
||||
if (!strnicmp(name, "DS", 2)) ft.type |= FG_SND;
|
||||
else if (!strnicmp(name, "D_", 2)) ft.type |= FG_MUS;
|
||||
else if (length < 400000) ft.type |= FG_SND;
|
||||
else ft.type |= FG_MUS;
|
||||
break;
|
||||
}
|
||||
return ft;
|
||||
}
|
||||
|
||||
FileType IdentifyFileType(const char *name, const uint8_t *data, int length)
|
||||
{
|
||||
if (length > 4)
|
||||
{
|
||||
for (auto &t : detectors)
|
||||
{
|
||||
if (t.checker(data, length))
|
||||
{
|
||||
return resolveUnknown(t.ret, name, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (length == 0)
|
||||
{
|
||||
return{ FT_BINARY, ".LMP" };
|
||||
}
|
||||
// Identify pure text files. If any character < 32, except \t, \n, \r is present, a binary file is assumed
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (data[i] < 9 || data[i] == 11 || data[i] == 12 || (data[i] >= 14 && data[i] < 32))
|
||||
{
|
||||
return{ FT_BINARY, ".LMP" };
|
||||
}
|
||||
}
|
||||
return{ FT_TEXT, ".TXT" };
|
||||
}
|
||||
|
||||
|
249
fileformat.h
Normal file
249
fileformat.h
Normal file
|
@ -0,0 +1,249 @@
|
|||
#include <stdint.h>
|
||||
|
||||
enum
|
||||
{
|
||||
FG_UNKNOWN = 0,
|
||||
FG_GFX = 0x10000,
|
||||
FG_SND = 0x20000,
|
||||
FG_MUS = 0x30000,
|
||||
FG_VOX = 0x40000,
|
||||
FG_FONT = 0x50000,
|
||||
FG_OTHER = 0x60000,
|
||||
FG_MASK = 0xff0000,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FT_MP3BASE = 1,
|
||||
FT_OGGBASE = 2,
|
||||
|
||||
FT_DOOMGFX = FG_GFX + 1,
|
||||
FT_PNG = FG_GFX + 2,
|
||||
FT_JPG = FG_GFX + 3,
|
||||
FT_PCX = FG_GFX + 4,
|
||||
FT_TGA = FG_GFX + 5,
|
||||
FT_DDS = FG_GFX + 6,
|
||||
FT_IMGZ = FG_GFX + 7,
|
||||
|
||||
FT_MP3 = FG_SND + FT_MP3BASE,
|
||||
FT_OGG = FG_SND + FT_OGGBASE,
|
||||
FT_DOOMSND = FG_SND + 3,
|
||||
FT_WAV = FG_SND + 4,
|
||||
FT_VOC = FG_SND + 5,
|
||||
FT_AIFF = FG_SND + 6,
|
||||
FT_FLAC = FG_SND + 7,
|
||||
|
||||
FT_MP3MUS = FG_MUS + FT_MP3BASE,
|
||||
FT_OGGMUS = FG_MUS + FT_OGGBASE,
|
||||
FT_MUS = FG_MUS + 3,
|
||||
FT_MID = FG_MUS + 4,
|
||||
FT_XMI = FG_MUS + 5,
|
||||
FT_HMP = FG_MUS + 6,
|
||||
FT_HMI = FG_MUS + 7,
|
||||
FT_SPC = FG_MUS + 8,
|
||||
FT_MOD = FG_MUS + 9,
|
||||
FT_IT = FG_MUS + 10,
|
||||
FT_XM = FG_MUS + 11,
|
||||
FT_S3M = FG_MUS + 12,
|
||||
// Todo: add more specialized formats if needed
|
||||
|
||||
FT_KVX = FG_VOX + 1,
|
||||
|
||||
FT_FON1 = FG_FONT + 1,
|
||||
FT_FON2 = FG_FONT + 2,
|
||||
FT_BMF = FG_FONT + 3,
|
||||
|
||||
FT_TEXT = FG_OTHER + 1,
|
||||
FT_BINARY = FG_OTHER + 2,
|
||||
FT_LEVEL = FG_OTHER + 3,
|
||||
FT_MARKER = FG_OTHER + 4,
|
||||
};
|
||||
|
||||
struct FileType
|
||||
{
|
||||
int type;
|
||||
const char *extension;
|
||||
};
|
||||
|
||||
// various file format headers for type detection.
|
||||
|
||||
// posts are runs of non masked source pixels
|
||||
struct column_t
|
||||
{
|
||||
BYTE topdelta; // -1 is the last post in a column
|
||||
BYTE length; // length data bytes follows
|
||||
};
|
||||
|
||||
struct patch_t
|
||||
{
|
||||
uint16_t width; // bounding box size
|
||||
uint16_t height;
|
||||
int16_t leftoffset; // pixels to the left of origin
|
||||
int16_t topoffset; // pixels below the origin
|
||||
uint32_t columnofs[1]; // only [width] used
|
||||
// the [0] is &columnofs[width]
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
struct TGAHeader
|
||||
{
|
||||
uint8_t id_len;
|
||||
uint8_t has_cm;
|
||||
uint8_t img_type;
|
||||
int16_t cm_first;
|
||||
int16_t cm_length;
|
||||
uint8_t cm_size;
|
||||
|
||||
int16_t x_origin;
|
||||
int16_t y_origin;
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
uint8_t bpp;
|
||||
uint8_t img_desc;
|
||||
};
|
||||
|
||||
struct PCXHeader
|
||||
{
|
||||
uint8_t manufacturer;
|
||||
uint8_t version;
|
||||
uint8_t encoding;
|
||||
uint8_t bitsPerPixel;
|
||||
|
||||
uint16_t xmin, ymin;
|
||||
uint16_t xmax, ymax;
|
||||
uint16_t horzRes, vertRes;
|
||||
|
||||
uint8_t palette[48];
|
||||
uint8_t reserved;
|
||||
uint8_t numColorPlanes;
|
||||
|
||||
uint16_t uint8_tsPerScanLine;
|
||||
uint16_t paletteType;
|
||||
uint16_t horzSize, vertSize;
|
||||
|
||||
uint8_t padding[54];
|
||||
|
||||
};
|
||||
|
||||
#ifndef __BIG_ENDIAN__
|
||||
#define MAKE_ID(a,b,c,d) ((DWORD)((a)|((b)<<8)|((c)<<16)|((d)<<24)))
|
||||
#else
|
||||
#define MAKE_ID(a,b,c,d) ((DWORD)((d)|((c)<<8)|((b)<<16)|((a)<<24)))
|
||||
#endif
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define ID_DDS MAKE_ID('D','D','S',' ')
|
||||
#define ID_DXT1 MAKE_ID('D','X','T','1')
|
||||
#define ID_DXT2 MAKE_ID('D','X','T','2')
|
||||
#define ID_DXT3 MAKE_ID('D','X','T','3')
|
||||
#define ID_DXT4 MAKE_ID('D','X','T','4')
|
||||
#define ID_DXT5 MAKE_ID('D','X','T','5')
|
||||
|
||||
// Bits in dwFlags
|
||||
#define DDSD_CAPS 0x00000001
|
||||
#define DDSD_HEIGHT 0x00000002
|
||||
#define DDSD_WIDTH 0x00000004
|
||||
#define DDSD_PITCH 0x00000008
|
||||
#define DDSD_PIXELFORMAT 0x00001000
|
||||
#define DDSD_MIPMAPCOUNT 0x00020000
|
||||
#define DDSD_LINEARSIZE 0x00080000
|
||||
#define DDSD_DEPTH 0x00800000
|
||||
|
||||
// Bits in ddpfPixelFormat
|
||||
#define DDPF_ALPHAPIXELS 0x00000001
|
||||
#define DDPF_FOURCC 0x00000004
|
||||
#define DDPF_RGB 0x00000040
|
||||
|
||||
// Bits in DDSCAPS2.dwCaps1
|
||||
#define DDSCAPS_COMPLEX 0x00000008
|
||||
#define DDSCAPS_TEXTURE 0x00001000
|
||||
#define DDSCAPS_MIPMAP 0x00400000
|
||||
|
||||
// Bits in DDSCAPS2.dwCaps2
|
||||
#define DDSCAPS2_CUBEMAP 0x00000200
|
||||
#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
|
||||
#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
|
||||
#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
|
||||
#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
|
||||
#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
|
||||
#define DDSCAPS2_CUBEMAP_NEGATIZEZ 0x00008000
|
||||
#define DDSCAPS2_VOLUME 0x00200000
|
||||
|
||||
struct DDPIXELFORMAT
|
||||
{
|
||||
uint32_t Size; // Must be 32
|
||||
uint32_t Flags;
|
||||
uint32_t FourCC;
|
||||
uint32_t RGBBitCount;
|
||||
uint32_t RBitMask, GBitMask, BBitMask;
|
||||
uint32_t RGBAlphaBitMask;
|
||||
};
|
||||
|
||||
struct DDCAPS2
|
||||
{
|
||||
uint32_t Caps1, Caps2;
|
||||
uint32_t Reserved[2];
|
||||
};
|
||||
|
||||
struct DDSURFACEDESC2
|
||||
{
|
||||
uint32_t Size; // Must be 124. DevIL claims some writers set it to 'DDS ' instead.
|
||||
uint32_t Flags;
|
||||
uint32_t Height;
|
||||
uint32_t Width;
|
||||
union
|
||||
{
|
||||
int32_t Pitch;
|
||||
uint32_t LinearSize;
|
||||
};
|
||||
uint32_t Depth;
|
||||
uint32_t MipMapCount;
|
||||
uint32_t Reserved1[11];
|
||||
DDPIXELFORMAT PixelFormat;
|
||||
DDCAPS2 Caps;
|
||||
uint32_t Reserved2;
|
||||
};
|
||||
|
||||
struct DDSFileHeader
|
||||
{
|
||||
uint32_t Magic;
|
||||
DDSURFACEDESC2 Desc;
|
||||
};
|
||||
|
||||
#define MAXVOXMIPS 5
|
||||
|
||||
struct kvxslab_t
|
||||
{
|
||||
uint8_t ztop; // starting z coordinate of top of slab
|
||||
uint8_t zleng; // # of uint8_ts in the color array - slab height
|
||||
uint8_t backfacecull; // low 6 bits tell which of 6 faces are exposed
|
||||
uint8_t col[1/*zleng*/];// color data from top to bottom
|
||||
};
|
||||
|
||||
struct FVoxelMipLevel
|
||||
{
|
||||
unsigned int SizeX;
|
||||
unsigned int SizeY;
|
||||
unsigned int SizeZ;
|
||||
int *OffsetX;
|
||||
short *OffsetXY;
|
||||
uint8_t *SlabData;
|
||||
};
|
||||
|
||||
inline int GetInt(const unsigned char *foo)
|
||||
{
|
||||
return *(const int *)foo;
|
||||
}
|
||||
|
||||
inline int GetShort(const unsigned char *foo)
|
||||
{
|
||||
return *(const short *)foo;
|
||||
}
|
||||
|
||||
FileType IdentifyFileType(const char *name, const uint8_t *data, int length);
|
||||
|
||||
bool FlatToPng(int options, const uint8_t *data, int length, const char *pngpath);
|
||||
bool PatchToPng(int options, const uint8_t *ldata, int length, const char *pngpath);
|
||||
bool DoomSndToWav(const uint8_t *data, int length, const char *filename);
|
93
main.cpp
Normal file
93
main.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "wadext.h"
|
||||
|
||||
void BuildWad(char * wadfilename,int options);
|
||||
void ExtractWad(char * wadfilename,int options);
|
||||
void ConvertTextureX();
|
||||
|
||||
int ParseOptions(int argc,char ** argv,int & index)
|
||||
{
|
||||
struct parseinf
|
||||
{
|
||||
char * opt;
|
||||
int flag;
|
||||
int argc;
|
||||
} pi[]={
|
||||
{"-nogfxconvert",NO_CONVERT_GFX},
|
||||
{"-nosndconvert",NO_CONVERT_SND },
|
||||
{"-heretic",DO_HERETIC_PAL},
|
||||
{"-hexen",DO_HEXEN_PAL},
|
||||
{"-strife",DO_STRIFE},
|
||||
{"-strip",DO_STRIP},
|
||||
{NULL,0}
|
||||
};
|
||||
|
||||
int def_opt=0;
|
||||
|
||||
for(int i=2;i<argc;i++)
|
||||
{
|
||||
for(int j=0;pi[j].opt;j++)
|
||||
{
|
||||
if (!stricmp(argv[i],pi[j].opt))
|
||||
{
|
||||
def_opt|=pi[j].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return def_opt;
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
if (argc>1 && !strcmp(argv[1], "-tx"))
|
||||
{
|
||||
ConvertTextureX();
|
||||
}
|
||||
else if (argc>2)
|
||||
{
|
||||
int index;
|
||||
int f=ParseOptions(argc,argv,index);
|
||||
ExtractWad(argv[1],f);
|
||||
}
|
||||
else if (argc > 1)
|
||||
{
|
||||
ExtractWad(argv[1],DO_STRIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("WadExt v1.0 (c) 2016 Christoph Oelckers\nUsage: wadext [options] filename\n");
|
||||
printf("Options:\n");
|
||||
printf(" -nogfxconvert : Leave Doom format patches and flats in their original form, if not specified they will be converted to PNG.\n");
|
||||
printf(" -nosndconvert : Leave Doom format sounds in their original form, if not specified they will be converted to WAV.\n");
|
||||
printf(" -heretic, -hexen, -strife: Force usage of the named game's palette if the WAD does not contain one. Default is Doom palette\n");
|
||||
printf(" -strip: Remove node lumps from extracted maps.\n");
|
||||
printf(" -tx: Converts a set of TEXTURE1/TEXTURE2/PNAMES in the current directory to a textures.txt file.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
88
resourcefile.h
Normal file
88
resourcefile.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#ifndef __RESOURCEFILE_H
|
||||
#define __RESOURCEFILE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "tarray.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct CWADLump
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
char name[9];
|
||||
};
|
||||
|
||||
class CWADFile
|
||||
{
|
||||
TArray<CWADLump> lumps;
|
||||
FILE *m_File;
|
||||
|
||||
char * m_Filename;
|
||||
int m_NumLumps;
|
||||
uint64_t m_LumpStart;
|
||||
|
||||
public:
|
||||
CWADFile(const char * filename);
|
||||
CWADFile(const char * name, const char * memory);
|
||||
~CWADFile(void);
|
||||
|
||||
const char * GetName() const
|
||||
{
|
||||
return m_Filename;
|
||||
}
|
||||
int NumLumps()
|
||||
{
|
||||
return m_NumLumps;
|
||||
}
|
||||
|
||||
virtual int FindLump(const char * name);
|
||||
virtual int GetLumpSize(int lump);
|
||||
virtual void * ReadLump(int lump);
|
||||
virtual void ReadLump(int lump, void * buffer);
|
||||
virtual const char * GetLumpName(int lump);
|
||||
};
|
||||
|
||||
extern CWADFile *mainwad;
|
||||
|
||||
struct WadItemList
|
||||
{
|
||||
int mLump;
|
||||
TArray<char> mData;
|
||||
|
||||
WadItemList(int lump)
|
||||
{
|
||||
mLump = lump;
|
||||
}
|
||||
|
||||
char * Address()
|
||||
{
|
||||
if (mData.Size() != Length())
|
||||
{
|
||||
mData.Resize(Length());
|
||||
}
|
||||
mainwad->ReadLump(mLump, &mData[0]);
|
||||
return &mData[0];
|
||||
}
|
||||
|
||||
int Length() const
|
||||
{
|
||||
return mainwad->GetLumpSize(mLump);
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
mData.Clear();
|
||||
}
|
||||
|
||||
const char * Name() const { return mainwad->GetLumpName(mLump); }
|
||||
};
|
||||
|
||||
void OpenMainWad(char * filename);
|
||||
|
||||
#endif
|
570
wadext.cpp
Normal file
570
wadext.cpp
Normal file
|
@ -0,0 +1,570 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include "wadext.h"
|
||||
#include "ResourceFile.h"
|
||||
#include "fileformat.h"
|
||||
|
||||
#pragma warning(disable:4996)
|
||||
|
||||
bool isLevel(WadItemList * we);
|
||||
char profile[256];
|
||||
char maindir[128];
|
||||
|
||||
bool pstartfound=false;
|
||||
WadItemList PNames(-1);
|
||||
|
||||
|
||||
char * getdir(const char * lump)
|
||||
{
|
||||
static char d[2]="";
|
||||
|
||||
if (*lump>='A' && *lump<='Z') d[0]=*lump;
|
||||
else if (*lump>='a' && *lump<='z') d[0]=*lump-32;
|
||||
else if (*lump>='0' && *lump<='9') d[0]='0';
|
||||
else d[0]='@';
|
||||
return d;
|
||||
}
|
||||
|
||||
bool isPatch(const char * n)
|
||||
{
|
||||
if (!pstartfound || PNames.mLump < 0) return false;
|
||||
long * l = (long*)PNames.Address();
|
||||
char * c = (char*)(l + 1);
|
||||
char nn[9];
|
||||
|
||||
|
||||
if (!l) return false;
|
||||
|
||||
strncpy(nn, n, 8);
|
||||
nn[8] = 0;
|
||||
strupr(nn);
|
||||
|
||||
for (int i = 0; i<*l; i++)
|
||||
{
|
||||
if (!strncmp(c, nn, 8)) return true;
|
||||
c += 8;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char * MakeFileName(const char * base, const char * ext)
|
||||
{
|
||||
char basebuffer[20];
|
||||
static char buffer[40];
|
||||
|
||||
strncpy(basebuffer,base,8);
|
||||
basebuffer[8]=0;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// replace special path characters in the lump name
|
||||
if (basebuffer[i] == '\\') basebuffer[i] = '^';
|
||||
if (basebuffer[i] == '/') basebuffer[i] = '§';
|
||||
if (basebuffer[i] == ':') basebuffer[i] = '¡';
|
||||
if (basebuffer[i] == '*') basebuffer[i] = '²';
|
||||
if (basebuffer[i] == '?') basebuffer[i] = '¿';
|
||||
}
|
||||
|
||||
for(int i=0;;i++)
|
||||
{
|
||||
if (i > 0) sprintf(buffer,"%s(%d)%s", basebuffer, i, ext);
|
||||
else sprintf(buffer, "%s%s", basebuffer, ext);
|
||||
strlwr(buffer);
|
||||
FILE *f = fopen(buffer, "rb");
|
||||
if (f == NULL) return buffer;
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
void Extract(WadItemList *w,char * dir,const char * ext, int options, bool isflat) //It is completely impossible to detect flats, so we have to flag it when extracting the F_ namespace
|
||||
{
|
||||
FileType ft = IdentifyFileType(w->Name(), (uint8_t*)w->Address(), w->Length());
|
||||
const char *filename;
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
switch (ft.type & FG_MASK)
|
||||
{
|
||||
case FG_GFX:
|
||||
if (isPatch(w->Name())) dir = "patches";
|
||||
else dir = "graphics";
|
||||
break;
|
||||
|
||||
case FG_SND:
|
||||
dir = "sounds";
|
||||
break;
|
||||
|
||||
case FG_MUS:
|
||||
dir = "music";
|
||||
break;
|
||||
|
||||
case FG_VOX:
|
||||
dir = "voxels";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
// Flats are easy to misidentify so if we are in the flat namespace and the size is exactly 4096 bytes, let it pass as flat
|
||||
if (isflat && (ft.type & FG_MASK) != FG_GFX && (ft.type == FT_DOOMSND || ft.type == FT_MP3 || w->Length() == 4096))
|
||||
{
|
||||
ft = { FT_BINARY, ".LMP"};
|
||||
}
|
||||
|
||||
if (dir != NULL)
|
||||
{
|
||||
mkdir(dir);
|
||||
chdir(dir);
|
||||
}
|
||||
printf("processing %.8s\n", w->Name());
|
||||
|
||||
if (ft.type == FT_DOOMGFX && !(options & NO_CONVERT_GFX))
|
||||
{
|
||||
filename = MakeFileName(w->Name(), ".png");
|
||||
PatchToPng(options, (const uint8_t*)w->Address(), w->Length(), filename);
|
||||
}
|
||||
else if (w->Length() > 0 && ft.type == FT_BINARY && !(options & NO_CONVERT_GFX) && (isflat || (w->Length() == 64000 && options&(DO_HEXEN_PAL | DO_HERETIC_PAL))))
|
||||
{
|
||||
filename = MakeFileName(w->Name(), ".png");
|
||||
FlatToPng(options, (const uint8_t*)w->Address(), w->Length(), filename);
|
||||
}
|
||||
else if (ft.type == FT_DOOMSND && !(options & NO_CONVERT_SND))
|
||||
{
|
||||
filename = MakeFileName(w->Name(), ".wav");
|
||||
DoomSndToWav((const uint8_t*)w->Address(), w->Length(), filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = MakeFileName(w->Name(), ft.extension);
|
||||
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (f == NULL)
|
||||
{
|
||||
printf("%s: Unable to create file\n", filename);
|
||||
chdir(maindir);
|
||||
return;
|
||||
}
|
||||
fwrite(w->Address(), 1, w->Length(), f);
|
||||
fclose(f);
|
||||
}
|
||||
chdir(maindir);
|
||||
}
|
||||
|
||||
int ListExtract(int startmarker,char * dir,char * endm,char * endm2,bool isflat,int options,int pack=0)
|
||||
{
|
||||
int ev=0;
|
||||
char dirbuf[200];
|
||||
|
||||
mkdir(dir);
|
||||
strcpy(dirbuf,dir);
|
||||
WadItemList ww(startmarker + 1);
|
||||
WadItemList *w = &ww;
|
||||
while (strncmp(w->Name(),endm,8) && strncmp(w->Name(),endm2,8))
|
||||
{
|
||||
Extract(w, dir, NULL, options, isflat);
|
||||
ww = ww.mLump + 1;
|
||||
}
|
||||
return ww.mLump;
|
||||
}
|
||||
|
||||
bool isLevel(int lump)
|
||||
{
|
||||
if (lump >= mainwad->NumLumps() - 3) return false; // any level is at least 3 lumps
|
||||
WadItemList w(lump + 1);
|
||||
if (!stricmp(w.Name(), "THINGS")) return true;
|
||||
if (!stricmp(w.Name(), "TEXTMAP")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int MapExtract(int startmarker,char *dir,int options)
|
||||
{
|
||||
int i;
|
||||
char buffer[40];
|
||||
int packlength[13]={0};
|
||||
TArray<CWADLump> directory;
|
||||
|
||||
mkdir(dir);
|
||||
chdir(dir);
|
||||
|
||||
WadItemList ww(startmarker);
|
||||
sprintf(buffer,"%.8s.wad", ww.Name());
|
||||
printf("processing %s\n",buffer);
|
||||
FILE *f=fopen(buffer, "wb");
|
||||
|
||||
fwrite("PWAD\xb\0\0\0\0\0\0\0",1, 12, f);
|
||||
|
||||
|
||||
CWADLump lmp;
|
||||
lmp.offset = ftell(f);
|
||||
strncpy(lmp.name, ww.Name(), 8);
|
||||
lmp.length = ww.Length();
|
||||
fwrite(ww.Address(), 1, ww.Length(), f);
|
||||
directory.Push(lmp);
|
||||
ww = ww.mLump + 1;
|
||||
|
||||
if (!stricmp(ww.Name(), "TEXTMAP"))
|
||||
{
|
||||
// UDMF
|
||||
while (true)
|
||||
{
|
||||
if (!(options & DO_STRIP) || (stricmp(ww.Name(), "ZNODES") && stricmp(ww.Name(), "BLOCKMAP") && stricmp(ww.Name(), "REJECT")))
|
||||
{
|
||||
CWADLump lmp;
|
||||
lmp.offset = ftell(f);
|
||||
strncpy(lmp.name, ww.Name(), 8);
|
||||
lmp.length = ww.Length();
|
||||
fwrite(ww.Address(), 1, ww.Length(), f);
|
||||
directory.Push(lmp);
|
||||
}
|
||||
|
||||
if (!stricmp(ww.Name(), "ENDMAP"))
|
||||
{
|
||||
goto finalize;
|
||||
}
|
||||
int lump = ww.mLump + 1;
|
||||
if (lump == mainwad->NumLumps())
|
||||
{
|
||||
printf("Unexpected end of UDMF map found\n");
|
||||
return lump;
|
||||
}
|
||||
ww = lump;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char *maplumps[] = { "THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS", "SSECTORS", "NODES", "SECTORS", "REJECT", "BLOCKMAP", "BEHAVIOR", "SCRIPTS" };
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
if (ww.Name() != NULL && !stricmp(ww.Name(), maplumps[i]))
|
||||
{
|
||||
CWADLump lmp;
|
||||
lmp.offset = ftell(f);
|
||||
strncpy(lmp.name, ww.Name(), 8);
|
||||
if ((options & DO_STRIP) && (i == 4 || i == 5 || i == 6 || i == 8 || i == 9))
|
||||
{
|
||||
lmp.length = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lmp.length = ww.Length();
|
||||
fwrite(ww.Address(), 1, ww.Length(), f);
|
||||
}
|
||||
directory.Push(lmp);
|
||||
ww = ww.mLump + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
finalize:
|
||||
uint32_t lumpc = directory.Size();
|
||||
uint32_t dpos = ftell(f);
|
||||
for (auto &p : directory)
|
||||
{
|
||||
fwrite(&p, 1, 16, f);
|
||||
}
|
||||
fseek(f, 4, 0);
|
||||
fwrite(&lumpc, 1, 4, f);
|
||||
fwrite(&dpos, 1, 4, f);
|
||||
fclose(f);
|
||||
chdir("..");
|
||||
return directory.Size();
|
||||
}
|
||||
|
||||
|
||||
typedef char pname[8];
|
||||
|
||||
bool AddWallTexture(FILE * fo,maptexture_t * wt,pname * pNames, bool first)
|
||||
{
|
||||
int k;
|
||||
char buffer[9];
|
||||
|
||||
sprintf(buffer,"%.8s",wt->name);
|
||||
strupr(buffer);
|
||||
bool cc = strspn(buffer, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789") < strlen(buffer) || *buffer <= '9';
|
||||
fprintf(fo,"WallTexture %s%s%s, %d, %d\n{\n",cc? "\"":"", buffer,cc? "\"":"", wt->width,wt->height);
|
||||
if (wt->ScaleX) fprintf(fo,"\tXScale %f\n",wt->ScaleX/8.0f);
|
||||
if (wt->ScaleY) fprintf(fo,"\tYScale %f\n",wt->ScaleY/8.0f);
|
||||
if (wt->Flags&0x8000) fprintf(fo,"\tWorldPanning\n");
|
||||
if (first) fprintf(fo,"\tNullTexture\n");
|
||||
for(k=0;k<wt->patchcount;k++)
|
||||
{
|
||||
sprintf(buffer,"%.8s",pNames[wt->patches[k].patch]);
|
||||
strupr(buffer);
|
||||
cc = strspn(buffer, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789") < strlen(buffer) || *buffer <= '9';
|
||||
fprintf(fo,"\tPatch %s%.8s%s, %d, %d\n",cc? "\"":"", buffer,cc? "\"":"", wt->patches[k].originx,wt->patches[k].originy);
|
||||
}
|
||||
fprintf(fo,"}\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddWallTexture(FILE * fo,strifemaptexture_t * wt,pname * pNames, bool first)
|
||||
{
|
||||
int k;
|
||||
char buffer[9];
|
||||
|
||||
sprintf(buffer,"%.8s",wt->name);
|
||||
strupr(buffer);
|
||||
bool cc = strspn(buffer, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789") < strlen(buffer) || *buffer <= '9';
|
||||
fprintf(fo,"WallTexture %s%s%s, %d, %d\n{\n",cc? "\"":"", buffer,cc? "\"":"", wt->width,wt->height);
|
||||
if (wt->ScaleX) fprintf(fo,"\tXScale %f\n",wt->ScaleX/8.0f);
|
||||
if (wt->ScaleY) fprintf(fo,"\tYScale %f\n",wt->ScaleY/8.0f);
|
||||
if (wt->Flags&0x8000) fprintf(fo,"\tWorldPanning\n");
|
||||
for(k=0;k<wt->patchcount;k++)
|
||||
{
|
||||
sprintf(buffer,"%.8s",pNames[wt->patches[k].patch]);
|
||||
strupr(buffer);
|
||||
cc = strspn(buffer, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789") < strlen(buffer) || *buffer <= '9';
|
||||
fprintf(fo,"\tPatch %s%.8s%s, %d, %d\n",cc? "\"":"", buffer,cc? "\"":"", wt->patches[k].originx,wt->patches[k].originy);
|
||||
}
|
||||
fprintf(fo,"}\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimExtract(WadItemList *w)
|
||||
{
|
||||
int i,numentries;
|
||||
char * c;
|
||||
char buffer[30];
|
||||
|
||||
mkdir("decompiled");
|
||||
chdir("decompiled");
|
||||
|
||||
strcpy(buffer,"animdefs.animated");
|
||||
printf("processing %s\n",buffer);
|
||||
|
||||
numentries=w->Length()/23;
|
||||
|
||||
c=(char*)w->Address();
|
||||
|
||||
FILE * fo=fopen(buffer,"wt");
|
||||
for(i=0;i<numentries;i++)
|
||||
{
|
||||
fprintf(fo,"%s %s Range %s Tics %d\n", *c? "Texture":"Flat",c+10, c+1,*(int*)(c+19));
|
||||
c+=23;
|
||||
}
|
||||
|
||||
fclose(fo);
|
||||
chdir(maindir);
|
||||
}
|
||||
|
||||
void SwitchExtract(WadItemList *w)
|
||||
{
|
||||
int i,numentries;
|
||||
char * c;
|
||||
char buffer[30];
|
||||
|
||||
mkdir("decompiled");
|
||||
chdir("decompiled");
|
||||
|
||||
|
||||
strcpy(buffer, "animdefs.switches");
|
||||
printf("processing %s\n",buffer);
|
||||
|
||||
numentries=w->Length()/20;
|
||||
|
||||
c=(char*)w->Address();
|
||||
|
||||
FILE * fo=fopen(buffer,"wt");
|
||||
for(i=0;i<numentries;i++)
|
||||
{
|
||||
if (*(short*)(c+18)==0) break;
|
||||
//fprintf(fo,"%s,%s,%d\n",c,c+9,*(short*)(c+18));
|
||||
fprintf(fo,"Switch %s on pic %s tics 0\n", c, c+9);
|
||||
c+=20;
|
||||
}
|
||||
|
||||
fclose(fo);
|
||||
chdir(maindir);
|
||||
//Extract(w, dir);
|
||||
}
|
||||
|
||||
|
||||
void GenerateTextureFile(const char *name, const char * pTex,const char * pPNam, int options, bool nullfirst)
|
||||
{
|
||||
const char * tr=pTex;
|
||||
int tc =*(int*)tr;
|
||||
int * to =(int*)(tr+4);
|
||||
pname * pr=(pname*)((char*)pPNam+4);
|
||||
|
||||
|
||||
FILE * fo=fopen(name,"wt");
|
||||
|
||||
// Todo: Be more thorough than this!
|
||||
if (!(options&DO_STRIFE))
|
||||
{
|
||||
for(int i=0;i<tc;i++)
|
||||
AddWallTexture(fo, (maptexture_t*)(tr+to[i]),pr, i == 0 && nullfirst);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<tc;i++)
|
||||
AddWallTexture(fo, (strifemaptexture_t*)((char*)tr+to[i]),pr, i == 0 && nullfirst);
|
||||
}
|
||||
|
||||
fclose(fo);
|
||||
}
|
||||
|
||||
void GenerateTextureFile(WadItemList * pTex,WadItemList * pPNam, int options)
|
||||
{
|
||||
char buffer[40];
|
||||
mkdir("decompiled");
|
||||
sprintf(buffer,"decompiled\\textures.%c", pTex->Name()[7]);
|
||||
bool nulltex = !strnicmp(pTex->Name(), "TEXTURE1", 8);
|
||||
GenerateTextureFile(buffer, (const char*)pTex->Address(), (const char *)pPNam->Address(), options, nulltex);
|
||||
}
|
||||
|
||||
void ExtractWad(char * wadfilename,int options)
|
||||
{
|
||||
WadItemList pTex1(-1), pTex2(-1), pPnam(-1);
|
||||
|
||||
OpenMainWad(wadfilename);
|
||||
|
||||
PNames = mainwad->FindLump("PNAMES");
|
||||
getcwd(maindir, 128);
|
||||
for(int i=0;i<mainwad->NumLumps();i++)
|
||||
{
|
||||
WadItemList ww(i);
|
||||
WadItemList *w = &ww;
|
||||
{
|
||||
if (!strcmp(w->Name(),"."))
|
||||
{
|
||||
w->Release();
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"S_START",8) || !strnicmp(w->Name(),"SS_START",8) )
|
||||
{
|
||||
i=ListExtract(i,"SPRITES","S_END","SS_END",false,options,false);
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"F_START",8) || !strnicmp(w->Name(),"FF_START",8) )
|
||||
{
|
||||
i=ListExtract(i,"FLATS","F_END","FF_END",true,options,false);
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"C_START",8))
|
||||
{
|
||||
i=ListExtract(i,"COLORMAPS","C_END","CC_END",false,false,options);
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"A_START",8))
|
||||
{
|
||||
i=ListExtract(i,"ACS","A_END","AA_END",false,false,options);
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"P_START",8) || !strnicmp(w->Name(),"PP_START",8))
|
||||
{
|
||||
pstartfound=true;
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"P_END",8) || !strnicmp(w->Name(),"PP_END",8)) // ignore
|
||||
{
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"TX_START",8))
|
||||
{
|
||||
i=ListExtract(i,"TEXTURES","TX_END","TX_END",false,options);
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"HI_START",8))
|
||||
{
|
||||
i=ListExtract(i,"HIRES","HI_END","HI_END",false,options);
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"VX_START",8))
|
||||
{
|
||||
i=ListExtract(i,"VOXELS","VX_END","VX_END",false,false,options);
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"GL_VERT",8)) // ignore
|
||||
{
|
||||
// skip GL nodes
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"GL_SEGS",8)) // ignore
|
||||
{
|
||||
// skip GL nodes
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"GL_SSECT",8)) // ignore
|
||||
{
|
||||
// skip GL nodes
|
||||
}
|
||||
else if (!strnicmp(w->Name(),"GL_NODES",8)) // ignore
|
||||
{
|
||||
// skip GL nodes
|
||||
}
|
||||
else if (!strnicmp(w->Name(), "GL_PVS", 8)) // ignore
|
||||
{
|
||||
// skip GL nodes
|
||||
}
|
||||
else if (isLevel(i))
|
||||
{
|
||||
i += MapExtract(i,"MAPS",options) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strnicmp(w->Name(), "TEXTURE1", 8)) pTex1 = *w;
|
||||
else if (!strnicmp(w->Name(), "TEXTURE2", 8)) pTex2 = *w;
|
||||
else if (!strnicmp(w->Name(), "PNAMES", 8)) pPnam = *w;
|
||||
else if (!strnicmp(w->Name(), "ANIMATED", 8))
|
||||
{
|
||||
AnimExtract(w);
|
||||
}
|
||||
else if (!strnicmp(w->Name(), "SWITCHES", 8))
|
||||
{
|
||||
SwitchExtract(w);
|
||||
}
|
||||
|
||||
Extract(w, NULL, NULL, options, false);
|
||||
}
|
||||
|
||||
if (pTex1.mLump >= 0 && pPnam.mLump >= 0)
|
||||
{
|
||||
GenerateTextureFile(&pTex1,&pPnam, options);
|
||||
pTex1 = -1;
|
||||
}
|
||||
if (pTex2.mLump >= 0 && pPnam.mLump >= 0)
|
||||
{
|
||||
GenerateTextureFile(&pTex2,&pPnam, options);
|
||||
pTex2=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertTextureX()
|
||||
{
|
||||
FILE *ft1 = fopen("texture1", "rb");
|
||||
if (!ft1) ft1 = fopen("texture1.lmp", "rb");
|
||||
|
||||
FILE *ft2 = fopen("texture2", "rb");
|
||||
if (!ft2) ft2 = fopen("texture2.lmp", "rb");
|
||||
|
||||
FILE *pnm = fopen("pnames", "rb");
|
||||
if (!pnm) pnm = fopen("pnames.lmp", "rb");
|
||||
|
||||
if (!pnm) exit(1);
|
||||
|
||||
static char bt1[100000], bt2[100000], bpn[100000];
|
||||
|
||||
if (ft1) fread(bt1, 1, 100000, ft1), fclose(ft1);
|
||||
if (ft2) fread(bt2, 1, 100000, ft2), fclose(ft2);
|
||||
if (pnm) fread(bpn, 1, 100000, pnm), fclose(pnm);
|
||||
|
||||
if (ft1) GenerateTextureFile("textures.txt", bt1, bpn, 0, true);
|
||||
if (ft2) GenerateTextureFile("textures.txt2", bt2, bpn, 0, false);
|
||||
}
|
||||
|
82
wadext.h
Normal file
82
wadext.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
enum ExtractOpt
|
||||
{
|
||||
NO_CONVERT_GFX=1,
|
||||
DO_HERETIC_PAL=2,
|
||||
DO_HEXEN_PAL=4,
|
||||
DO_STRIFE=8,
|
||||
DO_STRIP=16, // strip map lumps ZDoom does not need (nodes, blockmap, reject)
|
||||
NO_CONVERT_SND = 32,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Texture definition
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Each texture is composed of one or more patches, with patches being lumps
|
||||
// stored in the WAD. The lumps are referenced by number, and patched into
|
||||
// the rectangular texture space using origin and possibly other attributes.
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
short originx;
|
||||
short originy;
|
||||
short patch;
|
||||
short stepdir;
|
||||
short colormap;
|
||||
} mappatch_t;
|
||||
|
||||
//
|
||||
// A wall texture is a list of patches which are to be combined in a
|
||||
// predefined order.
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
char name[8];
|
||||
uint16_t Flags; // [RH] Was unused
|
||||
uint8_t ScaleX; // [RH] Scaling (8 is normal)
|
||||
uint8_t ScaleY; // [RH] Same as above
|
||||
short width;
|
||||
short height;
|
||||
uint8_t columndirectory[4]; // OBSOLETE
|
||||
short patchcount;
|
||||
mappatch_t patches[1];
|
||||
} maptexture_t;
|
||||
|
||||
#define MAPTEXF_WORLDPANNING 0x8000
|
||||
|
||||
// [RH] Just for documentation purposes, here's what I think the
|
||||
// Strife versions of the above two structures are:
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short originx;
|
||||
short originy;
|
||||
short patch;
|
||||
} strifemappatch_t;
|
||||
|
||||
//
|
||||
// A wall texture is a list of patches which are to be combined in a
|
||||
// predefined order.
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
char name[8];
|
||||
uint16_t Flags; // [RH] Was nused
|
||||
uint8_t ScaleX; // [RH] Scaling (8 is normal)
|
||||
uint8_t ScaleY; // [RH] Same as above
|
||||
short width;
|
||||
short height;
|
||||
short patchcount;
|
||||
strifemappatch_t patches[1];
|
||||
} strifemaptexture_t;
|
||||
|
189
wadfile.cpp
Normal file
189
wadfile.cpp
Normal file
|
@ -0,0 +1,189 @@
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright(C) 2005-2016 Christoph Oelckers
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "ResourceFile.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CWADFile::CWADFile(const char * filename)
|
||||
{
|
||||
char type[4];
|
||||
int diroffset;
|
||||
int numlumps;
|
||||
|
||||
m_NumLumps=0;
|
||||
m_LumpStart=0;
|
||||
|
||||
m_Filename = strdup(filename);
|
||||
m_File=NULL;
|
||||
|
||||
if (filename == NULL)
|
||||
{
|
||||
printf("No file name specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (!f)
|
||||
{
|
||||
printf("%s: unable to open\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
m_File = f;
|
||||
fread(&type, 1, 4, f);
|
||||
|
||||
if (memcmp(type, "IWAD", 4) && memcmp(type, "PWAD", 4))
|
||||
{
|
||||
printf("%s: not a WAD file\n", filename);
|
||||
return;
|
||||
}
|
||||
fread(&numlumps, 4, 1, f);
|
||||
fread(&diroffset, 4, 1, f);
|
||||
m_NumLumps = numlumps;
|
||||
|
||||
fseek(f, diroffset, SEEK_SET);
|
||||
|
||||
CWADLump lump;
|
||||
|
||||
for (int i = 0; i < numlumps; i++)
|
||||
{
|
||||
fread(&lump.offset, 4, 1, f);
|
||||
fread(&lump.length, 4, 1, f);
|
||||
fread(lump.name, 1, 8, f);
|
||||
lump.name[8]=0;
|
||||
|
||||
lumps.Push(lump);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CWADFile::~CWADFile(void)
|
||||
{
|
||||
if (m_File) fclose(m_File);
|
||||
if (m_Filename!=NULL) free(m_Filename);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int CWADFile::FindLump(const char * name)
|
||||
{
|
||||
for (int i = lumps.Size()-1; i>=0; i--)
|
||||
{
|
||||
if (!stricmp(name, lumps[i].name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int CWADFile::GetLumpSize(int lump)
|
||||
{
|
||||
if ((unsigned)lump < lumps.Size() ) return lumps[lump].length;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void * CWADFile::ReadLump(int lump)
|
||||
{
|
||||
if ((unsigned)lump < lumps.Size() )
|
||||
{
|
||||
void * Ptr= malloc(lumps[lump].length);
|
||||
ReadLump(lump, Ptr);
|
||||
return Ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void CWADFile::ReadLump(int lump, void * Ptr)
|
||||
{
|
||||
if ((unsigned)lump < lumps.Size() )
|
||||
{
|
||||
fseek(m_File, lumps[lump].offset, SEEK_SET);
|
||||
fread(Ptr, 1, lumps[lump].length, m_File);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const char * CWADFile::GetLumpName(int lump)
|
||||
{
|
||||
if ((unsigned)lump < lumps.Size() )
|
||||
{
|
||||
return lumps[lump].name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
CWADFile *mainwad;
|
||||
|
||||
void OpenMainWad(char *filename)
|
||||
{
|
||||
mainwad = new CWADFile(filename);
|
||||
if (mainwad->NumLumps() == 0)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
}
|
248
wadman.h
Normal file
248
wadman.h
Normal file
|
@ -0,0 +1,248 @@
|
|||
|
||||
#pragma pack(1)
|
||||
#pragma warning(disable:4200)
|
||||
|
||||
#include "ResourceFile.h"
|
||||
|
||||
extern CWADFile *mainwad;
|
||||
|
||||
struct CVertex
|
||||
{
|
||||
short x;
|
||||
short y;
|
||||
};
|
||||
|
||||
|
||||
struct CThing
|
||||
{
|
||||
short xpos; /* x position */
|
||||
short ypos; /* y position */
|
||||
short angle; /* facing angle */
|
||||
short type; /* thing type */
|
||||
short when; /* appears when? */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
this data structure contains the information about the LINEDEFS
|
||||
*/
|
||||
struct CLineDef
|
||||
{
|
||||
unsigned short start; /* from this vertex ... */
|
||||
unsigned short end; /* ... to this vertex */
|
||||
short flags; /* see NAMES.C for more info */
|
||||
short type; /* see NAMES.C for more info */
|
||||
short tag; /* crossing this linedef activates the sector wi*/
|
||||
short sidedef1; /* sidedef */
|
||||
short sidedef2; /* only if this line adjoins 2 sectors */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
this data structure contains the information about the SIDEDEFS
|
||||
*/
|
||||
struct CSideDef
|
||||
{
|
||||
short xoff; /* X offset for texture */
|
||||
short yoff; /* Y offset for texture */
|
||||
char texUpper[8]; /* texture name for the part above */
|
||||
char texLower[8]; /* texture name for the part below */
|
||||
char texNormal[8]; /* texture name for the regular part */
|
||||
short sector; /* adjacent sector */
|
||||
};
|
||||
|
||||
|
||||
struct CSector
|
||||
{
|
||||
short floorh;
|
||||
short ceilh;
|
||||
char floort[8];
|
||||
char ceilt[8];
|
||||
short light;
|
||||
short special;
|
||||
short tag;
|
||||
};
|
||||
|
||||
|
||||
struct CWadFileHeader
|
||||
{
|
||||
char id[4];
|
||||
long numEntries;
|
||||
long DirOffset;
|
||||
};
|
||||
|
||||
struct CWadFileEntry
|
||||
{
|
||||
long FileOffset;
|
||||
long EntryLength;
|
||||
char name[8];
|
||||
};
|
||||
|
||||
struct CWad3FileEntry
|
||||
{
|
||||
long FileOffset;
|
||||
long EntryLength;
|
||||
long EntryLength2;
|
||||
long type;
|
||||
char name[16];
|
||||
};
|
||||
|
||||
struct WadItemList;
|
||||
|
||||
struct CLevelInfo
|
||||
{
|
||||
CThing * pThings;
|
||||
CLineDef * pLineDefs;
|
||||
CSideDef * pSideDefs;
|
||||
CVertex * pVertexes;
|
||||
CSector * pSectors;
|
||||
|
||||
char * pNodes;
|
||||
char * pSegs;
|
||||
char * pSSector;
|
||||
|
||||
char * pBlockmap;
|
||||
char * pReject;
|
||||
|
||||
char * pBehavior;
|
||||
char * pScript;
|
||||
|
||||
int nThings;
|
||||
int nLineDefs;
|
||||
int nSideDefs;
|
||||
int nVertexes;
|
||||
int nSectors;
|
||||
|
||||
int nNodes;
|
||||
int nSegs;
|
||||
int nSSectors;
|
||||
|
||||
int cReject;
|
||||
int cBlockmap;
|
||||
int cBehavior;
|
||||
int cScript;
|
||||
|
||||
char * pGLVerts;
|
||||
char * pGLSegs;
|
||||
char * pGLSSectors;
|
||||
char * pGLNodes;
|
||||
|
||||
int nGLVertexes;
|
||||
int nGLNodes;
|
||||
int nGLSegs;
|
||||
int nGLSSectors;
|
||||
|
||||
int NameTag;
|
||||
|
||||
CLevelInfo()
|
||||
{
|
||||
NameTag=0;
|
||||
}
|
||||
|
||||
void Release();
|
||||
|
||||
~CLevelInfo()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
bool HasBehavior()
|
||||
{
|
||||
return pBehavior!=NULL;
|
||||
}
|
||||
bool HasScript()
|
||||
{
|
||||
return pBehavior!=NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
struct WadInfo
|
||||
{
|
||||
HANDLE hFile;
|
||||
HANDLE hMapping;
|
||||
CWadFileHeader * pwAddr;
|
||||
union
|
||||
{
|
||||
CWadFileEntry * pwDir;
|
||||
CWad3FileEntry * pw3Dir;
|
||||
};
|
||||
int wtype;
|
||||
char filename[256];
|
||||
};
|
||||
|
||||
|
||||
struct WadList
|
||||
{
|
||||
WadInfo * pwInfo;
|
||||
WadList * pNext;
|
||||
};
|
||||
|
||||
struct WadItemList
|
||||
{
|
||||
CWadFileEntry * pwInfo;
|
||||
int type;
|
||||
|
||||
WadInfo * pwWad;
|
||||
WadItemList * pSuccessor; // the overloaded entry
|
||||
WadItemList * pNext;
|
||||
|
||||
WadItemList * Next() { return pNext; }
|
||||
void* PackedAddress() const { return (void*)(((char*)pwWad->pwAddr)+pwInfo->FileOffset); }
|
||||
|
||||
bool isPacked() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char * Address()
|
||||
{
|
||||
return (char *)PackedAddress();
|
||||
}
|
||||
|
||||
int Length() const
|
||||
{
|
||||
return pwInfo->EntryLength;
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
}
|
||||
char * Name() const { return pwInfo->name; }
|
||||
char * WadFileName() { return pwWad->filename; }
|
||||
|
||||
WadItemList() { }
|
||||
~WadItemList() { }
|
||||
};
|
||||
*/
|
||||
|
||||
struct ImportInf
|
||||
{
|
||||
char name[9];
|
||||
int insX,insY;
|
||||
int transparentCol;
|
||||
};
|
||||
|
||||
//extern WadItemList * GlobalDirectory;
|
||||
|
||||
|
||||
|
||||
//void CloseWadFile(WadInfo * wi);
|
||||
void OpenMainWad(char * filename);
|
||||
void ClosePatchWad(const char * filename);
|
||||
void * GetWadItem(char * name,int * pLength);
|
||||
void FreeWadItem(char * name,char * blockstart=NULL);
|
||||
void NameError(char * level,char * section);
|
||||
bool GetLevelInfo(char * name,CLevelInfo * pLi);
|
||||
//int GetLevelFileInfo(char * fn,CLevelInfo * pli,WadInfo **pp=NULL);
|
||||
|
||||
|
||||
inline void CLevelInfo::Release()
|
||||
{
|
||||
NameTag=-1;
|
||||
}
|
||||
|
Loading…
Reference in a new issue