@@ -994,50 +994,49 @@ static bool CheckSubsidyDuplicate(Subsid
for (ss = _subsidies; ss != endof(_subsidies); ss++) {
if (s != ss &&
ss->from == s->from &&
ss->to == s->to &&
ss->cargo_type == s->cargo_type) {
s->cargo_type = CT_INVALID;
return true;
}
return false;
static void SubsidyMonthlyHandler(void)
{
Subsidy *s;
Pair pair;
Station *st;
uint n;
FoundRoute fr;
bool modified = false;
for(s=_subsidies; s != endof(_subsidies); s++) {
if (s->cargo_type == CT_INVALID)
continue;
if (s->cargo_type == CT_INVALID) continue;
if (s->age == 12-1) {
pair = SetupSubsidyDecodeParam(s, 1);
AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
modified = true;
} else if (s->age == 2*12-1) {
st = GetStation(s->to);
if (st->owner == _local_player) {
AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NEWS_FLAGS(NM_NORMAL, NF_TILE, NT_SUBSIDIES, 0), pair.a, pair.b);
} else {
s->age++;
// 25% chance to go on
if (CHANCE16(1,4)) {
// Find a free slot
s = _subsidies;
while (s->cargo_type != CT_INVALID) {
@@ -202,50 +202,49 @@ void GenerateWorld(int mode, uint size_x
if (mode == GW_EMPTY) {
// empty world in scenario editor
ConvertGroundTilesIntoWaterTiles();
GenerateLandscape();
GenerateClearTile();
// only generate towns, tree and industries in newgame mode.
if (mode == GW_NEWGAME) {
GenerateTowns();
GenerateTrees();
GenerateIndustries();
GenerateUnmovables();
// These are probably pointless when inside the scenario editor.
StartupPlayers();
StartupEngines();
StartupDisasters();
_generating_world = false;
// No need to run the tile loop in the scenario editor.
if (mode != GW_EMPTY) {
for(i=0x500; i!=0; i--)
RunTileLoop();
for (i = 0x500; i != 0; i--) RunTileLoop();
ResetObjectToPlace();
void DeleteName(StringID id)
if ((id & 0xF800) == 0x7800) {
memset(_name_array[id & 0x1FF], 0, sizeof(_name_array[id & 0x1FF]));
char *GetName(int id, char *buff)
return strecpy(buff, _name_array[id & ~0x600], NULL);
static void InitializeCheats(void)
memset(&_cheats, 0, sizeof(Cheats));
@@ -1355,50 +1355,51 @@ static void SaveLoadDlgWndProc(Window *w
HandleButtonClick(w, 12);
break;
case WE_TIMEOUT:
if (HASBIT(w->click_state, 11)) { /* Delete button clicked */
if (!FiosDelete(WP(w,querystr_d).text.buf)) {
ShowErrorMessage(INVALID_STRING_ID, STR_4008_UNABLE_TO_DELETE_FILE, 0, 0);
SetWindowDirty(w);
BuildFileList();
if (_saveload_mode == SLD_SAVE_GAME) {
GenerateFileName(); /* Reset file name to current date */
UpdateTextBufferSize(&WP(w, querystr_d).text);
} else if (HASBIT(w->click_state, 12)) { /* Save button clicked */
_switch_mode = SM_SAVE;
FiosMakeSavegameName(_file_to_saveload.name, WP(w,querystr_d).text.buf);
/* In the editor set up the vehicle engines correctly (date might have changed) */
if (_game_mode == GM_EDITOR) StartupEngines();
case WE_DESTROY:
// pause is only used in single-player, non-editor mode, non menu mode
if(!_networking && (_game_mode != GM_EDITOR) && (_game_mode != GM_MENU))
if (!_networking && _game_mode != GM_EDITOR && _game_mode != GM_MENU) {
DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
FiosFreeSavegameList();
CLRBIT(_no_scroll, SCROLL_SAVE);
case WE_RESIZE: {
/* Widget 2 and 3 have to go with halve speed, make it so obiwan */
uint diff = e->sizing.diff.x / 2;
w->widget[2].right += diff;
w->widget[3].left += diff;
w->widget[3].right += e->sizing.diff.x;
/* Same for widget 11 and 12 in save-dialog */
if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
w->widget[11].right += diff;
w->widget[12].left += diff;
w->widget[12].right += e->sizing.diff.x;
w->vscroll.cap += e->sizing.diff.y / 10;
} break;
static const WindowDesc _load_dialog_desc = {
WDP_CENTER, WDP_CENTER, 257, 294,
@@ -355,50 +355,49 @@ bad_town_name:;
str = SPECSTR_ANDCO_NAME;
strp = p->president_name_2;
goto set_name;
strp = Random();
goto verify_name;
#define COLOR_SWAP(i,j) do { byte t=colors[i];colors[i]=colors[j];colors[j]=t; } while(0)
static const byte _color_sort[16] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1};
static const byte _color_similar_1[16] = {8, 6, 255, 12, 255, 0, 1, 1, 0, 13, 11, 10, 3, 9, 15, 14};
static const byte _color_similar_2[16] = {5, 7, 255, 255, 255, 8, 7, 6, 5, 12, 255, 255, 9, 255, 255, 255};
static byte GeneratePlayerColor(void)
byte colors[16], pcolor, t2;
int i,j,n;
uint32 r;
Player *p;
// Initialize array
for(i=0; i!=16; i++)
colors[i] = i;
for (i = 0; i != 16; i++) colors[i] = i;
// And randomize it
n = 100;
do {
r = Random();
COLOR_SWAP(GB(r, 0, 4), GB(r, 4, 4));
} while (--n);
// Bubble sort it according to the values in table 1
i = 16;
for(j=0; j!=15; j++) {
if (_color_sort[colors[j]] < _color_sort[colors[j+1]]) {
COLOR_SWAP(j,j+1);
} while (--i);
// Move the colors that look similar to each player's color to the side
FOR_ALL_PLAYERS(p) if (p->is_active) {
pcolor = p->player_color;
for(i=0; i!=16; i++) if (colors[i] == pcolor) {
colors[i] = 0xFF;
@@ -1232,49 +1231,50 @@ static const SaveLoad _player_ai_desc[]
SLE_ARR(PlayerAI,wagon_list, SLE_UINT16, 9),
SLE_ARR(PlayerAI,order_list_blocks, SLE_UINT8, 20),
SLE_ARR(PlayerAI,banned_tiles, SLE_UINT16, 16),
SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 8, 2, 255),
SLE_END()
};
static const SaveLoad _player_ai_build_rec_desc[] = {
SLE_CONDVAR(AiBuildRec,spec_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
SLE_CONDVAR(AiBuildRec,spec_tile, SLE_UINT32, 6, 255),
SLE_CONDVAR(AiBuildRec,use_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
SLE_CONDVAR(AiBuildRec,use_tile, SLE_UINT32, 6, 255),
SLE_VAR(AiBuildRec,rand_rng, SLE_UINT8),
SLE_VAR(AiBuildRec,cur_building_rule,SLE_UINT8),
SLE_VAR(AiBuildRec,unk6, SLE_UINT8),
SLE_VAR(AiBuildRec,unk7, SLE_UINT8),
SLE_VAR(AiBuildRec,buildcmd_a, SLE_UINT8),
SLE_VAR(AiBuildRec,buildcmd_b, SLE_UINT8),
SLE_VAR(AiBuildRec,direction, SLE_UINT8),
SLE_VAR(AiBuildRec,cargo, SLE_UINT8),
static void SaveLoad_PLYR(Player *p) {
static void SaveLoad_PLYR(Player* p)
int i;
SlObject(p, _player_desc);
// Write AI?
if (!IS_HUMAN_PLAYER(p->index)) {
SlObject(&p->ai, _player_ai_desc);
for(i=0; i!=p->ai.num_build_rec; i++)
SlObject(&p->ai.src + i, _player_ai_build_rec_desc);
// Write economy
SlObject(&p->cur_economy, _player_economy_desc);
// Write old economy entries.
PlayerEconomyEntry *pe;
for(i=p->num_valid_stat_ent,pe=p->old_economy; i!=0; i--,pe++)
SlObject(pe, _player_economy_desc);
static void Save_PLYR(void)
@@ -757,53 +757,51 @@ static void SlSaveChunks(void)
while (true) {
if (((ch->flags >> CH_PRI_SHL) & (CH_NUM_PRI_LEVELS - 1)) == p)
SlSaveChunk(ch);
if (ch->flags & CH_LAST)
ch++;
// Terminator
SlWriteUint32(0);
/** Find the ChunkHandler that will be used for processing the found
* chunk in the savegame or in memory
* @param id the chunk in question
* @return returns the appropiate chunkhandler
*/
static const ChunkHandler *SlFindChunkHandler(uint32 id)
const ChunkHandler *ch;
const ChunkHandler *const *chsc;
for (chsc = _sl.chs; (ch=*chsc++) != NULL;) {
while(true) {
if (ch->id == id)
return ch;
for (;;) {
if (ch->id == id) return ch;
if (ch->flags & CH_LAST) break;
return NULL;
/** Load all chunks */
static void SlLoadChunks(void)
uint32 id;
for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
DEBUG(misc, 1) ("Loading chunk %c%c%c%c", id >> 24, id>>16, id>>8, id);
ch = SlFindChunkHandler(id);
if (ch == NULL) SlError("found unknown tag in savegame (sync error)");
SlLoadChunk(ch);
//*******************************************
//********** START OF LZO CODE **************
@@ -409,48 +409,49 @@ static bool load_intlist(const char *str
switch(type) {
case SDT_INT8 >> 4:
case SDT_UINT8 >> 4:
for(i=0; i!=nitems; i++) ((byte*)array)[i] = items[i];
case SDT_INT16 >> 4:
case SDT_UINT16 >> 4:
for(i=0; i!=nitems; i++) ((uint16*)array)[i] = items[i];
case SDT_INT32 >> 4:
case SDT_UINT32 >> 4:
for(i=0; i!=nitems; i++) ((uint32*)array)[i] = items[i];
default:
NOT_REACHED();
static void make_intlist(char *buf, void *array, int nelems, int type)
int i, v = 0;
byte *p = (byte*)array;
for(i=0; i!=nelems; i++) {
case SDT_INT8 >> 4: v = *(int8*)p; p += 1; break;
case SDT_UINT8 >> 4:v = *(byte*)p; p += 1; break;
case SDT_INT16 >> 4:v = *(int16*)p; p += 2; break;
case SDT_UINT16 >> 4:v = *(uint16*)p; p += 2; break;
case SDT_INT32 >> 4:v = *(int32*)p; p += 4; break;
case SDT_UINT32 >> 4:v = *(uint32*)p; p += 4; break;
default: NOT_REACHED();
buf += sprintf(buf, i ? ",%d" : "%d", v);
static void make_oneofmany(char *buf, const char *many, int i)
int orig_i = i;
char c;
while (--i >= 0) {
many++;
if (many[-1] == 0) {
sprintf(buf, "%d", orig_i);
@@ -283,50 +283,49 @@ char *ParseWord(char **buf)
// proceed until whitespace or NUL
r = s;
for(;;) {
if (*s == 0)
if (*s == ' ' || *s == '\t') {
*s++ = 0;
s++;
*buf = s;
return r;
// Forward declaration
static int TranslateArgumentIdx(int arg);
static void EmitWordList(char **words, int nw)
int i,j;
PutByte(nw);
for(i=0; i<nw; i++)
PutByte(strlen(words[i]));
for (i = 0; i < nw; i++) PutByte(strlen(words[i]));
for(i=0; i<nw; i++) {
for(j=0; words[i][j]; j++)
PutByte(words[i][j]);
static void EmitPlural(char *buf, int value)
int argidx = _cur_argidx;
char *words[5];
int nw = 0;
// Parse out the number, if one exists. Otherwise default to prev arg.
if (!ParseRelNum(&buf, &argidx))
argidx--;
// Parse each string
for (nw = 0; nw < 5; nw++) {
words[nw] = ParseWord(&buf);
if (!words[nw])
if (nw == 0)
@@ -344,50 +343,49 @@ static void EmitPlural(char *buf, int va
for(; nw < _plural_form_counts[_lang_pluralform]; nw++) {
words[nw] = words[nw - 1];
PutByte(0x8D);
PutByte(TranslateArgumentIdx(argidx));
EmitWordList(words, nw);
static void EmitGender(char *buf, int value)
char *words[8];
int nw;
if (buf[0] == '=') {
buf++;
// This is a {G=DER} command
for(nw=0; ;nw++) {
if (nw >= 8)
Fatal("G argument '%s' invalid", buf);
if (nw >= 8) Fatal("G argument '%s' invalid", buf);
if (!strcmp(buf, _genders[nw]))
// now nw contains the gender index
PutByte(0x87);
// This is a {G 0 foo bar two} command.
// If no relative number exists, default to +0
if (!ParseRelNum(&buf, &argidx)) {}
for(nw=0; nw<8; nw++) {
if (nw != _numgenders) Fatal("Bad # of arguments for gender command");
PutByte(0x85);
PutByte(13);
@@ -445,48 +445,49 @@ static int DeterminePluralForm(int32 n)
// Used in:
// Croatian, Czech, Russian, Slovak, Ukrainian
case 6:
return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
// Three forms, special case for one and some numbers ending in 2, 3, or 4
// Polish
case 7:
return n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
// Four forms, special case for one and all numbers ending in 02, 03, or 04
// Slovenian
case 8:
return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;
static const char *ParseStringChoice(const char *b, uint form, char *dst, int *dstlen)
//<NUM> {Length of each string} {each string}
uint n = (byte)*b++;
uint pos,i, mylen=0,mypos=0;
for(i=pos=0; i!=n; i++) {
uint len = (byte)*b++;
if (i == form) {
mypos = pos;
mylen = len;
pos += len;
*dstlen = mylen;
memcpy(dst, b + mypos, mylen);
return b + pos;
static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei)
byte b;
const int32 *argv_orig = argv;
uint modifier = 0;
while ((b = *str++) != '\0') {
switch (b) {
case 0x1: // {SETX}
*buff++ = b;
@@ -1152,50 +1152,49 @@ int GetTownRadiusGroup(const Town *t, Ti
smallest = 0;
for (i = 0; i != lengthof(t->radius); i++) {
if (dist < t->radius[i])
smallest = i;
return smallest;
static bool CheckFree2x2Area(Town *t1, TileIndex tile)
static const TileIndexDiffC _tile_add[] = {
{0 , 0 },
{0 - 0, 1 - 0},
{1 - 0, 0 - 1},
{1 - 1, 1 - 0}
for(i=0; i!=4; i++) {
tile += ToTileIndexDiff(_tile_add[i]);
if (GetTileSlope(tile, NULL))
if (GetTileSlope(tile, NULL)) return false;
if (CmdFailed(DoCommandByTile(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_FORCETEST, CMD_LANDSCAPE_CLEAR)))
static void DoBuildTownHouse(Town *t, TileIndex tile)
uint bitmask;
int house;
uint slope;
uint z;
uint oneof;
// Above snow?
slope = GetTileSlope(tile, &z);
// Get the town zone type
uint rad = GetTownRadiusGroup(t, tile);
@@ -2193,49 +2193,49 @@ static bool CheckReverseTrain(Vehicle *v
if (_patches.new_pathfinding_all) { /* Use a new pathfinding for everything */
NPFFindStationOrTileData fstd;
NPFFoundTargetData ftd;
byte trackdir, trackdir_rev;
Vehicle* last = GetLastVehicleInChain(v);
NPFFillWithOrderData(&fstd, v);
trackdir = GetVehicleTrackdir(v);
trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
assert(trackdir != 0xff);
assert(trackdir_rev != 0xff);
ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, last->tile, trackdir_rev, &fstd, TRANSPORT_RAIL, v->owner, v->u.rail.railtype);
if (ftd.best_bird_dist != 0) {
/* We didn't find anything, just keep on going straight ahead */
reverse_best = false;
if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE))
reverse_best = true;
else
fd.best_bird_dist = (uint)-1;
fd.best_track_dist = (uint)-1;
NewTrainPathfind(v->tile, v->dest_tile, reverse ^ i, (NTPEnumProc*)NtpCallbFindStation, &fd);
if (best_track != -1) {
if (best_bird_dist != 0) {
if (fd.best_bird_dist != 0) {
/* neither reached the destination, pick the one with the smallest bird dist */
if (fd.best_bird_dist > best_bird_dist) goto bad;
if (fd.best_bird_dist < best_bird_dist) goto good;
/* we found the destination for the first time */
goto good;
/* didn't find destination, but we've found the destination previously */
goto bad;
/* both old & new reached the destination, compare track length */
if (fd.best_track_dist > best_track_dist) goto bad;
if (fd.best_track_dist < best_track_dist) goto good;
@@ -987,50 +987,56 @@ static void DrawBridgePillars(const Tile
if (image != 0) {
int back_height, front_height, i=z;
const byte *p;
static const byte _tileh_bits[4][8] = {
{2,1,8,4, 16,11,0,9},
{1,8,4,2, 11,16,9,0},
{4,8,1,2, 16,11,0,9},
{2,4,8,1, 11,16,9,0},
if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image);
p = _tileh_bits[(image & 1) * 2 + (ti->map5&0x01)];
front_height = ti->z + ((ti->tileh & p[0])?8:0);
back_height = ti->z + ((ti->tileh & p[1])?8:0);
if (IsSteepTileh(ti->tileh)) {
if (!(ti->tileh & p[2])) front_height += 8;
if (!(ti->tileh & p[3])) back_height += 8;
for(; z>=front_height || z>=back_height; z=z-8) {
if (z>=front_height) AddSortableSpriteToDraw(image, x,y, p[4], p[5], 0x28, z); // front facing pillar
if (z>=back_height && z<i-8) AddSortableSpriteToDraw(image, x - p[6], y - p[7], p[4], p[5], 0x28, z); // back facing pillar
if (z >= front_height) {
// front facing pillar
AddSortableSpriteToDraw(image, x,y, p[4], p[5], 0x28, z);
if (z >= back_height && z < i - 8) {
// back facing pillar
AddSortableSpriteToDraw(image, x - p[6], y - p[7], p[4], p[5], 0x28, z);
uint GetBridgeFoundation(uint tileh, byte direction)
// normal level sloped building (7, 11, 13, 14)
if (BRIDGE_FULL_LEVELED_FOUNDATION & (1 << tileh))
return tileh;
// inclined sloped building
if ( ((i=0, tileh == 1) || (i+=2, tileh == 2) || (i+=2, tileh == 4) || (i+=2, tileh == 8)) &&
( direction == 0 || (i++, direction == 1)) )
return i + 15;
return 0;
/**
* Draws a tunnel of bridge tile.
* For tunnels, this is rather simple, as you only needa draw the entrance.
* Bridges are a bit more complex. base_offset is where the sprite selection comes into play
* and it works a bit like a bitmask.<p> For bridge heads:
@@ -1924,50 +1924,49 @@ byte GetDirectionTowards(const Vehicle *
int i = 0;
if (y >= v->y_pos) {
if (y != v->y_pos) i+=3;
i+=3;
if (x >= v->x_pos) {
if (x != v->x_pos) i++;
i++;
dir = v->direction;
dirdiff = _new_direction_table[i] - dir;
if (dirdiff == 0)
return dir;
return (dir+((dirdiff&7)<5?1:-1)) & 7;
Trackdir GetVehicleTrackdir(const Vehicle* v)
if (v->vehstatus & VS_CRASHED) return 0xFF;
switch(v->type)
switch (v->type) {
case VEH_Train:
if (v->u.rail.track == 0x80) /* We'll assume the train is facing outwards */
return DiagdirToDiagTrackdir(GetDepotDirection(v->tile, TRANSPORT_RAIL)); /* Train in depot */
if (v->u.rail.track == 0x40) /* train in tunnel, so just use his direction and assume a diagonal track */
return DiagdirToDiagTrackdir((v->direction >> 1) & 3);
return TrackDirectionToTrackdir(FIND_FIRST_BIT(v->u.rail.track),v->direction);
case VEH_Ship:
if (v->u.ship.state == 0x80) /* Inside a depot? */
/* We'll assume the ship is facing outwards */
return DiagdirToDiagTrackdir(GetDepotDirection(v->tile, TRANSPORT_WATER)); /* Ship in depot */
return TrackDirectionToTrackdir(FIND_FIRST_BIT(v->u.ship.state),v->direction);
case VEH_Road:
if (v->u.road.state == 254) /* We'll assume the road vehicle is facing outwards */
return DiagdirToDiagTrackdir(GetDepotDirection(v->tile, TRANSPORT_ROAD)); /* Road vehicle in depot */
if (IsRoadStationTile(v->tile)) /* We'll assume the road vehicle is facing outwards */
return DiagdirToDiagTrackdir(GetRoadStationDir(v->tile)); /* Road vehicle in a station */
@@ -688,49 +688,49 @@ static void Win32GdiMakeDirty(int left,
if (_wnd.double_size) {
filter(left, top, width, height);
r.left *= 2;
r.top *= 2;
r.right *= 2;
r.bottom *= 2;
InvalidateRect(_wnd.main_wnd, &r, FALSE);
static void CheckPaletteAnim(void)
if (_pal_last_dirty == -1)
return;
InvalidateRect(_wnd.main_wnd, NULL, FALSE);
static void Win32GdiMainLoop(void)
MSG mesg;
uint32 next_tick = GetTickCount() + 30, cur_ticks;
_wnd.running = true;
while (PeekMessage(&mesg, NULL, 0, 0, PM_REMOVE)) {
InteractiveRandom(); // randomness
TranslateMessage(&mesg);
DispatchMessage(&mesg);
if (_exit_game) return;
#if defined(_DEBUG)
if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0) {
if (
#else
if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0) {
/* Disable speeding up game with ALT+TAB (if syskey is pressed, the
* real key is in the upper 16 bits (see WM_SYSKEYDOWN in WndProcGdi()) */
if ((_pressed_key >> 16) & WKC_TAB &&
#endif
!_networking && _game_mode != GM_MENU)
_fast_forward |= 2;
} else if (_fast_forward & 2)
_fast_forward = 0;
cur_ticks = GetTickCount();
if ((_fast_forward && !_pause) || cur_ticks > next_tick)
next_tick = cur_ticks;
@@ -120,49 +120,49 @@ static void MakeCRCTable(uint32 *table)
static uint32 CalcCRC(byte *data, uint size, uint32 crc) {
for (; size > 0; size--) {
crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF];
return crc;
static void GetFileInfo(DebugFileInfo *dfi, const char *filename)
memset(dfi, 0, sizeof(dfi));
HANDLE file;
byte buffer[1024];
DWORD numread;
uint32 filesize = 0;
FILETIME write_time;
uint32 crc = (uint32)-1;
file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, 0);
if (file != INVALID_HANDLE_VALUE) {
if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 ||
numread == 0)
filesize += numread;
crc = CalcCRC(buffer, numread, crc);
dfi->size = filesize;
dfi->crc32 = crc ^ (uint32)-1;
if (GetFileTime(file, NULL, NULL, &write_time)) {
FileTimeToSystemTime(&write_time, &dfi->file_time);
CloseHandle(file);
static char *PrintModuleInfo(char *output, HMODULE mod)
char buffer[MAX_PATH];
DebugFileInfo dfi;
GetModuleFileName(mod, buffer, MAX_PATH);
Status change: