grfcodec-6.0.3/0000755000000000000000000000000012171043643011773 5ustar rootrootgrfcodec-6.0.3/version.def0000644000000000000000000000056712072267533014156 0ustar rootroot# Current year YEAR = 2013 ifdef REVISION VERSIONSTR := r$(REVISION) else VERSIONS := $(shell AWK="$(AWK)" "./findversion.sh") REV := $(shell echo "$(VERSIONS)" | cut -f 2 -d' ') VER := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') VERSIONSTR := $(shell [ "`echo "$(VERSIONS)" | cut -c 1`" = 'r' ] && echo "trunk $(VER)" && exit; echo "$(VER) r$(REV)") endif grfcodec-6.0.3/0compile.txt0000644000000000000000000000264012027143046014244 0ustar rootrootHow to compile the GRF development tools ----------------------- Compiling the GRF development tools is pretty straightforward. It can be done, with varying quantities of automation, with Cygwin's gcc (using Makefile for a cygwin-dependant binary, any Linux gcc (using Makefile, for a Linux binary). GRFCodec and NFORenum require Boost 1.36 or higher. The make system does not check the Boost version, so compiling with a lower version of Boost will result in compile failures. GRFCodec and NFORenum can optionally be compiled with PNG support. This requires libpng and zlib to be available. Compiling with make =================== The Makefile will attempt to auto-detect: - Whether you are building on Cygwin or Linux (ISCYGWIN) - The location of your boost includes (BOOST_INCLUDE) If it gets these wrong, modify Makefile.local appropriately, or set the above mentioned controlling variables. ISCYGWIN: 1 on cygwin and 0 on Linux. BOOST_INCLUDE is the directory where your boost headers can be found. Targets ------- The following are the most intersting targets. Other targets exist, but are less useful. all Compile grfcodec, grfdiff, grfid, grfmerge, grfstrip and nforenum grfcodec grfdiff grfid grfmerge grfstrip nforenum Compile the program in question, using gcc. release Compile all programs, then strip and upx them (if enabled) clean Delete all compiled files remake Equivalent of "make clean all" grfcodec-6.0.3/src/0000755000000000000000000000000012171043637012565 5ustar rootrootgrfcodec-6.0.3/src/md5.cpp0000644000000000000000000003022212027143046013750 0ustar rootroot/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. 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. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } grfcodec-6.0.3/src/pngsprit.h0000644000000000000000000000167012171043637014610 0ustar rootroot#ifndef _PNGSPRIT_H #define _PNGSPRIT_H #ifdef WITH_PNG #include "pcxsprit.h" #include #include class pngwrite: public pcxwrite { public: pngwrite(multifile *mfile, bool paletted); ~pngwrite(); void filestart(bool paletted); void filedone(int final); protected: void encodebytes(const CommonPixel &pixel, int num); void encodebytes(const CommonPixel *buffer, int num); private: pngwrite(const pngwrite&); void operator=(const pngwrite&); private: png_struct *png; png_info *info; std::vector cache; }; class pngread: public pcxread { public: pngread(singlefile * mfile); ~pngread(); void filestart(bool paletted); void setline(CommonPixel *band); private: pngread(const pngread&); void operator=(const pngread&); private: multifile *mfile; png_struct *png; png_info *info; bool paletted; U8 *line_buffer; U8 **whole_image; uint read_row; }; #endif /* WITH_PNG */ #endif /* _PNGSPRIT_H */ grfcodec-6.0.3/src/act123_classes.cpp0000644000000000000000000002641012027143046016001 0ustar rootroot/* * act123_classes.cpp * Defines classes and support functions for checking actions 1-3. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include using namespace std; #include"inlines.h" #include"ExpandingArray.h" #include"sanity_defines.h" #include"data.h" #include"rangedint.h" #include"pseudo.h" #include"messages.h" #include"command.h" #if defined(min)||defined(max) #error min and max must be implemented as functions #endif #include "act123.h" //**************************************** // act123 //**************************************** act123::act123(){init();} void act123::init(){ act1.init(); defined2IDs.init(); act3spritenum=0; } uint act123::MaxFoundFeat()const{ const vector&m=defined2IDs._m; short ret=0; for(uint i=0;i<(uint)m.size();i++) ret=max(ret,m[i].feature); return ret; } void act123::IDarray::define(uint feature,unsigned int id,bool checks1C){ _m[id].used=false; _m[id].sprite=(unsigned short)_spritenum; _m[id].v1C=checks1C; _m[id].feature=(ushort)feature; } bool act123::IDarray::test(uint offset,uint id)const{ if(!is_defined(id)){ IssueMessage(ERROR,UNDEFINED_ID,offset,id); return false; } return true; } //**************************************** // Check2v //**************************************** Check2v::Check2v(){ FILE*pFile=myfopen(2v); VarData tempvar; int var; maxop=GetCheckByte(2v); while(true){ var=tempvar.Load(pFile); if(var==-1)break; globvars[var]=tempvar; } _p=new FeatData[MaxFeature()+1]; for(uint i=0;i<=MaxFeature();i++){ _p[i].last80=0xFF; _p[i].featfor82=GetCheckByte(2v); while(true){ var=tempvar.Load(pFile); if(var==-1)break; if(tempvar.width==0x80){ _p[i].last80=var-1; break; } if(var==0xFF&&tempvar.width==0xF0)break; if(var&0x80)_p[i].var80[var&0x7F]=tempvar; else _p[i].vars[var]=tempvar; } } fclose(pFile); } bool Check2v::IsValid(uint feature, uint var)const{ if(var>=0x80) return _p[feature].var80[var&0x7F].width != 0; else return _p[feature].vars[var].width || globvars[var].width; } uint Check2v::MaxParam(uint feature, uint var)const{ assert((var&0xE0)==0x60); assert(IsValid(feature, var)); if(_p[feature].vars[var].width) return _p[feature].vars[var].maxparam; else return globvars[var].maxparam; } uint Check2v::GetWidth(uint feature, uint var)const{ assert(IsValid(feature, var)); if(_p[feature].vars[var].width) return _p[feature].vars[var].width; else return globvars[var].width & ~0x40; } uint Check2v::GetEffFeature(uint feature,uint type){ if((type&3)==2)return Instance()._p[feature].featfor82; return feature; } void Check2v::Check(uint feature,uint var,uint offs,uint param,uint shift)const{ if(feature>MaxFeature())return; uint real_var=var; if(real_var==0x7B){ var=param; if(var<0x60 || var>=0x80) IssueMessage(WARNING1,INDIRECT_VAR_NOT_6X,offs); } if(var&0x80){ if(var>_p[feature].last80) IssueMessage(ERROR,NONEXISTANT_VARIABLE,offs,var); else if(!IsValid(feature, var)) IssueMessage(WARNING1,NONEXISTANT_VARIABLE,offs,var); else if(shift>=_p[feature].var80[var&0x7F].width<<3)IssueMessage(WARNING4,SHIFT_TOO_FAR,offs+1,var); }else if(!IsValid(feature,var)) IssueMessage(WARNING1,NONEXISTANT_VARIABLE,offs,var); else{ if(var==0x7E){ if(real_var==0x7B){ IssueMessage(ERROR,INDIRECT_VAR_7E,offs); return; } act123::IDarray&IDs=act123::Instance().defined2IDs; if(!IDs.is_defined(param)) IssueMessage(ERROR,UNDEFINED_ID,offs+1,param); else{ if(IDs.GetFeature(param)!=feature) IssueMessage(WARNING1,FEATURE_CALL_MISMATCH,offs+1,param,IDs.GetFeature(param)); IDs.use(param); } }else if(var>=0x60 && real_var!=0x7B && param>MaxParam(feature,var)) IssueMessage(WARNING1,PARAM_TOO_LARGE,offs+1,param,var); if(shift>=GetWidth(feature, var)<<3)IssueMessage(WARNING1,SHIFT_TOO_FAR,offs+2,var); } } uint Check2v::Prohibit0Mask(uint var){ return !(CInstance().globvars[var].width & 0x40); } //**************************************** // Check2v::VarData //**************************************** int Check2v::VarData::Load(FILE*pFile){ uint var; var=GetCheckByte(2v); if((width=GetCheckByte(2v))==0xF0&&var==0xFF) return-1; if(!(width&0x7F))return var; assert(width&0x80); /* //Read lots of currently unused bytes. CHECK_EOF(min); if(min==0xFF){ uint type; bool done=false; while(!done){ CHECK_EOF(type); switch(type){ case'-': fgetc(pFile); case '+': fgetc(pFile); break; case 'x': done=true; break; DEFAULT(Checkv2::VarData::Init,type); } } }else{ for(;i>0;i--) min|=fgetc(pFile)<<(i*8);//ignore EOF--I'll catch that later CHECK_EOF(max); for(i=temp.width;i>0;i--) max|=fgetc(pFile)<<(i*8);//ignore EOF--I'll catch that later } } */ width&=0x7F; if((var&0xE0)==0x60)maxparam=GetCheckByte(2v); return var; } //**************************************** // varRange //**************************************** const uint varRange::rangemax[]={0,0xFF,0xFFFF,0,0xFFFFFFFF}; varRange::varRange(uint width):dflt(rangemax[width]),num(0),width(width){ VERIFY(width&&width<5&&width!=3,width); } void varRange::UpdateRange(uint Var,uint op,uint shift,const PseudoSprite&data,uint&offs){ uint add,divmod,nAnd=data.ExtractVariable(offs,width); if(Check2v::Prohibit0Mask(Var) && !nAnd)IssueMessage(WARNING1,AND_00,offs); offs+=width; range var(rangemax[width],0,(0xFFFFFFFF>>shift)&nAnd); if(shift&0xC0){ add=data.ExtractVariable(offs,width); divmod=data.ExtractVariable(offs+=width,width); if(divmod){ if((var.min+=add).LastOpOverflow()||(var.max+=add).LastOpOverflow()){ var.min=0; var.max=rangemax[width]; } if(shift&0x80){// % var.min=0; var.max=min(var.max,divmod-1); add%=divmod; }else{// / var.min/=divmod; var.max/=divmod; } if(!add&&!(divmod&(divmod-1))) IssueMessage(WARNING2,USE_SHIFT_AND,offs-3*width); }else{ var.min=0; var.max=rangemax[width]; IssueMessage(ERROR,DIVIDE_BY_ZERO,offs); } offs+=width; } assert(var.min<=var.max); assert(dflt.min<=dflt.max); switch(op){ case(uint)-1://First run case 0xF:// Discard left dflt=var; case 0xE:// Store case 0x10://Persistent store break; case 0:// + case 0xC:// | case 0xD:// ^ if((dflt.min+=var.min).LastOpOverflow()||(dflt.max+=var.max).LastOpOverflow()){ dflt.min=0; dflt.max=rangemax[width]; } break; case 1:// - if((dflt.min-=var.max).LastOpOverflow()||(dflt.max-=var.min).LastOpOverflow()){ dflt.min=0; dflt.max=rangemax[width]; } break; case 2:case 3:case 6:case 7://SIGNED min,max,/,% dflt.min=0; dflt.max=rangemax[width]; //TODO: signed op support break; case 4:// min case 0xB:// & dflt.min=min(dflt.min,var.min); dflt.max=min(dflt.max,var.max); break; case 5:// max dflt.min=max(dflt.min,var.min); dflt.max=max(dflt.max,var.max); case 8:// / if(var.min==0){ dflt.min=0; dflt.max=rangemax[width]; }else{ dflt.min/=var.max; dflt.max/=var.min; } break; case 9:// % dflt.min=0; dflt.max=var.max; break; case 0xA:// * if((dflt.min*=var.min).LastOpOverflow()||(dflt.max*=var.max).LastOpOverflow()){ var.min=0; var.max=rangemax[width]; } break; case 0x12:case 0x13: // <=> dflt.min=0; dflt.max=2; break; case 0x11: // ROR case 0x14: // SHL case 0x15: // SHR case 0x16: // SAR default: dflt.min=0; dflt.max=rangemax[width]; } } void varRange::AddRange(uint min,uint max){ AddRangeInternal(min,max,UNREACHABLE_VAR); num++; } void varRange::CheckDefault(){ num=-1; AddRangeInternal(dflt.min,dflt.max,UNREACHABLE_DEFAULT); } void varRange::AddRangeInternal(uint min,uint max,RenumMessageId unreachable){ bool obscured=false,repeat; do{ repeat=false; for(int i=0;i<(int)ranges.size();i++){ if(min>=ranges[i].min&&min<=ranges[i].max){ if(ranges[i].max>=dflt.max){ IssueMessage(WARNING1,unreachable,num); return; } repeat=obscured=true; min=ranges[i].max+1; } if(max>=ranges[i].min&&max<=ranges[i].max){ if(ranges[i].min<=dflt.min){ IssueMessage(WARNING1,unreachable,num); return; } repeat=obscured=true; max=ranges[i].min-1; } if(min>max){ IssueMessage(WARNING1,unreachable,num); return; } } }while(repeat); if(obscured&&num!=-1) IssueMessage(WARNING2,OBSCURED_VARIATION,num); ranges.push_back(range((uint)-1,min,max)); } //**************************************** // rand2 //**************************************** rand2::rand2(){ FILE*pFile=myfopen(2r); _p=new rand2info[MaxFeature()+1]; for(uint i=0;i<=MaxFeature();i++){ _p[i].bits[0]=fgetc(pFile); _p[i].bits[1]=fgetc(pFile); _p[i].numtriggers=fgetc(pFile); } CheckEOF(_p[MaxFeature()].numtriggers,2r); fclose(pFile); } void rand2::CheckRand(uint feat,uint type,uint triggers,uint first,uint nrand){ if(feat>MaxFeature())return; type&=1; uint bits=0; while(nrand>>=1)bits++; if(first>_p[feat].bits[type])IssueMessage(ERROR,OUT_OF_RANGE_BITS,5,_p[feat].bits[type]); else if(first+bits>_p[feat].bits[type])IssueMessage(ERROR,OUT_OF_RANGE_BITS,6,_p[feat].bits[type]); triggers&=0x7F; if(triggers>>_p[feat].numtriggers)IssueMessage(WARNING1,UNDEFINED_TRIGGER); } //**************************************** // Define2 //**************************************** Define2::~Define2(){ if(act123::CInstance().defined2IDs.is_defined(id)&&!act123::CInstance().defined2IDs.is_used(id)) IssueMessage(WARNING1,UNUSED_ID,id,act123::CInstance().defined2IDs.defined_at(id)); act123::Instance().defined2IDs.define(feature,id,checks1C); } void Define2::ChangeFeature(uint feat){ feature=feat; } //**************************************** // Callbacks //**************************************** Callbacks::Callbacks(){ FILE*pFile=myfopen(callbacks); _p=new uint[numcallbacks=GetCheckWord(callbacks)]; for(uint i=0;i * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #include #include "error.h" #include "sprites.h" #include "grfcomm.h" int maxx = 0, maxy = 0, maxs = 0; static int decodetile(U8 *buffer, int sx, int sy, CommonPixel *imgbuffer, long tilesize, bool has_mask, bool rgba, int grfcontversion) { bool long_format = tilesize > 65535; bool long_chunk = grfcontversion == 2 && sx > 256; buffer += SpriteInfo::Size(grfcontversion); if (grfcontversion == 2 && tilesize <= sy * (long_format ? 4 : 2)) return -1; for (int y=0; y= tilesize) return -1; islast = buffer[offset + 1] & 0x80; len = (buffer[offset + 1] & 0x7f) << 8 | buffer[offset + 0]; ofs = buffer[offset + 3] << 8 | buffer[offset + 2]; offset += 4; } else { if (grfcontversion == 2 && offset + 1 >= tilesize) return -1; islast = buffer[offset] & 0x80; len = buffer[offset++] & 0x7f; ofs = buffer[offset++]; } // fill from beginning of last chunk to start // of this one, with "background" colour for (x=chunkstart; xMakeTransparent(); imgbuffer++; } // then copy the number of actual bytes const U8 *obuffer = buffer + offset; if (grfcontversion == 2 && offset + len > tilesize) return -1; for (x=0; xDecode(obuffer, has_mask, rgba); imgbuffer++; } offset += obuffer - (buffer + offset); chunkstart = ofs + len; } while (!islast); // and fill from the end of the last chunk to the // end of the line for (x=chunkstart; xMakeTransparent(); imgbuffer++; } } return 1; } static int decoderegular(const U8 *buffer, int sx, int sy, CommonPixel *imgbuffer, bool has_mask, bool rgba, int grfcontversion) { buffer += SpriteInfo::Size(grfcontversion); for (int y=0; yDecode(buffer, has_mask, rgba); imgbuffer++; } } return 1; } static long uncompress(unsigned long size, U8* in, unsigned long *insize, U8* out, unsigned long outsize, int spriteno, int grfcontversion) { unsigned long inused, datasize, compsize, *testsize; const int infobytes = SpriteInfo::Size(grfcontversion); memcpy(out, in, infobytes); testsize = &datasize; if (grfcontversion == 2 || SIZEISCOMPRESSED(in[0])) // size is the compressed size testsize = &compsize; compsize = infobytes; // initially we only have the info data datasize = infobytes; in += infobytes; inused = infobytes; while (*testsize < size) { S8 code = * ( (S8*) in++); if (++inused > *insize) break; compsize++; if (code < 0) { U8 ofs = *(in++); inused++; compsize++; unsigned long count = -(code >> 3); unsigned long offset = ( (code & 7) << 8) | ofs; if (datasize < offset) { printf("\nOffset too large in sprite %d!\n", spriteno); exit(2); } if (datasize + count > outsize) return -2*(datasize + count); U8* copy_src = out + datasize - offset; U8* copy_dest = out + datasize; for(unsigned long i = 0; i < count; i++) { *copy_dest = *copy_src; copy_dest++; copy_src++; } datasize += count; } else { unsigned long skip = code; if (code == 0) skip = 128; if (datasize + skip > outsize) return -2*(datasize + skip); memmove(out+datasize, in, skip); in += skip; inused += skip; compsize += skip; datasize += skip; } } if (inused > *insize) { printf("\nNot enough input data for decompression of sprite %d\n", spriteno); exit(2); } *insize = inused; return datasize; } void SpriteInfo::writetobuffer(U8 *buffer, int grfcontversion) { int i = 0; if (grfcontversion == 2) { /* Copy bits 3 and 6 of the nfo and make it, for now, an 8bpp normal GRF. */ U8 img=0; switch(this->depth){ case DEPTH_8BPP: img=0x04; break; case DEPTH_32BPP: img=0x03; break; case DEPTH_MASK: img=0x07; break; } buffer[i++] = img | (this->info & (1 << 3 | 1 << 6)); buffer[i++] = this->zoom; buffer[i++] = this->ydim & 0xFF; buffer[i++] = this->ydim >> 8; } else { buffer[i++] = this->info; buffer[i++] = this->ydim; } buffer[i++] = this->xdim & 0xFF; buffer[i++] = this->xdim >> 8; buffer[i++] = this->xrel & 0xFF; buffer[i++] = this->xrel >> 8; buffer[i++] = this->yrel & 0xFF; buffer[i++] = this->yrel >> 8; } void SpriteInfo::readfromfile(const char *action, int grfcontversion, FILE *grf, int spriteno) { int i = 0; if (grfcontversion == 2) { U8 data = fgetc(grf); /* According to the documentation bit 0 must always be set, and bits 3 and 6 are the same as in the nfo. */ this->info = (1 << 0) | (data & (1 << 3 | 1 << 6)); switch(data&0x7){ case 0x03: this->depth=DEPTH_32BPP; break; case 0x04: this->depth=DEPTH_8BPP; break; case 0x07: this->depth=DEPTH_MASK; break; default: { printf("\nUnknown colour depth %02x for sprite %d. GRFCodec currently only supports M, RGBA and RGBAM formats.\n", data&0x7, spriteno); exit(2); } } this->zoom = fgetc(grf); this->ydim = readword(action, grf); i += 2; } else { this->info = fgetc(grf); this->depth = DEPTH_8BPP; this->zoom = 0; this->ydim = fgetc(grf); } this->xdim = readword(action, grf); this->xrel = readword(action, grf); this->yrel = readword(action, grf); } static void writesprite(bool first, spritestorage *image_writer, spriteinfowriter *info_writer, CommonPixel *image, SpriteInfo info) { image_writer->setsize(info.xdim, info.ydim); info_writer->addsprite(first, image_writer->filename(), image_writer->curspritex(), image_writer->curspritey(), info); for (int y=0; ynextpixel(*image++); image_writer->newrow(); } image_writer->spritedone(info.xdim, info.ydim); } int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, U32 *dataoffset, int grfcontversion) { static const char *action = "decoding sprite"; unsigned long size, datasize, inbufsize, outbufsize, startpos, returnpos = 0; SpriteInfo info; U8 *inbuffer, *outbuffer; CommonPixel *imgbuffer; int sx, sy; if (!writer || !imgpal) { printf("\nparameter is NULL!\n"); exit(2); } size = readspritesize(action, grfcontversion, grf); if (size == 0) return 0; startpos = ftell(grf); U8 inf; cfread(action, &inf, 1, 1, grf); U32 id = 0; if (grfcontversion == 2 && inf == 0xfd) { // Jump to the data offset id = readdword(action, grf); returnpos = ftell(grf); fseek(grf, *dataoffset, SEEK_SET); } long result; for (int i = 0;; i++) { if (returnpos != 0) { U32 dataid = readdword(action, grf); if (id != dataid) { if (i > 0) break; printf("\nUnexpected id for sprite %d; expected %d got %d\n", spriteno, (int)id, (int)dataid); exit(2); } size = readdword(action, grf); if (size == 0) { printf("\nUnexpected size for sprite %d; expected non-zero got %d\n", spriteno, (int)size); exit(2); } startpos = ftell(grf); cfread(action, &inf, 1, 1, grf); } if (inf == 0xff) { if (returnpos != 0) size--; imgpal->setsize(1, 0); outbuffer = (U8*) malloc(size); //outbuffer[0] = 0xff; cfread(action, outbuffer, 1, size, grf); writer->adddata(size, outbuffer/*+1*/); imgpal->spritedone(); result = 1; if (returnpos == 0) return result; *dataoffset = startpos + size + 1; break; } fseek(grf, startpos, SEEK_SET); info.readfromfile(action, grfcontversion, grf, spriteno); if(info.zoom >= ZOOM_LEVELS){ printf("\nUnknown zoom level %02x for sprite %d\n", info.zoom, spriteno); exit(2); } sx = info.xdim; sy = info.ydim; const int infobytes = SpriteInfo::Size(grfcontversion); outbufsize = 0L + sx * sy + infobytes; if (grfcontversion == 2 && HASTRANSPARENCY(info.info)) size -= 4; if (grfcontversion == 2 || SIZEISCOMPRESSED(info.info)) { // compressed size stated inbufsize = size; // assume uncompressed is max. twice the compressed outbufsize <<= 1; } else { // assume compressed is max 12% larger than uncompressed (overhead etc.) inbufsize = size + (size >> 3); } if (HASTRANSPARENCY(info.info)) { outbufsize += 0L + info.ydim * 4; } inbuffer = (U8*) malloc(inbufsize); outbuffer = (U8*) malloc(outbufsize); imgbuffer = (CommonPixel*) calloc(sx * sy, sizeof(CommonPixel)); if (!inbuffer || !outbuffer || !imgbuffer) { printf("\nError allocating sprite buffer, want %ld for sprite %d\n", inbufsize + outbufsize + sx * sy, spriteno); exit(2); } unsigned long tilesize = 0; do { fseek(grf, startpos, SEEK_SET); if (grfcontversion == 2 && HASTRANSPARENCY(info.info)) { int tmp = fread(inbuffer, 1, infobytes, grf); tilesize = readdword(action, grf); inbufsize = tmp + fread(inbuffer + infobytes, 1, inbufsize - infobytes, grf); } else { inbufsize = fread(inbuffer, 1, inbufsize, grf); } if (inbufsize == 0) { printf("\nError reading sprite %d\n", spriteno); exit(2); } result = uncompress(size, inbuffer, &inbufsize, outbuffer, outbufsize, spriteno, grfcontversion); if (result < 0) { outbufsize = -result; outbuffer = (U8*) realloc(outbuffer, outbufsize); if (!outbuffer) { printf("\nError increasing sprite buffer size for sprite %d\n", spriteno); exit(2); } } } while (result < 0); datasize = result; bool has_mask=info.depth==DEPTH_MASK||info.depth==DEPTH_8BPP; bool rgba=info.depth==DEPTH_MASK||info.depth==DEPTH_32BPP; if (HASTRANSPARENCY(info.info)) { // it's a tile if (grfcontversion == 2 && datasize != tilesize + SpriteInfo::Size(grfcontversion)) { printf("\nError: not enough data to perform tile decoding for sprite %d\n", spriteno); exit(2); } result = decodetile(outbuffer, sx, sy, imgbuffer, tilesize, has_mask, rgba, grfcontversion); if (result < 0) { printf("\nError: expected more data during tile decoding for sprite %d\n", spriteno); exit(2); } } else { U8 bytes_per_pixel=(has_mask?1:0)+(rgba?4:0); if (grfcontversion == 2 && datasize != (unsigned long)(sx * sy * bytes_per_pixel) + SpriteInfo::Size(grfcontversion)) { printf("\nError: not enough data to perform regular decoding for sprite %d\n", spriteno); exit(2); } result = decoderegular(outbuffer, sx, sy, imgbuffer, has_mask, rgba, grfcontversion); } if (info.depth==DEPTH_32BPP) { if (imgrgba == NULL) { printf("\nError: cannot decode 32bpp sprites to pcx\n"); exit(2); } writesprite(false, imgrgba, writer, imgbuffer, info); } else if (info.depth==DEPTH_MASK) { if (imgrgba == NULL) { printf("\nError: cannot decode 32bpp sprites to pcx\n"); exit(2); } info.depth=DEPTH_32BPP; writesprite(false, imgrgba, writer, imgbuffer, info); info.depth=DEPTH_MASK; writesprite(false, imgpal, writer, imgbuffer, info); } else if (info.depth==DEPTH_8BPP) { writesprite(i == 0, imgpal, writer, imgbuffer, info); } else { printf("\nError unknown sprite depth %d\n", spriteno); exit(2); } if (sy > maxy) maxy = sy; if (sx > maxx) maxx = sx; if (datasize > (unsigned long) maxs) maxs = datasize; free(inbuffer); free(outbuffer); free(imgbuffer); if (returnpos != 0) { *dataoffset = startpos + inbufsize; if (grfcontversion == 2 && HASTRANSPARENCY(info.info)) *dataoffset += 4; } else { returnpos = startpos + inbufsize; break; } } fseek(grf, returnpos, SEEK_SET); return result; } static long fakecompress(const U8 *in, long insize, U8 *out, long outsize, long *compsize, int grfcontversion) { long needsize = insize + ((insize + 0x7f) / 0x7f); if (outsize < needsize) { needsize += needsize / 8; return -needsize; } long inpos = 0, outpos = 0; while (inpos < insize) { long rest = insize - inpos; if (rest > 0x7f) rest = 0x7f; out[outpos++] = rest; memmove(&(out[outpos]), &(in[inpos]), rest); outpos += rest; inpos += rest; } if (outpos > (grfcontversion == 2 ? 1048576 : 65535)) { printf("\nSorry, uncompressed sprite too large\n"); exit(2); } *compsize = outpos; return 1; } #ifdef OLDSTRATEGY // different compression strategies for identifying repetition static multitype strategy1(const U8* data, unsigned int datasize, unsigned int datamax) { int overlap; multitype ret; unsigned int ofs, foundofs = GREP_NOMATCH; // can only find up to 11 bits back if (datasize >= (1 << 11)) { ofs = datasize - (1 << 11) + 1; data+=ofs; datasize-=ofs; } for (overlap=MAXOVERLAP;overlap >= MINOVERLAP;overlap--) { // see if we can find a repetition of length overlap // allow overlapping memory blocks? #if 0 foundofs = grepmem(data, datasize+overlap-1, data+datasize, overlap, 0); #else foundofs = grepmem(data, datasize, data+datasize, overlap, 0); #endif if (foundofs != GREP_NOMATCH) { // found one if (foundofs > datasize) { foundofs = GREP_NOMATCH; // not really continue; } ofs = datasize - foundofs; if (ofs + overlap > datasize) overlap = datasize - ofs; if (datasize + overlap > datamax) overlap = datamax - datasize; break; } } ret.u16[0] = ofs; ret.u8[2] = overlap; ret.u8[3] = (foundofs != GREP_NOMATCH) && (overlap >= MINOVERLAP); return ret; } #endif // use strategy from LZ77 algorithm // // data is the beginning of the sprite data // datasize is how much has been processed so far, and can be used for // the repetition finding // datamax is the entire size of the sprite data static multitype strategy2(const U8* data, unsigned int datasize, unsigned int datamax) { unsigned int overlap = 0, newoverlap, remain, minoverlap, maxoverlap; multitype ret; int foundofs = -1; const U8 *found; // can only find up to 11 bits back if (datasize >= (1 << 11)) { unsigned int ofs = datasize - (1 << 11) + 1; data+=ofs; datasize-=ofs; datamax-=ofs; } remain = datasize; found = data-1; maxoverlap = MAXOVERLAP; while (overlap < maxoverlap) { // minoverlap is minimum overlap we need to find minus one minoverlap = overlap; if (minoverlap < MINOVERLAP-1) minoverlap = MINOVERLAP-1; if (remain <= minoverlap) break; // don't have more data to find longer overlap int i; for (i=remain-minoverlap; i; i--) if ( *(++found) == data[datasize]) break; if (!i) break; foundofs = (int) (found - data); remain = datasize - foundofs - 1; maxoverlap = datasize - foundofs; if (maxoverlap > MAXOVERLAP) maxoverlap = MAXOVERLAP; // can't store more anyway if (maxoverlap > datamax - datasize) maxoverlap = datamax - datasize; // can't use more newoverlap = 1; while ( (newoverlap < maxoverlap) && (found[newoverlap] == data[datasize+newoverlap]) ) newoverlap++; if (newoverlap < MINOVERLAP) continue; if (newoverlap > overlap) { // a longer chunk ret.u16[0] = datasize - foundofs; overlap = newoverlap; } } ret.u8[2] = overlap; ret.u8[3] = (overlap >= MINOVERLAP); return ret; } #ifdef _MSC_VER #pragma warning(disable:4701)//chunk may be used uninitialized #endif static long realcompress(const U8 *in, long insize, U8 *out, long outsize, long *compsize, int grfcontversion) { long inpos = 0, outpos = 0; U8 *lastcodepos = out; multitype chunk; out[outpos++] = 1; out[outpos++] = in[inpos++]; while (inpos < insize) { // search for where the first repetition of >= 3 chars occurs int overlap; int ofsh,ofsl; // chunk = strategy1(in, inpos, insize); chunk = strategy2(in, inpos, insize); if (chunk.u8[3]) { // Yay! Found one! if (!*lastcodepos) // there's a zero length verbatim chunk -> delete it outpos--; ofsl = chunk.u8[BYTE_OFSL]; ofsh = chunk.u8[BYTE_OFSH]; overlap = chunk.u8[2]; out[outpos++] = (-overlap << 3) | ofsh; out[outpos++] = ofsl; out[outpos] = 0; // start new interim verbatim chunk if (*lastcodepos == 0x80) *lastcodepos = 0; lastcodepos = &(out[outpos++]); inpos += overlap; } else { // no we didn't. Increase length of verbatim chunk /* In container version 2, verbatim data of length 128 can be encoded using 0. * While various GRF format specs list this already for container version 1, it is not true. * See http://www.tt-forums.net/viewtopic.php?p=1051455#p1051455 for details. */ if (*lastcodepos == (grfcontversion >= 2 ? 0x80 : 0x7f)) { // check for maximum verbatim length if (*lastcodepos == 0x80) *lastcodepos = 0; lastcodepos = &(out[outpos++]); // start new one *lastcodepos = 0; } (*lastcodepos)++; out[outpos++] = in[inpos++]; } if (outpos + 2 >= outsize) { // buffer too small, estimate expected size long needed = (long) outpos * (long) insize / (long) inpos; needed += needed >> 3; // add 12% extra return -needed; } } if (inpos != insize) { printf("\nError: compressed %ld bytes too much: %ld not %ld!", inpos - insize, inpos, insize); printf("\nLast chunk was repetition=%d, len=%d, ofs=%d\n", chunk.u8[3], chunk.u8[2], chunk.u16[0]); exit(2); } if (!*lastcodepos) outpos--; if (*lastcodepos == 0x80) *lastcodepos = 0; *compsize = outpos; return 1; } #ifdef _MSC_VER #pragma warning(default:4701) #endif static long lasttilesize; long getlasttilesize() { return lasttilesize; } long encodetile(U8 **compressed_data, long *uncompressed_size, const CommonPixel *image, long imgsize, int sx, int sy, SpriteInfo inf, int docompress, int spriteno, bool has_mask, bool rgba, int grfcontversion) { long tilesize = imgsize + 16L * sy; bool long_format = false; const bool long_chunk = grfcontversion == 2 && sx > 256; const int chunk_len = long_chunk ? 0x7FFF : 0x7F; const int trans_len = long_chunk ? 0xFFFF : 0xFF; while (1) { // repeat in case we didn't allocate enough memory U8 *tile = (U8*) malloc(tilesize); if (!tile) { printf("\nError: can't allocate %ld bytes for tile memory of sprite %d\n", tilesize, spriteno); exit(2); } long offset_size = long_format ? 4 : 2; long tileofs = offset_size * sy; // first sy (int) offsets, then data int y; for (y=0; y trans_len) { // chunk extends past the 255-wall; encode the remainder of the line if (x1 > trans_len) // chunk cannot start after 255; move it back x1 = trans_len; x2 = sx; while ( (image[y*sx+x2-1].IsTransparent(has_mask, rgba)) ) x2--; len = x2 - x1; if (len > chunk_len) { // chunk is too long if (x1 < trans_len) { // first encode the part before the wall len = trans_len - x1; x2 = trans_len; } else { // chunk starts at wall, abort printf("Error: Sprite %d is too wide to use tile encoding.\n", spriteno); exit(2); } } } lastlenofs = tileofs; if (long_chunk) { tile[tileofs++] = len & 0xFF; tile[tileofs++] = len >> 8; tile[tileofs++] = x1 & 0xFF; tile[tileofs++] = x1 >> 8; } else { tile[tileofs++] = len; tile[tileofs++] = x1; } U8 *buffer = tile + tileofs; for (int i = 0; i < len; i++) { buffer = image[y*sx+x1+i].Encode(buffer, has_mask, rgba); } tileofs += buffer - (tile + tileofs); } else { // transparent to end of line if (x2 == 0) { // totally empty line tile[tileofs++] = 0; tile[tileofs++] = 0; if (long_chunk) { tile[tileofs++] = 0; tile[tileofs++] = 0; } } x2 = x1; } x1 = x2; } tile[lastlenofs + (long_chunk ? 1 : 0)] |= 0x80; if (tileofs + offset_size + sx >= tilesize) break; } if (tileofs + offset_size + sx >= tilesize) { // tile didn't hold all data, estimate real size // and enlarge it free(tile); long imgofs = y*sx + 1L; tilesize = tilesize * imgsize / imgofs; tilesize += (tilesize >> 3) + 16L; continue; } if (!long_format && tileofs >= 65536) { if (grfcontversion == 1) { printf("Error: Sprite %d is too big to use tile encoding.\n", spriteno); exit(2); } free(tile); long_format = true; continue; } lasttilesize = tileofs; *uncompressed_size = tileofs; int result = encoderegular(compressed_data, tile, tileofs, inf, docompress, spriteno, grfcontversion); free(tile); return result; } } long encoderegular(U8 **compressed_data, const U8 *image, long imgsize, SpriteInfo inf, int docompress, int spriteno, int grfcontversion) { const int infobytes = SpriteInfo::Size(grfcontversion); long compsize = imgsize + 24 + infobytes, uncompsize = compsize + infobytes; unsigned int size; U8 *compr = (U8*) malloc(compsize); U8 *uncomp = (U8*) malloc(uncompsize); if (!compr || !uncomp) { printf("\nError: can't allocate %ld bytes for compressed buffer while encoding sprite %d\n", compsize + uncompsize, spriteno); exit(2); } long result; long realcompsize = 0; while (1) { inf.writetobuffer(compr, grfcontversion); if (docompress) result = realcompress(image, imgsize, compr+infobytes, compsize-infobytes, &realcompsize, grfcontversion); else result = fakecompress(image, imgsize, compr+infobytes, compsize-infobytes, &realcompsize, grfcontversion); if (grfcontversion == 2 || SIZEISCOMPRESSED(inf.info)) // write compressed size size = realcompsize + infobytes; else size = imgsize + infobytes; if (result > 0) { do { // everything was good // check that the compression is correct, by uncompressing again unsigned long insize = realcompsize + infobytes; result = uncompress(size, compr, &insize, uncomp, uncompsize, spriteno, grfcontversion); if (result < 0) { uncompsize = -result; uncomp = (U8*) realloc(uncomp, uncompsize); if (!uncomp) { printf("\nError increasing sprite buffer size for sprite %d\n", spriteno); exit(2); } } // and verifying if ((result-imgsize-infobytes) || memcmp(uncomp+infobytes, image, imgsize)) { printf("\nError: invalid compression of sprite %d, ", spriteno); if (result-imgsize-infobytes) printf("length diff %ld, ", result-imgsize-infobytes); else { int i; for (i=0; uncomp[i+infobytes]==image[i]; i++) {} printf("data diff at %d of %ld bytes, ", i, imgsize); } if (docompress) { puts("trying without it for this sprite\n"); docompress = 0; } else { printf("even uncompressed, aborting.\n"); exit(2); } result = 0; } } while (result < 0); if (result) break; } else if (result < 0) { // buffer was too small compsize = -result; compr = (U8*) realloc(compr, compsize); if (!compr) { printf("\nError: can't allocate %ld bytes for compressed buffer of sprite %d\n", compsize, spriteno); exit(2); } } else { printf("\nError: unknown error while compressing sprite %d\n", spriteno); exit(2); } } *compressed_data = compr; free(uncomp); return realcompsize; } void writesprite(FILE *grf, const U8 *compressed_data, int compressed_size, int uncompressed_size, SpriteInfo inf, int spriteno, int grfcontversion) { const int infobytes = SpriteInfo::Size(grfcontversion); static const char *action = "writing real sprite"; int size; if (grfcontversion == 2 || SIZEISCOMPRESSED(inf.info)) // write compressed size size = compressed_size + infobytes; else size = uncompressed_size + infobytes; if (grfcontversion == 2) { writedword(action, spriteno + 1, grf); if (HASTRANSPARENCY(inf.info)) size += 4; } writespritesize(action, size, grfcontversion, grf); cfwrite(action, compressed_data, 1, infobytes, grf); if (grfcontversion == 2 && HASTRANSPARENCY(inf.info)) { writedword(action, uncompressed_size, grf); } cfwrite(action, compressed_data + infobytes, 1, compressed_size, grf); } void writespritesize(const char *action, unsigned int spritesize, int grfcontversion, FILE *grf) { if (grfcontversion == 2) { writedword(action, spritesize, grf); } else { writeword(action, spritesize, grf); } } void writeword(const char *action, unsigned int value, FILE *grf) { U16 le_value = BE_SWAP16(value); cfwrite(action, &le_value, 1, 2, grf); } void writedword(const char *action, unsigned int value, FILE *grf) { U32 le_value = BE_SWAP32(value); cfwrite(action, &le_value, 1, 4, grf); } unsigned int readspritesize(const char *action, int grfcontversion, FILE *grf) { return grfcontversion == 2 ? readdword(action, grf) : readword(action, grf); } U16 readword(const char *action, FILE *grf) { U16 le_value; cfread(action, &le_value, 1, 2, grf); return BE_SWAP16(le_value); } U32 readdword(const char *action, FILE *grf) { U32 le_value; cfread(action, &le_value, 1, 4, grf); return BE_SWAP32(le_value); } grfcodec-6.0.3/src/error.h0000644000000000000000000000017112027143046014061 0ustar rootroot#ifndef _ERROR_H #define _ERROR_H #include "typesize.h" void fperror(const char *format, ...); #endif /* _ERROR_H */ grfcodec-6.0.3/src/sanity_defines.h0000644000000000000000000000474112027143046015743 0ustar rootroot/* * sanity_defines.h * Internal sprite linting stuff. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_SANITY_DEFS_H_INCLUDED_ #define _RENUM_SANITY_DEFS_H_INCLUDED_ #include #include "message_mgr.h" bool CheckLength(int,int,RenumMessageId,...); bool CheckTextID(uint,uint,uint); bool CheckID(uint,uint); void Init0(); void Init123(); void final123(); void Init7(); void final7(); void InitF(); void finalF(); bool IsLabel(uint); //int GetBit(const string&); enum ActBit{ACT0=1,ACT1=2,ACT3=4,ACT4=8,EMPTY1=0x10,OVERRIDE3=0x20,GENERIC3=0x40,ACT3_BEFORE_PROP08=0x80}; enum sanstate{UNKNOWN,FIND_PSEUDO,FIND_REAL,FIND_INCLUDE,FIND_RECOLOR,FIND_REAL_OR_RECOLOR}; bool IsValidFeature(int actbits,uint feat); bool IsValid2Feature(uint feat); bool IsProp08Set(uint feat,uint id); uchar Get2Type(uint feat); uint MaxFeature(); templateclass auto_array{//can't use auto_ptr because I use new[]/delete[] public: auto_array():_p(NULL){} ~auto_array(){delete[]_p;} operator _Ty*&(){return _p;} operator const _Ty*()const{return _p;} const _Ty* operator=(_Ty*p){return _p=p;} protected: _Ty*_p; private: void operator=(const auto_array<_Ty>&); auto_array(const auto_array&); }; typedef auto_array Guintp; #define AUTO_ARRAY(type)\ auto_array_p;\ type&operator[](uint x){return _p[x];}\ type operator[](uint x)const{return _p[x];}\ class apWrapper{ private: va_list _ap; public: ~apWrapper(){va_end(_ap);} operator va_list&(){return _ap;} operator const va_list&()const{return _ap;} #ifdef __va_copy va_list&operator=(va_list&ap){ __va_copy(_ap,ap); return _ap; } #else va_list const&operator=(va_list const&ap){ return _ap=ap; } #endif }; #define WrapAp(v)\ apWrapper ap;\ va_start(ap,v); #endif//_RENUM_SANITY_DEFS_H_INCLUDED_ grfcodec-6.0.3/src/act79D.cpp0000644000000000000000000001404512027143046014323 0ustar rootroot/* * act79D.cpp * Contains definitions for checking actions 7, 9, and D. * * Copyright 2005-2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include using namespace std; #include"nforenum.h" #include"inlines.h" #include"messages.h" #include"sanity_defines.h" #include"data.h" #include"pseudo.h" #include"command.h" uint numvars; class Vars{ public: bool canRead7(uint v){return(v<0x80||(vjumps; int Check7(PseudoSprite&data){ uint desiredSize=data.Length()-5; data.SetAllHex(); uint var=data.ExtractByte(1),var_size=data.ExtractByte(2),cond=data.ExtractByte(3); data.SetOpByte(3, '7'); if(cond>0xE)IssueMessage(ERROR,BAD_CONDITION,cond); else if(cond>5&&cond<0xB){ if(var!=0x88){ IssueMessage(ERROR,GRFCOND_NEEDS_GRFVAR,cond); desiredSize=0; } data.SetGRFID(4); }else if(cond>0xA){ data.SetText(4,4); SetSize(4); } if(cond<6&&var==0x88){ IssueMessage(ERROR,GRFVAR_NEEDS_GRFCOND); desiredSize=0; } if(cond<2){ SetSize(1); var_size=1; } if(!Vars::Instance().canRead7(var))IssueMessage(ERROR,NONEXISTANT_VARIABLE,1,var); else if(var>0x7F&&cond>1&&Vars::Instance().isBitmask(var)){ IssueMessage(ERROR,BITTEST_VARIABLE,var); desiredSize=0; } if(var_size==8&&var==0x88){ if(desiredSize>=8){ uint grfid = data.ExtractDword(4), mask = data.ExtractDword(8); if((~mask&grfid)!=0) IssueMessage(WARNING1,MASKED_BIT_SET); } }else if(var_size==0||var_size==3||var_size>4){ IssueMessage(FATAL,BAD_VARSIZE,var_size); return 0; }else if((cond==0xB||cond==0xC)&&var_size!=4) IssueMessage(WARNING2,COND_SIZE_MISMATCH,cond,4); else if(var>0x7F&&cond>1){ CheckSize(var); if(!Vars::Instance().lenOK(var,var_size)) IssueMessage(WARNING2,VARIABLE_SIZE_MISMATCH,var_size,var); } if(_autocorrect&&desiredSize&&desiredSize!=data.ExtractByte(2)){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,2,VARSIZE,data.ExtractByte(2),desiredSize); data.SetByteAt(2,var_size=desiredSize); } if(cond<2? CheckLength(data.Length(),6,BAD_LENGTH,COND,VAL,cond,6): CheckLength(data.Length(),5+var_size,BAD_LENGTH,VARSIZE,VAL,data.ExtractByte(2),var_size+5))return 0; jumps.push_back(act7(data.ExtractByte(0),data.ExtractByte(4+var_size))); return data.ExtractByte(4+var_size); } #undef SetSize void Init7(){ jumps.clear(); } void final7(){ bool header=false; for(uint i=0;i_spritenum){ if(!header){ header=true; IssueMessage(WARNING2,LONG_JUMPLEAD); IssueMessage(WARNING2,UNEXP_EOF_LONGJUMP); } IssueMessage(WARNING2,LONG_JUMP,jumps[i].act,jumps[i].spriteno); } } bool CheckD(PseudoSprite&data,uint length){ if(length<5){IssueMessage(FATAL,INVALID_LENGTH,ACTION,0xD,ONE_OF,5,9);return false;} data.SetAllHex(); uint target=data.ExtractByte(1),op=data.ExtractByte(2),src1=data.ExtractByte(3),src2=data.ExtractByte(4); data.SetPositionalOpByte(2, 'D'); if(!Vars::Instance().canWriteD(target))IssueMessage(ERROR,INVALID_TARGET); if((op&0x7F)>D::Instance().maxop)IssueMessage(ERROR,INVALID_OP,2,op); if((src1!=0xFE||src2!=0xFE)&&!Vars::Instance().canReadD(src1))IssueMessage(ERROR,INVALID_SRC,1); if(op&&src2!=0xFE&&!Vars::Instance().canReadD(src2))IssueMessage(ERROR,INVALID_SRC,2); if((op&0x7F)&&src1==0xFF&&src2==0xFF)IssueMessage(ERROR,ONLY_ONE_DATA); if(src1==0xFF||src2==0xFF||src2==0xFE){ if(CheckLength(length,9,INVALID_LENGTH,ACTION,0xD,ONE_OF,5,9))return false; if(src2==0xFE){ uint info=data.ExtractDword(5); if((info&0xFF)!=0xFF){ if(op&0x7F)IssueMessage(ERROR,INVALID_OP,2,op); if(src1!=0xFE&&src1&0x80)IssueMessage(ERROR,INVALID_SRC,1); data.SetGRFID(5); }else if(info==0xFFFF){ if(op&0x7F)IssueMessage(ERROR,INVALID_OP,2,op); if(src1>D::Instance().maxpatchvar)IssueMessage(ERROR,INVALID_SRC,1); }else{ if(op)IssueMessage(ERROR,INVALID_OP,2,op); data.SetPositionalOpByte(3, 'D'); uint feat=(info>>8)&0xFF,count=info>>16; if(src1>6)IssueMessage(ERROR,INVALID_SRC,1); if(feat>MaxFeature()||!D::Instance()[feat])IssueMessage(ERROR,INVALID_FEATURE); else if(count>D::Instance()[feat])IssueMessage(WARNING1,OOR_COUNT); return true; } } }else if(length>5)IssueMessage(WARNING2,INVALID_LENGTH,ACTION,0xD,ONE_OF,5,9); return false; } grfcodec-6.0.3/src/grfcomm.h0000644000000000000000000000130212027143046014357 0ustar rootroot#ifndef _GRFCOMM_H #define _GRFCOMM_H /* header file for grfcomm.h */ extern char *lastspritefilename; extern const char *e_openfile; char *spritefilename(const char *basefilename, const char *reldirectory, const char *ext, int spriteno, const char *mode, int mustexist); int doopen(const char *grffile, const char *dir, const char *ext, const char *mode, char **filename, FILE **file, int mustexist); void cfread(const char *action, void *ptr, size_t size, size_t n, FILE *stream); void cfwrite(const char *action, const void *ptr, size_t size, size_t n, FILE *stream); char *getbakfilename(const char *filename); char *safestrncpy(char *dest, const char *src, size_t n); #endif /* _GRFCOMM_H */ grfcodec-6.0.3/src/sanity.cpp0000644000000000000000000003236112027143046014600 0ustar rootroot/* * sanity.cpp * Defines functions for sprite sanity checking. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include using namespace std; #include"nforenum.h" #include"globals.h" #include"inlines.h" #include"command.h" #include"messages.h" #include"sanity.h" #include"ExpandingArray.h" #include"sanity_defines.h" #include"data.h" #include"strings.h" #include"pseudo.h" bool _base_grf = false; class features{ public: uint maxFeat; struct featdat{ uchar validbits; uchar act2type; }; AUTO_ARRAY(featdat); SINGLETON(features) }; features::features(){ FILE*pFile=myfopen(feat); maxFeat=GetCheckByte(feat); _p=new features::featdat[maxFeat+1]; uint i=0; for(;i<=maxFeat;i++) _p[i].validbits=(uchar)GetCheckByte(feat); for(i=0;i<=maxFeat;i++) _p[i].act2type=(uchar)GetCheckByte(feat); fclose(pFile); } bool IsValidFeature(int act,uint feat){ if(feat>features::Instance().maxFeat)return false; return(features::Instance()[feat].validbits&act)!=0; } bool IsValid2Feature(uint feat){ if(feat>features::Instance().maxFeat)return false; return features::Instance()[feat].act2type!=0xFF; } uchar Get2Type(uint feat){ if(feat>features::Instance().maxFeat)return 0xFF; return features::Instance()[feat].act2type; } uint MaxFeature(){return features::Instance().maxFeat;} #define MAX_TTD_SPRITE 4894 static struct sanity{ sanity(){init();} void init(){ state=FIND_PSEUDO; defined10IDs.init(); act8=act11=act14=0; } sanstate state; unsigned int expectedsprites,seensprites,spritenum,act8,act11,act14,minnextlen; class labelArray{ public: labelArray(){init();} void init(){used.resize(0);sprite.resize(0);} bool is_defined(int id)const{return sprite[id]!=0;} bool is_used(int id)const{return used[id];} unsigned short defined_at(int id)const{return sprite[id];} void define(uint id){sprite[id]=(unsigned short)_spritenum;used[id]=false;} void use(int id){used[id]=true;} protected: Expanding0Arrayused; Expanding0Arraysprite; }defined10IDs; }status; static const sanity&crStatus=status; void Init123(); void InitF(); void ClearTextIDs(); void Check0(PseudoSprite&); int Check1(PseudoSprite&); void Check2(PseudoSprite&); void Check3(PseudoSprite&); int Check5(PseudoSprite&,sanstate&); uint Check6(PseudoSprite&); int Check7(PseudoSprite&); void CheckB(PseudoSprite&); bool CheckD(PseudoSprite&,uint); void CheckF(PseudoSprite&); void Check13(PseudoSprite&); void Check14(PseudoSprite&); void invalidate_act3(); void reset_sanity(){ status.init(); Init0(); Init123(); Init7(); InitF(); ClearTextIDs(); } bool IsLabel(uint x){ VERIFY(x<0x100,x); return status.defined10IDs.is_defined(x); } void Seen8(int action){ if(status.act8==0){ IssueMessage(ERROR,MISSING_8,action); status.act8=(unsigned)-1; } } void Before8(int action){ if(status.act8!=0){ IssueMessage(ERROR,BEFORE_8,action); } } bool CheckLength(int alen,int elen,RenumMessageId message,...){ WrapAp(message); if(alenelen) vIssueMessage(WARNING2,message,ap); return false; } void SetState(sanstate x){ if((signed)status.expectedsprites==-1)status.state=UNKNOWN; else if(status.expectedsprites==0)status.state=FIND_PSEUDO; else status.state=x; } void check_sprite(SpriteType type){ if(GetState(LINT)==OFF)return; switch(status.state){ case FIND_PSEUDO: if(type==REAL){ IssueMessage(ERROR,UNEXPECTED,REAL_S); status.state=UNKNOWN; }else if(type==INCLUDE){ IssueMessage(ERROR,UNEXPECTED,BIN_INCLUDE); status.state=UNKNOWN; } return; case FIND_REAL: case FIND_REAL_OR_RECOLOR: if(type==INCLUDE){ IssueMessage(ERROR,UNEXPECTED,BIN_INCLUDE); status.state=UNKNOWN; }else if(++status.seensprites==status.expectedsprites) status.state=FIND_PSEUDO; else if(status.seensprites>status.expectedsprites){ IssueMessage(ERROR,EXTRA,REAL_S,status.expectedsprites,status.spritenum); status.state=UNKNOWN; } return; case FIND_INCLUDE: if(type==REAL){ IssueMessage(ERROR,UNEXPECTED,REAL_S); status.state=UNKNOWN; }else if(++status.seensprites==status.expectedsprites) status.state=FIND_PSEUDO; else if(status.seensprites>status.expectedsprites){ IssueMessage(ERROR,EXTRA,BIN_INCLUDE,status.expectedsprites,status.spritenum); status.state=UNKNOWN; } return; case FIND_RECOLOR: if(type==REAL){ IssueMessage(ERROR,UNEXPECTED,REAL_S); status.state=UNKNOWN; }else if(type==INCLUDE){ IssueMessage(ERROR,UNEXPECTED,BIN_INCLUDE); status.state=UNKNOWN; }else if(++status.seensprites==status.expectedsprites) status.state=FIND_PSEUDO; return; case UNKNOWN:return; DEFAULT(status.state) } } void check_sprite(PseudoSprite&data){ if(GetState(LINT)==OFF)return; const uint length=data.Length(); if(length==1&&data.ExtractByte(0)==0&&status.state==FIND_REAL){ check_sprite(REAL); return; } if((status.state==FIND_RECOLOR||status.state==FIND_REAL_OR_RECOLOR)&&length==257&&data.ExtractByte(0)==0){ check_sprite(RECOLOR); data.SetAllHex(); data.SetEol(32,1); data.SetEol(64,1); data.SetEol(96,1); data.SetEol(128,1); data.SetEol(160,1); data.SetEol(192,1); data.SetEol(224,1); return; } if(data.ExtractByte(0)==0xFF||data.ExtractByte(0)==0xFE)check_sprite(INCLUDE); else{ switch(status.state){ case FIND_REAL: case FIND_REAL_OR_RECOLOR: case FIND_INCLUDE: case FIND_RECOLOR: IssueMessage(ERROR,INSUFFICIENT, status.state==FIND_INCLUDE?BIN_INCLUDE:(status.state==FIND_RECOLOR?RECOLOR_TABLE:REAL_S), status.spritenum,status.expectedsprites,status.seensprites); status.state=UNKNOWN; case FIND_PSEUDO: case UNKNOWN:break; DEFAULT(status.state) } } if(status.minnextlen>length) IssueMessage(ERROR,MODIFY_BEYOND_LENGTH); status.minnextlen=0; try{ const int act=data.ExtractByte(0); if(act!=3&&act!=6&&act!=7&&act!=9&&act!=0xC)invalidate_act3(); if(act == 0x14) Before8(act); else if(act<6 || act==0xA || act==0xF || act>0x11) Seen8(act); switch(act){ case 0: data.SetAllHex(); Check0(data); break; case 1: data.SetAllHex(); status.expectedsprites=Check1(data); SetState(FIND_REAL); status.spritenum=_spritenum; status.seensprites=0; break; case 2: Check2(data); break; case 3: data.SetAllHex(); Check3(data); break; case 4: Check4(data); break; case 5: data.SetAllHex(); status.expectedsprites=Check5(data,status.state); SetState(status.state); status.spritenum=_spritenum; status.seensprites=0; break; case 6: data.SetAllHex(); status.minnextlen=Check6(data); break; case 7:case 9:{ status.defined10IDs.use(Check7(data)); break; }case 8:{ if(status.act8!=0&&status.act8!=(unsigned)-1)IssueMessage(ERROR,DUPLICATE_ACT,8,status.act8); status.act8=_spritenum; _grfver=data.ExtractByte(1); if(_grfver<2||_grfver>8)IssueMessage(ERROR,INVALID_VERSION,GRF); if(status.act14!=0&&_grfver<7)IssueMessage(ERROR,INVALID_VERSION_ACT14,_grfver); if(_act14_pal==0&&_grfver>=7)IssueMessage(WARNING1,MISSING_PALETTE_INFO); const uint GRFid=data.ExtractDword(2); data.SetGRFID(2); _base_grf=(GRFid&0xFFFFFF)==0x00544FFF; if(!_base_grf&&(GRFid&0xFF)==0xFF&&GRFid!=0xFFFFFFFF)IssueMessage(WARNING1,RESERVED_GRFID); if(length<8){ IssueMessage(ERROR,INVALID_LENGTH,ACTION,8,AT_LEAST,8); break; } uint offs=6; CheckString(data,offs,CTRL_COLOR); try{ if(data[offs])data.SetEol(offs-1,1); }catch(uint){ IssueMessage(WARNING1,NO_NULL_FOUND); } CheckString(data,offs,CTRL_COLOR|CTRL_NEWLINE); if(offsMAX_TTD_SPRITE) IssueMessage(ERROR,SPRITENUM_TOO_HIGH,2+3*i); status.expectedsprites+=sprites; } status.spritenum=_spritenum; status.seensprites=0; SetState(FIND_REAL_OR_RECOLOR); break; case 0xB: data.SetAllHex(); CheckB(data); case 0xC:break; case 0xD: if(CheckD(data,length))Seen8(0xD); break; case 0xE:{ uint numids=data.SetHex(1).ExtractByte(1); if(_autocorrect&&length%4==2&&length/4!=numids&&length/4<256){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,1,NUM,numids,length/4); data.SetByteAt(1,numids=length/4); } if(CheckLength(length,2+4*numids,BAD_LENGTH,NUM,VAL,numids,2+4*numids))return; if(!numids)IssueMessage(WARNING1,NO_GRFIDS); if(numids<2)return; uint*id=new uint[numids]; for(uint i=0;i3)IssueMessage(ERROR,INVALID_FONT,2+4*i,sprites); sprites=data.ExtractByte(3+4*i); if(!sprites) IssueMessage(WARNING1,SET_WITH_NO_SPRITES,3+4*i,i); else if((data.ExtractWord(4+4*i)&~0x7F)!=((data.ExtractWord(4+4*i)+sprites-1)&~0x7F)) IssueMessage(ERROR,SPANS_BLOCKS,3+4*i,i); status.expectedsprites+=sprites; } status.spritenum=_spritenum; status.seensprites=0; SetState(FIND_REAL); break; case 0x13: Check13(data); break; case 0x14: if (status.act14==0) status.act14=_spritenum; Check14(data); break; case 0xFE:{ if(CheckLength(length,8,INVALID_LENGTH,IMPORTS,EXACTLY,8))return; uint feat=data.SetAllHex().ExtractByte(1); if(feat)IssueMessage(ERROR,INVALID_LITERAL,1,feat,0); if(data.ExtractByte(2)==0xFF)IssueMessage(WARNING1,INVALID_GRFID,2,0x11); data.SetGRFID(2); break; }case 0xFF: //if(data.ExtractByte(data.ExtractByte(1)+2)) break; default: IssueMessage(FATAL,INVALID_ACTION); } }catch(unsigned int off){ IssueMessage(FATAL,TOO_SHORT,EXPECTED_LOC(off),EXPECTED_BYTES(off)); } } void final_sanity(){ if(GetState(LINT)==OFF)return; if(status.seensprites){ s/(.)/sprintf '\x%02x',ord $1/ges; print qq{\n"$_"}; } print ";\nconst U32 grfmrgsize = sizeof(grfmrg)-1;\n"; grfcodec-6.0.3/src/sprites.h0000644000000000000000000000757612027143046014441 0ustar rootroot#ifndef _SPRITES_H #define _SPRITES_H /*****************************************\ * * * SPRITES.H - A couple of routines to * * decode and encode TTD .GRF * * sprites * * * * * * Copyright (C) 2000 by Josef Drexler * * * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #include #include #include using namespace std; #define ZOOM_LEVELS (6) extern const char *zoom_levels[ZOOM_LEVELS]; #define DEPTHS (3) extern const char *depths[DEPTHS]; static const int DEPTH_8BPP = 0; static const int DEPTH_32BPP = 1; static const int DEPTH_MASK = 2; #include "pcxfile.h" #include "typesize.h" // Define some of the bits in SpriteInfo::info #define DONOTCROP(info) (info & 64) #define HASTRANSPARENCY(info) (info & 8) #define SIZEISCOMPRESSED(info) (info & 2) // minimum and maximum overlap to search for in the compression routines #define MINOVERLAP 3 #define MAXOVERLAP 15 // must be <= 15 b/o how it's encoded /** Information about a single sprite. */ struct SpriteInfo { U8 info; ///< Info byte; bit 1: size is compressed size, bit 3: tile transparancy, value 0xFF: special sprite. U8 depth; ///< The "depth" of the image. U8 zoom; ///< The zoom level. U16 ydim; ///< Number of lines in the sprite. U16 xdim; ///< Number of columns in the sprite. S16 xrel; ///< Horizontal offset S16 yrel; ///< Vertical offset string name; int xpos,ypos,imgsize; bool forcereopen; void writetobuffer(U8 *buffer, int grfcontversion); void readfromfile(const char *action, int grfcontversion, FILE *grf, int spriteno); static int Size(int grfcontversion) { return grfcontversion == 2 ? 10 : 8; } }; class spriteinfowriter { public: ~spriteinfowriter() {} virtual void addsprite(bool /* first */, const char * /* filename */, int /* y */, int /*x*/, SpriteInfo /*info*/) { }; virtual void adddata(uint /*size*/, U8 * /*data*/) { }; }; class spritestorage { public: virtual ~spritestorage(){} virtual void newsprite() {}; virtual void setsize(int /*sx*/, int /*sy*/) {}; virtual int curspritex() {return 0;}; virtual int curspritey() {return 0;}; virtual const char *filename(){return NULL;}; virtual void newrow() {}; virtual void nextpixel(CommonPixel /*colour*/) {}; virtual void spritedone(int /*sx*/, int /*sy*/) {}; virtual void spritedone() {}; }; extern int maxx, maxy, maxs; int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, U32 *dataoffset, int grfcontversion); long getlasttilesize(); long encodetile(U8 **compressed_data, long *uncompressed_size, const CommonPixel *image, long imgsize, int sx, int sy, SpriteInfo inf, int docompress, int spriteno, bool has_mask, bool rgba, int grfcontversion); long encoderegular(U8 **compressed_data, const U8 *image, long imgsize, SpriteInfo inf, int docompress, int spriteno, int grfcontversion); void writesprite(FILE *grf, const U8 *compressed_data, int compressed_size, int uncompressed_size, SpriteInfo inf, int spriteno, int grfcontversion); void writespritesize(const char *action, unsigned int spritesize, int grfcontversion, FILE *grf); void writeword(const char *action, unsigned int value, FILE *grf); void writedword(const char *action, unsigned int value, FILE *grf); unsigned int readspritesize(const char *action, int grfcontversion, FILE *grf); U16 readword(const char *action, FILE *grf); U32 readdword(const char *action, FILE *grf); #endif /* _SPRITES_H */ grfcodec-6.0.3/src/grfcodec.cpp0000644000000000000000000007022412027143046015045 0ustar rootroot /****************************************\ * * * GRFCODEC - A program to decode and * * encode Transport Tycoon * * Deluxe .GRF files * * * * * * Copyright (C) 2000-2005 by * * Josef Drexler * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \****************************************/ #include #include #include #include #include #include #ifdef MINGW #include #define mkdir(a,b) mkdir(a) #define isatty _isatty #elif defined(_MSC_VER) #include #include #define mkdir(a,b) mkdir(a) #define F_OK 0 #define isatty _isatty #else #include #endif//_MSC_VER #define DOCHECK #define DEFINE_PALS #include "pcxfile.h" #include "sprites.h" #include "pcxsprit.h" #include "pngsprit.h" #include "ttdpal.h" #include "grfcomm.h" #include "info.h" #include "error.h" #include "version.h" #include "conv.h" #include "nfosprite.h" #include "path.h" static const char *version = "GRFCodec " VERSION " - Copyright (C) 2000-2005 by Josef Drexler"; static void usage(void) { printf( "%s\n" "Usage:\n" " GRFCODEC -d [] []\n" " Decode all sprites in the GRF file and put them in the directory\n" " GRFCODEC -e [] []\n" " Encode all sprites in the directory and combine them in the GRF file\n" "\n" " denotes the .GRF file you want to work on, e.g. TRG1.GRF\n" " is where the individual sprites should be saved. If omitted, they\n" "\twill default to a subdirectory called sprites/.\n" "\n" "Options for decoding:\n" " -w Write spritesheets with the given width (default 800, minimum 16)\n" " -h Split spritesheets when they reach this height (default no limit,\n" " minimum 16)\n" " -b Organize sprites in boxes of this size (default 16)\n" " -o Sets the format of generated spritesheets. See -o ? for a list.\n" " -p Use this palette instead of the default. See -p ? for a list.\n" " -t Disable decoding of plain text characters as strings.\n" " -x Disable production of unquoted escape sequences.\n" " -xx Disable production of both quoted and unquoted escape sequences.\n" " This has the side effect of producing a version 6 .nfo, instead\n" " of a version 32 .nfo.\n" " -X List sprite numbers in the PCX file in hex.\n" "\n" "Options for encoding:\n" " -c Crop extraneous transparent blue from real sprites\n" " -u Save uncompressed data (probably not a good idea)\n" " -q Suppress warning messages\n" " -s Suppress progress output\n" " -g Version of the encoded container format (default 1, maximum 2)\n" " -n Try both compression algorithms and choose the most efficient\n" "\n" "Options for both encoding and decoding:\n" " -m Apply colour translation to all sprites except character-glyphs.\n" " -M Apply colour translation to all sprites.\n" " If both of these are specified, only the last is obeyed.\n" " (-m ? or -M ? for a list of colour translations.)\n" "\n" "GRFCODEC is Copyright (C) 2000-2005 by Josef Drexler\n" "You may copy and redistribute it under the terms of the GNU General Public\n" "License, as stated in the file 'COPYING'.\n", version ); exit(1); } static void showpalettetext() { printf( "Options for the -p parameter:\n" "\n" "Built-in palettes: use -p , where is one of the following:\n" " %d DOS TTD\n" " %d Windows TTD\n" " %d DOS TTD, Candyland\n" " %d Windows TTD, Candyland\n" " %d TT Original\n" " %d TT Original, Mars landscape\n" "\n" "External palette files: use -p [type:]filename.\n" "[type:] can be bcp, psp, or gpl. (Other formats may become available later.)\n" "If the type is omitted, bcp is assumed.\n" "\n" "bcp binary coded palette with the same format as the palette in a PCX\n" " file: 256 triples of red, green and blue encoded in bytes.\n" "psp the palette format output by Paintshop Pro\n" "gpl the palette format output by The GIMP.\n" "\n", // note, -p values are the array index plus one (so that 0 is not // a valid number, which makes the atoi easier) PAL_ttd_norm+1, PAL_ttw_norm+1, PAL_ttd_cand+1, PAL_ttw_cand+1, PAL_tt1_norm+1, PAL_tt1_mars+1 ); } static void showcolourmaps() { printf( "Options for the -m parameter:\n" "\n" " 0 Convert a TTD-DOS file to TTD-Windows\n" " 1 Convert a TTD-Windows file to TTD-DOS\n" "\n" ); } static void showimageformats() { printf( "Options for the -o parameter:\n" "\n" #ifdef WITH_PNG " pcx\n" " png (default)\n" #else " pcx (default)\n" #endif "\n" ); } struct defpal { const char* grffile; int defpalno; }; static const defpal defpals[] = { // DOS TTD { "TRG1", PAL_ttd_norm }, { "TRGC", PAL_ttd_norm }, { "TRGH", PAL_ttd_norm }, { "TRGI", PAL_ttd_norm }, { "TRGT", PAL_ttd_cand }, // Windows TTD { "TRG1R", PAL_ttw_norm }, { "TRGCR", PAL_ttw_norm }, { "TRGHR", PAL_ttw_norm }, { "TRGIR", PAL_ttw_norm }, { "TRGTR", PAL_ttw_cand }, // DOS TTO or TT+WB { "TREDIT", PAL_tt1_norm }, { "TREND", PAL_tt1_norm }, { "TRTITLE", PAL_tt1_norm }, { "TRHCOM", PAL_tt1_norm }, { "TRHCOM2", PAL_tt1_mars }, // TTDPatch { "TTDPATCH", PAL_ttd_norm }, { "TTDPATCHW", PAL_ttw_norm }, { "TTDPBASE", PAL_ttd_norm }, { "TTDPBASEW", PAL_ttw_norm }, }; static int *colourmaps[] = { palmap0, palmap1 }; bool _interactive; bool _best_compression = false; static int movetoreal(char *newfile, char *realfile) { // rename original to bak if bak doesn't exist char *bakfile = getbakfilename(realfile); FILE *tmp = fopen(bakfile, "rb"); if (!tmp && (errno == ENOENT)) { // .bak doesn't exist, rename orig to .bak // XXX: Shouldn't we rename orig to .bak even if .bak already exists? --pasky if (_interactive) printf("\nRenaming %s to %s", realfile, bakfile); if (rename(realfile, bakfile)) { errno = EEXIST; // go delete it } else { errno = ENOENT; // don't try to delete it } } if (tmp) fclose(tmp); free(bakfile); // delete grf if it exists if (access(realfile, F_OK) == 0) { if (_interactive) printf("\nDeleting %s",realfile); if (remove(realfile)) fperror("\nError deleting %s", realfile); } // rename tmp to grf if (_interactive) printf("\nReplacing %s with %s\n", realfile, newfile); if (rename(newfile, realfile)) { fperror("Error renaming %s to %s", newfile, realfile); exit(2); } return 1; } enum SpriteSheetFormat { SSF_PCX, #ifdef WITH_PNG SSF_PNG, #endif }; #ifdef WITH_PNG SpriteSheetFormat _outputformat = SSF_PNG; #else SpriteSheetFormat _outputformat = SSF_PCX; #endif const char * getoutputext(bool rgba) { switch (_outputformat) { #ifdef WITH_PNG case SSF_PNG: return rgba ? "32.png" : ".png"; #endif case SSF_PCX: default: return ".pcx"; } } class spritefiles : public multifile { public: spritefiles() { init(); } spritefiles(const char *basename, const char *directory, bool rgba); virtual FILE *curfile() { return thecurfile; } virtual FILE *nextfile(); virtual const char *filename() { return thecurfilename; } virtual const char *getdirectory() { return directory; } private: void init () { thecurfile = NULL; basename = thecurfilename = NULL; directory = NULL; filenum = 0; rgba=false; } FILE *thecurfile; char *thecurfilename; const char *directory; const char *basename; unsigned int filenum; bool rgba; }; spritefiles::spritefiles(const char *basename, const char *directory, bool rgba) { init(); spritefiles::basename = basename; spritefiles::directory = directory; spritefiles::rgba=rgba; } FILE *spritefiles::nextfile() { FILE *oldfile = thecurfile; char *oldname = thecurfilename; thecurfilename = strdup(spritefilename(basename, directory, getoutputext(rgba), filenum++, "wb", 1)); thecurfile = fopen(thecurfilename, "wb"); if (thecurfile) { // new open succeeded, close old one if (oldfile) fclose(oldfile); free(oldname); } else { // retain old one free(thecurfilename); thecurfile = oldfile; thecurfilename = oldname; } return thecurfile; } int _crop=0; int _quiet=0; static const char header[] = { '\x00', '\x00', // End-of-file marker for old OTTDp versions 'G', 'R', 'F', '\x82', // Container version 2 '\x0D', '\x0A', '\x1A', '\x0A', // Detect garbled transmission }; static int encode(const char *file, const char *dir, int compress, int *colourmap, int grfcontversion) { char *grfnew, *infofile; FILE *grf; doopen(file, "", ".new", "wb", &grfnew, &grf, 0); doopen(file, dir, ".nfo", "rt", &infofile, NULL, 1); if (_interactive) printf("Encoding in temporary file %s\n", grfnew); inforeader info(infofile, grfcontversion); free(infofile); if (colourmap) info.installmap(colourmap); long totaluncomp = 1, totalcomp = 1; long totaltransp = 1, totaluntransp = 1; long totalreg = 1, totalunreg = 1; if (grfcontversion == 2) { cfwrite("writing header", header, sizeof(header), 1, grf); int size = 1 + 4; // The size of the zoom + end of data for(int i = 0; i < info.size(); i++) { switch(info[i].GetType()){ case Sprite::ST_INCLUDE: case Sprite::ST_REAL: size += 4 + 1 + 4; // Size + type + ID break; case Sprite::ST_PSEUDO: size += 4 + 1 + ((const Pseudo&)info[i]).size(); break; } } writedword("writing header", size, grf); fputc(0x00, grf); // Compression } for (int pass = 1; pass <= grfcontversion; pass++) { for(int i=0;i bininclude) { nameofs--; if (nameofs[0] == '\\' || nameofs[0] == '/') { nameofs++; break; } } int namelen = strlen(nameofs); if (namelen > 255) { fprintf(stderr, "%s:%i: Error: binary include has too long filename %s\n", file, i, nameofs); exit(2); } int spritesize = 3 + namelen + fsize; if (spritesize < 5) { fprintf(stderr, "%s:%i: Error: binary include %s is empty\n", file, i, nameofs); exit(2); } if (grfcontversion > 1) spritesize++; // We need the first 0xFF to be accounted for as well. /* GRF container version only allowed 64K, the rest prevents underflows. */ if ((grfcontversion == 1 && spritesize > 65535) || spritesize < fsize || spritesize < 0) { fprintf(stderr, "%s:%i: Error: binary include %s is too large\n", file, i, nameofs); exit(2); } totalcomp += spritesize; totaluncomp += spritesize; if (grfcontversion == 2) writedword(action, i + 1, grf); writespritesize(action, spritesize, grfcontversion, grf); fputc(0xff, grf); fputc(0xff, grf); fputc(namelen, grf); cfwrite(action, nameofs, namelen+1, 1, grf); char *buffer = new char[16384]; while (fsize > 0) { int chunk = 16384; if (chunk > fsize) chunk=fsize; cfread(action, buffer, chunk, 1, bin); cfwrite(action, buffer, chunk, 1, grf); fsize -= chunk; } delete[]buffer; fclose(bin); } break; case Sprite::ST_PSEUDO:{ if (pass != 1) { break; } static const char *action = "writing pseudo sprite"; const Pseudo&sprite=(const Pseudo&)info[i]; uint size=sprite.size(); totalcomp += size; totaluncomp += size; writespritesize(action, size, grfcontversion, grf); fputc(0xff, grf); cfwrite(action, sprite.GetData(),1,size,grf); if(i == 0 && sprite.size() == 4){ int reported = *((S32*)sprite.GetData()); reported = BE_SWAP32(reported) + 1; if(reported != info.size() && !_quiet) fprintf(stderr, "%s:1: Warning: Found %d %s sprites than sprite 0 reports.\n", file, abs(info.size() - reported), info.size()>reported?"more":"fewer"); } } break; case Sprite::ST_REAL:{ // real sprite, encode it static const char *action = "writing real sprite"; const Real&sprite=(Real&)info[i]; for (size_t j = 0; j < (grfcontversion == 1 ? 1 : sprite.infs.size()); j++) { if (pass != grfcontversion) { writespritesize(action, 4, grfcontversion, grf); fputc(0xfd, grf); writedword(action, i + 1, grf); break; } info.PrepareReal(sprite.infs[j]); CommonPixel *image = (CommonPixel*) calloc(info.imgsize, sizeof(CommonPixel)); if (!image) { fprintf(stderr, "%s:%d: Error: can't allocate sprite memory (%ld bytes)\n", file, i, info.imgsize); exit(2); } bool has_mask=sprite.infs[j].depth==DEPTH_8BPP; bool rgba=sprite.infs[j].depth==DEPTH_32BPP; info.getsprite(image); if(j+1= 0; j--) if (has_mask && image[j].m == 0xFF) k++; if (k && !_quiet) fprintf(stderr, "%s:%d: Warning: %d of %ld pixels (%ld%%) are pure white\n", file, i, k, info.imgsize, k*100/info.imgsize); if(_crop && !DONOTCROP(info.inf.info)){ int i=0,j=0; for(i=info.imgsize-1;i>=0;i--)if(!image[i].IsTransparent(has_mask, rgba))break; // Find last non-blue pixel if(i<0)// We've got an all-blue sprite info.sx=info.sy=info.imgsize=1; else{ i=info.imgsize-(i+info.sx-i%info.sx/*begining of next line*/); info.sy-=i/info.sx; for(i=0;i=0;i--){ for(j=0;jsetpalette(palette); pcx->setcolours(255, 0, 0); if (pcx32 != NULL) pcx32->setcolours(255, 0, 0); infowriter writer(info, (width + box - 1) / box, useplaintext, pcx->getdirectory()); if (colourmap) pcx->installwritemap(colourmap); pcx->startimage(true, width, height, box, box); if (pcx32 != NULL) pcx32->startimage(false, width, height, box, box); count = 0; if (_interactive) printf("Decoding:\n"); do { int newpct = 100L*ftell(grf)/fsize; if (_interactive && newpct != lastpct) { lastpct = newpct; printf("Sprite %d at %lX, %3d%% done\r", count, ftell(grf), lastpct); } pcx->newsprite(); if (pcx32 != NULL) pcx32->newsprite(); result = decodesprite(grf, pcx, pcx32, &writer, count, &dataoffset, grfcontversion); writer.flush(); count++; } while (result); count--; pcx->endimage(); if (pcx32 != NULL) pcx32->endimage(); delete(pcx); // closes output file delete(pcx32); if (pcx32 == NULL) delete imgname32; writer.flush(); writer.done(count); fclose(info); if (_interactive) printf("%s has %d sprites, maxx %d, maxy %d, maxs %d.\n", file, count, maxx, maxy, maxs); fclose(grf); return 0; } static U8 *readpal(const char *filearg) { enum paltype { UNK, BCP, PSP, GPL }; paltype type = UNK; static U8 pal[256*3]; if (!strnicmp(filearg, "bcp:", 4)) type = BCP; else if (!strnicmp(filearg, "psp:", 4)) type = PSP; else if (!strnicmp(filearg, "gpl:", 4)) type = GPL; if (type != UNK) filearg += 4; // remove type: from filename FILE *f = fopen(filearg, "rb"); if (!f) { fperror(e_openfile, filearg); exit(1); } switch (type) { case BCP: case UNK: if (fread(pal, 1, 256*3, f) != 256*3) { fprintf(stderr, "Error: %s is not a BCP file.\n", filearg); exit(1); } break; case PSP: char fmt[16]; if (fgets(fmt, sizeof(fmt), f) == NULL || strcmp(fmt, "JASC-PAL\r\n")) { psp_error: fprintf(stderr, "Error: %s is not a PSP palette file.\n", filearg); exit(1); } int nument, nument2; if (fscanf(f, "%x\n", &nument) != 1) goto psp_error; if (fscanf(f, "%d\n", &nument2) != 1) goto psp_error; if ( (nument != nument2) || (nument != 256) ) { fprintf(stderr, "%s: Error: GRFCodec supports only 256 colour palette files.\n", filearg); exit(1); } for (int i=0; i 255 || g > 255 || b > 255) { fprintf(stderr, "%s: Error: reading palette.\n", filearg); exit(1); } pal[3*i] = (U8) r; pal[3*i+1] = (U8) g; pal[3*i+2] = (U8) b; while (fgets(fmt, sizeof(fmt), f) != NULL && fmt[strlen(fmt)-1] != '\n' ) {}// color name } break; } fclose(f); return pal; } static SpriteSheetFormat setoutputformat(const char *formatarg) { if (!strnicmp(formatarg, "pcx", 3)) return SSF_PCX; #ifdef WITH_PNG if (!strnicmp(formatarg, "png", 3)) return SSF_PNG; #endif return SSF_PCX; } // find default palette static U8* findpal(char *grffile) { char base[MAXFILE]; char *bs; unsigned int i; bs = strrchr(grffile, '\\'); if (!bs) bs = strrchr(grffile, '/'); if (!bs) bs = grffile; safestrncpy(base, grffile, MAXFILE); bs = strchr(base, '.'); if (bs) *bs = 0; for (i=0; i 0) && (palnum <= sizeof(defaultpalettes)/sizeof(defaultpalettes[0])) ) { palette = defaultpalettes[palnum-1]; } else if (*optarg == '?') { showpalettetext(); exit(1); } else palette = readpal(optarg); break; case 'c': _crop++; break; case 'g': grfcontversion = atoi(optarg); if (grfcontversion < 1 || grfcontversion > 2) usage(); break; case 'm': case 'M': _mapAll= opt=='M'; unsigned int mapnum; mapnum = atoi(optarg); if (*optarg == '?') { printf("%s\n", version); showcolourmaps(); exit(1); } else if (mapnum < sizeof(colourmaps)/sizeof(colourmaps[0]) ) { colourmap = colourmaps[mapnum]; } else { usage(); } break; case 'u': compress = 0; break; case 't': useplaintext = 0; break; case 'f': _force=true; break; case 'x': if(_useexts)_useexts--; break; case 'q': _quiet++; break; case 's': _interactive = false; case 'X': _hexspritenums=true; break; case 'o': if (*optarg == '?') { showimageformats(); exit(1); } _outputformat = setoutputformat(optarg); break; default: usage(); } } // non-option arguments: filename and potentially directory if (optind < argc) grffile = argv[optind++]; safestrncpy(directory, optind < argc ? argv[optind++] : "sprites", MAXDIR); int offset = strlen(directory); if (directory[offset - 1] != '/' ) { safestrncpy(directory + offset, "/", MAXDIR - offset); } if (!action || !grffile || (width < 16) || ( (height < 16) && (height != -1) ) || (strlen(directory) < 1) || (strlen(grffile) < 1) || (box < 1)) usage(); if (action == 1) { return encode(grffile, directory, compress, colourmap, grfcontversion); } else if (action == 2) { if (!palette) palette = findpal(grffile); return decode(grffile, directory, palette, box, width, height, colourmap, useplaintext); } return 0; } grfcodec-6.0.3/src/grfcomm.cpp0000644000000000000000000001220612027143046014717 0ustar rootroot/* Functions and classes common to all GRF programs Copyright (C) 2000-2003 by Josef Drexler Distributed under the GNU General Public License */ #include #include //#include #include #include #include #ifdef MINGW # include # define mkdir(a,b) mkdir(a) #elif defined(_MSC_VER) # include # define mkdir(a,b) mkdir(a) #endif #include "error.h" //#include "sprites.h" #if defined(WIN32) || defined(GCC32) || defined(GCC64) # include "path.h" #endif #include "grfcomm.h" char *lastspritefilename; const char *e_openfile = "Error opening %.228s"; static int getspritefilename(char *filename, const char *basefilename, char *subdirectory, const char *ext, long spriteno) { char bdrive[MAXDRIVE], bdirectory[MAXDIR], bname[MAXFILE], bext[MAXEXT]; char sdrive[MAXDRIVE], sdirectory[MAXDIR]; fnsplit(subdirectory, sdrive, sdirectory, NULL, NULL); fnsplit(basefilename, bdrive, bdirectory, bname, bext); if (strlen(sdrive)) { // drive given, go relative char sfullpath[MAXPATH]; safestrncpy(sfullpath, subdirectory, MAXPATH); fnsplit(sfullpath, sdrive, sdirectory, NULL, NULL); safestrncpy(bdrive, sdrive, MAXDRIVE); } if (strlen(sdirectory)) { int offset = (sdirectory[0] == '\\' || sdirectory[0] == '/') ? 0 : strlen(bdirectory); safestrncpy(bdirectory + offset, sdirectory, MAXDIR - offset); } if (spriteno >= 0) { int offset = strlen(bname); snprintf(bname + offset, MAXFILE - offset, "%02ld", spriteno); /* int baselen = 8 - strlen(bname); char *numpart = bname + (8 - baselen); long max = 1; int i; for (i=0; i= max*36) { printf("Cannot find a sprite filename!\n"); exit(2); } for (i=0; i 0) dest[n - 1] = 0; return dest; } grfcodec-6.0.3/src/strings.h0000644000000000000000000000302312027143046014420 0ustar rootroot/* * strings.h * Contains declarations for checking strings in actions 4, 8, and B. * * Copyright 2005-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_STRINGS_H_INCLUDED_ #define _RENUM_STRINGS_H_INCLUDED_ #define CTRL_FONT_LARGE 1 #define CTRL_FONT_SMALL 2 #define CTRL_FONT (CTRL_FONT_LARGE|CTRL_FONT_SMALL) #define CTRL_SPACE 4 #define CTRL_NEWLINE 8 #define CTRL_COLOR 0x10 #define CTRL_ALL (CTRL_FONT|CTRL_SPACE|CTRL_NEWLINE|CTRL_COLOR) #define CTRL_NO_STACK_CHECK 0x20 enum{STACK_BYTE=1,STACK_WORD,STACK_TEXT,STACK_DWORD,STACK_DATE,STACK_QWORD,STACK_INVALID}; enum{RETURN_NULL,RETURN_STACK}; class PseudoSprite; void Check4(PseudoSprite&); int CheckString(PseudoSprite&,uint&,int,bool =false,string="",int =0); string MakeStack(int,...); string GetLangName(uint); void CheckLangID(uint,uint); #endif//_RENUM_STRINGS_H_INCLUDED_ grfcodec-6.0.3/src/ttdpal.h0000644000000000000000000011135712027143046014231 0ustar rootroot// Autogenerated file. DO NOT EDIT! // Edit Makefile.setup, pals/*.bcp, or pal2c.pl instead. #define NUM_PALS 8 extern U8 defaultpalettes[NUM_PALS][256*3]; #define PAL_ttd_norm 0 #define PAL_ttw_norm 1 #define PAL_ttd_cand 2 #define PAL_ttw_cand 3 #define PAL_tt1_norm 4 #define PAL_tt1_mars 5 #define PAL_ttw_pb_pal1 6 #define PAL_ttw_pb_pal2 7 #ifdef DEFINE_PALS U8 defaultpalettes[NUM_PALS][256*3] = { // PAL_ttd_norm { 0, 0,255, 16, 16, 16, 32, 32, 32, 48, 48, 48, // 0-3 64, 64, 64, 80, 80, 80, 100,100,100, 116,116,116, // 4-7 132,132,132, 148,148,148, 168,168,168, 184,184,184, // 8-11 200,200,200, 216,216,216, 232,232,232, 252,252,252, // 12-15 52, 60, 72, 68, 76, 92, 88, 96,112, 108,116,132, // 16-19 132,140,152, 156,160,172, 176,184,196, 204,208,220, // 20-23 48, 44, 4, 64, 60, 12, 80, 76, 20, 96, 92, 28, // 24-27 120,120, 64, 148,148,100, 176,176,132, 204,204,168, // 28-31 72, 44, 4, 88, 60, 20, 104, 80, 44, 124,104, 72, // 32-35 152,132, 92, 184,160,120, 212,188,148, 244,220,176, // 36-39 64, 0, 4, 88, 4, 16, 112, 16, 32, 136, 32, 52, // 40-43 160, 56, 76, 188, 84,108, 204,104,124, 220,132,144, // 44-47 236,156,164, 252,188,192, 252,208, 0, 252,232, 60, // 48-51 252,252,128, 76, 40, 0, 96, 60, 8, 116, 88, 28, // 52-55 136,116, 56, 156,136, 80, 176,156,108, 196,180,136, // 56-59 68, 24, 0, 96, 44, 4, 128, 68, 8, 156, 96, 16, // 60-63 184,120, 24, 212,156, 32, 232,184, 16, 252,212, 0, // 64-67 252,248,128, 252,252,192, 32, 4, 0, 64, 20, 8, // 68-71 84, 28, 16, 108, 44, 28, 128, 56, 40, 148, 72, 56, // 72-75 168, 92, 76, 184,108, 88, 196,128,108, 212,148,128, // 76-79 8, 52, 0, 16, 64, 0, 32, 80, 4, 48, 96, 4, // 80-83 64,112, 12, 84,132, 20, 104,148, 28, 128,168, 44, // 84-87 28, 52, 24, 44, 68, 32, 60, 88, 48, 80,104, 60, // 88-91 104,124, 76, 128,148, 92, 152,176,108, 180,204,124, // 92-95 16, 52, 24, 32, 72, 44, 56, 96, 72, 76,116, 88, // 96-99 96,136,108, 120,164,136, 152,192,168, 184,220,200, // 100-103 32, 24, 0, 56, 28, 0, 72, 40, 4, 88, 52, 12, // 104-107 104, 64, 24, 124, 84, 44, 140,108, 64, 160,128, 88, // 108-111 76, 40, 16, 96, 52, 24, 116, 68, 40, 136, 84, 56, // 112-115 164, 96, 64, 184,112, 80, 204,128, 96, 212,148,112, // 116-119 224,168,128, 236,188,148, 80, 28, 4, 100, 40, 20, // 120-123 120, 56, 40, 140, 76, 64, 160,100, 96, 184,136,136, // 124-127 36, 40, 68, 48, 52, 84, 64, 64,100, 80, 80,116, // 128-131 100,100,136, 132,132,164, 172,172,192, 212,212,224, // 132-135 40, 20,112, 64, 44,144, 88, 64,172, 104, 76,196, // 136-139 120, 88,224, 140,104,252, 160,136,252, 188,168,252, // 140-143 0, 24,108, 0, 36,132, 0, 52,160, 0, 72,184, // 144-147 0, 96,212, 24,120,220, 56,144,232, 88,168,240, // 148-151 128,196,252, 188,224,252, 16, 64, 96, 24, 80,108, // 152-155 40, 96,120, 52,112,132, 80,140,160, 116,172,192, // 156-159 156,204,220, 204,240,252, 172, 52, 52, 212, 52, 52, // 160-163 252, 52, 52, 252,100, 88, 252,144,124, 252,184,160, // 164-167 252,216,200, 252,244,236, 72, 20,112, 92, 44,140, // 168-171 112, 68,168, 140,100,196, 168,136,224, 200,176,248, // 172-175 208,184,255, 232,208,252, 60, 0, 0, 92, 0, 0, // 176-179 128, 0, 0, 160, 0, 0, 196, 0, 0, 224, 0, 0, // 180-183 252, 0, 0, 252, 80, 0, 252,108, 0, 252,136, 0, // 184-187 252,164, 0, 252,192, 0, 252,220, 0, 252,252, 0, // 188-191 204,136, 8, 228,144, 4, 252,156, 0, 252,176, 48, // 192-195 252,196,100, 252,216,152, 8, 24, 88, 12, 36,104, // 196-199 20, 52,124, 28, 68,140, 40, 92,164, 56,120,188, // 200-203 72,152,216, 100,172,224, 92,156, 52, 108,176, 64, // 204-207 124,200, 76, 144,224, 92, 224,244,252, 200,236,248, // 208-211 180,220,236, 132,188,216, 88,152,172, 244, 0,244, // 212-215 245, 0,245, 246, 0,246, 247, 0,247, 248, 0,248, // 216-219 249, 0,249, 250, 0,250, 251, 0,251, 252, 0,252, // 220-223 253, 0,253, 254, 0,254, 255, 0,255, 76, 24, 8, // 224-227 108, 44, 24, 144, 72, 52, 176,108, 84, 210,146,126, // 228-231 252, 60, 0, 252, 84, 0, 252,104, 0, 252,124, 0, // 232-235 252,148, 0, 252,172, 0, 252,196, 0, 64, 0, 0, // 236-239 255, 0, 0, 48, 48, 0, 64, 64, 0, 80, 80, 0, // 240-243 255,255, 0, 32, 68,112, 36, 72,116, 40, 76,120, // 244-247 44, 80,124, 48, 84,128, 72,100,144, 100,132,168, // 248-251 216,244,252, 96,128,164, 68, 96,140, 255,255,255, // 252-255 }, // PAL_ttw_norm { 0, 0,255, 238, 0,238, 239, 0,239, 240, 0,240, // 0-3 241, 0,241, 242, 0,242, 243, 0,243, 244, 0,244, // 4-7 245, 0,245, 246, 0,246, 168,168,168, 184,184,184, // 8-11 200,200,200, 216,216,216, 232,232,232, 252,252,252, // 12-15 52, 60, 72, 68, 76, 92, 88, 96,112, 108,116,132, // 16-19 132,140,152, 156,160,172, 176,184,196, 204,208,220, // 20-23 48, 44, 4, 64, 60, 12, 80, 76, 20, 96, 92, 28, // 24-27 120,120, 64, 148,148,100, 176,176,132, 204,204,168, // 28-31 100,100,100, 116,116,116, 104, 80, 44, 124,104, 72, // 32-35 152,132, 92, 184,160,120, 212,188,148, 244,220,176, // 36-39 132,132,132, 88, 4, 16, 112, 16, 32, 136, 32, 52, // 40-43 160, 56, 76, 188, 84,108, 204,104,124, 220,132,144, // 44-47 236,156,164, 252,188,192, 252,208, 0, 252,232, 60, // 48-51 252,252,128, 76, 40, 0, 96, 60, 8, 116, 88, 28, // 52-55 136,116, 56, 156,136, 80, 176,156,108, 196,180,136, // 56-59 68, 24, 0, 96, 44, 4, 128, 68, 8, 156, 96, 16, // 60-63 184,120, 24, 212,156, 32, 232,184, 16, 252,212, 0, // 64-67 252,248,128, 252,252,192, 32, 4, 0, 64, 20, 8, // 68-71 84, 28, 16, 108, 44, 28, 128, 56, 40, 148, 72, 56, // 72-75 168, 92, 76, 184,108, 88, 196,128,108, 212,148,128, // 76-79 8, 52, 0, 16, 64, 0, 32, 80, 4, 48, 96, 4, // 80-83 64,112, 12, 84,132, 20, 104,148, 28, 128,168, 44, // 84-87 64, 64, 64, 44, 68, 32, 60, 88, 48, 80,104, 60, // 88-91 104,124, 76, 128,148, 92, 152,176,108, 180,204,124, // 92-95 16, 52, 24, 32, 72, 44, 56, 96, 72, 76,116, 88, // 96-99 96,136,108, 120,164,136, 152,192,168, 184,220,200, // 100-103 32, 24, 0, 56, 28, 0, 80, 80, 80, 88, 52, 12, // 104-107 104, 64, 24, 124, 84, 44, 140,108, 64, 160,128, 88, // 108-111 76, 40, 16, 96, 52, 24, 116, 68, 40, 136, 84, 56, // 112-115 164, 96, 64, 184,112, 80, 204,128, 96, 212,148,112, // 116-119 224,168,128, 236,188,148, 80, 28, 4, 100, 40, 20, // 120-123 120, 56, 40, 140, 76, 64, 160,100, 96, 184,136,136, // 124-127 36, 40, 68, 48, 52, 84, 64, 64,100, 80, 80,116, // 128-131 100,100,136, 132,132,164, 172,172,192, 212,212,224, // 132-135 48, 48, 48, 64, 44,144, 88, 64,172, 104, 76,196, // 136-139 120, 88,224, 140,104,252, 160,136,252, 188,168,252, // 140-143 0, 24,108, 0, 36,132, 0, 52,160, 0, 72,184, // 144-147 0, 96,212, 24,120,220, 56,144,232, 88,168,240, // 148-151 128,196,252, 188,224,252, 16, 64, 96, 24, 80,108, // 152-155 40, 96,120, 52,112,132, 80,140,160, 116,172,192, // 156-159 156,204,220, 204,240,252, 172, 52, 52, 212, 52, 52, // 160-163 252, 52, 52, 252,100, 88, 252,144,124, 252,184,160, // 164-167 252,216,200, 252,244,236, 72, 20,112, 92, 44,140, // 168-171 112, 68,168, 140,100,196, 168,136,224, 200,176,248, // 172-175 208,184,255, 232,208,252, 60, 0, 0, 92, 0, 0, // 176-179 128, 0, 0, 160, 0, 0, 196, 0, 0, 224, 0, 0, // 180-183 252, 0, 0, 252, 80, 0, 252,108, 0, 252,136, 0, // 184-187 252,164, 0, 252,192, 0, 252,220, 0, 252,252, 0, // 188-191 204,136, 8, 228,144, 4, 252,156, 0, 252,176, 48, // 192-195 252,196,100, 252,216,152, 8, 24, 88, 12, 36,104, // 196-199 20, 52,124, 28, 68,140, 40, 92,164, 56,120,188, // 200-203 72,152,216, 100,172,224, 92,156, 52, 108,176, 64, // 204-207 124,200, 76, 144,224, 92, 224,244,252, 200,236,248, // 208-211 180,220,236, 132,188,216, 88,152,172, 16, 16, 16, // 212-215 32, 32, 32, 32, 68,112, 36, 72,116, 40, 76,120, // 216-219 44, 80,124, 48, 84,128, 72,100,144, 100,132,168, // 220-223 216,244,252, 96,128,164, 68, 96,140, 76, 24, 8, // 224-227 108, 44, 24, 144, 72, 52, 176,108, 84, 210,146,126, // 228-231 252, 60, 0, 252, 84, 0, 252,104, 0, 252,124, 0, // 232-235 252,148, 0, 252,172, 0, 252,196, 0, 64, 0, 0, // 236-239 255, 0, 0, 48, 48, 0, 64, 64, 0, 80, 80, 0, // 240-243 255,255, 0, 148,148,148, 247, 0,247, 248, 0,248, // 244-247 249, 0,249, 250, 0,250, 251, 0,251, 252, 0,252, // 248-251 253, 0,253, 254, 0,254, 255, 0,255, 255,255,255, // 252-255 }, // PAL_ttd_cand { 0, 0,255, 16, 16, 16, 32, 32, 32, 48, 48, 48, // 0-3 64, 64, 64, 80, 80, 80, 100,100,100, 116,116,116, // 4-7 132,132,132, 148,148,148, 168,168,168, 184,184,184, // 8-11 200,200,200, 216,216,216, 232,232,232, 252,252,252, // 12-15 52, 60, 72, 68, 76, 92, 88, 96,112, 108,116,132, // 16-19 132,140,152, 156,160,172, 176,184,196, 204,208,220, // 20-23 48, 44, 4, 64, 60, 12, 80, 76, 20, 96, 92, 28, // 24-27 120,120, 64, 148,148,100, 176,176,132, 204,204,168, // 28-31 72, 44, 4, 88, 60, 20, 104, 80, 44, 124,104, 72, // 32-35 152,132, 92, 184,160,120, 212,188,148, 244,220,176, // 36-39 64, 0, 4, 88, 4, 16, 112, 16, 32, 136, 32, 52, // 40-43 160, 56, 76, 188, 84,108, 204,104,124, 220,132,144, // 44-47 236,156,164, 252,188,192, 252,208, 0, 252,232, 60, // 48-51 252,252,128, 76, 40, 0, 96, 60, 8, 116, 88, 28, // 52-55 136,116, 56, 156,136, 80, 176,156,108, 196,180,136, // 56-59 68, 24, 0, 96, 44, 4, 128, 68, 8, 156, 96, 16, // 60-63 184,120, 24, 212,156, 32, 232,184, 16, 252,212, 0, // 64-67 252,248,128, 252,252,192, 32, 4, 0, 64, 20, 8, // 68-71 84, 28, 16, 108, 44, 28, 128, 56, 40, 148, 72, 56, // 72-75 168, 92, 76, 184,108, 88, 196,128,108, 212,148,128, // 76-79 8, 52, 0, 16, 64, 0, 32, 80, 4, 48, 96, 4, // 80-83 64,112, 12, 84,132, 20, 104,148, 28, 128,168, 44, // 84-87 28, 52, 24, 44, 68, 32, 60, 88, 48, 80,104, 60, // 88-91 104,124, 76, 128,148, 92, 152,176,108, 180,204,124, // 92-95 16, 52, 24, 32, 72, 44, 56, 96, 72, 76,116, 88, // 96-99 96,136,108, 120,164,136, 152,192,168, 184,220,200, // 100-103 32, 24, 0, 56, 28, 0, 72, 40, 4, 88, 52, 12, // 104-107 104, 64, 24, 124, 84, 44, 140,108, 64, 160,128, 88, // 108-111 76, 40, 16, 96, 52, 24, 116, 68, 40, 136, 84, 56, // 112-115 164, 96, 64, 184,112, 80, 204,128, 96, 212,148,112, // 116-119 224,168,128, 236,188,148, 80, 28, 4, 100, 40, 20, // 120-123 120, 56, 40, 140, 76, 64, 160,100, 96, 184,136,136, // 124-127 36, 40, 68, 48, 52, 84, 64, 64,100, 80, 80,116, // 128-131 100,100,136, 132,132,164, 172,172,192, 212,212,224, // 132-135 40, 20,112, 64, 44,144, 88, 64,172, 104, 76,196, // 136-139 120, 88,224, 140,104,252, 160,136,252, 188,168,252, // 140-143 0, 24,108, 0, 36,132, 0, 52,160, 0, 72,184, // 144-147 0, 96,212, 24,120,220, 56,144,232, 88,168,240, // 148-151 128,196,252, 188,224,252, 16, 64, 96, 24, 80,108, // 152-155 40, 96,120, 52,112,132, 80,140,160, 116,172,192, // 156-159 156,204,220, 204,240,252, 172, 52, 52, 212, 52, 52, // 160-163 252, 52, 52, 252,100, 88, 252,144,124, 252,184,160, // 164-167 252,216,200, 252,244,236, 72, 20,112, 92, 44,140, // 168-171 112, 68,168, 140,100,196, 168,136,224, 200,176,248, // 172-175 208,184,255, 232,208,252, 60, 0, 0, 92, 0, 0, // 176-179 128, 0, 0, 160, 0, 0, 196, 0, 0, 224, 0, 0, // 180-183 252, 0, 0, 252, 80, 0, 252,108, 0, 252,136, 0, // 184-187 252,164, 0, 252,192, 0, 252,220, 0, 252,252, 0, // 188-191 204,136, 8, 228,144, 4, 252,156, 0, 252,176, 48, // 192-195 252,196,100, 252,216,152, 8, 24, 88, 12, 36,104, // 196-199 20, 52,124, 28, 68,140, 40, 92,164, 56,120,188, // 200-203 72,152,216, 100,172,224, 92,156, 52, 108,176, 64, // 204-207 124,200, 76, 144,224, 92, 224,244,252, 200,236,248, // 208-211 180,220,236, 132,188,216, 88,152,172, 244, 0,244, // 212-215 245, 0,245, 246, 0,246, 247, 0,247, 248, 0,248, // 216-219 249, 0,249, 250, 0,250, 251, 0,251, 252, 0,252, // 220-223 253, 0,253, 254, 0,254, 255, 0,255, 76, 24, 8, // 224-227 108, 44, 24, 144, 72, 52, 176,108, 84, 210,146,126, // 228-231 252, 60, 0, 252, 84, 0, 252,104, 0, 252,124, 0, // 232-235 252,148, 0, 252,172, 0, 252,196, 0, 64, 0, 0, // 236-239 255, 0, 0, 48, 48, 0, 64, 64, 0, 80, 80, 0, // 240-243 255,255, 0, 28,108,124, 32,112,128, 36,116,132, // 244-247 40,120,136, 44,124,140, 92,164,184, 116,180,196, // 248-251 216,244,252, 112,176,192, 88,160,180, 255,255,255, // 252-255 }, // PAL_ttw_cand { 0, 0,255, 238, 0,238, 239, 0,239, 240, 0,240, // 0-3 241, 0,241, 242, 0,242, 243, 0,243, 244, 0,244, // 4-7 245, 0,245, 246, 0,246, 168,168,168, 184,184,184, // 8-11 200,200,200, 216,216,216, 232,232,232, 252,252,252, // 12-15 52, 60, 72, 68, 76, 92, 88, 96,112, 108,116,132, // 16-19 132,140,152, 156,160,172, 176,184,196, 204,208,220, // 20-23 48, 44, 4, 64, 60, 12, 80, 76, 20, 96, 92, 28, // 24-27 120,120, 64, 148,148,100, 176,176,132, 204,204,168, // 28-31 100,100,100, 116,116,116, 104, 80, 44, 124,104, 72, // 32-35 152,132, 92, 184,160,120, 212,188,148, 244,220,176, // 36-39 132,132,132, 88, 4, 16, 112, 16, 32, 136, 32, 52, // 40-43 160, 56, 76, 188, 84,108, 204,104,124, 220,132,144, // 44-47 236,156,164, 252,188,192, 252,208, 0, 252,232, 60, // 48-51 252,252,128, 76, 40, 0, 96, 60, 8, 116, 88, 28, // 52-55 136,116, 56, 156,136, 80, 176,156,108, 196,180,136, // 56-59 68, 24, 0, 96, 44, 4, 128, 68, 8, 156, 96, 16, // 60-63 184,120, 24, 212,156, 32, 232,184, 16, 252,212, 0, // 64-67 252,248,128, 252,252,192, 32, 4, 0, 64, 20, 8, // 68-71 84, 28, 16, 108, 44, 28, 128, 56, 40, 148, 72, 56, // 72-75 168, 92, 76, 184,108, 88, 196,128,108, 212,148,128, // 76-79 8, 52, 0, 16, 64, 0, 32, 80, 4, 48, 96, 4, // 80-83 64,112, 12, 84,132, 20, 104,148, 28, 128,168, 44, // 84-87 64, 64, 64, 44, 68, 32, 60, 88, 48, 80,104, 60, // 88-91 104,124, 76, 128,148, 92, 152,176,108, 180,204,124, // 92-95 16, 52, 24, 32, 72, 44, 56, 96, 72, 76,116, 88, // 96-99 96,136,108, 120,164,136, 152,192,168, 184,220,200, // 100-103 32, 24, 0, 56, 28, 0, 80, 80, 80, 88, 52, 12, // 104-107 104, 64, 24, 124, 84, 44, 140,108, 64, 160,128, 88, // 108-111 76, 40, 16, 96, 52, 24, 116, 68, 40, 136, 84, 56, // 112-115 164, 96, 64, 184,112, 80, 204,128, 96, 212,148,112, // 116-119 224,168,128, 236,188,148, 80, 28, 4, 100, 40, 20, // 120-123 120, 56, 40, 140, 76, 64, 160,100, 96, 184,136,136, // 124-127 36, 40, 68, 48, 52, 84, 64, 64,100, 80, 80,116, // 128-131 100,100,136, 132,132,164, 172,172,192, 212,212,224, // 132-135 48, 48, 48, 64, 44,144, 88, 64,172, 104, 76,196, // 136-139 120, 88,224, 140,104,252, 160,136,252, 188,168,252, // 140-143 0, 24,108, 0, 36,132, 0, 52,160, 0, 72,184, // 144-147 0, 96,212, 24,120,220, 56,144,232, 88,168,240, // 148-151 128,196,252, 188,224,252, 16, 64, 96, 24, 80,108, // 152-155 40, 96,120, 52,112,132, 80,140,160, 116,172,192, // 156-159 156,204,220, 204,240,252, 172, 52, 52, 212, 52, 52, // 160-163 252, 52, 52, 252,100, 88, 252,144,124, 252,184,160, // 164-167 252,216,200, 252,244,236, 72, 20,112, 92, 44,140, // 168-171 112, 68,168, 140,100,196, 168,136,224, 200,176,248, // 172-175 208,184,255, 232,208,252, 60, 0, 0, 92, 0, 0, // 176-179 128, 0, 0, 160, 0, 0, 196, 0, 0, 224, 0, 0, // 180-183 252, 0, 0, 252, 80, 0, 252,108, 0, 252,136, 0, // 184-187 252,164, 0, 252,192, 0, 252,220, 0, 252,252, 0, // 188-191 204,136, 8, 228,144, 4, 252,156, 0, 252,176, 48, // 192-195 252,196,100, 252,216,152, 8, 24, 88, 12, 36,104, // 196-199 20, 52,124, 28, 68,140, 40, 92,164, 56,120,188, // 200-203 72,152,216, 100,172,224, 92,156, 52, 108,176, 64, // 204-207 124,200, 76, 144,224, 92, 224,244,252, 200,236,248, // 208-211 180,220,236, 132,188,216, 88,152,172, 16, 16, 16, // 212-215 32, 32, 32, 28,108,124, 32,112,128, 36,116,132, // 216-219 40,120,136, 44,124,140, 92,164,184, 116,180,196, // 220-223 216,244,252, 112,176,192, 88,160,180, 76, 24, 8, // 224-227 108, 44, 24, 144, 72, 52, 176,108, 84, 210,146,126, // 228-231 252, 60, 0, 252, 84, 0, 252,104, 0, 252,124, 0, // 232-235 252,148, 0, 252,172, 0, 252,196, 0, 64, 0, 0, // 236-239 255, 0, 0, 48, 48, 0, 64, 64, 0, 80, 80, 0, // 240-243 255,255, 0, 148,148,148, 247, 0,247, 248, 0,248, // 244-247 249, 0,249, 250, 0,250, 251, 0,251, 252, 0,252, // 248-251 253, 0,253, 254, 0,254, 255, 0,255, 255,255,255, // 252-255 }, // PAL_tt1_norm { 0, 0,255, 16, 16, 16, 32, 32, 32, 48, 48, 48, // 0-3 68, 68, 68, 84, 84, 84, 100,100,100, 116,116,116, // 4-7 136,136,136, 152,152,152, 168,168,168, 184,184,184, // 8-11 204,204,204, 220,220,220, 236,236,236, 252,252,252, // 12-15 204,204,168, 184,184,152, 168,168,116, 152,152,100, // 16-19 136,136, 84, 100,100, 68, 84, 84, 48, 68, 68, 32, // 20-23 48, 48, 16, 252,220,116, 252,204, 68, 252,184, 32, // 24-27 220,152, 48, 184,132, 48, 148,120, 52, 116,100, 48, // 28-31 100, 84, 48, 84, 68, 32, 68, 48, 16, 0, 0, 44, // 32-35 4, 12, 68, 8, 24, 88, 12, 36,104, 20, 52,124, // 36-39 28, 68,140, 40, 92,164, 56,120,188, 72,152,216, // 40-43 100,172,224, 132,196,236, 168,216,244, 204,236,252, // 44-47 48, 0, 0, 80, 0, 0, 108, 4, 4, 136, 12, 12, // 48-51 164, 20, 20, 196, 32, 32, 224, 44, 44, 252, 56, 56, // 52-55 84, 32, 0, 100, 48, 0, 132, 64, 0, 168, 80, 0, // 56-59 200, 96, 0, 236,152, 0, 236,184, 68, 252,236,136, // 60-63 124,140, 60, 116,128, 48, 104,116, 36, 96,104, 28, // 64-67 84, 92, 20, 76, 80, 12, 68, 72, 4, 56, 60, 0, // 68-71 48, 48, 0, 252, 60, 0, 252, 96, 0, 252,128, 0, // 72-75 252,164, 0, 252,196, 0, 48, 16, 0, 68, 32, 0, // 76-79 100, 48, 16, 116, 68, 32, 136, 84, 32, 168,100, 48, // 80-83 184,116, 48, 220,136, 68, 236,152, 84, 236,168,100, // 84-87 252,184,116, 252,204,136, 108, 92, 92, 132, 88, 88, // 88-91 148, 80, 80, 164, 64, 64, 40, 16, 92, 64, 48,136, // 92-95 88, 64,172, 112, 84,212, 140,100,252, 160,140,252, // 96-99 204,192,180, 184,172,152, 164,148,132, 144,132,112, // 100-103 120,100, 76, 96, 72, 48, 68, 48, 24, 44, 28, 12, // 104-107 56, 44, 12, 56, 64, 32, 64, 48, 0, 100, 68, 28, // 108-111 84, 68, 0, 116,184,160, 88,160,124, 64,136, 92, // 112-115 44,116, 60, 24, 92, 32, 12, 72, 12, 0, 52, 0, // 116-119 116,116, 84, 168,152,100, 220,204,136, 252,236,168, // 120-123 116,100, 84, 152,136,116, 204,184,168, 252,220,204, // 124-127 200,132,108, 192,120, 96, 176,100, 80, 168, 88, 68, // 128-131 148, 68, 52, 132, 48, 36, 116, 32, 20, 100, 28, 12, // 132-135 68, 12, 0, 32, 16, 0, 112,140, 24, 80,124, 16, // 136-139 56,108, 12, 36, 96, 4, 40, 84, 16, 36, 72, 0, // 140-143 36, 64, 0, 136, 96, 60, 124, 84, 44, 112, 68, 32, // 144-147 100, 56, 20, 88, 44, 12, 72, 36, 4, 56, 24, 0, // 148-151 16, 16, 48, 32, 32, 68, 48, 48,100, 68, 72,120, // 152-155 92, 96,140, 120,120,164, 152,152,184, 168,168,204, // 156-159 180,196,116, 168,184, 84, 148,168, 84, 128,156, 80, // 160-163 112,140, 80, 96,124, 76, 72,100, 60, 52, 76, 48, // 164-167 32, 48, 32, 200,116, 32, 176,100, 24, 156, 84, 16, // 168-171 132, 72, 12, 112, 56, 4, 88, 40, 0, 68, 28, 0, // 172-175 252,252,180, 252,100,100, 148,204,168, 180,208,128, // 176-179 236,188,148, 228,172,132, 220,160,120, 212,144,108, // 180-183 204,128, 96, 196,116, 84, 184,104, 72, 168, 96, 64, // 184-187 148, 84, 52, 128, 76, 40, 112, 64, 32, 92, 52, 20, // 188-191 180,124,112, 172,104,100, 164, 88, 84, 132, 72, 68, // 192-195 104, 48, 48, 80, 32, 32, 241, 0,241, 242, 0,242, // 196-199 243, 0,243, 244, 0,244, 245, 0,245, 246, 0,246, // 200-203 247, 0,247, 248, 0,248, 249, 0,249, 250, 0,250, // 204-207 198,132,108, 190,120, 96, 174,100, 80, 166, 88, 68, // 208-211 146, 68, 52, 130, 48, 36, 114, 32, 20, 98, 28, 12, // 212-215 66, 12, 0, 30, 16, 0, 251, 0,251, 252, 0,252, // 216-219 253, 0,253, 254, 0,254, 255, 0,255, 0,188, 80, // 220-223 4,188, 92, 122,124,124, 142,144,144, 162,164,164, // 224-227 182,184,184, 202,204,204, 222,224,224, 242,244,244, // 228-231 32, 68,112, 255, 60, 0, 255, 84, 0, 255,108, 0, // 232-235 255,132, 0, 255,156, 0, 255,180, 0, 255,204, 0, // 236-239 50, 50, 0, 64, 64, 0, 78, 78, 0, 255,255, 0, // 240-243 72,100,144, 100,132,168, 216,244,252, 96,128,164, // 244-247 68, 96,140, 64, 0, 0, 255, 0, 0, 36, 72,116, // 248-251 40, 76,120, 44, 80,124, 48, 84,128, 255,255,255, // 252-255 }, // PAL_tt1_mars { 0, 0,255, 16, 16, 16, 32, 32, 32, 48, 48, 48, // 0-3 68, 68, 68, 84, 84, 84, 100,100,100, 116,116,116, // 4-7 136,136,136, 152,152,152, 168,168,168, 184,184,184, // 8-11 204,204,204, 220,220,220, 236,236,236, 252,252,252, // 12-15 204,204,168, 184,184,152, 168,168,116, 152,152,100, // 16-19 136,136, 84, 100,100, 68, 84, 84, 48, 68, 68, 32, // 20-23 48, 48, 16, 252,220,116, 252,204, 68, 252,184, 32, // 24-27 220,152, 48, 184,132, 48, 148,120, 52, 116,100, 48, // 28-31 100, 84, 48, 84, 68, 32, 68, 48, 16, 0, 0, 44, // 32-35 4, 12, 68, 8, 24, 88, 12, 36,104, 20, 52,124, // 36-39 28, 68,140, 40, 92,164, 56,120,188, 72,152,216, // 40-43 100,172,224, 132,196,236, 168,216,244, 204,236,252, // 44-47 48, 0, 0, 80, 0, 0, 108, 4, 4, 136, 12, 12, // 48-51 164, 20, 20, 196, 32, 32, 224, 44, 44, 252, 56, 56, // 52-55 84, 32, 0, 100, 48, 0, 132, 64, 0, 168, 80, 0, // 56-59 200, 96, 0, 236,152, 0, 236,184, 68, 252,236,136, // 60-63 124,140, 60, 116,128, 48, 104,116, 36, 96,104, 28, // 64-67 84, 92, 20, 76, 80, 12, 68, 72, 4, 56, 60, 0, // 68-71 48, 48, 0, 252, 60, 0, 252, 96, 0, 252,128, 0, // 72-75 252,164, 0, 252,196, 0, 48, 16, 0, 68, 32, 0, // 76-79 100, 48, 16, 116, 68, 32, 136, 84, 32, 168,100, 48, // 80-83 184,116, 48, 220,136, 68, 236,152, 84, 236,168,100, // 84-87 252,184,116, 252,204,136, 108, 92, 92, 132, 88, 88, // 88-91 148, 80, 80, 164, 64, 64, 40, 16, 92, 64, 48,136, // 92-95 88, 64,172, 112, 84,212, 140,100,252, 160,140,252, // 96-99 204,192,180, 184,172,152, 164,148,132, 144,132,112, // 100-103 120,100, 76, 96, 72, 48, 68, 48, 24, 44, 28, 12, // 104-107 56, 44, 12, 56, 64, 32, 64, 48, 0, 100, 68, 28, // 108-111 84, 68, 0, 116,184,160, 88,160,124, 64,136, 92, // 112-115 44,116, 60, 24, 92, 32, 12, 72, 12, 0, 52, 0, // 116-119 116,116, 84, 168,152,100, 220,204,136, 252,236,168, // 120-123 116,100, 84, 152,136,116, 204,184,168, 252,220,204, // 124-127 200,132,108, 192,120, 96, 176,100, 80, 168, 88, 68, // 128-131 148, 68, 52, 132, 48, 36, 116, 32, 20, 100, 28, 12, // 132-135 68, 12, 0, 32, 16, 0, 112,140, 24, 80,124, 16, // 136-139 56,108, 12, 36, 96, 4, 40, 84, 16, 36, 72, 0, // 140-143 36, 64, 0, 136, 96, 60, 124, 84, 44, 112, 68, 32, // 144-147 100, 56, 20, 88, 44, 12, 72, 36, 4, 56, 24, 0, // 148-151 16, 16, 48, 32, 32, 68, 48, 48,100, 68, 72,120, // 152-155 92, 96,140, 120,120,164, 152,152,184, 168,168,204, // 156-159 180,196,116, 168,184, 84, 148,168, 84, 128,156, 80, // 160-163 112,140, 80, 96,124, 76, 72,100, 60, 52, 76, 48, // 164-167 32, 48, 32, 200,116, 32, 176,100, 24, 156, 84, 16, // 168-171 132, 72, 12, 112, 56, 4, 88, 40, 0, 68, 28, 0, // 172-175 252,252,180, 252,100,100, 148,204,168, 180,208,128, // 176-179 236,188,148, 228,172,132, 220,160,120, 212,144,108, // 180-183 204,128, 96, 196,116, 84, 184,104, 72, 168, 96, 64, // 184-187 148, 84, 52, 128, 76, 40, 112, 64, 32, 92, 52, 20, // 188-191 180,124,112, 172,104,100, 164, 88, 84, 132, 72, 68, // 192-195 104, 48, 48, 80, 32, 32, 241, 0,241, 242, 0,242, // 196-199 243, 0,243, 244, 0,244, 245, 0,245, 246, 0,246, // 200-203 247, 0,247, 248, 0,248, 249, 0,249, 250, 0,250, // 204-207 198,132,108, 190,120, 96, 174,100, 80, 166, 88, 68, // 208-211 146, 68, 52, 130, 48, 36, 114, 32, 20, 98, 28, 12, // 212-215 66, 12, 0, 30, 16, 0, 251, 0,251, 252, 0,252, // 216-219 253, 0,253, 254, 0,254, 255, 0,255, 0,188, 80, // 220-223 4,188, 92, 122,124,124, 142,144,144, 162,164,164, // 224-227 182,184,184, 202,204,204, 222,224,224, 242,244,244, // 228-231 116, 0, 0, 255, 60, 0, 255, 84, 0, 255,108, 0, // 232-235 255,132, 0, 255,156, 0, 255,180, 0, 255,204, 0, // 236-239 50, 50, 0, 64, 64, 0, 78, 78, 0, 255,255, 0, // 240-243 156, 40, 12, 200, 76, 68, 228,112,108, 208, 84, 76, // 244-247 164, 48, 20, 64, 0, 0, 255, 0, 0, 124, 4, 0, // 248-251 136, 16, 4, 148, 28, 8, 160, 44, 16, 255,255,255, // 252-255 }, // PAL_ttw_pb_pal1 { 0, 0,255, 238, 0,238, 239, 0,239, 240, 0,240, // 0-3 241, 0,241, 242, 0,242, 243, 0,243, 244, 0,244, // 4-7 245, 0,245, 246, 0,246, 168,168,168, 184,184,184, // 8-11 200,200,200, 216,216,216, 232,232,232, 252,252,252, // 12-15 52, 60, 72, 68, 76, 92, 88, 96,112, 108,116,132, // 16-19 132,140,152, 156,160,172, 176,184,196, 204,208,220, // 20-23 48, 44, 4, 64, 60, 12, 80, 76, 20, 96, 92, 28, // 24-27 120,120, 64, 148,148,100, 176,176,132, 204,204,168, // 28-31 100,100,100, 116,116,116, 104, 80, 44, 124,104, 72, // 32-35 152,132, 92, 184,160,120, 212,188,148, 244,220,176, // 36-39 132,132,132, 88, 4, 16, 112, 16, 32, 136, 32, 52, // 40-43 160, 56, 76, 188, 84,108, 204,104,124, 220,132,144, // 44-47 236,156,164, 252,188,192, 252,208, 0, 252,232, 60, // 48-51 252,252,128, 76, 40, 0, 96, 60, 8, 116, 88, 28, // 52-55 136,116, 56, 156,136, 80, 176,156,108, 196,180,136, // 56-59 68, 24, 0, 96, 44, 4, 128, 68, 8, 156, 96, 16, // 60-63 184,120, 24, 212,156, 32, 232,184, 16, 252,212, 0, // 64-67 252,248,128, 252,252,192, 32, 4, 0, 64, 20, 8, // 68-71 84, 28, 16, 108, 44, 28, 128, 56, 40, 148, 72, 56, // 72-75 168, 92, 76, 184,108, 88, 196,128,108, 212,148,128, // 76-79 8, 52, 0, 16, 64, 0, 32, 80, 4, 48, 96, 4, // 80-83 64,112, 12, 84,132, 20, 104,148, 28, 128,168, 44, // 84-87 64, 64, 64, 44, 68, 32, 60, 88, 48, 80,104, 60, // 88-91 104,124, 76, 128,148, 92, 152,176,108, 180,204,124, // 92-95 16, 52, 24, 32, 72, 44, 56, 96, 72, 76,116, 88, // 96-99 96,136,108, 120,164,136, 152,192,168, 184,220,200, // 100-103 32, 24, 0, 56, 28, 0, 80, 80, 80, 88, 52, 12, // 104-107 104, 64, 24, 124, 84, 44, 140,108, 64, 160,128, 88, // 108-111 76, 40, 16, 96, 52, 24, 116, 68, 40, 136, 84, 56, // 112-115 164, 96, 64, 184,112, 80, 204,128, 96, 212,148,112, // 116-119 224,168,128, 236,188,148, 80, 28, 4, 100, 40, 20, // 120-123 120, 56, 40, 140, 76, 64, 160,100, 96, 184,136,136, // 124-127 36, 40, 68, 48, 52, 84, 64, 64,100, 80, 80,116, // 128-131 100,100,136, 132,132,164, 172,172,192, 212,212,224, // 132-135 48, 48, 48, 64, 44,144, 88, 64,172, 104, 76,196, // 136-139 120, 88,224, 140,104,252, 160,136,252, 188,168,252, // 140-143 0, 24,108, 0, 36,132, 0, 52,160, 0, 72,184, // 144-147 0, 96,212, 24,120,220, 56,144,232, 88,168,240, // 148-151 128,196,252, 188,224,252, 16, 64, 96, 24, 80,108, // 152-155 40, 96,120, 52,112,132, 80,140,160, 116,172,192, // 156-159 156,204,220, 204,240,252, 172, 52, 52, 212, 52, 52, // 160-163 252, 52, 52, 252,100, 88, 252,144,124, 252,184,160, // 164-167 252,216,200, 252,244,236, 72, 20,112, 92, 44,140, // 168-171 112, 68,168, 140,100,196, 168,136,224, 200,176,248, // 172-175 208,184,255, 232,208,252, 60, 0, 0, 92, 0, 0, // 176-179 128, 0, 0, 160, 0, 0, 196, 0, 0, 224, 0, 0, // 180-183 252, 0, 0, 252, 80, 0, 252,108, 0, 252,136, 0, // 184-187 252,164, 0, 252,192, 0, 252,220, 0, 252,252, 0, // 188-191 204,136, 8, 228,144, 4, 252,156, 0, 252,176, 48, // 192-195 252,196,100, 252,216,152, 8, 24, 88, 12, 36,104, // 196-199 20, 52,124, 28, 68,140, 40, 92,164, 56,120,188, // 200-203 72,152,216, 100,172,224, 92,156, 52, 108,176, 64, // 204-207 124,200, 76, 144,224, 92, 224,244,252, 200,236,248, // 208-211 180,220,236, 132,188,216, 88,152,172, 16, 16, 16, // 212-215 32, 32, 32, 32, 68,112, 36, 72,116, 40, 76,120, // 216-219 44, 80,124, 48, 84,128, 72,100,144, 100,132,168, // 220-223 216,244,252, 96,128,164, 68, 96,140, 255, 0,255, // 224-227 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 228-231 252, 60, 0, 252, 84, 0, 252,104, 0, 252,124, 0, // 232-235 252,148, 0, 252,172, 0, 252,196, 0, 64, 0, 0, // 236-239 255, 0, 0, 255, 0,255, 255, 0,255, 255, 0,255, // 240-243 255, 0,255, 148,148,148, 247, 0,247, 248, 0,248, // 244-247 249, 0,249, 250, 0,250, 251, 0,251, 252, 0,252, // 248-251 253, 0,253, 254, 0,254, 255, 0,255, 255,255,255, // 252-255 }, // PAL_ttw_pb_pal2 { 0, 0,255, 238, 0,238, 239, 0,239, 240, 0,240, // 0-3 241, 0,241, 242, 0,242, 243, 0,243, 244, 0,244, // 4-7 245, 0,245, 246, 0,246, 168,168,168, 184,184,184, // 8-11 200,200,200, 216,216,216, 232,232,232, 252,252,252, // 12-15 52, 60, 72, 68, 76, 92, 88, 96,112, 108,116,132, // 16-19 132,140,152, 156,160,172, 176,184,196, 204,208,220, // 20-23 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 24-27 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 28-31 100,100,100, 116,116,116, 255, 0,255, 255, 0,255, // 32-35 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 36-39 132,132,132, 255, 0,255, 255, 0,255, 255, 0,255, // 40-43 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 44-47 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 48-51 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 52-55 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 56-59 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 60-63 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 64-67 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 68-71 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 72-75 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 76-79 8, 52, 0, 16, 64, 0, 32, 80, 4, 48, 96, 4, // 80-83 64,112, 12, 84,132, 20, 104,148, 28, 128,168, 44, // 84-87 64, 64, 64, 255, 0,255, 255, 0,255, 255, 0,255, // 88-91 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 92-95 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 96-99 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 100-103 32, 24, 0, 56, 28, 0, 80, 80, 80, 255, 0,255, // 104-107 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 108-111 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 112-115 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 116-119 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 120-123 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 124-127 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 128-131 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 132-135 48, 48, 48, 255, 0,255, 255, 0,255, 255, 0,255, // 136-139 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 140-143 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 144-147 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 148-151 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 152-155 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 156-159 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 160-163 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 164-167 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 168-171 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 172-175 255, 0,255, 255, 0,255, 60, 0, 0, 92, 0, 0, // 176-179 128, 0, 0, 160, 0, 0, 196, 0, 0, 224, 0, 0, // 180-183 252, 0, 0, 252, 80, 0, 252,108, 0, 252,136, 0, // 184-187 252,164, 0, 252,192, 0, 252,220, 0, 252,252, 0, // 188-191 204,136, 8, 228,144, 4, 252,156, 0, 252,176, 48, // 192-195 252,196,100, 252,216,152, 8, 24, 88, 12, 36,104, // 196-199 20, 52,124, 28, 68,140, 40, 92,164, 56,120,188, // 200-203 72,152,216, 100,172,224, 255, 0,255, 255, 0,255, // 204-207 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 208-211 255, 0,255, 255, 0,255, 255, 0,255, 16, 16, 16, // 212-215 32, 32, 32, 255, 0,255, 255, 0,255, 255, 0,255, // 216-219 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 220-223 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 224-227 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 228-231 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 232-235 255, 0,255, 255, 0,255, 255, 0,255, 255, 0,255, // 236-239 255, 0, 0, 255, 0,255, 255, 0,255, 255, 0,255, // 240-243 255, 0,255, 148,148,148, 247, 0,247, 248, 0,248, // 244-247 249, 0,249, 250, 0,250, 251, 0,251, 252, 0,252, // 248-251 253, 0,253, 254, 0,254, 255, 0,255, 255, 0,255, // 252-255 }, }; #endif // DEFINE_PALS grfcodec-6.0.3/src/path.h0000644000000000000000000000103612027143046013665 0ustar rootroot#ifndef _PATH_H #define _PATH_H #include #include #include "typesize.h" #define WILDCARDS 0x01 #define EXTENSION 0x02 #define FILENAME 0x04 #define DIRECTORY 0x08 #define DRIVE 0x10 #define MAXPATH 1024 #define MAXDRIVE 3 #define MAXDIR 1024 #define MAXFILE 1024 #define MAXEXT 32 void fnmerge(register char *pathP, const char *driveP, const char *dirP, const char *nameP, const char *extP); int fnsplit(const char *pathP, char *driveP, char *dirP, char *nameP, char *extP); #endif /* _PATH_H */ grfcodec-6.0.3/src/language_mgr.h0000644000000000000000000000524712027143046015371 0ustar rootroot/* * language_mgr.h * Declares classes and functions for management of program language. * * Copyright (c) 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_LANGUAGE_MGR_H_INCLUDED_ #define _RENUM_LANGUAGE_MGR_H_INCLUDED_ #include #ifdef _MSC_VER #pragma warning (disable : 4702) // warning C4702: unreachable code #endif #include #ifdef _MSC_VER #pragma warning (default : 4702) #endif #include "singleton.h" // ------- // Generate type RenumLanguageId to be an enum of // all the supported language IDs. #ifndef RENUM_LANGUAGE #define START_LANGUAGES() typedef enum { #define RENUM_LANGUAGE(name,code)name, #define END_LANGUAGES() } RenumLanguageId; #endif // RENUM_LANGUAGE #include "lang/language_list.h" // ------- /*! Default language identifier */ #define RL_DEFAULT RL_ENGLISH /*! Collection mapping strings to language IDs. */ typedef std::map str2lang_map; /*! Handles program language detection and selection. */ class LanguageMgr { SINGLETON(LanguageMgr); public: /*! Gets the current language ID. \return ID of the current language. */ RenumLanguageId GetCurrentLanguage() const { return currentId; }; /*! Change the current language. \param id Language ID to set the current language to. */ void ChangeLanguage(RenumLanguageId id) { currentId = id; }; /*! Detects the current language based on environment variables. */ RenumLanguageId DetectLanguage() const; /*! Decodes a language code into its identifier. \param code A string containing the language code. \return Corresponding language ID, if such a language is supported. Otherwise the function returns RL_DEFAULT. */ RenumLanguageId DecodeLanguageCode(const std::string& code) const; private: /*! Initializes the language map with data about supported languages. */ void InitLanguageMap(); RenumLanguageId currentId; /*!< Current language ID */ str2lang_map codeIdMap; /*!< Maps language codes to identifiers */ }; #endif // _RENUM_LANGUAGE_MGR_H_INCLUDED_ grfcodec-6.0.3/src/message_mgr.cpp0000644000000000000000000001335112027143046015560 0ustar rootroot/* * message_mgr.cpp * Defines classes and functions for handling of program messages in multiple languages. * * Copyright (c) 2004-2006, Dale McCoy. * Copyright (c) 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "version.h" #include "globals.h" #include "message_mgr.h" using namespace std; const string MessageData::commentPrefix = "!!"; MessageData::MessageData(char props_) : textMap() { props = props_; } MessageData::MessageData(char props_, const string& default_text) : textMap() { props = props_; SetText(RL_DEFAULT, default_text); } string MessageData::Display(const string& prefix, va_list& ap) const { string ret = myvsprintf(GetMessage(prefix).c_str(), ap); ostream* const stream[] = {pErr, pOut, pNfo}; if((props & TO_MASK) != TO_NULL) (*(stream[(props & TO_MASK) >> TO_SHIFT])) << ret; return ret; } const string& MessageData::GetText() const { lang2str_map::const_iterator pos = textMap.find( LanguageMgr::Instance().GetCurrentLanguage()); if(pos == textMap.end()) { pos = textMap.find(RL_DEFAULT); if(pos == textMap.end()) { return MessageMgr::UNDEFINED_TEXT; } } return pos->second; } void MessageData::SetText(RenumLanguageId lang, const string& text) { textMap[lang] = text; } string MessageData::GetMessage(const string& prefix) const { string ret = GetText(); if(props & HAS_OFFSET) ret = MessageMgr::Instance().GetExtraText(OFFSET) + ret; if(props & USE_PREFIX) ret = prefix + ret; if(props & MAKE_COMMENT) ret = COMMENT_PREFIX + commentPrefix + ret; return ret; } // -------- const string MessageMgr::UNDEFINED_TEXT = "UNDEFINED_TEXT"; const MessageData MessageMgr::UNKNOWN_MESSAGE = MessageData(0,"UNKNOWN_MESSAGE"); MessageMgr::MessageMgr() { InitMessages(); InitMessageTexts(); InitExtraTexts(); } const MessageData& MessageMgr::GetMessageData(RenumMessageId i) const { msgid2data_map::const_iterator pos = msgDataMap.find(i); if(pos != msgDataMap.end()) { return pos->second; } return UNKNOWN_MESSAGE; } const std::string& MessageMgr::GetExtraText(RenumExtraTextId i) const { extid2data_map::const_iterator pos = extraTextMap.find(i); if(pos == extraTextMap.end()) { return UNDEFINED_TEXT; } const lang2str_map& textMap = pos->second; lang2str_map::const_iterator textPos = textMap.find( LanguageMgr::Instance().GetCurrentLanguage()); if(textPos == textMap.end()) { textPos = textMap.find(RL_DEFAULT); if(textPos == textMap.end()) { return UNDEFINED_TEXT; } } return textPos->second; } bool MessageMgr::AddMessage(RenumMessageId i, char props) { return msgDataMap.insert(make_pair(i, MessageData(props))).second; } bool MessageMgr::SetMessageText(RenumMessageId i, RenumLanguageId lang, const std::string& text) { msgid2data_map::iterator pos = msgDataMap.find(i); if(pos != msgDataMap.end()) { pos->second.SetText(lang, text); return true; } return false; } void MessageMgr::SetExtraText(RenumExtraTextId i, RenumLanguageId lang, const std::string& text) { extid2data_map::iterator pos = extraTextMap.find(i); if(pos == extraTextMap.end()) { pos = extraTextMap.insert(make_pair(i,lang2str_map())).first; } pos->second.insert(make_pair(lang, text)); } // ------- // Generate a function to initialize the message map with message data containing // the properties for all the supported messages. #undef MESSAGE #undef START_MESSAGES #undef END_MESSAGES #define START_MESSAGES(lang) void MessageMgr::InitMessages() { #define MESSAGE(name,message,props) AddMessage(name, props); #define END_MESSAGES() } #include "lang/message_english.h" // ------- // Generate functions to add message texts to all the messages // for each of the supported languages. #undef MESSAGE #undef START_MESSAGES #undef END_MESSAGES #define START_MESSAGES(lang) void InitMessageTexts_##lang(MessageMgr& msgmgr) { \ RenumLanguageId langId = lang; #define MESSAGE(name,message,props) msgmgr.SetMessageText(name,langId, message); #define END_MESSAGES() } #include "lang/all_messages.h" // ------- // Generate a master function to call all the individual message text // initialization functions. #undef START_LANGUAGES #undef RENUM_LANGUAGE #undef END_LANGUAGES #define START_LANGUAGES() void MessageMgr::InitMessageTexts() { #define RENUM_LANGUAGE(name,code) InitMessageTexts_##name(*this); #define END_LANGUAGES() } #include "lang/language_list.h" // ------- // Generate functions to initialize extra texts for each of the // supported languages. #undef EXTRA #undef START_EXTRA_STRINGS #undef END_EXTRA_STRINGS #define START_EXTRA_STRINGS(lang) void InitExtraTexts_##lang(MessageMgr& msgmgr) { \ RenumLanguageId langId = lang; #define EXTRA(name,str) msgmgr.SetExtraText(name, langId, str); #define END_EXTRA_STRINGS() } #include "lang/all_extra.h" // ------- // Generate a master function to call all the individual extra text // initialization functions. #undef START_LANGUAGES #undef RENUM_LANGUAGE #undef END_LANGUAGES #define START_LANGUAGES() void MessageMgr::InitExtraTexts() { #define RENUM_LANGUAGE(name,code) InitExtraTexts_##name(*this); #define END_LANGUAGES() } #include "lang/language_list.h" grfcodec-6.0.3/src/error.cpp0000644000000000000000000000035612027143046014421 0ustar rootroot #include #include #include "error.h" void fperror(const char *format, ...) { char buffer[256]; va_list argptr; va_start(argptr, format); vsprintf(buffer, format, argptr); va_end(argptr); perror(buffer); } grfcodec-6.0.3/src/sanity.h0000644000000000000000000000242612027143046014244 0ustar rootroot/* * sanity.h * Declares general functions for sprite sanity checking. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_SANITY_H_INCLUDED_ #define _RENUM_SANITY_H_INCLUDED_ class PseudoSprite; enum SpriteType{REAL,PSEUDO,INCLUDE,RECOLOR}; void reset_sanity(); void check_sprite(SpriteType);//real/include void check_sprite(PseudoSprite&);//Pseudo void final_sanity(); void sanity_use_id(int); void sanity_use_set(int); void sanity_test_id(int); int sanity_locate_id(int); void sanity_define_id(int,int); int sanity_get_feature(int); #endif//_RENUM_SANITY_H_DEFINED grfcodec-6.0.3/src/pngsprit.cpp0000644000000000000000000001437212171043637015146 0ustar rootroot#ifdef WITH_PNG #include "pngsprit.h" #include "ttdpal.h" #include "grfcomm.h" /***********************\ * * * class pngwrite * * * \***********************/ pngwrite::pngwrite(multifile *mfile, bool paletted): pcxwrite(mfile), png(NULL), info(NULL) { this->paletted = paletted; // Hopefully 8MiB should suffice cache.reserve(8*1024*1024); } pngwrite::~pngwrite() { // Make sure we clean up if grfcodec terminates prematurely if (png) png_destroy_write_struct(&png, &info); } void pngwrite::filestart(bool paletted) { // Create the libpng structs png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(png); if (!png || !info) { printf("%s: Agh! Unable to initialize libpng!\n", this->filename()); exit (254); } // Set the error out point if (setjmp(png_jmpbuf(png))) { exit (252); } } void pngwrite::filedone(int final) { // Do not save the png until the grf file has been processed if (final && png && cache.size() > 0) { // Initialise libpng io png_init_io(png, curfile); if (paletted) { // Store the final image's size png_set_IHDR(png, info, sx, totaly, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // Set the palette data png_set_PLTE(png, info, (png_color*)pcxwrite::palette, 256); } else { // Store the final image's size png_set_IHDR(png, info, sx, totaly, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } // Write the the png header png_write_info(png, info); // Flush the header and every so many lines png_write_flush(png); png_set_flush(png, 64); // Write the image data for (unsigned int i = 0, j = cache.size(); i < j; i += sx * (paletted ? 1 : 4)) png_write_row(png, (png_byte*)&cache[i]); // Finalise writing png_write_end(png, info); // Cleanup incase we are writing multiple files png_destroy_write_struct(&png, &info); cache.clear(); png = NULL; info = NULL; } } // Hooks the writing of lines out to file, // which we will be buffering internally void pngwrite::encodebytes(const CommonPixel &pixel, int num) { for (int i = 0; i < num; i++) { if (paletted) { cache.push_back(pixel.m); } else { cache.push_back(pixel.r); cache.push_back(pixel.g); cache.push_back(pixel.b); cache.push_back(pixel.a); } } } void pngwrite::encodebytes(const CommonPixel *buffer, int num) { for (int i = 0; i < num; i++) this->encodebytes(buffer[i], 1); } /***********************\ * * * class pngread * * * \***********************/ pngread::pngread(singlefile *mfile): pcxread(mfile), png(NULL), info(NULL), line_buffer(NULL), whole_image(NULL) { } pngread::~pngread() { if (png) png_destroy_read_struct(&png, &info, NULL); delete[] line_buffer; if (whole_image != NULL) { for (int i = 0; i < sy; ++i) { delete[] whole_image[i]; } delete[] whole_image; } } void pngread::setline(CommonPixel *band) { U8 *row; if (whole_image != NULL) { // Already read the whole image row = whole_image[read_row++]; } else { // Read the next row of the png file png_read_row(png, line_buffer, NULL); row = line_buffer; } for (int i = 0; i < sx; i++) { if (paletted) { band[i].m = row[i]; } else { band[i].r = row[i * 4]; band[i].g = row[i * 4 + 1]; band[i].b = row[i * 4 + 2]; band[i].a = row[i * 4 + 3]; } } } extern bool _force; extern int _quiet; void pngread::filestart(bool paletted) { this->paletted=paletted; if (png) { // Technically this should never be reached but as a safety net png_read_end(png, info); png_destroy_read_struct(&png, &info, NULL); } png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(png); if (!png || !info) { printf("%s: Agh! Unable to initialize libpng!\n", this->filename()); exit (254); } // Set the error out point if (setjmp(png_jmpbuf(png))) { exit (252); } // Reset the file back to the start fseek(curfile, 0, SEEK_SET); // Do a quick header check U8 header[8]; cfread("reading png header", header, 1, 8, curfile); if (png_sig_cmp((png_byte *)header, 0, 8)) { fprintf(stderr, "%s: Unrecognized file signature!\n", this->filename()); exit(2); } // Read in the information png_init_io(png, curfile); png_set_sig_bytes(png, 8); png_read_info(png, info); if (paletted) { // Colour depth / format if (png_get_channels(png, info) >= 3) { fprintf(stderr, "%s: Cannot read true colour PNG files!\n", this->filename()); exit(2); } if (png_get_channels(png, info) != 1 || png_get_bit_depth(png, info) != 8 || png_get_color_type(png, info) != PNG_COLOR_TYPE_PALETTE) { fprintf(stderr, "%s: Cannot read non-paletted PNG files!\n", this->filename()); exit(2); } // Gather the png's palette information int entries; U8 *palette; // Compatible format RGB png_get_PLTE(png, info, (png_color**)&palette, &entries); if (entries != 256) { fprintf(stderr, "%s: PNG file is not a 256 colour file!\n", this->filename()); exit(2); } // Look for a matching palette int i=0; for( ; ifilename()); } else { fprintf(stderr, "%s: Error: Unrecognized palette, aborting.\n" "Specify -f on the command line to override this check.\n", this->filename()); exit(2); } } } else { if (png_get_channels(png, info) != 4) { fprintf(stderr, "%s: Cannot read 32bpp PNG files without alpha layer!\n", this->filename()); exit(2); } } // Store the image dimentions sx = png_get_image_width(png, info); sy = png_get_image_height(png, info); totaly = 0; thisbandy = 0; if (png_get_interlace_type(png, info) == PNG_INTERLACE_NONE) { /* Read image row by row */ line_buffer = new U8[sx * (paletted?1:4)]; } else { /* Interlaced images can only be read as a whole */ read_row = 0; whole_image = new U8*[sy]; for (int i = 0; i < sy; ++i) { whole_image[i] = new U8[sx * (paletted?1:4)]; } png_read_image(png, whole_image); } } #endif /* WITH_PNG */ grfcodec-6.0.3/src/act5.cpp0000644000000000000000000000720512027143046014124 0ustar rootroot/* * act5.cpp * Contains definitions for checking action 5. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include using namespace std; #include"nforenum.h" #include"sanity.h" #include"inlines.h" #include"ExpandingArray.h" #include"sanity_defines.h" #include"data.h" #include"pseudo.h" #include"messages.h" #include"command.h" extern bool _base_grf; class c5{ public: int maxFeature(){return (int)sizes.size()+3;} const vector&operator[](int x)const {return sizes[x-4];} SINGLETON(c5) private: vector >sizes; }; c5::c5(){ FILE*pFile=myfopen(5); vector temp; int ch, count, opts, flags; while((ch=GetCheckByte(5))!=0){ flags = 0; if(ch&0x80){ flags = ch&0x7F; ch=GetCheckByte(5); } count = ch>>4; opts = ch&0xF; for(int i=count;i;i--){ temp.clear(); temp.push_back(flags); for(int j=opts;j;j--) if(flags&4) temp.push_back(GetCheckWord(5)); else temp.push_back(GetCheckByte(5)); sizes.push_back(temp); } } fclose(pFile); } // I finally want to do runtime-generated varargs calls. // But I can't, so I have to manually generate the string instead. void Act5CountWarn(const vector&sizes){ string str = mysprintf("%S",ACT5_SIZE, sizes[1], sizes[1]); int count=(int)sizes.size()-1; switch(count){ case 1: break; default: for(int i=2;ic5::Instance().maxFeature()){ IssueMessage(FATAL,INVALID_FEATURE); return sprites; } const vector&expSprites=c5::Instance()[feature]; if(!hasoffset){ for(int i=(int)expSprites.size();--i;){ // Test [1] ... [.size()-1] if(expSprites[i] == 0)goto countok; if(expSprites[i] == sprites)goto countok; } /* A base GRF may provide 10 sprites for shores. */ if(_base_grf && feature == 0x0D && sprites == 0x0A)goto countok; /* Having more sprites is generally okay for base GRFs as they are then more up-to-date than NFORenum. */ if(_base_grf && feature == 0x15 && sprites > expSprites[0])goto countok; Act5CountWarn(expSprites); }else{ if(!(expSprites[0]&8)) IssueMessage(ERROR,CANNOT_EXTEND); int pastend=sprites + data.ExtractExtended(off); off+=data.ExtendedLen(off); if(expSprites[1] != 0 && expSprites[1] < pastend) IssueMessage(WARNING1, ACTION_5_LIMIT, sprites, pastend-1, expSprites[1]); } countok: if(off * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #define maketype(type,size) \ typedef signed type S ## size; \ typedef unsigned type U ## size; #ifndef _MSC_VER #define strnicmp strncasecmp #define stricmp strcasecmp #endif #ifdef __BORLANDC__ # define HAVE_BYTES # define HAVE_SHORTS # define HAVE_LONGS maketype(char,8) maketype(short,16) maketype(long,32) // disable warnings for "condition is always false" and "unreachable code" #pragma warn -ccc #pragma warn -rch #elif WIN32 # define HAVE_BYTES # define HAVE_SHORTS # define HAVE_LONGS # define HAVE_LONGLONGS maketype(char,8) maketype(short int,16) maketype(long int,32) maketype(long long,64) #elif GCC32 # define HAVE_BYTES # define HAVE_SHORTS # define HAVE_LONGS # define HAVE_LONGLONGS maketype(char,8) maketype(short int,16) maketype(int,32) maketype(long long,64) #elif GCC64 # define HAVE_BYTES # define HAVE_SHORTS # define HAVE_LONGS # define HAVE_LONGLONGS maketype(char,8) maketype(short int,16) maketype(int,32) maketype(long int,64) #else # error Unknown variables sizes, please define. #endif #ifdef _MSC_VER // disable warnings: conversion from $LARGE_SIZE to $SMALL_SIZE #pragma warning(disable:4267 4244) // ... conditional expression is constant #pragma warning(disable:4127) #endif #undef maketype #ifdef DOCHECK void checksizes() { if ( #ifdef HAVE_BYTES (sizeof( S8) != 1) || (sizeof( U8) != 1) || #endif #ifdef HAVE_SHORTS (sizeof(S16) != 2) || (sizeof(U16) != 2) || #endif #ifdef HAVE_LONGS (sizeof(S32) != 4) || (sizeof(U32) != 4) || #endif #ifdef HAVE_LONGLONGS (sizeof(S64) != 8) || (sizeof(U64) != 8) || #endif (0) // the ||(0) is so that all previous lines can end in || ) { printf("Fatal: Incorrectly sized variables.\n"); #define PRINT_SZ(t,s) printf("%s size = %d, expected = %d\n", #t, (int)sizeof(t), s) #ifdef HAVE_BYTES PRINT_SZ(S8,1); PRINT_SZ(U8,1); #endif #ifdef HAVE_SHORTS PRINT_SZ(S16,2); PRINT_SZ(U16,2); #endif #ifdef HAVE_LONGS PRINT_SZ(S32,4); PRINT_SZ(U32,4); #endif #ifdef HAVE_LONGLONGS PRINT_SZ(S64,8); PRINT_SZ(U64,8); #endif #undef PRINT_SZ exit(254); } } #endif /* DOCHECK */ union multitype { U32 u32; S32 s32; U16 u16[2]; S16 s16[2]; U8 u8[4]; S8 s8[4]; }; #ifdef GRFCODEC_BIG_ENDIAN # define BE_SWAP16(b) (*((U8*)(&b))+(*(((U8*)(&b))+1)<<8)) # define BE_SWAP32(b) (*((U8*)(&b))+(*(((U8*)(&b))+1)<<8)+(*(((U8*)(&b))+2)<<16)+(*(((U8*)(&b))+3)<<24)) # define BYTE_OFSL 1 # define BYTE_OFSH 0 #elif defined(GRFCODEC_LITTLE_ENDIAN) # define BE_SWAP16(b) (b) # define BE_SWAP32(b) (b) # define BYTE_OFSL 0 # define BYTE_OFSH 1 #else # error "Endianness not defined!" #endif #endif /* _TYPESIZE_H */ typedef unsigned int uint; grfcodec-6.0.3/src/conv.h0000644000000000000000000000671612027143046013710 0ustar rootroot // convert between DOS and Windows GRF files // map DOS to Windows int palmap0[] = { 0, 215, 216, 136, 88, 106, 32, 33, // 0..7 40, 245, 10, 11, 12, 13, 14, 15, // 8..15 16, 17, 18, 19, 20, 21, 22, 23, // 16..23 24, 25, 26, 27, 28, 29, 30, 31, // 24..31 53, 107, 34, 35, 36, 37, 38, 39, // 32..39 178, 41, 42, 43, 44, 45, 46, 47, // 40..47 48, 49, 50, 51, 52, 53, 54, 55, // 48..55 56, 57, 58, 59, 60, 61, 62, 63, // 56..63 64, 65, 66, 67, 68, 69, 70, 71, // 64..71 72, 73, 74, 75, 76, 77, 78, 79, // 72..79 80, 81, 82, 83, 84, 85, 86, 87, // 80..87 96, 89, 90, 91, 92, 93, 94, 95, // 88..95 96, 97, 98, 99, 100, 101, 102, 103, // 96..103 104, 105, 53, 107, 108, 109, 110, 111, // 104..111 112, 113, 114, 115, 116, 117, 118, 119, // 112..119 120, 121, 122, 123, 124, 125, 126, 127, // 120..127 128, 129, 130, 131, 132, 133, 134, 135, // 128..135 170, 137, 138, 139, 140, 141, 142, 143, // 136..143 144, 145, 146, 147, 148, 149, 150, 151, // 144..151 152, 153, 154, 155, 156, 157, 158, 159, // 152..159 160, 161, 162, 163, 164, 165, 166, 167, // 160..167 168, 169, 170, 171, 172, 173, 174, 175, // 168..175 176, 177, 178, 179, 180, 181, 182, 183, // 176..183 184, 185, 186, 187, 188, 189, 190, 191, // 184..191 192, 193, 194, 195, 196, 197, 198, 199, // 192..199 200, 201, 202, 203, 204, 205, 206, 207, // 200..207 208, 209, 210, 211, 212, 213, 214, 7, // 208..215 8, 9, 246, 247, 248, 249, 250, 251, // 216..223 252, 253, 254, 230, 231, 227, 228, 229, // 224..231 236, 237, 238, 232, 233, 234, 235, 184, // 232..239 70, 241, 242, 244, 243, 220, 221, 217, // 240..247 218, 219, 226, 222, 223, 224, 225, 15, // 248..255 }; // map Windows to DOS int palmap1[] = { 0, 180, 2, 3, 4, 5, 6, 215, // 0..7 216, 219, 10, 11, 12, 13, 14, 15, // 8..15 16, 17, 18, 19, 20, 21, 22, 23, // 16..23 24, 25, 26, 27, 28, 29, 30, 31, // 24..31 6, 7, 34, 35, 36, 37, 38, 39, // 32..39 8, 41, 42, 43, 44, 45, 46, 47, // 40..47 48, 49, 50, 51, 52, 53, 54, 55, // 48..55 56, 57, 58, 59, 60, 61, 62, 63, // 56..63 64, 65, 66, 67, 68, 69, 70, 71, // 64..71 72, 73, 74, 75, 76, 77, 78, 79, // 72..79 80, 81, 82, 83, 84, 85, 86, 87, // 80..87 4, 89, 90, 91, 92, 93, 94, 95, // 88..95 96, 97, 98, 99, 100, 101, 102, 103, // 96..103 104, 105, 5, 107, 108, 109, 110, 111, // 104..111 112, 113, 114, 115, 116, 117, 118, 119, // 112..119 120, 121, 122, 123, 124, 125, 126, 127, // 120..127 128, 129, 130, 131, 132, 133, 134, 135, // 128..135 3, 137, 138, 139, 140, 141, 142, 143, // 136..143 144, 145, 146, 147, 148, 149, 150, 151, // 144..151 152, 153, 154, 155, 156, 157, 158, 159, // 152..159 160, 161, 162, 163, 164, 165, 166, 167, // 160..167 168, 169, 170, 171, 172, 173, 174, 175, // 168..175 176, 177, 178, 179, 180, 181, 182, 183, // 176..183 184, 185, 186, 187, 188, 189, 190, 191, // 184..191 192, 193, 194, 195, 196, 197, 198, 199, // 192..199 200, 201, 202, 203, 204, 205, 206, 207, // 200..207 208, 209, 210, 211, 212, 213, 214, 1, // 208..215 2, 247, 248, 249, 245, 246, 251, 252, // 216..223 253, 254, 250, 229, 230, 231, 227, 228, // 224..231 235, 236, 237, 238, 232, 233, 234, 239, // 232..239 240, 241, 242, 244, 243, 9, 218, 219, // 240..247 220, 221, 222, 223, 224, 225, 226, 255, // 248..255 }; grfcodec-6.0.3/src/pals/0000755000000000000000000000000012027143046013517 5ustar rootrootgrfcodec-6.0.3/src/pals/ttw_cand.bcp0000644000000000000000000000140012027143046016003 0ustar rootroot4 #pragma warning(default:4702) #else #include #endif using namespace std; templateclass ExpandingArray:public vector<_Ty>{ typedef ExpandingArray<_Ty> _MyT; typedef vector<_Ty> _Mybase; public: ExpandingArray(){} ExpandingArray(const _Ty&_fill):m_fill(_fill){} const _Ty&operator[](unsigned int x)const{ if(x>=_MyT::size())return m_fill; return vector<_Ty>::operator[](x); } _Ty&operator[](unsigned int x){ if(x>=_MyT::size())_MyT::resize(x+1); return _Mybase::operator[](x); } void ChangeFill(const _Ty&_fill){m_fill=_fill;} private: _Ty m_fill; }; templateclass Expanding0Array:public vector<_Ty>{ typedef Expanding0Array<_Ty> _MyT; public: _Ty operator[](unsigned int x)const{ if(x>=_MyT::size())return 0; return vector<_Ty>::operator[](x); } _Ty&operator[](unsigned int x){ if(x>=_MyT::size())_MyT::resize(x+1,0); return vector<_Ty>::operator[](x); } }; template<>class Expanding0Array:public vector{ public: bool operator[](unsigned int x)const{ if(x>=size())return false; return vector::operator[](x); } reference operator[](unsigned int x){ if(x>=size())resize(x+1,false); return vector::operator[](x); } }; #endif//_RENUM_EXPANDING_ARRAY_H_INCLUDED_ grfcodec-6.0.3/src/nforenum.h0000644000000000000000000000442412027143046014566 0ustar rootroot/* * renum.h * * Contains generic NFORenum stuff * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_RENUM_H_INCLUDED_ #define _RENUM_RENUM_H_INCLUDED_ /* If your compiler errors on the following line, boost is not * properly installed. * Get boost from http://www.boost.org */ #include /* file handling defs: * dirname contains the name of the sprites directory * foo_ext contains the extention to use for foo * These used to be all caps on _WIN32 systems, but I decided that * consistancy was preferable, and Win32 systems are case-insensitive. */ #define dirname "sprites/" #define nfo_ext ".nfo" #define new_ext ".new" #define bak_ext ".bak" typedef unsigned int uint; typedef unsigned short ushort; typedef unsigned char uchar; #if defined DEBUG || defined _DEBUG inline int _FORCE_INT_(int x){return x;} #define verify assert #else #define verify(x) (void(x)) #define _FORCE_INT_(x) ((int)x) #endif enum{EOK,EWARN=3,EERROR,EPARSE,EFILE,EDATA,EFATAL}; void SetCode(int); #define INTERNAL_ERROR(var,val)\ if(true){\ IssueMessage(0,INTERNAL_ERROR_TEXT,__FILE__,__LINE__,_spritenum,#var,_FORCE_INT_(val),BOOST_CURRENT_FUNCTION);\ assert(false);\ exit(EFATAL);\ }else\ ((void)0) #define DEFAULT(var)\ default:\ INTERNAL_ERROR(var,var); #define VERIFY(cond,var)\ if(!(cond))INTERNAL_ERROR(var,var);\ else\ ((void)0) #define EXPECTED_BYTES(off) (off>>24) #define EXPECTED_LOC(off) (off&0xFFFFFF) #define spritenum() (GetState(DIFF)?-1:\ GetState(USEOLDSPRITENUMS)?oldspritenum:(int)_spritenum) #endif//_RENUM_RENUM_H_INCLUDED_ grfcodec-6.0.3/src/info.h0000644000000000000000000000325212027143046013666 0ustar rootroot#ifndef _INFO_H #define _INFO_H #include #include "pcxsprit.h" #include "pngsprit.h" #include "sprites.h" #include "nfosprite.h" #include "allocarray.h" class inforeader { public: inforeader(char *nf, int grfcontversion); ~inforeader(); const Sprite&operator[](int x)const{return *(nfofile[x]);} int size()const{return nfofile.size();} void installmap(int *map); long imgsize; int sx, sy; SpriteInfo inf; void PrepareReal(const SpriteInfo&info); int getsprite(CommonPixel *sprite); pcxread *imgfile; protected: const char *imgname; int *colourmap; AllocArray nfofile; private: pcxread* MakeReader()const; }; struct Box { enum boxtype {issprite, isspriteextension, isdata}; Box(boxtype type) : type(type) {} virtual ~Box() {} boxtype type; }; struct BoxData : Box { BoxData(uint size, U8 *data) : Box(isdata), size(size), data(data) {} uint size; U8 *data; }; struct BoxSprite : Box { BoxSprite(bool first, const char *filename, int x, int y, SpriteInfo info) : Box(first ? issprite : isspriteextension), filename(strdup(filename)), x(x), y(y), info(info) {} ~BoxSprite() { free(filename); } char *filename; int x; int y; SpriteInfo info; }; class infowriter : public spriteinfowriter { public: infowriter(FILE *info, int maxboxes, int useplaintext, const char *directory); virtual ~infowriter(); void flush(); virtual void addsprite(bool first, const char *filename, int x, int y, SpriteInfo info); virtual void adddata(uint size, U8 *data); void done(int count); private: FILE *info; const char *directory; void resize(int newmaxboxes); Box **boxes; int spriteno, maxboxes, boxnum; int useplaintext; }; #endif /* _INFO_H */ grfcodec-6.0.3/src/allocarray.h0000644000000000000000000000433412027143046015066 0ustar rootroot/* * AllocArray.h * Defines a class for storing a collection of objects all derived from * the same base class * * Copyright 2006 by Dale McCoy. * dalestan@gmail.com * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _ALLOC_ARRAY_H #define _ALLOC_ARRAY_H #ifdef _MSC_VER #pragma warning(disable:4702)//Unreachable code //Yes. I have a C++ library in which contains unreachable code. #include #pragma warning(default:4702) #else #include #endif templateclass AllocArray:private std::vector<_Ty*>{ typedef AllocArray<_Ty> _Myt; typedef std::vector<_Ty*> _Mybase; typedef typename _Mybase::size_type size_type; typedef typename _Mybase::iterator iterator; typedef typename _Mybase::reference reference; typedef typename _Mybase::const_reference const_reference; public: AllocArray(){} ~AllocArray(){ for(size_type i=_Mybase::size();i;) delete operator[](--i); } templatevoid push_back(const _Cty&val){ _Mybase::push_back(new _Cty(val)); } templatevoid push_back(const _Cty*val){ _Mybase::push_back(new _Cty(*val)); } size_type size()const{ return _Mybase::size(); } reference last(){ return operator[](size()-1); } reference operator[](size_type x){ return _Mybase::operator [](x); } const_reference operator[](size_type x)const{ return _Mybase::operator [](x); } void clear(){ for(size_type i=_Mybase::size();i;) delete operator[](--i); _Mybase::clear(); } private: AllocArray(const _Myt&right); void operator=(const _Myt&right); }; #endif /* _ALLOC_ARRAY_H */ grfcodec-6.0.3/src/act6.cpp0000644000000000000000000000335112027143046014123 0ustar rootroot/* * act6.cpp * Contains definitions for checking action 6. * * Copyright 2005-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include using namespace std; #include"nforenum.h" #include"inlines.h" #include"sanity.h" #include"messages.h" #include"pseudo.h" #include"command.h" uint Check6(PseudoSprite&data){ assert(data.ExtractByte(0)==0x06); uint ofs=1,minlen=0; bool canCorrect=true; try{ while(data.ExtractByte(ofs++)!=0xFF){ canCorrect=false; int num=data.ExtractByte(ofs++)&0x7F; if(num)minlen=std::max(minlen,num+data.ExtractExtended(ofs)); else IssueMessage(WARNING1,DOES_NOT_MODIFY,ofs-1); ofs+=data.ExtendedLen(ofs); canCorrect=true; } if(ofs==2) IssueMessage(WARNING1,NO_MODIFICATIONS); if(ofs!=data.Length()) IssueMessage(WARNING2,EXTRA_DATA,data.Length(),ofs); }catch(...){ if(_autocorrect&&canCorrect){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECT_ADD,0xFF); data.Append(0xFF); }else{ IssueMessage(FATAL,UNTERM_ACT6); } } return minlen; } grfcodec-6.0.3/src/pcxsprit.cpp0000644000000000000000000001774012027143046015151 0ustar rootroot #include "pcxsprit.h" #include "ttdpal.h" #include "grfcomm.h" extern bool _mapAll,_hexspritenums; /***********************\ * * * class pcxwrite * * * \***********************/ // to make this a bit more readable, use binary digits instead of hex #define b____ 0 #define b___O 1 #define b__O_ 2 #define b__OO 3 #define b_O__ 4 #define b_O_O 5 #define b_OO_ 6 #define b_OOO 7 #define bO___ 8 #define bO__O 9 #define bO_O_ 10 #define bO_OO 11 #define bOO__ 12 #define bOO_O 13 #define bOOO_ 14 #define bOOOO 15 #define _(o,t) ((b ## t << 4) + b ## o) #define DIGITHEIGHT 5 #define DIGITWIDTH 4 // DIGITHEIGHT*DIGITWIDTH*16(digits)/8(bitsperbyte) = 40 bytes #define DIGITIND(digit,line) (digit/2+8*line) #define DIGITSHR(digit) (4*(digit&1)) static unsigned char digitlines[40] = { _( _OO_, __O_ ),_( OOO_, OOO_ ),_( __O_, OOOO),_( _OO_, OOOO),_( _OO_, _OO_ ), _( _OO_, OOO_ ), _( _OOO, OOO_ ), _( OOOO, OOOO ), _( O__O, _OO_ ),_( ___O, ___O ),_( _OO_, O___),_( O___, ___O),_( O__O, O__O ), _( O__O, O__O ), _( O___, O__O ), _( O___, O___ ), _( O__O, __O_ ),_( _OO_, _OO_ ),_( O_O_, OOO_),_( OOOO, __O_),_( _OO_, _OOO ), _( OOOO, OOO_ ), _( O___, O__O ), _( OOO_, OOO_ ), _( O__O, __O_ ),_( O___, ___O ),_( OOOO, ___O),_( O__O, _O__),_( O__O, ___O ), _( O__O, O__O ), _( O___, O__O ), _( O___, O___ ), _( _OO_, _OOO ),_( OOOO, OOO_ ),_( __O_, OOO_),_( _OO_, _O__),_( _OO_, _OO_ ), _( O__O, OOO_ ), _( _OOO, OOO_ ), _( OOOO, O___ ), }; #undef _ pcxwrite::pcxwrite(multifile *mfile) { setfile(mfile); spriteno=-1; // so the first one will be 0 lastdigitx = -50; } void pcxwrite::filedone(int final) { int y; if (curfile) { if (final) { // fill with blank lines to the right height if necessary for (y=totaly; y= pcxfile::sx) { newband(); lastdigitx = -50; } if (sy > thisbandy) { int needbandy = ( (int) (sy + bandy - 1) / bandy) * bandy; if ((totaly + needbandy > this->sy) && (needbandy <= this->sy)) { // would be too large newband(); lastdigitx = -50; /* Above call to newband might had already switched into a new file, have to recheck */ if ((totaly + needbandy > this->sy) && (needbandy <= this->sy)) { newfile(this->paletted, this->sx); } } thisbandy = needbandy; alloclines(thisbandy); } cx = 0; cy = 0; px = sx;// - bordersizex; py = sy;// - bordersizey; dx = 1; dy = 1; if (borderskip) { int i, bx, by; bx = sx - 2; by = sy - 2; for (i=0; i < 2*bx+2*by; i+=borderskip) { border.m = i & 8; if (i < bx) putpixel(i, 0, border); else if (i < bx + by) putpixel(0, i - bx, border); else if (i < 2*bx + by) putpixel(i-bx-by, by, border); else putpixel(bx, i-2*bx-by, border); } } // WRONG Y IN NFO FILE !! // show sprite number showspriteno(); dx++; dy+=1+DIGITHEIGHT+1; } void pcxwrite::showspriteno() { char spritenum[10]; int newlastx; if(_hexspritenums) sprintf(spritenum, "%X", spriteno); else sprintf(spritenum, "%d", spriteno); newlastx = subx+strlen(spritenum)*(DIGITWIDTH+1)+dx; if (newlastx >= pcxfile::sx) return; if (subx+dx < lastdigitx + 2*(DIGITWIDTH+1)) return; lastdigitx = newlastx; for (int i=0; spritenum[i]; i++) { int digit = spritenum[i] - '0'; if (digit > 9) digit += '0' - 'A'; for (int y=0; y> DIGITSHR(digit); for (int x=DIGITWIDTH-1; x>=0; x--) { if (pixels & 1) putpixel(x + i*(DIGITWIDTH+1),y,border); pixels >>= 1; } } } } void pcxwrite::setline(CommonPixel *band) { for (int i = 0; i < sx; i++) band[i] = background; } void pcxwrite::spritedone(int sx, int sy){ spritedone(); bool maybeGlyph=!_mapAll; for(int cx=0, x=subofsx(cx,0);cx pcxread::sy) { printf("\n%s: Error: Sprite y extends beyond end of the spritesheet.\nSpritesheet has %d lines, sprite wants %d..%d\n.", this->filename(), pcxread::sy, y, y + sy - 1); exit(2); } if (sy > bandlines) { // don't have enough lines in memory, read rest alloclines(sy); } if (y > totaly) { // doesn't start right at the top -> delete extra lines expirelines(y - totaly); totaly = y; } cx = 0; cy = 0; px = sx; py = sy; dx = 0; dy = 0; } void pcxread::setline(CommonPixel *band) { startdecoding(); decodebytes(band, sx); } extern bool _force; extern int _quiet; void pcxread::readheader() { long oldpos = ftell(curfile); fseek(curfile, 0, SEEK_SET); cfread("reading pcx header", &header, sizeof(pcxheader), 1, curfile); be_swapheader(header); if (header.nplanes == 3) { fprintf(stderr, "%s: Cannot read truecolour PCX files!\n", this->filename()); exit(2); } if ( (header.bpp != 8) || (header.nplanes != 1) ) { fprintf(stderr, "%s: PCX file is not a 256 colour file!\n", this->filename()); exit(2); } fseek(curfile,-768,SEEK_END); U8 palette[768]; if (fread(palette,1,768,curfile) != 768 ) { fprintf(stderr, "%s: Could not read palette from PCX file!\n", this->filename()); exit(2); } int i=0; for(;ifilename()); } else { fprintf(stderr, "%s: Error: Unrecognized palette, aborting.\n" "Specify -f on the command line to override this check.\n", this->filename()); exit(2); } } fseek(curfile, oldpos, SEEK_SET); /* header.bpl is number of bytes per scanline. * header.window[2] - header.window[0] + 1 is number of bytes actually used. * The original ZSoft standard defines header.bpl to be always even, so there may be unused bytes. * However, more modern software (e.g. gimp) do not care about that and do not waste any bytes. */ sx = header.bpl; sy = header.window[3] - header.window[1] + 1; totaly = 0; thisbandy = 0; } grfcodec-6.0.3/src/pcxfile.h0000644000000000000000000001145112027143046014365 0ustar rootroot#ifndef _PCXFILE_H #define _PCXFILE_H /*****************************************\ * * * PCXFILE.H - A class to combine several * * small images in one pcx file * * as well as read them out * * * * Copyright (C) 2000 by Josef Drexler * * * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #include #include #include #include "typesize.h" #include "file.h" /** Definition of a common pixel in GRFCodec's realm. */ struct CommonPixel { U8 r; ///< Red-channel U8 g; ///< Green-channel U8 b; ///< Blue-channel U8 a; ///< Alpha-channel U8 m; ///< Remap-channel explicit CommonPixel(U8 r = 0, U8 g = 0, U8 b = 0, U8 a = 0, U8 m = 0) : r(r), g(g), b(b), a(a), m(m) {} bool IsTransparent(bool has_mask, bool rgba) const { return rgba ? this->a == 0 : this->m == 0; } U8 *Encode(U8 *buffer, bool has_mask, bool rgba) const { if (rgba) { *buffer++ = this->r; *buffer++ = this->g; *buffer++ = this->b; *buffer++ = this->a; } if (has_mask) *buffer++ = this->m; return buffer; } const U8 *Decode(const U8 *buffer, bool has_mask, bool rgba) { if (rgba) { this->r = *buffer++; this->g = *buffer++; this->b = *buffer++; this->a = *buffer++; } if (has_mask) this->m = *buffer++; return buffer; } void MakeTransparent() { this->r = 0; this->g = 0; this->b = 0; this->a = 0; this->m = 0; } }; struct pcxheader { U8 manuf; // 10 U8 version; // 5 U8 encoding; // 1 U8 bpp; // 1, 2, 4 or 8 (per plane) U16 window[4]; // x1,y1,x2,x2 U16 dpi[2]; // x,y U8 cmap[48]; // colormap U8 reserved; // 0 U8 nplanes; S16 bpl; // bytes per line (per plane) S16 palinfo; // 1=colour S16 screen[2]; // x,y U8 filler[54]; }; class pcxfile { public: virtual ~pcxfile(); virtual const char *filename() { return mfile->filename(); }; virtual FILE *getnextfile() { return mfile->nextfile(); }; virtual FILE *getcurfile() { return mfile->curfile(); }; virtual void filedone(int /*final*/) { }; virtual void filestart(bool paletted) { fseek(curfile, sizeof(header), SEEK_SET); }; void setfile(multifile *mfile); void newfile(bool paletted, int sx); void newheader(int sx); void startimage(bool paletted, int sx, int sy, int bandx, int bandy); void alloclines(int newlines); void expirelines(int oldlines); void initline(int y); virtual void setline(CommonPixel* /*band*/) { }; void endimage(); virtual void startsubimage(int /*x*/, int /*y*/, int /*sx*/, int /*sy*/) { }; void newline(); void streamputpixel(CommonPixel colour); void streamputpixel(CommonPixel *buffer, unsigned long datasize); private: CommonPixel streamgetpixel(); public: void streamgetpixel(CommonPixel *buffer, unsigned long datasize); void installreadmap(int *map); void installwritemap(int *map); void putpixel(int x, int y, CommonPixel colour); //U8 getpixel(int x, int y); int subimagex() { return subx + dx; } int subimagey() { return totaly + dy; } void endsubimage(); const char *getdirectory() { return mfile->getdirectory(); }; void be_swapheader(pcxheader& header); protected: pcxfile(); void newband(); void startdecoding(); void startencoding(); virtual void encodebytes(const CommonPixel &pixel, int num); virtual void encodebytes(const CommonPixel *buffer, int num); void decodebytes(CommonPixel buffer[], int num); void endencoding(); int subofsx(int x, int checkbound); int subofsy(int y, int checkbound); FILE *curfile; pcxheader header; int sx, sy, // size of the PCX image subx, // current subimage x offset px, py, // subimage size x, y cx, cy, // subimage stream ptr x, y dx, dy, // subimage pos x, y (rel to subx, 0) bandx, bandy, thisbandy, // default band x, y, current band y totaly; // total lines written so far int bandlines; int codecing; bool paletted; class colourmap{ public: colourmap():map(new int[256]),deletemap(true){ for(int i=0;i<256;i++) map[i]=i; } ~colourmap(){ if(deletemap) delete[] map; } const colourmap&operator=(int*p){ if(deletemap) delete map; deletemap=false; map=p; return*this; } int operator[](int x){return map[x];} private: int*map; bool deletemap; void operator=(const colourmap&);// Not assignable colourmap(const colourmap&);// not copyable } getcolourmap, putcolourmap; CommonPixel **band; private: multifile *mfile; U8 last; U8 run; }; #endif /* _PCXFILE_H */ grfcodec-6.0.3/src/grfstrip.cpp0000644000000000000000000001173312027143046015131 0ustar rootroot/* * This file is part of GRFCodec. * GRFCodec 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, version 2. * GRFCodec 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 OpenTTD. If not, see . */ #include #include #include #include #include "md5.h" #ifndef WIN32 #include #else #include #define PROT_READ 0 #define MAP_PRIVATE 0 /* Lets fake mmap for Windows, please! */ void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) { char *mem = (char*)malloc(size + 1); mem[size] = 0; FILE *in = fdopen(handle, "rb"); if (fread(mem, size, 1, in) != 1) { fclose(in); free(mem); return NULL; } fclose(in); return mem; } long munmap (void *ptr, long size) { free(ptr); return 0; } #endif #include "version.h" size_t _file_length; uint8_t *_file_buffer; uint8_t *_buffer; inline void SkipBytes(size_t count) { _buffer += count; } inline uint8_t ReadByte() { return *(_buffer++); } inline uint16_t ReadWord() { uint16_t v = ReadByte(); return v | (ReadByte() << 8); } inline uint32_t ReadDWord() { uint32_t v = ReadWord(); return v | (ReadWord() << 16); } static const char header[] = { '\x00', '\x00', // End-of-file marker for old OTTDp versions 'G', 'R', 'F', '\x82', // Container version 2 '\x0D', '\x0A', '\x1A', '\x0A', // Detect garbled transmission }; const char *Strip(const char *origin, const char *dest, uint32_t allowed) { FILE *fin = fopen(origin, "rb"); if (fin == NULL) return "Unable to open origin file"; FILE *fout = fopen(dest, "wb"); if (fout == NULL) return "Unable to open destination file"; /* Get the length of the file */ fseek(fin, 0, SEEK_END); _file_length = ftell(fin); fseek(fin, 0, SEEK_SET); /* Map the file into memory */ _file_buffer = (uint8_t*)mmap(NULL, _file_length, PROT_READ, MAP_PRIVATE, fileno(fin), 0); uint8_t *end = _file_buffer + _file_length; if (_file_length <= sizeof(header) || memcmp(_file_buffer, header, sizeof(header)) != 0) { return "No GRF with container version 2."; } _buffer = _file_buffer + sizeof(header); uint32_t len = ReadDWord(); _buffer = _file_buffer + sizeof(header) + len + 4; if (_buffer >= end) return "Invalid GRF"; if (fwrite(_file_buffer, 1, _buffer - _file_buffer, fout) != (size_t)(_buffer - _file_buffer)) { return "Could not write to file"; } for (;;) { uint8_t *begin = _buffer; uint32_t id = ReadDWord(); if (id == 0) { if (fwrite(begin, 1, end - begin, fout) != (size_t)(end - begin)) { return "Could not write to file"; } break; } uint32_t size = ReadDWord(); uint8_t info = ReadByte(); uint8_t zoom = ReadByte(); int offset = ((info & 0x7) == 4 ? 0 : 16) + zoom; if (info == 0xFF || (allowed & (1 << offset)) != 0) { /* Copy */ if (fwrite(begin, 1, size + 8, fout) != (size_t)(size + 8)) { return "Could not write to file"; } } /* Skip sprite. */ SkipBytes(size - 2); if (_buffer >= end) return "Invalid GRF"; } munmap(_file_buffer, _file_length); fclose(fin); return NULL; } int main(int argc, char **argv) { if (argc < 3 || strcmp(argv[1], "-h") == 0) { printf( "GRFSTRIP " VERSION " - Copyright (C) 2009 by Remko Bijker\n" "\n" "Usage:\n" " GRFSTRIP [ ]\n" " Strip real sprites that are not in the set \"normal 8bpp and the ones\n" " specified at the command line\" from origin into dest.\n" " GRFSTRIP -v\n" " Get the version of GRFSTRIP\n" "\n" "You may copy and redistribute it under the terms of the GNU General Public\n" "License, as stated in the file 'COPYING'.\n"); return 1; } if (strcmp(argv[1], "-v") == 0) { printf("GRFSTRIP " VERSION " - Copyright (C) 2012 by Remko Bijker\n"); return 0; } uint32_t allowed = 1; for (int i = 3; i + 1 < argc; i++) { int depth_offset; if (strcmp(argv[i], "32bpp") == 0) { depth_offset = 16; } else if (strcmp(argv[i], "8bpp") == 0) { depth_offset = 0; } else { printf("Invalid depth \"%s\"\n", argv[i]); return 1; } static const char *zoom[] = { "normal", "zi4", "zi2", "zo2", "zo4", "zo8" }; int zoom_offset = 0xFF; for (int j = 0; j < 6; j++) { if (strcmp(argv[i + 1], zoom[j]) == 0) { zoom_offset = j; break; } } if (zoom_offset == 0xFF) { printf("Invalid zoom \"%s\"\n", argv[i]); } allowed |= 1 << (depth_offset + zoom_offset); } const char *err = Strip(argv[1], argv[2], allowed); if (err == NULL) { printf("Stripped %s into %s successfully\n", argv[1], argv[2]); return 0; } printf("Unable to get requested information: %s\n", err); return 1; } grfcodec-6.0.3/src/nforenum.cpp0000644000000000000000000005626012027143046015126 0ustar rootroot/* * renum.cpp * Renumbers and lints an NFO file specified on the commandline or piped * in via standard input. * * Return values: * See README[.txt] * * Copyright 2004-2007,2009 by Dale McCoy. * dalestan@gmail.com * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include #include #include #ifdef MINGW #include #define isatty _isatty #elif defined(_MSC_VER) #include #include #define F_OK 0 #define isatty _isatty #else #include #endif//_MSC_VER using namespace std; #include"getopt.h" #include"globals.h" #include"inlines.h" #include"sanity.h" #include"command.h" #include"messages.h" #include"inject.h" #include"pseudo.h" #include"help.h" #ifdef _WIN32 # include "win32.h" #endif #include "mapescapes.h" #include "data.h" nfe_map nfo_escapes; #ifndef _MSC_VER //Cygwin's GCC #defines __cdecl, but other GCCs do not //#undef it to prevent GCC from warning on the #define, //then #define it to prevent errors on main's definition. #undef __cdecl #define __cdecl #endif struct RealSpriteFormat{ bool bpp32; int zoom; bool operator<(const RealSpriteFormat&other)const{ return bpp32==other.bpp32?zoom present; bool mask_allowed; void Reset(){ present.clear(); mask_allowed = false; } }; int process_file(istream&); void output_buffer(const string&,bool,int); bool verify_real(string&,RealSpriteState&); static int _retval=EOK; static int _force=0; bool _interactive; void SetCode(int x){_retval=max(_retval,x);} void doexit(){exit(_retval);} //The VS project file specifies __stdcall as the default convention, //so main must be explicitly __cdecl'd int __cdecl main(const int argc,char**argv){ string infilename,outfilename,bakfilename,basename; int result,longind,opt=0,replace=1; static const option optlist[]={ /* Command-line only options */ {"auto-correct",no_argument,NULL,'a'}, {"comments",required_argument,NULL,'c'}, {"data",optional_argument,NULL,'D'}, {"force",no_argument,&_force,1}, {"help",no_argument,NULL,'h'}, {"keep-old",no_argument,&replace,0}, {"lock",no_argument,NULL,256}, {"no-replace",no_argument,&replace,0}, {"silent",no_argument,NULL,'s'}, {"version",no_argument,NULL,'v'}, {"write-data",no_argument,NULL,257}, /* Switches also available via @@ in the .nfo */ {"beautify",required_argument,NULL,'b'}, {"diff",no_argument,NULL,'d'}, {"extentions",required_argument,NULL,'e'}, // used to enable non-official nfo features. currently none. {"let",required_argument,NULL,'L'}, {"lint",optional_argument,NULL,'l'}, {"preserve-messages",no_argument,NULL,'P'}, {"real-sprites",required_argument,NULL,'r'}, {"use-old-nums",required_argument,NULL,'o'}, {"warning-disable",required_argument,NULL,'w'}, {"warning-enable",required_argument,NULL,'W'}, {NULL,0,0,0} }; _interactive = (isatty(fileno(stdout)) != 0); bool seen_startup_message = false; pOut=argc==1?&cerr:&cout; ifstream fin; ofstream fout; while(argc>1){ if(opt!=EOF)opt=getopt_long(argc,argv,"ac:D::fhksv" "b:de:L:l:pr:o:w:W:",optlist,&longind); switch(opt){ case 0:continue; case 257: /* --write-data */ for (int i = 0; i < FILES_MAX; i++) { FILE *pFile = _myfopen((files)i, true); fclose(pFile); } continue; case 's': _interactive = false; continue; case 'v': IssueMessage(0,STARTUP); return 0; case'D': if(optarg)datadir=optarg; dosleep=false; continue; case'k':replace=0;continue; case'c': switch(*optarg){ case'#':COMMENT_PREFIX="#";break; case';':COMMENT_PREFIX=";";break; case'/':COMMENT_PREFIX="//"; } continue; case'h': IssueMessage(0,STARTUP); ShowHelp(); return 0; case'f':_force=1;continue; case'a': _autocorrect++; if(!GetState(BEAUTIFY)){ optarg=(char*)"convertonly+"; CLCommand('b'); } continue; case EOF: if(optind==argc)doexit(); basename=argv[optind++];break; case '?': ShowHelp(); exit(1); default: if(!CLCommand(opt)) IssueMessage(0,BAD_CL_ARG,opt,optarg); continue; } if (!seen_startup_message && _interactive) { seen_startup_message = true; IssueMessage(0,STARTUP); } pNfo=&fout; bakfilename=basename+bak_ext; fin.open((infilename=basename).c_str()); if(!fin.is_open()){ fin.open((infilename=basename+nfo_ext).c_str()); bakfilename=basename+nfo_ext+bak_ext; } if(fin.is_open()){ fout.open((outfilename=(replace?basename+new_ext:basename+new_ext+nfo_ext)).c_str()); }else{ bakfilename=dirname+(basename+bak_ext); fin.open((infilename=dirname+basename).c_str()); if(!fin.is_open()){ bakfilename=dirname+(basename+nfo_ext+bak_ext); fin.open((infilename=dirname+basename+nfo_ext).c_str()); } if(fin.is_open()){ fout.open((outfilename=dirname+(replace?basename+new_ext:basename+new_ext+nfo_ext)).c_str()); }else{ IssueMessage(0,NO_INPUT_FILE,basename.c_str()); SetCode(EFILE); continue; } } if(!fout.is_open()){ IssueMessage(0,NO_OUTPUT_FILE,outfilename.c_str(),basename.c_str()); SetCode(EFILE); fin.close(); fout.clear(); continue; } fin.clear(); reset_sanity(); reset_commands(); _grfver=_act14_pal=0; if (_interactive) IssueMessage(0,PROCESSING_FILE,basename.c_str()); result=process_file(fin); fin.close(); fout.close(); if(result){ #if defined(_MSC_VER) && (_MSC_VER >= 1400) // unlink is deprecated in MSVS 8.0+ _unlink(outfilename.c_str()); #else unlink(outfilename.c_str()); #endif }else if(replace){ if(rename(infilename.c_str(),bakfilename.c_str())&&errno==EEXIST){ #if defined(_MSC_VER) && (_MSC_VER >= 1400) // unlink is deprecated in MSVS 8.0+ if(_unlink(infilename.c_str())) #else if(unlink(infilename.c_str())) #endif { IssueMessage(0,DELETE_FAILED,infilename.c_str(),errno); perror(NULL); SetCode(EFILE); } } if(rename(outfilename.c_str(),infilename.c_str())){ IssueMessage(0,REPLACE_FAILED,infilename.c_str(),outfilename.c_str(),errno); perror(NULL); SetCode(EFILE); } } if (_interactive) IssueMessage(0,PROCESSING_COMPLETE); } pNfo=&cout; IssueMessage(0,PROCESSING); process_file(cin); IssueMessage(0,PROCESSING_COMPLETE); return _retval; } #define flush_buffer()\ if(true) {\ if(buffer!="") {\ output_buffer(buffer,isPatch,oldspritenum);\ buffer="";\ }\ oldspritenum=temp;\ } else\ (void(0)) #define SetVersion(x)\ (NFOversion=max((x),NFOversion)) static bool hasHeader; int NFOversion; bool TrySetVersion(int x){ if(hasHeader&&NFOversion>=x)return true; if(hasHeader&&NFOversion<=6&&x>=7)return false; SetVersion(x); return true; } string smash(const string&,int&); int process_file(istream&in){ NFOversion=4; string sprite,datapart,buffer; inject_into(in); nfo_escapes.clear(); vector extra_lines; if(string(" \t\n*0123456789/;#*").find((char)in.peek())==NPOS){ IssueMessage(0,APPARENTLY_NOT_NFO); if(!_force){ IssueMessage(0,SKIPPING_FILE); SetCode(EPARSE); return-1; } } //This section is a rewrite of lines 35-50 or thereabouts of info.cc //from grfcodec: http://www.ttdpatch.net/grfcodec //grfcodec is Copyright 2000-2003 Josef Drexler getline(in,sprite);//Info header or first sprite hasHeader=false; if (sprite.substr(0,3)=="// "){ hasHeader=true; getline(in,sprite);//Info version (first sprite for ancient NFO versions) if(sscanf(sprite.c_str(),"// (Info version %d)",&NFOversion)){ if((NFOversion<4||NFOversion>7)&&NFOversion!=32){ IssueMessage(0,UNKNOWN_VERSION,NFOversion); if(NFOversion>7){ IssueMessage(0,SKIPPING_FILE); SetCode(EPARSE); return-1; } IssueMessage(0,PARSING_FILE); } if(NFOversion>2) getline(in,sprite);//Format line if (NFOversion>6) { while (strncmp(sprite.c_str(), "// Format: ", 11)) { if (!strncmp(sprite.c_str(), "// Escapes: ", 12)) { // Actually, that was an escapes line. Read it. istringstream esc(sprite); string str; int byte = 0; esc.ignore(12); while (esc>>str) if (str == "=") byte--; else if (str[0] == '@') byte = strtol(str.c_str()+1,NULL,16); else nfo_escapes.insert(nfe_pair(str, byte++)); } else if (strncmp(sprite.c_str(), "// ",3)) { // EEEP! No "Format:" line in this file! IssueMessage(0, APPARENTLY_NOT_NFO); SetCode(EPARSE); return -1; } else extra_lines.push_back(sprite); // store unknown lines getline(in,sprite); // Try again to skip "Format: " line } // Now remove all defaults. This serves two purposes: // 1) Prevent incorrectly specified defaults from causing problems later. // 2) Allow the beautifier to select custom escapes over built-ins. foreach(const esc& e, escapes) nfo_escapes.left.erase(e.str+1); } }else{ IssueMessage(0,UNKNOWN_VERSION,1); IssueMessage(0,PARSING_FILE); } getline(in,sprite);//first sprite } int temp=-1,size,oldspritenum=-1; _spritenum=(unsigned)-1; RealSpriteState realsprite_state; string::size_type firstnotpseudo; bool isPatch=false; ostringstream outbuffer; ostream*real_out=pNfo; pNfo=&outbuffer; SetVersion(4); AutoConsoleMessages(); while(true){ //IssueMessage(0,SPRITE,spritenum+1,sprite.c_str()); istringstream spritestream(sprite); eat_white(spritestream); if(spritestream.peek()==EOF) { buffer+='\n'; } else if(is_comment(spritestream)){ if(is_command(sprite)) { flush_buffer(); } if(parse_comment(sprite)) { buffer+=sprite+'\n'; } } else {//sprite if(!eat_white(spritestream>>temp)){ spritestream.clear(); temp=-1; } if(spritestream.peek()=='*'){ realsprite_state.Reset(); if(spritestream.ignore().peek()=='*'){ SetVersion(6); getline(eat_white(spritestream.ignore()),datapart); flush_buffer(); if(isPatch) { check_sprite(INCLUDE); } else { IssueMessage(ERROR,UNEXPECTED,BIN_INCLUDE); } _spritenum++; (*pNfo)<>size).clear(); eat_white(spritestream); flush_buffer(); if(_spritenum==(uint)-1){ isPatch=true; if(size!=4 && size!=0) outbuffer<=32&&spritestream.peek()=='|'){ eat_white(spritestream.ignore()); getline(spritestream,datapart); if(realsprite_state.present.empty()){ IssueMessage(0,NOT_IN_REALSPRITE,_spritenum+1); buffer+="//"+sprite+'\n'; }else{ if(verify_real(datapart,realsprite_state)){ flush_buffer(); (*pNfo)<<" | "< 6) { // (re)insert default escapes foreach(const esc& e, escapes) nfo_escapes.insert(nfe_pair(e.str+1, e.byte)); (*real_out)<<"// Escapes:"; int oldbyte = -1; for (int act = 0; act < 255; act++) { foreach (const nfe_rpair& p, nfo_escapes.right) { if (p.second[0] != act) continue; if (p.first == oldbyte) { (*real_out)<<" ="; --oldbyte; } else if (p.first < oldbyte) { (*real_out)<<"\n// Escapes:"; oldbyte = -1; } while (++oldbyte != p.first) (*real_out)<<" "<second; (*real_out)<<" "<(&end), 10); if (pos == end) { if(RPNOFF()||*pos!='(') return true; size_t offs = pos - start; token = DoCalc(input,offs); if(offs==NPOS) return true; anyprocessing = true; input.erase(0, offs); processed.append(mysprintf(" %d", token)); } else { size_t count = end - start; processed.append(input, 0, count); input.erase(0, count); } return false; } /** * Extract a hexadecimal integer from the beginning of a string. * This can involve parsing a RPN expression. * @param[in,out] input Input to extract integer from. The extracted data is removed from this string. * @param[out] token Extracted integer * @param[in,out] processed Processed data. The extracte data is appended to this string. * @param[in,out] anyprocessing Is set to true, if the data added to \a processed differs from the date removed * from \a input. E.g. because of parsing an RPN expression. * @return true on error */ static bool extract_hex(string&input,int&token,string&processed,bool&anyprocessing) { const char *start = input.c_str(); const char *pos = start; while (isspace(*pos)) pos++; const char *end = NULL; token = strtol(pos, const_cast(&end), 16); if (pos == end) return true; size_t count = end - start; processed.append(input, 0, count); input.erase(0, count); return false; } bool verify_real(string&data,RealSpriteState&formats){ string::size_type loc=NPOS; string udata=UCase(data); while(true){ loc=udata.find(".PCX",loc+1); if(loc==NPOS) loc = udata.find(".PNG",loc+1); if(loc==NPOS){ IssueMessage(0,REAL_NO_FILENAME); return false; } if(isspace(data[loc+4]))break; } string name=data.substr(0,loc+4); if(NFOversion>=32){ string depth; int xpos, ypos, xsize, ysize, xrel, yrel, zoom; string meta=data.substr(loc+5); string processed; bool anyprocessing = false; if (extract_string(meta,depth,processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"depth"); return COMMENTOFF(); } if (depth=="mask"){ if (!formats.mask_allowed) { IssueMessage(0,REAL_32BPP_BEFORE_MASK); return COMMENTOFF(); } formats.mask_allowed = false; if (extract_int(meta,xpos, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"xpos"); return COMMENTOFF(); } if (extract_int(meta,ypos, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"ypos"); return COMMENTOFF(); } if(xpos<0)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,XPOS,0); if(ypos<0)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,YPOS,0); string flag; while (!extract_string(meta,flag,processed,anyprocessing)) { { IssueMessage(0,REAL_UNKNOWN_FLAG,flag.c_str()); return COMMENTOFF(); } } } else if (depth=="32bpp"||depth=="8bpp"){ formats.mask_allowed = depth=="32bpp"; string zoom_str; if (extract_int(meta,xpos, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"xpos"); return COMMENTOFF(); } if (extract_int(meta,ypos, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"ypos"); return COMMENTOFF(); } if (extract_int(meta,xsize,processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"xsize"); return COMMENTOFF(); } if (extract_int(meta,ysize,processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"ysize"); return COMMENTOFF(); } if (extract_int(meta,xrel, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"xrel"); return COMMENTOFF(); } if (extract_int(meta,yrel, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"yrel"); return COMMENTOFF(); } if (extract_string(meta,zoom_str,processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"zoom"); return COMMENTOFF(); } if(xpos<0)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,XPOS,0); if(ypos<0)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,YPOS,0); if(xsize<1)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,XSIZE,1); else if(xsize>0xFFFF)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,XSIZE,0xFFFF); if(ysize<1)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,YSIZE,1); else if(ysize>0xFFFF)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,YSIZE,0xFFFF); if(xsize*ysize>0xFFFFFF)IssueMessage(ERROR,REAL_SPRITE_TOO_LARGE); // arbitrary but sane limit if(xrel<-32768)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,XREL,-32768); else if(xrel>32767)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,XREL,32767); if(yrel<-32768)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,YREL,-32768); else if(yrel>32767)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,YREL,32767); if (zoom_str=="normal") zoom = 0; else if (zoom_str=="zi4") zoom = 1; else if (zoom_str=="zi2") zoom = 2; else if (zoom_str=="zo2") zoom = 3; else if (zoom_str=="zo4") zoom = 4; else if (zoom_str=="zo8") zoom = 5; else { IssueMessage(0,REAL_MISSING_DATA,"zoom"); return COMMENTOFF(); } string flag; bool chunked = false, nocrop=false; while (!extract_string(meta,flag,processed,anyprocessing)) { if (!chunked&&flag=="chunked") chunked = true; else if (!nocrop&&flag=="nocrop") nocrop = true; else { IssueMessage(0,REAL_UNKNOWN_FLAG,flag.c_str()); return COMMENTOFF(); } } RealSpriteFormat format; format.bpp32 = depth=="32bpp"; format.zoom = zoom; if (formats.present.empty()&&(format.bpp32||format.zoom!=0)) IssueMessage(0,REAL_8BPP_NORMAL_FIRST); if (formats.present.count(format) > 0) { IssueMessage(0,REAL_DUPLICATE_ZOOM); return COMMENTOFF(); } formats.present.insert(format); } else { IssueMessage(0,REAL_MISSING_DATA,"depth"); return COMMENTOFF(); } if (anyprocessing) data=data.substr(0,loc+5)+processed+meta; return true; }else{ int xpos, ypos, comp, ysize, xsize, xrel, yrel; string meta=data.substr(loc+5); string processed; bool anyprocessing = false; if (extract_int(meta,xpos, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"xpos"); return COMMENTOFF(); } if (extract_int(meta,ypos, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"ypos"); return COMMENTOFF(); } if (extract_hex(meta,comp, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"comp"); return COMMENTOFF(); } if (extract_int(meta,ysize,processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"ysize"); return COMMENTOFF(); } if (extract_int(meta,xsize,processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"xsize"); return COMMENTOFF(); } if (extract_int(meta,xrel, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"xrel"); return COMMENTOFF(); } if (extract_int(meta,yrel, processed,anyprocessing)) { IssueMessage(0,REAL_MISSING_DATA,"yrel"); return COMMENTOFF(); } if (anyprocessing) data=data.substr(0,loc+5)+processed+meta; if(xpos<0)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,XPOS,0); if(ypos<0)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,YPOS,0); if(!(comp&1)||(comp&0x4B)!=comp)IssueMessage(comp==0xFF?ERROR:WARNING1,REAL_BAD_COMP,comp); if(xsize<1)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,XSIZE,1); else if(xsize>0xFFFF)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,XSIZE,0xFFFF); if(ysize<1)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,YSIZE,1); else if(ysize>0xFF)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,YSIZE,0xFF); if(xsize*ysize>0xFFFF)IssueMessage(ERROR,REAL_SPRITE_TOO_LARGE); if(xrel<-32768)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,XREL,-32768); else if(xrel>32767)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,XREL,32767); if(yrel<-32768)IssueMessage(ERROR,REAL_VAL_TOO_SMALL,YREL,-32768); else if(yrel>32767)IssueMessage(ERROR,REAL_VAL_TOO_LARGE,YREL,32767); return true; } } void output_buffer(const string&sprite,bool isPatch,int spriteno){ PseudoSprite data(sprite,spriteno); if(data.IsValid()){ _spritenum++; if(isPatch)check_sprite(data); else{ data.SetAllHex(); data.SetEol(32,1); data.SetEol(64,1); data.SetEol(96,1); data.SetEol(128,1); data.SetEol(160,1); data.SetEol(192,1); data.SetEol(224,1); } } (*pNfo)< * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ class multifile { public: multifile() {}; virtual ~multifile() {}; virtual FILE *curfile() { return NULL; }; virtual FILE *nextfile() { return NULL; }; virtual const char *filename() { return NULL; }; virtual const char *getdirectory() { return NULL; }; }; class singlefile : public multifile { public: singlefile(const char *filename, const char *mode, const char *dir); virtual ~singlefile(); void setfile(FILE *file); virtual FILE *curfile() { return thefile; }; virtual const char *filename() { return thefilename; }; virtual const char *getdirectory() { return directory; }; private: char *thefilename, *directory; FILE *thefile; int autoclose; }; #endif /* _FILE_H */ grfcodec-6.0.3/src/pseudo.cpp0000644000000000000000000005566612027143046014605 0ustar rootroot/* * pseudo.cpp * Implementation of the PseudoSprite class. * * Copyright 2006-2010 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include /* If your compiler errors on the following lines, boost is not * properly installed. * Get boost from http://www.boost.org */ #include #include #include #include #include using namespace boost::gregorian; using namespace boost::lambda; using namespace boost; #define foreach BOOST_FOREACH using namespace std; #include"nforenum.h" #include"pseudo.h" #include"globals.h" #include"messages.h" #include"inlines.h" #include"command.h" #include"utf8.h" extern int NFOversion; bool TrySetVersion(int); //QESC: \n or \xx // \" and \\ are implicit in TEXT. //QEXT: \Uxxxx, usually. enum{HEX,TEXT,UTF8,ENDQUOTE,QESC,QEXT,NQEXT,NOBREAK=0x80}; #define cur_pos() ((uint)out.str().length()-1) #define next_pos() ((uint)out.str().length()) #define cur_context() (context[cur_pos()]) #define ProcessWhite()\ if(white!=""){\ if(white[white.length()-1]==' '&&!GetState(CONVERTONLY))white=white.substr(0,white.length()-1);\ if((cur_context()!=""&&cur_context().find('\n')!=NPOS)||GetState(CONVERTONLY))cur_context()+=white;\ white="";\ }else ((void)0) int FindEscape(string str); string FindEscape(char, int); string FindEscape(char, int, uint); PseudoSprite::PseudoSprite(const string&sprite,int oldspritenum): orig(sprite), valid(true), useorig(false), oldspritenum(oldspritenum), extract_offs(0) { istringstream in(sprite); ostringstream out; char ch; bool newline=true; string white; while(in){ switch(in.peek()){ case EOF:continue; case'"': TrySetVersion(5); in.ignore(); ProcessWhite(); while(true){ if(!in.get(ch)){ IssueMessage(0,UNTERMINATED_STRING); Invalidate(); return; } if(ch=='"')break; if(ch=='\\'&&TrySetVersion(7)){ switch(ch=(char)in.get()){ case'n': ch='\r';//TTD uses Mac-style linefeeds (\r) break; case'"': case'\\': break; case'U':{ uint x=ReadHex(in,4); if(!in){ IssueMessage(0,INVALID_EXTENSION); Invalidate(); return; } if(x>0x7FF){ SetUTF8(next_pos(),3); out.write(GetUtf8Encode(x).c_str(),3); LinkBytes(3,out.str().length()); continue; }else if(x>0x7F){ SetUTF8(next_pos(),2); out.write(GetUtf8Encode(x).c_str(),2); LinkBytes(2,out.str().length()); continue; }else{ out.put(ch); LinkBytes(1,out.str().length()); continue; } break; }default: in.unget(); ch=(char)ReadHex(in,2); if(!in){ IssueMessage(0,INVALID_EXTENSION); Invalidate(); return; } break; } } SetText(next_pos()); newline=false; out.put(ch); } break; case'\\': if(TrySetVersion(7)){ ProcessWhite(); newline=false; in.ignore(); uint x; switch(in.get()){ case'b': if(in.peek()=='*'){// \b* x = ReadValue(in.ignore(), _BX_); if(!in||x>0xFFFF)break;//invalid if(x>0xFE){ out.put('\xFF').write(itoa(x,256,2).c_str(),2); LinkBytes(3,out.str().length()); }else{ out.put((char)x); LinkBytes(1,out.str().length()); } continue; } x = ReadValue(in, _B_); if(!in||x>0xFF)break;//invalid out.put((char)x); LinkBytes(1,out.str().length()); continue; case'w': x = ReadValue(in, _W_); if(!in||x>0xFFFF)break;//invalid out.write(itoa(x,256,2).c_str(),2); LinkBytes(2,out.str().length()); continue; case'd': x = ReadValue(in, _D_); if(!in)break; out.write(itoa(x,256,4).c_str(),4); LinkBytes(4,out.str().length()); continue; default:{ in.unget(); string esc; in>>esc; int byte = FindEscape(esc); if(byte == -1) break; out.put((char)byte); LinkBytes(1,out.str().length()); continue; }} IssueMessage(0,INVALID_EXTENSION); Invalidate(); return; } //fall through to default when !GetState(EXTENSIONS) default: if (is_comment(in)) { string comment; getline(in,comment); comment=white+comment; white=""; if(is_command(comment)||parse_comment(comment)) { if(newline) { AddComment(comment,cur_pos()); } else { TrailComment(comment,cur_pos()); } } newline=true; } else if(isspace(in.peek())) if(in.peek()=='\n'&&!GetState(CONVERTONLY)){ if(newline)AddBlank(cur_pos()); newline=true; white=""; in.ignore(); }else white+=(char)in.get(); else{ ch=(char)ReadHex(in,2); if(!in){ in.clear(); IssueMessage(0,INVALID_CHARACTER,in.peek()); Invalidate(); return; } ProcessWhite(); newline=false; out.put(ch); } } } packed=out.str(); if(white!=""&&Length()){ if(white[white.length()-1]==' '&&!GetState(CONVERTONLY))white=white.substr(0,white.length()-1); if((cur_context()!=""&&cur_context().find('\n')!=NPOS)||GetState(CONVERTONLY))cur_context()+=white; white=""; }; } void PseudoSprite::LinkBytes(int count, size_t e){ int end = (int)e; for(int i=end-count,high=0; i>8)&0xFF)+1,linkage[ofs+i]&0xFF,i+1,count); return; } } } } bool PseudoSprite::MayBeSprite(const string&sprite){ istringstream in(sprite); char ch; while(in.get(ch)){ if(ch=='"')return true; if(COMMENT.find(ch)!=NPOS){ in.ignore(INT_MAX,'\n'); continue; } if(isspace(ch)||string(VALID_PSEUDO).find(ch)==NPOS)continue; return true; } return false; } uint PseudoSprite::Length()const{return(uint)(valid?packed.length():0);} PseudoSprite&PseudoSprite::SetHex(uint i){beauty[i]=HEX;return*this;} PseudoSprite&PseudoSprite::SetHex(uint i,uint num){while(num--)beauty[i++]=HEX;return*this;} PseudoSprite&PseudoSprite::SetAllHex(){beauty.clear();return*this;} PseudoSprite&PseudoSprite::SetUTF8(uint i,uint len){ while(--len) beauty[i++]=uchar(UTF8|NOBREAK); beauty[i++]=UTF8; return*this; } PseudoSprite&PseudoSprite::SetText(uint i){ if(i&&GetState(CONVERTONLY)){ if((beauty[i-1]&~NOBREAK)==ENDQUOTE&&context[i-1]=="")context[i-1]=" "; } beauty[i]=TEXT; return*this; } PseudoSprite&PseudoSprite::SetText(uint i,uint num){ for(uint j=i+num-1;i max) { val -= 365*400 + 97; yearmod += 400; } date::ymd_type ymd = (date(1920,1,1) + days(val-base)).year_month_day(); uint y = ymd.year+yearmod, m = ymd.month, d = ymd.day; return SetEscape(i, false, mysprintf(" \\d%d/%d/%d", y, m, d), 4); }} return SetDec(i, num); } PseudoSprite&PseudoSprite::SetBE(uint i, uint num) { assert(num>0 && num<5); switch (num) { case 2: return SetEscape(i, false, mysprintf(" \\wx%x", ExtractWord(i)), 2); case 3: return SetEscape(i, false, mysprintf(" \\b*x%x", ExtractExtended(i)), ExtendedLen(i)); case 4: return SetEscape(i, false, mysprintf(" \\dx%x", ExtractDword(i)), 4); } return SetHex(i, num); } PseudoSprite&PseudoSprite::SetDec(uint i, uint num) { assert(num>0 && num<5); switch (num) { case 1: return SetEscape(i, false, mysprintf(" \\b%d", ExtractByte(i)), 1); case 2: return SetEscape(i, false, mysprintf(" \\w%d", ExtractWord(i)), 2); case 3: return SetEscape(i, false, mysprintf(" \\b*%d", ExtractExtended(i)), ExtendedLen(i)); case 4: return SetEscape(i, false, mysprintf(" \\d%d", ExtractDword(i)), 4); } return SetHex(i, num); } PseudoSprite&PseudoSprite::SetQEscape(uint i){ if(GetState(USEESCAPES)) beauty[i]=QESC; else SetHex(i); return*this; } PseudoSprite&PseudoSprite::SetQEscape(uint i,uint num){ if(GetState(USEESCAPES)){ while(num--) beauty[i++]=QESC; return *this; } return SetHex(i,num); } PseudoSprite&PseudoSprite::SetEscape(uint i, bool quote, string ext, uint len){ if(GetState(USEESCAPES)){ while(len--){ ext_print[i+len]=""; beauty[i+len]=char(quote?QEXT:NQEXT); } ext_print[i]=ext; return *this; } return SetHex(i,len); } PseudoSprite&PseudoSprite::SetEot(uint i){beauty[i]=ENDQUOTE;return*this;} PseudoSprite&PseudoSprite::SetEol(uint i,uint minbreaks,uint lead){ if(GetState(CONVERTONLY)||GetState(LINEBREAKS)>8); SetHex(off,2); // Remove any escape the beautifier might have generated from the old value. return*this; } PseudoSprite&PseudoSprite::SetDwordAt(uint off, uint dword){ VERIFY(off+3>8); packed[off+2]=(uchar)(dword>>16); packed[off+3]=(uchar)(dword>>24); SetHex(off,4); // Remove any escape the beautifier might have generated from the old value. return*this; } PseudoSprite&PseudoSprite::Append(uchar byte){ context.resize(Length()+1); context[Length()]=context[Length()-1]; context[Length()-1].clear(); packed.append(1,byte); return*this; } PseudoSprite&PseudoSprite::ColumnAfter(uint i){ context[i]+='\t'; return*this; } static uint(PseudoSprite::* const ExtractFuncs[])(uint)const= {NULL,&PseudoSprite::ExtractByte,&PseudoSprite::ExtractWord,&PseudoSprite::ExtractExtended,&PseudoSprite::ExtractDword}; uint PseudoSprite::ExtractVariable(uint offs,uint length)const{ VERIFY((length&&length<5),length); return(this->*(ExtractFuncs[length]))(offs); } uint PseudoSprite::ExtendedLen(uint offs)const{ return ExtractByte(offs)!=0xFF?1:3; } uint PseudoSprite::LinkSafeExtractByte(uint offs)const{ VERIFY(IsValid(),IsValid()); if(Length()<=offs) throw offs|1<<24; return(uchar)packed[offs]; } uint PseudoSprite::ExtractByte(uint offs)const{ CheckLinkage(offs,1); return LinkSafeExtractByte(offs); } uint PseudoSprite::ExtractWord(uint offs)const{ try{ CheckLinkage(offs,2); return LinkSafeExtractByte(offs)|LinkSafeExtractByte(offs+1)<<8; }catch(unsigned int){ throw offs|2<<24; } } uint PseudoSprite::ExtractExtended(uint offs)const{ uint val=LinkSafeExtractByte(offs); if(val!=0xFF){ CheckLinkage(offs,1); return val; } if(linkage[offs]!=0 && linkage[offs]!=1) { CheckLinkage(offs,3); ignorelinkage = true; } val = ExtractWord(offs+1); ignorelinkage = false; return val; } uint PseudoSprite::ExtractDword(uint offs)const{ try{ CheckLinkage(offs,4); ignorelinkage=true; uint val = ExtractWord(offs)|ExtractWord(offs+2)<<16; ignorelinkage=false; return val; }catch(unsigned int){ throw offs|4<<24; } } void PseudoSprite::AddComment(const string&str,uint i){ if(i==(uint)-1)NoBeautify(); else if(context[i]=="")context[i]+='\n'+str+'\n'; else if(context[i][context[i].length()-1]=='\n')context[i]+=str+'\n'; else{ uint offs=(uint)context[i].find_last_of('\n')+1; context[i]=context[i].substr(0,offs)+str+context[i].substr(offs); } } void PseudoSprite::TrailComment(const string&str,uint i){ if(i==(uint)-1)NoBeautify(); else if(context[i]=="")context[i]=str+'\n'; else if(context[i][0]!='\n')return; else context[i]=str+'\n'+context[i]; } void PseudoSprite::AddBlank(uint i){ if(i==(uint)-1)NoBeautify(); else if(context[i]=="")context[i]="\n\n"; else if(!Length())context[i]+='\n'; else{ string::size_type offs=context[i].find_first_of('\n'); if(offs==NPOS||context[i].substr(offs,2)!="\n\n") context[i]=context[i].substr(0,offs)+'\n'+context[i].substr(offs); } } void PseudoSprite::NoBeautify(){ useorig=true; } ostream&operator<<(ostream&out,PseudoSprite&sprite){ sprite.output(out); return out; } // Modified from a tokenizer in the C++ Programming HOW-TO by Al Dev (Alavoor Vasudevan) // http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html#ss7.3 // "Copyright policy is GNU/GPL as per LDP (Linux Documentation project)." // http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-22.html vector Tokenize(const string& str, char delimiter) { vector tokens; // Skip delimiters at beginning. string::size_type lastPos = str.find_first_not_of(delimiter); // Find first "non-delimiter". string::size_type pos = str.find_first_of(delimiter, lastPos); while (string::npos != pos || string::npos != lastPos) { // Found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // Skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiter, pos); // Find next "non-delimiter" pos = str.find_first_of(delimiter, lastPos); } return tokens; } ostream&PseudoSprite::output(ostream&out){ if(!valid){ istringstream datastream(orig); string line; getline(datastream,line); out<6){ if((beauty[i]&~NOBREAK)==QESC){ if((*this)[i]=='\r'){ outbuf<<"\\n"; count=+2; }else{ outbuf<6 && (beauty[i]&~NOBREAK)==NQEXT) str = ext_print[i].c_str()+skipspace; else str = mysprintf(" %2x"+skipspace,(*this)[i]); outbuf<=GetState(MAXLEN)-15) || (instr && ((count>=GetState(MAXLEN)-15 && (*this)[i]==' ') || count>=GetState(MAXLEN)))) && i > sections; foreach(const string &line, (Tokenize(buffer, '\n'))) sections.push_back(Tokenize(line, '\t')); // Count the columns uint columns = (uint)max_element(sections.begin(),sections.end(), bind(&vector::size,_1) < bind(&vector::size,_2))->size(); // For each column, for(uint i=0;i §ion, sections) if(section.size()>i+1) padWidth = max(padWidth, section[i].length()+1); // and make it that wide. foreach(vector §ion, sections) if(section.size()>i+1) section[i] += string(padWidth - section[i].length(), ' '); } // Tabs are expanded, write each line foreach(const vector&line, sections) for_each(line.begin(),line.end(),out<<_1)('\n'); }else out<0x1F&&(byte!='"'||NFOversion>6)&&(byte<0x7F||byte>0x9F); } bool PseudoSprite::DoQuote(uint i)const{ if((beauty[i]&~NOBREAK)==QESC || (beauty[i]&~NOBREAK)==QEXT) return NFOversion>6; // Quote IFF we have escapes return (CanQuote((*this)[i])&&IsText(i))||(IsUTF8(i)&&GetState(QUOTEUTF8)); } void PseudoSprite::Invalidate(){ IssueMessage(0,PARSE_FAILURE,_spritenum); valid=false; SetCode(EPARSE); } bool PseudoSprite::IsText(uint i)const{ int type = beauty[i]&~NOBREAK; if (NFOversion>6) return type==TEXT || type==ENDQUOTE || type==QESC || type==QEXT; else return type==TEXT || type==ENDQUOTE; } bool PseudoSprite::IsUTF8(uint i)const{ return (beauty[i]&~NOBREAK)==UTF8; } bool PseudoSprite::IsEot(uint i)const{ return (beauty[i]&~NOBREAK)==ENDQUOTE; } bool PseudoSprite::IsLinePermitted(uint i)const{ return!(beauty[i]&NOBREAK); } bool PseudoSprite::UseOrig()const{ return useorig||!GetState(BEAUTIFY); } uint PseudoSprite::ReadValue(istream& in, width w) { if (in.peek() == 'x') { // Read any hex value uint ret; in.ignore()>>setbase(16)>>ret>>setbase(10); return ret; } if (in.peek() == '(') { // Read any RPN value if(RPNOFF){ IssueMessage(0, INVALID_EXTENSION); return 0; } int val, err = 0, s = in.tellg(); val = DoCalc(in.ignore(),err); if (err>0) return 0; // Replace the original RPN with value int e = in.tellg(), p = orig.find(((istringstream&)in).str().substr(s, e - s)); orig.erase(p, e - s); ostringstream Val; Val << val; orig.insert(p, Val.str()); return val; } // Read any other value string str; // can't use operator>> -- that will consume comments in cases like \w12000//comment eat_white(in); // skip whitespace at front while(in && !is_comment(in) && !isspace(in.peek()) && in.peek() != EOF) str += (char)in.get(); char c1, c2; int y, m, d, count = sscanf(str.c_str(), "%d%c%d%c%d", &y, &c1, &m, &c2, &d); if (count==1) { // Got a decimal number if (w==_B_ && y>1920) y-=1920; // special case for byte-sized years return y; } // May have a date. Check, fiddle, and invoke date_time. if (count == 5 && c1 == c2 && (c1 == '-' || c1 == '/')) { int extra = 0; if (w == _W_) { // word date if (d==0 || (d>31 && d<100) || d>1919) swap(y, d); // Try DMY instead if (y==0) y = 2000; else if (y>31 && y<100) y+=1900; } else if (w == _D_) { // dword date extra = 701265; if (d >= 32) swap(y, d); // Try DMY instead // Boost doesn't support years out of the range 1400..9999 while (y>9999) { y -= 400; extra += 365*400 + 97; // 97 leap years every 400 years. } while (y<1400) { y += 400; extra -= 365*400 + 97; } } else goto fail; // I can't read a date of that width. try { return (date((ushort)y, (ushort)m, (ushort)d) - date(1920, 1, 1)).days() + extra; } catch (std::out_of_range) { // Fall through to fail } } fail: // Nothing worked in.clear(ios::badbit); return (uint)-1; } grfcodec-6.0.3/src/grfdiff.cpp0000644000000000000000000003423412027143046014701 0ustar rootroot /*****************************************\ * * * GRFDiff - A program to compare a .grf * * file and the decoded .pcx * * file(s) and produce a file * * of the sprites that were * * modified * * * * * * Copyright (C) 2003 by Josef Drexler * * * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #include #include #include #include #include #include #include #include #include #define DOCHECK #include "error.h" #include "sprites.h" #include "grfcomm.h" #include "grfmrg.h" #include "path.h" #include "version.h" /* Format of a .GRD file: Offset Size Content 0 4 Magic code to identify the GRD file 4 2 GRD file version 6 2 Number of sprites in this file 8 1 Length of GRF filename=L (including terminating NULL) 9 L GRF filename, without .grf extension or path 9+L var. Sprite data Each sprite has this format: Offset Size Content 0 2 Number of the sprite, counting from 0 2 var. Sprite content as stored in a GRF file */ U32 GRDmagic = 0x67fb49ad; const char *grffile[2]; char *grdfile = NULL; FILE *grd = NULL; long grdstart; int selfextr = 0, alwaysyes = 0, onlylist = 0; char *difflist; int difflistfrom, difflistto; int differences[32][2], diffruns; const char *exts[2] = { ".GRD", ".EXE" }; static void usage(void) { printf( "Usage:\n" " GRFDiff [options] \n" " Compare the two GRF files and produce a GRD file containing only the\n" " sprites from the second file that are different from the first file.\n" "\n" "GRFDiff makes a .GRD file with the same basename as the new GRF file.\n" "\n" "Options:\n" " -h Show this help\n" " -l \n" " Save the sprites with these numbers in the .GRD instead of\n" " finding the modified sprites. With this option, the first\n" " GRF file can be omitted.\n" " Format of the numbers: [-][,[-]]...\n" " e.g. 1-5,8,20-31 (must be increasing numbers)\n" " -n Only show a list of modified sprites, don't make a .GRD file\n" " -o \n" " Write to this file instead\n" " -x Make a self-extracting (.EXE) file instead of a .GRD\n" " -y Answer 'y' to all questions\n" "\n" "You can specify several sets of GRF files along with their -l options by\n" "separating them with a double-dash `--'. The result will be written to a\n" "single .GRD file. Only -l is valid after the first set.\n" "\n" "GRFDiff is Copyright (C) 2003 by Josef Drexler\n" "You may copy and redistribute it under the terms of the GNU General Public\n" "License, as stated in the file 'COPYING'.\n" ); exit(1); } void closegrd() { if (ftell(grd) <= grdstart) { // zero-length file, remove it printf("Removing %s\n", grdfile); remove(grdfile); } else { // write "EOF" marker GRDmagic = ~GRDmagic; cfwrite("writing end-of-file", &GRDmagic, 4, 1, grd); // might have some trailing garbage if the last set of comparisons // was empty (but others weren't), but I don't know how to truncate // a file on Windows } fclose(grd); } void myexit(int code) { if (grd) closegrd(); exit(code); } class infostorer : virtual public spriteinfowriter { public: infostorer(U8 *infptr, U8 **dataptr, U16 *datasizeptr); virtual void addsprite(int x, U8 info[8]); virtual void adddata(U16 newsize, U8 *newdata); U8 *inf; U8 **data; U16 *datasize; }; infostorer::infostorer(U8 *infptr, U8 **dataptr, U16 *datasizeptr) { inf = infptr; datasize = datasizeptr; data = dataptr; } void infostorer::addsprite(int x, U8 info[8]) { int i; for(i=0; i<8; i++) inf[i] = info[i]; } void infostorer::adddata(U16 newsize, U8 *newdata) { *datasize = newsize; *data = newdata; } class grfstore : virtual public spritestorage { public: grfstore(FILE *f) { grf = f; sdata = NULL; }; virtual void newsprite(); virtual void setsize(int sx, int sy); virtual void nextpixel(U8 colour); virtual void spritedone(); void getorgdata(U16 *size, U8 **data); int differsfrom(grfstore *other); FILE *grf; int sizex, sizey; long spritesize, datasize, spriteofs; long fpos_start, fpos_end; U8 *sdata; }; void grfstore::newsprite() { if (sdata) free(sdata); sdata = NULL; fpos_start = ftell(grf); } void grfstore::setsize(int sx, int sy) { sizex = sx; sizey = sy; spritesize = (long) sx * (long) sy; spriteofs = 0; if (!spritesize) // verbatim data? return; sdata = (U8*) malloc(spritesize); if (!sdata) { printf("Cannot allocate %ld bytes for sprite\n", spritesize); myexit(2); } } void grfstore::nextpixel(U8 colour) { if (spriteofs > spritesize) { printf("Sprite has too many pixels!\n"); myexit(2); } sdata[spriteofs++] = colour; } void grfstore::spritedone() { if (spriteofs < spritesize) { printf("Sprite has too few pixels!\n"); myexit(2); } fpos_end = ftell(grf); } int grfstore::differsfrom(grfstore *other) { if ( (sizex != other->sizex) || (sizey != other->sizey) ) return 1; return memcmp(sdata, other->sdata, spritesize); } void grfstore::getorgdata(U16 *size, U8 **data) { *size = fpos_end - fpos_start; long fpos_cur = ftell(grf); *data = (U8*) malloc(*size); if (!*data) { printf("Cannot allocate %d bytes for data\n", *size); myexit(2); } fseek(grf, fpos_start, SEEK_SET); cfread("reading GRF", *data, 1, *size, grf); fseek(grf, fpos_cur, SEEK_SET); } char *grfbasename(const char *filename) { static char bname[32]; fnsplit(filename, NULL, NULL, bname, NULL); return bname; } time_t mtime(FILE *f) { struct stat statbuf; fstat(fileno(f), &statbuf); return statbuf.st_mtime; } char *strmtime(time_t mtime) { static char strtime[128]; strftime(strtime, sizeof(strtime), "%d %b %Y %H:%M:%S", localtime(&mtime)); return strtime; } void mkselfextr() { static const char *action = "writing exe"; char *block; U8 r = 0, e; long newr = 0, chunk = 0, grdofs, blank; cfwrite(action, grfmrg, 1, grfmrgsize, grd); e = 0; while (!r) { chunk = 1< 255) { e++; } else { r = newr; } } fseek(grd, 0x1c, SEEK_SET); cfwrite(action, "JD", 2, 1, grd); cfwrite(action, &r, 1, 1, grd); cfwrite(action, &e, 1, 1, grd); fseek(grd, 0, SEEK_END); if (ftell(grd) != (S32) grfmrgsize) { printf("Huh???\n"); myexit(2); } grdofs = newr * chunk; blank = grdofs - grfmrgsize; if (blank) { block = (char*) malloc(blank); if (!block) { printf("Out of memory.\n"); myexit(2); } memset(block, 0, blank); cfwrite(action, block, 1, blank, grd); free(block); } } void opengrd() { if (grdfile) { grd = fopen(grdfile, "wb"); if (!grd) { fperror(e_openfile, grdfile); myexit(2); } } else if (!onlylist) { doopen(grffile[1], "", exts[selfextr], "wb", &grdfile, &grd, 0); } else { grd = NULL; } if (grd) { printf("Writing %s\n", grdfile); if (selfextr) mkselfextr(); grdstart = ftell(grd); } return; } int mkdiff() { static const char *action = "writing GRD"; FILE *grf[2]; long grfsize, thisgrdstart = 0; int res[2], i, isdiff, numdiff = 0, numdiffofs = 0, lastpct = -1; time_t modtime[2]; for (i=0; i<2; i++) if (grffile[i]) { grf[i] = fopen(grffile[i], "rb"); if (!grf[i]) { fperror(e_openfile, grffile[i]); myexit(2); } modtime[i] = mtime(grf[i]); } else grf[i] = NULL; if (grffile[0] && (modtime[0] > modtime[1])) { printf("Warning, %s is newer than %s.\n", grffile[0], grffile[1]); printf("%s was last modified on %s\n", grffile[0], strmtime(modtime[0])); printf("%s was last modified on %s\n", grffile[1], strmtime(modtime[1])); printf("But you've told me that %s contains the new sprites.\n", grffile[1]); printf("Are you sure you have the right order on the command line [Y/N] ? "); if (alwaysyes) printf("Y\n"); else if (tolower(getc(stdin)) != 'y') { printf("\nAborted.\n"); myexit(2); } printf("\nContinuing.\n"); } if (grd) { char *noext = grfbasename(grffile[1]); char *p; for (p = noext; *p; p++) { *p = tolower(*p); } thisgrdstart = ftell(grd); cfwrite(action, &GRDmagic, 4, 1, grd); i = 1; // GRD file version cfwrite(action, &i, 2, 1, grd); numdiffofs = ftell(grd); cfwrite(action, &numdiff, 2, 1, grd); i = strlen(noext) + 1; cfwrite(action, &i, 1, 1, grd); cfwrite(action, noext, 1, i, grd); } else grdfile = NULL; fseek(grf[1], 0, SEEK_END); grfsize = ftell(grf[1]); fseek(grf[1], 0, SEEK_SET); U8 inf[2][8], *verbdata[2], *data; U16 verbsize[2], size; grfstore *grfdata[2]; infostorer *grfinf[2]; for (i=0; i<2; i++) if (grf[i]) { grfdata[i] = new grfstore(grf[i]); grfinf[i] = new infostorer(inf[i], &verbdata[i], &verbsize[i]); } for (int spriteno = 0; ; spriteno++) { int thispct = ftell(grf[1])*100L/grfsize; if (thispct != lastpct) { lastpct = thispct; printf("\rSprite%5d Done:%3d%% \r", spriteno, thispct); } verbdata[0] = verbdata[1] = data = NULL; for (i=0; i<2; i++) if (grf[i]) { verbsize[i] = 0; res[i] = decodesprite(grf[i], grfdata[i], NULL, grfinf[i], spriteno, NULL, 1); } if (grf[0] && (res[0] != res[1])) { printf("The GRF files have a different number of sprites!\n"); myexit(2); } if (!res[1]) { printf("\rSprite%5d Done:%3d%% \r", spriteno, 100); break; } if (difflist) { while ( (difflistfrom < 0) || (spriteno > difflistto) ) { difflistfrom = difflistto = 32767; if (difflist[0] == ',') difflist++; if (!difflist[0]) break; difflistfrom = strtol(difflist, &difflist, 0); difflistto = -1; switch (difflist[0]) { case ',': difflist++; case 0: difflistto = difflistfrom; break; case '-': difflist++; difflistto = strtol(difflist, &difflist, 0); break; default: printf("Invalid number format at %s\n", difflist); myexit(2); } } isdiff = ( (spriteno >= difflistfrom) && (spriteno <= difflistto) ); } else { isdiff = 0; // find out if they're different, and remember original data if so if (verbsize[0]) { if (verbsize[0] != verbsize[1]) isdiff = 1; else isdiff = memcmp(verbdata[0], verbdata[1], verbsize[0]); } else if (verbsize[1]) { isdiff = 1; } else { isdiff = (inf[0][0] & ~1) != (inf[1][0] & ~1); if (!isdiff) isdiff = memcmp(inf[0]+1, inf[1]+1, 7); if (!isdiff) isdiff = grfdata[0]->differsfrom(grfdata[1]); } } if (isdiff) { numdiff++; if (!onlylist) { // this is a bit redundant for the verbatim data, // but the code is a lot clearer this way grfdata[1]->getorgdata(&size, &data); // store the modified sprite cfwrite(action, &spriteno, 2, 1, grd); cfwrite(action, data, 1, size, grd); } if ( (diffruns < 0) || (spriteno != differences[diffruns][1]+1) ) { diffruns++; int nummax = sizeof(differences)/sizeof(differences[0]) - 1; if (diffruns >= nummax) { diffruns = nummax; differences[diffruns][0] = -1; } else differences[diffruns][0] = spriteno; } differences[diffruns][1] = spriteno; } if (data) free(data); if (verbdata[0]) free(verbdata[0]); if (verbdata[1]) free(verbdata[1]); } if (!onlylist) { long grdcur = ftell(grd); fseek(grd, numdiffofs, SEEK_SET); cfwrite(action, &numdiff, 2, 1, grd); fseek(grd, grdcur, SEEK_SET); } if (diffruns < 0) { printf("\nNo differences."); if (grd) fseek(grd, thisgrdstart, SEEK_SET); } else { printf("\nSprites with differences: "); for (i=0; i<=diffruns; i++) { if (differences[i][0] >= 0) { printf("%d", differences[i][0]); if (differences[i][0] < differences[i][1]) printf("-%d", differences[i][1]); } else printf("... and others"); if (i < diffruns) printf(", "); } printf(" (%d total)", numdiff); } for (i=0; i<2; i++) if (grf[i]) fclose(grf[i]); printf("\nDone!\n"); return 1; } void onlyfirst(char opt) { printf("Warning: Option `-%c' is only valid in the first set of GRF files\n\tand cannot be set later.\n", opt); } int moreargs(int argc, char **argv) { if (optind >= argc) return 0; return strcmp(argv[optind], "--"); } int main(int argc, char **argv) { puts("GRFDiff " VERSION " - Copyright (C) 1999-2003 by Josef Drexler"); // loop over all sets of comparisons for (int grfset=0; optind. Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #include "endian.h" #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ void md5_init(md5_state_t *pms); /* Append a string to the message. */ void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ grfcodec-6.0.3/src/actB.cpp0000644000000000000000000000513612027143046014142 0ustar rootroot/* * actB.cpp * Contains definitions for checking action Bs. * * Copyright 2005-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include using namespace std; #include"nforenum.h" #include"inlines.h" #include"sanity_defines.h" #include"messages.h" #include"data.h" #include"strings.h" #include"pseudo.h" #include"command.h" class B{ public: uint maxSeverity,numMessages; AUTO_ARRAY(uchar); SINGLETON(B); }; B::B(){ FILE*pFile=myfopen(B); maxSeverity=GetCheckByte(B); _p=new uchar[numMessages=GetCheckByte(B)]; myfread(_p,numMessages,B); fclose(pFile); } void CheckB(PseudoSprite&data){ uint sev=data.ExtractByte(1),lang=data.ExtractByte(2),messageid=data.ExtractByte(3); uint offset=4; int specials; if((sev&0x7F)>B::Instance().maxSeverity)IssueMessage(ERROR,INVALID_SEVERITY); if(_grfver){ if(lang&0x80||(_grfver<7&&lang&0x60&&(lang&0x7F)!=0x7F))IssueMessage(WARNING2,UNKNOWN_LANG_BIT,2,lang); lang&=0x7F; if(_grfver>6)CheckLangID(lang,2); }else if((lang&=0x7F)>0x1F){ _grfver=7; CheckLangID(lang,2); _grfver=0; } if(messageid!=0xFF&&messageid>=B::Instance().numMessages){ IssueMessage(FATAL,INVALID_MESSAGEID); return; } if(messageid==0xFF) specials=CheckString(data,offset,CTRL_NEWLINE,false,MakeStack(4,STACK_TEXT,STACK_TEXT,STACK_DWORD,STACK_DWORD),RETURN_STACK); else specials=B::Instance()[messageid]; if(specials==-1)return; if(specials>1){ try{ if(messageid==0xFF&&data.ExtractByte(offset))data.SetEol(offset-1,1); else data.SetNoEol(offset-1); }catch(uint){} CheckString(data,offset,CTRL_NEWLINE); } if(specials>2){ if(data.ExtractByte(offset)>0x7F) IssueMessage(ERROR,INVALID_PARAM,offset,data.ExtractByte(offset)); offset++; } if(specials>3){ if(data.ExtractByte(offset)>0x7F) IssueMessage(ERROR,INVALID_PARAM,offset,data.ExtractByte(offset)); offset++; } if(offset!=data.Length())IssueMessage(WARNING2,EXTRA_DATA,data.Length(),offset); } grfcodec-6.0.3/src/utf8.h0000644000000000000000000000073312027143046013622 0ustar rootroot/**************************************************************************** * utf8.h * This header file defines constants and macros to be used for utf8 * decoding. * ***************************************************************************/ /* Original version (such as it is) at http://xsb.sourceforge.net/api/utf8_8h-source.html*/ #ifndef UTF8_H_INCLUDED #define UTF8_H_INCLUDED string GetUtf8Encode(uint); #endif /*UTF8_H_INCLUDED*/ grfcodec-6.0.3/src/act14.cpp0000644000000000000000000000611012027143046014176 0ustar rootroot/* * act14.cpp * Contains definitions for checking action 14s. * * Copyright 2005-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include using namespace std; #include"nforenum.h" #include"pseudo.h" #include"messages.h" #include"strings.h" #include"command.h" static bool Check14(PseudoSprite&data, uint&offset, vector&idstack) { /* NFORenum reads the NFO, which is a text file. As per definition the * NFO is LE ordered. If characters are interpreted as bytes they will * therefore be read in LE order. ExtractDword does interpret the * characters as bytes and construct a host endian ordered integer. * Consequently, there is no need to swap endian for the read data; it * will always be in the host order, or the constant below as long as * they have the expected integer value, thus reverse due to LE. */ static const uint ID_INFO = 0x4F464E49; // INFO in reverse order (LE) static const uint ID_PALS = 0x534C4150; // PALS in reverse order (LE) uint type = data.ExtractByte(offset++); while (type != 0) { uint id = data.ExtractDword(offset); offset += 4; idstack.push_back(id); switch (type) { case 'C': if (!Check14(data, offset, idstack)) return false; break; case 'T': { uint langs = data.ExtractByte(offset); extern uint _grfver; /* Hardcode GRF version to 7 as that's needed for the language ids * and because we at least require version 7; that is actually * checked a little bit later during Action 8. */ _grfver = 7; if (langs & 0x80) IssueMessage(WARNING2, UNKNOWN_LANG_BIT, offset, langs); langs &= 0x7F; CheckLangID(langs, offset++); CheckString(data, offset, CTRL_COLOR | CTRL_NEWLINE); break; } case 'B': { extern uint _act14_pal; uint size = data.ExtractWord(offset); offset += 2; if (idstack.size()==2 && idstack[0]==ID_INFO && idstack[1]==ID_PALS) { uint pal=data.ExtractByte(offset); if (size==1 && (pal=='D' || pal=='W' || pal=='A')) { _act14_pal=pal; } else IssueMessage(ERROR, INVALID_PALETTE_INFO, offset); } offset += size; break; } default: IssueMessage(FATAL, UNKNOWN_ACT14_TYPE, offset, type); return false; } idstack.pop_back(); type = data.ExtractByte(offset++); } return true; } void Check14(PseudoSprite&data) { vectoridstack; uint offset = 1; Check14(data, offset, idstack); } grfcodec-6.0.3/src/rangedint.cpp0000644000000000000000000000326012027143046015240 0ustar rootroot/* * rangedint.cpp * * Definitions for class of integers with a limited range. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ typedef unsigned int uint; #include "rangedint.h" RangedUint::RangedUint(uint max):m_max(max){} RangedUint::RangedUint(uint val,uint max):m_max(max),m_val(val){} RangedUint::operator uint()const{return m_val;} const RangedUint&RangedUint::operator+=(uint right){ if(m_val+right>=m_val)m_overflow=(m_val+=right)>m_max; else m_overflow=true; return*this; } const RangedUint&RangedUint::operator-=(uint right){ m_overflow=(m_val-right<=m_val); m_val-=right; return*this; } const RangedUint&RangedUint::operator/=(uint right){ m_overflow=false; m_val/=right; return*this; } const RangedUint&RangedUint::operator*=(uint right){ if(right&&(m_val*right)/right!=m_val) m_overflow=true; else m_overflow=(m_val*=right)>=m_max; return*this; } const RangedUint&RangedUint::operator=(uint right){ m_overflow=(right>m_max); m_val=right; return*this; } grfcodec-6.0.3/src/messages.h0000644000000000000000000000562512027143046014550 0ustar rootroot/* * messages.h * Contains messages output by NFORenum, and declares related functions * * Copyright 2004-2006 by Dale McCoy. * Copyright 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_MESSAGES_H_INCLUDED_ #define _RENUM_MESSAGES_H_INCLUDED_ #include // Message properties #define MAKE_COMMENT 1 //Indicates that the message should be prefixed with "//!!" #define USE_PREFIX 2 //Use the appropriate PREFIX_* string, as determined by the minSan argument to IssueMessage #define HAS_OFFSET 4 //Prefix "Offset %d" #define NO_CONSOLE 8 //Don't auto-send message to console // Message output stream #define TO_ERROR 0 #define TO_OUT 0x10 #define TO_NFO 0x20 #define TO_NULL 0x30 #define TO_MASK 0x30 #define TO_SHIFT 4 // -------- // Generate type RenumMessageId to be an enum of // all the supported message IDs #ifndef MESSAGE #define MESSAGE(name,message,props)name, #define START_MESSAGES(lang) typedef enum { #define END_MESSAGES() } RenumMessageId; #endif//MESSAGE #ifndef ERR_MESSAGE #define ERR_MESSAGE(name,message,props) MESSAGE(name,message,NO_CONSOLE|props|TO_ERROR) #define OUT_MESSAGE(name,message,props) MESSAGE(name,message,NO_CONSOLE|props|TO_OUT) #define NFO_MESSAGE(name,message,props) MESSAGE(name,message,MAKE_COMMENT|props|TO_NFO) #endif #ifndef MESSAGE_EX #define MESSAGE_EX(name,msg,props,loc,base) MESSAGE(name,msg,props|TO_##loc) #endif #ifndef MESSAGE_UNUSED #define MESSAGE_UNUSED(name) MESSAGE(unused_##name,"",0) #endif //#ifndef VMESSAGE // Verbose output messages //#define VMESSAGE(name,message) NFO_MESSAGE(V_##name,message,NO_CONSOLE|HAS_OFFSET) //#endif #include "lang/message_english.h" // -------- // Generate type RenumExtraTextId to be an enum of // all the supported extra text IDs #ifndef EXTRA #define EXTRA(name,str)name, #define START_EXTRA_STRINGS(lang) typedef enum { #define END_EXTRA_STRINGS() __LAST_EXTRA} RenumExtraTextId; #endif //EXTRA #include "lang/extra_english.h" // ------- std::string vIssueMessage(int,RenumMessageId,std::va_list&); std::string IssueMessage(int,RenumMessageId,...); void AutoConsoleMessages(); void ManualConsoleMessages(); std::string mysprintf(const char*,...); std::string myvsprintf(const char*,std::va_list&); #endif//_RENUM_MESSAGES_H_INCLUDED_ grfcodec-6.0.3/src/actF.cpp0000644000000000000000000001365012027143046014146 0ustar rootroot/* * actF.cpp * Contains definitions for checking action Fs. * * Copyright 2005-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include using namespace std; #include"nforenum.h" #include"inlines.h" #include"pseudo.h" #include"messages.h" #include"ExpandingArray.h" #include"strings.h" #include"command.h" class IDarray{ public: void init(){used.resize(0);sprite.resize(0);} bool is_defined(int id)const{return sprite[id]!=0;} bool is_used(int id)const{return used[id];} unsigned short defined_at(int id)const{return sprite[id];} void define(unsigned int id){ used[id]=false; sprite[id]=(unsigned short)_spritenum; } void use(int id){used[id]=true;} protected: Expanding0Arraysprite; Expanding0Arrayused; }status; static const IDarray&crStatus=status; void InitF(){status.init();} #define BITS(first, num) (((1U << (num)) - 1) << (first)) void CheckF(PseudoSprite&data){ data.SetAllHex(); uint id=data.ExtractByte(1),offset=2,langs,oldoff=0; bool isFinal=(id>=0x80); id&=0x7F; if(crStatus.is_defined(id)&&!status.is_used(id))IssueMessage(WARNING1,UNUSED_ID,id,status.defined_at(id)); status.define(id); if(isFinal){ status.use(id); ExpandingArraynameLocs; const ExpandingArray&cNameLocs=nameLocs; uint names=0; langs=data.ExtractByte(offset); do{ if(langs&0x80)IssueMessage(WARNING2,UNKNOWN_LANG_BIT,offset,langs); langs&=0x7F; names++; if(names>1)data.SetEol(oldoff-1,1); oldoff=offset; if(_grfver<7){ if(langs!=0x7F&&langs&0x60)IssueMessage(WARNING3,UNKNOWN_LANG_BIT,offset,langs); if(langs&0x10){if(nameLocs[4])IssueMessage(WARNING2,DUPLICATE_LANG_NAME,offset,4,nameLocs[4]);nameLocs[4]=offset;} if(langs&0x08){if(nameLocs[3])IssueMessage(WARNING2,DUPLICATE_LANG_NAME,offset,3,nameLocs[3]);nameLocs[3]=offset;} if(langs&0x04){if(nameLocs[2])IssueMessage(WARNING2,DUPLICATE_LANG_NAME,offset,2,nameLocs[2]);nameLocs[2]=offset;} if(langs&0x02){if(nameLocs[1])IssueMessage(WARNING2,DUPLICATE_LANG_NAME,offset,1,nameLocs[1]);nameLocs[1]=offset;} if(langs&0x01){if(nameLocs[0])IssueMessage(WARNING2,DUPLICATE_LANG_NAME,offset,0,nameLocs[0]);nameLocs[0]=offset;} }else{ CheckLangID(langs,offset); if(nameLocs[langs]) IssueMessage(WARNING2,DUPLICATE_LANG_NAME,offset,langs,nameLocs[langs]); nameLocs[langs]=offset; } if(CheckString(data,++offset,0)){ IssueMessage(FATAL,OVERRAN_F_NAME,oldoff+1,langs); return; } }while((langs=data.ExtractByte(offset))!=0); if(names>1)data.SetEol(oldoff-1,1); if(_grfver<7){ if(!nameLocs[4])IssueMessage(WARNING1,MISSING_LANG_NAME,4); if(!nameLocs[3])IssueMessage(WARNING1,MISSING_LANG_NAME,3); if(!nameLocs[2])IssueMessage(WARNING1,MISSING_LANG_NAME,2); if(!nameLocs[1])IssueMessage(WARNING1,MISSING_LANG_NAME,1); if(!nameLocs[0])IssueMessage(WARNING1,MISSING_LANG_NAME,0); }else if(!cNameLocs[0x7F])IssueMessage(WARNING1,MISSING_FALLBACK); offset++; } uint num_parts=data.SetEol(offset,1).ExtractByte(offset); if(isFinal)data.SetEol(offset-1,1); if(!num_parts)IssueMessage(ERROR,NO_PARTS,offset); uint bitsused=0; for(uint i=0;i1){ if(bitsused&BITS(firstbit,numbits)){ ostringstream s; int first=-1,bits=bitsused&BITS(firstbit,numbits); for(int j=0;j<32;j++){ if(bits&(1<32)IssueMessage(ERROR,OUT_OF_RANGE_BITS,fb_offs,32); for(uint j=0;j>=1)minbits++; if(numbits -c \n" " je znak (bud /, ;, nebo #), a specifikuje styl komentaru,\n" " ktery bude NFORenum pouzivat. Toto nastaveni neovlivni uvodni\n" " hlavicku souboru kvuli pozadavkum programu grfcodec.\n" " --data[=] -D[]\n" " Jestlize je specifikovan , NFORenum v nem bude hledat\n" " adresar .nforenum a v pripade, ze neexistuje jej vytvori.\n" " Jestlize neni specifikovan , NFORenum vypise cestu\n" " k stavajicimu datovemu adresari.\n" " V kazdem pripade pouziti tohoto parametru odstrani 5 vterinovou\n" " pauzu po vytvoreni adresare .nforenum urcenou pro to, aby uzivatele,\n" " kteri nespousteji program z prikazove radky, meli moznost spatrit\n" " zpravu o vytvoreni adresare.\n" " Standardni chovani: NFORenum hleda adresar .nforenum ve stavajicim\n" " adresari a potom v adresari nastavenem v promenne prostredi HOME\n" " (je-li definovana). V pripade, ze adresar neni nalezen, NFORenum\n" " jej nejprve zkusi vytvorit v HOME a pote ve stavajicim adresari.\n" " --force -f\n" " Nucene zpracovani souboru, ktere nevypadaji jako NFO.\n" " Standardni chovani: NFORenum zpracuje tyto soubory jako by mely\n" " specifikovanou prilis vysokou verzi NFO.\n" " --help -h\n" " Zobrazi tuto napovedu.\n" " --lock\n" " Uzamkne stavajici stav komentarovych prikazu. Prikazy budou\n" " analyzovany obvyklym zpusobem (takze NOPRESERVE bude platit,\n" " @@DIFF bude odstranen, atd) ale nebudou vykonavat zadnou funkci.\n" " --no-replace --keep-old -k\n" " Nenahrazovat puvodni soubor; NFORenum vytvori pro vystup novy\n" " soubor se jmenem ve stylu soubor.new.nfo.\n" " Standardni chovani: NFORenum pouzije soubor soubor[.nfo].new jako\n" " docasny a po ukonceni zpracovani jej prejmenuje na soubor[.nfo]\n" " --auto-correct -a\n" " NFORenum provede zakladni automatickou opravu chybnych pseudo-\n" " spritu. V pripade, ze je tento prepinac zadan dvakrat, NFORenum\n" " bude provadet i opravy, u nichz je vyssi sance, ze budou chybne.\n" "\n" "Nasledujici prepinace zpusobi, ze se NFORenum bude chovat, jako by\n" "vsechny vstupni soubory zacinaly odpovidajicim komentarovym prikazem.\n" "Kompletni popis vsech komentarovych prikazu je v souboru README.\n" "Dodatecne informace pro prikazy ktere je vyzaduji, je mozne zadat\n" "jako argument prepinace. S vyjimkou prepinace -L/--let NFORenum\n" "u argumentu nerozlisuje mezi velkymi a malymi pismeny.\n" "\"ON\" a \"OFF\" lze take zadat jako \"+\" and \"-\".\n" " --beautify -b @@BEAUTIFY\n" " --diff -d @@DIFF\n" " --let -L @@LET\n" " --lint -l @@LINT\n" " --preserve-messages -p @@PRESERVEMESSAGES\n" " --real-sprites -r @@REALSPRITES\n" " --use-old-nums -o @@USEOLDSPRITENUMS\n" " --warning-disable -w @@WARNING DISABLE\n" " --warning-enable -W @@WARNING ENABLE\n" " Jako argument prepinacu -w a -W (a jejich dlouhych variant)\n" " lze take zadat seznam carkou oddelenych ID zprav, ktere maji byt\n" " aktivovany ci deaktivovany.\n" "\n" "NFORenum - Copyright 2004-2009 Dale McCoy\n" "Tento program lze kopirovat a sirit dle podminek GNU General Public\n" "License obsazenych v souboru 'COPYING'.\n" "\n" "V pripade, ze jste nestihli precist celou zpravu, zkuste pouzit\n" " nforenum -h | more\n" END_HELP_TEXT() grfcodec-6.0.3/src/lang/extra_english.h0000644000000000000000000000631612027143046016514 0ustar rootroot/* * extra_english.h * Extra program text in English language. * * Copyright 2005-2006,2009 by Dale McCoy. * Copyright 2006 by Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Names of extra strings, below, are passed to correspond // with a %s or %S argument in the format. // A %S string consumes any arguments that immediately follow it, // according to its format, while %s strings do not. // If a literal char* must be passed, (eg __FILE__), use %t instead. // START_EXTRA_STRINGS() // - Language id as defined in language_list.h START_EXTRA_STRINGS(RL_ENGLISH) EXTRA(PREFIX_UNPARSEABLE,"Processing Failure: ") EXTRA(PREFIX_LINT_FATAL,"Fatal Error (%d): ") EXTRA(PREFIX_LINT_ERROR,"Error (%d): ") EXTRA(PREFIX_LINT_WARNING,"Warning (%d): ") EXTRA(OFFSET,"Offset %d: ") EXTRA(LOADING,"loading") EXTRA(LOADED,"loaded") EXTRA(LOTS,"lots-of-cargo") EXTRA(HOUSE_INSTYTILE,"houses and industry tiles") EXTRA(INDUSTRIES,"industries") EXTRA(BASICSTD2,"basic standard 02s") EXTRA(PROD2S,"Production callbacks") EXTRA(PROD2,"production callback") EXTRA(GROUND,"ground") EXTRA(NONTRANS,"non-transparent") EXTRA(GRF,"GRF") EXTRA(ACTION,"action %xs") EXTRA(IMPORTS,"sound import sprites") EXTRA(TYPE,"%s for %s") EXTRA(AT_LEAST,"at least %d") EXTRA(EXACTLY,"%d") EXTRA(ONE_OF,"%d or %d") EXTRA(VARS,"%s and %s") EXTRA(VAL,"%2x") EXTRA(VALS,"%2x and %2x") EXTRA(REAL_S,"real sprite") EXTRA(BIN_INCLUDE,"binary include") EXTRA(RECOLOR_TABLE,"recolor table") EXTRA(SET,"action 1 set") EXTRA(CID,"cargo ID") EXTRA(PROPLENGTH,"declared property length") EXTRA(ID,"ID") EXTRA(CARGO,"Cargo") EXTRA(ACT5_SIZE,"%d (0x%x)") EXTRA(ACT5_ORSIZE," or %d (0x%x)") EXTRA(EOF_READING_NAME,"EOF while reading name %2x.") EXTRA(OVERLENGTH_NAME,"Name %2x exceeds 100 characters long.") EXTRA(OPEN,"open") EXTRA(LOAD,"load") EXTRA(WRITE,"write") EXTRA(BYTE1,"byte 1") EXTRA(FEATURE,"feature") EXTRA(NUMINFO,"numinfo") EXTRA(NUMIDS,"numids") EXTRA(NUMENT1,"nument1") EXTRA(NUMENT2,"nument2") EXTRA(NVAR,"nvar") EXTRA(NRAND,"nrand") EXTRA(NID,"n-id") EXTRA(NUMCID,"num-cid") EXTRA(NUM,"num") EXTRA(NUMENT,"num-ent") EXTRA(NUMSPRITES,"num-sprites") EXTRA(NUMSETS,"num-sets") EXTRA(NUMDEFS,"num-defs") EXTRA(VARSIZE,"var-size") EXTRA(COND,"cond") EXTRA(XPOS,"xpos") EXTRA(YPOS,"ypos") EXTRA(XSIZE,"xsize") EXTRA(YSIZE,"ysize") EXTRA(XREL,"xrel") EXTRA(YREL,"yrel") EXTRA(XOFF,"xoff") EXTRA(XOFF_EXT,"xoff+xextent") EXTRA(YOFF,"yoff") EXTRA(YOFF_EXT,"yoff+yextent") EXTRA(FILELINE,"(%t:%d)") EXTRA(ERRNO,"(%d)") EXTRA(DAT2,"%2x %2x") EXTRA(DAT3,"%2x %2x %2x") END_EXTRA_STRINGS() grfcodec-6.0.3/src/lang/message_english.h0000644000000000000000000005345512027143046017023 0ustar rootroot/* * message_english.h * Message text and data in English language. * * Copyright 2005-2009 by Dale McCoy. * Copyright 2006 by Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Only the properties for messages in English are relevant. // Properties defined in files for additional languages are ignored. // MESSAGE_UNUSED and maintaining the message order is required in // English, but optional in all other languages. // The first message is different for a reason. // It is not run through myvsprintf; a number is appended at runtime. // All other messages follow the printf format // (see myvsprintf in messages.cpp for supported specifiers). // Macro invocations broken across multiple lines must be continued with a // trailing backslash, or checklang.pl will become confused. // START_MESSAGES() // - Language id as defined in language_list.h START_MESSAGES(RL_ENGLISH) ERR_MESSAGE(FATAL_MESSAGE_ERROR,"Fatal error issuing message ",0) ERR_MESSAGE(INTERNAL_ERROR_TEXT,"%t(%d): Fatal error parsing sprite %d: %t cannot equal %d.\n" \ "\t(function %t).\n",0) ERR_MESSAGE(INVALID_DATAFILE,"Data file \"%t\" contains invalid data. (%S)\n",0) ERR_MESSAGE(NO_INPUT_FILE,"Could not open \"%t\" specified on the command line.\n",0) ERR_MESSAGE(NO_OUTPUT_FILE,"Could not open output file \"%t\" for input \"%t\".\n",0) ERR_MESSAGE(REPLACE_FAILED,"Could not replace old file (%t) with new file (%t). (%d)\n",0) ERR_MESSAGE(DATAFILE_ERROR,"Failed to %s data file: \"%t\". %S\n",0) ERR_MESSAGE(CREATE_FAILED,"Could not create .nforenum directory in %t. (%d)\n",0) ERR_MESSAGE(DELETE_FAILED,"Could not remove old file %t. (%d)\n",0) OUT_MESSAGE(CREATED_DIR,"Created .nforenum directory in %t.\n",0) OUT_MESSAGE(PROCESSING,"Processing from standard input.\n",0) OUT_MESSAGE(PROCESSING_FILE,"Processing file \"%t\".\n",0) OUT_MESSAGE(PROCESSING_COMPLETE,"Processing complete.\n",0) ERR_MESSAGE(APPARENTLY_NOT_NFO,"Does not appear to be an NFO file.\n",0) ERR_MESSAGE(UNKNOWN_VERSION,"Unknown NFO file version: %d. ",0)//No \n. That's intentional. OUT_MESSAGE(SKIPPING_FILE,"Skipping file.\n",0) OUT_MESSAGE(PARSING_FILE,"Attempting to parse as version 4.\n",0) ERR_MESSAGE(PARSE_FAILURE,"The sprite following sprite %d could not be processed.\n",0) ERR_MESSAGE(PARTIAL_PARSE_FAILURE,"A portion of sprite %d could not be processed.\n",0) ERR_MESSAGE(NOT_IN_SPRITE,"Found pseudosprite continuation line while looking for sprite %d.\n",0) ERR_MESSAGE(CONSOLE_LINT_FATAL,"Linter failure on sprite %d.\n",0) ERR_MESSAGE(CONSOLE_LINT_ERROR,"Error on sprite %d.\n",0) ERR_MESSAGE(CONSOLE_LINT_WARNING,"Warning on sprite %d (level %d).\n",0) OUT_MESSAGE(CONSOLE_AUTOCORRECT,"Attempting to autocorrect sprite %d.\n",0) MESSAGE_EX(UNEXP_EOF_STD2,"Unexpected EOF: Expected additional standard Action 2s.\n",0,ERROR,UNUSED_SET) MESSAGE_EX(UNEXP_EOF_CARGOID,"Unexpected EOF: Unused CargoIDs detected for feature %x.\n",0,ERROR,UNUSED_ID) MESSAGE_EX(UNEXP_EOF_TOWNNAMES,"Unexpected EOF: Unused town name IDs detected.\n",0,ERROR,UNUSED_ID) MESSAGE_EX(UNEXP_EOF_LONGJUMP,"Unexpected EOF: Action 7/9 jumps past EOF.\n",0,ERROR,LONG_JUMPLEAD) OUT_MESSAGE(STARTUP,"NFORenum " VERSION " - Copyright (C) " YEARS " by Dale McCoy\n",0) NFO_MESSAGE(BAD_RPN,"Invalid RPN expression while reading character %c.\n",0) NFO_MESSAGE(BAD_RPN_EOF,"No close parenthesis found.\n",0) NFO_MESSAGE(UNDEF_VAR,"Undefined variable \"%t\".\n",0) NFO_MESSAGE(COMMAND_INVALID_ARG,"Missing or invalid argument to %t command.\n",0) NFO_MESSAGE(COMMAND_UNKNOWN,"Unknown comment command: %t\n",0) NFO_MESSAGE(COMMAND_REVERT_DEFAULT,"Assuming \"DEFAULT\".\n",0) NFO_MESSAGE(COMMAND_UNKNOWN_VERSION,"Unknown version number. If this version has been released, please get the latest versions.dat from the NFORenum website.\n",0) //UNPARSEABLE NFO_MESSAGE(INVALID_CHARACTER,"Invalid character: \"%c\".\n",0) NFO_MESSAGE(INVALID_EXTENSION,"Invalid escape sequence.\n",0) NFO_MESSAGE(UNTERMINATED_STRING,"Unterminated literal string.\n",0) NFO_MESSAGE(REAL_NO_FILENAME,"Apparent real sprite does not contain a file name.\n",MAKE_COMMENT) NFO_MESSAGE(REAL_MISSING_DATA,"Could not read %t from apparent real sprite.\n",0) //FATAL NFO_MESSAGE(INVALID_LENGTH,"All %S are %S bytes long.\n",USE_PREFIX) NFO_MESSAGE(BAD_LENGTH,"Length does not match %S of %S. (Expected %d bytes)\n",USE_PREFIX) NFO_MESSAGE(TOO_SHORT,"Linter requires %d byte(s) which do(es) not exist.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_FEATURE,"Invalid feature byte.\n",USE_PREFIX) NFO_MESSAGE(INVALID_TYPE,"Invalid nument1 or random-/variational-type byte.\n",USE_PREFIX) NFO_MESSAGE(INVALID_ACTION,"Invalid action byte.\n",USE_PREFIX) NFO_MESSAGE(INVALID_PROP,"Invalid property %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(UNTERM_ACT6,"Action 6 appears to be missing terminating FF.\n",USE_PREFIX) //ERROR NFO_MESSAGE(INSUFFICIENT,"Missing %s. Sprite %d declared %d, but only %d have been seen.\n",USE_PREFIX) NFO_MESSAGE(EXTRA,"Extra %s. The %d declared by sprite %d have already been seen.\n",USE_PREFIX) NFO_MESSAGE(UNEXPECTED,"Unexpected %s found.\n",USE_PREFIX) NFO_MESSAGE(FEATURE_MISMATCH,"Feature byte does not match feature byte of preceding Action %x at sprite %d.\n",USE_PREFIX) NFO_MESSAGE(RAND_2_NUMSETS,"Rand02s require power-of-two sets to choose from.\n",USE_PREFIX) NFO_MESSAGE(INDIRECT_VAR_7E,"Variable 7B is not allowed with parameter 7E.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NEITHER_ID_CALLBACK,"%4x is neither callback nor %s.\n",USE_PREFIX) NFO_MESSAGE(UNDEFINED_SPRITE_SET,"Sprite set %2x does not appear in the preceding Action 1 (sprite %d).\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_CARGO_TYPE,"Invalid cargo type: %2x\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_REQD_SETS,"Action 2 declaring no %s sets.\n",USE_PREFIX) NFO_MESSAGE(CANNOT_EXTEND,"This type of action 5 cannot use the extended format.\n",USE_PREFIX) NFO_MESSAGE(ACTION_5,"Expected %t sprites for this type.\n",USE_PREFIX) NFO_MESSAGE(ACTION_5_LIMIT,"Loading sprites 0x%x..0x%x into an array with only 0x%x entries.\n",USE_PREFIX) NFO_MESSAGE(UNDEFINED_ID,"ID %2x has not been defined.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INSUFFICIENT_PROPS,"Expected %d more properties.\n",USE_PREFIX) NFO_MESSAGE(INSUFFICIENT_DATA,"Expected more data for prop %2x. (%d bytes at %d.)\n",USE_PREFIX) NFO_MESSAGE(INSUFFICIENT_DATA2,"Expected %d more bytes for prop %2x.\n",USE_PREFIX) NFO_MESSAGE(MISSING_TERMINATOR,"Property data is missing terminating byte(s).\n",USE_PREFIX) NFO_MESSAGE(DUPLICATE_ACT,"Action %x already found at sprite %d.\n",USE_PREFIX) NFO_MESSAGE(MISSING_8,"An action 8 must precede action %x.\n",USE_PREFIX) NFO_MESSAGE(INVALID_VERSION,"Invalid %s version number.\n",USE_PREFIX) MESSAGE_UNUSED(BAD_VARIABLE) NFO_MESSAGE(BAD_VARSIZE,"Variable size %2x is invalid.\n",USE_PREFIX) NFO_MESSAGE(BAD_CONDITION,"Condition %2x is invalid.\n",USE_PREFIX) NFO_MESSAGE(GRFCOND_NEEDS_GRFVAR,"Condition %2x requires variable 88.\n",USE_PREFIX) NFO_MESSAGE(GRFVAR_NEEDS_GRFCOND,"Variable 88 requires a GRFid condition.\n",USE_PREFIX) NFO_MESSAGE(BITTEST_VARIABLE,"Variable %2x requires a bit-test condition.\n",USE_PREFIX) NFO_MESSAGE(VARIABLE_SIZE_MISMATCH,"%d is not a valid for variable %2x.\n",USE_PREFIX) MESSAGE_UNUSED(INVALID_LABEL)//,"Labels must have the high 3 bits set (E0-FF).\n",USE_PREFIX) NFO_MESSAGE(INVALID_LITERAL,"%2x was found where a literal %2x was expected.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INSUFFICIENT_STRINGS,"Expected %d more string(s) for this action 4.\n",USE_PREFIX) NFO_MESSAGE(TOO_LARGE,"Value of <%s> must not exceed %2xh.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SPRITENUM_TOO_HIGH,"TTD only defines sprites up to 4984 (1E 13).\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_COLOR_TRANS,"Color translation mode 3 is undefined.\n",USE_PREFIX) NFO_MESSAGE(INVALID_COLOR_SPRITE,"Sprite %d is not a color translation sprite.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_GROUNDSPRITE,"No %s sprite was specified.\n",USE_PREFIX) NFO_MESSAGE(NO_STD_3,"This livery override action 3 does not follow a standard action 3.\n",USE_PREFIX) NFO_MESSAGE(NONEXISTANT_VARIABLE,"Testing nonexistant variable %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(MODIFY_BEYOND_LENGTH,"Action 6 attempts to modify a byte after the end of this sprite.\n",USE_PREFIX) NFO_MESSAGE(NO_FOLLOWING_SPRITE,"There is no following sprite for this Action 6 to modify.\n",USE_PREFIX) //WARNING1 NFO_MESSAGE(NO_SETS,"Action %x declaring no sets.\n",USE_PREFIX) NFO_MESSAGE(NO_SPRITES,"Action %x declaring sets with no sprites.\n",USE_PREFIX) NFO_MESSAGE(SET_WITH_NO_SPRITES,"Set %d contains no sprites.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_PROPS,"Action 0 setting no properties.\n",USE_PREFIX) NFO_MESSAGE(NO_IDS,"Action 0 setting properties for no IDs.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_ID,"Redefining ID %2x not used since previous definition at sprite %d.\n",USE_PREFIX) MESSAGE_EX(UNUSED2IDLEAD,"For feature %x the following cargoIDs have not been used since their most recent definition:\n",MAKE_COMMENT,NFO,UNUSED_ID) MESSAGE_EX(UNUSEDIDFINAL,"%2x (last defined at sprite %d)\n",MAKE_COMMENT,NFO,UNUSED_ID) NFO_MESSAGE(UNUSED_SET,"Set %2x defined by the previous Action 1 (sprite %d) has not been used.\n",USE_PREFIX) NFO_MESSAGE(UNREACHABLE_VAR,"Variation %d cannot be reached.\n",USE_PREFIX) NFO_MESSAGE(EXTRA_DATA,"No more data was expected. Found %d bytes, expected %d bytes.\n",USE_PREFIX) NFO_MESSAGE(REUSED_DEFAULT,"Default ID appears earlier in sprite.\n",USE_PREFIX) NFO_MESSAGE(RESERVED_GRFID,"GRFIDs with a first byte of FF are reserved.\n",USE_PREFIX) NFO_MESSAGE(INDIRECT_VAR_NOT_6X,"Variable 7B only useful for 60+x variables.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SHIFT_TOO_FAR,"Shifting variable %2x past its length.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_MODIFICATIONS,"Action 6 does not make any changes.\n",USE_PREFIX) NFO_MESSAGE(DOES_NOT_MODIFY,"This section does not make any changes.\n",USE_PREFIX|HAS_OFFSET) //WARNING2 MESSAGE_UNUSED(BACKWARDS_GOTO)//,"Action %x jumping backwards to label %2x defined at sprite %d.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_LABEL_NO_PREV_DEF,"Label %2x has not been goto'ed.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_LABEL_PREV_DEF,"Label %2x has not been goto'ed since previous definition at sprite %d.\n",USE_PREFIX) NFO_MESSAGE(REPEATED_PROP,"Property %2x is previously defined at offset %d.\n",USE_PREFIX|HAS_OFFSET) MESSAGE_UNUSED(OFF_TILE) //WARNING3 NFO_MESSAGE(ONLY_ONE_CHOICE,"Random 2 declaring only one choice.\n",USE_PREFIX) NFO_MESSAGE(NOT_VARIATIONAL,"Variational 2 accesses only constant variables (1A & 1C).\n",USE_PREFIX) NFO_MESSAGE(NOT_RANDOM,"All random options have the same ID.\n",USE_PREFIX) MESSAGE_UNUSED(TOO_MANY_STRINGS) NFO_MESSAGE(NO_ACT1,"No preceding action 1.\n",USE_PREFIX) MESSAGE_UNUSED(INVALID_AGAIN)//," must be 00 or 01.\n",USE_PREFIX) NFO_MESSAGE(INVALID_OP,"Invalid operation %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SET_TOO_LARGE,"Sprite set contains more sprites than given feature can use.\n",USE_PREFIX) NFO_MESSAGE(STRANGE_SET_SIZE,"Sprite set contains an unusual number of sprites.\n",USE_PREFIX) MESSAGE_EX(UNUSEDFIDLEAD,"For new town names, the following IDs have not been used since their most recent definition:\n",MAKE_COMMENT,NFO,UNUSED_ID) NFO_MESSAGE(DUPLICATE_GRFID,"GRF ID previously deactivated at offset %d (%8x).\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_GRFIDS,"Action E is not disabling any GRF files.\n",USE_PREFIX) NFO_MESSAGE(INVALID_SRC,"Source parameter %d is invalid.\n",USE_PREFIX) NFO_MESSAGE(INVALID_TARGET,"Target parameter is invalid.\n",USE_PREFIX) NFO_MESSAGE(ONLY_ONE_DATA,"Only one of src1 and src2 may be 0xFF.\n",USE_PREFIX) NFO_MESSAGE(DUPLICATE_LANG_NAME,"A name for %L was previously specified at offset %d.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(MISSING_FALLBACK,"No fallback string was specified.\n",USE_PREFIX) NFO_MESSAGE(NO_PARTS,"Zero parts were specified.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OUT_OF_RANGE_BITS,"Only %d random bits are available.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INSUFFICIENT_BITS,"%x bits are required, but only %2x were allocated.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_PROBABILITY,"A probability of 0 was specified for this part.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(PARAM_TOO_LARGE,"Parameter %2x out of valid range for variable %2x.\n",HAS_OFFSET|USE_PREFIX) NFO_MESSAGE(NO_BUILDING_SPRITE,"Building sprites may not be null.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_SPRITE,"Unexpected end-of-sprite reading building sprite %d.\n",USE_PREFIX) MESSAGE_UNUSED(FIRST_SPRITE_CANNOT_SHARE) NFO_MESSAGE(INVALID_GRFID,"Action %x references reserved GRFid.\n",USE_PREFIX|HAS_OFFSET) MESSAGE_UNUSED(INSUFFICIENT_INCLUDE) MESSAGE_UNUSED(EXTRA_INCLUDE) MESSAGE_UNUSED(UNEXPECTED_INCLUDE) NFO_MESSAGE(OOR_COUNT,"Attempting to manage too many IDs.\n",USE_PREFIX) NFO_MESSAGE(INVALID_ID,"ID %2x out of valid range (%2x..%2x).\n",USE_PREFIX) NFO_MESSAGE(NO_CARGOTYPES," must be 0 for this feature.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_CONTROL,"Using unspecified control character %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_CONTROL,"Control character %2x should not be used in this string.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SMASH_STACK,"Control character %2x does not match %K on top of stack.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SMASH_STACK_SPAN,"Control character %2x reads data from multiple parameters.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_STACK,"Insufficient stack data for control character %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(CANNOT_SHUFFLE,"There is insufficient stack data to shuffle the stack.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_NULL_FOUND,"No terminating null found.\n",USE_PREFIX) NFO_MESSAGE(INVALID_SEVERITY,"Invalid severity byte.\n",USE_PREFIX) NFO_MESSAGE(UNKNOWN_LANG_BIT,"Unrecognized bit set in language-id byte %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_MESSAGEID,"Invalid message id.\n",USE_PREFIX) NFO_MESSAGE(INVALID_PARAM,"%2x is not a GRF parameter.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_OVERRIDE,"Cannot override graphics for this feature.\n",USE_PREFIX) NFO_MESSAGE(COND_SIZE_MISMATCH,"Condition %2x requires %d byte(s).\n",USE_PREFIX) NFO_MESSAGE(REAL_VAL_TOO_SMALL,"Metadata invalid. %s must not be smaller than %d.\n",USE_PREFIX) NFO_MESSAGE(REAL_VAL_TOO_LARGE,"Metadata invalid. %s must not be larger than %d.\n",USE_PREFIX) MESSAGE_UNUSED(REAL_MOVES_UP) NFO_MESSAGE(REAL_BAD_COMP,"Metadata invalid. compression can only have bits 0, 1, 3 and/or 6 set.\n",USE_PREFIX) NFO_MESSAGE(REAL_SPRITE_TOO_LARGE,"Metadata invalid. Sprite size exceeds 64K.\n",USE_PREFIX) NFO_MESSAGE(INVALID_TEXTID,"Text ID %4x is not a valid text ID.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(UNDEFINED_TEXTID,"Text ID %x has not been defined.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(CHECK_0C_RANGE,"Checking for var0C in the range [%2x,%2x].\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_CALLBACK,"%2x is not a valid callback for this feature.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_FONT,"%2x is not a valid font.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SPANS_BLOCKS,"Set %d declares glyphs across a block-break.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_F_NAME,"The name for language(s) %2x has no terminating null.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_F_PART,"The name-part starting at %d has no terminating null.\n",USE_PREFIX) NFO_MESSAGE(OBSCURED_VARIATION,"Variation %d is partially obscured.\n",USE_PREFIX) NFO_MESSAGE(UNREACHABLE_DEFAULT,"Default result cannot be reached.\n",USE_PREFIX) NFO_MESSAGE(DIVIDE_BY_ZERO,"var-adjust performs a divide-by-zero or modulo-zero operation.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(USE_SHIFT_AND,"A shift-and var-adjust would suffice here.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_SHIFT,"shift may not have both high bits set.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(UNDEFINED_TRIGGER,"Using an undefined trigger.\n",USE_PREFIX) NFO_MESSAGE(OVERLENGTH_UTF8,"Invalid UTF-8 sequence: Overlength representation.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_UTF8,"Invalid UTF-8 sequence: First byte not followed by sufficient continuation bytes.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OUTOFRANGE_UTF8,"Invalid UTF-8 sequence: Encodes a character beyond the BMP.\n",USE_PREFIX|HAS_OFFSET) MESSAGE_UNUSED(UNEXPECTED_UTF8_CONT) NFO_MESSAGE(UNKNOWN_LANGUAGE,"Language %2x is not defined.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INCLUDING_00_ID,"Including TextID %4x, which contains a 00 byte.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(AUTOCORRECTING,"Auto-correcting %s from %2x to %2x.\n",HAS_OFFSET) NFO_MESSAGE(EMBEDDED_00,"Embedded null byte.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(LONG_JUMPLEAD,"The following Action 7/9s jump past the end of this file:\n",USE_PREFIX|NO_CONSOLE) MESSAGE_EX(LONG_JUMP,"Action %x at sprite %d.\n",MAKE_COMMENT|NO_CONSOLE,NFO,LONG_JUMPLEAD) NFO_MESSAGE(NO_TEXTS,"Action 4 declaring no strings.\n",USE_PREFIX) NFO_MESSAGE(AUTOCORRECT_ADD,"Adding a trailing %2x byte.\n",0) NFO_MESSAGE(INVALID_EXT_CODE,"Undefined extended format code %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(FEATURE_LINK_MISMATCH,"ID %2x is defined with feature %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(FEATURE_CALL_MISMATCH,"ID %2x is defined with feature %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(AUTOCORRECT_LOOP,"Autocorrector seems to be stuck in an infinite loop.\n",USE_PREFIX) NFO_MESSAGE(BITS_OVERLAP," field %d reuses the following bits already used in this Action F: %t\n",USE_PREFIX|HAS_OFFSET) MESSAGE_EX(MISSING_LANG_NAME,"No name for %L was specified.\n",MAKE_COMMENT|USE_PREFIX,NFO,MISSING_FALLBACK) NFO_MESSAGE(OUT_OF_RANGE_TEXTID_13,"Action 13 can only define texts in the C4xx, C5xx, C9xx, D0xx, and DCxx ranges.\n",USE_PREFIX) NFO_MESSAGE(AND_00,"Anding with 0.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(GENERIC_AND_OVERRIDE,"Action 3 may not be both generic and an override.\n",USE_PREFIX) NFO_MESSAGE(RECURSIVE_F,"Action F may not chain to itself.\n",USE_PREFIX) NFO_MESSAGE(EXCESSIVE_ADD," should not be negative.\n",USE_PREFIX|HAS_OFFSET) MESSAGE_UNUSED(NOT_A_REGISTER)//,"Attempt to access non-existant register %4x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(DUPLICATE,"%s %2x previously specified at offset %d.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(ACT3_PRECEDES_PROP08,"Prop 08 has not been set for ID %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(MASKED_BIT_SET,"GRFID has a bit set that is clear in the mask.\n",USE_PREFIX) NFO_MESSAGE(DISCARD_UNSTORED,"Operation 0F follows a non-store operation.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_PERS_REGS,"No persistent registers exist for this feature.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(DUPLICATE_TRANS_TABLE,"Cargo translation table previously found at sprite %d.\n",USE_PREFIX) NFO_MESSAGE(BAD_RANDSUBTYPE,"Invalid random 2 subtype.\n",USE_PREFIX) NFO_MESSAGE(NO_BYTE_IDS,"Cannot set (extended-)byte IDs for feature %2x.\n",USE_PREFIX) NFO_MESSAGE(COULD_NOT_VERIFY,"Cannot check for usage of undefined IDs: Cannot find feature to check.\n",USE_PREFIX) NFO_MESSAGE(LENGTH_MISMATCH,"Declared length %d does not match actual length %d.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(EXTENSION_MISMATCH,"Found byte %d of a %d-byte escape while reading byte %d of a %d-byte field.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(BEFORE_8,"Action %x must precede action 8.\n",USE_PREFIX) NFO_MESSAGE(INVALID_VERSION_ACT14,"Action 14 requires version number 7 or higher, found %x.\n",USE_PREFIX) NFO_MESSAGE(UNKNOWN_ACT14_TYPE,"Unrecognized type %2x, ignoring rest.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NEED_VERSION_7,"NFO version 7 or higher is needed, found %x.\n",USE_PREFIX) NFO_MESSAGE(NESTED_CHOICE_LIST,"Choice lists can't be nested.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NOT_IN_CHOICE_LIST,"Choice list string code outside of choice list.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_DEFAULT_IN_CHOICE_LIST,"No default choice in choice list.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(CHOICE_LIST_NOT_TERMINATED,"The choice list is not terminated.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INDIRECT_VAR_START,"The first accessed variable may not be 7B.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(MISSING_PALETTE_INFO,"There was no Action 14 specifying the palette.\n",USE_PREFIX) NFO_MESSAGE(INVALID_PALETTE_INFO,"Palette information must be 1 byte (\"D\", \"W\" or \"A\").\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_ACT2_FLAGS,"Unknown flag set (offset %d) in advanced action2.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NOT_IN_REALSPRITE,"Found realsprite continuation line while looking for sprite %d.\n",0) NFO_MESSAGE(REAL_UNKNOWN_FLAG,"Unknown or duplicate flag '%t'.\n",0) NFO_MESSAGE(REAL_DUPLICATE_ZOOM,"Duplicate zoomlevel/depth sprite.\n",0) NFO_MESSAGE(REAL_8BPP_NORMAL_FIRST,"8bpp normal zoom sprite must appear first.\n",0) NFO_MESSAGE(REAL_32BPP_BEFORE_MASK,"mask sprites must be preceded by 32bpp sprites.\n",0) NFO_MESSAGE(UNKNOWN_ACT0_DATA,"Unknown data does not allow processesing past this point.\n",USE_PREFIX|HAS_OFFSET) /* Insert new NFO_MESSAGEs above this line unless a MESSAGE_UNUSED appears in a logical location. */ #if defined DEBUG || defined _DEBUG ERR_MESSAGE(BAD_STRING,"Error: String %d does not exist (%d/%d).\n",0) #else ERR_MESSAGE(BAD_STRING,"Error: String %d does not exist.\n",0) #endif ERR_MESSAGE(DATAFILE_MISMATCH,"%t contains information for fewer features than does feat.dat.\n" \ "Update it, or delete feat.dat.\n",0) ERR_MESSAGE(BAD_CL_ARG,"Unrecognized command-line argument: \"-%c %t\"\n",0) OUT_MESSAGE(DATA_FOUND_AT,"Data files loaded from '%t/.nforenum'.\n",0) END_MESSAGES() grfcodec-6.0.3/src/lang/extra_czech.h0000644000000000000000000000534512027143046016160 0ustar rootroot/* * extra_czech.h * Extra program text in Czech language. * * Copyright 2006 by Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ START_EXTRA_STRINGS(RL_CZECH) EXTRA(PREFIX_UNPARSEABLE,"Chyba pri zpracovani: ") EXTRA(PREFIX_LINT_FATAL,"Kriticka chyba (%d): ") EXTRA(PREFIX_LINT_ERROR,"Chyba (%d): ") EXTRA(PREFIX_LINT_WARNING,"Varovani (%d): ") EXTRA(OFFSET,"Offset %d: ") EXTRA(LOADING,"loading") EXTRA(LOADED,"loaded") EXTRA(LOTS,"lots-of-cargo") EXTRA(HOUSE_INSTYTILE,"budovy a policka prumyslu") EXTRA(INDUSTRIES,"prumysl") EXTRA(BASICSTD2,"Zakladni Akce 2") EXTRA(PROD2S,"Callbacky produkce") EXTRA(PROD2,"callback produkce") EXTRA(GROUND,"ground") EXTRA(NONTRANS,"nepruhledny") EXTRA(GRF,"GRF") EXTRA(ACTION,"Akce %x") EXTRA(IMPORTS,"sprity pro import zvuku") EXTRA(TYPE,"%s pro %s") EXTRA(AT_LEAST,"minimalne %d") EXTRA(EXACTLY,"%d") EXTRA(ONE_OF,"%d nebo %d") EXTRA(VARS,"%s a %s") EXTRA(VAL,"%2x") EXTRA(VALS,"%2x a %2x") EXTRA(REAL_S,"realny sprite") EXTRA(BIN_INCLUDE,"vkladaci sprite") EXTRA(RECOLOR_TABLE,"prebarvovaci tabulka") EXTRA(SET,"skupina z Akce 1") EXTRA(CID,"cargo ID") EXTRA(ACT5_SIZE,"%d (0x%x)") EXTRA(ACT5_ORSIZE," nebo %d (0x%x)") EXTRA(EOF_READING_NAME,"Konec souboru pri nacitani nazvu %2x.") EXTRA(OVERLENGTH_NAME,"Delka nazvu %2x presahuje 100 znaku.") EXTRA(OPEN,"otevrit") EXTRA(LOAD,"nacist") EXTRA(WRITE,"zapisovat") EXTRA(BYTE1,"byte 1") EXTRA(FEATURE,"feature") EXTRA(NUMINFO,"numinfo") EXTRA(NUMIDS,"numids") EXTRA(NUMENT1,"nument1") EXTRA(NUMENT2,"nument2") EXTRA(NVAR,"nvar") EXTRA(NRAND,"nrand") EXTRA(NID,"n-id") EXTRA(NUMCID,"num-cid") EXTRA(NUM,"num") EXTRA(NUMENT,"num-ent") EXTRA(NUMSPRITES,"num-sprites") EXTRA(NUMSETS,"num-sets") EXTRA(NUMDEFS,"num-defs") EXTRA(VARSIZE,"var-size") EXTRA(COND,"cond") EXTRA(XPOS,"xpos") EXTRA(YPOS,"ypos") EXTRA(XSIZE,"xsize") EXTRA(YSIZE,"ysize") EXTRA(XREL,"xrel") EXTRA(YREL,"yrel") EXTRA(XOFF,"xoff") EXTRA(XOFF_EXT,"xoff+xextent") EXTRA(YOFF,"yoff") EXTRA(YOFF_EXT,"yoff+yextent") EXTRA(FILELINE,"(%t:%d)") EXTRA(ERRNO,"(%d)") EXTRA(DAT2,"%2x %2x") EXTRA(DAT3,"%2x %2x %2x") END_EXTRA_STRINGS() grfcodec-6.0.3/src/lang/0translate.txt0000644000000000000000000000132212027143046016315 0ustar rootroot1) Add new language definition into language_list.h 2) Copy help_english.h, extra_english.h and message_english.h into new files named help_.h, extra_.h and message_.h, where is the english name of your language. 3) In the files created in step 2, change the language they are meant for and translate all the text that needs to be translated. Refer to SANITY.txt as necessary. 4) Add include statements for help_.h, extra_.h and message_.h into all_help.h, all_extra.h and all_messages.h respectively. The order of include statements in those files is irrelevant, however for clarity try to keep it identical to the order in language_list.h. 5) Compile. grfcodec-6.0.3/src/lang/language_list.h0000644000000000000000000000241312027143046016470 0ustar rootroot/* * language_list.h * List of definitions of supported languages. * * Copyright (c) 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // Each language definition has the following format: // RENUM_LANGUAGE(,) // - Used to refer to this language elsewhere in the program. // Will become part of RenumLanguageId enumeration. // - A string used to select this language. START_LANGUAGES() RENUM_LANGUAGE(RL_ENGLISH,"en") //RENUM_LANGUAGE(RL_CZECH,"cz") // ^ // | // +-- Add new definitions to the end of the list END_LANGUAGES() grfcodec-6.0.3/src/lang/message_czech.h0000644000000000000000000004614212027143046016461 0ustar rootroot/* * message_czech.h * Message text in Czech language. * * Copyright 2006 by Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ START_MESSAGES(RL_CZECH) ERR_MESSAGE(FATAL_MESSAGE_ERROR,"Kriticka chyba behem vytvareni zpravy ",0) ERR_MESSAGE(INTERNAL_ERROR_TEXT,"%t(%d): Kriticka chyba pri analyze spritu %d: %t se nesmi rovnat %d.\n" \ "\t(funkce %t).\n",0) ERR_MESSAGE(INVALID_DATAFILE,"Datovy soubor \"%t\" obsahuje chybna data. (%S)\n",0) ERR_MESSAGE(NO_INPUT_FILE,"Nelze otevrit soubor \"%t\" specifikovany na prikazove radce.\n",0) ERR_MESSAGE(NO_OUTPUT_FILE,"Nelze otevrit vystupni soubor \"%t\" pro vstupni soubor \"%t\".\n",0) ERR_MESSAGE(REPLACE_FAILED,"Nelze nahradit puvodni soubor (%t) novym souborem (%t). (%d)\n",0) ERR_MESSAGE(DATAFILE_ERROR,"Nelze %s datovy soubor: \"%t\". %S\n",0) ERR_MESSAGE(CREATE_FAILED,"Nelze vytvorit adresar .nforenum v %t. (%d)\n",0) ERR_MESSAGE(DELETE_FAILED,"Nelze odstranit stary soubor %t. (%d)\n",0) OUT_MESSAGE(CREATED_DIR,"Datovy adresar .nforenum byl vytvoren v adresari %t.\n",0) OUT_MESSAGE(PROCESSING,"Rezim zpracovani standardniho vstupu.\n",0) OUT_MESSAGE(PROCESSING_FILE,"Zpracovavam soubor \"%t\".\n",0) OUT_MESSAGE(PROCESSING_COMPLETE,"Zpracovani ukonceno.\n",0) ERR_MESSAGE(APPARENTLY_NOT_NFO,"Tento soubor neobsahuje platny NFO kod.\n",0) ERR_MESSAGE(UNKNOWN_VERSION,"Neznama verze NFO: %d. ",0)//No \n. That's intentional. OUT_MESSAGE(SKIPPING_FILE,"Preskakuji soubor.\n",0) OUT_MESSAGE(PARSING_FILE,"Pokousim se analyzovat jako NFO kod verze 4.\n",0) ERR_MESSAGE(PARSE_FAILURE,"Sprite nachazejici se po spritu %d nelze zpracovat.\n",0) ERR_MESSAGE(PARTIAL_PARSE_FAILURE,"Cast spritu %d nelze zpracovat.\n",0) ERR_MESSAGE(NOT_IN_SPRITE,"Pri hledani spritu %d bylo nalezeno pokracovani predchoziho pseudo-spritu.\n",0) ERR_MESSAGE(CONSOLE_LINT_FATAL,"Kriticka chyba linteru pri zpracovani spritu %d.\n",0) ERR_MESSAGE(CONSOLE_LINT_ERROR,"Chyba pri zpracovani spritu %d.\n",0) ERR_MESSAGE(CONSOLE_LINT_WARNING,"Varovani pri zpracovani spritu %d (uroven %d).\n",0) OUT_MESSAGE(CONSOLE_AUTOCORRECT,"Pokousim se automaticky opravit sprite %d.\n",0) MESSAGE_EX(UNEXP_EOF_STD2,"Neocekavany konec souboru: Ocekavam dalsi standardni Akce 2.\n",0,OUT,UNUSED_SET) MESSAGE_EX(UNEXP_EOF_CARGOID,"Neocekavany konec souboru: Zbyvaji nevyuzita CargoID pro feature %x.\n",0,OUT,UNUSED_ID) MESSAGE_EX(UNEXP_EOF_TOWNNAMES,"Neocekavany konec souboru: Zbyvaji nevyuzita ID nazvu mest.\n",0,OUT,UNUSED_ID) MESSAGE_EX(UNEXP_EOF_LONGJUMP,"Neocekavany konec souboru: Akce 7/9 odkazuje za konec souboru.\n",0,OUT,LONG_JUMPLEAD) OUT_MESSAGE(STARTUP,"NFORenum " VERSION " - Copyright " YEARS " Dale McCoy.\n",0) NFO_MESSAGE(BAD_RPN,"Chybny vyraz RPN (behem cteni znaku %c).\n",0) NFO_MESSAGE(BAD_RPN_EOF,"Chybi prava zavorka.\n",0) NFO_MESSAGE(UNDEF_VAR,"Promenna \"%t\" nebyla dosud definovana.\n",0) NFO_MESSAGE(COMMAND_INVALID_ARG,"Chybejici nebo chybny argument prikazu %t.\n",0) NFO_MESSAGE(COMMAND_UNKNOWN,"Neznamy prikaz: %t\n",0) NFO_MESSAGE(COMMAND_REVERT_DEFAULT,"Automaticky pouzivam \"DEFAULT\".\n",0) NFO_MESSAGE(COMMAND_UNKNOWN_VERSION,"Nezname cislo verze. Jestlize byla tato verze jiz vydana," \ "prosim pouzijte nejnovejsi verzi souboru versions.dat dostupnou na webovych strankach NFORenum.\n",0) //UNPARSEABLE NFO_MESSAGE(INVALID_CHARACTER,"Chybny znak: \"%c\".\n",0) NFO_MESSAGE(INVALID_EXTENSION,"Chybna escape sekvence.\n",0) NFO_MESSAGE(UNTERMINATED_STRING,"Neukonceny textovy retezec.\n",0) MESSAGE(REAL_NO_FILENAME,"Realny sprite neobsahuje nazev souboru.\n",TO_NULL|MAKE_COMMENT) NFO_MESSAGE(REAL_MISSING_DATA,"Z realneho spritu nelze nacist %t.\n",0) //FATAL NFO_MESSAGE(INVALID_LENGTH,"Vsechny %S jsou %S bytu dlouhe.\n",USE_PREFIX) NFO_MESSAGE(BAD_LENGTH,"Delka neodpovida %S hodnoty %S. (Ocekavam %d bytu)\n",USE_PREFIX) NFO_MESSAGE(TOO_SHORT,"Linter vyzaduje dalsich %d bytu, ktere vsak chybi.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_FEATURE,"Chybna hodnota polozky feature.\n",USE_PREFIX) NFO_MESSAGE(INVALID_TYPE,"Chybna hodnota polozky nument1 nebo typ nahodne/variabilni Akce 2.\n",USE_PREFIX) NFO_MESSAGE(INVALID_ACTION,"Chybne cislo Akce.\n",USE_PREFIX) NFO_MESSAGE(INVALID_PROP,"Chybna vlastnost %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(UNTERM_ACT6,"U Akce 6 chybi koncova hodnota FF.\n",USE_PREFIX) //ERROR NFO_MESSAGE(INSUFFICIENT,"Chybi %s. Sprite %d deklaruje %d, ale bylo nalezeno pouze %d.\n",USE_PREFIX) NFO_MESSAGE(EXTRA,"Prebyva %s. %d deklarovanych spritem %d jiz bylo nalezeno.\n",USE_PREFIX) NFO_MESSAGE(UNEXPECTED,"Nalezen neocekavany %s.\n",USE_PREFIX) NFO_MESSAGE(FEATURE_MISMATCH,"Hodnota feature neodpovida hodnote feature predchozi Akce %x ve spritu %d.\n",USE_PREFIX) NFO_MESSAGE(RAND_2_NUMSETS,"Nahodna Akce 2 musi obsahovat 2^n moznosti k vyberu.\n",USE_PREFIX) NFO_MESSAGE(INDIRECT_VAR_7E,"Variable 7B is not allowed with parameter 7E.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NEITHER_ID_CALLBACK,"%4x neni ani callback ani %s.\n",USE_PREFIX) NFO_MESSAGE(UNDEFINED_SPRITE_SET,"Skupina spritu %2x neni definovana v predchozi Akci 1 (sprite %d).\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_CARGO_TYPE,"Chybny druh nakladu: %2x\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_REQD_SETS,"Akce 2 nedeklaruje zadne skupiny spritu pro %s.\n",USE_PREFIX) // MESSAGE_UNUSED(SIGNALS) NFO_MESSAGE(ACTION_5,"Pro tento typ ocekavam %t spritu.\n",USE_PREFIX) // MESSAGE_UNUSED(FOUNDATIONS) NFO_MESSAGE(UNDEFINED_ID,"ID %2x nebylo dosud definovano.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INSUFFICIENT_PROPS,"Ocekavam dalsich %d vlastnosti.\n",USE_PREFIX) NFO_MESSAGE(INSUFFICIENT_DATA,"Pro vlastnost %2x ocekavam vice dat. (%d bytu na pozici %d.)\n",USE_PREFIX) NFO_MESSAGE(INSUFFICIENT_DATA2,"Ocekavam dalsich %d bytu pro vlastnost %2x.\n",USE_PREFIX) NFO_MESSAGE(MISSING_TERMINATOR,"Data vlastnosti neobsahuji koncove byty.\n",USE_PREFIX) NFO_MESSAGE(DUPLICATE_ACT,"Akce %x jiz byla nalezena ve spritu %d.\n",USE_PREFIX) NFO_MESSAGE(MISSING_8,"Akce 8 musi predchazet akci %x.\n",USE_PREFIX) NFO_MESSAGE(INVALID_VERSION,"Chybne cislo verze %s.\n",USE_PREFIX) MESSAGE_UNUSED(BAD_VARIABLE) NFO_MESSAGE(BAD_VARSIZE,"Velikost promenne %2x je chybna.\n",USE_PREFIX) NFO_MESSAGE(BAD_CONDITION,"Podminka %2x je chybna.\n",USE_PREFIX) NFO_MESSAGE(GRFCOND_NEEDS_GRFVAR,"Podminka %2x vyzaduje promennou 88.\n",USE_PREFIX) NFO_MESSAGE(GRFVAR_NEEDS_GRFCOND,"Promenna 88 vyzaduje podminku pro testovani GRFID.\n",USE_PREFIX) NFO_MESSAGE(BITTEST_VARIABLE,"Promenna %2x vyzaduje podminku pro testovani bitu.\n",USE_PREFIX) NFO_MESSAGE(VARIABLE_SIZE_MISMATCH,"%d je chybna pro promennou %2x.\n",USE_PREFIX) MESSAGE_UNUSED(INVALID_LABEL)//,"Stitky musi mit nejvyssi 3 bity zapnute (E0-FF).\n",USE_PREFIX) NFO_MESSAGE(INVALID_LITERAL,"%2x na miste, kde bych ocekaval %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INSUFFICIENT_STRINGS,"Pro tuto Akci 4 ocekavam dalsich %d retezcu.\n",USE_PREFIX) NFO_MESSAGE(TOO_LARGE,"Hodnota <%s> nesmi presahnout %2xh.\n",USE_PREFIX) NFO_MESSAGE(SPRITENUM_TOO_HIGH,"Nejvyssi ID spritu, ktere TTD definuje, je 4984 (1E 13).\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_COLOR_TRANS,"Prebarvovaci mod 3 neni definovan.\n",USE_PREFIX) NFO_MESSAGE(INVALID_COLOR_SPRITE,"Sprite %d neni sprite s tabulkou zmeny barev.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_GROUNDSPRITE,"Nebyl definovan zadny %s.\n",USE_PREFIX) NFO_MESSAGE(NO_STD_3,"Tato Akce 3 pro zmenu nateru nenasleduje standardni Akci 3.\n",USE_PREFIX) NFO_MESSAGE(NONEXISTANT_VARIABLE,"Promenna %2x neexistuje.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(MODIFY_BEYOND_LENGTH,"Akce 6 se pokousi o zmenu bytu, ktery se nachazi za koncem tohoto spritu.\n",USE_PREFIX) NFO_MESSAGE(NO_FOLLOWING_SPRITE,"Po teto Akci 6 neni zadny sprite ke zmeneni.\n",USE_PREFIX) //WARNING1 NFO_MESSAGE(NO_SETS,"Akce %x nedeklaruje zadnou skupinu.\n",USE_PREFIX) NFO_MESSAGE(NO_SPRITES,"Akce %x deklaruje skupiny, ktere neobsahuji zadne sprity.\n",USE_PREFIX) NFO_MESSAGE(SET_WITH_NO_SPRITES,"Skupina %d neobsahuje zadne sprity.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_PROPS,"Akce 0 nenastavuje zadne vlastnosti.\n",USE_PREFIX) NFO_MESSAGE(NO_IDS,"Akce 0 nenastavuje vlastnosti pro zadna ID.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_ID,"Redefinice ID %2x, ktere od sve posledni definice ve spritu %d nebylo dosud pouzito.\n",USE_PREFIX) MESSAGE_EX(UNUSED2IDLEAD,"Nasledujici ID pro feature %x nebyla od sve posledni definice dosud pouzita:\n",MAKE_COMMENT,NFO,UNUSED_ID) MESSAGE_EX(UNUSEDIDFINAL,"%2x (naposled definovano ve spritu %d)\n",MAKE_COMMENT,NFO,UNUSED_ID) NFO_MESSAGE(UNUSED_SET,"Skupina %2x definovana v predchozi Akci 1 (sprite %d) nebyla dosud pouzita.\n",USE_PREFIX) NFO_MESSAGE(UNREACHABLE_VAR,"Variace %d neni dosazitelna.\n",USE_PREFIX) NFO_MESSAGE(EXTRA_DATA,"Sprite obsahuje prebytecna data.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(REUSED_DEFAULT,"Standardni ID jiz bylo v tomto spritu pouzito.\n",USE_PREFIX) NFO_MESSAGE(RESERVED_GRFID,"GRFID zacinajici bytem FF jsou vyhrazena.\n",USE_PREFIX) NFO_MESSAGE(INDIRECT_VAR_NOT_6X,"Variable 7B only useful for 60+x variables.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SHIFT_TOO_FAR,"Posuv bitu promenne %2x presahuje jeji velikost.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_MODIFICATIONS,"Akce 6 nic nemeni.\n",USE_PREFIX) NFO_MESSAGE(DOES_NOT_MODIFY,"Tato cast nic nemeni.\n",USE_PREFIX|HAS_OFFSET) //WARNING2 MESSAGE_UNUSED(BACKWARDS_GOTO)//,"Akce %x skace zpet na stitek %2x definovany ve spritu %d.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_LABEL_NO_PREV_DEF,"Stitek %2x nebyl dosud pouzit.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_LABEL_PREV_DEF,"Stitek %2x nebyl od sve posledni definice ve spritu %d dosud pouzit.\n",USE_PREFIX) NFO_MESSAGE(REPEATED_PROP,"Vlastnost %2x jiz byla definovana na pozici %d.\n",USE_PREFIX|HAS_OFFSET) MESSAGE_UNUSED(OFF_TILE) //WARNING3 NFO_MESSAGE(ONLY_ONE_CHOICE,"Nahodna akce 2 obsahuje pouze jednu volbu na vyber.\n",USE_PREFIX) NFO_MESSAGE(NOT_VARIATIONAL,"Variacni akce 2 pouziva pouze konstantni promenne (1A a 1C).\n",USE_PREFIX) NFO_MESSAGE(NOT_RANDOM,"Vsechny nahodne volby obsahuji stejne ID.\n",USE_PREFIX) MESSAGE_UNUSED(TOO_MANY_STRINGS) NFO_MESSAGE(NO_ACT1,"Chybi predchozi Akce 1.\n",USE_PREFIX) MESSAGE_UNUSED(INVALID_AGAIN)//," musi byt 00 nebo 01.\n",USE_PREFIX) NFO_MESSAGE(INVALID_OP,"Chybna operace %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SET_TOO_LARGE,"Skupina spritu obsahuje vice spritu, nez muze dana feature vyuzit.\n",USE_PREFIX) NFO_MESSAGE(STRANGE_SET_SIZE,"Skupina spritu obsahuje neobvykly pocet spritu.\n",USE_PREFIX) MESSAGE_EX(UNUSEDFIDLEAD,"Nasledujici ID novych nazvu mest nebyla od posledni definice dosud pouzita:\n",MAKE_COMMENT,NFO,UNUSED_ID) NFO_MESSAGE(DUPLICATE_GRFID,"Toto GRFID jiz bylo deaktivovano na pozici %d (%8x).\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_GRFIDS,"Akce E nedeaktivuje zadne GRF soubory.\n",USE_PREFIX) NFO_MESSAGE(INVALID_SRC,"Zdrojovy parametr %d je chybny.\n",USE_PREFIX) NFO_MESSAGE(INVALID_TARGET,"Cilovy parametr je chybny.\n",USE_PREFIX) NFO_MESSAGE(ONLY_ONE_DATA,"Jen jeden argumentu src1 a src2 muze mit hodnotu 0xFF.\n",USE_PREFIX) NFO_MESSAGE(DUPLICATE_LANG_NAME,"Nazev pro %L jiz byl definovan na pozici %d.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(MISSING_FALLBACK,"Zadny nouzovy retezec nebyl definovan.\n",USE_PREFIX) NFO_MESSAGE(NO_PARTS,"Nebyly specifikovany zadne casti.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OUT_OF_RANGE_BITS,"Je dostupnych jen %d nahodnych bitu.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INSUFFICIENT_BITS,"Je vyzadovano %x bitu, ale je dostupnych pouze %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_PROBABILITY,"Pro tuto cast byla specifikovana nulova pravdepodobnost.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(PARAM_TOO_LARGE,"Parametr %2x presahuje maximalni povolenou hodnotu promenne %2x.\n",HAS_OFFSET|USE_PREFIX) NFO_MESSAGE(NO_BUILDING_SPRITE,"Sprity budovy nesmi byt prazdne.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_SPRITE,"Neocekavany konec spritu pri cteni spritu %d.\n",USE_PREFIX) MESSAGE_UNUSED(FIRST_SPRITE_CANNOT_SHARE) NFO_MESSAGE(INVALID_GRFID,"Akce %x odkazuje na vyhrazene GRFID.\n",USE_PREFIX|HAS_OFFSET) MESSAGE_UNUSED(INSUFFICIENT_INCLUDE) MESSAGE_UNUSED(EXTRA_INCLUDE) MESSAGE_UNUSED(UNEXPECTED_INCLUDE) NFO_MESSAGE(OOR_COUNT,"Pokus hospodarit s prilis mnoho ID.\n",USE_PREFIX) NFO_MESSAGE(INVALID_ID,"ID %2x mimo povoleny rozsah (%2x..%2x).\n",USE_PREFIX) NFO_MESSAGE(NO_CARGOTYPES,"Pro tuto feature musi byt rovno 0.\n",USE_PREFIX) NFO_MESSAGE(UNUSED_CONTROL,"Kontrolni znak %2x nema zadnou funkci.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_CONTROL,"V tomto retezci by kontrolni znak %2x nemel byt pouzit.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SMASH_STACK,"Kontrolni znak %2x neodpovida parametru typu %K na vrchu zasobniku.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SMASH_STACK_SPAN,"Kontrolni znak %2x cte data z vice parametru.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_STACK,"V zasobniku neni dostatek dat pro kontrolni znak %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(CANNOT_SHUFFLE,"V zasobniku neni dostatek dat pro presunuti.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_NULL_FOUND,"Chybi koncovy nulovy byte.\n",USE_PREFIX) NFO_MESSAGE(INVALID_SEVERITY,"Chybny byte zavaznosti.\n",USE_PREFIX) NFO_MESSAGE(UNKNOWN_LANG_BIT,"ID jazyka %2x ma zapnute nepouzivane bity.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_MESSAGEID,"Chybne ID zpravy.\n",USE_PREFIX) NFO_MESSAGE(INVALID_PARAM,"%2x neni parametr GRF.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_OVERRIDE,"Pro tuto feature nelze zmenit grafiku.\n",USE_PREFIX) NFO_MESSAGE(COND_SIZE_MISMATCH,"Podminka %2x vyzaduje %d bytu.\n",USE_PREFIX) NFO_MESSAGE(REAL_VAL_TOO_SMALL,"Chybna metadata. %s nesmi byt nizsi nez %d.\n",USE_PREFIX) NFO_MESSAGE(REAL_VAL_TOO_LARGE,"Chybna metadata. %s nesmi byt vyssi nez %d.\n",USE_PREFIX) MESSAGE_UNUSED(REAL_MOVES_UP) NFO_MESSAGE(REAL_BAD_COMP,"Chybna metadata. Komprese muze mit nastevene jen bity 0, 1, 3 a/nebo 6.\n",USE_PREFIX) NFO_MESSAGE(REAL_SPRITE_TOO_LARGE,"Chybna metadata. Velikost spritu presahuje 64K.\n",USE_PREFIX) NFO_MESSAGE(INVALID_TEXTID,"TextID %4x neexistuje.\n",USE_PREFIX|HAS_OFFSET) //NFO_MESSAGE(UNDEFINED_TEXTID,"Text ID %4x has not been defined.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(CHECK_0C_RANGE,"Zkouseni promenne 0C v rozsahu [%2x,%2x].\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_CALLBACK,"Pro tuto feature callback %2x neexistuje.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_FONT,"Font %2x neexistuje.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(SPANS_BLOCKS,"Skupina %d deklaruje znaky pro vice bloku.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_F_NAME,"Retezec s nazvy jazyka %2x neobsahuje koncovy nulovy byte.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OVERRAN_F_PART,"Cast nazvu zacinajici na pozici %d neobsahuje koncovy nulovy byte.\n",USE_PREFIX) NFO_MESSAGE(OBSCURED_VARIATION,"Variace %d je castecne zakryta.\n",USE_PREFIX) NFO_MESSAGE(UNREACHABLE_DEFAULT,"Standardni vysledek neni dosazitelny.\n",USE_PREFIX) NFO_MESSAGE(DIVIDE_BY_ZERO,"var-adjust se pokousi delit nulou.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(USE_SHIFT_AND,"Zde staci pouzit argumenty shift-and a var-adjust.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_SHIFT,"Argument shift nemuze mit oba nejvyssi bity zapnute.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(UNDEFINED_TRIGGER,"Pouziti neexistujici spousteci udalosti.\n",USE_PREFIX) NFO_MESSAGE(OVERLENGTH_UTF8,"Chybna sekvence UTF-8: Prilis dlouhe vyjadreni kodu znaku.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INVALID_UTF8,"Chybna sekvence UTF-8: Prvni byte neni nasledovan dostatecnym poctem pokracovacich bytu.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(OUTOFRANGE_UTF8,"Chybna sekvence UTF-8: Koduje znak mimo BMP.\n",USE_PREFIX|HAS_OFFSET) MESSAGE_UNUSED(UNEXPECTED_UTF8_CONT) NFO_MESSAGE(UNKNOWN_LANGUAGE,"Jazyk %2x neni definovan.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(INCLUDING_00_ID,"Pouziti TextID %4x, ktere obsahuje nulovy byte.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(AUTOCORRECTING,"Automaticka oprava %s z %2x na %2x.\n",HAS_OFFSET) NFO_MESSAGE(EMBEDDED_00,"Nulovy byte uprostred retezce.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(LONG_JUMPLEAD,"Nasledujici Akce 7/9 skacou za konec tohoto souboru:\n",USE_PREFIX|NO_CONSOLE) MESSAGE_EX(LONG_JUMP,"Akce %x ve spritu %d.\n",MAKE_COMMENT|NO_CONSOLE,NFO,LONG_JUMPLEAD) NFO_MESSAGE(NO_TEXTS,"Akce 4 nedeklaruje zadne retezce.\n",USE_PREFIX) NFO_MESSAGE(AUTOCORRECT_ADD,"Pridavam koncovy byte %2x.\n",0) NFO_MESSAGE(INVALID_EXT_CODE,"Rozsireny format %2x neexistuje.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(FEATURE_LINK_MISMATCH,"ID %2x je definovano pro feature %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(FEATURE_CALL_MISMATCH,"ID %2x je definovano pro feature %2x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(AUTOCORRECT_LOOP,"System pro automatickou opravu se pravdepodobne zasekl v nekonecnem cyklu.\n",USE_PREFIX) NFO_MESSAGE(BITS_OVERLAP,"Polozka %d argumentu pouziva nasledujici bity, ktere jiz byly v teto akci F pouzity: %t\n",USE_PREFIX|HAS_OFFSET) MESSAGE_EX(MISSING_LANG_NAME,"Pro %L nebyl specifikovan zadny nazev.\n",MAKE_COMMENT|USE_PREFIX,NFO,MISSING_FALLBACK) NFO_MESSAGE(OUT_OF_RANGE_TEXTID_13,"Akce 13 muze pouze definovat texty pro ID v rozsazich C4xx, C5xx, C9xx, D0xx a DCxx.\n",USE_PREFIX) NFO_MESSAGE(AND_00,"Operace AND hodnotou 0.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(GENERIC_AND_OVERRIDE,"Akce 3 muze byt bud obycejna nebo pro zmenu nateru, ne oboji.\n",USE_PREFIX) NFO_MESSAGE(RECURSIVE_F,"Action F nesmi odkazovat sama na sebe.\n",USE_PREFIX) NFO_MESSAGE(EXCESSIVE_ADD,"Hodnota nesmi byt zaporna.\n",USE_PREFIX|HAS_OFFSET) //NFO_MESSAGE(NOT_A_REGISTER,"Pokus o pristup k neexistujicimu registru %4x.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(DUPLICATE,"%s %2x jiz bylo specifikovano na pozici %d.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(ACT3_PRECEDES_PROP08,"Pro ID %2x nebyla definovana vlastnost 08.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(MASKED_BIT_SET,"GRFID ma zapnut bit, ktery je v masce vypnut.\n",USE_PREFIX) NFO_MESSAGE(DISCARD_UNSTORED,"Operace 0F nenasleduje operaci ulozeni do registru.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(NO_PERS_REGS,"Pro tuto feature neexistuji zadne trvale registry.\n",USE_PREFIX|HAS_OFFSET) NFO_MESSAGE(DUPLICATE_TRANS_TABLE,"Precislovaci tabulka nakladu se jiz nachazi na spritu %d.\n",USE_PREFIX) NFO_MESSAGE(BAD_RANDSUBTYPE,"Chybny subtyp nahodne akce 2.\n",USE_PREFIX) /* Insert new NFO_MESSAGEs above this line unless a MESSAGE_UNUSED appears in a logical location. */ #if defined DEBUG || defined _DEBUG ERR_MESSAGE(BAD_STRING,"Chyba: Retezec %d neexistuje (%d/%d).\n",0) #else ERR_MESSAGE(BAD_STRING,"Chyba: Retezec %d neexistuje.\n",0) #endif ERR_MESSAGE(DATAFILE_MISMATCH,"%t obsahuje informace pro mene features nez je v souboru feat.dat.\n" \ "Nahradte jej novejsi verzi nebo smazte feat.dat.\n",0) OUT_MESSAGE(DATA_FOUND_AT,"Datove soubory nacteny z adresare '%t/.nforenum'.\n",0) END_MESSAGES() grfcodec-6.0.3/src/lang/checklang.pl0000644000000000000000000000657012027143046015765 0ustar rootroot#!/usr/bin/env perl # Check NFORenum's language files # # Takes no arguments. # # Checks all *_.h files for agreement with the corresponding *_english.h. use strict; my %en; sub getfmt($){ local $_=$_[0]; my ($ofs,$fmt)=(-1,""); while(($ofs = index $_,'%',$ofs+1)!=-1){ substr($_,$ofs,3) =~ /(%[248]x)/ or substr($_,$ofs,2) =~ /(%.)/ or die; $fmt .= $1; } return $fmt; } ########################################################################## print "Checking message strings.\nLoading english.\n"; open FILE, "< message_english.h", or die "Could not open message_english.h.\n"; my $prev; while(){ s#//.*##; next unless /MESSAGE\(/ || /MESSAGE_EX/ || $prev; next if /BAD_STRING/; $_="$prev$_" if $prev; $prev=$_ and next if /\\\s$/; $prev=''; /MESSAGE.*\(([0-9A-Z_]*),\s*"(.*)",.*\)/s or die "$.:Could not parse line. Does it need a trailing backslash?\n"; $en{$1}=getfmt($2); } close FILE; while(){ next if /english/; open FILE, "< $_" or die "Could not open $_.\n"; /_(.*)\./; print "Checking $1.\n"; my %tr=%en; while(){ s#//.*##; next unless /MESSAGE\(/ || /MESSAGE_EX/ || $prev; next if /BAD_STRING/; $_="$prev$_" if $prev; $prev=$_ and next if /\\\s$/; $prev=''; /MESSAGE.*\(([0-9A-Z_]*),\s*"(.*)",.*\)/s or die "$.:Could not parse line. Does it need a trailing backslash?\n"; print "$.:$1 is a duplicate or does not exist in English.\n" and next unless exists $tr{$1}; print "$.:Format for $1 does not match English format.\n" unless getfmt($2) eq $tr{$1}; delete $tr{$1}; } print "$_ is not translated\n" for keys %tr; close FILE; } undef %en; ########################################################################## print "\nChecking extra strings.\nLoading english.\n"; open FILE, "< extra_english.h", or die "Could not open extra_english.h.\n"; while(){ next unless /^EXTRA/; /EXTRA\(([A-Z0-9_]*),"(.*)"\)/ or die "$.:Could not parse line. Does it need a trailing backslash?\n"; $en{$1}=getfmt($2); } close FILE; while(){ next if /english/; open FILE, "< $_" or die "Could not open $_.\n"; /_(.*)\./; print "Checking $1.\n"; my %tr=%en; while(){ next unless /^EXTRA/; /EXTRA\(([A-Z0-9_]*),"(.*)"\)/ or die "$.:Could not parse line. Does it need a trailing backslash?\n"; print "$.:$1 is a duplicate or does not exist in English\n" and next unless exists $tr{$1}; print "$.:Format for $1 does not match English format\n" unless $tr{$1} eq getfmt($2); delete $tr{$1}; } print "$_ is not translated\n" for keys %tr; close FILE; } undef %en; ########################################################################## print "\nChecking help strings.\nLoading english.\n"; open FILE, "< help_english.h", or die "Could not open help_english.h.\n"; while(){ print "$.:Tab characters are forbidden.\n" if /\t|\\t/; next unless (/START_HELP_TEXT/ .. /END_HELP_TEXT/) && /\s--(.*?)[[ =\\]/; $en{$1}=$_; } close FILE; while(){ next if /english/; open FILE, "< $_" or die "Could not open $_.\n"; /_(.*)\./; print "Checking $1.\n"; my %tr=%en; while(){ print "$.:Tab characters are forbidden.\n" if /\t|\\t/; next unless (/START_HELP_TEXT/ .. /END_HELP_TEXT/) && /\s--(.*?)[[ =\\]/; print "$.:Switch --$1 is a duplicate or does not exist in English.\n" unless exists $tr{$1}; delete $tr{$1}; } print "Switch --$_ is not translated.\n" for keys %tr; close FILE; } grfcodec-6.0.3/src/lang/all_help.h0000644000000000000000000000006412027143046015432 0ustar rootroot#include "help_english.h" //#include "help_czech.h" grfcodec-6.0.3/src/lang/all_messages.h0000644000000000000000000000007212027143046016310 0ustar rootroot#include "message_english.h" //#include "message_czech.h" grfcodec-6.0.3/src/lang/help_english.h0000644000000000000000000001140412027143046016313 0ustar rootroot/* * help_english.h * Program help in English language. * * Copyright 2005-2006 by Dale McCoy. * Copyright 2006 by Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // START_HELP_TEXT() // - Language id as defined in language_list.h // // The actual help is just one long string. START_HELP_TEXT(RL_ENGLISH) "Usage: nforenum [options] [file1 [file2 [file3 [...]]]]\n" " Any number of files may be specified.\n" " If no files or options are specified, NFORenum will read a file from\n" " standard input and write it to standard output.\n" "Options:\n" " --auto-correct -a\n" " Perform some rudimentary automatic correction of incorrect pseudo\n" " sprites. This may be specified twice to enable the corrections that\n" " are more likely to be incorrect.\n" " See the README for detailed information on the auto-correcter.\n" " --comments= -c \n" " is one character, either /, ;, or #, and specifies the comment\n" " style that NFORenum will use. This will not change the header, because\n" " grfcodec requires that the header be commented in C++-style.\n" " --data[=] -D[]\n" " If is specified, look for the .nforenum directory in , and\n" " create it if not found.\n" " If is not specified, report the location of the .nforenum directory.\n" " In either case, eliminate the 5-second wait used to ensure that those\n" " not running NFORenum from a command line can see the directory-created\n" " message.\n" " Default: Look for the .nforenum directory in the current directory, and\n" " then in the environment variable HOME, if defined. If not found attempt\n" " to create in HOME, then in .\n" " --force -f\n" " Forces processing of files that do not look like NFO files.\n" " The default is to treat such files as if they specified a too-high info\n" " version.\n" " --help -h\n" " Display this message and exit.\n" " --lock\n" " Locks the current comment command state. Commands will continue to be\n" " parsed as normal (so NOPRESERVE will be honored, @@DIFF will be\n" " removed, &c.) but their changes (such as turning on the diff-assister)\n" " will not be honored.\n" " --no-replace --keep-old -k\n" " Do not replace the old NFO file; write new file to file.new.nfo.\n" " Default: Use file[.nfo].new as temporary, rename it to file[.nfo]\n" " when done.\n" " --silent -s\n" " Suppress progress messages.\n" " --version -v\n" " Display version information and exit.\n" " --write-data\n" " Refresh all data files, unless they are newer.\n" "\n" "The following options cause NFORenum to behave as if all files started with\n" "the associated command. The readme has full details on the comment commands.\n" "Options associated with comment commands that require additional information\n" "take that information as an argument. With the exception of -L/--let, the\n" "options to the command line versions are case insensitive.\n" "\"ON\" and \"OFF\" may be specified with \"+\" and \"-\", respectively.\n" " --beautify -b @@BEAUTIFY\n" " --diff -d @@DIFF\n" " --let -L @@LET\n" " --lint -l @@LINT\n" " --preserve-messages -p @@PRESERVEMESSAGES\n" " --real-sprites -r @@REALSPRITES\n" " --use-old-nums -o @@USEOLDSPRITENUMS\n" " --warning-disable -w @@WARNING DISABLE\n" " --warning-enable -W @@WARNING ENABLE\n" " -w and -W (and their long counterparts) also accept a comma-separated\n" " list of messages, all of which will be ENABLEd or DISABLEd.\n" "\n" "NFORenum is Copyright 2004-2009 by Dale McCoy\n" "Portions Copyright 2006 Dan Masek\n" "Portions Copyright 2010 Thijs Marinussen, Remko Bijker, Christoph Elsenhans\n" "You may copy and redistribute it under the terms of the GNU General Public\n" "License, as stated in the file 'COPYING'.\n" "\n" "If this message scrolls by too quickly, you may want to try\n" " nforenum -h | more\n" END_HELP_TEXT() grfcodec-6.0.3/src/lang/all_extra.h0000644000000000000000000000006612027143046015627 0ustar rootroot#include "extra_english.h" //#include "extra_czech.h" grfcodec-6.0.3/src/inject.cpp0000644000000000000000000000277512027143046014553 0ustar rootroot/* * inject.cpp * Contains functions for injecting new sprites into the NFO. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include using namespace std; #include"globals.h" #include"inject.h" static queue_injected; static const istream*_into; istream&inj_getline(istream&in,string&str){ assert(&in==_into); if(_injected.size()){ str=_injected.front(); _injected.pop(); return in; } return getline(in,str); } int peek(istream&in){ assert(&in==_into); if(&in==_into&&_injected.size())return _injected.front()[0]; return in.peek(); } void inject(const string&str){ if(_into==NULL)(*pOut)< #include /** * Main call of the endian_check program * @param argc argument count * @param argv arguments themselves * @return exit code */ int main (int argc, char *argv[]) { union { unsigned int i; char c[4]; } bint = {0x01020304}; bool little_endian = (bint.c[0] != 1); if (argc > 1 && strcmp(argv[1], "BE") == 0) little_endian = false; if (argc > 1 && strcmp(argv[1], "LE") == 0) little_endian = true; const char *endian = little_endian ? "LITTLE" : "BIG"; printf( "#ifndef ENDIAN_H\n" "#define ENDIAN_H\n" "#define GRFCODEC_%s_ENDIAN 1\n" "#define ARCH_IS_%s_ENDIAN 1\n" "#endif /* ENDIAN_H */\n", endian, endian); return 0; } grfcodec-6.0.3/src/messages.cpp0000644000000000000000000001240612027143046015076 0ustar rootroot/* * messages.cpp * defines message processing functions. * * Copyright 2004-2006 by Dale McCoy. * Copyright 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include //#include using namespace std; // The prefered method for generating version.h for Visual Studio is to // install Cygwin and use the command "make version.h". // If this is not an option, create a file with the two lines // #define VERSION "v3.3.1 r" // #define YEARS "2004-2006" // where is the current revision of the nforenum source // Increment the 3.3.1 as necessary to agree with version.def #include"version.h" #include"nforenum.h" #include"inlines.h" #include"messages.h" #include"sanity_defines.h" #include"strings.h" #include"command.h" #include "message_mgr.h" //#define MSG_ARRAYS_INCLUDE_TIMES 3 //#include"msg_arrays.h" static const char*STACK[]={NULL,"byte","word","textID","dword","date"}; static bool bAutoMessage; void AutoConsoleMessages(){ bAutoMessage=true; } void ManualConsoleMessages(){ bAutoMessage=false; } string mysprintf(const char*str,...){ WrapAp(str); return myvsprintf(str,ap); } #if defined DEBUG || defined _DEBUG static RenumMessageId curMessage; #endif string IssueMessage(int minSan,RenumMessageId id,...){ WrapAp(id); return vIssueMessage(minSan,id,ap); } string vIssueMessage(int minSan,RenumMessageId id,va_list& arg_ptr){ #if defined DEBUG || defined _DEBUG curMessage=id; #endif /*if(minSan<0){ if(GetState(VERBOSE)<-minSan)return""; }else*/if(!GetWarn(id,minSan))return""; if(MessageMgr::Instance().GetMessageData(id).IsMakeComment() && GetState(DIFF)) return ""; RenumExtraTextId prefix = PREFIX_LINT_WARNING; switch(minSan){ case-1:case-2:break; case 0: prefix=PREFIX_UNPARSEABLE; break; case FATAL: case ERROR: prefix=minSan==FATAL?PREFIX_LINT_FATAL:PREFIX_LINT_ERROR; case WARNING1: case WARNING2: case WARNING3: case WARNING4: if(MessageMgr::Instance().GetMessageData(id).IsConsoleMessage()&&bAutoMessage) IssueMessage(0,(RenumMessageId)(CONSOLE_LINT_WARNING-(minSan=0)SetCode(EWARN); } try{ return MessageMgr::Instance().GetMessageData(id).Display( mysprintf(MessageMgr::Instance().GetExtraText(prefix).c_str(),id),arg_ptr); }catch(...){ (*pErr)<=__LAST_EXTRA){ #if defined DEBUG || defined _DEBUG IssueMessage(0,BAD_STRING,x,curMessage,_spritenum); #else IssueMessage(0,BAD_STRING,x); #endif assert(false); exit(EFATAL); } if(x!=-1) ret += MessageMgr::Instance().GetExtraText((RenumExtraTextId)x); break; }case'S':{ int x=(int)va_arg(arg_ptr,int); if(x>=__LAST_EXTRA){ #if defined DEBUG || defined _DEBUG IssueMessage(0,BAD_STRING,x,curMessage,_spritenum); #else IssueMessage(0,BAD_STRING,x); #endif assert(false); exit(EFATAL); } if(x!=-1) ret+=myvsprintf(MessageMgr::Instance().GetExtraText((RenumExtraTextId)x).c_str(),arg_ptr); break; }case'x':{ uint val=va_arg(arg_ptr,int); if(pad&&!(pad&1)){ while(pad||val){ ret+=itoa(val&0xFF,16,2); val>>=8; if((pad?pad-=2:0)||val)ret+=' '; } break; } ret+=itoa(val,16); break; }case'L':{ uint langID=va_arg(arg_ptr,int); ret+=mysprintf(GetLangName(langID).c_str(),langID); break; }case'K': ret+=STACK[va_arg(arg_ptr,int)];//_msgArrays[STACK].array[va_arg(arg_ptr,int)]; break; /*case'Y':{ uint array=va_arg(arg_ptr,uint),offset=va_arg(arg_ptr,uint); VERIFY(array>=INVALID_MSG_ARRAY,vIssueMessage,array); if(offset>=_msgArrays[array].length)offset=_msgArrays[array].length-1; ret+=_msgArrays[array].array[offset]; break; }*/default: ret+=fmt[i]; } } } return ret; } grfcodec-6.0.3/src/singleton.h0000644000000000000000000000271112027143046014734 0ustar rootroot/* * singleton.h * * Singleton macros * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_SINGLETON_H_INCLUDED_ #define _RENUM_SINGLETON_H_INCLUDED_ //Mutable singleton #define SINGLETON(class)\ public:\ static class&Instance(){static class obj;return obj;}\ static const class&CInstance(){return Instance();}\ private:\ class();\ class(const class&);\ void operator=(const class&); //Immutable singleton #define C_SINGLETON(class)\ public:\ static const class&Instance(){static const class obj;return obj;}\ private:\ class();\ class(const class&);\ void operator=(const class&); //Non-object class #define STATIC(class)\ private:\ class();\ class(const class&);\ void operator=(const class&); #endif // _RENUM_SINGLETON_H_INCLUDED_ grfcodec-6.0.3/src/strings.cpp0000644000000000000000000003344612027143046014767 0ustar rootroot/* * strings.cpp * Contains definitions for checking strings in actions 4, 8, and B. * * Copyright 2005-2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include using namespace std; #include"nforenum.h" #include"inlines.h" #include"sanity_defines.h" #include"pseudo.h" #include"strings.h" #include"data.h" #include"utf8.h" #include"messages.h" #include"command.h" class check4:public Guintp{ public: int GetGenericPerms(int feature); int GetNamePerms(int feature); SINGLETON(check4) }; check4::check4(){ FILE*pFile=myfopen(4); _p=new uint[MaxFeature()+1]; uint i=0; for(;i<=MaxFeature();i++) _p[i]=fgetc(pFile); for(i=0;i<=MaxFeature();i++) _p[i]|=GetCheckByte(4)<<8; fclose(pFile); } int check4::GetGenericPerms(int feature){return _p[feature]>>8;} int check4::GetNamePerms(int feature){return _p[feature]&0xFF;} void Check4(PseudoSprite&data){ const uint feature=data.ExtractByte(1),lang=data.ExtractByte(2); data.SetAllHex(); uint i=5; int nument=(signed)data.ExtractByte(3); if(!IsValidFeature(ACT4,feature)&&feature!=0x48){IssueMessage(FATAL,INVALID_FEATURE);return;} if(_grfver<7&&lang&0x60&&(lang&0x7F)!=0x7F)IssueMessage(WARNING3,UNKNOWN_LANG_BIT,2,lang); if(_grfver>6)CheckLangID(lang&0x7F,2); if(lang&0x80){ i=6; if(nument!=0) { uint base_id = data.ExtractWord(4); uint last_id = base_id + nument - 1; for (uint i = base_id; i <= last_id; i++) CheckTextID(0x48, i, 4); } else IssueMessage(WARNING1,NO_TEXTS); }else if(feature==0x48)IssueMessage(ERROR,INVALID_FEATURE); else if(feature>3)IssueMessage(ERROR,NO_BYTE_IDS,feature); else if(nument!=0){ CheckID(feature,data.ExtractExtended(4))&&CheckID(feature,data.ExtractExtended(4)+nument-1); i+=data.ExtendedLen(4)-1; }else IssueMessage(WARNING1,NO_TEXTS); int perms=feature==0x48?CTRL_ALL|CTRL_NO_STACK_CHECK :(check4::Instance().*(lang&0x80?&check4::GetGenericPerms:&check4::GetNamePerms))(feature); if(feature==0x0B){ for(;nument--||_autocorrect;){ int result=CheckString(data,i,perms,!nument,MakeStack(1,STACK_WORD)); if(result){ if(result!=-1)nument--; break; } try{ if(data[i])data.SetEol(i-1,1); }catch(uint){} } }else for(;nument--||_autocorrect;){ int result=CheckString(data,i,perms,!nument); if(result){ if(result!=-1)nument--; break; } try{ if(data[i])data.SetEol(i-1,1); else data.SetNoEol(i-1); }catch(uint){} } if(++nument){ if(_autocorrect){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,3,NUMENT,data.ExtractByte(3),data.ExtractByte(3)-nument); data.SetByteAt(3,data.ExtractByte(3)-nument); }else IssueMessage(ERROR,INSUFFICIENT_STRINGS,nument); } if(i>10==0xD0>>2||id>>8==0xDC||id>>9==0xC4>>1||id>>9==0xC9) CheckTextID(0x48,id,6)&&CheckTextID(0x48,id+nument-1,5); else IssueMessage(ERROR,OUT_OF_RANGE_TEXTID_13); }else IssueMessage(WARNING1,NO_TEXTS); for(;nument--||_autocorrect;){ int result=CheckString(data,offs,CTRL_ALL|CTRL_NO_STACK_CHECK,!nument); if(result){ if(result!=-1)nument--; break; } try{ if(data[offs])data.SetEol(offs-1,1); else data.SetNoEol(offs-1); }catch(uint){} } if(++nument){ if(_autocorrect){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,5,NUMENT,data.ExtractByte(5),data.ExtractByte(5)-nument); data.SetByteAt(5,data.ExtractByte(5)-nument); }else IssueMessage(ERROR,INSUFFICIENT_STRINGS,nument); } if(offsstack.length()){\ IssueMessage(WARNING1,OVERRAN_STACK,offs,ch);\ perms|=CTRL_NO_STACK_CHECK;\ }else if((stack[stackoffs]&0x0F)!=type){\ IssueMessage(WARNING1,SMASH_STACK,offs,ch,stack[stackoffs]);\ perms|=CTRL_NO_STACK_CHECK;\ }else if((stack[stackoffs]&0xF0)!=(stack[stackoffs+width-1]&0xF0)){\ IssueMessage(WARNING1,SMASH_STACK_SPAN,offs,ch);\ perms|=CTRL_NO_STACK_CHECK;\ }\ stackoffs+=width;\ break; /* Checks the string starting at at offs using perms (bitmask of CTRL_* in * string.h) and stack (returned from MakeStack) to control messages. * Returns with offs set to the ->next<- byte to process. * Return depends on retInfo: either the last character processed * (RETURN_NULL), or the number of stack-accessing control characters * encountered or -1 if the stack was smashed (RETURN_STACK) */ int CheckString(PseudoSprite&data,uint&offs,int perms,bool include_00_safe,string stack,const int retInfo){ const uint length=data.Length(); if(offs>=length)return -1; uint stackoffs=0,ret=0,ch; uint choice_list=0; bool utf8=false,valid=true; try{ utf8=data.ExtractWord(offs)==0x9EC3; if(utf8){ data.SetUTF8(offs,2); offs+=2; } }catch(uint){} while(0 != (ch = (utf8?data.ExtractUtf8(offs, valid):data.ExtractByte(offs++)))) { if(ch>(uint)-10){ IssueMessage(ERROR,OUTOFRANGE_UTF8,offs+(int)ch); continue; } offs--;//back up to last-parsed; move back to next-to-parse at end of loop (line ~212) if(utf8){ if(ch<128){ data.SetText(offs); if(ch>0x7A)ch=0x20;//bypass the control-char checks for 7B..7F }else if(ch<256){ if(!valid){//invalid UTF-8, parse as bytes if((/*ch>0x7A&&*/ch<0xA1)||ch==0xAA||ch==0xAC||ch==0xAD||ch==0xAF||(ch>0xB3&&ch<0xB9)) data.SetQEscape(offs);//nonprintable -- control or special. else data.SetText(offs); }else ch=0x20;//valid UTF-8 encoding of U+0080..U+00FF; bypass control-char checks }else if(ch>0xE07A&&ch<0xE100) ch&=0xFF;//UTF-8 encoding of U+E07B..U+E0FF; run control-char checks }else{//!utf8 if(ch<0x20||(ch>0x7A&&ch<0xA1)||ch==0xAA||ch==0xAC||ch==0xAD||ch==0xAF||(ch>0xB3&&ch<0xB9)) data.SetQEscape(offs);//nonprintable -- control or special. else data.SetText(offs); } if(ch<0x20){ data.SetQEscape(offs); if(ch==1){ if(~perms&CTRL_SPACE)IssueMessage(WARNING1,INVALID_CONTROL,offs,ch); if(!data.ExtractByte(++offs)&&!include_00_safe) IssueMessage(WARNING1,EMBEDDED_00,offs); data.SetQEscape(offs); }else if(ch==0x0D){ if(~perms&CTRL_NEWLINE)IssueMessage(WARNING1,INVALID_CONTROL,offs,ch); try{ if(data[offs+1]!=0x0D)data.SetEol(offs,2); else data.SetNoEol(offs); }catch(uint){} } else if(ch==0x0E){ if(~perms&CTRL_FONT_SMALL)IssueMessage(WARNING1,INVALID_CONTROL,offs,ch); }else if(ch==0x0F){ if(~perms&CTRL_FONT_LARGE)IssueMessage(WARNING1,INVALID_CONTROL,offs,ch); }else if(ch==0x1F){ if(~perms&CTRL_SPACE)IssueMessage(WARNING1,INVALID_CONTROL,offs,ch); if(!data.ExtractByte(++offs)&&!include_00_safe) IssueMessage(WARNING1,EMBEDDED_00,offs); data.SetQEscape(offs,2); if(!data.ExtractByte(++offs)&&!include_00_safe) IssueMessage(WARNING1,EMBEDDED_00,offs); }else IssueMessage(WARNING3,UNUSED_CONTROL,offs,ch); }else if(ch<0x7B); else if(ch==0x81){ int id=data.ExtractEscapeWord(++offs); CheckTextID(0x49,id,offs); if((!(id&0xFF)||!(id&0xFF00))&&!include_00_safe) IssueMessage(WARNING1,INCLUDING_00_ID,offs,id); ++offs; }else if(ch==0x86){ if(~perms&CTRL_NO_STACK_CHECK){ if(stack.length()<8){ IssueMessage(WARNING1,CANNOT_SHUFFLE,offs); perms|=CTRL_NO_STACK_CHECK; }else{ swap(stack[6],stack[0]); swap(stack[7],stack[1]); swap(stack[4],stack[6]); swap(stack[5],stack[7]); swap(stack[2],stack[4]); swap(stack[3],stack[5]); } } }else if(ch<0x88||ch==0x9A){ if(ch==0x9A){ uint arg; ch=data.ExtractQEscapeByte(++offs); switch(ch){ case 0x00: // print qword currency if(!include_00_safe)IssueMessage(WARNING1,EMBEDDED_00,offs); case 0x01: // print qword currency case 0x02: // ignore color code break; case 0x03: // push WORD stack = string(2,char(STACK_WORD)) + stack; arg=data.ExtractEscapeWord(++offs); if(!(arg&0xFF)&&!include_00_safe)IssueMessage(WARNING1,EMBEDDED_00,offs); ++offs; if(!(arg>>8)&&!include_00_safe)IssueMessage(WARNING1,EMBEDDED_00,offs); break; case 0x04: // Delete BYTE characters arg=data.ExtractQEscapeByte(++offs); if(!arg&&!include_00_safe)IssueMessage(WARNING1,EMBEDDED_00,offs); case 0x06: // print hex byte case 0x07: // ... word case 0x08: // ... dword case 0x0B: // ... qword case 0x0C: // print name of station case 0x0D: // print word in weight break; case 0x10: // choice list value if (choice_list == 0) IssueMessage(ERROR,NOT_IN_CHOICE_LIST,offs); /* FALL THROUGH */ case 0x0E: // set gender case 0x0F: // set case if (_grfver < 7) IssueMessage(WARNING1, NEED_VERSION_7, _grfver); arg = data.ExtractQEscapeByte(++offs); if (!arg) IssueMessage(ERROR,EMBEDDED_00, offs); break; case 0x11: // choice list default if (_grfver < 7) IssueMessage(WARNING1, NEED_VERSION_7, _grfver); if (choice_list == 0) IssueMessage(ERROR, NOT_IN_CHOICE_LIST, offs); choice_list = 2; break; case 0x12: // end choice list if (_grfver < 7) IssueMessage(WARNING1, NEED_VERSION_7, _grfver); if (choice_list == 0) IssueMessage(ERROR, NOT_IN_CHOICE_LIST, offs); if (choice_list == 1) IssueMessage(ERROR, NO_DEFAULT_IN_CHOICE_LIST, offs); choice_list = 0; break; case 0x13: // begin gender choice list case 0x15: // begin plural choice list arg = data.ExtractQEscapeByte(++offs); if (!arg) IssueMessage(ERROR, EMBEDDED_00, offs); /* FALL THROUGH */ case 0x14: // begin case choice list if (_grfver < 7) IssueMessage(WARNING1, NEED_VERSION_7, _grfver); if (choice_list != 0) IssueMessage(ERROR, NESTED_CHOICE_LIST, offs); choice_list = 1; break; default: IssueMessage(ERROR,INVALID_EXT_CODE,offs,ch); perms|=CTRL_NO_STACK_CHECK; } } if(~perms&CTRL_NO_STACK_CHECK){ switch(ch){ case 0x7D:case 0x06: STACK_CHECK(STACK_BYTE,1) case 0x82:case 0x83: STACK_CHECK(STACK_DATE,2) case 0x7C:case 0x7E:case 0x84:case 0x85:case 0x87:case 0x07:case 0x0C:case 0x0D: STACK_CHECK(STACK_WORD,2) case 0x80: STACK_CHECK(STACK_TEXT,2) case 0x7B:case 0x7F:case 0x08: STACK_CHECK(STACK_DWORD,4) //Extended format codes (9A XX) case 0x00:case 0x01:case 0x0B: STACK_CHECK(STACK_QWORD,8) case 0x02:case 0x03:case 0x04:case 0x0E:case 0x0F:case 0x10:case 0x11:case 0x12: case 0x13:case 0x14:case 0x15: --ret; // These do not read from the stack. break; DEFAULT(ch) } ++ret; } }else if(ch<0x9A){ data.SetQEscape(offs); if(~perms&CTRL_COLOR)IssueMessage(WARNING1,INVALID_CONTROL,offs,ch); if(ch==0x99){ if(!data.ExtractByte(++offs)&&!include_00_safe) IssueMessage(WARNING1,EMBEDDED_00,offs); data.SetQEscape(offs); } }else if(ch<0x9E){ data.SetQEscape(offs); IssueMessage(WARNING3,UNUSED_CONTROL,offs,ch); } if(++offs>=length)break; } if (choice_list != 0) IssueMessage(ERROR, CHOICE_LIST_NOT_TERMINATED, offs); if(ch) { if(_autocorrect) { IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECT_ADD,0); data.Append(0); ch=0; offs++; } else { IssueMessage(WARNING1,NO_NULL_FOUND); } } if(retInfo==RETURN_NULL)return ch; if(retInfo==RETURN_STACK)return(perms&CTRL_NO_STACK_CHECK)?(unsigned)-1:ret; INTERNAL_ERROR(retInfo,retInfo); } static const uchar stackSize[]={0,1,2,2,4,2,8}; string MakeStack(int items,...){ string ret; WrapAp(items); uint item; for(int i=0;i6,_grfver); if(GetLangName(id)==_unknownLanguage)IssueMessage(WARNING2,UNKNOWN_LANGUAGE,offs,id); } string GetLangName(uint id){ VERIFY(id<0x80,id); if(langNames::Instance().names[id]!="")return langNames::Instance().names[id]; return _unknownLanguage; } grfcodec-6.0.3/src/globals.cpp0000644000000000000000000000226512027143046014714 0ustar rootroot/* * globals.cpp * Defines global variables and constants for renum. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include using namespace std; #include "globals.h" ostream*pNfo=&cout,*pOut,*pErr=&cerr; const char*const VALID_PSEUDO="0123456789ABCDEFabcdef \t\v\r\n",*const WHITESPACE=" \t\v\r\n"; const string COMMENT="/;#"; string datadir; const char*COMMENT_PREFIX="//"; bool dosleep=true; unsigned int _spritenum,_grfver,_autocorrect=0,_act14_pal; grfcodec-6.0.3/src/pcxsprit.h0000644000000000000000000000324712027143046014613 0ustar rootroot#ifndef _PCXSPRIT_H #define _PCXSPRIT_H #include "pcxfile.h" #include "sprites.h" class pcxwrite : public pcxfile, public spritestorage { public: pcxwrite(multifile *mfile); virtual void filedone(int final); virtual void filestart(bool paletted); virtual void newsprite() {spriteno++; }; virtual void startsubimage(int x, int y, int sx, int sy); virtual void setline(CommonPixel *band); virtual void setsize(int sx, int sy) { startsubimage(-1, -1, sx, sy); }; virtual int curspritex() {return subimagex();}; virtual int curspritey() {return subimagey();}; virtual const char *filename(){return pcxfile::filename();}; virtual void newrow() { newline(); }; virtual void nextpixel(CommonPixel colour) { streamputpixel(colour); }; virtual void spritedone() { endsubimage(); }; virtual void spritedone(int sx, int sy); void writeheader(); void writepal(); void setcolours(U8 bg, U8 bord, int skip); void setpalette(const U8 *palette); //void setpalette(FILE *palfile); protected: const U8 *palette; private: void showspriteno(); CommonPixel background; CommonPixel border; int borderskip, spriteno, lastdigitx; pcxwrite(const pcxwrite&);//not copyable: pcxfile::colormap void operator=(const pcxwrite&);//not assignable: pcxfile::colormap }; class pcxread : public pcxfile { public: pcxread(singlefile *mfile); virtual void filestart(bool paletted); virtual void startsubimage(int x, int y, int sx, int sy); virtual void setline(CommonPixel *band); void readheader(); private: multifile *mfile; pcxread(const pcxread&); //not copyable: pcxfile::colormap void operator=(const pcxread&); //not assignable: pcx::colormap }; #endif /* _PCXSPRIT_H */ grfcodec-6.0.3/src/help.cpp0000644000000000000000000000312512027143046014215 0ustar rootroot/* * help.cpp * Defines functions for displaying program help in multiple languages. * * Copyright (c) 2004-2006, Dale McCoy. * Copyright (c) 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "language_mgr.h" #include "help.h" using namespace std; // -------- // Generate a ShowHelp function for each supported language. #define START_HELP_TEXT(lang) void ShowHelp_##lang(){ \ cout << "" #define END_HELP_TEXT() ; } #include "lang/all_help.h" // -------- // Generate a master ShowHelp function to switch to the correct // language specific one based on the current language. #undef START_LANGUAGES #undef RENUM_LANGUAGE #undef END_LANGUAGES #define START_LANGUAGES() void ShowHelp() { \ switch(LanguageMgr::Instance().GetCurrentLanguage()) { #define RENUM_LANGUAGE(name,code)case name: ShowHelp_##name(); break; #define END_LANGUAGES() } } #include "lang/language_list.h" grfcodec-6.0.3/src/inject.h0000644000000000000000000000205012027143046014202 0ustar rootroot/* * inject.h * Contains definitions for injecting new sprites into the NFO. * * Copyright 2005 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_INJECT_H_INCLUDED_ #define _RENUM_INJECT_H_INCLUDED_ istream&inj_getline(istream&,string&); int peek(istream&); void inject(const string&); void inject_into(const istream&); #endif//_RENUM_INJECT_H_INCLUDED_ grfcodec-6.0.3/src/grfmerge.cpp0000644000000000000000000002661112027143046015070 0ustar rootroot /*****************************************\ * * * GRFMerge - A program to integrate a * * .GRD file generated by * * GRFDiff into the respective * * GRF file. * * * * * * Copyright (C) 2003 by Josef Drexler * * * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #include #include #include #include #include #include #include #include "typesize.h" #include "version.h" #include "grfcomm.h" static const U32 GRDmagic = 0x67fb49ad; #define TEMPFILE "grfmerge.tmp" static int alwaysyes = 0; static char *grdfile = NULL; static long grdofs = 0; static int onlyshow = 0, issfx = 0; static void usage(void) { printf( "\nUsage:\n" " GRFMerge [options] %s[]\n" " Change sprites in the GRF file to the new ones from the GRD file.\n" " If the GRF file is not specified, GRFMerge will modify the one\n" " which the GRD file was generated from.\n" "\n" "Options:\n" " -h Show this help\n" " -l Only show which sprites the GRD file contains, don't integrate them\n" " -y Answer 'y' to all questions\n" "\n" "GRFMerge is Copyright (C) 2003 by Josef Drexler\n" "It may be freely copied and distributed.\n", issfx?"":" " ); exit(1); } static int checkisselfextr(const char *exe) { static const char *action = "reading exe"; FILE *f; char c[3]; U8 r, e; U32 magic = 0; f = fopen(exe, "rb"); if (!f && errno == ENOENT) { // try appending .exe for Win2k /* Length of string + length of ".exe" + '\0' */ char *altexe = (char*) malloc(strlen(exe) + 4 + 1); strcpy(altexe, exe); // Safe use due to already checked buffer size strcat(altexe, ".exe"); // Safe use due to already checked buffer size f = fopen(altexe, "rb"); free(altexe); } if (!f) return 0; cfread(action, c, 2, 1, f); if (c[0] != 'M' || c[1] != 'Z') return 0; fseek(f, 0x1c, SEEK_SET); cfread(action, c, 2, 1, f); c[2] = 0; if (!strcmp(c, "JD")) { cfread(action, &r, 1, 1, f); cfread(action, &e, 1, 1, f); grdofs = (long) r * (1L << e); fseek(f, grdofs, SEEK_SET); cfread(action, &magic, 4, 1, f); } fclose(f); return issfx = magic == GRDmagic; } static void die(const char *text, ...) { va_list argptr; va_start(argptr, text); vprintf(text, argptr); va_end(argptr); exit(2); } static int yesno(const char *txt) { char c; printf(" [Y/N] "); if (alwaysyes) { printf("Y\n"); } else { c = tolower(getc(stdin)); // skip the newline getc(stdin); if (c != 'y') { printf("%s", txt); return 0; } } return 1; } static char *block = NULL; #define BLOCKSIZE 8192 static void copyblock(size_t size, FILE *from, FILE *to) { size_t thisblock; while (size > 0) { if (size > BLOCKSIZE) thisblock = BLOCKSIZE; else thisblock = size; cfread("copying block", block, 1, thisblock, from); if (to) cfwrite("copying block", block, 1, thisblock, to); size -= thisblock; } } // this function reads a piece of data, and copies it to the other files static void copy(void *data, size_t size, size_t n, FILE *from, FILE *to) { size_t res; res = fread(data, size, n, from); if (res != n) die("Error while reading, wanted %d, got %d: %s", n, res, strerror(errno)); if (to) { res = fwrite(data, size, n, to); if (res != n) die("Error while writing, wanted %d, wrote %d: %s", n, res, strerror(errno)); } } // // Copy the data of a sprite from one file to another // this is complicated because for some sprites, the GRF file stores // the uncompressed length instead of how many bytes are in the file // // This code mostly copied from sprites.c, but to keep this program // small I didn't link in sprites.c and removed the unnecessary steps // from decodesprite (we're not actually interested in the uncompressed data, // just the length) // static U16 copysprite(FILE *from, FILE *to) { U8 info, ofs; S8 code; U16 size; size_t reallen; #ifdef DEBUG if (from) printf("Copying from pos. %ld\n", ftell(from)); if (to) printf("Copying to pos. %ld\n", ftell(to)); #endif if (feof(from)) return 0; copy(&size, 2, 1, from, to); if (!size) return 0; // EOF is also indicated by a zero-size sprite copy(&info, 1, 1, from, to); if (info == 0xff) { // verbatim data copyblock(size, from, to); return 1; } if (info & 2) { // size is compressed size copyblock(size-1, from, to); // already copied one byte return 1; } // the size given is the uncompressed size, so we need to go through // the uncompression routine until we have enough bytes copyblock(7, from, to); size -= 8; while (size > 0) { copy(&code, 1, 1, from, to); if (code < 0) { copy(&ofs, 1, 1, from, to); reallen = -(code >> 3); } else { reallen = code ? code : 128; copyblock(reallen, from, to); } if (size < reallen) die("\nOops, got too many bytes. How did that happen?\n" "Size is %d, len is %d at GRF file pos %ld\n", size, reallen, ftell(from)); size -= reallen; } return 1; } static void skipsprite(FILE *f) { copysprite(f, NULL); } static void showpct(long now, long total, int spriteno, int *pct) { int newpct = 100L*now/total; if (newpct == *pct) return; printf("\rSprite%5d Done:%3d%% \r", spriteno, newpct); *pct = newpct; } static int mergeset(FILE *grd, const char *grffile) { static const char *action = "reading GRD"; FILE *grf = NULL, *tmp = NULL; char grflen, *grfname; const char *c; char tempfile[16]; U16 version, i, j, numsprites, spriteno, curno; int lastfrom = -2, lastto = lastfrom, lastpct = -1; long grfsize = 0; U32 dummy; int skipped = onlyshow; cfread(action, &version, 2, 1, grd); if (version > 1) die("This is a GRD file version %d, I don't know how to handle that.\n", version); cfread(action, &numsprites, 2, 1, grd); cfread(action, &grflen, 1, 1, grd); /* Maximum length of string + 4 for ".bak" extension + '\0' */ grfname = (char*) malloc(grflen + 4 + 1); if (!grfname) die("Out of memory.\n"); cfread(action, grfname, 1, grflen, grd); /* Make sure the string is properly terminated. */ grfname[(int)grflen] = '\0'; if (onlyshow) { printf("Generated from: %s.grf\nSprites in file: ", grfname); } else { if (grffile) { c=strrchr(grffile, '\\'); if (!c) c=strchr(grffile, ':'); if (!c) c=grffile; else c++; if (strrchr(c, '.')) j=strrchr(c, '.') - c; else j=strlen(c); if (strnicmp(c, grfname, j)) { printf("Warning, this GRD file was generated from %s.GRF.\n", grfname); printf("Are you sure you want to apply it to %s?", grffile); if (!yesno("Skipping file\n")) { for (i=0; i= 0) printf(", "); lastfrom = spriteno; printf("%d", lastfrom); } lastto = spriteno; } skipsprite(grd); } else { while (++curno <= spriteno) { copysprite(grf, tmp); showpct(ftell(grf), grfsize, curno, &lastpct); } skipsprite(grf); copysprite(grd, tmp); showpct(ftell(grf), grfsize, curno, &lastpct); } } if (onlyshow) { if (lastfrom < 0) printf("No sprites."); else if (lastfrom != lastto) printf("-%d", lastto); printf("\n"); } else if (!skipped) { // copy remaining sprites, if any for (; copysprite(grf, tmp); ) showpct(ftell(grf), grfsize, ++curno, &lastpct); showpct(grfsize, grfsize, curno, &lastpct); // write the dummy checksum dummy = 0; cfwrite("writing dummy checksum", &dummy, 4, 1, tmp); } if (tmp) fclose(tmp); if (grf) fclose(grf); if (!skipped) { printf("\nDone\n"); // rename grf to bak if bak doesn't exist char *bakfile = getbakfilename(grffile); tmp = fopen(bakfile, "rb"); if (!tmp && (errno == ENOENT)) { // .bak doesn't exist, rename .grf to .bak printf("Renaming %s to %s\n", grffile, bakfile); if (rename(grffile, block)) { printf("Error while renaming: %s\n", strerror(errno)); printf("Shall I delete it instead?"); if (!yesno("Aborted.\n")) { die(""); } errno = EEXIST; // go delete it } else { errno = ENOENT; // don't try to delete it } } free(bakfile); if (tmp || (errno != ENOENT)) { printf("Deleting %s\n", grffile); if (remove(grffile)) die("Error while deleting: %s\n", strerror(errno)); } // rename tmp to grf printf("Renaming %s to %s\n", tempfile, grffile); if (rename(tempfile, grffile)) die("Error while renaming: %s\n", strerror(errno)); printf("All done!\n"); } free(grfname); return 1; } static int domerge(int argc, char **argv) { FILE *grd; U32 magic; int first = 1; grd = fopen(grdfile, "rb"); if (!grd) die("Can't open %s: %s\n", grdfile, strerror(errno)); block = (char*) malloc(BLOCKSIZE); if (!block) die("Out of memory.\n"); // read all sets of sprites while (1) { if (feof(grd)) break; fseek(grd, grdofs, SEEK_SET); cfread("reading GRD", &magic, 4, 1, grd); if (magic != GRDmagic) { if (first) die("This is not a GRD file.\n"); break; } first = 0; mergeset(grd, optind < argc ? argv[optind++] : NULL); grdofs = ftell(grd); }; if (grd) fclose(grd); free(block); return 1; } int main(int argc, char **argv) { char opt; printf("GRFMerge " VERSION " - Copyright (C) 2003 by Josef Drexler\n"); #ifdef WIN32 // debugint(); #endif checkisselfextr(argv[0]); while (1) { opt = getopt(argc, argv, "hlyv"); if (opt == (char) EOF) break; switch (opt) { case 'l': onlyshow = 1; break; case 'v': /* The version is already printed. */ return 0; case 'y': alwaysyes = 1; break; default: usage(); } } if (!issfx && (optind < argc) ) // no first arg if we're self-extracting grdfile = argv[optind++]; if (grdfile) // see if the GRD file specified is a self-extracting executable // also sets grdofs to skip the .exe code checkisselfextr(grdfile); else { // no GRD file specified; see if we're a self-extracting executable if (issfx) grdfile = argv[0]; else { printf("No GRD file specified!\n"); exit(2); } } return domerge(argc, argv); } grfcodec-6.0.3/src/pal2c.pl0000755000000000000000000000171212027143046014122 0ustar rootroot#!/usr/bin/perl -w use strict; use File::Basename; my @files = map glob, @ARGV; print "// Autogenerated file. DO NOT EDIT!\n"; print "// Edit Makefile.setup, pals/*.bcp, or pal2c.pl instead.\n\n"; print "#define NUM_PALS ".@files."\n\n"; print "extern U8 defaultpalettes[NUM_PALS][256*3];\n\n"; my $palind = 0; for (@files) { $_ = basename $_; s/\..*//; print "#define PAL_$_ $palind\n"; $palind++; } print "\n#ifdef DEFINE_PALS\n\n"; print " U8 defaultpalettes[NUM_PALS][256*3] = {\n"; @files = map glob, @ARGV; for (@files) { open FILE, "<$_" or die "Can't open $_: $!"; binmode FILE; local $/ = \3; # read three bytes at a time $.=0; $_ = basename $_; s/\..*//; print "// PAL_$_\n"; print " {\n"; while () { s/(.)/sprintf "%3d,",ord $1/ge; print "\t" if $. % 4 == 1 ; print "$_ "; printf "\t// %d-%d\n", $.-4, $.-1 if $. % 4 == 0; } close FILE; print " },\n"; } printf(" };\n"); print "\n#endif // DEFINE_PALS\n" grfcodec-6.0.3/src/pcxfile.cpp0000644000000000000000000002211412027143046014716 0ustar rootroot/*****************************************\ * * * PCX.CC - A class to combine several * * small images in one pcx file * * as well as read them out * * * * Copyright (C) 2000 by Josef Drexler * * * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #include //#include #include "pcxfile.h" #include "error.h" /***********************\ * * * class pcxfile * * * \***********************/ pcxfile::pcxfile() { if (sizeof(pcxheader) != 128) { printf("Somebody's packing the PCX header, it's not 128 bytes large!"); exit(254); } sx = -1; sy = -1; totaly = 0; subx = 0; px = 0; py = 0; bandy = -1; bandlines = 0; band = NULL; run = 0; curfile = NULL; mfile = NULL; header.window[2] = 65535; codecing = 0; paletted = true; } pcxfile::~pcxfile() { delete(mfile); if (band) { for (int i=0; icurfile(); } void pcxfile::newfile(bool paletted, int sx) { if (curfile) { // do we already have a file filedone(1); } // is it really a new file, or still the old one? if (getnextfile() || (header.window[2] == 65535)) { curfile = getcurfile(); newheader(sx); totaly = 0; subx = 0; px = 0; py = 0; } this->paletted = paletted; filestart(paletted); } void pcxfile::newheader(int sx) { const static pcxheader baseheader = { 10, 5, 1, 8, // manuf, version, encoding, bpp {0, 0, 65535, 65535}, // window[4] {72, 72}, // dpi[2] {0}, // cmap[48] 0, 1, -1, 1, // reserved, nplanes, bpl, palinfo {-1, -1}, // screen[2] {0 }}; // filler[54] header = baseheader; header.window[2] = sx - 1; header.screen[0] = sx - 1; header.bpl = sx; } void pcxfile::startimage(bool paletted, int sx, int sy, int bandx, int bandy) { pcxfile::sx = sx; pcxfile::sy = sy; pcxfile::bandx = bandx; pcxfile::bandy = bandy; newfile(paletted, sx); if (bandy > bandlines) alloclines(bandy); thisbandy = bandy; } void pcxfile::alloclines(int newlines) { CommonPixel **newband, **oldband = band; if (newlines <= bandlines) return; newband = new CommonPixel*[newlines]; if (!newband) { printf("%s: Error allocating band array\n", this->filename()); exit(2); } int i; for (i=0; ifilename()); exit(2); } } delete[](band); band = newband; i = bandlines; bandlines = newlines; for (; i= bandlines) { printf("%s: y=%d larger than bandlines=%d\n", this->filename(), y, bandlines); exit(2); } setline(band[y]); }; void pcxfile::endimage() { if (px) newband(); if (run) endencoding(); if (band) { int i; for (i=0; ifilename(), colour.m); exit(2); } band[y][x] = colour; // Colour mapping moved to pcxwrite::spritedone cx++; } void pcxfile::streamputpixel(CommonPixel *buffer, unsigned long datasize) { for (unsigned long i=0; ifilename(), colour.m); exit(2); } colour.m = putcolourmap[colour.m]; band[subofsy(y, 1)][subofsx(x, 1)] = colour; } /*U8 pcxfile::getpixel(int x, int y) { int sx = subofsx(x, 0); int sy = subofsy(y, 0); int colour; if (sx < 0 || sy < 0) colour = 255; else colour = band[sy][sx]; if (getcolourmap[colour] == -1) { printf("Agh! Getting colour %d but it has no map!\n", colour); exit(2); } return getcolourmap[colour]; }*/ void pcxfile::endsubimage() { } void pcxfile::newband() { int i, y; if ( (totaly + thisbandy > sy) && (thisbandy <= sy) ) { // would be too large newfile(this->paletted, sx); } totaly += thisbandy; for (y=0; yfilename()); exit(2); } while (num) { byte = (buffer++)->m; num--; thisrun = 1; while (num && (byte == buffer->m) && (thisrun < 0x3f)) { thisrun++; buffer++; num--; } if ((thisrun > 1) || ( (byte & 0xc0) == 0xc0) ) fputc(thisrun | 0xc0, curfile); fputc(byte, curfile); } } void pcxfile::encodebytes(const CommonPixel &pixel, int num) { U8 byte = pixel.m; int thisrun; if (codecing != 1) { printf("%s: I'm not encoding, but got a byte?\n", this->filename()); exit(2); } while (num) { thisrun = num; if (thisrun > 0x3f) thisrun = 0x3f; if ((thisrun > 1) || ( (byte & 0xc0) == 0xc0) ) fputc(thisrun | 0xc0, curfile); fputc(byte, curfile); num -= thisrun; } } void pcxfile::decodebytes(CommonPixel buffer[], int num) { U8 byte = 0; int thisrun, used; if (codecing != 2) { printf("%s: I'm not decoding, but am supposed to return a byte?\n", this->filename()); exit(2); } thisrun = run; if (thisrun) { used = run; if (used > num) used = num; for (int i = 0; i < used; i++) buffer[i].m = byte; buffer += used; num -= used; thisrun -= used; } while (num) { byte = fgetc(curfile); if ( (byte & 0xc0) == 0xc0) { // it's a run of equal bytes thisrun = byte & 0x3f; byte = fgetc(curfile); used = thisrun; if (used > num) used = num; for (int i = 0; i < used; i++) buffer[i].m = byte; buffer += used; num -= used; thisrun -= used; } else { (buffer++)->m = byte; num--; } } run = thisrun; return; } void pcxfile::endencoding() { // if (codecing == 1) // encodebytes(last - 1); // run = 0; codecing = 0; } int pcxfile::subofsx(int x, int checkbound) { int ofsx = subx + x + dx; if (ofsx >= sx) { if (checkbound) { printf("\n%s: ofsx too large: is %d=%d+%d+%d, sx=%d\n", this->filename(), ofsx, subx, x, dx, sx); exit(2); } else { return -1; } } return ofsx; } int pcxfile::subofsy(int y, int checkbound) { int ofsy = y + dy; if (ofsy >= bandlines) { if (checkbound) { printf("\n%s: ofsy too large\n", this->filename()); exit(2); } else { return -1; } } return ofsy; } void pcxfile::installreadmap(int *map) { getcolourmap = map; } void pcxfile::installwritemap(int *map) { putcolourmap = map; } #ifdef GRFCODEC_BIG_ENDIAN void pcxfile::be_swapheader(pcxheader& header) { header.window[0] = BE_SWAP16(header.window[0]); header.window[1] = BE_SWAP16(header.window[1]); header.window[2] = BE_SWAP16(header.window[2]); header.window[3] = BE_SWAP16(header.window[3]); header.dpi[0] = BE_SWAP16(header.dpi[0]); header.dpi[1] = BE_SWAP16(header.dpi[1]); header.bpl = BE_SWAP16(header.bpl); header.palinfo = BE_SWAP16(header.palinfo); header.screen[0] = BE_SWAP16(header.screen[0]); header.screen[1] = BE_SWAP16(header.screen[1]); } #else void pcxfile::be_swapheader(pcxheader&){} #endif grfcodec-6.0.3/src/path.cpp0000644000000000000000000000466512027143046014233 0ustar rootroot #include #include "path.h" #include "grfcomm.h" static int DotFound(const char *pB) { if (*(pB-1) == '.') pB--; switch (*--pB) { case ':' : if (*(pB-2) != '\0') break; case '/' : case '\\' : case '\0' : return 1; } return 0; } static char *stpcopy(char *dest, const char *src, unsigned maxlen) { safestrncpy(dest, src, maxlen); return dest + strlen(dest); } void fnmerge(register char *pathP, const char *driveP, const char *dirP, const char *nameP, const char *extP) { char *origpathP = pathP; if (driveP && *driveP) { *pathP++ = *driveP++; *pathP++ = ':'; } if (dirP && *dirP) { pathP = stpcopy(pathP, dirP, MAXPATH - (pathP - origpathP)); if (*(pathP-1) != '\\' && *(pathP-1) != '/') *pathP++ = '/'; } if (nameP) { pathP = stpcopy(pathP, nameP, MAXPATH - (pathP - origpathP)); } if (extP && *extP) { if (*extP != '.') *pathP++ = '.'; pathP = stpcopy(pathP, extP, MAXPATH - (pathP - origpathP)); } *pathP = 0; } int fnsplit(const char *pathP, char *driveP, char *dirP, char *nameP, char *extP) { register char *pB; register int Wrk; int Ret; char buf[ MAXPATH+2 ]; /* Set all string to default value zero */ Ret = 0; if (driveP) *driveP = 0; if (dirP) *dirP = 0; if (nameP) *nameP = 0; if (extP) *extP = 0; /* Copy filename into template up to MAXPATH characters */ pB = buf; while (*pathP == ' ') pathP++; if ((Wrk = strlen(pathP)) > MAXPATH) Wrk = MAXPATH - 1; *pB++ = 0; safestrncpy(pB, pathP, Wrk + 1); pB += Wrk; /* Split the filename and fill corresponding nonzero pointers */ Wrk = 0; for (; ; ) { switch (*--pB) { case '.' : if (!Wrk && (*(pB+1) == '\0')) Wrk = DotFound(pB); if ((!Wrk) && ((Ret & EXTENSION) == 0)) { Ret |= EXTENSION; safestrncpy(extP, pB, MAXEXT); *pB = 0; } continue; case ':' : if (pB != &buf[2]) continue; case '\0' : if (Wrk) { if (*++pB) Ret |= DIRECTORY; safestrncpy(dirP, pB, MAXDIR); *pB-- = 0; break; } case '/' : case '\\' : if (!Wrk) { Wrk++; if (*++pB) Ret |= FILENAME; safestrncpy(nameP, pB, MAXFILE); *pB-- = 0; if (*pB == 0 || (*pB == ':' && pB == &buf[2])) break; } continue; case '*' : case '?' : if (!Wrk) Ret |= WILDCARDS; default : continue; } break; } if (*pB == ':') { if (buf[1]) Ret |= DRIVE; safestrncpy(driveP, &buf[1], MAXDRIVE); } return (Ret); } grfcodec-6.0.3/src/grfmrg.asm0000644000000000000000000000017112027143046014545 0ustar rootrootifdef M32 .386 .model flat else .model compact endif .data public _grfmrg,_grfmrgsize _grfmrg = $ include grfmrg.ah endgrfcodec-6.0.3/src/mapescapes.h0000644000000000000000000000273112027143046015055 0ustar rootroot/* * mapescapes.h * Helper definitions for using boost::bimap * * Copyright 2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* If your compiler errors on the following lines, boost is not * properly installed, or your version of boost is too old. * Get boost from http://www.boost.org */ #include #include #include using namespace boost::bimaps; #define foreach BOOST_FOREACH typedef unsigned char U8; #include "escapes.h" typedef bimap > nfe_map; typedef nfe_map::value_type nfe_pair; typedef nfe_map::left_value_type nfe_lpair; typedef nfe_map::right_value_type nfe_rpair; typedef nfe_map::left_iterator nfe_left_iter; typedef nfe_map::right_iterator nfe_right_iter; extern nfe_map nfo_escapes; grfcodec-6.0.3/src/command.h0000644000000000000000000000761612027143046014361 0ustar rootroot/* * command.h * Defines structs and declares functions for comment commands. * * Copyright 2004-2006,2008-2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_COMMAND_H_INCLUDED_ #define _RENUM_COMMAND_H_INCLUDED_ #ifndef COMMAND_DATA /* Be careful when changing these defs; they have to remain compatible * with the ones in command.cpp.*/ #define COMMAND_DATA_START(name) enum name{ #define COMMAND_DATA(command) command, #define COMMAND_DATA_EX(placeholder,command) placeholder, #define COMMAND_DATA_END() }; #endif//COMMAND_DATA #ifndef RPNOFF #define RPNON() ((GetState(REALSPRITES)&1)==0) #define RPNOFF() ((GetState(REALSPRITES)&1)!=0) #define COMMENTON() ((GetState(REALSPRITES)&2)==0) #define COMMENTOFF() ((GetState(REALSPRITES)&2)!=0) #endif COMMAND_DATA_START(gen) COMMAND_DATA(REMOVEMESSAGES) COMMAND_DATA(PRESERVEMESSAGES) COMMAND_DATA(LINT) COMMAND_DATA(DIFF) COMMAND_DATA(USEID2) COMMAND_DATA(USESET) COMMAND_DATA(WARNING) COMMAND_DATA(VERSIONCHECK) COMMAND_DATA(LET) COMMAND_DATA(REALSPRITES) COMMAND_DATA(BEAUTIFY) COMMAND_DATA(CLEARACTION2) COMMAND_DATA(CLEARACTIONF) COMMAND_DATA(TESTID2) COMMAND_DATA(DEFINEID2) COMMAND_DATA(LOCATEID2) COMMAND_DATA(USEOLDSPRITENUMS) //COMMAND_DATA(VERBOSE) /* Add new comment commands here; if they need arguments, create a new * COMMENT_DATA_START/.../COMMENT_DATA_END block. * Also add code to parse_comment in command.cpp and, if necessary, one or * both of GetState(enum gen) or a new GetState. * Basically the same procedure applies for adding new arguments to existing * commands, except that they must go in the approprate COMMAND_DATA block, * and the GetState support, if necessary, must go in the correct GetState*/ COMMAND_DATA_END() COMMAND_DATA_START(san) COMMAND_DATA(OFF) COMMAND_DATA(NONE) COMMAND_DATA(FATAL) COMMAND_DATA(ERROR) COMMAND_DATA(WARNING1) COMMAND_DATA(WARNING2) COMMAND_DATA(WARNING3) COMMAND_DATA(WARNING4) COMMAND_DATA_END() COMMAND_DATA_START(preserve) COMMAND_DATA(NOPRESERVE) COMMAND_DATA_END() COMMAND_DATA_START(warn) COMMAND_DATA(DEFAULT) COMMAND_DATA(ENABLE) COMMAND_DATA(DISABLE) COMMAND_DATA_END() COMMAND_DATA_START(real) COMMAND_DATA(RPNOFF) COMMAND_DATA(RPNON) COMMAND_DATA(COMMENTOFF) COMMAND_DATA(COMMENTON) COMMAND_DATA_END() COMMAND_DATA_START(beaut)//Be sure to update GetState(enum beaut) if necessary COMMAND_DATA_EX(__NOUSE,OFF)//OFF is already defined in enum san. Same numeric value is vital for this trick. COMMAND_DATA(ON) COMMAND_DATA(MAXLEN) COMMAND_DATA(QUOTEHIGHASCII) COMMAND_DATA(QUOTEUTF8) COMMAND_DATA(HEXGRFID) COMMAND_DATA(LEADINGSPACE) COMMAND_DATA(CONVERTONLY) COMMAND_DATA(LINEBREAKS) COMMAND_DATA(GETCOOKIE) COMMAND_DATA(SETCOOKIE) COMMAND_DATA(USEESCAPES) COMMAND_DATA_END() COMMAND_DATA_START(ext) COMMAND_DATA_EX(__NOUSE2,OFF) COMMAND_DATA_EX(__NOUSE3,ON) //COMMAND_DATA(INOUTPUT) COMMAND_DATA_END() #ifndef _RENUM_COMMAND_H_FUNCTIONS_INCLUDED_ #define _RENUM_COMMAND_H_FUNCTIONS_INCLUDED_ int GetState(enum gen); uint GetState(enum beaut,int =0); bool GetWarn(int,int); bool is_command(const string&); bool parse_comment(const string&); void reset_commands(); int DoCalc(const string&,size_t&); int DoCalc(istream&,int&); bool CLCommand(int); #endif//_RENUM_COMMAND_H_FUNCTIONS_INCLUDED_ #endif//_RENUM_COMMAND_H_INCLUDED_ grfcodec-6.0.3/src/language_mgr.cpp0000644000000000000000000000327512027143046015723 0ustar rootroot/* * language_mgr.cpp * Defines classes and functions for management of program language. * * Copyright (c) 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "language_mgr.h" using namespace std; #include "inlines.h" LanguageMgr::LanguageMgr() { InitLanguageMap(); currentId = DetectLanguage(); } RenumLanguageId LanguageMgr::DetectLanguage() const { string langCode = safetostring(getenv("LANG")); return DecodeLanguageCode(langCode); } RenumLanguageId LanguageMgr::DecodeLanguageCode(const string& code) const { str2lang_map::const_iterator pos = codeIdMap.find(code); if(pos != codeIdMap.end()) return pos->second; return RL_DEFAULT; } // -------- // Generate language list initializer containing supported languages. #undef START_LANGUAGES #undef RENUM_LANGUAGE #undef END_LANGUAGES #define START_LANGUAGES() void LanguageMgr::InitLanguageMap() { #define RENUM_LANGUAGE(name,code) \ codeIdMap.insert(make_pair(code,name)); #define END_LANGUAGES() } #include "lang/language_list.h" grfcodec-6.0.3/src/grfid.cpp0000644000000000000000000001376212171043637014375 0ustar rootroot/* * This file is part of GRFCodec. * GRFCodec 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, version 2. * GRFCodec 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 OpenTTD. If not, see . */ #include #include #include #include #include "md5.h" #ifndef WIN32 #include #else #include #define PROT_READ 0 #define MAP_PRIVATE 0 /* Lets fake mmap for Windows, please! */ void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) { char *mem = (char*)malloc(size + 1); mem[size] = 0; FILE *in = fdopen(handle, "rb"); if (fread(mem, size, 1, in) != 1) { fclose(in); free(mem); return NULL; } fclose(in); return mem; } long munmap (void *ptr, long size) { free(ptr); return 0; } #endif #include "version.h" size_t _file_length; uint8_t *_file_buffer; uint8_t *_buffer; inline void SkipBytes(size_t count) { _buffer += count; } inline uint8_t ReadByte() { if (_buffer > _file_buffer + _file_length) return 0; return *(_buffer++); } inline uint16_t ReadWord() { uint16_t v = ReadByte(); return v | (ReadByte() << 8); } inline uint32_t ReadDWord() { uint32_t v = ReadWord(); return v | (ReadWord() << 16); } void SkipSpriteData(uint8_t type, uint16_t num) { if (type & 2) { SkipBytes(num); } else { while (num > 0) { int8_t i = ReadByte(); if (i >= 0) { int size = (i == 0) ? 0x80 : i; num -= size; SkipBytes(size); } else { i = -(i >> 3); num -= i; ReadByte(); } } } } inline uint32_t Swap32(uint32_t x) { return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000); } static const char header[] = { '\x00', '\x00', // End-of-file marker for old OTTDp versions 'G', 'R', 'F', '\x82', // Container version 2 '\x0D', '\x0A', '\x1A', '\x0A', // Detect garbled transmission }; inline uint32_t ReadSize(int grfcontversion) { return grfcontversion == 2 ? ReadDWord() : ReadWord(); } const char *GetGrfID(const char *filename, uint32_t *grfid) { *grfid = 0; FILE *f = fopen(filename, "rb"); if (f == NULL) return "Unable to open file"; /* Get the length of the file */ fseek(f, 0, SEEK_END); _file_length = ftell(f); fseek(f, 0, SEEK_SET); /* Map the file into memory */ _file_buffer = (uint8_t*)mmap(NULL, _file_length, PROT_READ, MAP_PRIVATE, fileno(f), 0); _buffer = _file_buffer; int grfcontversion = 1; if (_file_length > sizeof(header) && memcmp(_buffer, header, sizeof(header)) == 0) { grfcontversion = 2; _buffer += sizeof(header) + 4 + 1; // Header + offset till data + compression } /* Check the magic header, or what there is of one */ if (ReadSize(grfcontversion) != 0x04 || ReadByte() != 0xFF) return "No magic header"; /* Number of sprites. */ ReadDWord(); while (_buffer < _file_buffer + _file_length) { uint32_t num = ReadSize(grfcontversion); if (num == 0) break; if (_buffer + num > _file_buffer + _file_length) return "Corrupt GRF; would read beyond buffer"; uint8_t type = ReadByte(); if (type == 0xFF) { /* Pseudo sprite */ uint8_t action = ReadByte(); if (action == 0x08) { /* GRF Version, do not care */ ReadByte(); /* GRF ID */ *grfid = Swap32(ReadDWord()); /* No more, we don't care */ break; } else { SkipBytes(num - 1); } } else { SkipBytes(7); /* Skip sprite data */ SkipSpriteData(type, num - 8); } } munmap(_file_buffer, _file_length); fclose(f); return (*grfid == 0) ? "File valid but no GrfID found" : NULL; } const char *GetMD5(const char *filename, md5_state_t *md5) { FILE *f = fopen(filename, "rb"); if (f == NULL) return "Unable to open file"; /* Get the length of the file */ fseek(f, 0, SEEK_END); _file_length = ftell(f); fseek(f, 0, SEEK_SET); /* Map the file into memory */ _file_buffer = (uint8_t*)mmap(NULL, _file_length, PROT_READ, MAP_PRIVATE, fileno(f), 0); _buffer = _file_buffer; size_t read_length = _file_length; if (_file_length > sizeof(header) && memcmp(_buffer, header, sizeof(header)) == 0) { _buffer += sizeof(header); /* Reduce the length to contain only the data, but not the sprites. */ read_length = sizeof(header) + 4 + ReadDWord(); if (read_length > _file_length) return "Invalid sprite location offset"; } md5_append(md5, _file_buffer, read_length); munmap(_file_buffer, _file_length); fclose(f); return NULL; } int main(int argc, char **argv) { if (argc < 2 || strcmp(argv[1], "-h") == 0 || (strcmp(argv[1], "-m") == 0 && argc < 3)) { printf( "GRFID " VERSION " - Copyright (C) 2009 by Peter Nelson\n" "\n" "Usage:\n" " GRFID \n" " Get the GRF ID from the NewGRF file\n" " GRFID -m \n" " Get the MD5 checksum of the NewGRF file\n" " GRFID -v\n" " Get the version of GRFID\n" "\n" "You may copy and redistribute it under the terms of the GNU General Public\n" "License, as stated in the file 'COPYING'.\n" "Uses MD5 implementation of L. Peter Deutsch.\n"); return 1; } if (strcmp(argv[1], "-v") == 0) { printf("GRFID " VERSION " - Copyright (C) 2009 by Peter Nelson\n"); return 0; } const char *err; if (strcmp(argv[1], "-m") == 0) { md5_state_t md5; md5_init(&md5); err = GetMD5(argv[2], &md5); if (err == NULL) { md5_byte_t digest[16]; md5_finish(&md5, digest); for (size_t i = 0; i < sizeof(digest); i++) { printf("%02x", digest[i]); } printf("\n"); return 0; } } else { uint32_t grfid; err = GetGrfID(argv[1], &grfid); if (err == NULL) { printf("%08x\n", grfid); return 0; } } printf("Unable to get requested information: %s\n", err); return 1; } grfcodec-6.0.3/src/mapescapes.cpp0000644000000000000000000000360712027143046015413 0ustar rootroot/* * mapescapes.cpp * Helper functions for using boost::bimapped escapes * * Copyright 2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include using namespace std; #include "nforenum.h" #include "inlines.h" #include "messages.h" #include "mapescapes.h" string FindEscape(char action, int byte) { // Look for a custom escape foreach(const nfe_rpair& p, nfo_escapes.right.equal_range(byte)) if (p.second[0] == action) return " \\" + p.second; // Look for a built-in escape foreach(const esc& e, escapes) if (e.action==ctoi(action) && e.byte==byte) return ' ' + string(e.str); return ""; } string FindEscape(char action, int byte, uint offset) { // This time, look for a built-in escape first foreach(const esc& e, escapes) if (e.action==ctoi(action) && e.byte==byte && e.pos==offset) return ' ' + string(e.str); // Look for a custom escape foreach(const nfe_rpair& p, nfo_escapes.right.equal_range(byte)) if (p.second[0] == action) return " \\" + p.second; return ""; } int FindEscape(string str) { foreach(esc e, escapes) if(str == e.str+1) return e.byte; nfe_left_iter ret = nfo_escapes.left.find(str); if(ret == nfo_escapes.left.end()) return -1; return ret->second; } grfcodec-6.0.3/src/globals.h0000644000000000000000000000446512027143046014365 0ustar rootroot/* * globals.h * Contains global variables and constants (some #defined) for renum. * * Copyright 2004-2006,2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_GLOBALS_H_INCLUDED_ #define _RENUM_GLOBALS_H_INCLUDED_ #include #include // NFO header string #define NFO_HEADER(ver)\ ("// Automatically generated by GRFCODEC. Do not modify!\n"\ "// (Info version "+itoa(ver)+")\n") #define NFO_FORMAT(ver)\ (ver >= 32 ? "// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags\n"\ : "// Format: spritenum pcxfile xpos ypos compression ysize xsize xrel yrel\n") extern const char*const VALID_PSEUDO; // List of valid pseudo-sprite characters extern const char*const WHITESPACE; // List of whitespace characters extern const std::string COMMENT; // List of comment prefix characters extern std::string datadir; // Current data directory path extern bool dosleep; // If true, program will wait after creating a new data directory // If false, program will report where it found its data files. extern const char*COMMENT_PREFIX; // Comment prefix string #define NPOS (std::basic_string::npos) extern unsigned int _spritenum; // Current sprite number extern unsigned int _grfver; // GRF format version of current NFO extern unsigned int _act14_pal; // Palette info from action 14 extern unsigned int _autocorrect; // Auto-correction level //TODO: add command-line arguments to set these appropriately. extern std::ostream*pNfo; // NFO file output stream extern std::ostream*pOut; // Console output stream extern std::ostream*pErr; // Error output stream #endif//_RENUM_GLOBALS_H_INCLUDED_ grfcodec-6.0.3/src/pseudo.h0000644000000000000000000001062712027143046014236 0ustar rootroot/* * pseudo.h * Declaration of the PsuedoSprite class. Stores and re-writes pseudo-sprites. * * Copyright 2006-2010 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_PSEUDO_H_INCLUDED_ #define _RENUM_PSEUDO_H_INCLUDED_ #include #include"ExpandingArray.h" class PseudoSprite{ public: //PseudoSprite(); PseudoSprite(const string&,int); void CheckLinkage(int ofs,int count)const; // Use to read a single byte if you don't know/care about its meaning. // To read a field that happens to be one byte wide, use ExtractByte. uint LinkSafeExtractByte(uint)const; private: void LinkBytes(int,size_t); Expanding0Array linkage; static bool ignorelinkage; public: // Use to read a single byte if you don't know/care about its meaning. // To read a field that happens to be one byte wide, use ExtractByte. uint operator[](uint offs)const{return LinkSafeExtractByte(offs);} operator const char*()const{return packed.c_str();} uint Length()const; bool IsValid()const{return Length()!=0;} PseudoSprite&SetText(uint); PseudoSprite&SetText(uint,uint); PseudoSprite&SetUTF8(uint,uint); PseudoSprite&SetOpByte(uint,char); PseudoSprite&SetPositionalOpByte(uint,char); PseudoSprite&SetDate(uint,uint); PseudoSprite&SetQEscape(uint); PseudoSprite&SetQEscape(uint,uint); private: PseudoSprite&SetEscape(uint,bool,string,uint); public: PseudoSprite&SetHex(uint); PseudoSprite&SetHex(uint,uint); PseudoSprite&SetAllHex(); PseudoSprite&SetEot(uint); PseudoSprite&SetEol(uint,uint,uint); PseudoSprite&SetEol(uint loc,uint minbreaks){ return SetEol(loc,minbreaks,(minbreaks>1)?1:0); } PseudoSprite&SetNoEol(uint); PseudoSprite&SetGRFID(uint); PseudoSprite&SetDec(uint,uint); PseudoSprite&SetBE(uint,uint); PseudoSprite&SetByteAt(uint,uint); PseudoSprite&SetWordAt(uint,uint); PseudoSprite&SetDwordAt(uint,uint); PseudoSprite&Append(uchar); PseudoSprite&ColumnAfter(uint); uint ExtractByte(uint offs)const; uint ExtractWord(uint offs)const; uint ExtractExtended(uint offs)const; uint ExtractDword(uint offs)const; uint ExtendedLen(uint)const; uint ExtractVariable(uint,uint)const; uint ExtractUtf8(uint&, bool&); // in utf8.cpp. uint ExtractQEscapeByte(uint offs){ SetQEscape(offs); return ExtractByte(offs); } uint ExtractEscapeWord(uint offs){ SetBE(offs,2); return ExtractWord(offs); } void AddComment(const string&,uint); void TrailComment(const string&,uint); void AddBlank(uint); void NoBeautify(); friend ostream&operator<<(ostream&,PseudoSprite&); private: ostream&output(ostream&); public: static bool CanQuote(uint); static bool MayBeSprite(const string&); enum width {_B_, _BX_, _W_, _D_}; uint ReadValue(istream&, width); private: bool DoQuote(uint)const; bool IsText(uint)const; bool IsUTF8(uint)const; bool IsEot(uint)const; bool IsLinePermitted(uint)const; bool NoPrint(uint)const; void Invalidate(); bool UseOrig()const; string orig,packed; Expanding0Arraybeauty; ExpandingArraycontext,ext_print; bool valid,useorig; const int oldspritenum; // Support for sequential access public: #define PS_LOC_REF(size) \ class size; \ PseudoSprite& operator >>(size&); \ PseudoSprite& Extract(size&, uint); \ class size { \ public: \ size(); \ size& set(uint); \ uint val() const; \ uint loc() const; \ operator uint() const {return val();} \ friend PseudoSprite& PseudoSprite::operator >>(size&); \ friend PseudoSprite& PseudoSprite::Extract(size&, uint); \ private: \ PseudoSprite *p; \ uint offs; \ }; \ PS_LOC_REF(Byte) PS_LOC_REF(Word) PS_LOC_REF(ExtByte) PS_LOC_REF(Dword) #undef PS_LOC_REF uint BytesRemaining() const; PseudoSprite& seek(uint); private: uint extract_offs; }; #endif//_RENUM_PSEUDO_H_INCLUDED_ grfcodec-6.0.3/src/utf8.cpp0000644000000000000000000000617712027143046014165 0ustar rootroot/**************************************************************************** * utf8.c[pp] * This file contains functions to decode utf8 characters data the input * stream. * **************************************************************************/ /* Original version at http://xsb.sourceforge.net/api/utf8_8c-source.html */ #include #include #include"nforenum.h" #include"pseudo.h" #include"utf8.h" #include"messages.h" #include"command.h" #include"globals.h" #define CONT(i) ((data[off+i]&0xc0) == 0x80) #define VAL(i, s) ((data[off+i]&0x3f) << s) uint PseudoSprite::ExtractUtf8(uint& off, bool& valid){ PseudoSprite& data = *this; // Historical valid=false; if(data[off]<0xC0||data[off]>0xFC){ CheckLinkage(off,1); return data[off++]; } valid=true; /* 2-byte, 0x80-0x7ff */ if ( (data[off]&0xe0) == 0xc0 && CONT(1) ){ uint ret = ((data[off]&0x1f) << 6)|VAL(1,0); if(ret<0x80){ IssueMessage(ERROR,OVERLENGTH_UTF8,off); valid=false; return data[off++]; } data.SetUTF8(off,2); CheckLinkage(off,2); off+=2; return ret; } /* 3-byte, 0x800-0xffff */ if ( (data[off]&0xf0) == 0xe0 && CONT(1) && CONT(2) ){ uint ret = ((data[off]&0xf) << 12)|VAL(1,6)|VAL(2,0); if(ret<0x800){ IssueMessage(ERROR,OVERLENGTH_UTF8,off); valid=false; return data[off++]; } data.SetUTF8(off,3); CheckLinkage(off,3); if (ret>0xE07A && ret<0xE100) SetEscape(off, true, mysprintf("\\U%x", ret), 3); off+=3; return ret; } /* 4-byte, 0x10000-0x1FFFFF */ if ( (data[off]&0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3) ){ if((((data[off]&0x7) << 18)|VAL(1,12)/*|VAL(2,6)|VAL(3,0)*/)<0x10000){ IssueMessage(ERROR,OVERLENGTH_UTF8,off); valid=false; return data[off++]; } data.SetUTF8(off,4); off+=4; return(uint)-4; } /* 5-byte, 0x200000-0x3FFFFFF */ if ( (data[off]&0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4) ){ if((((data[off]&0x3) << 24)|VAL(1,18)/*|VAL(2,12)|VAL(3,6)|VAL(4,0)*/)<0x200000){ IssueMessage(ERROR,OVERLENGTH_UTF8,off); valid=false; return data[off++]; } data.SetUTF8(off,5); off+=5; return(uint)-5; } /* 6-byte, 0x4000000-0x7FFFFFFF */ if ( (data[off]&0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5) ){ if((((data[off]&0x1) << 30)|VAL(1,24)/*|VAL(2,18)|VAL(3,12)|VAL(4,6)|VAL(5,0)*/)<0x4000000){ IssueMessage(ERROR,OVERLENGTH_UTF8,off); valid=false; return data[off++]; } data.SetUTF8(off,6); off+=6; return(uint)-6; } IssueMessage(WARNING2,INVALID_UTF8,off); return data[off++]; } #define CHAR(x) (char(((ch>>((x)*6))&0x3F)|0x80)) string GetUtf8Encode(uint ch){ if(ch<0x80)return string()+char(ch); if(ch<0x800)return string()+char(((ch>>6 )&0x1F)|0xC0)+CHAR(0); if(ch<0x10000)return string()+char(((ch>>12)&0x0F)|0xE0)+CHAR(1)+CHAR(0); if(ch<0x200000)return string()+char(((ch>>18)&0x07)|0xF0)+CHAR(2)+CHAR(1)+CHAR(0); if(ch<0x4000000)return string()+char(((ch>>24)&0x03)|0xF8)+CHAR(3)+CHAR(2)+CHAR(1)+CHAR(0); if(ch<0x80000000)return string()+char(((ch>>30)&0x01)|0xFC)+CHAR(4)+CHAR(3)+CHAR(2)+CHAR(1)+CHAR(0); INTERNAL_ERROR(ch,ch); } grfcodec-6.0.3/src/inlines.h0000644000000000000000000000604712027143046014401 0ustar rootroot/* * inlines.h * Contains inlinable fuctions for renum * * Copyright 2004-2005 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_INLINES_H_INCLUDED_ #define _RENUM_INLINES_H_INCLUDED_ #include #include #include #include #include #include"globals.h" #include"nforenum.h" inline string safetostring(const char*ptr){return ptr?ptr:"";} inline istream&eat_white(istream&in){ while(isspace(in.peek()))in.ignore(); return in; } inline void strip_trailing_white(string&str){ string::iterator last = str.end(); for (string::iterator i = str.begin(); i != str.end(); i++) if (!isspace(*i)) last = i; if (last != str.end()) str.erase(last+1, str.end()); } inline int ctoi(char ch){ if(ch>='0'&&ch<='9')return ch-'0'; if(ch>='A'&&ch<='F')return ch-'A'+10; if(ch>='a'&&ch<='f')return ch-'a'+10; return 0; } inline bool is_comment(istream&in){ if(strchr("#;",in.peek()))return true; if(in.peek()!='/')return false; in.ignore(); if(in.peek()=='/'){ in.unget(); return true; } in.unget(); return false; } inline bool is_comment(const string&str,size_t off){ if(strchr("#;",str[off]))return true; if(str[off]!='/'||str[off+1]!='/') return false; return true; } inline bool is_comment(const string&line){ return line==""||is_comment(line,line.find_first_not_of(WHITESPACE)); } inline string UCase(string str){ size_t len=str.length(); for(size_t i=0;i>=8; } return ret; } if(!x)ret="0"; assert(radix<=16); while(x){ ret="0123456789ABCDEF"[x%radix]+ret; x/=radix; } while(ret.length()=0)return itoa((uint)x,radix,minlen); if(x==INT_MIN)return '-'+itoa(uint(INT_MAX)+1,radix,minlen); else return '-'+itoa((uint)-x,radix,minlen); } inline uint ReadHex(istream&in,uint digits){ uint ret; while(isspace(in.peek()))in.ignore(); char ch; in.get(ch); if((ret=ctoi(ch))==0&&ch!='0'){ in.unget().clear(ios::badbit); return ret; } for(;--digits;){ in.get(ch); if(ctoi(ch)==0&&ch!='0'){ in.unget(); return ret; } ret<<=4; ret|=ctoi(ch); } return ret; } #endif//_RENUM_INLINES_H_INCLUDED_ grfcodec-6.0.3/src/data.h0000644000000000000000000000600112027143046013637 0ustar rootroot/* * data.h * Declarations for the data files helper functions. * * Copyright 2005-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_DATA_H_INCLUDED_ #define _RENUM_DATA_H_INCLUDED_ #include #ifndef DATA #define DATA() enum files{ #endif #ifndef DATA_FILE #define DATA_FILE(name) dat##name, #endif #ifndef END_DATA #define END_DATA() FILES_MAX }; #endif DATA() DATA_FILE(79Dv) DATA_FILE(B) DATA_FILE(5) DATA_FILE(TextIDs) DATA_FILE(callbacks) DATA_FILE(langs) DATA_FILE(versions) DATA_FILE(feat) DATA_FILE(0) DATA_FILE(2v) DATA_FILE(D) DATA_FILE(IDs) DATA_FILE(4) DATA_FILE(2r) /* * To add a new data files, pick a name (matching the regex [0-9a-zA-Z_]*), * add a DATA_FILE(name) macro here, and add a static const char _datname[] * to data.cpp. (Preferably in the same order as above. More instructions * immediately before the definition of _datfeat, and after the last * _dat* definiton.) * Files that depend on feat.dat must appear after it; files that do not must * appear before it. * * Open the file with FILE*pFile=myfopen(name);. myfopen (re)writes, if * necessary, name.dat and returns a non-null input FILE*. * Read from the file using standard C file IO functions, or the four * #defines below. CheckEOF errors if ch==EOF and returns ch. GetCheck* * returns a byte/word read from pFile, and will error if insufficient data * is present. GetCheckWord (and ...Dword, if/when implemented) read * words/dwords little-endian. myfread uses fread to read count bytes into * pch, and errors if insufficient bytes are present. * name is used to generate proper error messages. * * Close the file with fclose(), as normal. * Unless you have a very good reason, do not call the FILE* anything other * than pFile. The GetCheck*s all assume that the FILE* is pFile. */ END_DATA() #define myfopen(file) _myfopen(dat##file, false) FILE*_myfopen(files, bool); int _CheckEOF(int,files,const char*,int); int _GetCheckWord(FILE*,files,const char*,int); void _myfread(FILE*,uchar*,uint,files,const char*,int); #define CheckEOF(ch,name) _CheckEOF(ch,dat##name,__FILE__,__LINE__) #define GetCheckByte(name) CheckEOF(fgetc(pFile),name) #define GetCheckWord(name) _GetCheckWord(pFile,dat##name,__FILE__,__LINE__) #define myfread(pch,count,name) _myfread(pFile,pch,count,dat##name,__FILE__,__LINE__) #endif//_RENUM_DATA_H_INCLUDED_ grfcodec-6.0.3/src/escapes.h0000644000000000000000000001200712027143046014354 0ustar rootroot// Escapes.h // The data required for writing the various not-quoted escape sequences. // // This file is shared between GRFCodec and NFORenum. // GRFCodec defines GRFCODEC. NFORenum does not. #ifndef GRFCODEC #define START_ESCAPES()\ const struct esc{\ char byte;\ char*str;\ char action;\ uint pos;\ }escapes[]={ #define ESCAPE(byte,str,action,off)\ {(char)0x##byte,(char*)("\\" str),(char)0x##action,off}, #define ESCAPE_79(byte,str,off)\ ESCAPE(byte,str,7,off) #define ESCAPE_AD(byte,str,action,off,adtl)\ {(char)0x##byte,(char*)("\\" str),(char)0x##action,off}, #define ESCAPE_OVR(byte,str,action,ovr)\ {(char)0x##byte,(char*)("\\" str),(char)0x##action,0}, #else /* GRFCODEC */ #define START_ESCAPES()\ const struct esc{\ char byte;\ char*str;\ char action;\ uint pos;\ bool (*additional)(const U8*,uint);\ bool (*override)(const U8*,uint);\ }escapes[]={ #define ESCAPE(byte,str,action,off)\ {(char)0x##byte,(char*)("\\" str),(char)0x##action,off,NULL,NULL}, #define ESCAPE_79(byte,str,off)\ ESCAPE(byte,str,7,off) ESCAPE(byte,str,9,off) #define ESCAPE_AD(byte,str,action,off,adtl)\ {(char)0x##byte,(char*)("\\" str),(char)0x##action,off,__ESC_AD__##adtl,NULL}, #define ESCAPE_OVR(byte,str,action,ovr)\ {(char)0x##byte,(char*)("\\" str),(char)0x##action,0,NULL,__ESC_OVR__##ovr}, #define CALLBACK_AD(name)\ bool __ESC_AD__##name(const U8*data,uint len) #define CALLBACK_OVR(name)\ bool __ESC_OVR__##name(const U8*data,uint pos) #endif /* GRFCODEC */ #define END_ESCAPES() };\ static const unsigned int num_esc=sizeof(escapes)/sizeof(escapes[0]); #ifdef GRFCODEC // *********************************************************************** // Define callback functions for ESCAPE_* here // Use the same value for the argument to the CALLBACK_* macro and the last // argument to ESCAPE_* // The signature for CALLBACK_AD is: // bool func(const U8*data, uint len) // The signature for CALLBACK_OVR is: // bool func(const U8*data, uint pos) // *********************************************************************** CALLBACK_AD(IsGRM){ return len==9&&data[2]==0&&data[4]==0xFE&&data[5]==0xFF; } CALLBACK_OVR(Is2Op){ if(pos<7||!(data[3]&0x80)||data[3]==0x80||data[3]==0x83)return false; uint w = 1<<((data[3]>>2)&3); uint loc=4;//Start at first while(true){//read [] [ ...]. loc reports byte to be checked. if((data[loc++/**/]&0xE0)==0x60)loc++;// if(loc>=pos)return false; if(!(data[loc]&0x20))return false;//end of advanced if(data[loc++/**/]&0xC0) loc+=2*w;// and
/ loc+=w;// if(loc==pos)return true;//This is an operation byte if(loc++/**/>pos)return false;//past proposed op byte } } #endif /* GRFCODEC */ START_ESCAPES() // *********************************************************************** // Define escape sequences here. // The arguments to ESCAPE* are: // byte: the byte value for this escape sequence, in hex. // str: the string for this escape sequence, excluding the \. // action: the action for this escape sequence, eg 2, 7, D, &c. // Note that 7 and 9 are usually paired, with ESCAPE_79, which does // not take an action argument. // off: the offset in the action where this escape sequence appears // ESCAPE_AD takes an additional argument; the CALLBACK to call if the // byte, action, and off checks all pass. // EXCAPE_OVR takes an argument in place of off, the CALLBACK to call // instead of running the off check. // *********************************************************************** ESCAPE_OVR(00,"2+",2,Is2Op) ESCAPE_OVR(01,"2-",2,Is2Op) ESCAPE_OVR(02,"2<",2,Is2Op) ESCAPE_OVR(03,"2>",2,Is2Op) ESCAPE_OVR(04,"2u<",2,Is2Op) ESCAPE_OVR(05,"2u>",2,Is2Op) ESCAPE_OVR(06,"2/",2,Is2Op) ESCAPE_OVR(07,"2%",2,Is2Op) ESCAPE_OVR(08,"2u/",2,Is2Op) ESCAPE_OVR(09,"2u%",2,Is2Op) ESCAPE_OVR(0A,"2*",2,Is2Op) ESCAPE_OVR(0B,"2&",2,Is2Op) ESCAPE_OVR(0C,"2|",2,Is2Op) ESCAPE_OVR(0D,"2^",2,Is2Op) ESCAPE_OVR(0E,"2sto",2,Is2Op) ESCAPE_OVR(0E,"2s",2,Is2Op) ESCAPE_OVR(0F,"2rst",2,Is2Op) ESCAPE_OVR(0F,"2r",2,Is2Op) ESCAPE_OVR(10,"2psto",2,Is2Op) ESCAPE_OVR(11,"2ror",2,Is2Op) ESCAPE_OVR(11,"2rot",2,Is2Op) ESCAPE_OVR(12,"2cmp",2,Is2Op) ESCAPE_OVR(13,"2ucmp",2,Is2Op) ESCAPE_OVR(14,"2<<",2,Is2Op) ESCAPE_OVR(15,"2u>>",2,Is2Op) ESCAPE_OVR(16,"2>>",2,Is2Op) ESCAPE_79(00,"71",3) ESCAPE_79(01,"70",3) ESCAPE_79(02,"7=",3) ESCAPE_79(03,"7!",3) ESCAPE_79(04,"7<",3) ESCAPE_79(05,"7>",3) ESCAPE_79(06,"7G",3) ESCAPE_79(07,"7g",3) ESCAPE_79(08,"7gG",3) ESCAPE_79(09,"7GG",3) ESCAPE_79(0A,"7gg",3) ESCAPE_79(0B,"7c",3) ESCAPE_79(0C,"7C",3) ESCAPE(00,"D=",D,2) ESCAPE(01,"D+",D,2) ESCAPE(02,"D-",D,2) ESCAPE(03,"Du*",D,2) ESCAPE(04,"D*",D,2) ESCAPE(05,"Du<<",D,2) ESCAPE(06,"D<<",D,2) ESCAPE(07,"D&",D,2) ESCAPE(08,"D|",D,2) ESCAPE(09,"Du/",D,2) ESCAPE(0A,"D/",D,2) ESCAPE(0B,"Du%",D,2) ESCAPE(0C,"D%",D,2) ESCAPE_AD(00,"DR",D,3,IsGRM) ESCAPE_AD(01,"DF",D,3,IsGRM) ESCAPE_AD(02,"DC",D,3,IsGRM) ESCAPE_AD(03,"DM",D,3,IsGRM) ESCAPE_AD(04,"DnF",D,3,IsGRM) ESCAPE_AD(05,"DnC",D,3,IsGRM) ESCAPE_AD(06,"DO",D,3,IsGRM) END_ESCAPES() grfcodec-6.0.3/src/grfmrgc.asm0000644000000000000000000000025012027143046014706 0ustar rootrootsection .data global _grfmrg,_grfmrgsize,grfmrg,grfmrgsize align 4 grfmrgsize: _grfmrgsize dd _grfmrg_end-_grfmrg grfmrg: _grfmrg: incbin "grfmrgc.bin" _grfmrg_end: grfcodec-6.0.3/src/nfosprite.h0000644000000000000000000000423512027143046014746 0ustar rootroot/* * nfosprite.h * A collection of classes for parsing and sprites from an .nfo file. * * Copyright 2006 by Dale McCoy. * dalestan@gmail.com * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _NFOSPRITE_H #define _NFOSPRITE_H #include #include #include"typesize.h" #include"sprites.h" typedef unsigned short ushort; class Sprite{ protected: Sprite(){} public: virtual ~Sprite(){} enum SpriteType{ST_REAL,ST_PSEUDO,ST_INCLUDE}; virtual SpriteType GetType()const =0; class unparseable{//thrown by the constructors public: unparseable(string reason,size_t sprite); string reason; }; }; class Real:public Sprite{ public: void AddSprite(size_t,int,const string&); Sprite::SpriteType GetType()const{return ST_REAL;} vector infs; private: ostream&output(ostream&)const; static string prevname; static int prevy; }; class Pseudo:public Sprite{ public: Pseudo(size_t,int,int,const string&,int); U8 operator[](int offs)const{return packed[offs];} uint size()const; Sprite::SpriteType GetType()const{return ST_PSEUDO;} const char*GetData()const{return packed.c_str();} //static bool CanQuote(uint); static bool MayBeSprite(const string&); enum width {_B_, _BX_, _W_, _D_}; static uint ReadValue(istream&, width); private: string packed; }; class Include:public Sprite{ public: Include(const string&); Sprite::SpriteType GetType()const{return ST_INCLUDE;} const char *GetName()const{return name.c_str();} private: string name; }; #endif /* _NFOSPRITE_H */ grfcodec-6.0.3/src/act0.cpp0000644000000000000000000004102712027143046014117 0ustar rootroot/* * act0.cpp * Contains definitions for checking action 0s. * * Copyright 2005-2010 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #ifdef _MSC_VER #pragma warning(disable:4702)//unreachable code #include #pragma warning(default:4702) #else #include #endif #include #include #include using namespace std; #include"nforenum.h" #include"inlines.h" #include"messages.h" #include"ExpandingArray.h" #include"sanity_defines.h" #include"data.h" #include"pseudo.h" #include"command.h" #include"rangedint.h" #include"act123.h" /*Data Format: bits indicate width: 0-2 width 3 special formatting or checks 5-4 Basic formatting 7-6 (FE strings only) linebreak formatting 7 (Non-FE strings only) permit property multiple times Width: 1-4: byte, word, extended byte, double; resp. Special formatting/checks: If set: - Print decimal values as dates - Check BE words against defined TTD and DCxx IDs - Check BE doubles against remaining size of property (e.g. indu prop 0A) - Check default words against defined IDs for feature that relates to this one (i.e. Check that tiles used in indu prop 0A are defined.) Basic formatting: 0:default 1:quote 2:decimal 3:B-E hex linebreak formatting: 0x:default Cx:linebreak;long lead Special cases: char FE means variable length, see corresponding LengthData struct in subData char FF means no such property for variable length properties only: As above, with special cases as follows: char r means the next char is repeated some number of times, set by the char after it, for which chars 80-FF take on the value of the data indicated by char num&0x7F of this string (well, sorta--FEs aren't counted, for one) char x means multiply the next two chars together char * means the next char is repeated an arbitrary number of times. This is followed by the length of the terminator (1, 2, or 4) and then the terminator char l means the next character appears in the NFO char | means what is on either side is valid -- right side will be ignored if left side does not have at least one literal (ex: \x03 == l\xFF\x02|\x01, but \x01|l\xFF\x02 will always read exactly one byte.) char FD takes the same type of parameter as r, but adds that value to the list of 80+x values for all following FE substrings. char FE as above char C0 means to insert a linebreak (as if encountering C1..C4) but without reading any bytes A backslash is used to escape nulls that are not end-of-string characters char FF is undef */ typedef basic_string ustring; typedef vector int_str; class PropData:public auto_array{ public: PropData(){} void Init(FILE*,bool); uchar GetData(uint)const; uint GetLength()const{return(uint)length.length();} const PropData*GetVarLength(int)const; uint GetValue(uint&,const int_str&)const; uint maxfirst(int prop){return idRange[prop]&0xFF;} uint maxlast(int prop){return (idRange[prop]>>8)&0xFF;} private: ustring length; vector idRange; void readString(FILE*,bool); int CountFE(); void operator=(const PropData&); PropData(const PropData&); }; class Check0:public auto_array{ public: void Check(PseudoSprite&); static Check0&Instance(){static Check0 obj;return obj;} uint GetFeat8(){return _p[8].GetLength();} private: Check0(); bool CheckVar(uint&,PseudoSprite&,const PropData&,bool addblank,bool,int_str =int_str())const; void operator=(const Check0&); Check0(const Check0&); }; void Check0(PseudoSprite&str){ Check0::Instance().Check(str); } uchar PropData::GetData(unsigned int prop)const{ return prop >)_m)[feat][id]; } private: static ExpandingArray > _m; }; ExpandingArray > Prop08Tracking::_m; bool IsProp08Set(uint feature,uint id){ return Prop08Tracking::Check(feature,id); } uint CargoTransTable(int newlimit=0){ static int limit=0; static uint prevtable; if(newlimit<0) limit=0; else if(newlimit){ if(limit) IssueMessage(WARNING1,DUPLICATE_TRANS_TABLE,prevtable); limit = newlimit; prevtable=_spritenum; } if(limit) return (uint)limit; return 0x1B; } void Init0(){ Prop08Tracking::Reset(); CargoTransTable(-1); } #define GetWidth(x) ((x)&7) #define IsSpecial(x) ((x)&8) #define GetFormat(x) ((x>>4)&3) #define GetLinebreak(x) ((x>>6)&3) bool IsTextDefined(uint); static vector lengthlist; static void FormatSprite(PseudoSprite&str, uint&ofs, const uint format, const uint IDs = 1) { uint feature = str.ExtractByte(1); for(uint j=0;j warned; if (k>MaxFeature()) { if (!warned[feature]) IssueMessage(WARNING1,COULD_NOT_VERIFY); warned[feature]=true; break; } if (!IsProp08Set(k,str.ExtractWord(ofs))) IssueMessage(ERROR,ACT3_PRECEDES_PROP08,ofs,str.ExtractWord(ofs)); } break; case 1: if(IsSpecial(format)) { str.SetText(ofs); } else { str.SetText(ofs,GetWidth(format)); } break; case 2: // Decimal (or date) if (IsSpecial(format)) str.SetDate(ofs,GetWidth(format)); else str.SetDec(ofs,GetWidth(format)); break; case 3: // BE hex if (IsSpecial(format)) { if (GetWidth(format)==2) { // Check word against defined TextIDs. if(!IsTextDefined(str.ExtractWord(ofs))) IssueMessage(ERROR,UNDEFINED_TEXTID,ofs,str.ExtractWord(ofs)); } else if (GetWidth(format)==4) // Check dword against prop length lengthlist.push_back(ofs); } str.SetBE(ofs,GetWidth(format)); break; } if(GetWidth(format)==3) ofs+=str.ExtendedLen(ofs); else ofs+=GetWidth(format); } } void Check0::Check(PseudoSprite&str){ assert(str.ExtractByte(0)==0); int feature=str.ExtractByte(1); //IssueMessage(-2,V_ACTION_FOR,1,0,ACTION_STRINGS,0,FEATURE_STRINGS,feature); if(!IsValidFeature(ACT0,feature)){ IssueMessage(FATAL,INVALID_FEATURE); return; } int propsRemain=str.ExtractByte(2),prop=-1,len; //IssueMessage(-1,V_PROPS,2, unsigned int i=4+str.ExtendedLen(4),firstID=str.ExtractExtended(4),IDs=str.ExtractByte(3),j; //IssueMessage(-1,V_IDS,3,firstID,firstID+IDs-1,IDs); uint maxID=firstID+IDs-1; if(propsRemain==0) IssueMessage(WARNING1,NO_PROPS); if(IDs==0&&(propsRemain!=1||feature||str.ExtractByte(i)!=0x1A)){ IssueMessage(WARNING1,NO_IDS); return; } feature!=8&&IDs&&CheckID(feature,firstID)&&CheckID(feature,maxID); Expanding0ArraypropLoc, idWidth; try{ while(propsRemain||_autocorrect){ try{ prop=str.ExtractByte(i); }catch(unsigned int){ if(propsRemain>0)IssueMessage(ERROR,INSUFFICIENT_PROPS,propsRemain); if(_autocorrect>=2||(_autocorrect&&propsRemain<3&&str.ExtractByte(2)-propsRemain>1)){ if(i>str.Length()){ i=propLoc[prop]; propsRemain++; } if(propsRemain){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,2,NUMINFO,str.ExtractByte(2),str.ExtractByte(2)-propsRemain); str.SetByteAt(2,str.ExtractByte(2)-propsRemain); } break; } return; } if(feature==8 && prop==9) CargoTransTable(IDs-1); len=_p[feature].GetData(prop); if(prop==8)// Mark prop 08 as set, if necessary. for(uint i=firstID;i<=maxID;i++) Prop08Tracking::Set(feature,i); if(len==0xFF){ IssueMessage(FATAL,INVALID_PROP,i,prop); if(_autocorrect){ if(propsRemain){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,2,NUMINFO,str.ExtractByte(2),str.ExtractByte(2)-propsRemain); str.SetByteAt(2,str.ExtractByte(2)-propsRemain); } break; } return; } if(feature==8){ if(firstID>_p[feature].maxfirst(prop)) IssueMessage(ERROR,INVALID_ID,firstID,0,_p[feature].maxfirst(prop)); if(IDs&&maxID>_p[feature].maxlast(prop)) IssueMessage(ERROR,INVALID_ID,maxID,0,_p[feature].maxlast(prop)); } if(propLoc[prop]&&!(len&0x80)) IssueMessage(WARNING2,REPEATED_PROP,i,prop,propLoc[prop]); propLoc[prop]=i++; if(len==0xFE){ const PropData*data=_p[feature].GetVarLength(prop); for(j=0;jstr.Length()) IssueMessage(ERROR,INSUFFICIENT_DATA2,i-str.Length(),prop); else{ if(i1||GetState(LINEBREAKS)==3)&&str.ExtractByte(2)>1; uint data; for(i=0;i1) str.AddBlank(str_loc-1); return true; } Check0::Check0(){ FILE*pFile=myfopen(0); _p=new PropData[MaxFeature()+1]; for(uint i=0;i<=MaxFeature();i++) _p[i].Init(pFile,i==8); fclose(pFile); } grfcodec-6.0.3/src/act0.h0000644000000000000000000000164712027143046013570 0ustar rootroot/* * act0.h * Contains declarations for checking action 0s. * * Copyright 2005 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_PROPERTIES_H_INCLUDED_ #define _RENUM_PROPERTIES_H_INCLUDED_ void Check0(const string&); #endif grfcodec-6.0.3/src/win32.h0000644000000000000000000000241212027143046013672 0ustar rootroot/* * win32.h * Windows specific stuff for NFORenum. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_WIN32_H_INCLUDED_ #define _RENUM_WIN32_H_INCLUDED_ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include #undef ERROR #define sleep(x) Sleep(x*1000) #if defined(_MSC_VER) && (_MSC_VER >= 1400) // mkdir is deprecated in MSVS 8.0+ inline int mkdir(const char*x,int){return _mkdir(x);} #else inline int mkdir(const char*x,int){return mkdir(x);} #endif //string GetOpt(char*); #endif//_WIN32 #endif//_RENUM_WIN32_H_INCLUDED_ grfcodec-6.0.3/src/act123.h0000644000000000000000000000747612027143046013744 0ustar rootroot/* * act123.h * Declares classes to support checking actions 1-3. * * Copyright 2004-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "singleton.h" #include "message_mgr.h" class PseudoSprite; struct act123{ void init(); uint MaxFoundFeat()const; class Act1{ public: Act1(){init();} void init(){spritenum=0;used.resize(0);} bool is_used(int set)const{return used[set];} void use(int set){used[set]=true;} unsigned int feature,numsets,spritenum; private: Expanding0Arrayused; }act1; class IDarray{ public: void init(){_m.resize(0);} bool is_defined(int id)const{return _m[id].sprite!=0;} bool is_used(int id)const{return _m[id].used;} unsigned short defined_at(int id)const{return _m[id].sprite;} void define(uint feature,unsigned int id,bool checks1C); bool checks1C(int id)const{return _m[id].v1C;} void use(int id){_m[id].used=true;} bool test(uint,uint)const; unsigned short GetFeature(uint id)const{return _m[id].feature;} friend uint act123::MaxFoundFeat()const; private: struct info{ info():used(false),v1C(false),sprite(0),feature((unsigned short)-1){} bool used,v1C; unsigned short sprite; unsigned short feature; }; ExpandingArray_m; }defined2IDs; uint act3feature,act3spritenum; SINGLETON(act123) }; class Check2v{ struct VarData{ VarData():width(0){} VarData(int x):width(x){} int Load(FILE*); uint min,max,width,maxparam; }; struct FeatData{ FeatData():var80(VarData(1)){} ExpandingArrayvars; ExpandingArrayvar80; uint last80,featfor82; }; public: void Check(uint,uint,uint,uint,uint)const; static uint GetMaxOp(){return Instance().maxop;} static uint Prohibit0Mask(uint); static uint GetEffFeature(uint,uint); bool IsValid(uint feature, uint var)const; SINGLETON(Check2v) private: ExpandingArrayglobvars; auto_array_p; uint maxop; uint MaxParam(uint feature, uint var)const; uint GetWidth(uint feature, uint var)const; }; class varRange{ private: struct range{ explicit range(uint max):min(0,max),max(max,max){} range(const range&right):min(right.min),max(right.max){} range(uint rangemax,uint minval,uint maxval):min(minval,rangemax),max(maxval,rangemax){} RangedUint min,max; }dflt; public: static const uint rangemax[]; explicit varRange(uint); void UpdateRange(uint var,uint op,uint shift,const PseudoSprite&data,uint&offs); void AddRange(uint min,uint max); void CheckDefault(); private: int num; uint width; vectorranges; void AddRangeInternal(uint min,uint max,RenumMessageId unreachable); }; class rand2{ private: struct rand2info{ uint bits[2],numtriggers; }; auto_array_p; public: void CheckRand(uint feat,uint type,uint triggers,uint first,uint nrand); SINGLETON(rand2); }; //An object of this class will check and define the given ID when it is destroyed. class Define2{ public: Define2(uint feat,uint id):feature(feat),id(id),checks1C(false){} ~Define2(); void Check(uint var){checks1C|=(var==0x1C);} void ChangeFeature(uint); private: uint feature,id; bool checks1C; }; class Callbacks:public auto_array{ public: uint numcallbacks; SINGLETON(Callbacks); }; grfcodec-6.0.3/src/pseudo_seq.cpp0000644000000000000000000000450712027143046015441 0ustar rootroot/* * pseudo_seq.cpp * Sequential access implementation for the PseudoSprite classes. * Separated due to preprocessor magic. * * Copyright 2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef INCLUDING #include #include "nforenum.h" #include "pseudo.h" #define INCLUDING #define FOR_CLASS Byte #define WIDTH(x) 1 #include "pseudo_seq.cpp" #define FOR_CLASS ExtByte #define EXTRACT Extended #define WIDTH(x) ExtendedLen(x) #include "pseudo_seq.cpp" #define FOR_CLASS Word #define WIDTH(x) 2 #include "pseudo_seq.cpp" #define FOR_CLASS Dword #define WIDTH(x) 4 #include "pseudo_seq.cpp" #undef INCLUDING uint PseudoSprite::BytesRemaining() const { return (uint)packed.length() - extract_offs; } PseudoSprite& PseudoSprite::seek(uint off) { extract_offs = off; return *this; } PseudoSprite::Byte& PseudoSprite::Byte::set(uint u) { p->SetByteAt(offs, u); return *this; } PseudoSprite::Word& PseudoSprite::Word::set(uint u) { p->SetByteAt(offs, u&0xFF); p->SetByteAt(offs, u>>8); return *this; } #else // INCLUDING #ifndef EXTRACT # define EXTRACT FOR_CLASS #endif PseudoSprite::FOR_CLASS::FOR_CLASS() : p(NULL) {} uint PseudoSprite::FOR_CLASS::val() const { return p->BOOST_PP_CAT(Extract, EXTRACT(offs)); } uint PseudoSprite::FOR_CLASS::loc() const { return offs; } PseudoSprite& PseudoSprite::operator >>(PseudoSprite::FOR_CLASS& b) { b.p = this; b.offs = extract_offs; extract_offs += WIDTH(extract_offs); return *this; } PseudoSprite& PseudoSprite::Extract(PseudoSprite::FOR_CLASS& b, uint off) { b.p = this; b.offs = off; return *this; } #undef FOR_CLASS #undef EXTRACT #undef WIDTH #endif //INCLUDING grfcodec-6.0.3/src/command.cpp0000644000000000000000000004520612027143046014711 0ustar rootroot/* * command.cpp * Defines functions for comment commands. * * Copyright 2004-2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #ifdef _MSC_VER # pragma warning(disable:4702)//unreachable code # include # pragma warning(default:4702) #else # include #endif #include #include using namespace std; #include"globals.h" #include"nforenum.h" #include"command.h" #include"inlines.h" #include"sanity.h" #include"messages.h" #include"inject.h" #include"sanity_defines.h" #include"data.h" #include"ExpandingArray.h" #define CASE(_case,_return)\ case _case:return _commandState._return; struct commandData{ const char*name; int value; }; #undef _RENUM_COMMAND_H_INCLUDED_ #undef COMMAND_DATA_START #undef COMMAND_DATA #undef COMMAND_DATA_EX #undef COMMAND_DATA_END #define COMMAND_DATA_START(x) const commandData x[]={ #define COMMAND_DATA(x) {#x,x}, #define COMMAND_DATA_EX(val,name) {#name,val}, #define COMMAND_DATA_END() {NULL,-1}}; #include "command.h" struct command{ command(); uint sanity_messages;//,verbose; int real:2; bool remove_messages,beautifier,diff,locked,useoldnums; //7..0: MAXLEN //8: QuoteHighAscii //9: QuoteUTF8 //10: HexGRFID //12..11: Linebreaks //13: UseEscape //14: Unused //15: Unused //20..16, 25..21, 30..26: Leading space 1,2,3 //31: CONVERTONLY uint beauty; Expanding0Arraywarnstate; }_commandState,_CLstate; static map_varmap,_CLvar; const command&crCommandState=_commandState; command::command(){ remove_messages=true; beautifier=diff=locked=false; sanity_messages=WARNING3; real=0; beauty=686039958; // verbose=0; } int find_command(const string&command,const commandData type[]){ for(int i=0;;i++){ if(type[i].name==NULL)return -1; if(UCase(command)==type[i].name)return type[i].value; } } bool is_command(const string&line){ assert(is_comment(line)); string::size_type x=line.find_first_not_of(COMMENT+WHITESPACE); return x!=string::npos&&x<(line.length()-1)&&line[x]=='@'&&line[x+1]=='@'; } bool is_message(const string&line){ assert(is_comment(line)); string::size_type x=line.find_first_not_of(COMMENT+WHITESPACE); return x!=string::npos&&x<(line.length()-1)&&line[x]=='!'&&line[x+1]=='!'; } void reset_commands(){ _commandState=_CLstate; _varmap=_CLvar; } string GetOnOffString(string str){ if(str[str.length()-1]=='+'){ str[str.length()-1]=' '; str+="ON"; }else if(str[str.length()-1]=='-'){ str[str.length()-1]=' '; str+="OFF"; } return str; } bool CLCommand(int command){ bool locked=_commandState.locked; _commandState.locked=false; switch(command){ case'd':parse_comment("//@@DIFF");break; case'L':parse_comment("//@@LET "+string(optarg));break; case'l':parse_comment("//@@LINT "+GetOnOffString(optarg));break; case'r':parse_comment("//@@REALSPRITES "+string(optarg));break; case'b':parse_comment("//@@BEAUTIFY "+GetOnOffString(optarg));break; case'p':_commandState.remove_messages=false;break; case'e':parse_comment("//@@EXTENTIONS "+GetOnOffString(optarg));break; case'o':parse_comment("//@@USEOLDSPRITENUMS "+GetOnOffString(optarg));break; case 256:locked=true;break; case'w':case'W':{ string s(optarg); if (s.find_first_not_of("0123456789,") != NPOS) return false; string::size_type loc; while ( (loc=s.find_first_of(',')) != NPOS) s[loc]='+'; istringstream arg(s); uint opt; while(arg>>opt){ parse_comment((command=='w'?"//@@WARNING DISABLE ":"//@@WARNING ENABLE ")+itoa(opt)); arg.ignore(); } break; }DEFAULT(command) } _commandState.locked=locked; _CLstate=_commandState; _CLvar=_varmap; return true; } void SetVar(const string&,const string&); string ReadVar(istream&); bool parse_comment(const string&line){ assert(is_comment(line)); if(is_message(line)) return!GetState(REMOVEMESSAGES); if(!is_command(line)) return true; string command=line.c_str()+line.find_first_not_of(COMMENT+WHITESPACE+'@'),command_part; while(command.find('=')!=NPOS)command[command.find('=')]=' '; istringstream commandstream(command); commandstream>>command_part; int id; switch(find_command(command_part,gen)){ case REMOVEMESSAGES: _commandState.remove_messages=true; break; case PRESERVEMESSAGES: _commandState.remove_messages=false; break; case LINT: if(commandstream>>command_part){ if(GetState(LINT)!=OFF){ int x=find_command(command_part,san); _commandState.sanity_messages=(x==-1?WARNING3:x); } break; } return true; case USEID2:{ int feature; commandstream>>setbase(16)>>feature>>id; if(!commandstream) id=feature; else if(!IsValid2Feature(feature)){ IssueMessage(0,COMMAND_INVALID_ARG,gen[USEID2].name); return true; }else{ inject(mysprintf("%t@@USEID2 %2x",COMMENT_PREFIX,id)); return false; } sanity_use_id(id); return true; }case USESET: commandstream>>setbase(16)>>id; sanity_use_set(id); return true; case DIFF: _commandState.diff=_commandState.remove_messages=true; _commandState.sanity_messages=OFF; if(_commandState.locked)_commandState=_CLstate; return false; case WARNING:{ commandstream>>command_part; int num=0,state=find_command(command_part,warn); commandstream>>num; if(state==-1){ IssueMessage(0,COMMAND_UNKNOWN,command_part.c_str()); IssueMessage(0,COMMAND_REVERT_DEFAULT); } _commandState.warnstate[num]=state; break; }case VERSIONCHECK:{ commandstream>>command_part; int ver; if(command_part.length()==8&&command_part.find_first_not_of(VALID_PSEUDO)==NPOS) ver=ctoi(command_part[0])<<28|ctoi(command_part[1])<<24|ctoi(command_part[2])<<20|ctoi(command_part[3])<<16| ctoi(command_part[4])<<12|ctoi(command_part[5])<<8|ctoi(command_part[6])<<4|ctoi(command_part[7]); else{ uint M,m,r,b; if(sscanf(command_part.c_str(),"%u.%u.%u.%u",&M,&m,&r,&b)==4&&M<256&&m<16&&r<16&&b<65536) ver=M<<24|m<<20|r<<16|b; else if((sscanf(command_part.c_str(),"201a%u",&b)==1||sscanf(command_part.c_str(),"2.0.1a%u",&b)==1)&&b<6553) ver=0x020A0000|(b*10); else if((sscanf(command_part.c_str(),"25b%u",&b)==1||sscanf(command_part.c_str(),"2.5b%u",&b)==1)){ if(b<6)ver=0x02500000|(b*10); else{ FILE*pFile=myfopen(versions); uint maxVer=fgetc(pFile); if(b<=maxVer){ int r=0; for(b-=5;b;b--) r=GetCheckWord(versions); ver=0x02500000|r; }else{ IssueMessage(0,COMMAND_UNKNOWN_VERSION,gen[VERSIONCHECK].name); fclose(pFile); return true; } fclose(pFile); } }else if((sscanf(command_part.c_str(),"2%ur%x",&m,&b)==2||sscanf(command_part.c_str(),"2.%ur%x",&m,&b)==2)&&m<16&&b>417&&b<0x10000) ver=0x02000000|(m<<20)|b; else{ IssueMessage(0,COMMAND_INVALID_ARG,gen[VERSIONCHECK].name); return true; } } if(!getline(commandstream,command_part)){ IssueMessage(0,COMMAND_INVALID_ARG,gen[VERSIONCHECK].name); return true; } inject(mysprintf("0*0 09 8B 04 05 %8x 01",ver-1)); inject(mysprintf("0*0 0B 03 1F 00%t 00",command_part.c_str())); //inject("//@@PRESERVEMESSAGES NOPRESERVE"); inject(mysprintf("0*0 09 8B 04 04 %8x 00"/* %t!! MOVE ME AFTER THE ACTION 8 !!"*/,ver,COMMENT_PREFIX)); //if(GetState(REMOVEMESSAGES))inject("//@@REMOVEMESSAGES NOPRESERVE"); return false; }case LET:{ string var=ReadVar(commandstream); if(var=="")return true; if(eat_white(commandstream).peek()=='=')commandstream.ignore(); getline(eat_white(commandstream),command_part); if(!_commandState.locked)SetVar(var,command_part); return true; }case REALSPRITES: commandstream>>command_part; switch(find_command(command_part,real)){ case RPNON:_commandState.real&=~1;break; case RPNOFF:_commandState.real|=3;break;//Yes, 3. RPNOFF also sets COMMENTOFF. case COMMENTON:_commandState.real&=~2;break; case COMMENTOFF:_commandState.real|=2;break; case-1:IssueMessage(0,COMMAND_INVALID_ARG,gen[REAL].name);return true; default: INTERNAL_ERROR(command,find_command(command_part,real)); } break; case BEAUTIFY:{ commandstream>>command_part; uint val=find_command(command_part,beaut),togglebit; if(val!=(uint)-1&&val!=OFF)_commandState.beautifier=true; switch(val){ case -1: IssueMessage(0,COMMAND_INVALID_ARG,gen[BEAUTIFY].name); return true; case OFF:_commandState.beautifier=false;break; case ON:break; case MAXLEN: if(!(commandstream>>val)||val>255){ IssueMessage(0,COMMAND_INVALID_ARG,gen[BEAUTIFY].name); commandstream.ignore(INT_MAX); return true; } _commandState.beauty=(_commandState.beauty&~0xFF)|val; break; case QUOTEHIGHASCII: togglebit = 0x100; goto dotoggle; case QUOTEUTF8: togglebit = 0x200; goto dotoggle; case HEXGRFID: togglebit = 0x400; goto dotoggle; case LEADINGSPACE:{ commandstream>>command_part; uint lead[3]={0,0,0}; int count=sscanf(command_part.c_str(),"%u,%u,%u",lead,lead+1,lead+2); if(lead[0]==0)lead[0]=GetState(LEADINGSPACE); if(lead[1]==0)lead[1]=GetState(LEADINGSPACE,1); if(lead[2]==0)lead[2]=GetState(LEADINGSPACE,2); while(count&&count!=3){ lead[count]=lead[count-1]+3; count++; } if(lead[0]>32||lead[1]>32||lead[2]>32){ IssueMessage(0,COMMAND_INVALID_ARG,gen[BEAUTIFY].name); return true; } _commandState.beauty=(_commandState.beauty&~0x7FFF0000)|((lead[0]-1)<<16)|((lead[1]-1)<<21)|((lead[2]-1)<<26); break; }case LINEBREAKS:{ uint breaks=4; commandstream>>breaks; if(breaks>3){ IssueMessage(0,COMMAND_INVALID_ARG,gen[BEAUTIFY].name); return true; } _commandState.beauty&=~0x1800; _commandState.beauty|=((breaks+2)&3)<<11; break; }case CONVERTONLY:{ togglebit = 0x80000000; goto dotoggle; }case GETCOOKIE: inject(mysprintf("%t@@BEAUTIFY SETCOOKIE %d",COMMENT_PREFIX,_commandState.beauty)); return false; case SETCOOKIE: if(!(commandstream>>_commandState.beauty)){ IssueMessage(0,COMMAND_INVALID_ARG,gen[BEAUTIFY].name); return true; } break; case USEESCAPES: togglebit = 0x2000; goto dotoggle; default: INTERNAL_ERROR(command,find_command(command_part,beaut)); dotoggle: commandstream>>command_part; val=find_command(command_part,beaut); if(!commandstream||val==(uint)-1){ IssueMessage(0,COMMAND_INVALID_ARG,gen[BEAUTIFY].name); return true; } if(val==OFF)_commandState.beauty&=~togglebit; else _commandState.beauty|=togglebit; } commandstream>>command_part; if(_commandState.locked)_commandState=_CLstate; return find_command(command_part,preserve)!=NOPRESERVE; }case CLEARACTION2: final123(); Init123(); AutoConsoleMessages();//final123 calls ManualConsoleMessages(); break; case CLEARACTIONF: finalF(); InitF(); AutoConsoleMessages();//finalF calls ManualConsoleMessages(); break; case TESTID2:{ int feature; commandstream>>setbase(16)>>feature>>id; if(!commandstream) id=feature; else if(!IsValid2Feature(feature)){ IssueMessage(0,COMMAND_INVALID_ARG,gen[TESTID2].name); return true; }else{ inject(mysprintf("%t@@TESTID2 %2x",COMMENT_PREFIX,id)); return false; } sanity_test_id(id); return true; }case DEFINEID2:{ int feature; commandstream>>setbase(16)>>feature>>id; if(!commandstream) id=feature; else if(!IsValid2Feature(feature)){ IssueMessage(0,COMMAND_INVALID_ARG,gen[DEFINEID2].name); return true; } sanity_define_id(feature,id); return true; }case LOCATEID2:{ int feature; commandstream>>setbase(16)>>feature>>id; if(!commandstream) id=feature; else if(!IsValid2Feature(feature)){ IssueMessage(0,COMMAND_INVALID_ARG,gen[LOCATEID2].name); return true; }else{ inject(mysprintf("%t@@LOCATEID2 %2x",COMMENT_PREFIX,id)); return false; } inject("//@@PRESERVEMESSAGES NOPRESERVE"); inject(mysprintf("//!!LOCATEID2 %2x %2x: %d",sanity_get_feature(id),id,sanity_locate_id(id))); if(GetState(REMOVEMESSAGES))inject("//@@REMOVEMESSAGES NOPRESERVE"); break; }case USEOLDSPRITENUMS: commandstream>>command_part; if(!commandstream)return true; id=find_command(command_part,ext); if(id==ON)_commandState.useoldnums=true; else if(id==OFF)_commandState.useoldnums=false; else{ IssueMessage(0,COMMAND_INVALID_ARG,gen[USEOLDSPRITENUMS].name); return true; } break; /*case VERBOSE:{ uint level; if(!(commandstream>>level)||level>2){ IssueMessage(0,COMMAND_INVALID_ARG,gen[VERBOSE].name); return true; } _commandState.verbose=level; break; }*/ /* Add case condition for new comment commands here. * The order in this function should be the same as the order in command.h. */ case -1: IssueMessage(0,COMMAND_UNKNOWN,command_part.c_str()); return true; default: INTERNAL_ERROR(find_command(command_part,gen),find_command(command_part,gen)); } commandstream>>command_part; if(_commandState.locked)_commandState=_CLstate; return find_command(command_part,preserve)!=NOPRESERVE; } int GetState(enum gen type){ switch(type){ CASE(REMOVEMESSAGES,remove_messages); CASE(LINT,sanity_messages); CASE(DIFF,diff); CASE(REALSPRITES,real); CASE(BEAUTIFY,beautifier); CASE(USEOLDSPRITENUMS,useoldnums); // CASE(VERBOSE,verbose); /* Add CASE(COMMAND,variable) macros for new comment commands here. * The order in this function should be the same as the order in command.h.*/ DEFAULT(type); } } uint GetState(enum beaut type,int arg){ const uint&beaut=_commandState.beauty; switch(type){ case MAXLEN:return beaut&0xFF; case LEADINGSPACE: return(beaut>>(16+5*arg))&0x1F; case QUOTEHIGHASCII:return beaut&0x100; case QUOTEUTF8:return beaut&0x200; case HEXGRFID:return beaut&0x400; case LINEBREAKS:return(((beaut&0x1800)>>11)+2)&3; case USEESCAPES:return beaut&0x2000; case CONVERTONLY:return beaut&0x80000000; DEFAULT(type); } } #undef MESSAGE #undef START_MESSAGES #undef END_MESSAGES #undef MESSAGE_EX #define MESSAGE(name,message,props)name, #define START_MESSAGES(lang) int msg_type[]={ #define END_MESSAGES() }; #define MESSAGE_EX(name,msg,props,loc,base) base, #include "lang/message_english.h" bool GetWarn(int message,int minSan){ message=msg_type[message]; switch(crCommandState.warnstate[message]){ case ENABLE:return true; case DISABLE:if(minSan>=ERROR)return false; } return GetState(LINT)>=minSan; } void SetVar(const string&var,const string&value){ int val; string::size_type offs; if((offs=value.find('('))==NPOS){ const char*pch=value.c_str(); while(isspace(*pch))pch++; val=atoi(pch); }else{ val=DoCalc(value,offs); if(offs==NPOS)return; } _varmap[var] = val; } int GetVar(const string&var,int&err){ map::const_iterator it; if((it=_varmap.find(var))!=_varmap.end())return it->second; IssueMessage(0,(RenumMessageId)(err=UNDEF_VAR),var.c_str()); SetCode(EPARSE); return 0; } string ReadVar(istream&in){ eat_white(in); int ch; string delim="=()+/-*",var; while(!isspace(ch=in.get())&&delim.find((char)ch)==NPOS&&ch!=EOF)var+=(char)ch; if(ch==EOF)var=""; else in.unget(); return var; } int ReadNum(istream&in){ if (in.get()=='0') { if (in.get()=='x') in>>setbase(16); else{ in.unget()>>setbase(8); if (!isdigit(in.peek())) return 0; } } else in.unget()>>setbase(10); int ret; in>>ret; return ret; } int DoCalc(istream&data,int&err){ stacknums; // the unary and binary op charcters. string unyops="-~)", binops="+-*/%|&^<>"; int ch,l; while(true){ ch=eat_white(data).get(); if(isdigit(ch)){ data.unget(); nums.push(ReadNum(data)); continue; } if(ch == '-'){ // a minus followed immediately by digits is a negative number if(isdigit(data.peek())){ nums.push(-ReadNum(data)); continue; } } if(unyops.find((char)ch)!=NPOS){ if(nums.size()<1){ IssueMessage(0,(RenumMessageId)(err=BAD_RPN),ch); return 0; } l = nums.top(); switch(ch){ case '~': nums.top() = ~l; continue; case ')': return l; case '-': if (data.peek() == '-'){ data.ignore(); nums.top() = -l; continue; } break; DEFAULT(ch); } } if(binops.find((char)ch)!=NPOS){ if(nums.size()<2){ IssueMessage(0,(RenumMessageId)(err=BAD_RPN),ch); return 0; } int r; r=nums.top(); nums.pop(); l=nums.top(); switch(ch){ case'+':nums.top()=l+r;break; case'-':nums.top()=l-r;break; case'*':nums.top()=l*r;break; case'/':nums.top()=l/r;break; case'%':nums.top()=l%r;break; case'^':nums.top()=l^r;break; case'&':nums.top()=l&r;break; case'|':nums.top()=l|r;break; case'<': if(data.get()=='<'){ nums.top()=l<': if(data.get()=='>'){ nums.top()=l>>r; break; }else{ IssueMessage(0,(RenumMessageId)(err=BAD_RPN),ch); return 0; } DEFAULT(ch); } }else if(ch==EOF){ IssueMessage(0,(RenumMessageId)(err=BAD_RPN_EOF)); return 0; }else{ data.unget(); // And now, restore first character of the var name. string var=ReadVar(data); nums.push(GetVar(var,err)); if(err)return 0; } } } int DoCalc(const string&data,string::size_type&offs){ istringstream in(data); in.ignore((int)offs+1); int err=0,ret=DoCalc(in,err); offs=err?NPOS:data.find(')',offs)+1; return ret; } /*int DoCalc(istringstream&data,int&err){ char ch=eat_white(data).peek(); int l,r,op; if(isdigit(ch))data>>l; else if(ch=='('){ l=DoCalc(data.ignore(),err); if(err)return l; }else{ string var; data>>var; l=GetVar(var,err); if(err)return l; } eat_white(data).get(ch); if(ch==')')return l; string ops="+-*" "/"; int op=(int)ops.find(ch); if(op==NPOS){ err=NOT_OP; return ch; } if(isdigit(ch))data>>r; else if(ch=='('){ r=DoCalc(data.ignore(),err); if(err)return r; }else{ string var; data>>var; r=GetVar(var,err); if(err)return r; } switch(op){ case 0:return l+r; case 1:return l-r; case 2:return l*r; case 3:return l/r; DEFAULT(DoCalc,op); } } int DoCalc(const string&data,size_t&offs){ char ch; int l=0,r=0,op=0; while(true){ if(isspace(ch=data[offs++]))continue; if(ch=='(')(op?r:l)=DoCalc(data,offs); else if(ops.find(ch)!=NPOS)op=ops.find(ch)+1; else if(ch>='0'&&ch<='9'){ (op?r:l)*=10; (op?r:l)+=ch-'0'; }else if(ch==')') }*/ grfcodec-6.0.3/src/grfmrg.h0000644000000000000000000000021412027143046014212 0ustar rootroot#ifndef _GRFMRG_H #define _GRFMRG_H extern const char grfmrg[]; extern const U32 grfmrgsize; extern U32 grfmrgcrc; #endif /* _GRFMRG_H */ grfcodec-6.0.3/src/data.cpp0000644000000000000000000012210112171043637014177 0ustar rootroot/* * data.cpp * Data file contents and implementation of helper functions. * * Copyright 2005-2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef _WIN32 #include"win32.h" #endif #include #include #include #include #include #include #include #ifndef _WIN32 # include #endif using namespace std; #include"nforenum.h" #include"inlines.h" #include"globals.h" #include"data.h" #include"messages.h" #include"win32.h" #include"sanity_defines.h" #include"strings.h" //Let's dump the data files into the source code. That sounds like fun, right? /* Data file format ================ Files that appear before the DATA_FILE(feat) line in data.h have two leading bytes that are checked and then eaten by myfopen. The first byte is a format byte; start it at \x00. Each time the file format gets updated (ie the file reader changes), increment it and reset the version byte to \x00. The second byte is a version byte; increment it every time the file gets updated. Files that depend on feat.dat (appear below it in data.h), have three leading bytes that are eaten by myfopen. The first two are as described above. The third byte is the maximum feature supported by this file. This should usually match the third byte of _datfeat, but under some circumstances, it is appropriate to increment the this byte without changing _datfeat. */ #define NDF_HEADER(format, version) format, version #define NDF_END 0 // --------------------------------------------------------------------------- // ------------------------- Feature-independent data ------------------------ // --------------------------------------------------------------------------- /* Action 7/9/D variables */ #define NOTHING 0x00 /* Only VarAction2 access */ #define BITMASK 0x00 /* Bitmask variable, use instead of B, W or D */ #define B 0x01 /* Byte access allowed */ #define W 0x02 /* Word access allowed */ #define D 0x04 /* DWord access allowed */ #define WD 0x20 /* Action D Write access allowed */ #define RD 0x40 /* Action D Read access allowed */ #define R7 0x80 /* Action 7 Read access allowed */ static const unsigned char _dat79Dv[]={ NDF_HEADER(0x20, 5), /* Number of variables: */ 0x25, /*80*/ NOTHING, /*81*/ B | RD | R7, /*82*/ NOTHING, /*83*/ B | RD | R7, /*84*/ B | D | RD | R7, /*85*/ BITMASK | R7, /*86*/ BITMASK | R7, /*87*/ NOTHING, /*88*/ D | R7, /*89*/ NOTHING, /*8A*/ NOTHING, /*8B*/ W | D | RD | R7, /*8C*/ NOTHING, /*8D*/ B | RD | R7, /*8E*/ B | WD | RD | R7, /*8F*/ D | WD | RD | R7, /*90*/ NOTHING, /*91*/ NOTHING, /*92*/ B | RD | R7, /*93*/ W | D | WD | RD | R7, /*94*/ W | D | WD | RD | R7, /*95*/ W | D | WD | RD | R7, /*96*/ W | D | WD | RD | R7, /*97*/ B | WD | RD | R7, /*98*/ NOTHING, /*99*/ D | WD, /*9A*/ B | W | D | R7, /*9B*/ NOTHING, /*9C*/ NOTHING, /*9D*/ D | RD | R7, /*9E*/ D | WD | RD | R7, /*9F*/ D | WD, /*A0*/ NOTHING, /*A1*/ D | RD | R7, /*A2*/ D | RD | R7, /*A3*/ D | RD | R7, /*A4*/ D | RD | R7, NDF_END }; #undef B #undef W #undef D #undef WD #undef RD #undef R7 /* Action B ======== */ static const char _datB[]="\x01\x02" // Maximum severity: "\x03" // Number of message types: "\x07" // Parameter counts for message types: "\x02\x02\x02\x03\x02\x02\x02" ; /* Action 5 * Historical remark: * The higher nibble in the OPTIONS byte can be used to define the type and alternatives for multiple entries. * We do not use that anymore, as we want one line per entry. */ #define OPTIONS(num) 0x10 | num /* Number of alternatives wrt. total sprite count */ #define RECOLOUR 0x81 /* Only allow recolour sprites */ #define MIXED 0x82 /* Allow both recolour and real sprites */ #define WORD 0x84 /* Spritecount is larger than a byte and is defined using W() */ #define OFFSET 0x88 /* Allow replacing sprite ranges with offsets */ #define W(cnt) cnt & 0xFF, cnt >> 8 /* Construct word count */ static const unsigned char _dat5[]={ NDF_HEADER(0x04, 15), /*04*/ OFFSET, OPTIONS(3), 0x30, 0x70, 0xF0, /*05*/ OFFSET, OPTIONS(1), 0x30, /*06*/ OFFSET, OPTIONS(2), 0x4A, 0x5A, /*07*/ OPTIONS(1), 0x5D, /*08*/ OFFSET, OPTIONS(1), 0x41, /*09*/ OFFSET, OPTIONS(1), 0x06, /*0A*/ OFFSET | RECOLOUR | WORD, OPTIONS(1), W(0x100), /*0B*/ OFFSET, OPTIONS(1), 0x71, /*0C*/ OPTIONS(1), 0x85, /*0D*/ OPTIONS(2), 0x10, 0x12, /*0E*/ MIXED, OPTIONS(1), 0x00, /*0F*/ OFFSET, OPTIONS(1), 0x0C, /*10*/ OFFSET, OPTIONS(1), 0x0F, /*11*/ OFFSET, OPTIONS(1), 0x08, /*12*/ OFFSET, OPTIONS(1), 0x08, /*13*/ OFFSET, OPTIONS(1), 0x37, /*14*/ OFFSET, OPTIONS(1), 0x24, /*15*/ OFFSET, OPTIONS(1), 0xAE, /*16*/ OFFSET, OPTIONS(1), 0x09, /*17*/ OFFSET, OPTIONS(1), 0x10, 00, NDF_END }; #undef OPTIONS #undef RECOLOUR #undef MIXED #undef WORD #undef OFFSET #undef W /* Text IDs ======== */ static const char _datTextIDs[]="\x04\x09" //-0000- -1000- -2000- -3000- "\x35\x03\x11\x00\x25\x00\x19\x00\x5D\x00\x11\x00\x6D\x00\x08\x00" //-4000- -5000- -6000- -7000- "\x11\x00\x3C\x00\x2A\x00\x08\x00\x19\x00\x39\x00\x80\x00\x00\x00" //-8000- -9000- -A000- -B000- "\x08\x01\x6C\x00\x38\x00\x43\x00\x44\x00\x00\x00\x06\x00\x00\x00" //-C000- -D000- -E000- -F000- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x4D\x00\x00\x00\x00\x00\x9B\x01" // Number of special string ID ranges: "\x03" // High bytes of special string IDs: "\xC4\xC5\xC9" ; /* Callbacks */ #define W(cnt) cnt & 0xFF, cnt >> 8 /* Construct word count */ #define TRAIN 0x0 #define ROADVEH 0x1 #define SHIP 0x2 #define AIRCRAFT 0x3 #define STATION 0x4 #define CANAL 0x5 #define BRIDGE 0x6 #define HOUSE 0x7 #define GLOBAL 0x8 #define INDTILE 0x9 #define INDUSTRY 0xA #define CARGO 0xB #define SOUND 0xC #define AIRPORT 0xD #define SIGNAL 0xE #define OBJECT 0xF #define RAILTYPE 0x10 #define AIRTILE 0x11 #define MASK(f) 0x80 | (1 << f) #define NONE 0x80 #define GROUNDVEHICLE MASK(TRAIN) | MASK(ROADVEH) #define VEHICLE MASK(TRAIN) | MASK(ROADVEH) | MASK(SHIP) | MASK(AIRCRAFT) static const unsigned char _datcallbacks[]={ NDF_HEADER(0x05, 23), /* Count: */ W(0x160), /* 00*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 10*/ GROUNDVEHICLE | MASK(SHIP), GROUNDVEHICLE, VEHICLE, STATION, STATION, VEHICLE, GROUNDVEHICLE, HOUSE, /* 18*/ MASK(STATION) | VEHICLE, VEHICLE, HOUSE, HOUSE, HOUSE, TRAIN, HOUSE, HOUSE, /* 20*/ HOUSE, HOUSE, INDUSTRY, VEHICLE, STATION, INDTILE, INDTILE, INDTILE, /* 28*/ INDUSTRY, INDUSTRY, HOUSE, INDTILE, INDTILE, VEHICLE, HOUSE, INDTILE, /* 30*/ INDTILE, VEHICLE, VEHICLE, MASK(BRIDGE) | VEHICLE, VEHICLE, INDUSTRY, VEHICLE, INDUSTRY, /* 38*/ INDUSTRY, CARGO, INDUSTRY, INDUSTRY, INDTILE, INDUSTRY, NONE, NONE, /* 40*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 50*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 60*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 70*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 80*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* 90*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* A0*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* B0*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* C0*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* D0*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* E0*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /* F0*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /*100*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /*110*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /*120*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /*130*/ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, /*140*/ STATION, STATION, STATION, HOUSE, SOUND, CARGO, SIGNAL, CANAL, /*148*/ HOUSE, STATION, INDUSTRY, INDUSTRY, INDUSTRY, HOUSE, HOUSE, HOUSE, /*150*/ AIRTILE, NONE, AIRTILE, AIRTILE, AIRTILE, AIRPORT, AIRPORT, OBJECT, /*158*/ OBJECT, OBJECT, OBJECT, OBJECT, OBJECT, OBJECT, VEHICLE, INDUSTRY, NDF_END }; #undef W #undef TRAIN #undef ROADVEH #undef SHIP #undef AIRCRAFT #undef STATION #undef CANAL #undef BRIDGE #undef HOUSE #undef GLOBAL #undef INDTILE #undef INDUSTRY #undef CARGO #undef SOUND #undef AIRPORT #undef SIGNAL #undef OBJECT #undef RAILTYPE #undef AIRTILE #undef MASK #undef NONE #undef GROUNDVEHICLE #undef VEHICLE /* Languages * ======== * * Names of languages by ID (empty if not defined), each terminated by newline */ static const char _datlangs[]="\x00\x07" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*0x*/ "American\n" "English\n" "German\n" "French\n" /*0x*/ "Spanish\n" "Esperanto\n" "Ido\n" "Russian\n" /*0x*/ "Irish\n" "Maltese\n" "Tamil\n" "Chuvash\n" /*0x*/ "Chinese (Traditional)\n" "Serbian\n" "Norwegian (Nynorsk)\n" "Welsh\n" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*1x*/ "Belarusian\n" "Marathi\n" "Faroese\n" "Scottish Gaelic\n" /*1x*/ "Arabic (Egypt)\n" "Czech\n" "Slovak\n" "\n" /*1x*/ "Bulgarian\n" "\n" "\n" "Afrikaans\n" /*1x*/ "\n" "\n" "Greek\n" "Dutch\n" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*2x*/ "\n" "Basque\n" "Catalan\n" "Luxembourgish\n" /*2x*/ "Hungarian\n" "\n" "Macedonian\n" "Italian\n" /*2x*/ "Romanian\n" "Icelandic\n" "Latvian\n" "Lithuanian\n" /*2x*/ "Slovenian\n" "Danish\n" "Swedish\n" "Norwegian (Bokmal)\n" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*3x*/ "Polish\n" "Galician\n" "Frisian\n" "Ukrainian\n" /*3x*/ "Estonian\n" "Finnish\n" "Portuguese\n" "Brazilian Portuguese\n" /*3x*/ "Croatian\n" "Japanese\n" "Korean\n" "\n" /*3x*/ "Malay\n" "Australian\n" "Turkish\n" "\n" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*4x*/ "\n" "\n" "Thai\n" "\n" /*4x*/ "\n" "\n" "\n" "\n" /*4x*/ "\n" "\n" "\n" "\n" /*4x*/ "\n" "\n" "\n" "\n" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*5x*/ "\n" "\n" "\n" "\n" /*5x*/ "Vietnamese\n" "\n" "Chinese (Simplified)\n" "\n" /*5x*/ "\n" "\n" "Indonesian\n" "\n" /*5x*/ "Urdu\n" "\n" "\n" "\n" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*6x*/ "\n" "Hebrew\n" "Persian\n" "\n" /*6x*/ "\n" "\n" "\n" "\n" /*6x*/ "\n" "\n" "\n" "\n" /*6x*/ "\n" "\n" "\n" "\n" // x0/x4/x8/xC x1/x5/x9/xD x2/x6/xA/xE x3/x7/xB/xF /*7x*/ "\n" "\n" "\n" "\n" /*7x*/ "\n" "\n" "\n" "\n" /*7x*/ "\n" "\n" "\n" "\n" /*7x*/ "\n" "\n" "\n" "any\n" ; /* Version check data ================== */ static const char _datversions[]="\x00\x04" // Maximum version (beta): "\x09" // Revisions (starting from beta 6) "\xD8\x01" "\x31\x06" "\x81\x07" "\x70\x11" ; /* Features */ #define ACT0 0x01 #define ACT1 0x02 #define ACT3 0x04 #define ACT4 0x08 #define EMPTY1 0x10 #define OVERRIDE3 0x20 #define GENERIC3 0x40 #define ACT3_BEFORE_PROP08 0x80 #define ACT2_VEHICLE 0x00 #define ACT2_STATION 0x01 #define ACT2_CARGO 0x02 #define ACT2_HOUSE 0x03 #define ACT2_INDPROD 0x04 #define ACT2_NONE 0xFF static const unsigned char _datfeat[]={ NDF_HEADER(0x12, 3), /* Max. feature: */ 0x11, /*00*/ ACT0 | ACT1 | ACT3 | ACT4 | EMPTY1 | OVERRIDE3 | GENERIC3 | ACT3_BEFORE_PROP08, /*01*/ ACT0 | ACT1 | ACT3 | ACT4 | EMPTY1 | GENERIC3 | ACT3_BEFORE_PROP08, /*02*/ ACT0 | ACT1 | ACT3 | ACT4 | EMPTY1 | GENERIC3 | ACT3_BEFORE_PROP08, /*03*/ ACT0 | ACT1 | ACT3 | ACT4 | EMPTY1 | OVERRIDE3 | GENERIC3 | ACT3_BEFORE_PROP08, /*04*/ ACT0 | ACT1 | ACT3 | ACT4 | EMPTY1 | GENERIC3, /*05*/ ACT0 | ACT1 | ACT3 | ACT4 | ACT3_BEFORE_PROP08, /*06*/ ACT0 | ACT4 | EMPTY1 | GENERIC3 | ACT3_BEFORE_PROP08, /*07*/ ACT0 | ACT1 | ACT3 | ACT4, /*08*/ ACT0, /*09*/ ACT0 | ACT1 | ACT3 | ACT4, /*0A*/ ACT0 | ACT3 | ACT4, /*0B*/ ACT0 | ACT1 | ACT3 | ACT4 | ACT3_BEFORE_PROP08, /*0C*/ ACT0, /*0D*/ ACT0 | ACT1 | ACT3 | ACT4, /*0E*/ EMPTY1 | GENERIC3, /*0F*/ ACT0 | ACT1 | ACT3 | ACT4, /*10*/ ACT0 | ACT1 | ACT3 | ACT4, /*11*/ ACT0 | ACT1 | ACT3 | ACT4, /*00*/ ACT2_VEHICLE, /*01*/ ACT2_VEHICLE, /*02*/ ACT2_VEHICLE, /*03*/ ACT2_VEHICLE, /*04*/ ACT2_STATION, /*05*/ ACT2_CARGO, /*06*/ ACT2_CARGO, /*07*/ ACT2_HOUSE, /*08*/ ACT2_NONE, /*09*/ ACT2_HOUSE, /*0A*/ ACT2_INDPROD, /*0B*/ ACT2_CARGO, /*0C*/ ACT2_NONE, /*0D*/ ACT2_CARGO, /*0E*/ ACT2_VEHICLE, /*0F*/ ACT2_HOUSE, /*10*/ ACT2_CARGO, /*11*/ ACT2_HOUSE, NDF_END }; #undef ACT0 #undef ACT1 #undef ACT3 #undef ACT4 #undef EMPTY1 #undef OVERRIDE3 #undef GENERIC3 #undef ACT3_BEFORE_PROP08 #undef ACT2_VEHICLE #undef ACT2_STATION #undef ACT2_CARGO #undef ACT2_HOUSE #undef ACT2_INDPROD #undef ACT2_NONE // --------------------------------------------------------------------------- // ------------------------- Feature-dependent data -------------------------- // --------------------------------------------------------------------------- /* Action 0 properties */ /* Invalid property */ #define INVALID 0xFF /* End of current block */ #define END 00 /* Zeros need escaping to distinguish from END */ #define ZERO '\\', 0 /* Data size */ #define BYTE 0x01 #define WORD 0x02 #define EXTBYTE 0x03 #define DWORD 0x04 /* Formatting */ #define QUOTED 0x10 /* Quoted string */ #define DECIMAL 0x20 /* Escaped decimal */ #define HEX 0x30 /* Escaped hex */ #define MAGIC 0x08 /* Various meanings */ #define DATE DECIMAL | MAGIC /* Date, that is days since 1920 if WORD, or since 0 if DWORD. For BYTE it means years since 1920. */ #define TEXTID WORD | HEX | MAGIC /* Check for valid Text/String ID */ #define TILEID WORD | MAGIC /* Check for valid tile ID, e.g. industrytile in industrylayout */ #define REMAININGSIZE DWORD | HEX | MAGIC /* Value is number of bytes for the property after this length information */ /* Allow multiple assignments to a property. (Only valid outside of SUBDATA) */ #define REASSIGNABLE 0x80 /* Insert linebreak. (Only valid within SUBDATA) * May be specified alone, or combined with any of the BYTE/EXTBYTE/WORD/DWORD datas */ #define LINEBREAK 0xC0 /* Is replaced by the data following after the next END. Mulitple SUBDATA are resolved in a depth-first style. */ #define SUBDATA 0xFE /* Raw byte to appear in the nfo */ #define RAW(b) 'l', b #define RAWBYTES(len, ...) 'm', len, __VA_ARGS__ /* Test for a specific byte value * 'offset' is the position of the byte to test within the current SUBDATA. * 'mask' is a AND bitmask to apply before testing. * 'value' is the value to test for. * 'data' is the stuff to process when the test "(byte[offset] & mask) == value" succeeds. */ #define IF(lhs, rhs, data) 'e', lhs, rhs, data #define IFNOT(lhs, rhs, data) 'n', lhs, rhs, data #define ASSERT 'a' #define SKIPNEXT 's' /* Bitwise AND */ #define AND(lhs, rhs) '&', lhs, rhs /* Repeat 'data' 'times' times, where 'times' is known before reading the data. * 'times' may be a fixed number, or a reference to an earlier BYTE/EXTBYTE/WORD/DWORD within the current SUBDATA. * You can also multiply multiple values using MUL() */ #define REPEAT_N(data, times) 'r', data, times #define MUL(a, b) 'x', a, b #define DATAFROM(offset) offset | 0x80 /* Uses the value read with the token at position 'offset' within the current SUBDATA */ /* Repeat 'data' until a certain terminator with length 'length' is encountered */ #define REPEAT_UNTIL(data, length, ...) '*', data, length, __VA_ARGS__ static const unsigned char _dat0[]={ NDF_HEADER(0x0E, 0), /*Maximum feature:*/ 0x11, // Feature 00: /*00*/ WORD | DATE, INVALID, BYTE, BYTE | DECIMAL, BYTE | DECIMAL, BYTE, BYTE, BYTE | DECIMAL, /*08*/ BYTE, WORD | DECIMAL, INVALID, WORD | DECIMAL, INVALID, BYTE, DWORD, INVALID, /*10*/ INVALID, INVALID, BYTE, BYTE, BYTE | DECIMAL, BYTE, BYTE, BYTE, /*18*/ BYTE, BYTE, EXTBYTE, WORD | DECIMAL, BYTE, DWORD | HEX, BYTE, BYTE, /*20*/ BYTE, BYTE, BYTE, BYTE | DECIMAL, BYTE, BYTE, BYTE | DECIMAL, BYTE, /*28*/ WORD | HEX, WORD | HEX, DWORD | DATE, WORD, SUBDATA, SUBDATA, END, // Subdata - prop 2C: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Subdata - prop 2D: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Feature 01: /*00*/ WORD | DATE, INVALID, BYTE, BYTE | DECIMAL, BYTE | DECIMAL, INVALID, BYTE, BYTE | DECIMAL, /*08*/ BYTE | DECIMAL, BYTE, DWORD, INVALID, INVALID, INVALID, BYTE, BYTE | DECIMAL, /*10*/ BYTE, BYTE, BYTE, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, DWORD | HEX, BYTE, /*18*/ BYTE, BYTE, BYTE, BYTE | DECIMAL, BYTE, WORD | HEX, WORD | HEX, DWORD | DATE, /*20*/ EXTBYTE, BYTE, WORD, BYTE, SUBDATA, SUBDATA, END, // Subdata - prop 24: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Subdata - prop 25: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Feature 02: /*00*/ WORD | DATE, INVALID, BYTE, BYTE | DECIMAL, BYTE | DECIMAL, INVALID, BYTE, BYTE | DECIMAL, /*08*/ BYTE, BYTE, BYTE, BYTE | DECIMAL, BYTE, WORD | DECIMAL, INVALID, BYTE, /*10*/ BYTE, DWORD | HEX, BYTE, BYTE, BYTE, BYTE, BYTE | DECIMAL, BYTE, /*18*/ WORD | HEX, WORD | HEX, DWORD | DATE, EXTBYTE, BYTE, WORD, SUBDATA, SUBDATA, END, // Subdata - prop 1E: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Subdata - prop 1F: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Feature 03: /*00*/ WORD | DATE, INVALID, BYTE, BYTE | DECIMAL, BYTE | DECIMAL, INVALID, BYTE, BYTE | DECIMAL, /*08*/ BYTE, BYTE, BYTE, BYTE, BYTE | DECIMAL, BYTE, BYTE, WORD | DECIMAL, /*10*/ INVALID, BYTE | DECIMAL, BYTE, DWORD | HEX, BYTE, BYTE, BYTE | DECIMAL, BYTE, /*18*/ WORD | HEX, WORD | HEX, DWORD | DATE, EXTBYTE, WORD, SUBDATA, SUBDATA, WORD, END, // Subdata - prop 1D: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Subdata - prop 1E: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Feature 04: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ DWORD | QUOTED, SUBDATA, BYTE, BYTE, BYTE, BYTE, SUBDATA, BYTE, /*10*/ WORD | DECIMAL, BYTE, DWORD | HEX, BYTE, BYTE, BYTE, WORD | HEX, BYTE | DECIMAL, /*18*/ WORD, INVALID, SUBDATA, END, // Subdata - prop 09: EXTBYTE, REPEAT_N(SUBDATA, DATAFROM(0)), END, LINEBREAK, RAW(ZERO), RAW(ZERO), RAW(ZERO), RAW(ZERO), '|', LINEBREAK, DWORD | HEX, LINEBREAK, REPEAT_UNTIL(SUBDATA, 1, 0x80), END, BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, DWORD | HEX, LINEBREAK, END, // Subdata - prop 0E: REPEAT_UNTIL(SUBDATA, 2, ZERO, ZERO), END, BYTE, BYTE, REPEAT_N(BYTE, MUL(DATAFROM(0), DATAFROM(1))), LINEBREAK, END, // Subdata - prop 20: EXTBYTE, REPEAT_N(SUBDATA, DATAFROM(0)), END, // spritelayout without flags BYTE, IFNOT(AND(DATAFROM(0), RAW(0x40)), ZERO, SKIPNEXT), DWORD, LINEBREAK, REPEAT_N(SUBDATA, AND(DATAFROM(0), RAW(0x3F))), // spritelayout with flags '|', BYTE, LINEBREAK, SUBDATA, REPEAT_N(SUBDATA, AND(DATAFROM(0), RAW(0x3F))), END, // building sprite without flags DWORD, BYTE | DECIMAL, BYTE | DECIMAL, RAW(0x80), LINEBREAK, '|', DWORD, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, LINEBREAK, END, // groundsprite with flags DWORD, WORD | HEX, IFNOT(AND(DATAFROM(1), RAWBYTES(2, 0x30, 0xFF)), ZERO, ASSERT), // assert on unknown flags IFNOT(AND(DATAFROM(1), RAW(0x01)), ZERO, BYTE), // skip sprite IFNOT(AND(DATAFROM(1), RAW(0x02)), ZERO, BYTE), // sprite offset IFNOT(AND(DATAFROM(1), RAW(0x04)), ZERO, BYTE), // palette offset IFNOT(AND(DATAFROM(1), RAW(0x40)), ZERO, BYTE), // sprite var10 IFNOT(AND(DATAFROM(1), RAW(0x80)), ZERO, BYTE), // palette var10 LINEBREAK, END, // buildingsprite with flags DWORD, WORD | HEX, BYTE | DECIMAL, BYTE | DECIMAL, RAW(0x80), IFNOT(AND(DATAFROM(1), RAWBYTES(2, ZERO, 0xFF)), ZERO, ASSERT), // assert on unknown flags IFNOT(AND(DATAFROM(1), RAW(0x01)), ZERO, BYTE), // skip sprite IFNOT(AND(DATAFROM(1), RAW(0x02)), ZERO, BYTE), // sprite offset IFNOT(AND(DATAFROM(1), RAW(0x04)), ZERO, BYTE), // palette offset IFNOT(AND(DATAFROM(1), RAW(0x10)), ZERO, BYTE), // X offset IFNOT(AND(DATAFROM(1), RAW(0x20)), ZERO, BYTE), // Y offset IFNOT(AND(DATAFROM(1), RAW(0x40)), ZERO, BYTE), // sprite var10 IFNOT(AND(DATAFROM(1), RAW(0x80)), ZERO, BYTE), // palette var10 LINEBREAK, '|', DWORD, WORD | HEX, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, BYTE | DECIMAL, IFNOT(AND(DATAFROM(1), RAWBYTES(2, ZERO, 0xFF)), ZERO, ASSERT), // assert on unknown flags IFNOT(AND(DATAFROM(1), RAW(0x01)), ZERO, BYTE), // skip sprite IFNOT(AND(DATAFROM(1), RAW(0x02)), ZERO, BYTE), // sprite offset IFNOT(AND(DATAFROM(1), RAW(0x04)), ZERO, BYTE), // palette offset IFNOT(AND(DATAFROM(1), RAW(0x10)), ZERO, SUBDATA), // X/Y offset IFNOT(AND(DATAFROM(1), RAW(0x20)), ZERO, BYTE), // Z offset IFNOT(AND(DATAFROM(1), RAW(0x40)), ZERO, BYTE), // sprite var10 IFNOT(AND(DATAFROM(1), RAW(0x80)), ZERO, BYTE), // palette var10 LINEBREAK, END, BYTE, BYTE, END, // X/Y offset // Feature 05: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, BYTE, END, // Feature 06: /*00*/ BYTE, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE | DATE, BYTE | DECIMAL, BYTE | DECIMAL, BYTE, WORD | DECIMAL, SUBDATA, BYTE, DWORD | DECIMAL, /*10*/ TEXTID, TEXTID, TEXTID, WORD | DECIMAL, END, // Subdata - prop 0D: BYTE, BYTE, REPEAT_N(DWORD | HEX, MUL(DATAFROM(1), 32)), LINEBREAK, END, // Feature 07: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, BYTE, SUBDATA, BYTE, BYTE, BYTE, BYTE, BYTE, /*10*/ WORD | DECIMAL, BYTE, TEXTID, WORD, BYTE, BYTE | REASSIGNABLE, BYTE, DWORD, /*18*/ BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, DWORD, BYTE, /*20*/ SUBDATA, WORD | DECIMAL, WORD | DECIMAL, END, // Subdata - prop 0A: BYTE | DATE, BYTE | DATE, END, // Subdata - prop 20: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Feature 08: // Different format this feature only: // Non-INVALID properties are followed by two bytes: // The max value for the action 0's entity // The max ID that can be set // (0f8.dat was merged into here to prevent it from getting out of sync.) /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, 0x46, 0x46, DWORD | QUOTED, 0x00, 0xFC, TEXTID, 0x12, 0x12, DWORD | DECIMAL, 0x12, 0x12, /*0C*/ WORD | QUOTED, 0x12, 0x12, DWORD | QUOTED, 0x12, 0x12, DWORD | QUOTED, 0x12, 0x12, WORD | DECIMAL, 0x12, 0x12, /*10*/ SUBDATA, 0x00, 0x00, SUBDATA, 0x00, 0xFF, DWORD | QUOTED, 0x00, 0xFC, SUBDATA, 0x7E, 0x7E, /*14*/ SUBDATA, 0x7E, 0x7E, BYTE, 0x7E, 0x7E, END, // Subdata - prop 10: REPEAT_N(SUBDATA, 11), SUBDATA, END, REPEAT_N(BYTE, 32), LINEBREAK, END, REPEAT_N(BYTE, 32), END, // Subdata - prop 11: DWORD | QUOTED, DWORD | QUOTED, END, // Subdata - prop 13: REPEAT_UNTIL(SUBDATA, 1, ZERO), END, BYTE, REPEAT_UNTIL(SUBDATA, 1, ZERO), LINEBREAK, END, BYTE | MAGIC | QUOTED, END, // Subdata - prop 14: REPEAT_UNTIL(SUBDATA, 1, ZERO), END, BYTE, REPEAT_UNTIL(SUBDATA, 1, ZERO), LINEBREAK, END, BYTE | MAGIC | QUOTED, END, // Feature 09: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, BYTE | REASSIGNABLE, WORD, WORD, WORD, BYTE, BYTE, WORD, /*10*/ BYTE, BYTE, BYTE, END, // Feature 0A: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, BYTE, SUBDATA, BYTE, TEXTID, TEXTID, TEXTID, BYTE, /*10*/ WORD, DWORD, BYTE, BYTE, BYTE, SUBDATA, SUBDATA, BYTE, /*18*/ BYTE, BYTE, DWORD, TEXTID, DWORD, DWORD, DWORD, TEXTID, /*20*/ DWORD, BYTE, BYTE, DWORD | DECIMAL, TEXTID, END, // Subdata - prop 0A: BYTE, REMAININGSIZE | LINEBREAK, REPEAT_N(SUBDATA, DATAFROM(0)), END, RAW(0xFE), BYTE, BYTE | LINEBREAK, '|', REPEAT_UNTIL(SUBDATA, 2, ZERO, 0x80), END, END, // bogus end for RAW(0xFE) BYTE, BYTE, SUBDATA, LINEBREAK, END, RAW(0xFE), TILEID, '|', BYTE, END, END, // bogus end for RAW(0xFE) // Subdata - prop 15: BYTE, REPEAT_N(BYTE, DATAFROM(0)), END, // Subdata - prop 16: REPEAT_N(BYTE, 3), END, // Feature 0B: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE | DECIMAL, TEXTID, TEXTID, TEXTID, TEXTID, TEXTID, WORD | HEX, BYTE, /*10*/ BYTE, BYTE, DWORD | HEX, BYTE, BYTE, BYTE, WORD | HEX, DWORD | QUOTED, /*18*/ BYTE, WORD | HEX, BYTE, TEXTID, TEXTID, WORD, END, // Feature 0C: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, BYTE, BYTE, END, // Feature 0D: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, DWORD, SUBDATA, INVALID, SUBDATA, BYTE, BYTE, BYTE, /*10*/ WORD, WORD, END, // Subdata - prop 0A: BYTE, REMAININGSIZE | LINEBREAK, REPEAT_N(SUBDATA, DATAFROM(0)), END, BYTE, RAW(0xFE), BYTE, BYTE | LINEBREAK, '|', BYTE, REPEAT_UNTIL(SUBDATA, 2, ZERO, 0x80), END, END, // bogus end for RAW(0xFE) BYTE, BYTE, SUBDATA, LINEBREAK, END, RAW(0xFE), TILEID, '|', BYTE, END, END, // bogus end for RAW(0xFE) // Subdata - prop 0C: WORD, WORD, END, // Feature 0E: END, // Feature 0F: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ DWORD | QUOTED, WORD, WORD, BYTE, BYTE, BYTE, DWORD | DATE, DWORD | DATE, /*10*/ WORD | HEX, WORD | HEX, BYTE | DECIMAL, WORD, BYTE, WORD | HEX, BYTE, BYTE, END, // Feature 10: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ DWORD | QUOTED, WORD, WORD, WORD, WORD, WORD, SUBDATA, SUBDATA, /*10*/ BYTE, BYTE, BYTE, WORD, WORD, BYTE, BYTE, DWORD | DATE, /*18*/ SUBDATA, SUBDATA, BYTE, WORD, WORD, SUBDATA, END, // Subdata - prop 0E: BYTE, REPEAT_N(DWORD | QUOTED, DATAFROM(0)), END, // Subdata - prop 0F: BYTE, REPEAT_N(DWORD | QUOTED, DATAFROM(0)), END, // Subdata - prop 18: BYTE, REPEAT_N(DWORD | QUOTED, DATAFROM(0)), END, // Subdata - prop 19: BYTE, REPEAT_N(DWORD | QUOTED, DATAFROM(0)), END, // Subdata - prop 1D: BYTE, REPEAT_N(DWORD | QUOTED, DATAFROM(0)), END, // Feature 11: /*00*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /*08*/ BYTE, BYTE | REASSIGNABLE, INVALID, INVALID, INVALID, INVALID, BYTE, WORD, /*10*/ BYTE, BYTE, END, NDF_END }; #undef INVALID #undef END #undef ZERO #undef BYTE #undef WORD #undef EXTBYTE #undef DWORD #undef QUOTED #undef DECIMAL #undef HEX #undef MAGIC #undef DATE #undef TEXTID #undef TILEID #undef REMAININGSIZE #undef REASSIGNABLE #undef LINEBREAK #undef SUBDATA #undef RAW #undef RAWBYTES #undef IF #undef IFNOT #undef ASSERT #undef SKIPNEXT #undef AND #undef REPEAT_N #undef MUL #undef DATAFROM #undef REPEAT /* Variational action 2 */ #define ALLOW0MASK 0x40 /* Allow masking all bits */ #define VAR(var, size) var, 0x80 | size #define VAR6x(var, size, max) VAR(var, size), max #define BYTE(var) VAR(var, 1) #define WORD(var) VAR(var, 2) #define DWORD(var) VAR(var, 4) #define BYTE6x(var, max) VAR6x(var, 1, max) #define WORD6x(var, max) VAR6x(var, 2, max) #define DWORD6x(var, max) VAR6x(var, 4, max) #define LASTVAR80(var) (var == 0xFF ? 0xFF : var + 1), (var == 0xFF ? 0xF0 : 0x80) #define NOVAR80 LASTVAR80(0x7F) static const unsigned char _dat2v[]={ NDF_HEADER(0x0D, 28), /*Maximum feature:*/ 0x11, /*Maximum operator:*/ 0x16, // Global variables: WORD(0x00), BYTE(0x01), BYTE(0x02), BYTE(0x03), BYTE(0x06), WORD(0x09), WORD(0x0A), DWORD(0x0B), WORD(0x0C), BYTE(0x0D), BYTE(0x0E), VAR(0x0F, 3), DWORD(0x10), /* var 11 in feature 04 */ BYTE(0x12), WORD(0x13), WORD(0x14), WORD(0x15), WORD(0x16), DWORD(0x18), VAR(0x1A, 4 | ALLOW0MASK), BYTE(0x1B), DWORD(0x1C), BYTE(0x1D), DWORD(0x1E), BYTE(0x20), DWORD(0x21), DWORD(0x22), DWORD(0x23), DWORD(0x24), DWORD6x(0x7D, 0xFF), VAR6x(0x7E, 2 | ALLOW0MASK, 0xFF), DWORD6x(0x7F, 0x7F), // Things like 25, 5F and 7C as feature specific, so there are put with features LASTVAR80(0xFF), // Feature 00: /*Related:*/ 0x00, DWORD(0x25), VAR(0x40, 3), VAR(0x41, 3), DWORD(0x42), DWORD(0x43), VAR(0x45, 3), DWORD(0x46), DWORD(0x47), BYTE(0x48), DWORD(0x49), DWORD(0x4A), DWORD(0x4B), DWORD(0x4C), WORD(0x5F), BYTE6x(0x60, 0x73), DWORD6x(0x61, 0xFF), DWORD6x(0x62, 0xFF), LASTVAR80(0xFF), // Feature 01: /*Related:*/ 0x01, VAR(0x40, 3), VAR(0x41, 3), VAR(0x42, 3), DWORD(0x43), VAR(0x45, 3), DWORD(0x46), DWORD(0x47), BYTE(0x48), DWORD(0x49), DWORD(0x4B), DWORD(0x4C), WORD(0x5F), DWORD6x(0x61, 0xFF), DWORD6x(0x62, 0xFF), LASTVAR80(0xFF), // Feature 02: /*Related:*/ 0x02, BYTE(0x42), DWORD(0x43), DWORD(0x46), DWORD(0x47), BYTE(0x48), DWORD(0x49), DWORD(0x4B), DWORD(0x4C), WORD(0x5F), LASTVAR80(0xFF), // Feature 03: /*Related:*/ 0x03, VAR(0x40, 3), BYTE(0x42), DWORD(0x43), WORD(0x44), DWORD(0x46), DWORD(0x47), BYTE(0x48), DWORD(0x49), DWORD(0x4B), DWORD(0x4C), WORD(0x5F), LASTVAR80(0xFF), // Feature 04: /*Related:*/ 0x08, BYTE(0x11), DWORD(0x40), DWORD(0x41), WORD(0x42), VAR(0x43, 3), BYTE(0x44), WORD(0x45), DWORD(0x46), DWORD(0x47), DWORD(0x48), DWORD(0x49), BYTE(0x4A), DWORD(0x5F), WORD6x(0x60, 0xFF), BYTE6x(0x61, 0xFF), DWORD6x(0x62, 0xFF), BYTE6x(0x63, 0xFF), WORD6x(0x64, 0xFF), BYTE6x(0x65, 0xFF), DWORD6x(0x66, 0xFF), DWORD6x(0x67, 0xFF), WORD6x(0x68, 0xFF), BYTE6x(0x69, 0xFF), LASTVAR80(0xFF), // Feature 05: /*Related:*/ 0x05, WORD(0x5F), LASTVAR80(0x83), // Feature 06: /*Related:*/ 0x08, BYTE(0x40), BYTE(0x41), NOVAR80, // Feature 07: /*Related:*/ 0x08, BYTE(0x40), BYTE(0x41), BYTE(0x42), BYTE(0x43), DWORD(0x44), BYTE(0x45), BYTE(0x46), WORD(0x47), WORD(0x5F), WORD6x(0x60, 0x6B), WORD6x(0x61, 0xFF), DWORD6x(0x62,0xFF), BYTE6x(0x63, 0xFF), BYTE6x(0x64, 0xFF), BYTE6x(0x65, 0xFF), DWORD6x(0x66, 0xFF), DWORD6x(0x67, 0xFF), NOVAR80, // Town variables ("Feature 08" *cough*cough*) /*Related:*/ 0x08, BYTE(0x40), BYTE(0x41), LASTVAR80(0xDD), // Feature 09: /*Related:*/ 0x0A, BYTE(0x40), BYTE(0x41), BYTE(0x42), VAR(0x43, 3), BYTE(0x44), WORD(0x5F), DWORD6x(0x60, 0xFF), DWORD6x(0x61, 0xFF), WORD6x(0x62, 0xFF), NOVAR80, // Feature 0A: /*Related:*/ 0x08, WORD(0x40), WORD(0x41), WORD(0x42), WORD(0x43), BYTE(0x44), DWORD(0x45), DWORD(0x46), VAR(0x5F, 3), WORD6x(0x60, 0xFF), BYTE6x(0x61, 0xFF), DWORD6x(0x62, 0xFF), DWORD6x(0x63, 0xFF), DWORD6x(0x64, 0xFF), VAR6x(0x65, 3, 0xFF), VAR6x(0x66, 3, 0xFF), DWORD6x(0x67, 0xFF), DWORD6x(0x68, 0xFF), DWORD6x(0x7C, 0x0F), LASTVAR80(0xB5), // Feature 0B: /*Related:*/ 0x0B, NOVAR80, // Feature 0C: /*Related:*/ 0x0C, NOVAR80, // Feature 0D: /*Related:*/ 0x0D, NOVAR80, // Feature 0E: /*Related:*/ 0x0E, DWORD6x(0x60, 0xFF), NOVAR80, // Feature 0F: /*Related:*/ 0x08, VAR(0x40, 3), WORD(0x41), DWORD(0x42), BYTE(0x43), BYTE(0x44), DWORD(0x45), DWORD(0x46), BYTE(0x47), BYTE(0x48), WORD(0x5F), WORD6x(0x60, 0xFF), BYTE6x(0x61, 0xFF), DWORD6x(0x62, 0xFF), WORD6x(0x63, 0xFF), DWORD6x(0x64, 0xFF), NOVAR80, // Feature 10: /*Related:*/ 0x10, BYTE(0x40), BYTE(0x41), BYTE(0x42), DWORD(0x43), BYTE(0x44), WORD(0x5F), NOVAR80, // Feature 11: /*Related:*/ 0x0D, BYTE(0x41), BYTE(0x42), VAR(0x43, 3), BYTE(0x44), DWORD(0x5F), DWORD6x(0x60, 0xFF), DWORD6x(0x61, 0xFF), WORD6x(0x62, 0xFF), NOVAR80, NDF_END }; #undef ALLOW0MASK #undef VAR #undef VAR6x #undef BYTE #undef WORD #undef DWORD #undef BYTE6x #undef WORD6x #undef DWORD6x #undef LASTVAR80 #undef NOVAR80 #define W(cnt) cnt & 0xFF, cnt >> 8 /* Construct word count */ static const unsigned char _datD[]={ NDF_HEADER(0x14, 7), /*Maximum feature:*/ 0x11, /*Max patch variable:*/ 0x16, /*Max operator:*/ 0x0C, // GRM count: /*00*/W(0x74), /*01*/W(0x58), /*02*/W(0x0B), /*03*/W(0x29), /*04*/W(0), /*05*/W(0), /*06*/W(0), /*07*/W(0), /*08*/W(0x131E), /*09*/W(0), /*0A*/W(0), /*0B*/W(0x40), /*0C*/W(0), /*0D*/W(0), /*0E*/W(0), /*0F*/W(0), /*10*/W(0), /*11*/W(0), NDF_END }; static const unsigned char _datIDs[]={ NDF_HEADER(0x77, 4), /*Maximum feature:*/ 0x11, /*00*/W(0x73), /*01*/W(0x57), /*02*/W(0x0A), /*03*/W(0x28), /*04*/W(0xFF), /*05*/W(0x08), /*06*/W(0x0C), /*07*/W(0xFF), /*08*/W(0x00), /*09*/W(0xFF), /*0A*/W(0x24), /*0B*/W(0x1F), /*0C*/W(0xFFFF), /*0D*/W(0x00), /*0E*/W(0x00), /*0F*/W(0xFF), /*10*/W(0xFF), /*11*/W(0xFF), NDF_END }; #undef W /* Action 4 strings */ static const unsigned char _dat4[]={ NDF_HEADER(0x03, 5), /*Maximum feature:*/ 0x11, // Rules for one-byte IDs: /*00*/CTRL_SPACE, /*01*/CTRL_SPACE, /*02*/CTRL_SPACE, /*03*/CTRL_SPACE, /*04*/0, /*05*/0, /*06*/0, /*07*/0, /*08*/0, /*09*/0, /*0A*/0, /*0B*/0, /*0C*/0, /*0D*/0, /*0E*/0, /*0F*/0, /*10*/0, /*11*/ CTRL_COLOR, // Rules for two-byte IDs: /*00*/CTRL_SPACE | CTRL_NEWLINE | CTRL_COLOR, /*01*/CTRL_SPACE | CTRL_NEWLINE | CTRL_COLOR, /*02*/CTRL_SPACE | CTRL_NEWLINE | CTRL_COLOR, /*03*/CTRL_SPACE | CTRL_NEWLINE | CTRL_COLOR, /*04*/CTRL_SPACE, /*05*/CTRL_SPACE, /*06*/0, /*07*/CTRL_SPACE, /*08*/0, /*09*/CTRL_SPACE | CTRL_NEWLINE | CTRL_COLOR, /*0A*/CTRL_SPACE | CTRL_NEWLINE | CTRL_COLOR | CTRL_FONT_LARGE | CTRL_NO_STACK_CHECK, /*0B*/CTRL_SPACE | CTRL_FONT_SMALL, /*0C*/0, /*0D*/0, /*0E*/0, /*0F*/0, /*10*/CTRL_SPACE, /*11*/CTRL_SPACE | CTRL_NEWLINE | CTRL_COLOR, NDF_END }; /* Randomized action 2 */ #define ACT2RANDOM(self_bits, related_bits, num_triggers) self_bits, related_bits, num_triggers static const unsigned char _dat2r[]={ NDF_HEADER(0x02, 6), /*Maximum feature:*/ 0x11, /*00*/ACT2RANDOM( 8, 8, 5), /*01*/ACT2RANDOM( 8, 8, 5), /*02*/ACT2RANDOM( 8, 8, 5), /*03*/ACT2RANDOM( 8, 8, 5), /*04*/ACT2RANDOM(20, 0, 6), /*05*/ACT2RANDOM( 8, 0, 0), /*06*/ACT2RANDOM( 0, 0, 0), /*07*/ACT2RANDOM( 8, 0, 2), /*08*/ACT2RANDOM( 0, 0, 0), /*09*/ACT2RANDOM( 8, 16, 3), /*0A*/ACT2RANDOM(16, 0, 0), /*0B*/ACT2RANDOM( 0, 0, 0), /*0C*/ACT2RANDOM( 0, 0, 0), /*0D*/ACT2RANDOM( 0, 0, 0), /*0E*/ACT2RANDOM( 0, 0, 0), /*0F*/ACT2RANDOM( 8, 0, 0), /*10*/ACT2RANDOM( 2, 0, 0), /*11*/ACT2RANDOM( 4, 16, 0), NDF_END }; #undef ACT2RANDOM // --------------------------------------------------------------------------- struct dat{ const char*data,*name; uint len; }; #undef _RENUM_DATA_H_INCLUDED_ #undef DATA #undef DATA_FILE #undef END_DATA #define DATA() static const dat data[]={ #define DATA_FILE(name)\ {(char*)_dat##name,"/.nforenum/" #name ".dat",sizeof(_dat##name)-1},\ #define END_DATA() }; #define NFORENUM_DIR_LEN (11) #include "data.h" bool makedir(const string&dir,bool dieonfail=false){ if(dir==""){ if(dieonfail)exit(EDATA); return false; } if(mkdir((dir+"/.nforenum").c_str(),0755)){ IssueMessage(0,CREATE_FAILED,dir.c_str(),errno); perror(NULL); if(dosleep)sleep(5); if(dieonfail)exit(EDATA); return false; }else{ IssueMessage(0,CREATED_DIR,dir.c_str()); if(dosleep)sleep(5); return true; } } bool finddir(string&dir){ if(dir=="")return false; struct stat Stat; if(dir[dir.length()-1]=='\\'||dir[dir.length()-1]=='/') dir.resize(dir.length()-1); if(stat((dir+"/.nforenum").c_str(),&Stat))return false; else if(Stat.st_mode&S_IFREG)return false; return true; } static string getdir(bool allow_mkdir){ string *pret; string cwd,home,homedrpath; if(datadir!=""){ verify(finddir(datadir)||makedir(datadir,true)); pret=&datadir; }else{ #if defined(_MSC_VER) && (_MSC_VER >= 1400) // getcwd is deprecated in MSVS 8.0+ char*pcwd=_getcwd(NULL,0); #else char*pcwd=getcwd(NULL,0); #endif cwd=pcwd; home=safetostring(getenv("HOME")); homedrpath=safetostring(getenv("HOMEDRIVE"))+safetostring(getenv("HOMEPATH")); free(pcwd); if (finddir(cwd)) { pret=&cwd; } else if (finddir(home) || (!home.empty() && (!allow_mkdir || makedir(home)))) { pret=&home; } else if (finddir(homedrpath) || (!allow_mkdir || makedir(homedrpath))) { pret=&homedrpath; } else{ if (allow_mkdir) verify(makedir(cwd, true)); pret=&cwd; } } if(!dosleep)IssueMessage(0,DATA_FOUND_AT,pret->c_str()); return *pret; } FILE*tryopen(const char*name,const char*mode,bool allownull=false){ string dir = getdir(mode[0] == 'w'); FILE*pFile=fopen((dir+name).c_str(),mode); if(pFile||allownull)return pFile; IssueMessage(0,DATAFILE_ERROR,OPEN,name+1,ERRNO,errno); perror(NULL); assert(false); exit(EDATA); } FILE*_myfopen(files file, bool write){ FILE*pFile=tryopen(data[file].name,"rb",true); if(pFile){ if(fgetc(pFile)==data[file].data[0]&&fgetc(pFile)>=data[file].data[1]){ if(file>datfeat && (uint)fgetc(pFile)(data[file].data), data[file].len, "rb"); if (pFile == NULL) { IssueMessage(0, DATAFILE_ERROR, OPEN, data[file].name + 1, ERRNO, errno); perror(NULL); assert(false); exit(EDATA); } } else #endif /* WITH_FMEMOPEN */ { pFile = tryopen(data[file].name,"wb"); if (fwrite(data[file].data, 1, data[file].len, pFile) != data[file].len) { IssueMessage(0, DATAFILE_ERROR, WRITE, data[file].name + 1, -1); assert(false); exit(EDATA); } fclose(pFile); pFile = tryopen(data[file].name,"rb"); } fgetc(pFile); fgetc(pFile); if(file>datfeat && (uint)fgetc(pFile) #include #include #include #include #include #include using namespace std; // grfcodec requires boost::date_time for its processing of the \wYMD and // \wDMY formats. Get boost from www.boost.org #include using namespace boost::gregorian; #include"nfosprite.h" #include"allocarray.h" #include"inlines.h" extern int _quiet; const char *zoom_levels[ZOOM_LEVELS] = { "normal", "zi4", "zi2", "zo2", "zo4", "zo8" }; const char *depths[DEPTHS] = { "8bpp", "32bpp", "mask" }; #define checkspriteno()\ if(spriteno!=-1&&spriteno!=(int)sprites.size() && !_quiet){\ fprintf(stderr, "Warning: Found sprite %d looking for sprite %d.\n",spriteno,(int)sprites.size());\ }else(void(0)) #define flush_buffer()\ if(true){\ if(buffer!=""){\ checkspriteno();\ sprites.push_back(Pseudo(sprites.size(),infover,grfcontversion,buffer,claimed_size));\ buffer="";\ }\ spriteno=temp;\ }else\ (void(0)) void read_file(istream&in,int infover,int grfcontversion,AllocArray&sprites){ string sprite,datapart,buffer; int temp=-1,spriteno=-1,claimed_size=1; string::size_type firstnotpseudo; while(true){ getline(in,sprite); istringstream spritestream(sprite); eat_white(spritestream); if(spritestream.peek()==EOF || // blank is_comment(spritestream)){ // comment }else{//sprite if(!eat_white(spritestream>>temp)){ spritestream.clear(); temp=-1; } char peeked=spritestream.peek(); if(peeked=='*'){ if(spritestream.ignore().peek()=='*'){ flush_buffer(); getline(eat_white(spritestream.ignore()),datapart); strip_trailing_white(datapart); checkspriteno(); sprites.push_back(Include(datapart)); }else{ flush_buffer(); eat_white(spritestream>>claimed_size); getline(spritestream,buffer); buffer+='\n'; } }else{ getline(spritestream,datapart); firstnotpseudo=datapart.find_first_not_of(VALID_PSEUDO); if((!spritestream||firstnotpseudo==NPOS|| (datapart[firstnotpseudo]=='"'&&infover>4)|| (datapart[firstnotpseudo]=='\\'&&infover>6)|| is_comment(datapart,firstnotpseudo))&& Pseudo::MayBeSprite(buffer)){ buffer+=sprite+'\n'; }else{ flush_buffer(); checkspriteno(); if (peeked!='|') { sprites.push_back(Real()); } else { do { datapart.erase(0, 1); } while (isspace(datapart[0])); } ((Real*)sprites.last())->AddSprite(sprites.size()-1,infover,datapart); } } } if(in.peek()==EOF){ flush_buffer(); return; } } } Sprite::unparseable::unparseable(string reason,size_t sprite){ this->reason="Error: "+reason+".\n\tWhile reading sprite:"+itoa((int)sprite)+'\n'; } void Real::AddSprite(size_t sprite,int infover,const string&data){ string::size_type loc=NPOS; string udata=UCase(data); while(true){ loc=udata.find(".PCX",loc+1); #ifdef WITH_PNG if(loc==NPOS) loc = udata.find(".PNG",loc+1); #endif if(loc==NPOS) { #ifndef WITH_PNG loc = udata.find(".PNG",loc+1); if(loc!=NPOS) throw Sprite::unparseable("Found PNG sprite, but GRFCodec is compiled without PNG support",sprite); #endif throw Sprite::unparseable("Could not find filename",sprite); } if(isspace(data[loc+4]))break; } SpriteInfo inf; if((inf.name=data.substr(0,loc+4))!=prevname){ prevy=0; prevname=inf.name; } const char*meta=data.c_str()+loc+5; if(infover<3){ unsigned int intinf[8]; if(sscanf(data.c_str(), "%d %d %x %x %x %x %x %x %x %x", &inf.xpos, &inf.ypos, &(intinf[0]), &(intinf[1]), &(intinf[2]), &(intinf[3]), &(intinf[4]), &(intinf[5]), &(intinf[6]), &(intinf[7]))!=10) throw Sprite::unparseable("Insufficient meta-data",sprite); for(int i=0;i<8;i++){ if(intinf[i]>0xFF) throw Sprite::unparseable("\"Byte\" "+itoa(i)+" isn't.",sprite); } inf.info = U8(intinf[0]); inf.depth = DEPTH_8BPP; inf.zoom = 0; inf.ydim = U8(intinf[1]); inf.xdim = U16(intinf[2] | intinf[3] >> 8); inf.xrel = S16(intinf[4] | intinf[5] >> 8); inf.yrel = S16(intinf[6] | intinf[7] >> 8); }else if(infover<32){ int sx,sy,rx,ry,comp; if(sscanf(meta,"%d %d %2x %d %d %d %d",&inf.xpos,&inf.ypos,&comp,&sy,&sx,&rx,&ry)!=7){ throw Sprite::unparseable("Insufficient meta-data",sprite); } if(sx<1)throw Sprite::unparseable("xsize is too small",sprite); if(sx>0xFFFF)throw Sprite::unparseable("xsize is too large",sprite); if(sy<1)throw Sprite::unparseable("ysize is too small",sprite); if(sy>0xFF)throw Sprite::unparseable("ysize is too large",sprite); if(rx<-32768)throw Sprite::unparseable("xrel is too small",sprite); if(rx>32767)throw Sprite::unparseable("xrel is too large",sprite); if(ry<-32768)throw Sprite::unparseable("yrel is too small",sprite); if(ry>32767)throw Sprite::unparseable("yrel is too large",sprite); inf.zoom = 0; inf.depth = DEPTH_8BPP; inf.info = U8(comp); inf.ydim = U8(sy); inf.xdim = U16(sx); inf.xrel = S16(rx); inf.yrel = S16(ry); }else{ int sx,sy,rx,ry; char depth[8],zoom[8],flags[2][8]; int read = sscanf(meta,"%7s %d %d %d %d %d %d %7s %7s %7s",depth,&inf.xpos,&inf.ypos,&sx,&sy,&rx,&ry,zoom,flags[0],flags[1]); if(strcmp(depth,"mask")==0?read!=3:read < 8){ throw Sprite::unparseable("Insufficient meta-data",sprite); } inf.depth=0xFF; for (int i = 0; i < DEPTHS; i++) { if(strcmp(depth,depths[i])==0){ inf.depth = i; break; } } if (inf.depth==0xFF)throw Sprite::unparseable("invalid depth",sprite); inf.info = 1; // Bit 1 has to be always set for container version 1 if (inf.depth!=DEPTH_MASK){ if(sx<1)throw Sprite::unparseable("xsize is too small",sprite); if(sx>0xFFFF)throw Sprite::unparseable("xsize is too large",sprite); if(sy<1)throw Sprite::unparseable("ysize is too small",sprite); if(sy>0xFFFF)throw Sprite::unparseable("ysize is too large",sprite); if(rx<-32768)throw Sprite::unparseable("xrel is too small",sprite); if(rx>32767)throw Sprite::unparseable("xrel is too large",sprite); if(ry<-32768)throw Sprite::unparseable("yrel is too small",sprite); if(ry>32767)throw Sprite::unparseable("yrel is too large",sprite); inf.zoom=0xFF; for (int i = 0; i < ZOOM_LEVELS; i++) { if(strcmp(zoom,zoom_levels[i])==0){ inf.zoom = i; break; } } if (inf.zoom==0xFF)throw Sprite::unparseable("invalid zoom",sprite); for (int i = 8; i < read; i++) { const char *flag=flags[i - 8]; /* Comment. */ if (*flag == '#' || *flag == '/' || *flag == ';') break; if (strcmp(flag,"chunked")==0)inf.info|=8; else if (strcmp(flag,"nocrop")==0)inf.info|=64; else throw Sprite::unparseable("invalid flag",sprite); } inf.ydim = U16(sy); inf.xdim = U16(sx); inf.xrel = S16(rx); inf.yrel = S16(ry); } } if (infover < 4) inf.ypos++; // bug, had an extra line at the top if(inf.xpos<0)throw Sprite::unparseable("xpos is too small",sprite); if(inf.ypos<0)throw Sprite::unparseable("ypos is too small",sprite); inf.forcereopen=(inf.ypos>((x)*6))&0x3F)|0x80)) string GetUtf8Encode(uint ch){ if(ch<0x80)return string()+char(ch); if(ch<0x800)return string()+char(((ch>>6 )&0x1F)|0xC0)+CHAR(0); /*if(ch<0x10000)*/return string()+char(((ch>>12)&0x0F)|0xE0)+CHAR(1)+CHAR(0); //if(ch<0x200000)return string()+char(((ch>>18)&0x07)|0xF0)+CHAR(2)+CHAR(1)+CHAR(0); //if(ch<0x4000000)return string()+char(((ch>>24)&0x03)|0xF8)+CHAR(3)+CHAR(2)+CHAR(1)+CHAR(0); //if(ch<0x80000000)return string()+char(((ch>>30)&0x01)|0xFC)+CHAR(4)+CHAR(3)+CHAR(2)+CHAR(1)+CHAR(0); //INTERNAL_ERROR(ch,ch); } #undef CHAR int FindEscape(string); Pseudo::Pseudo(size_t num,int infover,int grfcontversion,const string&sprite,int claimed_size){ istringstream in(sprite); ostringstream out; char ch; while(in){ eat_white(in); switch(in.peek()){ case EOF:continue; case'"': in.ignore(); while(true){ if(!in.get(ch)) throw Sprite::unparseable("Unterminated literal string",num); if(ch=='"') break; if(ch=='\\'&&infover>6){ switch(ch=(char)in.get()){ case'n': ch='\r';//TTD uses Mac-style linefeeds (\r) break; case'"': case'\\': break; case'U':{ uint x=ReadHex(in,4); if(!in) throw Sprite::unparseable("Could not parse quoted escape sequence",num); if(x>0x7FF) out.write(GetUtf8Encode(x).c_str(),3); else if(x>0x7F) out.write(GetUtf8Encode(x).c_str(),2); else out.put(x); continue; } default: in.unget(); ch=(char)ReadHex(in,2); if(!in) throw Sprite::unparseable("Could not parse quoted escape sequence",num); break; } } out.put(ch); } break; case'/':case'#':case';'://comment in.ignore(INT_MAX,'\n'); break; case'\\': if(infover>6){ in.ignore(); uint x; switch(in.get()){ case'b': if(in.peek()=='*'){// \b* x = ReadValue(in.ignore(), _BX_); if(!in||x>0xFFFF)break;//invalid if(x>0xFE){ out.put('\xFF'); out.put(x); out.put(x>>8); }else out.put((char)x); continue; } x = ReadValue(in, _B_); if(!in||x>0xFF)break;//invalid out.put((char)x); continue; case'w': x = ReadValue(in, _W_); if(!in||x>0xFFFF)break;//invalid out.put(x); out.put(x>>8); continue; case'd': x = ReadValue(in, _D_); if(!in)break; out.put(x); out.put(x>>8); out.put(x>>16); out.put(x>>24); continue; default:{ in.unget(); string esc; in>>esc; int byte = FindEscape(esc); if(byte == -1) break; out.put(byte); continue; }} throw Sprite::unparseable("Could not parse unquoted escape sequence",num); } default: ch=(char)ReadHex(in,2); if(!in) throw Sprite::unparseable("Encountered invalid character looking for literal byte",num); out.put(ch); } } packed=out.str(); if(!size()) throw Sprite::unparseable("Found a zero-byte pseudo-sprite",num); if(grfcontversion==1&&size()>=65536) throw Sprite::unparseable("Found pseudo-sprite larger than 65535 bytes. This requires container version 2",num); if(size()!=(uint)claimed_size&&claimed_size!=0 && !_quiet) fprintf(stderr, "Warning: Sprite %d reports %d bytes, but I found %d.\n",(int)num,claimed_size,size()); } uint Pseudo::size()const{return (uint)packed.size();} bool Pseudo::MayBeSprite(const string&sprite){ istringstream in(sprite); char ch; while(in.get(ch)){ if(ch=='"')return true; if(COMMENT.find(ch)!=NPOS){ in.ignore(INT_MAX,'\n'); continue; } if(isspace(ch)||string(VALID_PSEUDO).find(ch)==NPOS)continue; return true; } return false; } Include::Include(const string&data):name(data){} uint Pseudo::ReadValue(istream& in, width w) { if (in.peek() == 'x') { // Read any hex value uint ret; in.ignore()>>setbase(16)>>ret>>setbase(10); return ret; } /*if (in.peek() == '(') { // Read any RPN value //TODO: Magic goes here }*/ // Read any other value string str; // can't use operator>> -- that will consume comments in cases like \w12000//comment eat_white(in); // skip whitespace at front while(in && !is_comment(in) && !isspace(in.peek()) && in.peek() != EOF) str += (char)in.get(); char c1, c2; int y, m, d, count = sscanf(str.c_str(), "%d%c%d%c%d", &y, &c1, &m, &c2, &d); if (count==1) { // Got a decimal number if (w==_B_ && y>=1920) y-=1920; // special case for byte-sized years return y; } // May have a date. Check, fiddle, and invoke date_time. if (count == 5 && c1 == c2 && (c1 == '-' || c1 == '/')) { int extra = 0; if (w == _W_) { // word date if (d==0 || (d>31 && d<100) || d>1919) swap(y, d); // Try DMY instead if (y==0) y = 2000; else if (y>31 && y<100) y+=1900; } else if (w == _D_) { // dword date extra = 701265; if (d >= 32) swap(y, d); // Try DMY instead // Boost doesn't support years out of the range 1400..9999 while (y>9999) { y -= 400; extra += 365*400 + 97; // 97 leap years every 400 years. } while (y<1400) { y += 400; extra -= 365*400 + 97; } } else goto fail; // I can't read a date of that width. try { return (date((ushort)y, (ushort)m, (ushort)d) - date(1920, 1, 1)).days() + extra; } catch (std::out_of_range) { // Fall through to fail } } fail: // Nothing worked in.clear(ios::badbit); return (uint)-1; } grfcodec-6.0.3/src/file.cpp0000644000000000000000000000250212027143046014202 0ustar rootroot/*****************************************\ * * * FILE.CC - Classes for image file * * processing * * * * Copyright (C) 2000 by Josef Drexler * * * * * * Permission granted to copy and redist- * * ribute under the terms of the GNU GPL. * * For more info please read the file * * COPYING which should have come with * * this file. * * * \*****************************************/ #include #include #include #include "file.h" #include "error.h" /***********************\ * * * class singlefile * * * \***********************/ singlefile::singlefile(const char *filename, const char *mode, const char *dir) { FILE *f = fopen(filename, mode); if (!f) { fperror("\nCan't read %s", filename); exit(1); } setfile(f); thefilename = strdup(filename); autoclose = 1; if (dir) directory = strdup(dir); else directory = NULL; }; singlefile::~singlefile() { if (autoclose && thefile) fclose(thefile); free(thefilename); free(directory); }; void singlefile::setfile(FILE *file) { thefile = file; thefilename = NULL; autoclose = 0; } grfcodec-6.0.3/src/act123.cpp0000644000000000000000000004616412027143046014274 0ustar rootroot/* * act123.cpp * Contains definitions for checking actions 1-3. * * Copyright 2004-2009 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include using namespace std; #include"inlines.h" #include"ExpandingArray.h" #include"sanity_defines.h" #include"data.h" #include"rangedint.h" #include"pseudo.h" #include"act123.h" #include"command.h" #include"messages.h" #define MAX_TTD_SPRITE 4894 uint CargoTransTable(int=0); #define CHANGED_FEATURE(type)\ {\ int loop;\ loop=0;\ type##ChangedFeature:\ if(loop++>10){\ IssueMessage(FATAL,AUTOCORRECT_LOOP);\ return;\ }\ } /*int parity(uint x){ int ret=0; while(x){ ret+=x%2; x/=2; } return ret; }*/ bool CheckSpriteNum(uint num,uint offset,act123::Act1&act1,uint feature,bool&mismatch,bool&hasGround){ uint sprite=num&0x3FFF; if(num&1<<31){ if(feature!=act1.feature&&!mismatch){ IssueMessage(ERROR,FEATURE_MISMATCH,1,act1.spritenum); mismatch=true; return false; } if(sprite>=act1.numsets) IssueMessage(ERROR,UNDEFINED_SPRITE_SET,offset,sprite,act1.spritenum); else act1.use(sprite); }else if(sprite>MAX_TTD_SPRITE) IssueMessage(ERROR,SPRITENUM_TOO_HIGH,offset); hasGround|=((num&1<<30)!=0); int translate=num>>14&3,color=num>>16&0x3FFF; if(translate==3)IssueMessage(ERROR,INVALID_COLOR_TRANS,offset); else if((translate==1||(translate==2&&color))&&(color<775||color>790)&&(color<795||color>803)) IssueMessage(WARNING1,INVALID_COLOR_SPRITE,offset+2,color); return true; } bool CheckCargoID(uint offset,unsigned int id,uint feature,uint&newfeature){ act123::IDarray&IDs=act123::Instance().defined2IDs; if(id&0x8000)return false;//callback else if(id>>8){ IssueMessage(ERROR,NEITHER_ID_CALLBACK,id,CID); return true; } if(IDs.test(offset,id)){ if(IDs.GetFeature(id)!=feature){ IssueMessage(ERROR,FEATURE_LINK_MISMATCH,offset,id,IDs.GetFeature(id)); if(newfeature==(uint)-1)newfeature=IDs.GetFeature(id); else if(newfeature!=IDs.GetFeature(id))newfeature=feature; }else newfeature=feature; IDs.use(id); return IDs.checks1C(id); }else return true; } void invalidate_act3(){ act123::Instance().act3spritenum=0; } void CheckCallback(uint offs,uint feature,uint cb){ Callbacks&cbs=Callbacks::Instance(); if(cb&&(cb>=cbs.numcallbacks||cb<0x10||(cbs[cb]&0x80000000?!(cbs[cb]&(1<4&&(act1.feature==7||act1.feature==9))||(numsprites>8&&act1.feature<4)|| (numsprites>1&&act1.feature==0x0B))IssueMessage(WARNING1,SET_TOO_LARGE); else if(numsprites>4&&numsprites<8&&act1.feature<4)IssueMessage(WARNING1,STRANGE_SET_SIZE); act1.spritenum=_spritenum; return numsprites*act1.numsets; } void Check2(PseudoSprite&data){ data.SetAllHex(); act123::Act1&act1=act123::Instance().act1; uint feature=data.ExtractByte(1),id=data.ExtractByte(2); uint nument1=data.ExtractByte(3),length=data.Length(),i,j; Define2 defineID(feature,id); if(!IsValid2Feature(feature)){ IssueMessage((nument1&0x80)?ERROR:FATAL,INVALID_FEATURE); if(_autocorrect==2&&act1.spritenum&&!(nument1&0x80)){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,1,FEATURE,feature,act1.feature); data.SetByteAt(1,feature=act1.feature); }else if(!(nument1&0x80)) return; } switch(nument1){ case 0x80: case 0x83: case 0x84: { CHANGED_FEATURE(rand) bool isRand=false; unsigned int prevID=(unsigned)-1,rID,newfeature=(uint)-1; uint base = 7; // offset of first randID if(nument1==0x84){ base = 8; if(data.ExtractByte(4)&0x30) IssueMessage(ERROR,BAD_RANDSUBTYPE); } uint nument2=data.ExtractByte(base-1); if((nument2-1)&nument2/*tests for only one bit set*/||!nument2)IssueMessage(ERROR,RAND_2_NUMSETS); else if(nument2==1)IssueMessage(WARNING3,ONLY_ONE_CHOICE); rand2::Instance().CheckRand(feature,nument1,data.ExtractByte(base-3),data.ExtractByte(base-2),nument2); if(_autocorrect&&!((length-base)%2)){ uint realcount=(length-base)/2; if(nument2!=realcount && realcount<256 && !((realcount-1)&realcount)){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,base-1,NRAND,nument2,realcount); data.SetByteAt(base-1,nument2=realcount); } } if(CheckLength(length,base+2*nument2,BAD_LENGTH,NRAND,VAL,nument2,base+2*nument2))return; for(i=0;i>2)&3),off=4,var,param=0,shift,op=(uint)-1,newfeature=(uint)-1, effFeature = Check2v::GetEffFeature(feature,nument1); bool isvar=false,isadv=false; uint oldop = 0; varRange ranges(extract); while(true){//read [] [ ...]. off reports byte to be read. var=data.ExtractByte(off++); if(op==0xF && oldop!=0xE && oldop!=0x10 && var!=0x7B) IssueMessage(WARNING1,DISCARD_UNSTORED,off-2); else if(op==0x10 && !Check2v::Instance().IsValid(effFeature, 0x7C)) IssueMessage(ERROR,NO_PERS_REGS,off-2); oldop = op; if(Is60x(var))param=data.ExtractByte(off++); shift=data.ExtractByte(off++); if(!isadv&&var==0x7B) IssueMessage(WARNING1,INDIRECT_VAR_START,off-3); Check2v::Instance().Check(effFeature,var,off-2-(Is60x(var)?1:0),param,shift&0x1F); if((shift&0xC0)==0xC0){ IssueMessage(FATAL,INVALID_SHIFT,off-1); return; } if(isadv||(shift&0x20))data.SetEol(off-(Is60x(var)?4:3),2); ranges.UpdateRange(var,op,shift,data,off); defineID.Check(var); isvar|=(var!=0x1A&&var!=0x1C); if(!(shift&0x20))break; isadv=true; if((op=data.ExtractByte(off++))>Check2v::GetMaxOp()) IssueMessage(ERROR,INVALID_OP,off-1,op); else data.SetOpByte(off-1, '2'); } uint nument2=data.ExtractByte(off);//off switches to byte-just-read. if(isadv)data.SetEol(off-1,1); else if(nument2>1)data.SetEol(off,1); if(!isvar)IssueMessage(WARNING4,NOT_VARIATIONAL); uint width=2+extract*2,end=++off+width*nument2; int change=int(length-end-2)/int(width); if(change&&_autocorrect&&!((length-end-2)%width)&&nument2+change<256){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,off-1,NVAR,nument2,nument2+change); data.SetByteAt(off-1,nument2+=change); end=length-2; } if(CheckLength(length,end+2,BAD_LENGTH,NVAR,VAL,nument2,end+2))return; uint def=data.ExtractWord(end),vID; for(i=off;i [...] vID=data.ExtractWord(i); isvar=CheckCargoID(i,vID,feature,newfeature); uint min=data.ExtractVariable(i+2,extract),max=data.ExtractVariable(i+2+extract,extract); if(nument2>1)data.SetEol(i+1+extract*2,isadv?2:1); if(min>max)IssueMessage((i==off)?WARNING4:WARNING1,UNREACHABLE_VAR,(i-off)/width); else{ ranges.AddRange(min,max); if(def==vID&&(nument2!=1||!isvar))IssueMessage(WARNING3,REUSED_DEFAULT); } if(var==0x0C&&!isadv){ if(min!=max&&!( (feature==7&&min==0x1B&&max==0x1C)|| (feature==0&&min==0x10&&max==0x11&&(vID==0x8000||vID==0xFF00)) )) IssueMessage(WARNING1,CHECK_0C_RANGE,i+2,min,max); else{ CheckCallback(i+2,feature,min); } } } ranges.CheckDefault(); CheckCargoID(end,def,feature,newfeature); if(_autocorrect&&newfeature!=(uint)-1&&newfeature!=feature){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,1,FEATURE,feature,newfeature); data.SetByteAt(1,feature=newfeature); defineID.ChangeFeature(feature); goto varChangedFeature; } return; } default: CHANGED_FEATURE(std) if(nument1&0x80){ IssueMessage(FATAL,INVALID_TYPE); return; } switch(Get2Type(feature)){ case 0: case 1: case 2:{ // Standard format bool mismatch=false,no1=false; uint nument2=data.ExtractByte(4); if(CheckLength(length,2*(nument1+nument2)+5,BAD_LENGTH,VARS,NUMENT1,NUMENT2,VALS,nument1,nument2, 2*(nument1+nument2)+5)) break; if (Get2Type(feature) == 0) { if(!nument1)IssueMessage(ERROR,NO_REQD_SETS,LOADED); if(!nument2)IssueMessage(ERROR,NO_REQD_SETS,LOADING); } else if (Get2Type(feature) == 1) { if(!nument2)IssueMessage(ERROR,NO_REQD_SETS,LOTS); } else { if(nument1!=1)IssueMessage(ERROR,INVALID_LITERAL,3,nument1,1); if(nument2)IssueMessage(ERROR,INVALID_LITERAL,4,nument2,0); } for(i=0;i>8)IssueMessage(ERROR,NEITHER_ID_CALLBACK,j,SET); else if(act1.spritenum==0&&!no1){ IssueMessage(ERROR,NO_ACT1); no1=true; }else if(feature!=act1.feature&&!mismatch&&!no1){ mismatch=true; IssueMessage(ERROR,FEATURE_MISMATCH,1,act1.spritenum); if(_autocorrect==2||(_autocorrect&&Get2Type(act1.feature)<3)){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,1,FEATURE,feature,act1.feature); data.SetByteAt(1,feature=act1.feature); defineID.ChangeFeature(feature); goto stdChangedFeature; } }else if(j>=act1.numsets) IssueMessage(ERROR,UNDEFINED_SPRITE_SET,2*i+5,j,act1.spritenum); else act1.use(j); } break; }case 3:{ // House/Industry tile format uint ground=data.ExtractDword(4); uint ground_flags=0; uint off=8; if(nument1&0x40) { ground_flags=data.ExtractWord(off);off+=2; if(ground_flags&0x01)off+=1; if(ground_flags&0x02)off+=1; if(ground_flags&0x04)off+=1; /*(flags&0x08) is valid but doesn't eat an extra byte*/ if(ground_flags&0xFFF0)IssueMessage(ERROR,INVALID_ACT2_FLAGS,8); } bool mismatch=false,hasGround=(ground!=0)||(ground_flags&0x06); if(ground&&!(ground_flags&0x06))CheckSpriteNum(ground,4,act1,feature,mismatch,hasGround); if(nument1){//Extended format bool has_flags = nument1&0x40; nument1&=0x3F; data.SetEol(3,3);//EOL before ground sprite data.SetEol(off-1,1);//EOL after ground sprite for(i=0;i16)IssueMessage(WARNING3,TOO_LARGE,curoff-6,XOFF,16); else if(xoff+x>16)IssueMessage(WARNING3,TOO_LARGE,curoff-6,XOFF_EXT,16); if(yoff>16)IssueMessage(WARNING3,TOO_LARGE,curoff-5,YOFF,16); else if(yoff+y>16)IssueMessage(WARNING3,TOO_LARGE,curoff-5,YOFF_EXT,16); } if(flags&0x01)curoff+=1; if(flags&0x02)curoff+=1; if(flags&0x04)curoff+=1; /*(flags&0x08) is valid but doesn't eat an extra byte*/ if(flags&0x10)curoff+=2; if(flags&0x20)curoff+=1; if(flags&0xFFC0)IssueMessage(ERROR,INVALID_ACT2_FLAGS,8); off=curoff; if(++i!=nument1)data.SetEol(off-1,1); if(i==0x3F&&_autocorrect)throw 0; }catch(...){ if(_autocorrect&&i){ if(i!=nument1){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,3,NUMSPRITES,nument1,i); data.SetByteAt(3,i|(has_flags?0x40:0)); } break; }else{ IssueMessage(FATAL,OVERRAN_SPRITE,i); return; } } } if(off!=length)IssueMessage(WARNING2,EXTRA_DATA,length,off); if(!hasGround)IssueMessage(WARNING2,NO_GROUNDSPRITE,NONTRANS); }else{//Basic format if(!ground)IssueMessage(ERROR,NO_GROUNDSPRITE,GROUND); if(CheckLength(length,17,INVALID_LENGTH,TYPE,BASICSTD2,HOUSE_INSTYTILE,EXACTLY,17))break; uint building=data.ExtractDword(8),xoff=data.ExtractByte(12),yoff=data.ExtractByte(13), x=data.ExtractByte(14),y=data.ExtractByte(15);//,z=data.ExtractByte(16); if(building){ if(!CheckSpriteNum(building,8,act1,feature,mismatch,hasGround)&& (_autocorrect==2||(_autocorrect&&Get2Type(act1.feature)==3))){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,1,FEATURE,feature,act1.feature); data.SetByteAt(1,feature=act1.feature); goto stdChangedFeature; } if(xoff>16)IssueMessage(WARNING3,TOO_LARGE,12,XOFF,16); else if(xoff+x>16)IssueMessage(WARNING3,TOO_LARGE,12,XOFF_EXT,16); if(yoff>16)IssueMessage(WARNING3,TOO_LARGE,13,YOFF,16); else if(yoff+y>16)IssueMessage(WARNING3,TOO_LARGE,13,YOFF_EXT,16); //if(z>0x87)IssueMessage(WARNING1,TOO_LARGE,16,ZEXT,0x87); } } break; }case 4: // Industry format switch(data.ExtractByte(3)){ // Callback version case 0: if(CheckLength(length,15,INVALID_LENGTH,TYPE,PROD2S,INDUSTRIES,ONE_OF,10,15))break; if(data.ExtractWord(10)>32768)IssueMessage(WARNING1,EXCESSIVE_ADD,1); if(data.ExtractWord(12)>32768)IssueMessage(WARNING1,EXCESSIVE_ADD,2); break; case 1: CheckLength(length,10,INVALID_LENGTH,TYPE,PROD2S,INDUSTRIES,ONE_OF,10,15); break; default: IssueMessage(ERROR,INVALID_VERSION,PROD2); } break; DEFAULT(feature) } } } void Check3(PseudoSprite&data){ PseudoSprite::Byte feature, numIDs; CHANGED_FEATURE(act3) data.seek(1)>>feature>>numIDs; uint newfeature=(uint)-1, i; bool isOverride=((numIDs&0x80)!=0),isGeneric=((numIDs&0x7F)==0); if(isOverride&&isGeneric)IssueMessage(ERROR,GENERIC_AND_OVERRIDE); if(!isGeneric&&!IsValidFeature(ACT3,feature)){IssueMessage(FATAL,INVALID_FEATURE);return;} else if(isOverride&&!IsValidFeature(OVERRIDE3,feature))IssueMessage(ERROR,INVALID_FEATURE); else if(isGeneric&&!IsValidFeature(GENERIC3,feature))IssueMessage(ERROR,INVALID_FEATURE); Expanding0Array ids; PseudoSprite::ExtByte id; for(i=0;i<(numIDs&0x7F);i++){ data>>id; if(ids[id]) IssueMessage(WARNING1,DUPLICATE,id.loc(),ID,id.val(),ids[id]); ids[id]=id.loc(); CheckID(feature,id); if(!IsValidFeature(ACT3_BEFORE_PROP08,feature) && !IsProp08Set(feature,id)) IssueMessage(ERROR,ACT3_PRECEDES_PROP08,id.loc(),id.val()); } PseudoSprite::Byte numCIDs; data>>numCIDs; uint newCIDs=data.BytesRemaining()/3; if(_autocorrect>=2&&(data.BytesRemaining()%3)==2&&newCIDs!=numCIDs&&newCIDs<256){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,numCIDs.loc(),NUMCID,numCIDs.val(),newCIDs); numCIDs.set(newCIDs); } if(numCIDs&&feature>4&&feature!=0xF&&feature!=0x10)IssueMessage(WARNING1,NO_CARGOTYPES); PseudoSprite::Byte cargo; PseudoSprite::Word cid,def; data.Extract(def,numCIDs.loc()+1+numCIDs*3); ids.clear(); // Reuse as cargos ids.reserve(256); for (i=0; i>cargo>>cid; if ((feature == 0x0F && cargo != 0x00 && cargo != 0xFF) || (feature == 0x10 && cargo > 0x0A) || (feature <= 0x04 && cargo>CargoTransTable() && cargo != 0xFF && (cargo != 0xFE || feature != 4))) IssueMessage(ERROR,INVALID_CARGO_TYPE,cargo.loc(),cargo.val()); if(ids[cargo]) IssueMessage(WARNING1,DUPLICATE,cargo.loc(),CARGO,cargo.val(),ids[cargo]); ids[cargo] = cargo.loc(); CheckCargoID(cid.loc(),cid,feature,newfeature); if(def==cid) IssueMessage(WARNING1,REUSED_DEFAULT); } CheckCargoID(def.loc(),def,feature,newfeature); if (isOverride && act123::Instance().act3spritenum && feature != act123::Instance().act3feature) { IssueMessage(ERROR,FEATURE_MISMATCH, 3, act123::Instance().act3spritenum); newfeature = act123::Instance().act3feature; } if(_autocorrect&&newfeature!=(uint)-1&&newfeature!=feature){ IssueMessage(0,CONSOLE_AUTOCORRECT,_spritenum); IssueMessage(0,AUTOCORRECTING,1,FEATURE,feature.val(),newfeature); feature.set(newfeature); goto act3ChangedFeature; } if(isGeneric)// Generic 3s cannot be followed by an override act123::Instance().act3spritenum=0; else if(!isOverride){ act123::Instance().act3feature=feature; act123::Instance().act3spritenum=_spritenum; }else if(!act123::Instance().act3spritenum) IssueMessage(ERROR,NO_STD_3); } void Init123(){act123::Instance().init();} void final123(){ const act123::IDarray& IDs=act123::CInstance().defined2IDs; ManualConsoleMessages(); bool header=false; if(act123::Instance().act1.spritenum) for(unsigned int i=0;i #include #ifdef _MSC_VER #pragma warning (disable : 4702) // warning C4702: unreachable code #endif #include #ifdef _MSC_VER #pragma warning (default : 4702) #endif #include "language_mgr.h" #include "messages.h" /*! Collection mapping language IDs to strings. */ typedef std::map lang2str_map; /*! Encapsulates a NFORenum message. */ class MessageData { public: /*! Creates a new instance of MessageData with the specified properties. \param props_ Initial properties of the message. */ MessageData(char props_ = 0); /*! Creates a new instance of MessageData with the specified properties and text in the default language. \param props_ Initial properties of the message. \param default_text Text of the message in the default language. */ MessageData(char props_, const std::string& default_text); /*! Check whether this message is meant for the console. \return true if the message is meant for the console. */ bool IsConsoleMessage() const { return !(props & NO_CONSOLE); } /*! Check whether this message is meant to make a comment. \return true if the message is supposed to make a comment. */ bool IsMakeComment() const { return (props & MAKE_COMMENT); } /*! Output the message to the appropriate stream. \param prefix Message prefix \param ap Message parameter list \return The composed message */ std::string Display(const std::string& prefix, std::va_list& ap) const; /*! Get the text of this message in the current language. If the text is not available in the current language, get text in the default language. If even that fails return a fallback string. \return Text of the message, or MessageMgr::UNDEFINED_TEXT if not available. */ const std::string& GetText() const; /*! Get the properties of this message. \return Message properties */ char GetProps() const { return props; } /*! Set message text for the specified language. \param lang Language to set the text for \param text Text of the message */ void SetText(RenumLanguageId lang, const std::string& text); private: /*! Renders the message in the current language with given optional prefix. \param prefix Optional message prefix \return Rendered message */ std::string GetMessage(const std::string& prefix = "") const; /*! A string inserted between comment delimiter and the beginning of a message. */ const static std::string commentPrefix; lang2str_map textMap; /*!< Contains message texts for each language. */ char props; /*!< Message properties */ }; /*! Collection mapping message IDs to message data. */ typedef std::map msgid2data_map; /*! Collection mapping extra text IDs to extra text data. */ typedef std::map extid2data_map; /*! Manages program messages and extra texts for various supported languages. */ class MessageMgr { SINGLETON(MessageMgr); public: const static MessageData UNKNOWN_MESSAGE; /*!< Fallback message data. */ const static std::string UNDEFINED_TEXT; /*!< Fallback message text. */ /*! Get the data for the specified message ID in the current language. \param i Message ID. \return Reference to message data for the given ID. If the ID is unknown, a reference to UNKNOWN_MESSAGE is returned. */ const MessageData& GetMessageData(RenumMessageId i) const; /*! Get the data for the specified message ID in the current language. \param i Extra text ID. \return Extra text, or MessageMgr::UNDEFINED_TEXT if not available. */ const std::string& GetExtraText(RenumExtraTextId i) const; /*! Adds new message data for the specified message ID. \param i Message ID to add. \param props Properties of this message. \return true if successful. If message data for the speficied ID already exists, this function returns false. */ bool AddMessage(RenumMessageId i, char props); /*! Sets the message text for the specified message ID and language. \param i Message ID \param lang Language this particular text is in \param text Text of the message \return true if successful. If no such message ID exists returns false. */ bool SetMessageText(RenumMessageId i, RenumLanguageId lang, const std::string& text); /*! Set the extra text for the specifified extra text ID and language. \param i Extra text ID \param lang Language this particular text is in \param text The extra text */ void SetExtraText(RenumExtraTextId i, RenumLanguageId lang, const std::string& text); private: /*! Initialize message data and properties. */ void InitMessages(); /*! Initialize message texts for all supported languages. */ void InitMessageTexts(); /*! Initialize extra text data for all supported languages. */ void InitExtraTexts(); msgid2data_map msgDataMap; /*!< Message data for each message ID. */ extid2data_map extraTextMap; /*!< Extra text data for each extra text ID. */ }; #endif // _RENUM_MESSAGE_MGR_H_INCLUDED_ grfcodec-6.0.3/src/IDs.cpp0000644000000000000000000000622312027143046013746 0ustar rootroot/* * IDs.cpp * ID checking for actions 0-4. * * Copyright 2005-2006 by Dale McCoy. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include using namespace std; #include"nforenum.h" #include"inlines.h" #include"messages.h" #include"sanity_defines.h" #include"data.h" #include"command.h" #include"ExpandingArray.h" class IDs:public Guintp{ public: SINGLETON(IDs); }; IDs::IDs(){ FILE*pFile=myfopen(IDs); _p=new uint[MaxFeature()+1]; for(uint i=0;i<=MaxFeature();i++) _p[i]=GetCheckWord(IDs); fclose(pFile); } class TextIDs{ public: uint idClasses[0x20],numspecials; bool CheckID(uint,uint); void Define(uint); bool IsDefined(uint); static void Clear(); AUTO_ARRAY(uchar); SINGLETON(TextIDs); private: static Expanding0Array _m; }; Expanding0Array TextIDs::_m; TextIDs::TextIDs(){ FILE*pFile=myfopen(TextIDs); uint i=0; for(;i<0x20;i++) idClasses[i]=GetCheckWord(TextIDs); _p=new uchar[numspecials=GetCheckByte(TextIDs)]; myfread(_p,numspecials,TextIDs); fclose(pFile); } bool TextIDs::CheckID(uint feature,uint ID){ if((ID&0xF000)==0xD000){ if(feature==0x48)return ID<0xD400||(ID>0xDBFF&&ID<0xDD00); return ID>0xD3FF&&ID<0xD800; } if(feature==0x49&&ID==0xC7FF)return true; if(idClasses[ID>>11]==0xFFFF){ for(uint i=0;i>8==_p[i])return true; return false; } return(ID&0x7FF)>11]; } void TextIDs::Define(uint ID){ if(idClasses[ID>>11]==0xFFFF){ ID-=0xC000; _m[ID]=true; } } bool TextIDs::IsDefined(uint ID){ if(idClasses[ID>>11]==0xFFFF) return const_cast& >(_m)[ID-0xC000]; return (ID&0x7FF)>11]; } void TextIDs::Clear() { _m.clear(); } void ClearTextIDs() { TextIDs::Clear(); } bool CheckTextID(uint feature,uint ID,uint offset){ VERIFY(feature==0x48||feature==0x49,feature); VERIFY(ID<0x10000,ID); if(TextIDs::Instance().CheckID(feature,ID)){ if (feature==0x48) TextIDs::Instance().Define(ID); return true; } IssueMessage(ERROR,INVALID_TEXTID,offset,ID); return false; } bool IsTextDefined(uint ID) { return TextIDs::Instance().IsDefined(ID); } bool CheckID(uint feature,uint ID){ VERIFY(feature<=MaxFeature(),feature); VERIFY(ID<0x10000,ID); uint maxID=IDs::Instance()[feature]; if(ID>maxID){ IssueMessage(ERROR,INVALID_ID,ID,feature==0x0C?0x49:0,maxID); return false; } if(feature==0x0C&&ID<0x49){ IssueMessage(ERROR,INVALID_ID,ID,0x49,0xFFFF); return false; } return true; } grfcodec-6.0.3/src/help.h0000644000000000000000000000202412027143046013657 0ustar rootroot/* * help.h * Declares functions for displaying program help in multiple languages. * * Copyright (c) 2004-2006, Dale McCoy. * Copyright (c) 2006, Dan Masek. * * 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 2 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, write to the Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _RENUM_HELP_H_INCLUDED_ #define _RENUM_HELP_H_INCLUDED_ /*! Display help to standard output. */ void ShowHelp(); #endif // _RENUM_HELP_H_INCLUDED_ grfcodec-6.0.3/src/info.cpp0000644000000000000000000002233112027143046014220 0ustar rootroot/* A class for dealing with .NFO files */ #include #include #include #include #include #include #include "info.h" #include "sprites.h" #include "error.h" #include "grfcomm.h" #define GRFCODEC #include "mapescapes.h" extern bool _interactive; int makeint(U8 low, S8 high) { S16 combined; combined = (high << 8) | low; return combined; } void read_file(istream&in,int infover,int grfcontversion,AllocArray&sprites); nfe_map nfo_escapes; inforeader::inforeader(char *fn, int grfcontversion) { ifstream f; f.open(fn); string buffer; int infover; imgfile = NULL; imgname = NULL; getline(f,buffer); // read first line, a comment if (strncmp(buffer.c_str(), "// ", 3)) { printf("NFO file missing header lines and version info\n"); exit(1); } getline(f,buffer); // second line used to get info version if (strncmp(buffer.c_str(), "// (Info version ", 17)) { infover = 1; f.seekg(0); } else infover = atoi(buffer.c_str() + 17); if (infover > 2) getline(f,buffer); // skip "format: " line if (infover > 6) { while (strncmp(buffer.c_str(), "// Format: ", 11)) { if (!strncmp(buffer.c_str(), "// Escapes: ", 12)) { // Nope. That was an escapes line. istringstream esc(buffer); string str; int byte = 0; esc.ignore(12); while (esc>>str){ if(str == "=") byte--; else if (str[0] == '@') byte = strtol(str.c_str()+1, NULL, 16); else nfo_escapes.insert(nfe_pair(str, byte++)); } } getline(f, buffer); // Try again to skip "format: " line } } colourmap = NULL; try{ read_file(f,infover,grfcontversion,nfofile); }catch(Sprite::unparseable e){ printf("%s", e.reason.c_str()); exit(1); } } inforeader::~inforeader() { delete imgfile; } void inforeader::PrepareReal(const SpriteInfo&info){ int oldy=inf.ypos; inf=info; if ( inf.forcereopen || !imgfile || !imgname || (stricmp(inf.name.c_str(), imgname) != 0) || oldy > inf.ypos) { // new file delete imgfile; imgname = inf.name.c_str(); if (_interactive) { printf("Loading %s\n", imgname); } imgfile = MakeReader(); if (!imgfile) { printf("\nError: can't open %s\n", imgname); exit(2); } if (colourmap) imgfile->installreadmap(colourmap); imgfile->startimage(inf.depth!=DEPTH_32BPP, 0, 0, 0, 0); } sx = inf.xdim; sy = inf.ydim; imgfile->startsubimage(inf.xpos, inf.ypos, sx, sy); imgsize = (long) sx * (long) sy; } pcxread* inforeader::MakeReader()const{ #ifdef WITH_PNG if(toupper(imgname[strlen(imgname)-1])=='X')//pcx return new pcxread(new singlefile(imgname, "rb", NULL)); else //png return new pngread(new singlefile(imgname, "rb", NULL)); #else return new pcxread(new singlefile(imgname, "rb", NULL)); #endif } int inforeader::getsprite(CommonPixel *sprite) { imgfile->streamgetpixel(sprite, imgsize); return 1; } void inforeader::installmap(int *map) { colourmap = map; } extern int _useexts; infowriter::infowriter(FILE *info, int maxboxes, int useplaintext, const char *directory) { this->directory = directory; infowriter::info = info; fputs("// Automatically generated by GRFCODEC. Do not modify!\n", info); fprintf(info,"// (Info version %d)", _useexts ? 32 : 6); if(_useexts) { // (re)insert default escapes foreach(const esc& e, escapes) nfo_escapes.insert(nfe_pair(e.str+1, e.byte)); fputs("\n// Escapes:", info); int oldbyte = -1; for (int act = 0; act < 255; act++) { foreach (const nfe_rpair& p, nfo_escapes.right) { if (p.second[0] != act) continue; if (p.first == oldbyte) { fprintf(info, " ="); --oldbyte; } else if (p.first < oldbyte) { fputs("\n// Escapes:", info); oldbyte = -1; } while (++oldbyte != p.first) fprintf(info," %s", nfo_escapes.right.begin()->second.c_str()); fprintf(info, " %s", p.second.c_str()); } } } if (_useexts) { fputs("\n// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags\n", info); }else { fputs("\n// Format: spritenum pcxfile xpos ypos compression ysize xsize xrel yrel\n", info); } infowriter::useplaintext = useplaintext; infowriter::maxboxes = maxboxes; boxes = new Box*[maxboxes]; boxnum = 0; spriteno = 0; for (int i=0; itype) { case Box::issprite: case Box::isspriteextension: { if (boxes[i]->type == Box::issprite) { fprintf(info, "%5d ", spriteno++); } else { fprintf(info, " | "); } BoxSprite *s = (BoxSprite*)boxes[i]; if (_useexts) { if (s->info.depth == 2) { fprintf(info, "%s %5s %4d %4d", s->filename, depths[s->info.depth], s->x, s->y); } else { fprintf(info, "%s %5s %4d %4d %4d %4d %4d %4d %s", s->filename, depths[s->info.depth], s->x, s->y, s->info.xdim, s->info.ydim, s->info.xrel, s->info.yrel, zoom_levels[s->info.zoom]); if (HASTRANSPARENCY(s->info.info)) fputs(" chunked", info); if (DONOTCROP(s->info.info)) fputs(" nocrop", info); } } else { fprintf(info, "%s %d %d %02X %d %d %d %d", s->filename, s->x, s->y, s->info.info, s->info.ydim, s->info.xdim, s->info.xrel, s->info.yrel); } fputs("\n", info); break; } case Box::isdata: { fprintf(info, "%5d ", spriteno++); BoxData *d = (BoxData*)boxes[i]; int instr = 0; int count = 0; if (d->data[0] == 0xff && d->size>4 && spriteno>1) { // binary include file int namelen = d->data[1]; int len = strlen(this->directory) + namelen + 1; char *filename = new char[len]; snprintf(filename, len, "%s%s", this->directory, (char*) d->data + 2); // Strip trailing whitespace int last = 0; for (int j=0; jdata+3+namelen, d->size-3-namelen, 1, bin); delete[]filename; fclose(bin); } else { fprintf(info, "* %d\t", d->size); for (j=0; jsize; j++) { // Readable characters are 32..126 and 158..255 #define istxt(x) (j+(x)size && ((d->data[j+(x)]>=32 && (_useexts || d->data[j+(x)] != 34) && d->data[j+(x)]<127) || d->data[j+(x)] > 158)) //int thistxt = (d->data[j] >= 32 && d->data[j] < 127) || d->data[j] > 158; //int nexttxt = j+1size && ((d->data[j+1]>=32 && d->data[j+1]<127) || d->data[j+1] > 158); if (spriteno>1 && istxt(0) && useplaintext && (instr || //two in a row for 8 and E (istxt(1) && (d->data[0]==8 || d->data[0]==0xE || //four in a row for everything else. (istxt(2) && istxt(3)) )) )) { if (!instr) { fputs(" \"", info); instr = 1; } if(_useexts && d->data[j]=='\\') fputs("\\\\", info); else if(_useexts && d->data[j]=='"') fputs("\\\"", info); else fputc(d->data[j], info); } else { if (instr) { fputs("\"", info); instr = 0; } uint k=0; if (_useexts == 2 && spriteno>1) { for(;kdata[j]&& escapes[k].action==d->data[0]&& (escapes[k].override?escapes[k].override(d->data,j):escapes[k].pos==j)&& (escapes[k].additional==NULL||escapes[k].additional(d->data,d->size))){ fprintf(info," %s",escapes[k].str); break; } }else k = num_esc; if(k==num_esc) fprintf(info, " %02X", d->data[j]); } // break lines after 32 non-text characters // or at spaces after 32 text characters or // after 60 text characters count++; if ( ((!instr && count>=32) || (instr && ((count>=32 && d->data[j]==' ') || count>=50))) && jsize-1) { if (instr) { if(istxt(1)){ fputs("\"\n\t \"", info); }else{ fputs("\"\n\t", info); instr = 0; } }else fputs("\n\t", info); count = 0; } } if (instr) fputs("\"", info); fputs("\n", info); } free(d->data); break; } default: printf("\nHuh? What kind of box is that?\n"); exit(2); } } boxnum = 0; for (i=0; i= maxboxes) resize(maxboxes*2); boxes[boxnum++] = new BoxSprite(first, filename, x, y, info); } void infowriter::adddata(uint size, U8 *data) { if (boxnum >= maxboxes) resize(maxboxes*2); boxes[boxnum++] = new BoxData(size, data); } void infowriter::done(int count) { if (count != spriteno) { fprintf(stderr, "\nError: GRFCodec thinks it has written %d sprites but the info file only got %d\n", count, spriteno); exit(2); } } grfcodec-6.0.3/Makefile0000644000000000000000000002157112171043637013444 0ustar rootroot# ========================================================= # Makefile for the GRF development tools # # Don't put any local configuration in here # Change Makefile.local instead, it'll be # preserved when updating the sources # ========================================================= PACKAGE_NAME = grfcodec -include Makefile.local # Gnu compiler settings SHELL ?= /bin/sh CXX ?= g++ STRIP ?= UPX ?= AWK ?= awk SRCZIP_FLAGS ?= -9 SRCZIP ?= gzip LIBPNG_CONFIG?= libpng-config # OS detection: Cygwin vs Linux ISCYGWIN ?= $(shell [ ! -d /cygdrive/ ]; echo $$?) MACHINE ?= $(shell $(CXX) -dumpmachine || echo '??' ) # OS dependent variables EXE ?= $(shell ( [ \( $(ISCYGWIN) -eq 1 \) -o \( "$(MACHINE)" = "mingw32" \) ] ) && echo .exe) GRFCODEC ?= grfcodec$(EXE) GRFDIFF ?= grfdiff$(EXE) GRFMERGE ?= grfmerge$(EXE) GRFID ?= grfid$(EXE) GRFSTRIP ?= grfstrip$(EXE) NFORENUM ?= nforenum$(EXE) ENDIAN_CHECK ?= endian_check$(EXE) TYPESIZE ?= GCC32 # Somewhat automatic detection of the correct boost include folder ifndef BOOST_INCLUDE BOOST_INCLUDE=$(shell \ find /usr/include /usr/local/include /opt/local/include -maxdepth 1 -name 'boost-*' 2> /dev/null | sort -t - -k 2 | tail -n 1 ) ifeq ($(BOOST_INCLUDE),) BOOST_INCLUDE=$(shell \ ( [ -d /usr/include/boost/date_time ] && echo /usr/include ) || \ ( [ -d /usr/local/include/boost/date_time ] && echo /usr/local/include ) || \ ( [ -d /opt/local/include/boost/date_time ] && echo /opt/local/include ) ) endif endif ifeq ($(BOOST_INCLUDE),) BOOST_ERROR = echo Error: Boost not found. Compilation will fail. endif ifndef V V=0 # verbose build default off endif ifndef FLAGS ifeq ($(ISCYGWIN),1) FLAGS = -I $(BOOST_INCLUDE) -O2 else FLAGS = -idirafter$(BOOST_INCLUDE) -O2 endif FLAGS += -D$(TYPESIZE) -D_FORTIFY_SOURCE=2 FLAGS += -Wall -Wno-uninitialized -Wsign-compare -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wformat=2 ifeq ($(DEBUG),1) FLAGS += -DDEBUG endif ifeq ($(MACHINE),mingw32) FLAGS += -DMINGW endif # Sadly enough fmemopen is ifneq ($(shell grep fmemopen /usr/include/stdio.h 2> /dev/null | wc -l | sed "s/ *//"),0) ifndef NO_FMEMOPEN FLAGS += -DWITH_FMEMOPEN endif endif ifeq ($(shell uname),Darwin) FLAGS += -isystem/opt/local/include endif # GCC 4.5.0 has an optimisation bug that influences GRFCodec. # As such we disable optimisation when GCC 4.5.0 is detected. # The issue has been fixed in GCC 4.5.1 ifneq ($(shell $(CXX) -v 2>&1 | grep "4\.5\.0" || true),) FLAGS += -O0 endif # Complication of png support in grfcodec ifneq ($(shell $(LIBPNG_CONFIG) --version 2>/dev/null),) WITH_PNG = 0 FLAGS += -DWITH_PNG $(shell $(LIBPNG_CONFIG) --cflags) endif endif MY_CXXFLAGS ?= $(FLAGS) $(CXXFLAGS) # ======================================================================= # setup verbose/non-verbose make process # ======================================================================= # _E = prefix for the echo [TYPE] TARGET # _C = prefix for the actual command(s) # _I = indentation for sub-make # _Q = number of 'q's for UPX # _S = sub-makes silent? ifeq (${V},1) # verbose, set _C = nothing (print command), _E = comment (don't echo) _C= _E=@\# _Q=-qq _S= else # not verbose, _C = @ (suppress cmd line), _E = @echo (echo type&target) _C=@ _E:=@echo ${_I} _Q=-qqq _S=-s endif # increase indentation level for sub-makes _I := ${_I}" " export _I # standard compilation commands should be of the form # target: prerequisites # ${_E} [CMD] $@ # ${_C}${CMD} ...arguments... # # non-standard commands (those not invoked by make all/dos/win) should # use the regular syntax (without the ${_E} line and without the ${_C} prefix) # because they'll be only used for testing special conditions # # ======================================================================= # sources to be compiled and linked GRFCODECSRC=grfcomm.cpp pcxfile.cpp sprites.cpp pcxsprit.cpp pngsprit.cpp \ info.cpp globals.cpp mapescapes.cpp error.cpp path.cpp readinfo.cpp \ file.cpp grfcodec.cpp GRFDIFFSRC=grfcomm.cpp error.cpp sprites.cpp grfdiff.cpp path.cpp GRFMERGESRC=grfcomm.cpp error.cpp grfmerge.cpp path.cpp GRFIDSRC=grfid.cpp md5.cpp GRFSTRIPSRC=grfstrip.cpp NFORENUMSRC=IDs.cpp act0.cpp act123.cpp act123_classes.cpp act5.cpp act6.cpp \ act79D.cpp actB.cpp actF.cpp act14.cpp command.cpp data.cpp globals.cpp \ inject.cpp messages.cpp pseudo.cpp rangedint.cpp nforenum.cpp sanity.cpp \ strings.cpp utf8.cpp help.cpp message_mgr.cpp language_mgr.cpp \ mapescapes.cpp pseudo_seq.cpp PALORDER = ttd_norm&ttw_norm&ttd_cand&ttw_cand&tt1_norm&tt1_mars&ttw_pb_pal1&ttw_pb_pal2 PAL_FILES = pals/$(subst &,.bcp pals/,$(PALORDER)).bcp # deafult targets all: $(GRFCODEC) $(GRFDIFF) $(GRFMERGE) $(GRFID) $(GRFSTRIP) $(NFORENUM) remake: $(_E) [CLEAN] $(_C)$(MAKE) ${_S} clean $(_E) [REBUILD] $(_C)$(MAKE) src/version.h src/endian.h $(_C)$(MAKE) ${_S} all $(GRFCODEC): $(GRFCODECSRC:%.cpp=objs/%.o) $(_E) [LD] $@ ifdef WITH_PNG $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) $(shell $(LIBPNG_CONFIG) --ldflags) else $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) endif $(GRFDIFF): $(GRFDIFFSRC:%.cpp=objs/%.o) objs/grfmrg.o $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) $(GRFMERGE): $(GRFMERGESRC:%.cpp=objs/%.o) $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) $(GRFID): $(GRFIDSRC:%.cpp=objs/%.o) $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) $(GRFSTRIP): $(GRFSTRIPSRC:%.cpp=objs/%.o) $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) $(NFORENUM): $(NFORENUMSRC:%.cpp=objs/%.o) $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) clean: $(_C)rm -rf objs $(GRFCODEC) $(GRFDIFF) $(GRFMERGE) $(GRFID) $(GRFSTRIP) $(NFORENUM) bundle bundles grfcodec-* src/endian.h mrproper: clean $(_C)rm -f src/version.h src/grfmrg.cpp $(_C)touch -ct 9901010000 ttdpal.h # don't delete it, so we don't confuse version control, but force it to be remade distclean: mrproper $(_C)rm -rf Makefile.local FORCE: @$(BOOST_ERROR) include version.def src/version.h: FORCE @echo // Autogenerated by make. Do not edit. Edit version.def or the Makefile instead. > $@.tmp @echo "#define VERSION \"$(VERSIONSTR)\"" >> $@.tmp @echo "#define YEARS \"2004-$(YEAR)\"" >> $@.tmp @(diff $@.tmp $@ > /dev/null 2>&1 && rm -f $@.tmp) || (rm -f $@ ; mv $@.tmp $@) objs/$(ENDIAN_CHECK): src/endian_check.cpp $(_C) mkdir -p objs $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) src/endian_check.cpp $(LDOPT) src/endian.h: objs/$(ENDIAN_CHECK) $(_E) [ENDIAN] Determining endianness $(_C)objs/$(ENDIAN_CHECK) $(ENDIAN_PARAMS) > src/endian.h || rm src/endian.h FORCE: %_r: FORCE $(_E) [REBUILD] $(@:%_r=%) $(_C)rm -f $(@:%_r=%) $(_C)$(MAKE) ${_S} $(@:%_r=%) ifneq ($(STRIP),) $(_E) [STRIP] $(@:%_r=%) $(_C)$(STRIP) $(@:%_r=%) endif ifneq ($(UPX),) $(_E) [UPX] $(@:%_r=%) $(_C)$(UPX) $(_Q) --best $(@:%_r=%) endif .NOTPARALLEL release: FORCE $(GRFCODEC)_r $(GRFDIFF)_r $(GRFMERGE)_r $(GRFID)_r $(GRFSTRIP)_r $(NFORENUM)_r # make grfmerge.exe (as grfmrgc.bin) optimized for size instead of speed objs/grfmrgc.bin: objs/grfmerge.os $(GRFMERGESRC:%.cpp=objs/%.os) $(_C)rm -f $@ $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) -Os $^ ifneq ($(STRIP),) $(_E) [STRIP] $@ $(_C)$(STRIP) $@ endif ifneq ($(UPX),) $(_E) [UPX] $@ $(_C)$(UPX) $(_Q) --best $@ endif src/grfmrg.cpp: objs/grfmrgc.bin src/grfmrgc.pl $(_E) [PERL] $@ $(_C)perl -w src/grfmrgc.pl > $@ src/ttdpal.h: $(PAL_FILES:%=src/%) src/pal2c.pl $(_E) [PERL] $@ $(_C)perl src/pal2c.pl $(PAL_FILES:%=src/%) > $@ # Gnu compiler rules objs/%.o : src/%.cpp Makefile $(_E) [CPP] $@ $(_C)$(CXX) -c -o $@ $(MY_CXXFLAGS) -MMD -MF $@.d -MT $@ $< % : objs/%.o Makefile $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) $(_C)$(CP_TO_EXE) # same as above but optimized for size not speed objs/%.os : src/%.cpp Makefile $(_E) [CPP] $@ $(_C)$(CXX) -c -o $@ $(MY_CXXFLAGS) -Os -MMD -MF $@.d -MT $@ $< % :: objs/%.os Makefile $(_E) [LD] $@ $(_C)$(CXX) -o $@ $(MY_CXXFLAGS) $^ $(LDOPT) # On some installations a version.h exists in /usr/include. This one is then # found by the dependency tracker and thus the dependencies do not contain # a reference to version.h, so it isn't generated and compilation fails. objs/grfcodec.o: src/version.h objs/grfmerge.o: src/version.h objs/grfmerge.os: src/version.h objs/grfdiff.o: src/version.h objs/grfid.o: src/version.h objs/grfstrip.o: src/version.h objs/message_mgr.o: src/version.h objs/messages.o: src/version.h objs/%.o.d: src/%.cpp Makefile src/endian.h $(_E) [CPP DEP] $@ $(_C)$(CXX) $(MY_CXXFLAGS) -DMAKEDEP -MM -MG src/$*.cpp -MF $@ ifndef NO_MAKEFILE_DEP -include $(GRFCODECSRC:%.cpp=objs/%.o.d) -include $(GRFMERGESRC:%.cpp=objs/%.o.d) -include $(GRFDIFFSRC:%.cpp=objs/%.o.d) -include $(GRFIDSRC:%.cpp=objs/%.o.d) -include $(GRFSTRIPSRC:%.cpp=objs/%.o.d) -include $(GRFMERGESRC:%.cpp=objs/%.os.d) -include $(NFORENUMSRC:%.cpp=objs/%.o.d) endif include Makefile.bundle grfcodec-6.0.3/Makefile.local.sample0000644000000000000000000000265512027143046016012 0ustar rootroot# ========================================================= # Local Makefile settings for the GRF development tools # ========================================================= # Copy this file to Makefile.local (if make didn't do it for you) # and edit to modify the settings # If the boost folder auto-detection fails, set your boost include folder here. # If boost can be found in your standard include search paths, setting this to # any non-empty value will cause make to assume that boost is present. #BOOST_INCLUDE = # Gnu compiler settings #SHELL = /bin/sh #CXX = g++ #STRIP = strip #UPX = upx #AWK = awk #SRCZIP_FLAGS = -9 #SRCZIP = gzip # use 386 instructions but optimize for pentium II/III #MY_CXXFLAGS = -g -DWIN32 -O1 $(BOOST_INCLUDE) -Wall -Wno-uninitialized $(CXXFLAGS) #LDOPT = -g -Wl,--subsystem,console -luser32 -lgdi32 -lwinmm -lcomdlg32 -lcomctl32 #LDOPT = -Wl,--subsystem,console,-s #LDOPT += -Wl,-Map,$(@:%=%.map) # to make map files # for profiling #MY_CXXFLAGS += -pg #LDOPT += -pg # to pass the right 'type' sizes to typesize.h #TYPESIZE = GCC32 #TYPESIZE = GCC64 #TYPESIZE = WIN32 # Use one of the following to force big endian or little endian. # You might need to clean before it takes effect. #ENDIAN_PARAMS = BE #ENDIAN_PARAMS = LE # Several options to influence the installation of documentation #DO_NOT_INSTALL_DOCS = 1 #DO_NOT_INSTALL_CHANGELOG = 1 #DO_NOT_INSTALL_LICENSE = 1 #DO_NOT_INSTALL_MAN = 1 grfcodec-6.0.3/changelog.txt0000644000000000000000000014420612171043637014475 0ustar rootrootChanges in 6.0.3 (2013-07-15) - NFORenum specific changes: - Data file updates - Action 4 language ID 0x13 (Scottish Gaelic). - Action D patch variables 15 and 16. - Action 5, type 15 (OpenTTD GUI): Now 174 sprites are allowed - GRFcodec specific changes: - Fix container v2 include sprite decoding. - Fix encoding from interlaced png images. - GRFID specific changes: - Fix number of crashes caused by corrupted NewGRFs Changes in 6.0.2 (2013-01-06) - NFORenum specific changes: - Data file updates - Base costs. - Action5 type 15. - GRFcodec specific changes: - Fix encoding container v1 wrt. maximum size of verbatim data. - Fix container v2 tile decompression. Changes in 6.0.1 (2012-09-21) - NFORenum specific changes: - Data file updates - Action 0 station property 1A. - Action 2 global variables 06, 0B..0F, 13..16, 1E, 21, 22. - Action 2 train variables 4C, 61, 62. - Action 2 road vehicle variables 4B, 4C, 61, 62. - Action 2 ship variables 4B, 4C. - Action 2 aircraft variables 4B, 4C. - Action 5 type 15. - Callback 15F. - Add RPN calculations; the RPN expression is replaced by the calculated value. - GRFcodec specific changes: - Fix reading/writing the size value for pseudo sprites so pseudo sprites actually work with container v2. - Reject pseudo sprites that are too large for container v1 when not compiling v2. - Do not write incomplete sprites when the maximum height of output images is limited. - Fix reading incorrect graphics when multiple graphics are provided for a sprite and writing a GRF container version 1 GRF and the y position decreases. - Fix decoding of regular encoded 32bpp sprites. - Print appropiate error message when trying to decode unsupported colour depth formats. Changes in 6.0.0 (2012-03-05) - NFO version 32 for supporting GRF container version 2. - GRF container version 2 with bigger sprites and multiple images (bit depth and zoom level) for real sprites. - GRFID now has a command line option to create the (OpenTTD) MD5 checksum of a NewGRF. For GRF container version 2 NewGRFs this means the MD5 checksum of the header and data sections. - GRFCodec specific changes: - Command line option -n that determines the best compression for sprites during compilation. This could improve compression - NFORenum specific changes: - Data file updates - Action 0 airport property 11. - Action 0 railtype properties 1C and 1D. - Action 0 aircraft property 1F. - Action 0 cargo property 1D. - Action 2 railtype variable 44. - Action 4 language ID 0x3D (Australian). - Action 5 type 17/97. - Action 5 type 15/95. Changes in 5.1.3 (2011-12-19) - GRFCodec specific changes: - Fix creation of PNG as some versions of libpng would see the generated PNG as corrupt. - NFORenum specific changes: - Data file updates - Action 0 train property 2B. - Action 0 road vehicle properties 22 and 23. - Action 0 ship properties 1D. - Action 0 aircraft property 1C. - Action 0 railtype property 1B. - Action 2 callback 15E. - Action 2 vehicle variable 4B. - Action 8 GRF version 8. - Action D patch variable 14. - Support for font size 3 (monospaced font). Changes in 5.1.2 (2011-10-07) - NFORenum specific changes: - Data file updates - Action 3 canals ID 8. - Action 5 type 15 takes 0xA2 sprites. - Action 5 types 84, 85, 86, 88, 89, 8A, 8B, 8F, 90, 91, 92 and 93 - Support the advanced sprite layout in action2. - Fix action 14 palette checking on BE machines. - Disable warning 209 when checking action 0 raw ('l') data. Changes in 5.1.1 (2011-03-19) - GRFCodec specific changes: - Make PNG the default output sprite sheet format if libpng is found. - NFORenum specific changes: - Data file updates - Action 0 rail types properties 17..1A. - Action 4 language ID 0x12 (Faroese). - Action 2 station variable 67 is dword sized. - Add support for variable 7B. - Warn if the palette is not specified via an Action 14. Changes in 5.1.0 (2010-12-10) - Add support for PNG formatted sprite sheets with both encoding and decoding (requires libpng). - NFORenum specific changes: - Data file updates - Action 0 road vehicle property 21. - Action 0 ship property 1C. - Action 0 cargo properties 1B, 1C. - Action 0 general variable properties 13..15. - Action 0 object property 17. - Action 2 object variables 43, 47, 48. - Callback 10 works for road vehicles and ships as well. - Add support for string code 9A 0D..9A 15. - Change format of some warning messages to provide more information. - Fix stack validator triggering a (wrong) assert - For operating systems where fmemopen is supported the data files and its directory are not created by default anymore. - GRFCodec specific changes: - Prevent pcxfile::expirelines from reading more lines than the spritesheet has. - Fix several mismatched delete/free valgrind warnings. - Fix possible reading beyond a buffer causing crashes. Changes in 5.0.0 (2010-10-17) - Merge the source packages of GRFCodec (1.0.0) and NFORenum (4.0.0). This means that this package now requires Boost 1.36 or higher. - Add command line option to silence all progress output. - Add command line option to refresh all data files. - Fix Cygwin compilation issues. - Fix UPX-ing of release binaries under some circumstances. - Fix difference between GRFCodec and NFORenum escapes format. - (devel) Fix putting version.def twice in the source bundle. - (devel) Use directories from the Make conventions for installation directories and add a few "parameters" to disable installation of certain bits of documentation. - (devel) Disable strip and UPX as default. - (devel) Add make distclean that removes Makefile.local as well. - NFORenum specific changes - Data file updates - Action 0 objects properties 11..16. - Action 2 variable 5F had wrong length for most features. - Action 2 objects variables 42, 44..46, 5F, 60..64. - Action 2 callbacks 157..15D. - Action 5 type 15. - Action D patch variables 12, 13. - Add support for reading the (Action 14) version of other NewGRFs via Action D parameter 7E. - Fix bogus warning when using \d in an action 2 for features 7/9/F. - Fix returning a non-zero exit code upon an unrecognised command line option. - GRFCodec specific changes - Add filename to a number of PCX related error messages. - Fix cropping did not work on big endian architectures. ===== GRFCodec before the merge ===== Changes in 1.0.0 (2010-08-14) - (devel) Complete rewrite of installation of binaries, so if you are packaging this you will have to check whether custom installation and such are still needed or that the Makefile does handle it correctly. - (devel) Detect UPX, fix some race issues in the Makefile, disable optimization if GCC 4.5.0 is detected (to work around an optimization bug), fix version.h generation if there is a version.h in /usr/include. - (devel) Fix a number of compiler warnings. - Clamp the arguments for -w and -h to 65535 as that is the maximum size of a PCX. - Fix reading of PCX files with more bytes per scanline than pixels. (This is the case for odd image widths when following the PCX standard closely.) - Silence progress-meter output when stdout is not a console. - Unify warnings and errors so they go to stderr and are prefixed by "Warning:" or "Error:". - Allow hex escapes that have bit 31 set. - Fix comments not prefixed by whitespace could cause grfcodec to reject the preceding escape. - After cropping a sprite, compress and write the correct number of bytes. - Add -X to print PCX sprite numbers in hex - (devel) Many compilation issues with different compilers and architectures. - Fix bug in UTF-8 generation for escapes \U800..\U7FFF. - Fix U+E0xx characters being output quoted. - (devel) By Tron: code cleanup, make C functions and variables static where possible, remove dead and debugging code. - Require two slashes before dismissing anything as a C++ style comment. - Fix reading of real sprites with Unixy absolute paths. - Check for pixels with palette index of 255 when encoding. - Add -v to get the version. - Add -q to silence warnings. - Add -c to automatically crop extraenous transparent blue pixels. - Add escapes for the new action 2 operations 0E, 0F, 10, 11, 12, 13, 14, 15, 16 - Prevent quotes and escapes in sprite 0. - Add escapes for long-format intro dates. Changes in 0.9.10 (svn r819) - (bugfix) Correct reading of \7c, \7C, \D| and \D&. (DaleStan) Changes in 0.9.9 (svn r653) - By Patchman: - Check for sprites that extend beyond the end of the PCX file. - Update versioning system to show last-comitted revision for non-release builds. - By DaleStan: - (devel) Add release targets to the Makefiles - Check the palette of the PCX file before encoding from it. (Override a failed check with -f) - Introduce several backslash escape sequences; see the wiki for further information. (disable with -x or -xx) - Do not apply colormap to sprites that like character glyphs. (Apply colormap to all sprites with -M instead of -m) - Enable reading of GIMP palette files with -p. - (devel) Terse build mode; get the verbose mode with make V=1. - (devel) Touch version.h if and only if it changes. Changes in 0.9.8 (svn r197) - By DaleStan: - (devel) grfcodec (but not grfdiff or grfmerge) can now be built in MS Visual Studio 2003. - Slightly change the plaintext quoting algorithm. - (devel) Change several memcpy()s to pointer assignments. - (devel) Plug several memory leaks - (devel) Source code and Makefile changes to grfdiff and grfmerge build with both Makefiles, on both Cygwin and Linux. - Make code gcc 4 -Wall clean. - Use NFORenum's NFO reading engine: - Sprite numbers are now optional, and need not be correct if present. - Sprite lengths need not be correct. Set to 0 to supress the incorrect length warnings. - Real sprites are checked for format compliance. - Make 0-byte pseudo sprites an error. - (bugfix) Prevent binary includes from including directories on OSes that would othewise allow it. - (bugfix) It is now possible for a real sprite to start above the preceeding sprite (the infamous decreasing ypos bug) - grfcodec now exits with 0 on success. Changes in 0.9.7 - support including binary files using " 4 ** data/dingdong.wav" syntax - by Oskar: support // and # comments within pseudo-sprites - fixed incorrect error message while encoding if .nfo file could not be read (now it reports "Cannot read %s" instead of Creating sprites/: File exists") - made code -Wall clean - remove myalloc stuff Changes in 0.9.6 - by pasky: * made it possible to compile grfcodec on Linux * made compatible with gcc 3.x * when decoding, text strings are written in plain text (disable with -t) * supports plain text in .nfo files * fixed bug when first encoding a grf file wouldn't rename .new to .grf Changes in 0.9.5 - self-extracting executables now work on Win2K etc., which doesn't pass the full path to the C library - GRFMerge will just skip .grf files it can't find - making sprites larger doesn't work if they're at the right edge; complains that ofsx too large; instead just use background colour - GRFDiff doesn't like grfdiff -l 1254 ... (single value in -l), complains that there were no differences and makes no output - allow GRFMerge to read GRFDiff's .exe files, both for -l and other options Changes in 0.9.4 - fixed yet another crash while compressing - sprites no longer need correct numbers in the .NFO file; just use "-1" for each number and it will be assumed to be correct Changes in 0.9.3 - fixed crash due to buffer overrun while compressing - slightly improved compression efficiency and speed - GRFCodec now handles spaces in file/directory names properly - GRFCodec now supports comments in .NFO files (from //, ; or # to end of line) - speed up PCX processing Changes in 0.9.2 - fixed crash if pcx file not found - fixed crash if nfo file has no version info header Changes in 0.9.1 - bug fix by Marcin: wrong order of test in encode function Changes in release April 20 2002 - -p now actually uses the parameter you give it Changes in release Dec 03 2001 - made -p option a valid option - improve compression speed even more using assembly optimizations - compression is now on by default, disable with -c- - fixed bug where encoding would fail if the grf file didn't exist already - fixed bug where decoding would fail creating the sprites directory - corrected some mistakes in grf.txt (checksum, and initial offsets for tiles) Changes in release March 26 2001 - fix bug that didn't flush last row if it only contained a single sprite - fix bug with no height given (would make PCX have height -1) - show percentage done while decoding - fix compression algorithm - improve compression performance - try without compression if data is inconsistent after decompressing our compressed data (this shouldn't happen anymore anyway, report it as a bug if it does) - -p to choose palette Changes before release March 26 2001 - I don't remember anymore ===== NFORenum before the merge ===== v3.4.6 to 4.0.0 (2010-08-14) - Change rename "renum" to "nforenum" including ".renum" to ."nforenum" so the name is less generic and the same as in several downstreams. You might need to update your development environment / build scripts. - (devel) Complete rewrite of installation of binaries, so if you are packaging this you will have to check whether custom installation and such are still needed or that the Makefile does handle it correctly. - Data file updates: - Enable actions 1..3 for airports, newobjects, railtypes and airport tiles. - Action 0 train prop 1A (change to extended byte). - Action 0 road vehicle prop 20, - Action 0 ship prop 1B. - Action 0 plane prop 1B. - Action 0 general variable properties 08, 11, 12. - Action 0 house props 21..22. - Action 0 bridge props 00, 10..13. - Action 0 airport properties 08..0A, 0C..10. - Action 0 object properties 0B..10. - Action 0 railtype properties 08..16. - Action 0 airport tile properties 08, 09, 0E..11. - Action 2 operators 14, 15, 16 - Action 2 variables 12, 1D, 23, 24, 25. - Action 2 vehicle variable 49, 4A. - Action 2 stations: fix parameter limits on station var 60. - Action 2 house variable 47, 65, 66, 67. - Action 2 industry variable 46. - Action 2 objects variable 40..43. - Action 2 railtype variable 40..43, 80. - Action 2 airport tile variable 40..44, 60..62. - Action 2 station random bits: only 14h, not 20h bits are available. - Action 2 object random bits. - Action 2 canal random bits. - Action 2 railtype random bits. - Action 2 airport tile random bits. - Action 2 callback 149 works for objects. - Action 2 callbacks 14D..150, 152..154. - Action 5 types 07, 0D, 14, 15, 16. - Action 4 text IDs F960..F99A. - Action 4 twenty three new languages. - Action 7 variables A2..A4. - Action D variables A1..A4 were not readable. - Fix U+E0xx characters being output quoted. - Fix a hang when parsing non-UTF-8 quoted strings. - Fix parameter parsing of stringcode 9A 04. - Fix complaints about both params of action D operator 80 being FF. - Fix assert when encountering end-of-line "comments" that begin with a single forward slash. - Fix assert when $HOME ends with a slash. - Fix comments not prefixed by whitespace could cause NFORenum to reject the preceding escape. - Fix color codes in action 8 are permitted. - Fix a 64-bit sign-extension vs zero-extension crash. - Fix an action0 with no IDs caused a hang of NFORenum. - Fix the error message "A portion of sprite xx could not be processed." reported the sprite before the one with the error. - Fix a warning on newobject's buy menu sprite cargo type. - Fix warning message about exceeded limits of bounding boxes. - Fix bogus warnings when defining a range strings and then referring to a string in the middle of that range. - Remove warning 135 (first sprite cannot share bounding box with previous sprite) as it's no longer a valid warning since both openttd and ttdpatch support multiple ground sprites - Add -v to get the version. - Make -w/-W work the way it is supposed to. - Make NFO error/warning messages go to stderr. - Allow the beautifier to output escape sequences. - Allow extended byte IDs in actions 3 and 4. - Allow hex escapes that have bit 31 set. - Allow bit 7 of the operation byte to be set when reading patch variables and other GRF parameters in action D. - 0.dat can now specify that certain properties may exist multiple times in an action 0. - Check action 3s for cargos that are specified twice. - Add escapes for the new action 2 operations 10, 12, 13, 14, 15 and 16. - Support bridge IDs 0B and 0C. - Support random 2 type 84. - Support string codes 9A 06, 9A 07, 9A 08, 9A 0B, 9A 0C. - Support action 7/9 condition types 0D and 0E. - Support action 14. - (devel) Can no longer build without boost. - (devel) Detect UPX and make strip optional. - (devel) Race and bash-ism issues with the Makefile. - (devel) Fix numerous compile warnings and harden NFORenum. v3.4.5 to v3.4.6 (svn r1795) - Data file updates: - Industry texts may have arbitrary text-stack data. - Action D patch variable 11. - Action 5 types 0F..12. - Action 5 type 07 takes 75 sprites. - Languages: Esperanto, Bulgarian, Japanese, Korean - House property 1F, 20. - Canal properties 08, 09. - Canal IDs 05..07. - Industry variables 44, 45, 68. - Mark variable 81 as readable in actions 7 and D. - Text IDs F945..F95F. - Adv. action 2 ops 11..13 - House variable 63, 64. - Station variables 67, 68, 69. - Station variables 60..65 can take a parameter up to FF. - Callbacks 147..14C. - Industry properties 23, 24. - Action 7 variable A1. - Action B message 06. - Canal variables 82..83. - Fix parameter check for global 60+x variables. - Allow variational 2s to take var 1A with an of 0. - Check that variational 2 operator 0F's left-hand side side was stored. - Prohibit storing to persistent registers when they don't exist. - Fix several bugs in the formatting of variable-length properties. - Check cargo types against the cargo translation table. - Add \2ror and \2rot for Adv2 op 11. - Add \d and \d to generate long format intro dates. - Support the extended action 5 format. - Add support for string codes 9A 01 through 9A 04. v3.4.4 to v3.4.5 (svn r1396) - Data file updates: - New signals. - Variable 20. - Text IDs F941..F944. - Fix yet more array index vs char* problems. - Add offset info to a message that failed to have it. - Ensure that VERSIONCHECK gets its required two arguments. - Fix version 1 industry production callback support. - Support Action 7/9's new GRFID/mask format. - (minime) Allow @@LET variables to be redefined. v3.4.3 to v3.4.4 (svn r1350) - Data file updates: - Variable 7D. - Industries do not use GRM. - Industry tile variable 62. - Industry variables 43, 65, 66, 67, 7C. - New objects properties. - Make unknown action 5 types look for real sprites or recolor sprites. - Recognize action 2 operations 0E and 0F. - Catch Action Fs that chain to themselves. - Add escapes for the new action 2 operations 0E and 0F. - Support new signals. (Actions 5, variational 2, and 3.) - Process var. and random 2s and action 3 even when the feature is not recognized. - (fix) Don't correct the feature of a var. or random 2 to match the preceding action 1. - Industry production callback version 1. - Produce a useful error message when data files are out of sync with each other. - Variational action 2 operator 10. - Make --data also report the data-file location. - Check for duplicate IDs in an action 3. - Check that prop 08 has been set before the action 3, when necessary. v3.4.2 to v3.4.3 (svn r1244) - Permit Action 1/2/3 for bridges (Callback 33) - Data file updates: - Articulated RV callbacks and variables. - The long date properties - (fix) Station prop 18 is a word, not a byte - (fix) Callbacks 140..142 are for stations. - Action 7/9 variable 9A. - Version 2.5 beta 9. - TextIDs F90A..F940. - Add $HOMEDRIVE$HOMEPATH to the list of search paths for .renum/ - Allow multiple sizes for some action 7/9 variables. - Accept GRF version 7 lang-id bytes in action Bs that precede the action 8. - Allow Action 6 entries with bit 7 set. v3.4.1 to v3.4.2 (svn r1057) - Data file updates: - Callback 144 - Callback 145 - Action B messages 04 & 05 - New action 5 sprites for trams and the GUI - Action 13 - (bugfix) Enable autocorrection for feature 0B (cargo) action 4s - Require two slashes before dismissing anything as a C++ style comment. - Fix reading of real sprites with Unixy absolute paths. - Add check for B/W/Ds of 0 in varaction 2s. - Fix off-by-one error when checking block extents in Action 12. v3.4.0 to 3.4.1 (svn r820) - Check that in GRF version 6, Action F declares names for all five standard languages. - (bugfix) Slight change to action F formating, for increased consistancy. - Prevent the beautifier from adding newlines after the end of a sprite. - Fix: Version number is revision in hex digits, not converted to hex. - Fix: LOCATEID2 now reports the correct feature byte. - Data file updates: - Version 2.5 beta 8 - Callback 143 - (bugfix) Correct reading of \7c, \7C, \D| and \D&. v3.3.1 to v3.4.0 (svn r688) - (devel) Can now make the version without \w with NO_BOOST=1. - (devel) By Patchman: non-release versions show last-committed revision, not repository revision. - Added support for: - Industry variable 64. - String code 94. - Variable 7E (procedure calls). - Added 2.r format for @@VERSIONCHECK. - Added a missing check for 00 byte following string code 99. - (devel) Terse build mode. - Corrected handling of action 2 CargoIDs; all share the same table. - Added offset info to the variational 2 messages that didn't have it. - (bugfix) No longer crashes when an industry production callback is not 15 bytes long. - (autocorrect) Feature byte for actions 2 and 3. - Made optional in most commands taking . - Fixed two over-long lines in the --help message. - (devel) Removed Boost headers from Makefile.dep. - Remove warning about moving to a smaller ypos. - Added check for second use of a single bit in Action F. - (bugfix) Action Fs that try to use too many bits now report the correct and , instead of having them swapped. - (bugfix) Fix parsing of quoted \##. v3.3.0 to v3.3.1 (svn r320) - Recognize Info version 7. - Warn about generic action 4s that declare no texts. - More auto-corrector changes: - Append an FF to action 6s. - Append a 00 to strings. - @@BEAUTIFY CONVERTONLY now converts hex to "strings", not "s" "t" "r" ... - (bugfix) Action4s declaring texts for language FF could cause NFORenum to abort. v3.2.1 to v3.3.0 (svn r284) - Add an auto corrector, which will attempt to correct some portions of some pseudo-sprites when enabled. (See README) - (bugfix) Specifying -f could potentially cause undefined behaviour. - Allow + and - in more places on the commandline. Specifically, in eg "-b convertonly+", rather than just "-b-". - (devel, docs) fixed release scripts that caused breakage in the 3.2.1 docs, and repaired the breakage. - Also check for embedded 00 bytes after the 01 and 1F control characters. - Add a length-check for actions 7 and 9. - Produce more useful and reliable messages when a file-system-related call fails. - If the input file can't be deleted, report about that, instead of just reporting that the rename failed. - Check that action 7/9 don't jump past the end of the file. - (bugfix) Fix an issue creating the .renum folder on Win9x - Update langs.dat for the new languages. - (bugfix) Warn about action 4s that declare no texts, rather than dying. v3.2.0 to v3.2.1 (svn r187) - @@USEOLDSPRITENUMS - @@DEFINEID2 - @@LOCATEID2 - @@TESTID2 - (bugfix) Error message when Action B contains an invalid parameter now reports correct offset and parameter. - Check for including textIDs with a 00 byte. - (bugfix) Prevent beautifier from inserting extraneous blank lines a line that contains only quoted characters. - Merge the / checks with the +/+ checks, and reduce them to Warn3. - Remove the check requiring that callbacks 40..FF be checked with a doubleword var2. 1) It's a word var2, and 2) they're invalid anyway. - New properties, variables, and callbacks: - Station properties: 16, 17, 18 - Station variables: 4A, 66 - Callbacks: 140, 141, 142 - New action 5 type 0D Changelog: v3.1.4 to v3.2.0 (svn r156) - (hotfix) TextIDs F900..F904. - (hotfix) Callbacks 3C and 3D. - (hotfix) Industry variable 63, industry tile variable 61, vehicle variable 48. - (devel) Parse pseudos into strings of bytes, not strings of hex characters. (~33% speed increase, ~50% memory usage reduction) - New format for lang bytes. - Check that lang byte contains a known language. - @@BEAUTIFY LINEBREAKS (see README[.txt]) - @@BEAUTIFY CONVERTONLY (see README[.txt]) - (devel) Use boost for current-function macro. - (devel) Split act123.cpp since I could never find anything in it. - (change) Ensure that Action 2s of at least three bytes always define their ID. - (devel) Lose the goto that sometimes succeded at the above. - (devel) Merge the two forms of INTERNAL_ERROR (file/line) - Check for duplicate style-names for all languages. - Allow ON and OFF on the command line as + and -, resp. - @@CLEARACTION2 - @@CLEARACTIONF v3.1.3 to v3.1.4 - Action 02 feature 07/09 and no are longer limited to 00..0F. - (bugfix) Fix check for non-decreasing ypos in real sprites. v3.1.2 to v3.1.3 - (bugfix) Bit 7 of is not a trigger. - (hotfix) Add industry property 10. v3.1.1 to v3.1.2 - Enable pretty-printing of overlength action 0s. - Tightened resultant range from shift-and-add-mod varadjusts in some cases. - (bugfix) Reinstate check for random 2 s of 00. - Always check triggers and bits in random 2s, not just if is valid. - (bugfix) Skip the offset byte after code 01 in strings. - (bugfix) Report correct offsets when random 2s misuse the available bits. - Complain about shift-and-add-mod when add%mod==0, not just when add==0. - (hotfix) Added station variable 65. v3.1.0 to v3.1.1 - (bugfix) Check for UTF-8 in UTF-8 strings, not Latin-TTD strings. - Added 2.0.1a, 25b, and 2.5b formats to VERSIONCHECK. v3.0.2 to v3.1.0 - Varaction range checking now checks ranges for agreement with . - Randactions are checked for using valid bits and triggers. - Added check for both high bits set in varaction s. - Reverted "Do not break if the remaining bytes are guaranteed to fit" in favor of an explicit "no line break here" when line breaks do not belong. - (bugfix) Action F checker occasionally requested one too many random bits. - (devel) Data files now contain two meta-info bytes; format and version. - (hotfix) Pulled industry var 5F. - (hotfix) Added industry var 62. - (hotfix) Added type 0C action 5s. - (bugfix) Removed extraneous "m/" from message when a datafile read failed. - Fully functional UTF-8 parser: - Encoded Thorn is C3 9E. (again, grr...) - Encoded control characters are now checked. - 7B..7E in UTF-8 strings are quoted. v3.0.1 to v3.0.2 - (bugfix) Check proper range when checking default on type 89/8A varactions. - (bugfix) Action 0 feat 8 prop 10 is 384 bytes. - Added pretty-printing for action 0 feature 8 prop 10. v3.0.0 to v3.0.1 - Added variational range accessibility checks. - 2.0.1 alpha 74 updates: - Widened industry variable 61 to a word. - General variables prop 10. - Added missing \n to --help message. v3.0.0 pre 2 to v3.0.0 - Added pretty-printing for action 0 and F. - Several beautifier bugfixes/changes: - Obey LINELENGTH. - Add missing newline between and in action B. - Whitespace between code and comment from the previous line(s) in a sprite no longer added to the current line. - Do not break if the remaining bytes are guaranteed to fit. - Action F updates: - Uses the action 4/8/B string parsing routines. - New language byte format applies to action F too. - Added --lock, to prevent NFO files from overriding the commandline. - (bugfix) "Unexpected EOF: Unused town name IDs" message goes to the console, not the NFO. - (bugfix) Make -k not cause crashes. - Add check for presence of in action 8. - (bugfix) Action Bs with message-id FF now check ... v3.0.0 pre 1 to v3.0.0 pre 2 - Added pretty-printing for all actions except 0 and F. - Added pretty-printing for recolor maps and binary imports. - All strings now obey QUOTEUTF8. - All GRFIDs now obey HEXGRFID. - Changed beautifier's cookie format. - Changed LEADINGSPACE to allow three independent settings. - Changed line breaks to start 15 characters before max. - (bugfix) GETCOOKIE returns a valid comment command. - (bugfix) Corrected NOPRESERVE's meaning when following @@BEAUTIFY - (bugfix) UTF-8 encoded Thorn is C3 9E, not C3 93. - (bugfix) Action 7/9 test 06 is a GRFid test. v2.8.5 to v2.8.6/v3.0.0 pre 1 - Made comment commands case insensitive (except for variable names). - Made undef @@BEAUTIFY options and settings complain instead of set default. - More a73 updates: - Callback 3B. - Industry production callback's may have any value. - Industry variable 61. - TextIDs F8FB..F8FF. - (3.0.0 pre 1 only) Enabled the beautifier. - (2.8.6 only) diked out @@BEAUTIFY, &c. v2.8.4 to v2.8.5 - (bugfix) -? message now says @@REALSPRITES. - (bugfix) Checked to ensure that pseudo continuation lines were being attached to pseudosprites, rather than turning into independent sprites. - Added @@BEAUTIFY/--beautify/-b. (No beautifier to control, though.) - Added '=' as an acceptable delimiter for comment commands. - Changed @@DIFF to imply @@LINT NONE. v2.8.3 to v2.8.4 - (hotfix) Added industry variable 60. - Added support and checks for action 12. v2.8.2 to v2.8.3 - Beginnings of sprite-rewriting system. No new functionality yet, though. - (devel) Moved data-file version bytes to data.cpp. - Changed "Length does not match ..." (#40) to contain more information. - (bugfix) Reverted "(bugfix) Checks length of extended house/industry tile action2s before processing." from 2.4.8. - (bugfix) Callback 30 is for industry tiles, not industries. - Added check for action 8 before GRM action Ds. v2.8.1 to v2.8.2 - More a72 and GRFv7 updates: - Action 7 condition 0C - Allow action 4s for industry tiles - Allow line breaks in industry texts (hotfix) - Industry property 22 (hotfix) - (bugfix) Actually add --real-sprites. - Add check for "looks like an NFO file" (override with -f). - (bugfix) Set EPARSE when encountering a file with a too-large version. v2.8.0 to v2.8.1 - Up to date with 2.0.1 alpha 72 (all hotfix) - Train variable 48 (still undocumented) - House variable 62 - Industry tile variable 60 (widened to 4 bytes) - Cargo properties 19..1A - Callbacks 38..3A - (bugfix) Fixed hang when outputting a wider-than-specified value. v2.7.0 to v2.8.0 - Added @@REALSPRITES/--real-sprites/-r. - Made sprite numbers optional most of the time. - Up to date with a70's action 7/9/10 handling. - Add checks for valid usage of variable 0C. (messages 163..165) - Made "-1 * 1 00" only parse as a real sprite when looking for real sprites. - (bugfix) Report proper ID range on invalid non-text ids. v2.6.4 to v2.7.0 - Change @@DIFF to set sprite lengths to 0 and sprite 0 to "00 00 00 00". - Add several command-line arguments (see renum -?). - Look for .renum directory in HOME too, if defined. - (bugfix) Crash when directory could not be created. - (devel) Use GNU getopt for command-line parsing. - (devel) Split and sanify data directory location & creation. v2.6.3 to v2.6.4 - Complain when DCxx IDs are included. - (bugfix) Allow changing class E0 TextIDs. - (devel) Revert %e format specifier. - Revert format/arguement agreement checks. - Make argument supercede format for width determination. v2.6.2 to v2.6.3 - (hotfix) Add new class F8 TextIDs. - (bugfix) Allow including TextID C7FF (81 FF C7). - (bugfix) Format/argument agreement for some instances of INVALID_ID (141). - (bugfix) No longer die on (non-Text)IDs above FF. - (devel) Added %e format specifier, for extended bytes. - Added format/argument agreement checks. (non-fatal) - (bugfix) Re-write import sprites in canon format. - (bugfix) Allow setting properties for sound ID 49. v2.6.1 to v2.6.2 - (bugfix) No warnings about backwards gotos when skipping 20..DF sprites. - (bugfix) Fixed hangs when using control characters where they are ignored. - (devel) Moved Action 0 feature 8 special-casing to 0f8.dat - Added checks for generic textIDs. - Checks for setting out-of-range texts using too-large . - Up to date with 2.0.1 alpha 69: - (hotfix) Action D variable 9F. - (hotfix) Action 0 feature 08 props 0A..0F. v2.6.0 to v2.6.1 - Up to date with 2.0.1 alpha 68: - Added UTF-8 support - Action 5 type 0B - Action D variable 9E - (bugfix) Really fixed the broken param checking for 60+x vars. - Added missing checks for extra data in action 8s. - Removed special casing in action 8s that permitted non-terminated strings. v2.5.5 to v2.6.0 - Added RPN calculations in real sprites. (see README.RPN) - Added @@LET comment command. - (devel) s/setcode/SetCode/g. - (devel) split check_sprite into two functions. - (devel) removed a write-only string in verify_real. - Changed "Cannot read sprite metadata" message to report where it failed. v2.5.4 to v2.5.5 - (devel) Split action 5 processing off to act5.cpp. - (devel) New datafile: 5.dat. - Added action 5 types 09 and 0A. - Added missing num-sprites checks for action 5. - Added support for recolor maps. - Accept recolor maps in action A blocks. - (bugfix) Correctly number pseudo/include sprites that precede real sprites. v2.5.3 to v2.5.4 - Added 201a66 format to @@VERSIONCHECK. - (devel) More reworking of the message system. - (bugfix) Fixed a GPF on invalid real sprites. - (bugfix) Accept real sprites where ".pcx" is followed by a non-space whitespace character. - Added numerous checks of the real sprite meta data. (156-60) - (hotfix) Fixed an off-by-one in GRM (D.dat). v2.5.2 to v2.5.3 - Up to date with a66: - General prop 09 - Cargo prop 17 - Action 2 variable 47 (vehicles) - Action 3 cargo type checks - Ignore high bit of action B severities. - Changed @@VERSIONCHECK to agree more closely with the documentation. - Action 7 condition 0B. - Fixed general variable ID checks - Added check for setting sound props for IDs <74 (4Ah) - (devel) Removed action 2 variable range data and associated loading code. - (bugfix) Check correct byte in "0*0 00 01 00 FF xx xx 01 1A". - (devel) New data-file loading #define, GetCheckEOF. - (bugfix) Add several missing fcloses. - (devel) Substantial rework of the message output system. - (bugfix) Remove an idiotic check in the message output system. v2.5.1 to v2.5.2 - (bugfix) fixed @@VERSIONCHECK (also shortened the output by 3 bytes). - Added patch variable 9D. - Made patch variable 99 write-only. - (bugfix) Re-added action D operations 09..0C. v2.5.0 to v2.5.1 - Added @@LINT command; deprecated @@SANITY. - Changed/fixed exit codes. - (bugfix) Fixed stack checking for data other than words. - Added @@VERSIONCHECK command. - Redid livery override checks (valid feature and follows std 3). - (bugfix) Added missing data-clearing between files for actions 1-3. - Downgraded the "Not a recolor sprite" message to Warn 1. - (devel) renamed defines.h to renum.h v2.4.9 to v2.5.0 - (hotfix) Made variables 10 and 18 always accessible. - NFORenum will now automatically write its data files if old or not found. - (devel) Added versioning byte to beginning of every data file. - Added full recognition of all string control characters. - Added (some) string consistancy checking. (actions 4/8/B) (messages 144-9) - Added action B checking. (messages 150-3) - (devel) added %K, for stack types. - (devel) removed attempts at Mac compatibility (still endian-safe, though) - Reversed the file search order. - (bugfix) no longer append an 'L' to language names. - (devel) changed many of the global objects to singletons. - Up to date with alpha 63: - Widened vehicle variable 43. - Accept action 1 ==0. (features 0-4 only, though) - Action 7/9 tests 09 and 0A. - GRM operation 06. - Updated the strings containing "Sanity". v2.4.8 to v2.4.9 - (bugfix) Don't issue an invalid action byte message on import sprites. v2.4.7 to v2.4.8 - (hotfix) Added houses variables 10 and 18. - (hotfix) Widened house var 44 to a dword. - Up to date with a61: - Supports sound imports - Action 0 is now an extended byte - (devel) added %S to my *printf spec, for "expandable string". - Some message considation. - (devel) s/LengthCheck/CheckLength/g - (bugfix) Checks length of extended house/industry tile action2s before processing. - (bugfix) Fixed callback result check (id&0x8000, not &0xF000) - Added check for valid transparent translation sprite. - Added offset leaders to three more messages - (devel) removed offset leaders from strings; added HAS_OFFSET bit instead. - (docs) removed suppression comment from SANITY.txt - Added check for using only constant variables (1A and 1C). (message 113) - Removed duplicate default warning if (and only if) nvar == 1 and the referenced cargo ID checks variable 1C. v2.4.6 to v2.4.7 - (devel) completed datafile reworking. - Up to date with a59: - Added variables 1C, 5F. - Added train variable 46. - Added station variable 49. - (change) Added variable 42 to RVs, ships, planes. (only low byte, though) - Added property to message 65 (unexpected end-of-sprite). v2.4.5 to v2.4.6 - (bugfix) Revert to 2.4.2's newline handling. (My "fix" in 2.4.3 had a tightloop that would terminate in ENOMEMORY.) - (packing) Removed an old file from source dir. - (devel) started reworking of datafile handling - Up to date with a59pre3: - Action 2 variable 7F - Action 2 trains variable 46 - Action D operations 09..0C - Renumbered messages. v2.4.4 to v2.4.5 - (bugfix) Added variables 10 and 18 to houses. - (bugfix) Enabled cargotypes 1D..1F in action 3s. v2.4.3 to v2.4.4 - Up to date with a58: - Newsounds properties v2.4.2 to v2.4.3 - Removed check for not-variational action 2 (now it's a callback return). - (bugfix) Fatal errors on action 2s define the associated ID. - (devel) moved meat of LENGTH_CHECK into LengthCheck. - States version on startup. - (bugfix) Using standard in/out works again. Also, explicitly state that stdin/out are being used. - (bugfix) Correct handling of quoted newlines. - Checks ID(s) given in actions 0,3,4 (1 byte IDs only in 4s) (message 139) - (bugfix) No longer errors on no-groundsprite house action 2s. - Checks for at least one non-transparent building sprite if no ground sprite in house/industry tile action 2s. - (devel) "%#x" now safely produces little endian text, as XX XX ... (bugfix) GRFids no longer come out reversed on LE systems. (message 119) - (bugfix) Reports the correct sprite number if an incorrect number of reals follow an action 5. - (devel) Some cleanup in act123.cpp. (bugfix?) Probably some fixes in standard action 2 handling. - Checks in action 3s (must be 0 for features 5,7,9..B). (message 140) - Attempted to be up-to-date with a58: - Train props 27..29 - RV props 1C..1E - Ship props 17..19 - Plane props 17..19 - Cargo prop 16 - Variable 1B - Industry tile variable 60 - Checks that livery overrides are only used with features 0 and 3. v2.4.1 to v2.4.2 - Added check for Action E disabling reserved GRFID (FF .. .. ..) (message 134) - Increases nfo version, if necessary. - Up to date with documentation for alpha 57: - Binary include sprites (and their pre-grfcodec 0.9.7 equivilants) (messsages 135..137) - Action 11 - (bugfix) Fixed resource management feature check. - (bugfix) Now complains about 79Dv.dat, not 7Dv.dat. - (devel) Changed resouce management to use a data file. - Added checks for resource management. (message 138) - (devel) Messages are now stored as char*s, not std::strings. - Removed the whole "Can disable following warnings/errors" concept. (and some associated bugs.) - (bugfix) No longer eats NFO files with an unknown version. - (bugfix) No longer eats NFO files that follow a file with an unknown version. v2.4.0 to v2.4.1 - Cargo prop 15 (alpha 57) - (bugfix) Action 2s can refer to their own ID. - Train variable 60 (alpha 57) v2.3.6 to v2.4.0 - Checks actions D, E, F (messages 119..129) - Up to date with alpha 55 vcs 3 - House props 1D, 1E (a55vcs2) - Parameterized variable support (message 130) - Station variables 48, 60..64 - House variables 60, 61 - New house/industry tile action 2 format (messages 131..133) - (bugfix) probable crash on incorrect length basic 07/09 standard 2s. - (bugfix) color translation checks didn't. - (devel) added 79Dv.dat for the 7/9/D variable information. - (devel) renamed 7.cpp 79D.cpp to more accurately reflect its purpose. v2.3.5 to v2.3.6 - Up to date with alpha 55 vcs - newcargos - global variable 1A - multiply, and, or, and xor operations - Added warning for too many sprites in set. - Added warning for an unusual set size (features 0-3, sizes 5-7) v2.3.4 to v2.3.5 - (bugfix) Gives the correct offset for an incorrect operation code. - (bugfix) Enabled variable 80 for vehicles. (Used in AI callbacks.) - (bugfix) Reports correct location of preceding action 1. v2.3.3 to v2.3.4 - (bugfix) No longer overruns the sprite on variational action 2s where is greater than 1. v2.3.2 to v2.3.3 - Parses a54's new variational action 2s. - Checks for valid operation in new variational action 2s. - Added to message 84. (Testing nonexistent variable) - (bugfix) Unused industry cargoIDs are now reported. - (bugfix) Message 23 (Unexpected EOF: Unused cargo ids...) now displays feature in hex. (invisible) - Added variable 18 for industries. v2.3.1 to v2.3.2 - (bugfix) Standard action 2s not preceded by an action 1 now returns a more meaningful error. - (bugfix) Standard action 2s that do not require new graphics do not check the preceding action 1 (if it exists) - Up to date with alpha 53 vcs: - Industry production callbacks - Industry tile properties 0E-11 - Industry tile variable 44 - Industry variables 40-42 - Changed one more sprite-too-long type message to warning level 2. - (devel) Changed INTERNAL_ERROR to be more useful. - (devel) Cleared up gcc compilation. v2.3.0 to v2.3.1 - Added station variables 46 and 47 (a51). - (bugfix) Now checking correct byte of action 7s for potential goto. - Changed all the sprite-too-long type messages to warning level 2. - Added checks for Action 6: Changes following sprite Does not attempt to extend following sprite Following sprite exists - (packaging fix) Removed renum.tar.bz2 from the src/ dir (renum.rar and renum.zip) Please don't ask me how it got there. v2.2.3 to v2.3.0 - (devel) Moved action 1-3 checking to its own .cpp file - (bugfix) "Feature byte does not match..." message would output jibberish instead of the location of the previous action 3. - Added checks: Standard action 3 precedes override action 3 Override action 3 closely follows standard 3 Variable in variational action 2 exists. Variable in variational action 2 is not being shifted into oblivion. - (bugfixes) Validated 0.dat: Fixed house props 11, 12, and 16 Fixed bridge props 0B-0D, added 0E Added station props 14 (a47) and 15 (a51) Fixed industry props 1B, 1C v2.2.2 to v2.2.3 - Removed check for comments at the end of pseudo-sprite lines - (bugfix) '/' is now an acceptable directory separator - (bugfix) String support no longer breaks when high-ASCII characters are quoted. - (devel) fixed gcc 3.4.3 compilation v2.2.1 to v2.2.2 - Added @@WARNING command. - Changed FAILURE to FATAL. - Changed/combined some strings. - (bugfix) No longer warns about "-1*6 00 00 01 00 ?? 1A" (Finally!) - Raised error messages to always. - Enabled var/rand action 2 and action 3 for feature 0A. - (devel) fixed gcc warnings when compiled -W -Wall. v2.2.0 to v2.2.1 - (bugfix) TTD defines sprites up to #4894. - (bugfix) changing TTD's last sprite is permissible. v2.1.0 to v2.2.0 - (bugfix) 0.dat can be updated for new features without changing the source. - (devel) Added MSVC .NET project files to src/ - Up-to-date with alpha 49: New action 0 properties for industry tiles and industries Extended-byte for action 1 and for action 5 Action 10 - (bugfix) Terminated repetition now correctly handles multi-byte terminators. - Updated the action 1/2/3 linter: Feature bytes larger than 07 are permissible. Checks ALL standard action 2s Accepts callback results in standard action 2s - Added detection for property repetition in an action 0. - Added string support (but only if "Info version 5" or no NFO header) - (devel) Cleaned up whitespace - Added @@PRESERVEMESSAGES and made @@REMOVEMESSAGES default. - Added checks: Action 8: Presence Duplicate Valid GRFID Action 7/9: , , and agreement Backwards goto Action 10: Duplicate Usage Action 4: String count Action A: Sprite number - Adjusted some warning levels. - (bugfix) Feature 0A prop 1A is a dword, not a byte. - Do not lint NFO files where the first sprite is a real sprite. - (linter) Do not accept real sprites prior to the first Action 1/5/A. v2.0.4 to v2.1.0 - Added checking of Action 0s - (Bugfix) Removed various incorrect messages that could be issued on an overlength Action 3 - Moved source files to the src/ directory v2.0.3 to v2.0.4 - Changed supression of errors and warnings by failures. - Added a @@DIFF comment-command -- causes all sprites to be numbered -1, to help produce useful diffs. - Changed "Invalid action byte" to a failure. - (devel) Removed ugly system calls; replaced with real file-handling funcs. - (Bugfix) removed "invalid ID" message for @@USEID2 - (Bugfix) Added some missing "can't happen"s - (devel) Moved all messages to messages.h - Up-to-date with a43 v2.0.2 to v2.0.3 - Corrected number of sprites required for foundations. - Ensure that the sanity checker will never try to read bytes that do not exist. v2.0.1 to v2.0.2 - Added missing checks for Variational/Random Action 2s Action 2 pointing to itself All choices the same in random 2 Default ID appearing before the end of the sprite in var 2 - Added missing check for action 3 Default ID appearing before the end of the sprite - Added a list of the sanity checker's messages (SANITY or SANITY.txt) - Downgraded severity of some messages. - Made sanity failures suppress following non-failure-level messages v2.0 to v2.0.1 - Added sanity checking to ensure that there is a chain from all vehicle sprites to an action 3. - Added a comment command (USESET) to work around unchecked Action 6s. - Fixed condition where pseudosprite continuations could be replaced with real sprites. This occured when the line could be parsed as a single decimal number. - (devel) passed memory allocation and bit-packing off to the vector class. v1.2.1 to v2.0 - Added sanity checking for Actions 1-3, 5, and A. - Added comment commands. - Changed *nix version to look in the "sprites/" directory. - (devel) Split source yet again (hopefully for the last time) - (devel) Changed NFO output to a global ostream* - (devel) removed some outdated stuff from defines.h - (devel) Added an exit value of 3 to indicate internal failure. v1.2 to v1.2.1 - Fixed real-sprite validity check to agree with GRFCodec. Now properly handles whitespace in filenames and trailing comments. - Fixed condition where sprites could get numbered in hex. This occured when renumbering a non-patch NFO after a patch NFO. - (devel) Changed message and error output to global ostream*s v1.1 to v1.2 - Now adds missing NFO header. - Checks real sprites for validity. This mostly solves the problem of destroying continuation lines of pseudo-sprites with invalid characters. - Changed backup and temp file names in some cases, to always use .NFO.BAK and .NFO.NEW - (devel) code for checking sanity of actions 1, 5, and A included, but #ifdef-ed out. NO_SANITY_CHECKING is the controlling symbol. - (devel) more source rearranging and cleanup. v1.0 to v1.1 - Now processes all files listed on the command line, not just the last one. - Always produces output. - Warning and error messages will now be sent to both the console and the NFO. In the NFO, messages are commented and prefixed with "!!" - Changed handling of invalid pseudo-sprites. Instead of dying, comments the sprite out and continues. Message to console and NFO. - (bugfix) Added a check to ensure that the output file got opened. - (devel) moved file processing to a separate function. - (devel) substantially cleaned up the i/o stream selection system. It actually makes sense again. - (devel) general code cleaning and organizing - (devel) upgraded to UPX 1.25 v0.4 to v1.0 - Now handles multi-line pseudo-sprites correctly. - Now writes sprite 0 in the correct location. - More permissive TTDPatch NFO detection If the first sprite is a pseudo-sprite, treat as a TTDPatch NFO. If the first sprite claims to be 4 bytes long, discard and recreate. Otherwise, comment old sprite 0 and create new sprite 0. - Successful runs no longer produce output, other than the fixed NFOs. - (devel) Now stores most of the NFO in memory while processing. v0.3.1 to v0.4 - (devel) Now does its own file handling (disable by #defining NO_FILE_HANDLING) - Accepts absolute paths for .NFO locations. - Drag&drop from Windows explorer now works. - The executable is now UPX packed. - renum.bat is no longer necessary; the executable is now renum.exe. - GNU/Linux systems (GNU fileutils) receive a new backup everytime the NFO is renumbered. v0.3 to v0.3.1(bugfix) - No longer destroys real sprites. v0.2 to v0.3 - Now also reports on potential continued pseudo-sprites with trailing comments - No longer eats whitespace before comments - No longer eats blank lines v0.1 to v0.2 - No longer silently destroys data in multi-line pseudo-sprites. - Return value of 1 now indicates potential data destruction. - (side effect) Renum.bat will not delete the old version of the NFO if pseudosprite data may have been destroyed. - Detects TTDPatch NFOs, and reports size stats. - In TTDPatch NFOs, if sprite 0 does not report the exact size of the NFO, outputs corrected sprite 0 to the console, and, commented, as the last line of the NFO. - Now returns 2 to indicate error. grfcodec-6.0.3/.ottdrev0000644000000000000000000000002212171043643013455 0ustar rootroot6.0.3 964 0 6.0.3 grfcodec-6.0.3/released.ptxt0000644000000000000000000000002512072267536014506 0ustar rootroot2013-01-06 12:34 UTC grfcodec-6.0.3/Makefile.bundle0000644000000000000000000001216712027143046014710 0ustar rootroot# # Creation of bundles # # Standard make convention variables/locations prefix ?= /usr/local exec_prefix ?= $(prefix) datarootdir ?= $(prefix)/share datadir ?= $(datarootdir) bindir ?= $(exec_prefix)/bin mandir ?= $(datarootdir)/man man1dir ?= $(mandir)/man1 docdir ?= $(datarootdir)/doc/$(PACKAGE_NAME) openttddir ?= $(datarootdir}/openttd openttdgmdir ?= $(openttddir)/gm/$(PACKAGE_NAME) openttddatadir ?= $(openttddir)/data/$(PACKAGE_NAME) ifeq (${V},1) VERBOSE := 1 endif ifndef BUNDLE_NAME BUNDLE_NAME = $(PACKAGE_NAME)-$(REV) endif ROOT_DIR = $(shell pwd) ifndef BUNDLE_DIR BUNDLE_DIR := "$(ROOT_DIR)/bundle" endif ifndef BUNDLES_DIR BUNDLES_DIR := "$(ROOT_DIR)/bundles" endif bundle: release $(_E) '[BUNDLE] Constructing bundle' $(_C)rm -rf "$(BUNDLE_DIR)" $(_C)mkdir -p "$(BUNDLE_DIR)" $(_C)mkdir -p "$(BUNDLE_DIR)/docs" $(_C)mkdir -p "$(BUNDLE_DIR)/man" $(_C)cp $(GRFCODEC) "$(BUNDLE_DIR)/" $(_C)cp $(GRFDIFF) "$(BUNDLE_DIR)/" $(_C)cp $(GRFID) "$(BUNDLE_DIR)/" $(_C)cp $(GRFSTRIP) "$(BUNDLE_DIR)/" $(_C)cp $(GRFMERGE) "$(BUNDLE_DIR)/" $(_C)cp $(NFORENUM) "$(BUNDLE_DIR)/" $(_C)cp COPYING "$(BUNDLE_DIR)/COPYING" $(_C)cp changelog.txt "$(BUNDLE_DIR)/" $(_C)cp docs/*.txt "$(BUNDLE_DIR)/docs/" $(_C)cp docs/*.1 "$(BUNDLE_DIR)/man/" $(_C)gzip -9 "$(BUNDLE_DIR)/man/"*.1 ifeq ($(GRFCODEC), grfcodec.exe) $(_C)unix2dos "$(BUNDLE_DIR)/docs/"*.txt "$(BUNDLE_DIR)/COPYING" "$(BUNDLE_DIR)/changelog.txt" endif install: bundle @echo '[INSTALL] Installing' $(_C)install -d "$(DESTDIR)$(bindir)" $(_C)install -m 755 "$(BUNDLE_DIR)/$(GRFCODEC)" "$(DESTDIR)$(bindir)/" $(_C)install -m 755 "$(BUNDLE_DIR)/$(GRFMERGE)" "$(DESTDIR)$(bindir)/" $(_C)install -m 755 "$(BUNDLE_DIR)/$(GRFDIFF)" "$(DESTDIR)$(bindir)/" $(_C)install -m 755 "$(BUNDLE_DIR)/$(GRFID)" "$(DESTDIR)$(bindir)/" $(_C)install -m 755 "$(BUNDLE_DIR)/$(GRFSTRIP)" "$(DESTDIR)$(bindir)/" $(_C)install -m 755 "$(BUNDLE_DIR)/$(NFORENUM)" "$(DESTDIR)$(bindir)/" ifndef DO_NOT_INSTALL_DOCS $(_C)install -d "$(DESTDIR)$(docdir)" $(_C)install -m 644 "$(BUNDLE_DIR)/docs/"* "$(DESTDIR)$(docdir)" endif ifndef DO_NOT_INSTALL_CHANGELOG $(_C)install -d "$(DESTDIR)$(docdir)" $(_C)install -m 644 "$(BUNDLE_DIR)/changelog.txt" "$(DESTDIR)$(docdir)" endif ifndef DO_NOT_INSTALL_LICENSE $(_C)install -d "$(DESTDIR)$(docdir)" $(_C)install -m 644 "$(BUNDLE_DIR)/COPYING" "$(DESTDIR)$(docdir)" endif ifndef DO_NOT_INSTALL_MAN $(_C)install -d "$(DESTDIR)$(man1dir)" $(_C)install -m 644 "$(BUNDLE_DIR)/man/"*.1.gz "$(DESTDIR)$(man1dir)/" endif ### Packing the current bundle into several compressed file formats ### # # Zips & dmgs do not contain a root folder, i.e. they have files in the root of the zip/dmg. # gzip, bzip2 and lha archives have a root folder, with the same name as the bundle. # # One can supply a custom name by adding BUNDLE_NAME:= to the make command. # bundle_zip: bundle $(_E) '[BUNDLE] Creating $(BUNDLE_NAME).zip' $(_C)mkdir -p "$(BUNDLES_DIR)" $(_C)cd "$(BUNDLE_DIR)" && zip -r $(shell if test -z "$(VERBOSE)"; then echo '-q'; fi) "$(BUNDLES_DIR)/$(BUNDLE_NAME).zip" . bundle_gzip: bundle $(_E) '[BUNDLE] Creating $(BUNDLE_NAME).tar.gz' $(_C)mkdir -p "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)" $(_C)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)/" $(_C)cd "$(BUNDLES_DIR)/.gzip" && tar -zc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.gz" "$(BUNDLE_NAME)" $(_C)rm -rf "$(BUNDLES_DIR)/.gzip" bundle_bzip2: bundle $(_E) '[BUNDLE] Creating $(BUNDLE_NAME).tar.bz2' $(_C)mkdir -p "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)" $(_C)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)/" $(_C)cd "$(BUNDLES_DIR)/.bzip2" && tar -jc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.bz2" "$(BUNDLE_NAME)" $(_C)rm -rf "$(BUNDLES_DIR)/.bzip2" bundle_lha: bundle $(_E) '[BUNDLE] Creating $(BUNDLE_NAME).lha' $(_C)mkdir -p "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)" $(_C)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)/" $(_C)cd "$(BUNDLES_DIR)/.lha" && lha ao6 "$(BUNDLES_DIR)/$(BUNDLE_NAME).lha" "$(BUNDLE_NAME)" $(_C)rm -rf "$(BUNDLES_DIR)/.lha" bundle_dmg: bundle $(_E) '[BUNDLE] Creating $(BUNDLE_NAME).dmg' $(_C)mkdir -p "$(BUNDLES_DIR)/GRF Development Tools $(REV)" $(_C)cp -R "$(BUNDLE_DIR)/" "$(BUNDLES_DIR)/GRF Development Tools $(REV)" $(_C)hdiutil create -ov -format UDZO -srcfolder "$(BUNDLES_DIR)/GRF Development Tools $(REV)" "$(BUNDLES_DIR)/$(BUNDLE_NAME).dmg" $(_C)rm -fr "$(BUNDLES_DIR)/GRF Development Tools $(REV)" bundle_src: $(_E) '[BUNDLE] Creating $(BUNDLE_NAME).tar.gz' $(_C) hg archive -t tar $(BUNDLE_NAME).tar -X "\.hg*" -X "\.devzone*" -X "version.def" $(_C) mkdir -p $(BUNDLE_NAME) $(_C) echo YEAR = "$(YEAR)" >> $(BUNDLE_NAME)/version.def $(_C) echo REV = "$(REV)" >> $(BUNDLE_NAME)/version.def $(_C) echo VERSIONSTR = "$(VERSIONSTR)" >> $(BUNDLE_NAME)/version.def $(_C) tar -uf $(BUNDLE_NAME).tar $(BUNDLE_NAME)/version.def $(_C) rm -rf $(BUNDLE_NAME) $(_C) $(SRCZIP) $(SRCZIP_FLAGS) $(BUNDLE_NAME).tar grfcodec-6.0.3/findversion.sh0000755000000000000000000000574312027143046014667 0ustar rootroot#!/bin/sh # $Id: findversion.sh 16462 2009-05-29 21:24:51Z rubidium $ # Arguments given? Show help text. if [ "$#" != "0" ]; then cat <\t\t\t REV a string describing what version of the code the current checkout is based on. The exact format of this string depends on the version control system in use, but it tries to identify the revision used as close as possible (using the svn revision number or hg/git hash). This also includes an indication of whether the checkout was modified and which branch was checked out. This value is not guaranteed to be sortable, but is mainly meant for identifying the revision and user display. If no revision identifier could be found, this is left empty. REV_NR the revision number of the svn revision this checkout is based on. This can be used to determine which functionality is present in this checkout. For trunk svn checkouts and hg/git branches based upon it, this number should be accurate. For svn branch checkouts, this number is mostly meaningless, at least when comparing with the REV_NR from other branches or trunk. This number should be sortable. Within a given branch or trunk, a higher number means a newer version. However, when using git or hg, this number will not increase on new commits. If no revision number could be found, this is left empty. MODIFIED Whether (the src directory of) this checkout is modified or not. A value of 0 means not modified, a value of 2 means it was modified. Modification is determined in relation to the commit identified by REV, so not in relation to the svn revision identified by REV_NR. A value of 1 means that the modified status is unknown, because this is not an svn/git/hg checkout for example. CLEAN_REV the same as REV but without branch name By setting the AWK environment variable, a caller can determine which version of "awk" is used. If nothing is set, this script defaults to "awk". EOF exit 1; fi # Allow awk to be provided by the caller. if [ -z "$AWK" ]; then AWK=awk fi # Find out some dirs cd `dirname "$0"` ROOT_DIR=`pwd` SRC_DIR=`pwd` # Determine if we are using a modified version # Assume the dir is not modified MODIFIED="0" if [ -d "$ROOT_DIR/.hg" ]; then # We are a hg checkout if [ -n "`hg status | grep -v '^?'`" ]; then MODIFIED="2" fi REV_NR=`LC_ALL=C hg id -n | cut -d+ -f1` if [ -n "`hg id -t | grep -v tip`" ]; then REV=`hg id -t | grep -v tip` BRANCH="" else REV=r$REV_NR BRANCH=`hg branch | sed 's@^default$@@'` fi elif [ -f "$ROOT_DIR/.ottdrev" ]; then # We are an exported source bundle cat $ROOT_DIR/.ottdrev exit else # We don't know MODIFIED="1" BRANCH="" REV="" REV_NR="" fi if [ "$MODIFIED" -eq "2" ]; then REV="${REV}M" fi CLEAN_REV=${REV} if [ -n "$BRANCH" ]; then REV="${REV}-$BRANCH" fi echo "$REV $REV_NR $MODIFIED $CLEAN_REV" grfcodec-6.0.3/build-number.txt0000644000000000000000000000021412171043637015121 0ustar rootroot#Created by the Bamboo Continuous Integration Server #Mon Jul 15 21:03:59 CEST 2013 build.number=12 build.timestamp="2013-07-15 21\:03\:59" grfcodec-6.0.3/COPYING0000644000000000000000000004325412027143046013034 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. grfcodec-6.0.3/docs/0000755000000000000000000000000012171043637012726 5ustar rootrootgrfcodec-6.0.3/docs/grfcodec.10000644000000000000000000000574312027143046014570 0ustar rootroot.\" Hey, EMACS: -*- nroff -*- .\" Please adjust this date whenever revising the manpage. .Dd February 24, 2012 .Dt GRFCodec 1 .Sh NAME .Nm GRFCodec .Nd A tool to convert a GRF file into graphics files and meta data, and vice versa. .Sh SYNOPSIS .Nm grfcodec .Op Fl sv .Op Fl d | e .Op options .Ar GRF\(hyfile .Op Directory .Pp denotes the .GRF file you want to work on, e.g. TRG1.GRF .Pp is where the individual sprites should be saved. If omitted, they will default to a subdirectory called sprites/. .Sh OPTIONS .Bl -tag .It Fl ? Display the help message. .It Fl e Encode a GRF file. The .Ar GRF\(hyfile to pass is the file where to encode to. The source of the GRF\(hyfile, i.e. the .nfo, will be looked for in .Pa sprites/GRF\(hyfile.nfo . All graphics files will be searched for relative from the location of the GRF\(hyfile. .It Fl d Decode a GRF file. The .Ar GRF\(hyfile to pass is the file to decode. The result will be in .Pa sprites/GRF\(hyfile.nfo and .Pa sprites/GRF\(hyfile.png . .It Fl s Silences the progress output in interactive mode .It Fl v Display the version. .El .Pp Options for decoding: .Bl -tag .It Fl w Ar num Write spritesheets files with the given width (default 800, minimum 16) .It Fl h Ar num Split spritesheets when they reach this height (default no limit, minimum 16) .It Fl b Ar num Organize sprites in boxes of this size (default 16) .It Fl o Ar ssf Sets the format of generated spritesheets. See .Fl o ? for a list. .It Fl p Ar pal Use this palette instead of the default. See .Fl p ? for a list. .It Fl t Disable decoding of plain text characters as strings. .It Fl x Disable production of unquoted escape sequences. .It Fl xx Disable production of both quoted and unquoted escape sequences. .Pp This has the side effect of producing a version 6 .nfo, instead of a version 7 .nfo. .It Fl X List sprite numbers in the image file in hex. .El .Pp Options for encoding: .Bl -tag .It Fl c Crop extraneous transparent blue from real sprites .It Fl u Save uncompressed data (probably not a good idea) .It Fl q Suppress warning messages .It Fl g Ar num Create a GRF file with the given container version. Valid versions are 1 and 2, where the latter allows bigger sprites, larger sounds, and multiple zoom levels and bit depths for the sprites. .It Fl n Try both compression algorithms and use the most efficient. This might cause trouble when loading the NewGRF in TTDPatch. .El .Pp Options for both encoding and decoding: .Bl -tag .It Fl m Ar num Apply colour translation to all sprites except character\(hyglyphs. .It Fl M Ar num Apply colour translation to all sprites. .Pp If both of these are specified, only the last is obeyed. .Fl m ? or .Fl M ? for a list of colour translations. .El .Sh SEE ALSO The documentation in .Pa /usr/share/doc/grfcodec/ .Sh AUTHOR GRFCodec was written by Josef Drexler. .Pp This manual page was written by Remko Bijker. .Sh COPYRIGHT GRFCodec is Copyright (C) 2000\(hy2005 by Josef Drexler grfcodec-6.0.3/docs/grf.txt0000644000000000000000000002114512027143046014243 0ustar rootroot Format of a GRF File A GRF file is a collection of "sprites", defining pretty much everything that you can see in the game. The sprites can be graphics, but also define many non-visual properties of the game entities like vehicles. There are two different file formats defined. The older format 1 simply consists of one sprite following another until the end of the file, with no header or other meta-information, except for a checksum at the very end of the file. Format 2 consists of a header, followed by a data section containing all non-image sprites, followed by a sprite section containing the actual graphics. All numbers in a GRF file are stored in little-endian byte order. File header (format 2 only) A format 2 GRF starts with a header with the following bytes: 00 00 47 52 46 82 0D 0A 1A 0A DWORD sprite_offs Number of bytes to skip after this DWORD to reach the start of the sprite section. BYTE data_compr Compression format of the data section. 00 No compression others Not defined Data section (formats 1 and 2) The data section consists of sprites with the following format: WORD size (format 1) DWORD size (format 2) The size of the current sprite, not including itself. The meaning depends on the info byte that follows. BYTE info Bitcoded value that determines what type this sprite is. FF Pseudo sprite that contains non-image data, see the NewGraphicsSpecs for details. For a pseudo sprite, the size does *not* include the info byte. FD (Only valid in format 2) Reference to sprite section. Size does *not* include the info byte. others (Only valid in format 1) Normal sprite with image data, see the section "Normal sprites" for details. If bit 2 is set, size is the length of the sprite in the file including the info byte. If it is not set, you have to decode the image data to find out where the next sprite starts. DATA data The length of the data depends on size and info. If the info value is FD, this is a single DWORD containing an ID that is looked up in the sprite section and processed instead of this sprite. The data sections is termindated by a WORD (format 1) / DWORD (format 2) of value 0. For format 1 GRFs, a four byte checksum follows. The algorithm to calculate it is unknown, but it is never processed by the game anyway. Sprite section (format 2 only) The sprite section consists of entries with the following format: DWORD id ID used to reference the entry from the data section. DWORD size Length of the following data in the file. BYTE info Bitcoded value that determines what type this sprite is. FF Non-image data, for example sounds. See the NewGraphicsSpecs for details. others Image data, see the section "Normal sprites" for details. DATA data size-1 bytes of data. Multiple entries with the same ID are allowed. IDs must be ordered ascending. The sprite section is terminated by a DWORD of value 0, which means that 0 is never a valid ID. Normal sprites Normal sprites contain the visible graphics of the game. The exact format depends on the file format. For format 1 files, normal sprites occur in the data section, while for format 2 files they are found in the sprite section. For format 1 GRFs, the info byte has the following meaning: Bit Val Meaning 0 1 Color index 0 is transparent (should always be set). 1 2 Size is compressed size if set. If this bit is set, the given size is simply the size in the file. If it is unset, you *must* decompress it to find out how large it is in the file. 3 8 Has transparency (i.e. is a tile), see below. 6 40h The exact size of this sprite is significant. If not set, grfcodec may attempt to remove extraneous transparent pixels. others Undefined. For format 2 GRFs, the info byte has the following meaning: Bit Val Meaning 0 1 Pixel format contains RGB components. 1 2 Pixel format contains alpha component. 2 4 Pixel format contains mask/palette component. 3 8 Has transparency (i.e. is a tile), see below. 6 40h The exact size of this sprite is significant. If not set, grfcodec may attempt to remove extraneous transparent pixels. others Undefined. Pixel components are ordered R, G, B, A, M, with not present components skipped without padding. For file format 1, pixel format is implicitly defined to be only the palette component. BYTE zoom_level (format 2 only) Zoom level of the current sprite, the following values are defined: 00 normal zoom 01 4x zoom-in 02 2x zoom-in 03 2x zoom-out 04 4x zoom-out 05 8x zoom-out BYTE ydim (format 1) WORD ydim (format 2) How many lines there are in the sprite (y dimension) WORD xdim How many columns there are (x dimension) WORD xrel Horizontal offset. The offset is counted from the base coordinate for each sprite. WORD yrel Vertical offset. DWORD uncomp_size (format 2, only if info bit 3 is set) Uncompressed size of the tile encoded image data. After this follows the actual compressed data. If info bit 3 is not set, the data is simply a stream of bytes from left to right, and from top to bottom, making up xdim*ydim pixels. Tile sprites If info bit 3 is set, the sprite is a tile and has some special transparency information that is encoded like follows. Each line is encoded separately and split into "chunks". Each chunk contains pixels, but the chunks may skip a few pixels which are then transparent. The sprite data first starts off with a list of WORD offsets for format 1 GRFs and format 2 GRFs with an uncompressed size below 65536 bytes. If the size is bigger in a format 2 GRF, the sprite starts with a list of DWORD offsets. There is one offset for each line. These determine at which offset each line starts, counted from the first data byte. Then follow the chunks for the lines: BYTE cinfo (format 1) WORD cinfo (format 2 if width > 256) The high bit is set if this is the last chunk in the line. The line need not be filled entirely, any remaining pixels are simply transparent. The lower seven/fifteen bits give the length of this chunk in pixels. BYTE cofs (format 1) WORD cofs (format 2 if width > 256) x offset at which this chunk starts. The pixels between this chunk and the last one will be transparent. After this follow (cinfo & 0x7f or cinfo & 0x7fff, respectively) bytes of pixels. Compression algorithm The compression used is a variation on the LZ77 algorithm which detects redundancy and losslessly reduces the size of the data. Here's how the compressed data looks in a GRF file. The compressed stream contains either a pointer to an earlier location and a length, which means that these bytes are copied over from the given location, or it contains a length and a verbatim chunk which is copied to the output stream. BYTE code The high bit of the code shows whether this is a verbatim chunk (not set) or a repetition of earlier data (set). The meaning of the following bytes depends on whether the high bit of code is set. If the high bit is not set, what follows is code&0x7f bytes of verbatim data. If the high bit is set, the code has a slightly different meaning. Bits 3 to 7 are now three bits to a length value, stating how much data should be copied from the earlier location. Bits 0 to 2 are the high bits of an offset, with the low bits being in the next byte. BYTE lofs Low bits of the offset Use this to extract length and offset: unsigned long length = -(code >> 3); unsigned long offset = ( (code & 7) << 8 ) | lofs; It's important that the variables are unsigned and at least two bytes large. The offset is counted backwards from the current location. So you subtract the offset from your position in the output stream and copy the given number of bytes. And that's pretty much all you need to know about a GRF file! ______________________________________________________________________ Copyright © 1999-2012 by Josef Drexler. grfcodec-6.0.3/docs/grfmerge.10000644000000000000000000000166412027143046014610 0ustar rootroot.\" Hey, EMACS: -*- nroff -*- .\" Please adjust this date whenever revising the manpage. .Dd August 05, 2010 .Dt GRFMerge 1 .Sh NAME .Nm GRFMerge .Nd A tool to apply a binary GRF diff, generated by GRFDiff, to a GRF. .Sh SYNOPSIS .Nm grfmerge .Op Fl hlyv .Ar GRD\(hyfile .Op Ar GRF\(hyfile .Pp Change sprites in the GRF file to the new ones from the GRD file. If the GRF file is not specified, GRFMerge will modify the one which the GRD file was generated from. .Sh OPTIONS .Bl -tag .It Fl h Display the help message. .It Fl l Only show which sprites the GRD file contains, don't integrate them. .It Fl y Answer 'y' to all questions. .It Fl v Display the version. .El .Sh SEE ALSO The documentation in .Pa /usr/share/doc/grfcodec/ .Sh AUTHOR GRFMerge was written by Josef Drexler. .Pp This manual page was written by Remko Bijker. .Sh COPYRIGHT GRFMerge is Copyright (C) 2003 by Josef Drexler grfcodec-6.0.3/docs/readme.rpn.txt0000644000000000000000000000433312027143046015520 0ustar rootrootNFORenum -- RPN calculator ========================== Most of you are familiar with infix notation, eg "4 + 2" or "4 + (2 * 2)". Infix can be expressed as "left operation right" RPN (Reverse Polish Notation, http://tinyurl.com/akj8w) uses "left right operation", eg "4 2 +" or "4 2 2 * +". RPN has the advantage that no parentheses are required in the expression; each well-formed expression can only be evaluated in one and only one way. In NFORenum, an RPN expression is introduced by an open parenthesis, and accepts as operators +, -, *, /, %, &, |, ^, <<, >>, ~, and --. Completion of an RPN expression is signaled by a close parenthesis, and the result of the RPN expression is returned. If extra numbers are listed, they are simply ignored (eg (1 2 3 +) is 5). If a number is listed at the end of an expression, that number is returned (eg (1 2 + 3) and (3) are both 3). Division is integer division, and rounded down; (5 3 /) is 1. The operators are as in C, except for --: add, subtract, multiply, divide, modulo, and, or, xor, left shift, right shift, unary not, and unary negate. All three standard numeric formats are accepted. A leading 0x indicates hexadecimal; a leading 0, octal; and any non-zero leading digit, decimal. If a minus sign immediately abuts the number (eg "-0x15", "-015", or "-15") it will be interpreted as a negative number, not the subtraction operator. Ensure that the subtraction operator is not immediately followed by a digit. In RPN expressions, a previously defined variable (variables are defined by @@LET) may be used in place of any number, both in real sprites and in @@LET commands. Variables should be valid C identifiers (first character must be A..Z, a..z or _, all others must be A..Z, a..z, 0..9 or _), and are case sensitive. Variables with 2 leading underscores are reserved for possible future use by NFORenum. An RPN expression may be used in a real sprite at any place where an decimal integer is expected(xpos, ypos, ysize, xsize, xrel, and yrel), and on the right side of the @@LET command. RPN expressions may not be nested. Malformed RPN expressions will cause the real sprite to be commented out, just as if it were missing metadata. The calculator will do its best to let you know what went wrong. grfcodec-6.0.3/docs/grftut.txt0000644000000000000000000001270012027143046014775 0ustar rootroot GRFCodec - A tutorial by [1]Josef Drexler. This tutorial is a list of the steps you need to take to edit a GRF file, and if you like, send your modifications to others. Since all GRFCodec programs are command line utilities (no graphical interface available), you have to make yourself familiar with the DOS or Windows command prompt. However, that's beyond the scope of this tutorial. These are the basic steps to modifiy a GRF file: 1. Decode the GRF file 2. Edit the PCX file 3. Encode the GRF file Optional steps to distribute your changes: 4. Make a GRD or self-extracting file 1. Decode the GRF file After installing the GRFCodec programs into your TTD folder, simply run GRFCodec. At the command prompt, type grfcodec -d trg1.grf This will decode trg1.grf, and put an editable PCX file in the SPRITES folder. Note that the image will be quite huge, and if you instead want to split it into smaller files, use grfcodec -d trg1.grf -w 800 -h 600 1a. Choosing a palette Skip this step unless you find that the colours are wrong. In that case, you need an extra option on the GRFCodec command line: the -p option. It tells GRFCodec to choose a different palette. After the -p option, you specify a number indicating which palette you want. You have the following choice: Number Meaning 1 DOS TTD 2 Windows TTD 3 DOS TTD, Candyland 4 Windows TTD, Candyland 5 TT Original 6 TT Original, Mars landscape So, for example, use "-p 2" when you're decoding a file from the Windows version of TTD, like so: grfcodec -d trg1r.grf -p 2 2. Edit the PCX file For this, you open your favourite graphics editor, like Paintshop Pro, Adobe Photoshop, or any other graphics editor that can deal with PCX files. (Just about all of them can.) You should then load trg1.pcx in the SPRITES folder. Or, if you used the second command above to split it into smaller files, open trg10000.pcx, which is the first part. The following parts simply have higher numbers. If at this point you find that the colours are wrong, you need to decode the GRF again, using a different colour palette. In that case please follow the instructions in step 1a). If however everything looks fine, you can then start changing the sprites. Note that it is fairly difficult to actually change their size, but changing the look is easy enough. Once you've changed all you need, save the PCX file again. 3. Encode the GRF file This step is the reverse of step 1), it takes the PCX file(s) and makes a GRF file out of them. At the command prompt enter grfcodec -e trg1.grf This will take a bit longer than decoding, but shouldn't take too long. Once it's done, you can start TTD and see the fruits of your labour! 4. Make a GRD or self-extracting file So now that you have successfully changed a GRF file, you'll of course want to give your awesome modifications to other people. You can simply send them the new trg1.grf file, but that has a few disadvantages. First, the GRF files are fairly large, so downloading them is going to take a fairly long time. Also, this means that your friend will lose all changes he made to his own trg1.grf file. If only there was a way to send only the changed sprites... ...and luckily, there is! It's called GRFDiff, and you use it like this: grfdiff trg1.bak trg1.grf Here, trg1.bak is a backup copy of the original GRF file. GRFCodec should have made it during step 3. Once it exists, GRFCodec won't touch it again, so it'll always remain the original copy. Now what this command does, is take all the sprites that are new and put them in a file called trg1.grd. This file should be fairly small, so that you can easily send it to your friend. What your friend then has to do is run GRFMerge like this: grfmerge trg1.grd That will integrate your changes into his trg1.grf, and everyone will be happy. Unless he doesn't have GRFMerge... ...in that case, you can instead tell GRFDiff to make a self-extracting file. That means it turns the GRD file into a program, which you can run instead of GRFMerge. To do that, run grfdiff -x trg1.bak trg1.grf -o yourmod.exe That will make yourmod.exe, or any other name you give it. Be creative, and make the name relevant to what you actually changed. Then simply send out yourmod.exe, and tell people to copy it to their TTD folders and run it. Tadaa! They've got your modified sprites. If you want to make your .exe file compatible with both the DOS and the Windows version of the game, you of course need to edit both trg1.grf and trg1r.grf. Then you combine the changes from both files into one executable like this: grfdiff -x -o yourmod.exe trg1.bak trg1.grf + trg1r.bak trg1r.grf When run, yourmod.exe will patch either both of the files if they are installed, or otherwise it will just skip those that it can't find. That way, it'll work no matter whether the DOS or the Windows version is installed, or even if both are present. Easy, wasn't it? ______________________________________________________________________ Copyright © 1999-2003 by Josef Drexler. Last changed on May 17 2003 15:45 EDT by [2]Josef Drexler References 1. http://www.ttdpatch.net/email.php?GRFCodec%2CTutorial 2. http://www.ttdpatch.net/email.php?TTDPatch%2CGRFCodec grfcodec-6.0.3/docs/sanity.txt0000644000000000000000000007304012027143046014775 0ustar rootrootThe messages are sorted by number. Similar messages that have adjacent numbers are grouped together. The format is as follows: : "Message" (severity/ies) Translation Fix [notes] Messages listed as starting with will have "Offset :" prepended to them; is the 0-based (that is, the action byte is byte 0) decimal offset of the problem byte, or first byte of the problem bytes, if something longer than a single byte is invalid. 41: "All are bytes long." (Fatal/Warn 2) 42: "Length does not match of ..." (Fatal/Warn 2) This pseudosprite is too short (Fatal) or too long (Warn 2). Add or remove data and/or change (if applicable). 43: " Sanity checker requires byte(s) ..." (Fatal) The sanity checker attempted to read bytes that didn't exist. Add the required bytes to the sprite. This is somewhat of a cop-out on my part, so given a good replacement error message and a sprite that causes it, I'll consider putting the better error message in. 44: "Invalid feature byte." (Fatal/Error) The feature byte of this sprite is not valid. Change the feature byte to something between 00 and 0F. Which features are valid depends on which action you are coding. See the wiki for the meanings of the feature bytes. 45: "Invalid nument1 or random-/variational-type byte" (Fatal) This action 2 has a type byte with no meaning. Change the type byte to 80-86, 89, or 8A for var/random, or 00-7F for standard. 46: "Invalid action byte." (Fatal) This is not a valid action. Fix the action byte. 47: " Invalid property ." (Fatal) The byte at offset appears to be a property byte, but is not a known propery. Fix this byte and/or check preceding properties for validity. 48: "Action 6 appears to be missing terminating FF." (Fatal) The parser hit end-of-sprite before finding the expected FF terminating byte. Ensure that the FF exists and that the preceding triplets are all valid. 49: "Insufficient . ..." (Error) 50: "Extra . ..." (Error) The number of sprites (real/include) seen since the most recent action 1/5/A/11/12 does not match the number declared by that 1/5/A/11/12. Add/remove sprites and/or adjust the declaring action. Note that "-1 * 1 00" is interpreted as a real sprite in action 1 blocks and most action 5 blocks. 51: " unexpected here." (Error) There was no reason to expect a sprite here; the immediately preceding sprite was not an Action 1/5/A/11/12. Remove the sprite, or add an action 1/5/A/11/12. Note that "* 1 00" is interpreted as a real sprite in action 1 blocks and most action 5 blocks. 52: "Feature byte does not match feature byte of preceding ..." (Error) This standard action 2 declares a cargoID for a different feature than the preceding Action 1. **OR** This override action 3 attempts to override for a feature other than the one the preceding action 3 set sprites for. Change one or both of the feature bytes so they agree. 53: "Rand02s require power-of-two sets to choose from." (Error) This random action 2 has an invalid nrand value. Set the nrand value to 02, 04, 08, 10, 20, 40, or 80. 55: " is neither callback nor cargo ID." (Error) This action 2/3 attempts to use an invalid ID. If you are trying to declare a callback, ensure that the high bit is set. Otherwise, ensure that you padded the ID with "00". 56: " Sprite set does not appear in the preceding ..." (Error) This standard action 2 attempts to use sets that are not defined by the preceding action 1. Add sprites to the action 1 or choose a defined spriteset for the action 2. 57: " Invalid cargo type: ..." (Error) This action 3 declares a cargo-specific cargoID for a cargo-type that does not exist. This may also mean that the cargo does not appear in the cargo translation table. Change the cargo type, remove the cargo type/cargoID pair, or add the cargo to the cargo translation table. 58: "Action 2 declaring no sprites." (Error) This standard action 2 declares no sprites for loadstate/loadingstates/ numlotssets. Although not strictly an error, this is asking for a divide-by-0 error. Change the offending byte. 59: "Signals require 48, 112, or 240 (0x30, 0x70, or 0xF0) sprites." (Error) 60: "Expected (0x) sprites for this type." (Error) The numsprites declared by this action 5 does not agree with the feature for which these sprites will be used. Correct the sprite so numsprites and feature agree. Valid values for numsprites are listed. 62: " ID has not been defined." (Error) This action 2/3 attempts to use an undefined ID. 63: "Expected more properties." (Error) This Action 0 ended before all properties declared were found. Add missing properties, or reduce the number of properties you are setting. 64: "Expected more data for prop . ( bytes at .)" (Fatal) 65: "Expected more bytes for prop ." (Error) Property does not have enough data. Add missing data. The action 0 parser thought it should be able to read bytes at (or at the end of the sprite). This does not necessarily mean that just adding enough bytes to make that possible will fix the sprite. 66: "Property data is missing terminating byte(s)." (Error) This sprite contains a variable-lengthed data that requires terminating byte(s), but they were not found. Check the sprite for variable-lengthed data, and make sure the terminator exists. 67: "Action already found at sprite ." (Error) This NFO file has two or more action 8/11s. Remove one of the action 8/11s. 68: "An action 8 must precede action ." (Error) No action 8 has been seen. Add an action 8 before this sprite. This error will only be issued once. Note that not all action Ds require a preceding 8; this message will not be issued on non-resource-management Ds. 69: "Invalid version number." (Error) The version number listed in this sprite is out of range for the object it encodes. Correct the version number. 71: "Variable size is invalid." (Fatal) 72: "Condition is invalid." (Error) This Action 7 or 9 sets or to invalid values. See the wiki for valid values and meanings. 73: "Condition requires variable 88." (Error) 74: "Variable 88 requires a GRFid condition." (Error) One of the five GRFid conditions was attempted on a variable other than 88, or vice versa. Change the condition and/or variable so they agree. 75: "Variable reqires a bit-test condition." (Error) A bit-test variable is paired with an non-bit-test condition. Change the condition or the variable. 76: "Variable is byte(s) long." (Warn 2) This variable/var-size pairing is invalid. Change the variable or the variable size. 78: " was found where literal was expected." (Error) The byte at was expected to be . Change the byte at , and/or check the feature byte. 79: "Expected more strings for this action 4." (Error) This action 4 contains too few "00" bytes for the number of strings it declares. Check that the strings are terminated, add strings, and/or reduce num-ent. 80: " Value of / must not exceed 10h." (Warn 3) or was set to too high a value. Reduce the offset. 81: "TTD only defines sprites up to 4984 (1E 13)." (Error) Access was attemted to a TTD sprite that TTD doesn't define. Reduce the sprite number. 82: "Color translation mode 3 is undefined." (Error) A color translation of 3 was requested, but only 0-2 are valid. Change the color translation mode. 83: "Sprite is not a color translation sprite." (Warn 1) Color translation was requested, but a sprite that is not a color translation sprite was specified. Specify a color translation sprite or turn off color translation. 84: "No ground sprite was specified." (Error) 84: "No non-transparent sprite was specified." (Error) This house/industry tile was specified with neither a groundsprite nor non-transparent building sprite. Specify a ground sprite or at least one non-transparent building sprite. 85: "No standard action 3 exists prior to this livery override..." (Error) A livery override action 3 was the first action 3 seen in the file. Correct this sprite, or add a standard action 3. This message will only be issued once, even if multiple override 3s precede the first standard 3. 86: " Testing nonexistant variable ." (Error/Warn 1) This variational action 2 or action 7 tests a variable that does not exist. Change the feature, type, and/or variable. 87: "Action 6 attempts to modify data beyond the end of this sprite." (Error) The action 6 preceding this message attempts to add data to the end of this sprite. Add padding to the end of this sprite, or fix the action 6. 88: "There is no following sprite for this Action 6 to modify." (Error) An Action 6 is the last sprite in the file. Remove the action 6 or add additional sprites to the file. 89: "Action 1/A/12 declaring no sets" (Warn 1) 90: "Action 1 declaring sets with no sprites" (Warn 1) The values numsets or numsprites, respectively, are 0. Remove the Action 1/A/12, or set numsets/numsprites to their correct value. 91: " Set contains no sprites" (Warn 1) This action A/12 declares a set with no sprites. Remove this spriteset, or set numsprites to a non-zero value. 92: "Action 0 setting no properties." (Warn 1) 93: "Action 0 setting properties for no IDs." (Warn 1) The num-props or num-info bytes are 0. Set the num-props and num-info bytes to non-zero values, or remove the action 0. 94: "Redefining ID not used since previous definition ..." (Warn 1) has not been used since its previous definition Remove one definition, or add an Action 2/3 that references that ID between the two definitions. 95: "For feature the following cargoIDs have not been used..." (Warn 1) The following list of cargoIDs were defined but never used. Remove the definition, or add an action 2/3 that references the CargoID 97: "Set defined by the previous Action 1 ..." (Warn 1) The previous Action 1 declared graphics that have not yet been referenced by an Action 2. Remove the unreferenced graphics or add an Action 2 that references them. 98: "Variation cannot be reached." (Warn 1/4) Variation has minval>maxval, or is completely obscured by earlier variations. Remove this variation or change minval and/or maxval such that minval<=maxval. This warning is level 4 on the first variation ( = 1) and level 1 on all others. See also message 169. 99: " No more data was expected." (Warn 2) Extraneous data was found. Remove the extra bytes or increase , , or . 100: "Default ID appears earlier in sprite" (Warn 1/3) The default CargoID for this variational action 2 or action 3 appears multiple times. Remove the earlier references to the default CargoID or change the default CargoID. 101: "GRFIDs with a first byte of FF are reserved." (Warn 1) This action 8 declares GRFID with a first byte of FF. Change the GRFID. GRFIDs with a first byte of FF (with the exception of FFFFFFFF) are reserved for TTDPatch internal use, and must not be used by GRF files. 103: " Shifting variable past its length." (Warn 1/4) is shifting this variable further than its defined length. Reduce so defined data is being read. All 80+x variables are defined to be 1 byte long, even if TTD considers that location to contain a word or a double. Overshifting an 80+x is a level 4 warning. 104: "Action 6 does not make any changes." (Warn 1) 105: " This section does not make any changes." (Warn 1) This action 6, or a portion thereof, does not make any changes to the following sprite. Remove the action 6, or fix it and/or the offending subsection so it changes the next sprite. 107: "Label