Initial commit.
This commit is contained in:
65
tools/pngtgaTool/TgaWiz.cpp
Normal file
65
tools/pngtgaTool/TgaWiz.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// TgaWiz.cpp : Defines the entry point for the console application.
|
||||
//
|
||||
#include <windows.h>
|
||||
#include <cstdio>
|
||||
#include "png.h"
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
void R_MipMap (byte *in, int width, int height, bool simple = true);
|
||||
void LoadTGA ( const char *name, byte **pic, int *width, int *height);
|
||||
void SaveTGA( byte *pic, int width, int height, char *fileName );
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned char *img;
|
||||
int w, h;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
printf("USAGE: %s infile outfile\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load the PNG file, make sure that we have an alpha channel in memory
|
||||
if (!LoadPNG32(argv[1], &img, &w, &h, NULL))
|
||||
{
|
||||
printf("ERROR: Couldn't load %s\n", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Save it out as TGA
|
||||
SaveTGA(img, w, h, argv[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
unsigned char *img;
|
||||
int w, h;
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
printf("USAGE: %s infile outfile N\n");
|
||||
printf(" N is largest allowed dimensions\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int maxSize = atoi(argv[3]);
|
||||
|
||||
// Load it
|
||||
LoadTGA(argv[1], &img, &w, &h);
|
||||
|
||||
while (w > maxSize || h > maxSize)
|
||||
{
|
||||
R_MipMap(img, w, h, true);
|
||||
w /= 2;
|
||||
h /= 2;
|
||||
}
|
||||
|
||||
SaveTGA(img, w, h, argv[2]);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
21
tools/pngtgaTool/TgaWiz.sln
Normal file
21
tools/pngtgaTool/TgaWiz.sln
Normal file
@@ -0,0 +1,21 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 7.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TgaWiz", "TgaWiz.vcproj", "{CF864863-5FC5-489B-BE7E-427F17921820}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
ConfigName.0 = Debug
|
||||
ConfigName.1 = Release
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectDependencies) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{CF864863-5FC5-489B-BE7E-427F17921820}.Debug.ActiveCfg = Debug|Win32
|
||||
{CF864863-5FC5-489B-BE7E-427F17921820}.Debug.Build.0 = Debug|Win32
|
||||
{CF864863-5FC5-489B-BE7E-427F17921820}.Release.ActiveCfg = Release|Win32
|
||||
{CF864863-5FC5-489B-BE7E-427F17921820}.Release.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
150
tools/pngtgaTool/TgaWiz.vcproj
Normal file
150
tools/pngtgaTool/TgaWiz.vcproj
Normal file
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding = "Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.00"
|
||||
Name="TgaWiz"
|
||||
ProjectGUID="{CF864863-5FC5-489B-BE7E-427F17921820}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/TgaWiz.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/TgaWiz.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="1"
|
||||
OmitFramePointers="TRUE"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
StringPooling="TRUE"
|
||||
RuntimeLibrary="4"
|
||||
EnableFunctionLevelLinking="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/TgaWiz.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
|
||||
<File
|
||||
RelativePath="TgaWiz.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="deflate.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="deflate.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="inflate.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="inflate.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="png.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="png.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="tga.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="zip.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="zipcommon.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc">
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="ReadMe.txt">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
0
tools/pngtgaTool/_console_skin_list_
Normal file
0
tools/pngtgaTool/_console_skin_list_
Normal file
0
tools/pngtgaTool/_console_str_list_
Normal file
0
tools/pngtgaTool/_console_str_list_
Normal file
2082
tools/pngtgaTool/deflate.cpp
Normal file
2082
tools/pngtgaTool/deflate.cpp
Normal file
File diff suppressed because it is too large
Load Diff
231
tools/pngtgaTool/deflate.h
Normal file
231
tools/pngtgaTool/deflate.h
Normal file
@@ -0,0 +1,231 @@
|
||||
// Stream status
|
||||
#define INIT_STATE 42
|
||||
#define BUSY_STATE 113
|
||||
#define FINISH_STATE 666
|
||||
|
||||
#define HASH_BITS 15
|
||||
#define HASH_SIZE (1 << HASH_BITS)
|
||||
#define HASH_MASK (HASH_SIZE - 1)
|
||||
|
||||
// Size of match buffer for literals/lengths. There are 4 reasons for
|
||||
// limiting lit_bufsize to 64K:
|
||||
// - frequencies can be kept in 16 bit counters
|
||||
// - if compression is not successful for the first block, all input
|
||||
// data is still in the window so we can still emit a stored block even
|
||||
// when input comes from standard input. (This can also be done for
|
||||
// all blocks if lit_bufsize is not greater than 32K.)
|
||||
// - if compression is not successful for a file smaller than 64K, we can
|
||||
// even emit a stored file instead of a stored block (saving 5 bytes).
|
||||
// This is applicable only for zip (not gzip or zlib).
|
||||
// - creating new Huffman trees less frequently may not provide fast
|
||||
// adaptation to changes in the input data statistics. (Take for
|
||||
// example a binary file with poorly compressible code followed by
|
||||
// a highly compressible string table.) Smaller buffer sizes give
|
||||
// fast adaptation but have of course the overhead of transmitting
|
||||
// trees more frequently.
|
||||
// - I can't count above 4
|
||||
#define LIT_BUFSIZE (1 << 14)
|
||||
|
||||
#define MAX_BLOCK_SIZE 0xffff
|
||||
|
||||
// Number of bits by which ins_h must be shifted at each input
|
||||
// step. It must be such that after MIN_MATCH steps, the oldest
|
||||
// byte no longer takes part in the hash key.
|
||||
#define HASH_SHIFT ((HASH_BITS + MIN_MATCH - 1) / MIN_MATCH)
|
||||
|
||||
// Matches of length 3 are discarded if their distance exceeds TOO_FAR
|
||||
#define TOO_FAR 32767
|
||||
|
||||
// Number of length codes, not counting the special END_BLOCK code
|
||||
#define LENGTH_CODES 29
|
||||
|
||||
// Number of codes used to transfer the bit lengths
|
||||
#define BL_CODES 19
|
||||
|
||||
// Number of literal bytes 0..255
|
||||
#define LITERALS 256
|
||||
|
||||
// Number of Literal or Length codes, including the END_BLOCK code
|
||||
#define L_CODES (LITERALS + 1 + LENGTH_CODES)
|
||||
|
||||
// See definition of array dist_code below
|
||||
#define DIST_CODE_LEN 512
|
||||
|
||||
// Maximum heap size
|
||||
#define HEAP_SIZE (2 * L_CODES + 1)
|
||||
|
||||
// Index within the heap array of least frequent node in the Huffman tree
|
||||
#define SMALLEST 1
|
||||
|
||||
// Bit length codes must not exceed MAX_BL_BITS bits
|
||||
#define MAX_BL_BITS 7
|
||||
|
||||
// End of block literal code
|
||||
#define END_BLOCK 256
|
||||
|
||||
// Repeat previous bit length 3-6 times (2 bits of repeat count)
|
||||
#define REP_3_6 16
|
||||
|
||||
// Repeat a zero length 3-10 times (3 bits of repeat count)
|
||||
#define REPZ_3_10 17
|
||||
|
||||
// Repeat a zero length 11-138 times (7 bits of repeat count)
|
||||
#define REPZ_11_138 18
|
||||
|
||||
// Number of bits used within bi_buf. (bi_buf might be implemented on
|
||||
// more than 16 bits on some systems.)
|
||||
#define BUF_SIZE (8 * 2)
|
||||
|
||||
// Minimum amount of lookahead, except at the end of the input file.
|
||||
// See deflate.c for comments about the MIN_MATCH+1.
|
||||
#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NEED_MORE, // block not completed, need more input or more output
|
||||
BLOCK_DONE, // block flush performed
|
||||
FINISH_STARTED, // finish started, need only more output at next deflate
|
||||
FINISH_DONE // finish done, accept no more input or output
|
||||
} block_state;
|
||||
|
||||
// Data structure describing a single value and its code string.
|
||||
typedef struct ct_data_s
|
||||
{
|
||||
union
|
||||
{
|
||||
word freq; // frequency count
|
||||
word code; // bit string
|
||||
} fc;
|
||||
union
|
||||
{
|
||||
word dad; // father node in Huffman tree
|
||||
word len; // length of bit string
|
||||
} dl;
|
||||
} ct_data;
|
||||
|
||||
typedef struct static_tree_desc_s
|
||||
{
|
||||
const ct_data *static_tree; // static tree or NULL
|
||||
const ulong *extra_bits; // extra bits for each code or NULL
|
||||
ulong extra_base; // base index for extra_bits
|
||||
ulong elems; // max number of elements in the tree
|
||||
ulong max_length; // max bit length for the codes
|
||||
} static_tree_desc;
|
||||
|
||||
typedef struct tree_desc_s
|
||||
{
|
||||
ct_data *dyn_tree; // the dynamic tree
|
||||
ulong max_code; // largest code with non zero frequency
|
||||
static_tree_desc *stat_desc; // the corresponding static tree
|
||||
} tree_desc;
|
||||
|
||||
// Main structure which the deflate algorithm works from
|
||||
typedef struct deflate_state_s
|
||||
{
|
||||
z_stream *z; // pointer back to this zlib stream
|
||||
ulong status; // as the name implies
|
||||
|
||||
EFlush last_flush; // value of flush param for previous deflate call
|
||||
int noheader; // suppress zlib header and adler32
|
||||
|
||||
byte pending_buf[MAX_BLOCK_SIZE + 5];// output still pending
|
||||
byte *pending_out; // next pending byte to output to the stream
|
||||
ulong pending; // nb of bytes in the pending buffer
|
||||
|
||||
// Sliding window. Input bytes are read into the second half of the window,
|
||||
// and move to the first half later to keep a dictionary of at least wSize
|
||||
// bytes. With this organization, matches are limited to a distance of
|
||||
// wSize-MAX_MATCH bytes, but this ensures that IO is always
|
||||
// performed with a length multiple of the block size. Also, it limits
|
||||
// the window size to 64K, which is quite useful on MSDOS.
|
||||
// To do: use the user input buffer as sliding window.
|
||||
byte window[WINDOW_SIZE * 2];
|
||||
|
||||
// Link to older string with same hash index. To limit the size of this
|
||||
// array to 64K, this link is maintained only for the last 32K strings.
|
||||
// An index in this array is thus a window index modulo 32K.
|
||||
word prev[WINDOW_SIZE];
|
||||
|
||||
word head[HASH_SIZE]; // Heads of the hash chains or NULL.
|
||||
|
||||
ulong ins_h; // hash index of string to be inserted
|
||||
|
||||
// Window position at the beginning of the current output block. Gets
|
||||
// negative when the window is moved backwards.
|
||||
int block_start;
|
||||
|
||||
ulong match_length; // length of best match
|
||||
ulong prev_match; // previous match
|
||||
ulong match_available; // set if previous match exists
|
||||
ulong strstart; // start of string to insert
|
||||
ulong match_start; // start of matching string
|
||||
ulong lookahead; // number of valid bytes ahead in window
|
||||
|
||||
// Length of the best match at previous step. Matches not greater than this
|
||||
// are discarded. This is used in the lazy match evaluation.
|
||||
ulong prev_length;
|
||||
|
||||
// Attempt to find a better match only when the current match is strictly
|
||||
// smaller than this value. This mechanism is used only for compression levels >= 4.
|
||||
ulong max_lazy_match;
|
||||
|
||||
ulong good_match; // Use a faster search when the previous match is longer than this
|
||||
ulong nice_match; // Stop searching when current match exceeds this
|
||||
|
||||
// To speed up deflation, hash chains are never searched beyond this
|
||||
// length. A higher limit improves compression ratio but degrades the speed.
|
||||
ulong max_chain_length;
|
||||
|
||||
ELevel level; // compression level (0..9)
|
||||
|
||||
ct_data dyn_ltree[HEAP_SIZE]; // literal and length tree
|
||||
ct_data dyn_dtree[(2 * D_CODES) + 1]; // distance tree
|
||||
ct_data bl_tree[(2 * BL_CODES) + 1]; // Huffman tree for bit lengths
|
||||
|
||||
tree_desc l_desc; // desc. for literal tree
|
||||
tree_desc d_desc; // desc. for distance tree
|
||||
tree_desc bl_desc; // desc. for bit length tree
|
||||
|
||||
word bl_count[MAX_WBITS + 1]; // number of codes at each bit length for an optimal tree
|
||||
|
||||
// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
|
||||
// The same heap array is used to build all trees.
|
||||
ulong heap[(2 * L_CODES) + 1]; // heap used to build the Huffman trees
|
||||
ulong heap_len; // number of elements in the heap
|
||||
ulong heap_max; // element of largest frequency
|
||||
|
||||
byte depth[(2 * L_CODES) + 1]; // Depth of each subtree used as tie breaker for trees of equal frequency
|
||||
|
||||
byte l_buf[LIT_BUFSIZE]; // buffer for literals or lengths
|
||||
|
||||
ulong last_lit; // running index in l_buf
|
||||
|
||||
// Buffer for distances. To simplify the code, d_buf and l_buf have
|
||||
// the same number of elements. To use different lengths, an extra flag
|
||||
// array would be necessary.
|
||||
word d_buf[LIT_BUFSIZE];
|
||||
|
||||
ulong opt_len; // bit length of current block with optimal trees
|
||||
ulong static_len; // bit length of current block with static trees
|
||||
ulong matches; // number of string matches in current block
|
||||
ulong last_eob_len; // bit length of EOB code for last block
|
||||
|
||||
word bi_buf; // Output buffer. bits are inserted starting at the bottom (least significant bits).
|
||||
ulong bi_valid; // Number of valid bits in bi_buf. All bits above the last valid bit are always zero.
|
||||
|
||||
ulong adler;
|
||||
} deflate_state;
|
||||
|
||||
// Compression function. Returns the block state after the call.
|
||||
typedef block_state (*compress_func) (deflate_state *s, EFlush flush);
|
||||
|
||||
typedef struct config_s
|
||||
{
|
||||
word good_length; // reduce lazy search above this match length
|
||||
word max_lazy; // do not perform lazy search above this match length
|
||||
word nice_length; // quit search above this match length
|
||||
word max_chain;
|
||||
compress_func func;
|
||||
} config;
|
||||
|
||||
// end
|
||||
1843
tools/pngtgaTool/inflate.cpp
Normal file
1843
tools/pngtgaTool/inflate.cpp
Normal file
File diff suppressed because it is too large
Load Diff
145
tools/pngtgaTool/inflate.h
Normal file
145
tools/pngtgaTool/inflate.h
Normal file
@@ -0,0 +1,145 @@
|
||||
// Maximum size of dynamic tree. The maximum found in a long but non-
|
||||
// exhaustive search was 1004 huft structures (850 for length/literals
|
||||
// and 154 for distances, the latter actually the result of an
|
||||
// exhaustive search). The actual maximum is not known, but the
|
||||
// value below is more than safe.
|
||||
|
||||
#define MANY 1440
|
||||
|
||||
// maximum bit length of any code (if BMAX needs to be larger than 16, then h and x[] should be ulong.)
|
||||
#define BMAX 15
|
||||
|
||||
typedef ulong (*check_func) (ulong check, const byte *buf, ulong len);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TYPE, // get type bits (3, including end bit)
|
||||
LENS, // get lengths for stored
|
||||
STORED, // processing stored block
|
||||
TABLE, // get table lengths
|
||||
BTREE, // get bit lengths tree for a dynamic block
|
||||
DTREE, // get length, distance trees for a dynamic block
|
||||
CODES, // processing fixed or dynamic block
|
||||
DRY, // output remaining window bytes
|
||||
DONE, // finished last block, done
|
||||
BAD // got a data error--stuck here
|
||||
} inflate_block_mode;
|
||||
|
||||
// waiting for "i:"=input, "o:"=output, "x:"=nothing
|
||||
typedef enum
|
||||
{
|
||||
START, // x: set up for LEN
|
||||
LEN, // i: get length/literal/eob next
|
||||
LENEXT, // i: getting length extra (have base)
|
||||
DIST, // i: get distance next
|
||||
DISTEXT, // i: getting distance extra
|
||||
COPY, // o: copying bytes in window, waiting for space
|
||||
LIT, // o: got literal, waiting for output space
|
||||
WASH, // o: got eob, possibly still output waiting
|
||||
END, // x: got eob and all data flushed
|
||||
BADCODE // x: got error
|
||||
} inflate_codes_mode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
imMETHOD, // waiting for method byte
|
||||
imFLAG, // waiting for flag byte
|
||||
imBLOCKS, // decompressing blocks
|
||||
imCHECK4, // four check bytes to go
|
||||
imCHECK3, // three check bytes to go
|
||||
imCHECK2, // two check bytes to go
|
||||
imCHECK1, // one check byte to go
|
||||
imDONE, // finished check, done
|
||||
imBAD // got an error--stay here
|
||||
} inflate_mode;
|
||||
|
||||
typedef struct inflate_huft_s
|
||||
{
|
||||
byte Exop; // number of extra bits or operation
|
||||
byte Bits; // number of bits in this code or subcode
|
||||
ulong base; // literal, length base, distance base, or table offset
|
||||
} inflate_huft_t;
|
||||
|
||||
// inflate codes private state
|
||||
typedef struct inflate_codes_state_s
|
||||
{
|
||||
inflate_codes_mode mode; // current inflate_codes mode
|
||||
|
||||
// mode dependent information
|
||||
ulong len;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
inflate_huft_t *tree; // pointer into tree
|
||||
ulong need; // bits needed
|
||||
} code; // if LEN or DIST, where in tree
|
||||
ulong lit; // if LIT, literal
|
||||
struct
|
||||
{
|
||||
ulong get; // bits to get for extra
|
||||
ulong dist; // distance back to copy from
|
||||
} copy; // if EXT or COPY, where and how much
|
||||
}; // submode
|
||||
|
||||
// mode independent information
|
||||
byte lbits; // ltree bits decoded per branch
|
||||
byte dbits; // dtree bits decoder per branch
|
||||
inflate_huft_t *ltree; // literal/length/eob tree
|
||||
inflate_huft_t *dtree; // distance tree
|
||||
} inflate_codes_state_t;
|
||||
|
||||
// inflate blocks semi-private state
|
||||
typedef struct inflate_blocks_state_s
|
||||
{
|
||||
// mode
|
||||
inflate_block_mode mode; // current inflate_block mode
|
||||
|
||||
// mode dependent information
|
||||
union
|
||||
{
|
||||
ulong left; // if STORED, bytes left to copy
|
||||
struct
|
||||
{
|
||||
ulong table; // table lengths (14 bits)
|
||||
ulong index; // index into blens (or border)
|
||||
ulong *blens; // bit lengths of codes
|
||||
ulong bb; // bit length tree depth
|
||||
inflate_huft_t *tb; // bit length decoding tree
|
||||
} trees; // if DTREE, decoding info for trees
|
||||
struct
|
||||
{
|
||||
inflate_codes_state_t *codes;
|
||||
} decode; // if CODES, current state
|
||||
}; // submode
|
||||
bool last; // true if this block is the last block
|
||||
|
||||
// mode independent information
|
||||
ulong bitk; // bits in bit buffer
|
||||
ulong bitb; // bit buffer
|
||||
inflate_huft_t *hufts; // single malloc for tree space
|
||||
byte window[WINDOW_SIZE]; // sliding window
|
||||
byte *end; // one byte after sliding window
|
||||
byte *read; // window read pointer
|
||||
byte *write; // window write pointer
|
||||
ulong check; // check on output
|
||||
} inflate_blocks_state_t;
|
||||
|
||||
// inflate private state
|
||||
typedef struct inflate_state_s
|
||||
{
|
||||
inflate_mode mode; // current inflate mode
|
||||
|
||||
ulong method; // if FLAGS, method byte
|
||||
|
||||
// mode independent information
|
||||
int nowrap; // flag for no wrapper
|
||||
ulong wbits; // log2(window size) (8..15, defaults to 15)
|
||||
inflate_blocks_state_t *blocks; // current inflate_blocks state
|
||||
|
||||
ulong adler;
|
||||
ulong calcadler;
|
||||
} inflate_state;
|
||||
|
||||
|
||||
// end
|
||||
822
tools/pngtgaTool/png.cpp
Normal file
822
tools/pngtgaTool/png.cpp
Normal file
@@ -0,0 +1,822 @@
|
||||
// Generic PNG file loading code
|
||||
|
||||
// leave this as first line for PCH reasons...
|
||||
//
|
||||
//#include "../game/q_shared.h"
|
||||
//#include "../qcommon/qcommon.h"
|
||||
|
||||
#include "zip.h"
|
||||
#include "png.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
//#include "../qcommon/memory.h"
|
||||
|
||||
static int BigLong(int l)
|
||||
{
|
||||
byte b1,b2,b3,b4;
|
||||
|
||||
b1 = l&255;
|
||||
b2 = (l>>8)&255;
|
||||
b3 = (l>>16)&255;
|
||||
b4 = (l>>24)&255;
|
||||
|
||||
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
|
||||
}
|
||||
|
||||
// Error returns
|
||||
|
||||
#define PNG_ERROR_OK 0
|
||||
#define PNG_ERROR_DECOMP 1
|
||||
#define PNG_ERROR_COMP 2
|
||||
#define PNG_ERROR_MEMORY 3
|
||||
#define PNG_ERROR_NOSIG 4
|
||||
#define PNG_ERROR_TOO_SMALL 5
|
||||
#define PNG_ERROR_WNP2 6
|
||||
#define PNG_ERROR_HNP2 7
|
||||
#define PNG_ERROR_NOT_TC 8
|
||||
#define PNG_ERROR_INV_FIL 9
|
||||
#define PNG_ERROR_FAILED_CRC 10
|
||||
#define PNG_ERROR_CREATE_FAIL 11
|
||||
#define PNG_ERROR_WRITE 12
|
||||
#define PNG_ERROR_NOT_PALETTE 13
|
||||
#define PNG_ERROR_NOT8BIT 14
|
||||
#define PNG_ERROR_TOO_LARGE 15
|
||||
|
||||
static int png_error = PNG_ERROR_OK;
|
||||
|
||||
static const byte png_signature[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
|
||||
static const char png_copyright[] = "Copyright\0Raven Software Inc. 2001";
|
||||
static const char *png_errors[] =
|
||||
{
|
||||
"OK.",
|
||||
"Error decompressing image data.",
|
||||
"Error compressing image data.",
|
||||
"Error allocating memory.",
|
||||
"PNG signature not found.",
|
||||
"Image is too small to load.",
|
||||
"Width is not a power of two.",
|
||||
"Height is not a power of two.",
|
||||
"Image is not 24 or 32 bit.",
|
||||
"Invalid filter or compression type.",
|
||||
"Failed CRC check.",
|
||||
"Could not create file.",
|
||||
"Error writing to file.",
|
||||
"Image is not indexed colour.",
|
||||
"Image does not have 8 bits per sample.",
|
||||
"Image is too large",
|
||||
};
|
||||
|
||||
// Gets the error string for a failed PNG operation
|
||||
|
||||
const char *PNG_GetError(void)
|
||||
{
|
||||
return(png_errors[png_error]);
|
||||
}
|
||||
|
||||
// Create a header chunk
|
||||
|
||||
void PNG_CreateHeader(png_ihdr_t *header, int width, int height, int bytedepth)
|
||||
{
|
||||
header->width = BigLong(width);
|
||||
header->height = BigLong(height);
|
||||
header->bitdepth = 8;
|
||||
|
||||
if(bytedepth == 3)
|
||||
{
|
||||
header->colortype = 2;
|
||||
}
|
||||
if(bytedepth == 4)
|
||||
{
|
||||
header->colortype = 6;
|
||||
}
|
||||
header->compression = 0;
|
||||
header->filter = 0;
|
||||
header->interlace = 0;
|
||||
}
|
||||
|
||||
// Processes the header chunk and checks to see if all the data is valid
|
||||
|
||||
bool PNG_HandleIHDR(const byte *data, png_image_t *image)
|
||||
{
|
||||
png_ihdr_t *ihdr = (png_ihdr_t *)data;
|
||||
|
||||
image->width = BigLong(ihdr->width);
|
||||
image->height = BigLong(ihdr->height);
|
||||
|
||||
// Make sure image is a reasonable size
|
||||
if((image->width < 2) || (image->height < 2))
|
||||
{
|
||||
png_error = PNG_ERROR_TOO_SMALL;
|
||||
return(false);
|
||||
}
|
||||
if(image->width > MAX_PNG_WIDTH)
|
||||
{
|
||||
png_error = PNG_ERROR_TOO_LARGE;
|
||||
return(false);
|
||||
}
|
||||
if(ihdr->bitdepth != 8)
|
||||
{
|
||||
png_error = PNG_ERROR_NOT8BIT;
|
||||
return(false);
|
||||
}
|
||||
// Check for non power of two size (but not for data files)
|
||||
if(image->isimage)
|
||||
{
|
||||
if(image->width & (image->width - 1))
|
||||
{
|
||||
png_error = PNG_ERROR_WNP2;
|
||||
return(false);
|
||||
}
|
||||
if(image->height & (image->height - 1))
|
||||
{
|
||||
png_error = PNG_ERROR_HNP2;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
// Make sure we have a 24 or 32 bit image (for images)
|
||||
if(image->isimage)
|
||||
{
|
||||
if((ihdr->colortype != 2) && (ihdr->colortype != 6))
|
||||
{
|
||||
png_error = PNG_ERROR_NOT_TC;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
// Make sure we have an 8 bit grayscale image for data files
|
||||
if(!image->isimage)
|
||||
{
|
||||
if(ihdr->colortype && (ihdr->colortype != 3))
|
||||
{
|
||||
png_error = PNG_ERROR_NOT_PALETTE;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
// Make sure we aren't using any wacky compression or filter algos
|
||||
if(ihdr->compression || ihdr->filter)
|
||||
{
|
||||
png_error = PNG_ERROR_INV_FIL;
|
||||
return(false);
|
||||
}
|
||||
// Extract the data we need
|
||||
if(!ihdr->colortype || (ihdr->colortype == 3))
|
||||
{
|
||||
image->bytedepth = 1;
|
||||
}
|
||||
if(ihdr->colortype == 2)
|
||||
{
|
||||
image->bytedepth = 3;
|
||||
}
|
||||
if(ihdr->colortype == 6)
|
||||
{
|
||||
image->bytedepth = 4;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Filter a row of data
|
||||
|
||||
void PNG_Filter(byte *out, byte filter, const byte *in, const byte *lastline, ulong rowbytes, ulong bpp)
|
||||
{
|
||||
ulong i;
|
||||
|
||||
switch(filter)
|
||||
{
|
||||
case PNG_FILTER_VALUE_NONE:
|
||||
memcpy(out, in, rowbytes);
|
||||
break;
|
||||
case PNG_FILTER_VALUE_SUB:
|
||||
for(i = 0; i < bpp; i++)
|
||||
{
|
||||
*out++ = *in++;
|
||||
}
|
||||
for(i = bpp; i < rowbytes; i++)
|
||||
{
|
||||
*out++ = *in - *(in - bpp);
|
||||
in++;
|
||||
}
|
||||
break;
|
||||
case PNG_FILTER_VALUE_UP:
|
||||
for(i = 0; i < rowbytes; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out++ = *in++ - *lastline++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PNG_FILTER_VALUE_AVG:
|
||||
for(i = 0; i < bpp; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out++ = *in++ - (*lastline++ >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
for(i = bpp; i < rowbytes; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out++ = *in - ((*lastline++ + *(in - bpp)) >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out++ = *in - (*(in - bpp) >> 1);
|
||||
}
|
||||
in++;
|
||||
}
|
||||
break;
|
||||
case PNG_FILTER_VALUE_PAETH:
|
||||
int a, b, c;
|
||||
int pa, pb, pc, p;
|
||||
|
||||
for(i = 0; i < bpp; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out++ = *in++ - *lastline++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
for(i = bpp; i < rowbytes; i++)
|
||||
{
|
||||
a = *(in - bpp);
|
||||
c = 0;
|
||||
b = 0;
|
||||
if(lastline)
|
||||
{
|
||||
c = *(lastline - bpp);
|
||||
b = *lastline++;
|
||||
}
|
||||
|
||||
p = b - c;
|
||||
pc = a - c;
|
||||
|
||||
pa = p < 0 ? -p : p;
|
||||
pb = pc < 0 ? -pc : pc;
|
||||
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
|
||||
|
||||
p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
|
||||
|
||||
*out++ = *in++ - p;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Unfilters a row of data
|
||||
|
||||
void PNG_Unfilter(byte *out, byte filter, const byte *lastline, ulong rowbytes, ulong bpp)
|
||||
{
|
||||
ulong i;
|
||||
|
||||
switch(filter)
|
||||
{
|
||||
case PNG_FILTER_VALUE_NONE:
|
||||
break;
|
||||
case PNG_FILTER_VALUE_SUB:
|
||||
out += bpp;
|
||||
for(i = bpp; i < rowbytes; i++)
|
||||
{
|
||||
*out += *(out - bpp);
|
||||
out++;
|
||||
}
|
||||
break;
|
||||
case PNG_FILTER_VALUE_UP:
|
||||
for(i = 0; i < rowbytes; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out += *lastline++;
|
||||
}
|
||||
out++;
|
||||
}
|
||||
break;
|
||||
case PNG_FILTER_VALUE_AVG:
|
||||
for(i = 0; i < bpp; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out += *lastline++ >> 1;
|
||||
}
|
||||
out++;
|
||||
}
|
||||
for(i = bpp; i < rowbytes; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out += (*lastline++ + *(out - bpp)) >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out += *(out - bpp) >> 1;
|
||||
}
|
||||
out++;
|
||||
}
|
||||
break;
|
||||
case PNG_FILTER_VALUE_PAETH:
|
||||
int a, b, c;
|
||||
int pa, pb, pc, p;
|
||||
|
||||
for(i = 0; i < bpp; i++)
|
||||
{
|
||||
if(lastline)
|
||||
{
|
||||
*out += *lastline++;
|
||||
}
|
||||
out++;
|
||||
}
|
||||
for(i = bpp; i < rowbytes; i++)
|
||||
{
|
||||
a = *(out - bpp);
|
||||
c = 0;
|
||||
b = 0;
|
||||
if(lastline)
|
||||
{
|
||||
c = *(lastline - bpp);
|
||||
b = *lastline++;
|
||||
}
|
||||
p = b - c;
|
||||
pc = a - c;
|
||||
|
||||
pa = p < 0 ? -p : p;
|
||||
pb = pc < 0 ? -pc : pc;
|
||||
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
|
||||
|
||||
p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
|
||||
|
||||
*out++ += p;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Pack up the image data line by line
|
||||
|
||||
bool PNG_Pack(byte *out, ulong *size, ulong maxsize, byte *data, int width, int height, int bytedepth)
|
||||
{
|
||||
z_stream zdata;
|
||||
ulong rowbytes;
|
||||
ulong y;
|
||||
const byte *lastline, *source;
|
||||
// Storage for filter type and filtered row
|
||||
byte workline[(MAX_PNG_WIDTH * MAX_PNG_DEPTH) + 1];
|
||||
|
||||
// Number of bytes per row
|
||||
rowbytes = width * bytedepth;
|
||||
|
||||
memset(&zdata, 0, sizeof(z_stream));
|
||||
if(deflateInit(&zdata, Z_FAST_COMPRESSION_HIGH) != Z_OK)
|
||||
{
|
||||
png_error = PNG_ERROR_COMP;
|
||||
return(false);
|
||||
}
|
||||
|
||||
zdata.next_out = out;
|
||||
zdata.avail_out = maxsize;
|
||||
|
||||
lastline = NULL;
|
||||
source = data + ((height - 1) * rowbytes);
|
||||
for(y = 0; y < height; y++)
|
||||
{
|
||||
// Refilter using the most compressable filter algo
|
||||
// Assume paeth to speed things up
|
||||
workline[0] = (byte)PNG_FILTER_VALUE_PAETH;
|
||||
PNG_Filter(workline + 1, (byte)PNG_FILTER_VALUE_PAETH, source, lastline, rowbytes, bytedepth);
|
||||
|
||||
zdata.next_in = workline;
|
||||
zdata.avail_in = rowbytes + 1;
|
||||
if(deflate(&zdata, Z_SYNC_FLUSH) != Z_OK)
|
||||
{
|
||||
deflateEnd(&zdata);
|
||||
png_error = PNG_ERROR_COMP;
|
||||
return(false);
|
||||
}
|
||||
lastline = source;
|
||||
source -= rowbytes;
|
||||
}
|
||||
if(deflate(&zdata, Z_FINISH) != Z_STREAM_END)
|
||||
{
|
||||
png_error = PNG_ERROR_COMP;
|
||||
return(false);
|
||||
}
|
||||
*size = zdata.total_out;
|
||||
deflateEnd(&zdata);
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Unpack the image data, line by line
|
||||
|
||||
bool PNG_Unpack(const byte *data, const ulong datasize, png_image_t *image)
|
||||
{
|
||||
ulong rowbytes, zerror, y;
|
||||
byte filter;
|
||||
z_stream zdata;
|
||||
byte *lastline, *out;
|
||||
|
||||
// MD_PushTag(TAG_ZIP_TEMP);
|
||||
|
||||
memset(&zdata, 0, sizeof(z_stream));
|
||||
if(inflateInit(&zdata, Z_SYNC_FLUSH) != Z_OK)
|
||||
{
|
||||
png_error = PNG_ERROR_DECOMP;
|
||||
// MD_PopTag();
|
||||
return(false);
|
||||
}
|
||||
zdata.next_in = (byte *)data;
|
||||
zdata.avail_in = datasize;
|
||||
|
||||
rowbytes = image->width * image->bytedepth;
|
||||
|
||||
lastline = NULL;
|
||||
out = image->data;
|
||||
for(y = 0; y < image->height; y++)
|
||||
{
|
||||
// Inflate a row of data
|
||||
zdata.next_out = &filter;
|
||||
zdata.avail_out = 1;
|
||||
if(inflate(&zdata) != Z_OK)
|
||||
{
|
||||
inflateEnd(&zdata);
|
||||
png_error = PNG_ERROR_DECOMP;
|
||||
// MD_PopTag();
|
||||
return(false);
|
||||
}
|
||||
zdata.next_out = out;
|
||||
zdata.avail_out = rowbytes;
|
||||
zerror = inflate(&zdata);
|
||||
if((zerror != Z_OK) && (zerror != Z_STREAM_END))
|
||||
{
|
||||
inflateEnd(&zdata);
|
||||
png_error = PNG_ERROR_DECOMP;
|
||||
// MD_PopTag();
|
||||
return(false);
|
||||
}
|
||||
|
||||
// Unfilter a row of data
|
||||
PNG_Unfilter(out, filter, lastline, rowbytes, image->bytedepth);
|
||||
|
||||
lastline = out;
|
||||
out += rowbytes;
|
||||
}
|
||||
inflateEnd(&zdata);
|
||||
// MD_PopTag();
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Scan through all chunks and process each one
|
||||
|
||||
bool PNG_Load(const byte *data, ulong datasize, png_image_t *image)
|
||||
{
|
||||
bool moredata;
|
||||
const byte *next;
|
||||
byte *workspace, *work;
|
||||
ulong length, type, crc, totallength;
|
||||
|
||||
png_error = PNG_ERROR_OK;
|
||||
|
||||
if(memcmp(data, png_signature, sizeof(png_signature)))
|
||||
{
|
||||
png_error = PNG_ERROR_NOSIG;
|
||||
return(false);
|
||||
}
|
||||
data += sizeof(png_signature);
|
||||
|
||||
// workspace = (byte *)Z_Malloc(datasize, TAG_TEMP_PNG, qfalse);
|
||||
workspace = new byte[datasize];
|
||||
work = workspace;
|
||||
totallength = 0;
|
||||
|
||||
moredata = true;
|
||||
while(moredata)
|
||||
{
|
||||
length = BigLong(*(ulong *)data);
|
||||
data += sizeof(ulong);
|
||||
|
||||
type = BigLong(*(ulong *)data);
|
||||
const byte *crcbase = data;
|
||||
data += sizeof(ulong);
|
||||
|
||||
// CRC checksum location
|
||||
next = data + length + sizeof(ulong);
|
||||
|
||||
// CRC checksum includes header field
|
||||
crc = crc32(0, crcbase, length + sizeof(ulong));
|
||||
if(crc != (ulong)BigLong(*(ulong *)(next - 4)))
|
||||
{
|
||||
if(image->data)
|
||||
{
|
||||
delete [] image->data;
|
||||
//Z_Free(image->data);
|
||||
image->data = NULL;
|
||||
}
|
||||
delete [] workspace;
|
||||
//Z_Free(workspace);
|
||||
png_error = PNG_ERROR_FAILED_CRC;
|
||||
return(false);
|
||||
}
|
||||
switch(type)
|
||||
{
|
||||
case PNG_IHDR:
|
||||
if(!PNG_HandleIHDR(data, image))
|
||||
{
|
||||
delete [] workspace;
|
||||
//Z_Free(workspace);
|
||||
return(false);
|
||||
}
|
||||
image->data = (byte *)Z_Malloc(image->width * image->height * image->bytedepth, TAG_TEMP_PNG, qfalse);
|
||||
break;
|
||||
case PNG_IDAT:
|
||||
// Need to copy all the various IDAT chunks into one big one
|
||||
// Everything but 3dsmax has one IDAT chunk
|
||||
memcpy(work, data, length);
|
||||
work += length;
|
||||
totallength += length;
|
||||
break;
|
||||
case PNG_IEND:
|
||||
if(!PNG_Unpack(workspace, totallength, image))
|
||||
{
|
||||
delete [] workspace;
|
||||
delete [] image->data;
|
||||
//Z_Free(workspace);
|
||||
//Z_Free(image->data);
|
||||
image->data = NULL;
|
||||
return(false);
|
||||
}
|
||||
moredata = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
data = next;
|
||||
}
|
||||
delete [] workspace;
|
||||
//Z_Free(workspace);
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Outputs a crc'd chunk of PNG data
|
||||
#if 0
|
||||
bool PNG_OutputChunk(fileHandle_t fp, ulong type, byte *data, ulong size)
|
||||
{
|
||||
ulong crc, little, outcount;
|
||||
|
||||
// Output a standard PNG chunk - length, type, data, crc
|
||||
little = BigLong(size);
|
||||
outcount = FS_Write(&little, sizeof(little), fp);
|
||||
|
||||
little = BigLong(type);
|
||||
crc = crc32(0, (byte *)&little, sizeof(little));
|
||||
outcount += FS_Write(&little, sizeof(little), fp);
|
||||
|
||||
if(size)
|
||||
{
|
||||
crc = crc32(crc, data, size);
|
||||
outcount += FS_Write(data, size, fp);
|
||||
}
|
||||
|
||||
little = BigLong(crc);
|
||||
outcount += FS_Write(&little, sizeof(little), fp);
|
||||
|
||||
if(outcount != (size + 12))
|
||||
{
|
||||
png_error = PNG_ERROR_WRITE;
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Saves a PNG format compressed image
|
||||
bool PNG_Save(const char *name, byte *data, int width, int height, int bytedepth)
|
||||
{
|
||||
byte *work;
|
||||
fileHandle_t fp;
|
||||
int maxsize;
|
||||
ulong size, outcount;
|
||||
png_ihdr_t png_header;
|
||||
|
||||
png_error = PNG_ERROR_OK;
|
||||
|
||||
// Create the file
|
||||
fp = FS_FOpenFileWrite(name);
|
||||
if(!fp)
|
||||
{
|
||||
png_error = PNG_ERROR_CREATE_FAIL;
|
||||
return(false);
|
||||
}
|
||||
// Write out the PNG signature
|
||||
outcount = FS_Write(png_signature, sizeof(png_signature), fp);
|
||||
if(outcount != sizeof(png_signature))
|
||||
{
|
||||
FS_FCloseFile(fp);
|
||||
png_error = PNG_ERROR_WRITE;
|
||||
return(false);
|
||||
}
|
||||
// Create and output a valid header
|
||||
PNG_CreateHeader(&png_header, width, height, bytedepth);
|
||||
if(!PNG_OutputChunk(fp, PNG_IHDR, (byte *)&png_header, sizeof(png_header)))
|
||||
{
|
||||
FS_FCloseFile(fp);
|
||||
return(false);
|
||||
}
|
||||
// Create and output the copyright info
|
||||
if(!PNG_OutputChunk(fp, PNG_tEXt, (byte *)png_copyright, sizeof(png_copyright)))
|
||||
{
|
||||
FS_FCloseFile(fp);
|
||||
return(false);
|
||||
}
|
||||
// Max size of compressed image (source size + 0.1% + 12)
|
||||
maxsize = (width * height * bytedepth) + 4096;
|
||||
work = (byte *)Z_Malloc(maxsize, TAG_TEMP_PNG, qtrue); // fixme: optimise to qfalse sometime - ok?
|
||||
|
||||
// Pack up the image data
|
||||
if(!PNG_Pack(work, &size, maxsize, data, width, height, bytedepth))
|
||||
{
|
||||
Z_Free(work);
|
||||
FS_FCloseFile(fp);
|
||||
return(false);
|
||||
}
|
||||
// Write out the compressed image data
|
||||
if(!PNG_OutputChunk(fp, PNG_IDAT, (byte *)work, size))
|
||||
{
|
||||
Z_Free(work);
|
||||
FS_FCloseFile(fp);
|
||||
return(false);
|
||||
}
|
||||
Z_Free(work);
|
||||
// Output terminating chunk
|
||||
if(!PNG_OutputChunk(fp, PNG_IEND, NULL, 0))
|
||||
{
|
||||
FS_FCloseFile(fp);
|
||||
return(false);
|
||||
}
|
||||
FS_FCloseFile(fp);
|
||||
return(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
=============
|
||||
PNG_ConvertTo32
|
||||
=============
|
||||
*/
|
||||
|
||||
void PNG_ConvertTo32(png_image_t *image)
|
||||
{
|
||||
byte *temp;
|
||||
byte *old, *old2;
|
||||
ulong i;
|
||||
|
||||
//temp = (byte *)Z_Malloc(image->width * image->height * 4, TAG_TEMP_PNG, qtrue);
|
||||
temp = new byte[image->width * image->height * 4];
|
||||
old = image->data;
|
||||
old2 = old;
|
||||
image->data = temp;
|
||||
image->bytedepth = 4;
|
||||
|
||||
for(i = 0; i < image->width * image->height; i++)
|
||||
{
|
||||
*temp++ = *old++;
|
||||
*temp++ = *old++;
|
||||
*temp++ = *old++;
|
||||
*temp++ = 0xff;
|
||||
}
|
||||
//Z_Free(old2);
|
||||
delete [] old2;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadPNG32
|
||||
=============
|
||||
*/
|
||||
bool LoadPNG32 (char *name, byte **pixels, int *width, int *height, int *bytedepth)
|
||||
{
|
||||
byte *buffer;
|
||||
byte **bufferptr = &buffer;
|
||||
int nLen;
|
||||
png_image_t png_image;
|
||||
|
||||
if(!pixels)
|
||||
{
|
||||
bufferptr = NULL;
|
||||
}
|
||||
|
||||
|
||||
byte *pTempLoadedBuffer = 0;
|
||||
HANDLE hnd = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
DWORD dwSize = GetFileSize(hnd, NULL);
|
||||
if (dwSize == INVALID_FILE_SIZE)
|
||||
{
|
||||
CloseHandle(hnd);
|
||||
return false;
|
||||
}
|
||||
pTempLoadedBuffer = new byte[dwSize];
|
||||
DWORD dwRead;
|
||||
ReadFile(hnd, pTempLoadedBuffer, dwSize, &dwRead, NULL);
|
||||
CloseHandle(hnd);
|
||||
if (dwRead != dwSize)
|
||||
{
|
||||
delete [] pTempLoadedBuffer;
|
||||
return false;
|
||||
}
|
||||
*bufferptr = pTempLoadedBuffer;
|
||||
nLen = dwSize;
|
||||
|
||||
|
||||
*pixels = NULL;
|
||||
png_image.isimage = true;
|
||||
if(!PNG_Load(buffer, nLen, &png_image))
|
||||
{
|
||||
printf ("Error parsing %s: %s\n", name, PNG_GetError());
|
||||
return(false);
|
||||
}
|
||||
if(png_image.bytedepth != 4)
|
||||
{
|
||||
PNG_ConvertTo32(&png_image);
|
||||
}
|
||||
*pixels = png_image.data;
|
||||
if(width)
|
||||
{
|
||||
*width = png_image.width;
|
||||
}
|
||||
if(height)
|
||||
{
|
||||
*height = png_image.height;
|
||||
}
|
||||
if(bytedepth)
|
||||
{
|
||||
*bytedepth = png_image.bytedepth;
|
||||
}
|
||||
//FS_FreeFile(buffer);
|
||||
return(true);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadPNG8
|
||||
=============
|
||||
*/
|
||||
#if 0
|
||||
bool LoadPNG8 (char *name, byte **pixels, int *width, int *height)
|
||||
{
|
||||
byte *buffer;
|
||||
byte **bufferptr = &buffer;
|
||||
int nLen;
|
||||
png_image_t png_image;
|
||||
|
||||
if(!pixels)
|
||||
{
|
||||
bufferptr = NULL;
|
||||
}
|
||||
nLen = FS_ReadFile ( ( char * ) name, (void **)bufferptr);
|
||||
if (nLen == -1)
|
||||
{
|
||||
if(pixels)
|
||||
{
|
||||
*pixels = NULL;
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
if(!pixels)
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
*pixels = NULL;
|
||||
png_image.isimage = false;
|
||||
if(!PNG_Load(buffer, nLen, &png_image))
|
||||
{
|
||||
Com_Printf ("Error parsing %s: %s\n", name, PNG_GetError());
|
||||
return(false);
|
||||
}
|
||||
*pixels = png_image.data;
|
||||
if(width)
|
||||
{
|
||||
*width = png_image.width;
|
||||
}
|
||||
if(height)
|
||||
{
|
||||
*height = png_image.height;
|
||||
}
|
||||
FS_FreeFile(buffer);
|
||||
return(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
// end
|
||||
73
tools/pngtgaTool/png.h
Normal file
73
tools/pngtgaTool/png.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// Known chunk types
|
||||
|
||||
#define PNG_IHDR 'IHDR'
|
||||
#define PNG_IDAT 'IDAT'
|
||||
#define PNG_IEND 'IEND'
|
||||
#define PNG_tEXt 'tEXt'
|
||||
|
||||
#define PNG_PLTE 'PLTE'
|
||||
#define PNG_bKGD 'bKGD'
|
||||
#define PNG_cHRM 'cHRM'
|
||||
#define PNG_gAMA 'gAMA'
|
||||
#define PNG_hIST 'hIST'
|
||||
#define PNG_iCCP 'iCCP'
|
||||
#define PNG_iTXt 'iTXt'
|
||||
#define PNG_oFFs 'oFFs'
|
||||
#define PNG_pCAL 'pCAL'
|
||||
#define PNG_sCAL 'sCAL'
|
||||
#define PNG_pHYs 'pHYs'
|
||||
#define PNG_sBIT 'sBIT'
|
||||
#define PNG_sPLT 'sPLT'
|
||||
#define PNG_sRGB 'sRGB'
|
||||
#define PNG_tIME 'tIME'
|
||||
#define PNG_tRNS 'tRNS'
|
||||
#define PNG_zTXt 'zTXt'
|
||||
|
||||
// Filter values
|
||||
|
||||
#define PNG_FILTER_VALUE_NONE 0
|
||||
#define PNG_FILTER_VALUE_SUB 1
|
||||
#define PNG_FILTER_VALUE_UP 2
|
||||
#define PNG_FILTER_VALUE_AVG 3
|
||||
#define PNG_FILTER_VALUE_PAETH 4
|
||||
#define PNG_FILTER_NUM 5
|
||||
|
||||
// Common defines and typedefs
|
||||
|
||||
#define MAX_PNG_WIDTH 4096
|
||||
#define MAX_PNG_DEPTH 4
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct png_ihdr_s
|
||||
{
|
||||
ulong width;
|
||||
ulong height;
|
||||
byte bitdepth; // Bits per sample (not per pixel)
|
||||
byte colortype; // bit 0 - palette; bit 1 - RGB; bit 2 - alpha channel
|
||||
byte compression; // 0 for zip - error otherwise
|
||||
byte filter; // 0 for adaptive with the 5 basic types - error otherwise
|
||||
byte interlace; // 0 for no interlace - 1 for Adam7 interlace
|
||||
} png_ihdr_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct png_image_s
|
||||
{
|
||||
byte *data;
|
||||
ulong width;
|
||||
ulong height;
|
||||
ulong bytedepth;
|
||||
bool isimage;
|
||||
} png_image_t;
|
||||
|
||||
bool LoadPNG32 (char *name, byte **pixels, int *width, int *height, int *bytedepth);
|
||||
bool LoadPNG8 (char *name, byte **pixels, int *width, int *height);
|
||||
bool PNG_Save(const char *name, byte *data, int width, int height, int bytedepth);
|
||||
|
||||
// end
|
||||
8
tools/pngtgaTool/stdafx.cpp
Normal file
8
tools/pngtgaTool/stdafx.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// TgaWiz.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
12
tools/pngtgaTool/stdafx.h
Normal file
12
tools/pngtgaTool/stdafx.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
512
tools/pngtgaTool/tga.cpp
Normal file
512
tools/pngtgaTool/tga.cpp
Normal file
@@ -0,0 +1,512 @@
|
||||
// Bootleg TGA support, stolen from Q3
|
||||
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <cstdio>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
|
||||
// Prints an error message, and aborts the program
|
||||
void Error(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "ERROR: %s\n", msg);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_MipMap2
|
||||
|
||||
Uses temp mem, but then copies back to input, quartering the size of the texture
|
||||
Proper linear filter
|
||||
================
|
||||
*/
|
||||
void R_MipMap2( unsigned *in, int inWidth, int inHeight )
|
||||
{
|
||||
int i, j, k;
|
||||
byte *outpix;
|
||||
int inWidthMask, inHeightMask;
|
||||
int total;
|
||||
int outWidth, outHeight;
|
||||
unsigned *temp;
|
||||
|
||||
outWidth = inWidth >> 1;
|
||||
outHeight = inHeight >> 1;
|
||||
temp = new unsigned[outWidth*outHeight*4];
|
||||
|
||||
inWidthMask = inWidth - 1;
|
||||
inHeightMask = inHeight - 1;
|
||||
|
||||
for ( i = 0 ; i < outHeight ; i++ ) {
|
||||
for ( j = 0 ; j < outWidth ; j++ ) {
|
||||
outpix = (byte *) ( temp + i * outWidth + j );
|
||||
for ( k = 0 ; k < 4 ; k++ ) {
|
||||
total =
|
||||
1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
|
||||
2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
|
||||
2 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
|
||||
1 * ((byte *)&in[ ((i*2-1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
|
||||
|
||||
2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
|
||||
4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
|
||||
4 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
|
||||
2 * ((byte *)&in[ ((i*2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
|
||||
|
||||
2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
|
||||
4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
|
||||
4 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
|
||||
2 * ((byte *)&in[ ((i*2+1)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k] +
|
||||
|
||||
1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2-1)&inWidthMask) ])[k] +
|
||||
2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2)&inWidthMask) ])[k] +
|
||||
2 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+1)&inWidthMask) ])[k] +
|
||||
1 * ((byte *)&in[ ((i*2+2)&inHeightMask)*inWidth + ((j*2+2)&inWidthMask) ])[k];
|
||||
outpix[k] = total / 36;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy( in, temp, outWidth * outHeight * 4 );
|
||||
delete [] temp;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_MipMap
|
||||
|
||||
Operates in place, quartering the size of the texture
|
||||
================
|
||||
*/
|
||||
void R_MipMap (byte *in, int width, int height, bool simple)
|
||||
{
|
||||
int i, j;
|
||||
byte *out;
|
||||
int row;
|
||||
|
||||
if ( width == 1 && height == 1 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !simple ) {
|
||||
R_MipMap2( (unsigned *)in, width, height );
|
||||
return;
|
||||
}
|
||||
|
||||
row = width * 4;
|
||||
out = in;
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
|
||||
if ( width == 0 || height == 0 ) {
|
||||
width += height; // get largest
|
||||
for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
|
||||
out[0] = ( in[0] + in[4] )>>1;
|
||||
out[1] = ( in[1] + in[5] )>>1;
|
||||
out[2] = ( in[2] + in[6] )>>1;
|
||||
out[3] = ( in[3] + in[7] )>>1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0 ; i<height ; i++, in+=row) {
|
||||
for (j=0 ; j<width ; j++, out+=4, in+=8) {
|
||||
out[0] = (in[0] + in[4] + in[row+0] + in[row+4])>>2;
|
||||
out[1] = (in[1] + in[5] + in[row+1] + in[row+5])>>2;
|
||||
out[2] = (in[2] + in[6] + in[row+2] + in[row+6])>>2;
|
||||
out[3] = (in[3] + in[7] + in[row+3] + in[row+7])>>2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// My TGA loader...
|
||||
//
|
||||
//---------------------------------------------------
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
byte byIDFieldLength; // must be 0
|
||||
byte byColourmapType; // 0 = truecolour, 1 = paletted, else bad
|
||||
byte byImageType; // 1 = colour mapped (palette), uncompressed, 2 = truecolour, uncompressed, else bad
|
||||
word w1stColourMapEntry; // must be 0
|
||||
word wColourMapLength; // 256 for 8-bit palettes, else 0 for true-colour
|
||||
byte byColourMapEntrySize; // 24 for 8-bit palettes, else 0 for true-colour
|
||||
word wImageXOrigin; // ignored
|
||||
word wImageYOrigin; // ignored
|
||||
word wImageWidth; // in pixels
|
||||
word wImageHeight; // in pixels
|
||||
byte byImagePlanes; // bits per pixel (8 for paletted, else 24 for true-colour)
|
||||
byte byScanLineOrder; // Image descriptor bytes
|
||||
// bits 0-3 = # attr bits (alpha chan)
|
||||
// bits 4-5 = pixel order/dir
|
||||
// bits 6-7 scan line interleave (00b=none,01b=2way interleave,10b=4way)
|
||||
} TGAHeader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
// *pic == pic, else NULL for failed.
|
||||
//
|
||||
// returns false if found but had a format error, else true for either OK or not-found (there's a reason for this)
|
||||
//
|
||||
|
||||
void LoadTGA ( const char *name, byte **pic, int *width, int *height)
|
||||
{
|
||||
// these don't need to be declared or initialised until later, but the compiler whines that 'goto' skips them.
|
||||
//
|
||||
byte *pRGBA = NULL;
|
||||
byte *pOut = NULL;
|
||||
byte *pIn = NULL;
|
||||
|
||||
*pic = NULL;
|
||||
|
||||
#define TGA_FORMAT_ERROR(blah) Error(blah)
|
||||
|
||||
//
|
||||
// load the file
|
||||
//
|
||||
byte *pTempLoadedBuffer = 0;
|
||||
HANDLE hnd = CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
DWORD dwSize = GetFileSize(hnd, NULL);
|
||||
if (dwSize == INVALID_FILE_SIZE)
|
||||
{
|
||||
CloseHandle(hnd);
|
||||
return;
|
||||
}
|
||||
pTempLoadedBuffer = new byte[dwSize];
|
||||
DWORD dwRead;
|
||||
ReadFile(hnd, pTempLoadedBuffer, dwSize, &dwRead, NULL);
|
||||
CloseHandle(hnd);
|
||||
if (dwRead != dwSize)
|
||||
{
|
||||
delete [] pTempLoadedBuffer;
|
||||
return;
|
||||
}
|
||||
|
||||
TGAHeader_t *pHeader = (TGAHeader_t *) pTempLoadedBuffer;
|
||||
|
||||
if (pHeader->byColourmapType!=0)
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: colourmaps not supported\n" );
|
||||
}
|
||||
|
||||
if (pHeader->byImageType != 2 && pHeader->byImageType != 3 && pHeader->byImageType != 10)
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RLE-RGB) images supported\n");
|
||||
}
|
||||
|
||||
if (pHeader->w1stColourMapEntry != 0)
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: colourmaps not supported\n" );
|
||||
}
|
||||
|
||||
if (pHeader->wColourMapLength !=0 && pHeader->wColourMapLength != 256)
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: ColourMapLength must be either 0 or 256\n" );
|
||||
}
|
||||
|
||||
if (pHeader->byColourMapEntrySize != 0 && pHeader->byColourMapEntrySize != 24)
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: ColourMapEntrySize must be either 0 or 24\n" );
|
||||
}
|
||||
|
||||
if ( ( pHeader->byImagePlanes != 24 && pHeader->byImagePlanes != 32) && (pHeader->byImagePlanes != 8 && pHeader->byImageType != 3))
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
|
||||
}
|
||||
|
||||
if ((pHeader->byScanLineOrder&0x30)!=0x00 &&
|
||||
(pHeader->byScanLineOrder&0x30)!=0x10 &&
|
||||
(pHeader->byScanLineOrder&0x30)!=0x20 &&
|
||||
(pHeader->byScanLineOrder&0x30)!=0x30
|
||||
)
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: ScanLineOrder must be either 0x00,0x10,0x20, or 0x30\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// these last checks are so i can use ID's RLE-code. I don't dare fiddle with it or it'll probably break...
|
||||
//
|
||||
if ( pHeader->byImageType == 10)
|
||||
{
|
||||
if ((pHeader->byScanLineOrder & 0x30) != 0x00)
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB Images (type 10) must be in bottom-to-top format\n");
|
||||
}
|
||||
if (pHeader->byImagePlanes != 24 && pHeader->byImagePlanes != 32) // probably won't happen, but avoids compressed greyscales?
|
||||
{
|
||||
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB Images (type 10) must be 24 or 32 bit\n");
|
||||
}
|
||||
}
|
||||
|
||||
// now read the actual bitmap in...
|
||||
//
|
||||
// Image descriptor bytes
|
||||
// bits 0-3 = # attr bits (alpha chan)
|
||||
// bits 4-5 = pixel order/dir
|
||||
// bits 6-7 scan line interleave (00b=none,01b=2way interleave,10b=4way)
|
||||
//
|
||||
int iYStart,iXStart,iYStep,iXStep;
|
||||
|
||||
switch(pHeader->byScanLineOrder & 0x30)
|
||||
{
|
||||
default: // default case stops the compiler complaining about using uninitialised vars
|
||||
case 0x00: // left to right, bottom to top
|
||||
|
||||
iXStart = 0;
|
||||
iXStep = 1;
|
||||
|
||||
iYStart = pHeader->wImageHeight-1;
|
||||
iYStep = -1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x10: // right to left, bottom to top
|
||||
|
||||
iXStart = pHeader->wImageWidth-1;
|
||||
iXStep = -1;
|
||||
|
||||
iYStart = pHeader->wImageHeight-1;
|
||||
iYStep = -1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x20: // left to right, top to bottom
|
||||
|
||||
iXStart = 0;
|
||||
iXStep = 1;
|
||||
|
||||
iYStart = 0;
|
||||
iYStep = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x30: // right to left, top to bottom
|
||||
|
||||
iXStart = pHeader->wImageWidth-1;
|
||||
iXStep = -1;
|
||||
|
||||
iYStart = 0;
|
||||
iYStep = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// feed back the results...
|
||||
//
|
||||
if (width)
|
||||
*width = pHeader->wImageWidth;
|
||||
if (height)
|
||||
*height = pHeader->wImageHeight;
|
||||
|
||||
pRGBA = new byte[pHeader->wImageWidth * pHeader->wImageHeight * 4];
|
||||
*pic = pRGBA;
|
||||
pOut = pRGBA;
|
||||
pIn = pTempLoadedBuffer + sizeof(*pHeader);
|
||||
|
||||
// I don't know if this ID-thing here is right, since comments that I've seen are at the end of the file,
|
||||
// with a zero in this field. However, may as well...
|
||||
//
|
||||
if (pHeader->byIDFieldLength != 0)
|
||||
pIn += pHeader->byIDFieldLength; // skip TARGA image comment
|
||||
|
||||
byte red,green,blue,alpha;
|
||||
|
||||
if ( pHeader->byImageType == 2 || pHeader->byImageType == 3 ) // RGB or greyscale
|
||||
{
|
||||
for (int y=iYStart, iYCount=0; iYCount<pHeader->wImageHeight; y+=iYStep, iYCount++)
|
||||
{
|
||||
pOut = pRGBA + y * pHeader->wImageWidth *4;
|
||||
for (int x=iXStart, iXCount=0; iXCount<pHeader->wImageWidth; x+=iXStep, iXCount++)
|
||||
{
|
||||
switch (pHeader->byImagePlanes)
|
||||
{
|
||||
case 8:
|
||||
blue = *pIn++;
|
||||
green = blue;
|
||||
red = blue;
|
||||
*pOut++ = red;
|
||||
*pOut++ = green;
|
||||
*pOut++ = blue;
|
||||
*pOut++ = 255;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
blue = *pIn++;
|
||||
green = *pIn++;
|
||||
red = *pIn++;
|
||||
*pOut++ = red;
|
||||
*pOut++ = green;
|
||||
*pOut++ = blue;
|
||||
*pOut++ = 255;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
blue = *pIn++;
|
||||
green = *pIn++;
|
||||
red = *pIn++;
|
||||
alpha = *pIn++;
|
||||
*pOut++ = red;
|
||||
*pOut++ = green;
|
||||
*pOut++ = blue;
|
||||
*pOut++ = alpha;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // if we ever hit this, someone deleted a header check higher up
|
||||
TGA_FORMAT_ERROR("LoadTGA: Image can only have 8, 24 or 32 planes for RGB/greyscale\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (pHeader->byImageType == 10) // RLE-RGB
|
||||
{
|
||||
// I've no idea if this stuff works, I normally reject RLE targas, but this is from ID's code
|
||||
// so maybe I should try and support it...
|
||||
//
|
||||
byte packetHeader, packetSize, j;
|
||||
|
||||
for (int y = pHeader->wImageHeight-1; y >= 0; y--)
|
||||
{
|
||||
pOut = pRGBA + y * pHeader->wImageWidth *4;
|
||||
for (int x=0; x<pHeader->wImageWidth;)
|
||||
{
|
||||
packetHeader = *pIn++;
|
||||
packetSize = 1 + (packetHeader & 0x7f);
|
||||
if (packetHeader & 0x80) // run-length packet
|
||||
{
|
||||
switch (pHeader->byImagePlanes)
|
||||
{
|
||||
case 24:
|
||||
|
||||
blue = *pIn++;
|
||||
green = *pIn++;
|
||||
red = *pIn++;
|
||||
alpha = 255;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
|
||||
blue = *pIn++;
|
||||
green = *pIn++;
|
||||
red = *pIn++;
|
||||
alpha = *pIn++;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // if we ever hit this, someone deleted a header check higher up
|
||||
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB can only have 24 or 32 planes\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (j=0; j<packetSize; j++)
|
||||
{
|
||||
*pOut++ = red;
|
||||
*pOut++ = green;
|
||||
*pOut++ = blue;
|
||||
*pOut++ = alpha;
|
||||
x++;
|
||||
if (x == pHeader->wImageWidth) // run spans across rows
|
||||
{
|
||||
x = 0;
|
||||
if (y > 0)
|
||||
y--;
|
||||
else
|
||||
goto breakOut;
|
||||
pOut = pRGBA + y * pHeader->wImageWidth * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // non run-length packet
|
||||
|
||||
for (j=0; j<packetSize; j++)
|
||||
{
|
||||
switch (pHeader->byImagePlanes)
|
||||
{
|
||||
case 24:
|
||||
|
||||
blue = *pIn++;
|
||||
green = *pIn++;
|
||||
red = *pIn++;
|
||||
*pOut++ = red;
|
||||
*pOut++ = green;
|
||||
*pOut++ = blue;
|
||||
*pOut++ = 255;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
blue = *pIn++;
|
||||
green = *pIn++;
|
||||
red = *pIn++;
|
||||
alpha = *pIn++;
|
||||
*pOut++ = red;
|
||||
*pOut++ = green;
|
||||
*pOut++ = blue;
|
||||
*pOut++ = alpha;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // if we ever hit this, someone deleted a header check higher up
|
||||
TGA_FORMAT_ERROR("LoadTGA: RLE-RGB can only have 24 or 32 planes\n");
|
||||
break;
|
||||
}
|
||||
x++;
|
||||
if (x == pHeader->wImageWidth) // pixel packet run spans across rows
|
||||
{
|
||||
x = 0;
|
||||
if (y > 0)
|
||||
y--;
|
||||
else
|
||||
goto breakOut;
|
||||
pOut = pRGBA + y * pHeader->wImageWidth * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
breakOut:;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] pTempLoadedBuffer;
|
||||
}
|
||||
|
||||
void SaveTGA( byte *pic, int width, int height, char *fileName )
|
||||
{
|
||||
TGAHeader_t header;
|
||||
memset (&header, 0, sizeof(header));
|
||||
header.byImageType = 2; // Uncompressed
|
||||
header.wImageHeight = height;
|
||||
header.wImageWidth = width;
|
||||
header.byImagePlanes = 32; // BPP
|
||||
header.byScanLineOrder = 0x20;
|
||||
|
||||
// swap rgb to bgr
|
||||
byte *buffer = pic;
|
||||
byte temp;
|
||||
for (int i = 0; i < width * height * 4; i += 4)
|
||||
{
|
||||
temp = buffer[i];
|
||||
buffer[i] = buffer[i+2];
|
||||
buffer[i+2] = temp;
|
||||
}
|
||||
|
||||
HANDLE hnd = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
DWORD dwWritten;
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
WriteFile(hnd, &header, sizeof(header), &dwWritten, NULL);
|
||||
if (dwWritten != sizeof(header))
|
||||
{
|
||||
printf("ERROR: Couldn't write to file %s\n", fileName);
|
||||
CloseHandle(hnd);
|
||||
return;
|
||||
}
|
||||
WriteFile(hnd, pic, width * height * 4, &dwWritten, NULL);
|
||||
CloseHandle(hnd);
|
||||
}
|
||||
201
tools/pngtgaTool/zip.h
Normal file
201
tools/pngtgaTool/zip.h
Normal file
@@ -0,0 +1,201 @@
|
||||
//
|
||||
// zlib.h -- interface of the 'zlib' general purpose compression library
|
||||
// version 1.1.3, July 9th, 1998
|
||||
//
|
||||
// Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// Jean-loup Gailly Mark Adler
|
||||
// jloup@gzip.org madler@alumni.caltech.edu
|
||||
//
|
||||
// The data format used by the zlib library is described by RFCs (Request for
|
||||
// Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
|
||||
// (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
|
||||
//
|
||||
|
||||
// The 'zlib' compression library provides in-memory compression and
|
||||
// decompression functions, including integrity checks of the uncompressed
|
||||
// data. This version of the library supports only one compression method
|
||||
// (deflation) but other algorithms will be added later and will have the same
|
||||
// stream interface.
|
||||
//
|
||||
// Compression can be done in a single step if the buffers are large
|
||||
// enough (for example if an input file is mmap'ed), or can be done by
|
||||
// repeated calls of the compression function. In the latter case, the
|
||||
// application must provide more input and/or consume the output
|
||||
// (providing more output space) before each call.
|
||||
//
|
||||
// The library does not install any signal handler. The decoder checks
|
||||
// the consistency of the compressed data, so the library should never
|
||||
// crash even in case of corrupted input.
|
||||
|
||||
// This particular implementation has been heavily modified by jscott@ravensoft.com
|
||||
// to increase inflate/deflate speeds on 32 bit machines.
|
||||
|
||||
// for more info about .ZIP format, see
|
||||
// ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
|
||||
// PkWare has also a specification at :
|
||||
// ftp://ftp.pkware.com/probdesc.zip
|
||||
|
||||
// ========================================================================================
|
||||
// External calls and defines required for the zlib
|
||||
// ========================================================================================
|
||||
|
||||
// The deflate compression method
|
||||
#define ZF_STORED 0
|
||||
#define ZF_DEFLATED 8
|
||||
|
||||
// Compression levels
|
||||
typedef enum
|
||||
{
|
||||
Z_STORE_COMPRESSION,
|
||||
Z_FAST_COMPRESSION_LOW,
|
||||
Z_FAST_COMPRESSION,
|
||||
Z_FAST_COMPRESSION_HIGH,
|
||||
Z_SLOW_COMPRESSION_LOWEST,
|
||||
Z_SLOW_COMPRESSION_LOW,
|
||||
Z_DEFAULT_COMPRESSION,
|
||||
Z_SLOW_COMPRESSION_HIGH,
|
||||
Z_SLOW_COMPRESSION_HIGHEST,
|
||||
Z_MAX_COMPRESSION,
|
||||
} ELevel;
|
||||
|
||||
// Allowed flush values
|
||||
typedef enum
|
||||
{
|
||||
Z_NEED_MORE = -1, // Special case when finishing up the stream
|
||||
Z_NO_FLUSH,
|
||||
Z_SYNC_FLUSH, // Sync up the stream ready for another call
|
||||
Z_FINISH // Finish up the stream
|
||||
} EFlush;
|
||||
|
||||
// Return codes for the compression/decompression functions. Negative
|
||||
// values are errors, positive values are used for special but normal events.
|
||||
typedef enum
|
||||
{
|
||||
Z_STREAM_ERROR = -3, // Basic error from failed sanity checks
|
||||
Z_BUF_ERROR, // Not enough input or output
|
||||
Z_DATA_ERROR, // Invalid data in the stream
|
||||
Z_OK,
|
||||
Z_STREAM_END // End of stream
|
||||
} EStatus;
|
||||
|
||||
// Maximum value for windowBits in deflateInit and inflateInit.
|
||||
// The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
// that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||
// for small objects.
|
||||
#define MAX_WBITS 15 // 32K LZ77 window
|
||||
#define WINDOW_SIZE (1 << MAX_WBITS)
|
||||
#define BIG_WINDOW_SIZE (WINDOW_SIZE << 1)
|
||||
#define WINDOW_MASK (WINDOW_SIZE - 1)
|
||||
|
||||
// The three kinds of block type
|
||||
#define STORED_BLOCK 0
|
||||
#define STATIC_TREES 1
|
||||
#define DYN_TREES 2
|
||||
#define MODE_ILLEGAL 3
|
||||
|
||||
// The minimum and maximum match lengths
|
||||
#define MIN_MATCH 3
|
||||
#define MAX_MATCH 258
|
||||
|
||||
// number of distance codes
|
||||
#define D_CODES 30
|
||||
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
extern const ulong extra_dbits[D_CODES];
|
||||
|
||||
// Structure to be used by external applications
|
||||
|
||||
#define Z_Malloc(s, x1, x2) malloc((s))
|
||||
#define Z_Free(p) free((p))
|
||||
|
||||
// The application must update next_in and avail_in when avail_in has
|
||||
// dropped to zero. It must update next_out and avail_out when avail_out
|
||||
// has dropped to zero. All other fields are set by the
|
||||
// compression library and must not be updated by the application.
|
||||
|
||||
typedef struct z_stream_s
|
||||
{
|
||||
byte *next_in; // next input unsigned char
|
||||
ulong avail_in; // number of unsigned chars available at next_in
|
||||
ulong total_in; // total number of bytes processed so far
|
||||
|
||||
byte *next_out; // next output unsigned char should be put there
|
||||
ulong avail_out; // remaining free space at next_out
|
||||
ulong total_out; // total number of bytes output
|
||||
|
||||
EStatus status;
|
||||
EStatus error; // error code
|
||||
|
||||
struct inflate_state_s *istate; // not visible by applications
|
||||
struct deflate_state_s *dstate; // not visible by applications
|
||||
|
||||
ulong quality;
|
||||
} z_stream;
|
||||
|
||||
// Update a running crc with the bytes buf[0..len-1] and return the updated
|
||||
// crc. If buf is NULL, this function returns the required initial value
|
||||
// for the crc. Pre- and post-conditioning (one's complement) is performed
|
||||
// within this function so it shouldn't be done by the application.
|
||||
// Usage example:
|
||||
//
|
||||
// ulong crc = crc32(0L, NULL, 0);
|
||||
//
|
||||
// while (read_buffer(buffer, length) != EOF) {
|
||||
// crc = crc32(crc, buffer, length);
|
||||
// }
|
||||
// if (crc != original_crc) error();
|
||||
|
||||
ulong crc32(ulong crc, const byte *buf, ulong len);
|
||||
|
||||
// Update a running Adler-32 checksum with the bytes buf[0..len-1] and
|
||||
// return the updated checksum. If buf is NULL, this function returns
|
||||
// the required initial value for the checksum.
|
||||
// An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
|
||||
// much faster. Usage example:
|
||||
//
|
||||
// ulong adler = adler32(0L, NULL, 0);
|
||||
//
|
||||
// while (read_buffer(buffer, length) != EOF) {
|
||||
// adler = adler32(adler, buffer, length);
|
||||
// }
|
||||
// if (adler != original_adler) error();
|
||||
|
||||
ulong adler32(ulong adler, const byte *buf, ulong len);
|
||||
|
||||
// External calls to the deflate code
|
||||
EStatus deflateInit(z_stream *strm, ELevel level, int noWrap = 0);
|
||||
EStatus deflateCopy(z_stream *dest, z_stream *source);
|
||||
EStatus deflate(z_stream *strm, EFlush flush);
|
||||
EStatus deflateEnd(z_stream *strm);
|
||||
const char *deflateError(void);
|
||||
|
||||
// External calls to the deflate code
|
||||
EStatus inflateInit(z_stream *strm, EFlush flush, int noWrap = 0);
|
||||
EStatus inflate(z_stream *z);
|
||||
EStatus inflateEnd(z_stream *strm);
|
||||
const char *inflateError(void);
|
||||
|
||||
// External calls to the zipfile code
|
||||
bool InflateFile(byte *src, ulong compressedSize, byte *dst, ulong uncompressedSize, int noWrap = 0);
|
||||
bool DeflateFile(byte *src, ulong uncompressedSize, byte *dst, ulong maxCompressedSize, ulong *compressedSize, ELevel level, int noWrap = 0);
|
||||
|
||||
// end
|
||||
117
tools/pngtgaTool/zipcommon.cpp
Normal file
117
tools/pngtgaTool/zipcommon.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Table of CRC-32's of all single-byte values (made by make_crc_table)
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
static const unsigned long crc_table[256] =
|
||||
{
|
||||
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
0x2d02ef8dL
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Calculate 32 bit CRC checksum for len bytes
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned long len)
|
||||
{
|
||||
if(!buf)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
crc = crc ^ 0xffffffff;
|
||||
while(len--)
|
||||
{
|
||||
crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
return(crc ^ 0xffffffff);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Calculate 32 bit Adler checksum (quicker than CRC)
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
// largest prime smaller than 65536
|
||||
#define BASE 65521
|
||||
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
#define NMAX 5552
|
||||
|
||||
unsigned long adler32(unsigned long adler, const unsigned char *buf, unsigned long len)
|
||||
{
|
||||
unsigned long s1;
|
||||
unsigned long s2;
|
||||
int k;
|
||||
|
||||
if(!buf)
|
||||
{
|
||||
return(1);
|
||||
}
|
||||
s1 = adler & 0xffff;
|
||||
s2 = (adler >> 16) & 0xffff;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
k = len < NMAX ? len : NMAX;
|
||||
len -= k;
|
||||
|
||||
while (k--)
|
||||
{
|
||||
s1 += *buf++;
|
||||
s2 += s1;
|
||||
}
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
return (s2 << 16) | s1;
|
||||
}
|
||||
|
||||
// end
|
||||
Reference in New Issue
Block a user