/* * pHatt - PalmOS(TM) Hattrick (http://www.hattrick.org) Manager Assistant * * convert.c - convert .hrf's to .pdb's * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include "resource.h" #include "hrf2pdb.h" #define TYPE 1147237473 #define CREATOR 1883791732 #define TIMEDIFF 2082844800 /* Position Weights */ static char posWeights[] = { /* form, exp, sta, goa, play, pass, wing, defe, scor, sett, lead */ 0x37, 0x32, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Keep */ 0x37, 0x32, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, /* Def */ 0x37, 0x32, 0x0a, 0x00, 0x03, 0x00, 0x0c, 0x4b, 0x00, 0x00, 0x00, /* DefW */ 0x37, 0x32, 0x0a, 0x00, 0x11, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, /* DefO */ 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, 0x00, 0x00, 0x00, /* WBac */ 0x37, 0x32, 0x00, 0x00, 0x05, 0x00, 0x28, 0x37, 0x00, 0x00, 0x00, /* WBOf */ 0x37, 0x32, 0x0a, 0x00, 0x00, 0x00, 0x0f, 0x4b, 0x00, 0x00, 0x00, /* WBMi */ 0x37, 0x32, 0x00, 0x00, 0x00, 0x00, 0x14, 0x50, 0x00, 0x00, 0x00, /* WBDe */ 0x37, 0x32, 0x14, 0x00, 0x32, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x00, /* Mid */ 0x37, 0x32, 0x14, 0x00, 0x32, 0x19, 0x00, 0x05, 0x00, 0x00, 0x00, /* MidO */ 0x37, 0x32, 0x14, 0x00, 0x23, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, /* MidW */ 0x37, 0x32, 0x14, 0x00, 0x32, 0x0c, 0x00, 0x12, 0x00, 0x00, 0x00, /* MidD */ 0x37, 0x32, 0x07, 0x00, 0x1a, 0x0f, 0x27, 0x0d, 0x00, 0x00, 0x00, /* Wing */ 0x37, 0x32, 0x0c, 0x00, 0x14, 0x06, 0x3c, 0x02, 0x00, 0x00, 0x00, /* WOff */ 0x37, 0x32, 0x07, 0x00, 0x22, 0x0f, 0x1f, 0x0d, 0x00, 0x00, 0x00, /* WMid */ 0x37, 0x32, 0x07, 0x00, 0x1a, 0x0f, 0x1d, 0x17, 0x00, 0x00, 0x00, /* WDef */ 0x37, 0x32, 0x0a, 0x00, 0x03, 0x1d, 0x00, 0x00, 0x3a, 0x00, 0x00, /* For */ 0x37, 0x32, 0x0a, 0x00, 0x0d, 0x20, 0x00, 0x00, 0x2d, 0x00, 0x00, /* ForD */ 0x37, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, /* Capt */ 0x37, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00 /* Sett */ }; /* Functions */ static unsigned int get32(char *w) { return (w[0] >= 0 ? w[0] : w[0] + 256) * 16777216 + (w[1] >= 0 ? w[1] : w[1] + 256) * 65536 + (w[2] >= 0 ? w[2] : w[2] + 256) * 256 + (w[3] >= 0 ? w[3] : w[3] + 256) ; } static void set32(char *w, unsigned int n) { w[0] = n / 16777216; w[1] = (n % 16777216) / 65536; w[2] = (n % 65536) / 256; w[3] = n % 256; } static unsigned int get16(char *w) { return ( w[0] >= 0 ? w[0] : w[0] + 256) * 256 + ( w[1] >= 0 ? w[1] : w[1] + 256); } static void set16(char *w, unsigned int n) { w[0] = n / 256; w[1] = n % 256; } static int sortbyage(const void *a, const void *b) { if ( ((struct player *)*(int *)a)->age < ((struct player *)*(int *)b)->age ) return -1; if ( ((struct player *)*(int *)a)->age > ((struct player *)*(int *)b)->age ) return 1; return 0; } static int sortbyvalue(const void *a, const void *b) { if ( ((struct player *)*(int *)a)->value < ((struct player *)*(int *)b)->value ) return -1; if ( ((struct player *)*(int *)a)->value > ((struct player *)*(int *)b)->value ) return 1; return 0; } static int sortbyname(const void *a, const void *b) { return strcmp(((struct player *)*(int *)a)->name, ((struct player *)*(int *)b)->name); } static void recordheader(FILE *f, unsigned int offset, char *uniqueid) { char w[4]; set32(w, offset); putc(w[0], f); /* offset */ putc(w[1], f); putc(w[2], f); putc(w[3], f); set32(uniqueid, get32(uniqueid) + 1); putc(64, f); /* attributes */ putc(uniqueid[1], f); /* offset */ putc(uniqueid[2], f); putc(uniqueid[3], f); } static int getCountry(int c) { switch ( c ) { case 1: return Country_Sverige; case 2: return Country_England; case 3: return Country_Deutschland; case 4: return Country_Italia; case 5: return Country_France; case 6: return Country_Mexico; case 7: return Country_Argentina; case 8: return Country_USA; case 9: return Country_Norge; case 10: return Country_Danmark; case 11: return Country_Suomi; case 12: return Country_Nederland; case 13: return Country_Oceania; case 14: return Country_Brasil; case 15: return Country_Canada; case 16: return Country_Chile; case 17: return Country_Colombia; case 18: return Country_India; case 19: return Country_Ireland; case 20: return Country_Nippon; case 21: return Country_Peru; case 22: return Country_Polska; case 23: return Country_Portugal; case 24: return Country_Scotland; case 25: return Country_SthAfrica; case 26: return Country_Uruguay; case 27: return Country_Venezuela; case 28: return Country_Korea; case 29: return Country_Thai; case 30: return Country_Turkiye; case 31: return Country_Egypt; case 32: return Country_China; case 33: return Country_Rossiya; case 34: return Country_Espana; case 35: return Country_Portugal; case 36: return Country_Island; case 37: return Country_Oesterreich; case 38: return Country_Belgie; case 39: return Country_Malaysia; case 40: return Country_Schweiz; case 41: return Country_Singapore; case 42: return Country_Hellas; case 43: return Country_Hungary; case 44: return Country_Ceska; case 45: return Country_Latvija; case 46: return Country_Indonesia; case 47: return Country_Pilipinas; case 48: return Country_Eesti; case 49: return Country_Srbija; case 50: return Country_Hrvatska; case 51: return Country_HongKong; case 52: return Country_Taiwan; case 53: return Country_Wales; case 54: return Country_Bulgaria; case 55: return Country_Israel; case 56: return Country_Slovenija; case 57: return Country_Lietuva; case 58: return Country_Slovakia; case 59: return Country_Ukraina; case 60: return Country_Bosnia; case 61: return Country_Vietnam; case 62: return Country_Pakistan; default: return Country_England; } } static char *convertUTF(char *l) { char *p, *n, *r; unsigned char c, d; if ( ! (r = (char *) malloc(strlen(l)))) usage(ERR_ALLOC); p = l; n = r; while ( *p != '\r' ) { c = *p; if ( c >= 0x90 ) { if ( (c & 0xfc) != 0xc0 ) { /* Character that quite probably can't * be translated to the Palm-Charset, * so just leave an ? for now */ *n = '?'; p++; if ( c < 0xc0 ) usage(ERR_UTF); if ( c > 0xe0 ) p++; if ( c > 0xf0 ) p++; if ( c > 0xf8 ) p++; if ( c > 0xfc ) p++; if ( c > 0xfe ) p++; } else { c &= 0x03; c <<= 6; p++; d = *p; if ( (d & 0xc0) != 0x80 ) usage(ERR_UTF); d &= 0x3f; *n = c | d; } } else *n = *p; p++; n++; } *n = '\0'; return r; } static int parseHRF(FILE *f, struct player *p[], struct preferences *s) { int state = 0; /* FSM: 0 nowhere, 1 in player, * 2 in arena, 3 in club, 4 in basic */ int player = -1; char line[1024]; int version = 100; while (( fgets(line, 1024, f))) { if ( strstr(line, "[player") == line ) { player++; if ( ! (p[player] = (struct player *) malloc(sizeof(struct player)))) usage(ERR_ALLOC); p[player]->id = atoi(line+7); state = 1; } if ( strstr(line, "[arena]") == line ) state = 2; if ( strstr(line, "[club]") == line) state = 3; if ( strstr(line, "[basics]") == line) state = 4; if ( state == 2 && strstr(line, "antalStaplats=") == line ) { set32(s->arenaHasTerraces, atoi(line+14)); } if ( state == 2 && strstr(line, "antalSitt=") == line) set32(s->arenaHasBasic, atoi(line+10)); if ( state == 2 && strstr(line, "antalTak=") == line) set32(s->arenaHasRoof, atoi(line+9)); if ( state == 2 && strstr(line, "antalVIP=") == line) set32(s->arenaHasVIP, atoi(line+9)); if ( state == 3 && strstr(line, "fanclub=") == line ) set32(s->supporters, atoi(line+8)); if ( state == 4 && strstr(line, "countryID=") == line ) set16(s->country, getCountry(atoi(line+10))); if ( state == 4 && strstr(line, "version=") == line ) version = atoi(line+8); if ( state == 1 && strstr(line, "name=") == line ) { if ( ! (p[player]->name = malloc(strlen(line) - 4))) usage(ERR_ALLOC); /* Windows seems to fuck up without this */ memset(p[player]->name, 0, strlen(line) - 4); if ( version > 100 ) strcpy(p[player]->name, convertUTF(line+5)); else strncpy(p[player]->name, line+5, strlen(line) - 7); } if ( state == 1 && strstr(line, "ald=") == line ) p[player]->age = atoi(line+4); if ( state == 1 && strstr(line, "for=") == line ) p[player]->form = atoi(line+4) - 1; if ( state == 1 && strstr(line, "uth=") == line ) p[player]->stamina = atoi(line+4) - 1; if ( state == 1 && strstr(line, "spe=") == line ) p[player]->playmaking = atoi(line+4) - 1; if ( state == 1 && strstr(line, "mal=") == line ) p[player]->scoring = atoi(line+4) - 1; if ( state == 1 && strstr(line, "fra=") == line ) p[player]->passing = atoi(line+4) - 1; if ( state == 1 && strstr(line, "ytt=") == line ) p[player]->winging = atoi(line+4) - 1; if ( state == 1 && strstr(line, "fas=") == line ) p[player]->setting = atoi(line+4) - 1; if ( state == 1 && strstr(line, "bac=") == line ) p[player]->defending = atoi(line+4) - 1; if ( state == 1 && strstr(line, "mlv=") == line ) p[player]->goalie = atoi(line+4) - 1; if ( state == 1 && strstr(line, "rut=") == line ) p[player]->experience = atoi(line+4) - 1; if ( state == 1 && strstr(line, "led=") == line ) p[player]->leading = atoi(line+4) - 1; if ( state == 1 && strstr(line, "mkt=") == line ) p[player]->value = atoi(line+4); if ( state == 1 && strstr(line, "honesty=") == line ) p[player]->honest = atoi(line+8); if ( state == 1 && strstr(line, "gentleness=") == line ) p[player]->nice = atoi(line+11); if ( state == 1 && strstr(line, "Aggressiveness=") == line ) p[player]->wild = atoi(line+15); if ( state == 1 && strstr(line, "ska=") == line ) { if ( atoi(line+4) > 0 ) p[player]->injured = atoi(line+4); else p[player]->injured = 0; } if ( state == 1 && strstr(line, "speciality=") == line ) { switch ( atoi(line+11) ) { case 1: /* Technical */ p[player]->speciality = 1; break; case 2: /* Quick */ p[player]->speciality = 2; break; case 3: /* Powerful */ p[player]->speciality = 3; break; case 4: /* Unpredictable */ p[player]->speciality = 5; break; case 5: /* Head */ p[player]->speciality = 4; break; default: p[player]->speciality = 0; break; } } } return player + 1; } static struct changes *fillChanges(struct player *p, struct player *op[], int nop) { int i; struct changes *c; if (! (c = (struct changes *)malloc(sizeof(struct changes)))) usage(ERR_ALLOC); memset(c, 0, sizeof(struct changes)); for ( i = 0; i < nop; i++ ) { if ( op[i]->id && op[i]->id == p->id ) { c->form = p->form - op[i]->form; c->experience = p->experience - op[i]->experience; c->stamina = p->stamina - op[i]->stamina; c->winging = p->winging - op[i]->winging; c->goalie = p->goalie - op[i]->goalie; c->defending = p->defending - op[i]->defending; c->playmaking = p->playmaking - op[i]->playmaking; c->scoring = p->scoring - op[i]->scoring; c->passing = p->passing - op[i]->passing; c->setting = p->setting - op[i]->setting; set32(c->value, p->value - op[i]->value); } } return c; } static unsigned int getTransfer(struct player *p, struct player *op[], int nop) { int i; for ( i = 0; i < nop; i++ ) if ( op[i]->id && op[i]->id == p->id ) return op[i]->transfer; return 0; } /* * MAIN */ int convert (char *oldfile, char *hrffile, char *newfile) { FILE *old, *new, *hrf; int i, j; struct player *players[50]; struct player *oldplayers[50]; struct pplayer player; struct preferences prefs; struct database dbheader; struct changes *dp; char *datap; int nof_players = 0, old_nofp; char uniqueid[4]; int c; int nof_records; int offset = 0; int nooldb = 0; unsigned int now; /* Very basic checking */ if ( ! ( newfile && hrffile )) usage(ERR_EMPTY); if ( oldfile ) { if ( ! ( old = fopen(oldfile, "rb"))) usage(ERR_OLD); if ( ! ( hrf = fopen(hrffile, "rb"))) usage(ERR_HRF); if ( ! ( new = fopen(newfile, "wb"))) usage(ERR_NEW); } else { nooldb = 1; old = NULL; if ( ! ( hrf = fopen(hrffile, "rb"))) usage(ERR_HRF); if ( ! ( new = fopen(newfile, "wb"))) usage(ERR_NEW); } now = time(NULL) + TIMEDIFF; if ( nooldb ) { sprintf(dbheader.name, "pHattDB"); set16(dbheader.attributes, 0); set16(dbheader.version, 1); set32(dbheader.creation_date, now); set32(dbheader.modification_date, now); set32(dbheader.backup_date, 0); set32(dbheader.modification_number, 1); set32(dbheader.app_info_id, 0); set32(dbheader.sort_info_id, 0); set32(dbheader.type, TYPE); set32(dbheader.creator, CREATOR); set32(dbheader.uniqueidseed, 0); set32(dbheader.next_record_list, 0); set16(dbheader.number_of_records, 0); old_nofp = 0; set16(prefs.country, Country_England); prefs.isalarm = '\0'; prefs.positionPage = 0; set16(prefs.selectedScreen, PlayerScreen); set16(prefs.selectedPlayer, 0); set16(prefs.selectedEditPage, PlayerEditScreen); set16(prefs.selectedPositionPage, PositionScreen); set16(prefs.prefsPlayerScreen, PrefsKeeper); set16(prefs.prefsPrevScreen, PlayerScreen); set16(prefs.prefsAttitude, PosNormalButton); prefs.selectedArena = 1; prefs.arenaPessimistic = 20; prefs.arenaNormal = 25; prefs.arenaOptimistic = 30; prefs.arenaTerraces = 62; prefs.arenaBasic = 25; prefs.arenaRoof = 10; prefs.arenaVIP = 3; set16(prefs.orderby, PrefsOrderName); for ( i = 0; i < 220; i++ ) prefs.positionWeight[i] = posWeights[i]; } else { /* Read in old Database */ datap = (char *) &dbheader; for ( i = 0; i < sizeof(struct database); i++) *datap++ = getc(old); /* Check whether it's one of ours */ if ( ! ( dbheader.name[0] == 'p') ) usage(ERR_DB); if ( ! ( dbheader.name[1] == 'H') ) usage(ERR_DB); if ( ! ( dbheader.name[2] == 'a') ) usage(ERR_DB); if ( ! ( dbheader.name[3] == 't') ) usage(ERR_DB); if ( ! ( dbheader.name[4] == 't') ) usage(ERR_DB); if ( ! ( dbheader.name[5] == 'D') ) usage(ERR_DB); if ( ! ( dbheader.name[6] == 'B') ) usage(ERR_DB); if ( ! ( dbheader.name[7] == '\0') ) usage(ERR_DB); if ( ! ( get32(dbheader.type) == TYPE ) ) usage(ERR_DB); if ( ! ( get32(dbheader.creator) == CREATOR ) ) usage(ERR_DB); /* Skip old record headers */ for ( i = 0; i < 8 * dbheader.number_of_records[1] + 3; i++ ) getc(old); /* Read in the version */ c = getc(old); if ( c != 1 ) usage(ERR_VERSION); /* Read in the prefs */ datap = (char *) &prefs; for ( i = 0; i < sizeof(struct preferences); i++) *datap++ = getc(old); /* Read in the old players */ old_nofp = getc(old); /* printf("Loading %i old players\n", old_nofp); */ for ( j = 0; j < old_nofp; j++ ) { datap = (char *) &player; for ( i = 0; i < sizeof(struct pplayer); i++ ) *datap++ = getc(old); if ( ! (oldplayers[j] = (struct player *)malloc(sizeof (struct player)))) usage(ERR_ALLOC); oldplayers[j]->age = player.age; oldplayers[j]->form = player.form; oldplayers[j]->injured = player.injured; oldplayers[j]->nice = player.nice; oldplayers[j]->wild = player.wild; oldplayers[j]->honest = player.honest; oldplayers[j]->value = get32(player.value); oldplayers[j]->experience = player.experience; oldplayers[j]->stamina = player.stamina; oldplayers[j]->winging = player.winging; oldplayers[j]->goalie = player.goalie; oldplayers[j]->defending = player.defending; oldplayers[j]->leading = player.leading; oldplayers[j]->playmaking = player.playmaking; oldplayers[j]->scoring = player.scoring; oldplayers[j]->passing = player.passing; oldplayers[j]->setting = player.setting; oldplayers[j]->speciality = player.speciality; oldplayers[j]->namelen = player.namelen; oldplayers[j]->transfer = get32(player.transfer); oldplayers[j]->id = get32(player.id); if (! (oldplayers[j]->name = (char *)malloc(player.namelen + 1))) usage(ERR_ALLOC); datap = (char *) oldplayers[j]->name; for ( i = 0; i < player.namelen; i++ ) *datap++ = getc(old); } fclose(old); } /* Parse the HRF file */ nof_players = parseHRF(hrf, players, &prefs); fclose(hrf); if ( ! nof_players ) usage(ERR_NOPLAYER); /* printf("%i players found\n", nof_players); */ /* Sort the players according to preferences */ switch ( get16(prefs.orderby) ) { case PrefsOrderAge: qsort(players, nof_players, sizeof(struct player *), sortbyage); break; case PrefsOrderValue: qsort(players, nof_players, sizeof(struct player *), sortbyvalue); break; case PrefsOrderName: qsort(players, nof_players, sizeof(struct player *), sortbyname); break; } /* Increment the modification number */ set32(dbheader.modification_number, get32(dbheader.modification_number) + 1); /* Set the modification date */ set32(dbheader.modification_date, now); /* Reset the next record list (should be 0 anyway, just make sure) */ for ( i = 0; i < 4; i++ ) dbheader.next_record_list[i] = 0; /* Set the new number of records */ nof_records = 3 + 2 * nof_players; dbheader.number_of_records[1] = nof_records; /* We can only have 50 players, so it's always just one byte */ /* Initalize the unique-id-seed */ set32(dbheader.uniqueidseed, nof_records + 2); /* Write out the db-header */ datap = (char *) &dbheader; for ( i = 0; i < sizeof(struct database); i++) putc(*datap++, new); /* Write out the record headers */ set32(uniqueid, 1); offset = sizeof(struct database) + nof_records * 8 + 2; recordheader(new, offset, uniqueid); /* version */ offset += 2; recordheader(new, offset, uniqueid); /* prefs */ offset += sizeof(struct preferences); recordheader(new, offset, uniqueid); /* nofplayers */ offset++; for ( i = 0; i < nof_players ; i++ ) { recordheader(new, offset, uniqueid); /* player */ offset += sizeof(struct pplayer); recordheader(new, offset, uniqueid); /* player name */ offset += strlen(players[i]->name) + 1; } putc(0, new); /* Padding */ putc(0, new); /* Write version record */ putc(0, new); /* Version 1 */ putc(1, new); nof_records = 3 + 2 * nof_players; /* Make sure we don't select a non-existing player */ if ( get16(prefs.selectedPlayer) > nof_players ) set16(prefs.selectedPlayer, nof_players); /* Write the prefs */ datap = (char *) &prefs; for ( i = 0; i < sizeof(struct preferences); i++ ) putc(*datap++, new); /* Write the number of players */ putc(nof_players, new); /* Finally write the players */ for ( i = 0; i < nof_players; i++ ) { for ( j = 0; j < 4; j++ ) player.nextp[j] = 0; for ( j = 0; j < 4; j++ ) player.namep[j] = 0; set32(player.id, players[i]->id); player.age = players[i]->age; player.form = players[i]->form; player.injured = players[i]->injured; player.nice = players[i]->nice; player.wild = players[i]->wild; player.honest = players[i]->honest; set32(player.value, players[i]->value); player.experience = players[i]->experience; player.stamina = players[i]->stamina; player.winging = players[i]->winging; player.goalie = players[i]->goalie; player.defending = players[i]->defending; player.leading = players[i]->leading; player.playmaking = players[i]->playmaking; player.scoring = players[i]->scoring; player.passing = players[i]->passing; player.setting = players[i]->setting; player.speciality = players[i]->speciality; player.namelen = strlen(players[i]->name) + 1; set32(player.transfer, getTransfer(players[i], oldplayers, old_nofp)); dp = fillChanges(players[i], oldplayers, old_nofp); memcpy(&player.changes, dp, sizeof(struct changes)); free(dp); datap = (char *) &player; for ( j = 0; j < sizeof(struct pplayer); j++) putc(*datap++, new); fprintf(new, players[i]->name); putc(0, new); } fclose(new); return 0; }