forgot to commit lol
This commit is contained in:
parent
4e43c73f9c
commit
6612d0731f
90
cmd/loginServer/clients.go
Normal file
90
cmd/loginServer/clients.go
Normal file
@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
type ClientState int
|
||||
|
||||
const (
|
||||
StateConnected ClientState = iota
|
||||
StateAuthenticated
|
||||
StateCharacterSelect
|
||||
StateDisconnected
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
conn gnet.Conn
|
||||
address string
|
||||
connected time.Time
|
||||
lastActive time.Time
|
||||
state ClientState
|
||||
accountID uint32
|
||||
accountName string
|
||||
version int16
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
type ClientManager struct {
|
||||
clients map[int]*Client
|
||||
db *sqlitex.Pool
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewClientManager(db *sqlitex.Pool) *ClientManager {
|
||||
return &ClientManager{
|
||||
clients: make(map[int]*Client),
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (cm *ClientManager) AddClient(fd int, client *Client) {
|
||||
cm.mu.Lock()
|
||||
defer cm.mu.Unlock()
|
||||
cm.clients[fd] = client
|
||||
}
|
||||
|
||||
func (cm *ClientManager) RemoveClient(fd int) {
|
||||
cm.mu.Lock()
|
||||
defer cm.mu.Unlock()
|
||||
delete(cm.clients, fd)
|
||||
}
|
||||
|
||||
func (cm *ClientManager) GetClient(fd int) *Client {
|
||||
cm.mu.RLock()
|
||||
defer cm.mu.RUnlock()
|
||||
return cm.clients[fd]
|
||||
}
|
||||
|
||||
func (cm *ClientManager) CleanupExpired() {
|
||||
cm.mu.Lock()
|
||||
defer cm.mu.Unlock()
|
||||
|
||||
cutoff := time.Now().Add(-30 * time.Minute)
|
||||
for fd, client := range cm.clients {
|
||||
if client.lastActive.Before(cutoff) {
|
||||
client.conn.Close()
|
||||
delete(cm.clients, fd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cm *ClientManager) GetStats() (int, int) {
|
||||
cm.mu.RLock()
|
||||
defer cm.mu.RUnlock()
|
||||
|
||||
total := len(cm.clients)
|
||||
authenticated := 0
|
||||
|
||||
for _, client := range cm.clients {
|
||||
if client.state == StateAuthenticated {
|
||||
authenticated++
|
||||
}
|
||||
}
|
||||
|
||||
return total, authenticated
|
||||
}
|
86
cmd/loginServer/config.go
Normal file
86
cmd/loginServer/config.go
Normal file
@ -0,0 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Server ServerConfig `json:"server"`
|
||||
Database DatabaseConfig `json:"database"`
|
||||
Web WebConfig `json:"web"`
|
||||
Game GameConfig `json:"game"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Port int `json:"port"`
|
||||
MaxClients int `json:"max_clients"`
|
||||
MaxWorldServers int `json:"max_world_servers"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type WebConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Address string `json:"address"`
|
||||
Port int `json:"port"`
|
||||
CertFile string `json:"cert_file"`
|
||||
KeyFile string `json:"key_file"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type GameConfig struct {
|
||||
AllowAccountCreation bool `json:"allow_account_creation"`
|
||||
ExpansionFlag uint32 `json:"expansion_flag"`
|
||||
CitiesFlag uint8 `json:"cities_flag"`
|
||||
DefaultSubscriptionLevel uint32 `json:"default_subscription_level"`
|
||||
EnabledRaces uint32 `json:"enabled_races"`
|
||||
MaxCharactersPerAccount int `json:"max_characters_per_account"`
|
||||
}
|
||||
|
||||
func LoadConfig(filename string) (*Config, error) {
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
// Return default config if file doesn't exist
|
||||
return getDefaultConfig(), nil
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := json.Unmarshal(data, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func getDefaultConfig() *Config {
|
||||
return &Config{
|
||||
Server: ServerConfig{
|
||||
Port: 5998,
|
||||
MaxClients: 1000,
|
||||
MaxWorldServers: 10,
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Path: "login.db",
|
||||
},
|
||||
Web: WebConfig{
|
||||
Enabled: true,
|
||||
Address: "0.0.0.0",
|
||||
Port: 8080,
|
||||
Username: "admin",
|
||||
Password: "password",
|
||||
},
|
||||
Game: GameConfig{
|
||||
AllowAccountCreation: true,
|
||||
ExpansionFlag: 0x7CFF,
|
||||
CitiesFlag: 0xFF,
|
||||
DefaultSubscriptionLevel: 0xFFFFFFFF,
|
||||
EnabledRaces: 0xFFFF,
|
||||
MaxCharactersPerAccount: 7,
|
||||
},
|
||||
}
|
||||
}
|
201
cmd/loginServer/database.go
Normal file
201
cmd/loginServer/database.go
Normal file
@ -0,0 +1,201 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
)
|
||||
|
||||
func authenticateUser(conn *sqlite.Conn, username, password string, allowCreate bool) (bool, uint32, error) {
|
||||
stmt := conn.Prep("SELECT id, password FROM accounts WHERE name = ?")
|
||||
stmt.BindText(1, username)
|
||||
|
||||
if hasRow, err := stmt.Step(); err != nil {
|
||||
return false, 0, err
|
||||
} else if !hasRow {
|
||||
if allowCreate {
|
||||
return createAccount(conn, username, password)
|
||||
}
|
||||
return false, 0, nil
|
||||
}
|
||||
|
||||
accountID := stmt.ColumnInt64(0)
|
||||
storedPassword := stmt.ColumnText(1)
|
||||
|
||||
if verifyPassword(password, storedPassword) {
|
||||
return true, uint32(accountID), nil
|
||||
}
|
||||
|
||||
return false, 0, nil
|
||||
}
|
||||
|
||||
func createAccount(conn *sqlite.Conn, username, password string) (bool, uint32, error) {
|
||||
hashedPassword := hashPassword(password)
|
||||
|
||||
stmt := conn.Prep("INSERT INTO accounts (name, password, created_date) VALUES (?, ?, ?)")
|
||||
stmt.BindText(1, username)
|
||||
stmt.BindText(2, hashedPassword)
|
||||
stmt.BindInt64(3, time.Now().Unix())
|
||||
|
||||
if _, err := stmt.Step(); err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
accountID := conn.LastInsertRowID()
|
||||
return true, uint32(accountID), nil
|
||||
}
|
||||
|
||||
func hashPassword(password string) string {
|
||||
hash := sha512.Sum512([]byte(password))
|
||||
return fmt.Sprintf("%x", hash)
|
||||
}
|
||||
|
||||
func verifyPassword(password, stored string) bool {
|
||||
return hashPassword(password) == stored
|
||||
}
|
||||
|
||||
func getCharacterList(conn *sqlite.Conn, accountID uint32) ([]*Character, error) {
|
||||
stmt := conn.Prep(`
|
||||
SELECT id, name, race, class, gender, level, current_zone_id,
|
||||
server_id, created_date, last_played
|
||||
FROM login_characters
|
||||
WHERE account_id = ? AND deleted = 0
|
||||
`)
|
||||
stmt.BindInt64(1, int64(accountID))
|
||||
|
||||
var characters []*Character
|
||||
|
||||
for {
|
||||
hasRow, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !hasRow {
|
||||
break
|
||||
}
|
||||
|
||||
char := &Character{
|
||||
ID: uint32(stmt.ColumnInt64(0)),
|
||||
Name: stmt.ColumnText(1),
|
||||
Race: uint8(stmt.ColumnInt64(2)),
|
||||
Class: uint8(stmt.ColumnInt64(3)),
|
||||
Gender: uint8(stmt.ColumnInt64(4)),
|
||||
Level: uint8(stmt.ColumnInt64(5)),
|
||||
Zone: getZoneName(stmt.ColumnInt64(6)),
|
||||
ServerID: uint32(stmt.ColumnInt64(7)),
|
||||
Created: stmt.ColumnInt64(8),
|
||||
LastLogin: stmt.ColumnInt64(9),
|
||||
}
|
||||
|
||||
characters = append(characters, char)
|
||||
}
|
||||
|
||||
return characters, nil
|
||||
}
|
||||
|
||||
func createCharacter(conn *sqlite.Conn, accountID uint32, req *CreateCharacterRequest) (uint32, error) {
|
||||
// Check if name is taken
|
||||
stmt := conn.Prep("SELECT id FROM login_characters WHERE name = ? AND deleted = 0")
|
||||
stmt.BindText(1, req.Name)
|
||||
|
||||
if hasRow, err := stmt.Step(); err != nil {
|
||||
return 0, err
|
||||
} else if hasRow {
|
||||
return 0, fmt.Errorf("name already taken")
|
||||
}
|
||||
|
||||
// Create character
|
||||
stmt = conn.Prep(`
|
||||
INSERT INTO login_characters (
|
||||
account_id, server_id, char_id, name, race, class, gender,
|
||||
deity, body_size, body_age, created_date
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`)
|
||||
|
||||
stmt.BindInt64(1, int64(accountID))
|
||||
stmt.BindInt64(2, int64(req.ServerID))
|
||||
stmt.BindInt64(3, generateCharacterID())
|
||||
stmt.BindText(4, req.Name)
|
||||
stmt.BindInt64(5, int64(req.Race))
|
||||
stmt.BindInt64(6, int64(req.Class))
|
||||
stmt.BindInt64(7, int64(req.Gender))
|
||||
stmt.BindInt64(8, int64(req.Deity))
|
||||
stmt.BindFloat(9, float64(req.BodySize))
|
||||
stmt.BindFloat(10, float64(req.BodyAge))
|
||||
stmt.BindInt64(11, time.Now().Unix())
|
||||
|
||||
if _, err := stmt.Step(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return uint32(conn.LastInsertRowID()), nil
|
||||
}
|
||||
|
||||
func deleteCharacter(conn *sqlite.Conn, accountID, characterID uint32) error {
|
||||
stmt := conn.Prep(`
|
||||
UPDATE login_characters
|
||||
SET deleted = 1
|
||||
WHERE id = ? AND account_id = ?
|
||||
`)
|
||||
stmt.BindInt64(1, int64(characterID))
|
||||
stmt.BindInt64(2, int64(accountID))
|
||||
|
||||
_, err := stmt.Step()
|
||||
return err
|
||||
}
|
||||
|
||||
func generateCharacterID() int64 {
|
||||
return time.Now().UnixNano() / 1000000 // Use timestamp as unique ID
|
||||
}
|
||||
|
||||
func getZoneName(zoneID int64) string {
|
||||
// Simple zone mapping - in real implementation this would be from database
|
||||
zones := map[int64]string{
|
||||
1: "Qeynos",
|
||||
2: "Freeport",
|
||||
3: "Kelethin",
|
||||
4: "Neriak",
|
||||
5: "Gorowyn",
|
||||
6: "New Halas",
|
||||
7: "Queen's Colony",
|
||||
8: "Outpost of the Overlord",
|
||||
}
|
||||
|
||||
if name, exists := zones[zoneID]; exists {
|
||||
return name
|
||||
}
|
||||
return "Unknown Zone"
|
||||
}
|
||||
|
||||
func updateCharacterLastLogin(conn *sqlite.Conn, characterID uint32) error {
|
||||
stmt := conn.Prep("UPDATE login_characters SET last_played = ? WHERE id = ?")
|
||||
stmt.BindInt64(1, time.Now().Unix())
|
||||
stmt.BindInt64(2, int64(characterID))
|
||||
|
||||
_, err := stmt.Step()
|
||||
return err
|
||||
}
|
||||
|
||||
func getAccountStats(conn *sqlite.Conn) (int, int, error) {
|
||||
// Total accounts
|
||||
stmt := conn.Prep("SELECT COUNT(*) FROM accounts")
|
||||
if hasRow, err := stmt.Step(); err != nil {
|
||||
return 0, 0, err
|
||||
} else if !hasRow {
|
||||
return 0, 0, nil
|
||||
}
|
||||
totalAccounts := int(stmt.ColumnInt64(0))
|
||||
|
||||
// Total characters
|
||||
stmt = conn.Prep("SELECT COUNT(*) FROM login_characters WHERE deleted = 0")
|
||||
if hasRow, err := stmt.Step(); err != nil {
|
||||
return 0, 0, err
|
||||
} else if !hasRow {
|
||||
return totalAccounts, 0, nil
|
||||
}
|
||||
totalCharacters := int(stmt.ColumnInt64(0))
|
||||
|
||||
return totalAccounts, totalCharacters, nil
|
||||
}
|
267
cmd/loginServer/main.go
Normal file
267
cmd/loginServer/main.go
Normal file
@ -0,0 +1,267 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
"github.com/valyala/fasthttp"
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
type LoginServer struct {
|
||||
config *Config
|
||||
db *sqlitex.Pool
|
||||
clients *ClientManager
|
||||
worlds *WorldManager
|
||||
opcodes map[int16]*OpcodeManager
|
||||
webServer *fasthttp.Server
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
mu sync.RWMutex
|
||||
running bool
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
func main() {
|
||||
server := &LoginServer{
|
||||
startTime: time.Now(),
|
||||
}
|
||||
|
||||
if err := server.initialize(); err != nil {
|
||||
log.Fatalf("Failed to initialize server: %v", err)
|
||||
}
|
||||
|
||||
server.printHeader()
|
||||
|
||||
if err := server.start(); err != nil {
|
||||
log.Fatalf("Failed to start server: %v", err)
|
||||
}
|
||||
|
||||
// Wait for shutdown signal
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigCh
|
||||
|
||||
log.Println("Shutting down...")
|
||||
server.shutdown()
|
||||
}
|
||||
|
||||
func (s *LoginServer) initialize() error {
|
||||
s.ctx, s.cancel = context.WithCancel(context.Background())
|
||||
|
||||
// Load configuration
|
||||
config, err := LoadConfig("login_config.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.config = config
|
||||
|
||||
// Initialize database
|
||||
if err := s.initDatabase(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize managers
|
||||
s.clients = NewClientManager(s.db)
|
||||
s.worlds = NewWorldManager(s.db)
|
||||
|
||||
// Load opcodes
|
||||
if err := s.loadOpcodes(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize web server
|
||||
s.initWebServer()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LoginServer) initDatabase() error {
|
||||
pool, err := sqlitex.Open(s.config.Database.Path, 0, 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.db = pool
|
||||
|
||||
// Create tables
|
||||
conn := s.db.Get(s.ctx)
|
||||
defer s.db.Put(conn)
|
||||
|
||||
return s.createTables(conn)
|
||||
}
|
||||
|
||||
func (s *LoginServer) createTables(conn *sqlite.Conn) error {
|
||||
schema := `
|
||||
CREATE TABLE IF NOT EXISTS accounts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
created_date INTEGER DEFAULT CURRENT_TIMESTAMP,
|
||||
ip_address TEXT,
|
||||
last_client_version INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS login_characters (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER NOT NULL,
|
||||
server_id INTEGER NOT NULL,
|
||||
char_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
race INTEGER NOT NULL,
|
||||
class INTEGER NOT NULL,
|
||||
gender INTEGER NOT NULL,
|
||||
deity INTEGER NOT NULL,
|
||||
body_size REAL NOT NULL,
|
||||
body_age REAL NOT NULL,
|
||||
level INTEGER DEFAULT 1,
|
||||
current_zone_id INTEGER DEFAULT 1,
|
||||
created_date INTEGER DEFAULT CURRENT_TIMESTAMP,
|
||||
last_played INTEGER,
|
||||
deleted INTEGER DEFAULT 0,
|
||||
FOREIGN KEY(account_id) REFERENCES accounts(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS login_worldservers (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account TEXT UNIQUE NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
admin_id INTEGER DEFAULT 0,
|
||||
disabled INTEGER DEFAULT 0,
|
||||
ip_address TEXT,
|
||||
lastseen INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS login_equipment (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
login_characters_id INTEGER NOT NULL,
|
||||
equip_type INTEGER NOT NULL,
|
||||
red INTEGER NOT NULL,
|
||||
green INTEGER NOT NULL,
|
||||
blue INTEGER NOT NULL,
|
||||
highlight_red INTEGER NOT NULL,
|
||||
highlight_green INTEGER NOT NULL,
|
||||
highlight_blue INTEGER NOT NULL,
|
||||
slot INTEGER NOT NULL,
|
||||
FOREIGN KEY(login_characters_id) REFERENCES login_characters(id)
|
||||
);`
|
||||
|
||||
return sqlitex.ExecScript(conn, schema)
|
||||
}
|
||||
|
||||
func (s *LoginServer) loadOpcodes() error {
|
||||
s.opcodes = make(map[int16]*OpcodeManager)
|
||||
|
||||
// For demo, loading basic opcodes - in real implementation,
|
||||
// these would be loaded from database
|
||||
manager := &OpcodeManager{
|
||||
opcodes: map[string]uint16{
|
||||
"OP_LoginRequestMsg": 0x0001,
|
||||
"OP_LoginReplyMsg": 0x0002,
|
||||
"OP_AllWSDescRequestMsg": 0x0003,
|
||||
"OP_CreateCharacterRequestMsg": 0x0004,
|
||||
"OP_PlayCharacterRequestMsg": 0x0005,
|
||||
"OP_DeleteCharacterRequestMsg": 0x0006,
|
||||
},
|
||||
}
|
||||
|
||||
s.opcodes[1208] = manager // Default version
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LoginServer) initWebServer() {
|
||||
router := &WebRouter{server: s}
|
||||
s.webServer = &fasthttp.Server{
|
||||
Handler: router.Handler,
|
||||
Name: "EQ2LoginWeb",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LoginServer) start() error {
|
||||
s.mu.Lock()
|
||||
s.running = true
|
||||
s.mu.Unlock()
|
||||
|
||||
// Start TCP server for game clients
|
||||
go func() {
|
||||
tcpServer := &TCPServer{
|
||||
server: s,
|
||||
clients: s.clients,
|
||||
worlds: s.worlds,
|
||||
}
|
||||
|
||||
log.Printf("Starting TCP server on port %d", s.config.Server.Port)
|
||||
if err := gnet.Run(tcpServer,
|
||||
"tcp://:"+string(rune(s.config.Server.Port)),
|
||||
gnet.WithMulticore(true),
|
||||
gnet.WithTCPKeepAlive(time.Minute*5)); err != nil {
|
||||
log.Printf("TCP server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Start web server
|
||||
if s.config.Web.Enabled {
|
||||
go func() {
|
||||
addr := s.config.Web.Address + ":" + string(rune(s.config.Web.Port))
|
||||
log.Printf("Starting web server on %s", addr)
|
||||
if err := s.webServer.ListenAndServe(addr); err != nil {
|
||||
log.Printf("Web server error: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Start periodic tasks
|
||||
go s.runPeriodicTasks()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LoginServer) runPeriodicTasks() {
|
||||
ticker := time.NewTicker(time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
s.clients.CleanupExpired()
|
||||
s.worlds.UpdateStats()
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LoginServer) shutdown() {
|
||||
s.mu.Lock()
|
||||
s.running = false
|
||||
s.mu.Unlock()
|
||||
|
||||
s.cancel()
|
||||
|
||||
if s.webServer != nil {
|
||||
s.webServer.Shutdown()
|
||||
}
|
||||
|
||||
if s.db != nil {
|
||||
s.db.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LoginServer) printHeader() {
|
||||
log.Println("===============================================")
|
||||
log.Println(" EverQuest II Login Server - Go Edition")
|
||||
log.Println(" High Performance Game Authentication Server")
|
||||
log.Println("===============================================")
|
||||
log.Printf("Server Port: %d", s.config.Server.Port)
|
||||
if s.config.Web.Enabled {
|
||||
log.Printf("Web Interface: %s:%d", s.config.Web.Address, s.config.Web.Port)
|
||||
}
|
||||
log.Println("Server starting...")
|
||||
}
|
143
cmd/loginServer/opcodes.go
Normal file
143
cmd/loginServer/opcodes.go
Normal file
@ -0,0 +1,143 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Opcodes
|
||||
const (
|
||||
OpLoginRequest uint16 = 0x0001
|
||||
OpLoginReply uint16 = 0x0002
|
||||
OpWorldListRequest uint16 = 0x0003
|
||||
OpWorldListReply uint16 = 0x0004
|
||||
OpCharacterListRequest uint16 = 0x0005
|
||||
OpCharacterListReply uint16 = 0x0006
|
||||
OpCreateCharacter uint16 = 0x0007
|
||||
OpCreateCharacterReply uint16 = 0x0008
|
||||
OpDeleteCharacter uint16 = 0x0009
|
||||
OpDeleteCharacterReply uint16 = 0x000A
|
||||
OpPlayCharacter uint16 = 0x000B
|
||||
OpPlayCharacterReply uint16 = 0x000C
|
||||
OpError uint16 = 0xFFFF
|
||||
)
|
||||
|
||||
var ErrIncompletePacket = errors.New("incomplete packet")
|
||||
|
||||
type EQ2Packet struct {
|
||||
Opcode uint16
|
||||
Size uint16
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Version int16 `json:"version"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
Response uint8 `json:"response"`
|
||||
AccountID uint32 `json:"account_id"`
|
||||
SubLevel uint32 `json:"sub_level"`
|
||||
RaceFlag uint32 `json:"race_flag"`
|
||||
ClassFlag uint32 `json:"class_flag"`
|
||||
Username string `json:"username"`
|
||||
Unknown5 uint32 `json:"unknown5"`
|
||||
CitiesFlag uint8 `json:"cities_flag"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type WorldInfo struct {
|
||||
ID uint32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status uint8 `json:"status"`
|
||||
Players uint32 `json:"players"`
|
||||
MaxPlayers uint32 `json:"max_players"`
|
||||
Address string `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Locked bool `json:"locked"`
|
||||
}
|
||||
|
||||
type WorldListResponse struct {
|
||||
NumWorlds uint32 `json:"num_worlds"`
|
||||
Worlds []*WorldInfo `json:"worlds"`
|
||||
}
|
||||
|
||||
type Character struct {
|
||||
ID uint32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Race uint8 `json:"race"`
|
||||
Class uint8 `json:"class"`
|
||||
Gender uint8 `json:"gender"`
|
||||
Level uint8 `json:"level"`
|
||||
Zone string `json:"zone"`
|
||||
ServerID uint32 `json:"server_id"`
|
||||
Created int64 `json:"created"`
|
||||
LastLogin int64 `json:"last_login"`
|
||||
}
|
||||
|
||||
type CharacterListResponse struct {
|
||||
NumCharacters uint32 `json:"num_characters"`
|
||||
Characters []*Character `json:"characters"`
|
||||
AccountID uint32 `json:"account_id"`
|
||||
MaxChars uint32 `json:"max_chars"`
|
||||
}
|
||||
|
||||
type CreateCharacterRequest struct {
|
||||
Name string `json:"name"`
|
||||
Race uint8 `json:"race"`
|
||||
Class uint8 `json:"class"`
|
||||
Gender uint8 `json:"gender"`
|
||||
Deity uint8 `json:"deity"`
|
||||
BodySize float32 `json:"body_size"`
|
||||
BodyAge float32 `json:"body_age"`
|
||||
ServerID uint32 `json:"server_id"`
|
||||
}
|
||||
|
||||
type CreateCharacterResponse struct {
|
||||
Success bool `json:"success"`
|
||||
CharacterID uint32 `json:"character_id"`
|
||||
Name string `json:"name"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type DeleteCharacterRequest struct {
|
||||
CharacterID uint32 `json:"character_id"`
|
||||
ServerID uint32 `json:"server_id"`
|
||||
}
|
||||
|
||||
type DeleteCharacterResponse struct {
|
||||
Success bool `json:"success"`
|
||||
CharacterID uint32 `json:"character_id"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type PlayCharacterRequest struct {
|
||||
CharacterID uint32 `json:"character_id"`
|
||||
ServerID uint32 `json:"server_id"`
|
||||
}
|
||||
|
||||
type PlayCharacterResponse struct {
|
||||
Success bool `json:"success"`
|
||||
ServerIP string `json:"server_ip"`
|
||||
ServerPort uint16 `json:"server_port"`
|
||||
SessionKey string `json:"session_key"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type OpcodeManager struct {
|
||||
opcodes map[string]uint16
|
||||
}
|
||||
|
||||
func (om *OpcodeManager) GetOpcode(name string) (uint16, bool) {
|
||||
opcode, exists := om.opcodes[name]
|
||||
return opcode, exists
|
||||
}
|
||||
|
||||
func generateSessionKey() string {
|
||||
bytes := make([]byte, 16)
|
||||
rand.Read(bytes)
|
||||
return hex.EncodeToString(bytes)
|
||||
}
|
300
cmd/loginServer/tcp.go
Normal file
300
cmd/loginServer/tcp.go
Normal file
@ -0,0 +1,300 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
)
|
||||
|
||||
type TCPServer struct {
|
||||
gnet.BuiltinEventEngine
|
||||
server *LoginServer
|
||||
clients *ClientManager
|
||||
worlds *WorldManager
|
||||
}
|
||||
|
||||
func (s *TCPServer) OnBoot(eng gnet.Engine) gnet.Action {
|
||||
log.Printf("TCP server started on %s", eng.Addr())
|
||||
return gnet.None
|
||||
}
|
||||
|
||||
func (s *TCPServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) {
|
||||
addr := c.RemoteAddr().String()
|
||||
log.Printf("New connection from %s", addr)
|
||||
|
||||
client := &Client{
|
||||
conn: c,
|
||||
address: addr,
|
||||
connected: time.Now(),
|
||||
state: StateConnected,
|
||||
version: 0,
|
||||
}
|
||||
|
||||
s.clients.AddClient(c.Fd(), client)
|
||||
return nil, gnet.None
|
||||
}
|
||||
|
||||
func (s *TCPServer) OnClose(c gnet.Conn, err error) gnet.Action {
|
||||
s.clients.RemoveClient(c.Fd())
|
||||
if err != nil {
|
||||
log.Printf("Connection closed with error: %v", err)
|
||||
}
|
||||
return gnet.None
|
||||
}
|
||||
|
||||
func (s *TCPServer) OnTraffic(c gnet.Conn) gnet.Action {
|
||||
client := s.clients.GetClient(c.Fd())
|
||||
if client == nil {
|
||||
return gnet.Close
|
||||
}
|
||||
|
||||
for {
|
||||
packet, err := s.readPacket(c)
|
||||
if err != nil {
|
||||
if err != ErrIncompletePacket {
|
||||
log.Printf("Error reading packet: %v", err)
|
||||
return gnet.Close
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if err := s.handlePacket(client, packet); err != nil {
|
||||
log.Printf("Error handling packet: %v", err)
|
||||
return gnet.Close
|
||||
}
|
||||
}
|
||||
|
||||
return gnet.None
|
||||
}
|
||||
|
||||
func (s *TCPServer) readPacket(c gnet.Conn) (*EQ2Packet, error) {
|
||||
// Read packet header (2 bytes length + 2 bytes opcode)
|
||||
if c.InboundBuffered() < 4 {
|
||||
return nil, ErrIncompletePacket
|
||||
}
|
||||
|
||||
header := make([]byte, 4)
|
||||
if _, err := c.Peek(header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
length := binary.LittleEndian.Uint16(header[0:2])
|
||||
opcode := binary.LittleEndian.Uint16(header[2:4])
|
||||
|
||||
totalLength := int(length) + 4 // Add header size
|
||||
if c.InboundBuffered() < totalLength {
|
||||
return nil, ErrIncompletePacket
|
||||
}
|
||||
|
||||
// Read complete packet
|
||||
data := make([]byte, totalLength)
|
||||
if _, err := c.Read(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EQ2Packet{
|
||||
Opcode: opcode,
|
||||
Size: length,
|
||||
Data: data[4:], // Skip header
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *TCPServer) handlePacket(client *Client, packet *EQ2Packet) error {
|
||||
switch packet.Opcode {
|
||||
case OpLoginRequest:
|
||||
return s.handleLoginRequest(client, packet)
|
||||
case OpWorldListRequest:
|
||||
return s.handleWorldListRequest(client, packet)
|
||||
case OpCharacterListRequest:
|
||||
return s.handleCharacterListRequest(client, packet)
|
||||
case OpCreateCharacter:
|
||||
return s.handleCreateCharacter(client, packet)
|
||||
case OpDeleteCharacter:
|
||||
return s.handleDeleteCharacter(client, packet)
|
||||
case OpPlayCharacter:
|
||||
return s.handlePlayCharacter(client, packet)
|
||||
default:
|
||||
log.Printf("Unknown opcode: 0x%04X", packet.Opcode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TCPServer) handleLoginRequest(client *Client, packet *EQ2Packet) error {
|
||||
var loginReq LoginRequest
|
||||
if err := json.Unmarshal(packet.Data, &loginReq); err != nil {
|
||||
return s.sendLoginDenied(client, "Invalid login data")
|
||||
}
|
||||
|
||||
account, err := s.server.db.Get(s.server.ctx)
|
||||
if err != nil {
|
||||
return s.sendLoginDenied(client, "Database error")
|
||||
}
|
||||
defer s.server.db.Put(account)
|
||||
|
||||
// Authenticate user
|
||||
authenticated, accountID, err := authenticateUser(account, loginReq.Username, loginReq.Password, s.server.config.Game.AllowAccountCreation)
|
||||
if err != nil {
|
||||
return s.sendLoginDenied(client, "Authentication failed")
|
||||
}
|
||||
|
||||
if !authenticated {
|
||||
return s.sendLoginDenied(client, "Invalid credentials")
|
||||
}
|
||||
|
||||
client.accountID = accountID
|
||||
client.accountName = loginReq.Username
|
||||
client.state = StateAuthenticated
|
||||
client.version = loginReq.Version
|
||||
|
||||
return s.sendLoginAccepted(client)
|
||||
}
|
||||
|
||||
func (s *TCPServer) sendLoginAccepted(client *Client) error {
|
||||
response := LoginResponse{
|
||||
Response: 1,
|
||||
AccountID: client.accountID,
|
||||
SubLevel: s.server.config.Game.DefaultSubscriptionLevel,
|
||||
RaceFlag: s.server.config.Game.EnabledRaces,
|
||||
ClassFlag: 0x7FFFFFE,
|
||||
Username: client.accountName,
|
||||
Unknown5: s.server.config.Game.ExpansionFlag,
|
||||
CitiesFlag: s.server.config.Game.CitiesFlag,
|
||||
}
|
||||
|
||||
return s.sendPacket(client, OpLoginReply, &response)
|
||||
}
|
||||
|
||||
func (s *TCPServer) sendLoginDenied(client *Client, reason string) error {
|
||||
response := LoginResponse{
|
||||
Response: 0,
|
||||
Reason: reason,
|
||||
}
|
||||
return s.sendPacket(client, OpLoginReply, &response)
|
||||
}
|
||||
|
||||
func (s *TCPServer) handleWorldListRequest(client *Client, packet *EQ2Packet) error {
|
||||
if client.state != StateAuthenticated {
|
||||
return s.sendError(client, "Not authenticated")
|
||||
}
|
||||
|
||||
worlds := s.worlds.GetWorldList()
|
||||
worldList := WorldListResponse{
|
||||
NumWorlds: uint32(len(worlds)),
|
||||
Worlds: worlds,
|
||||
}
|
||||
|
||||
return s.sendPacket(client, OpWorldListReply, &worldList)
|
||||
}
|
||||
|
||||
func (s *TCPServer) handleCharacterListRequest(client *Client, packet *EQ2Packet) error {
|
||||
if client.state != StateAuthenticated {
|
||||
return s.sendError(client, "Not authenticated")
|
||||
}
|
||||
|
||||
conn := s.server.db.Get(s.server.ctx)
|
||||
defer s.server.db.Put(conn)
|
||||
|
||||
characters, err := getCharacterList(conn, client.accountID)
|
||||
if err != nil {
|
||||
return s.sendError(client, "Failed to load characters")
|
||||
}
|
||||
|
||||
charList := CharacterListResponse{
|
||||
NumCharacters: uint32(len(characters)),
|
||||
Characters: characters,
|
||||
AccountID: client.accountID,
|
||||
MaxChars: uint32(s.server.config.Game.MaxCharactersPerAccount),
|
||||
}
|
||||
|
||||
return s.sendPacket(client, OpCharacterListReply, &charList)
|
||||
}
|
||||
|
||||
func (s *TCPServer) sendPacket(client *Client, opcode uint16, data any) error {
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packet := make([]byte, 4+len(jsonData))
|
||||
binary.LittleEndian.PutUint16(packet[0:2], uint16(len(jsonData)))
|
||||
binary.LittleEndian.PutUint16(packet[2:4], opcode)
|
||||
copy(packet[4:], jsonData)
|
||||
|
||||
_, err = client.conn.Write(packet)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TCPServer) sendError(client *Client, message string) error {
|
||||
return s.sendPacket(client, OpError, map[string]string{"error": message})
|
||||
}
|
||||
|
||||
func (s *TCPServer) handleCreateCharacter(client *Client, packet *EQ2Packet) error {
|
||||
var createReq CreateCharacterRequest
|
||||
if err := json.Unmarshal(packet.Data, &createReq); err != nil {
|
||||
return s.sendError(client, "Invalid character data")
|
||||
}
|
||||
|
||||
conn := s.server.db.Get(s.server.ctx)
|
||||
defer s.server.db.Put(conn)
|
||||
|
||||
charID, err := createCharacter(conn, client.accountID, &createReq)
|
||||
if err != nil {
|
||||
return s.sendError(client, "Failed to create character")
|
||||
}
|
||||
|
||||
response := CreateCharacterResponse{
|
||||
Success: true,
|
||||
CharacterID: charID,
|
||||
Name: createReq.Name,
|
||||
}
|
||||
|
||||
return s.sendPacket(client, OpCreateCharacterReply, &response)
|
||||
}
|
||||
|
||||
func (s *TCPServer) handleDeleteCharacter(client *Client, packet *EQ2Packet) error {
|
||||
var deleteReq DeleteCharacterRequest
|
||||
if err := json.Unmarshal(packet.Data, &deleteReq); err != nil {
|
||||
return s.sendError(client, "Invalid delete request")
|
||||
}
|
||||
|
||||
conn := s.server.db.Get(s.server.ctx)
|
||||
defer s.server.db.Put(conn)
|
||||
|
||||
if err := deleteCharacter(conn, client.accountID, deleteReq.CharacterID); err != nil {
|
||||
return s.sendError(client, "Failed to delete character")
|
||||
}
|
||||
|
||||
response := DeleteCharacterResponse{
|
||||
Success: true,
|
||||
CharacterID: deleteReq.CharacterID,
|
||||
}
|
||||
|
||||
return s.sendPacket(client, OpDeleteCharacterReply, &response)
|
||||
}
|
||||
|
||||
func (s *TCPServer) handlePlayCharacter(client *Client, packet *EQ2Packet) error {
|
||||
var playReq PlayCharacterRequest
|
||||
if err := json.Unmarshal(packet.Data, &playReq); err != nil {
|
||||
return s.sendError(client, "Invalid play request")
|
||||
}
|
||||
|
||||
world := s.worlds.GetWorld(playReq.ServerID)
|
||||
if world == nil {
|
||||
return s.sendError(client, "World server not available")
|
||||
}
|
||||
|
||||
// Generate session key and send to world server
|
||||
sessionKey := generateSessionKey()
|
||||
|
||||
response := PlayCharacterResponse{
|
||||
Success: true,
|
||||
ServerIP: world.Address,
|
||||
ServerPort: world.Port,
|
||||
SessionKey: sessionKey,
|
||||
}
|
||||
|
||||
return s.sendPacket(client, OpPlayCharacterReply, &response)
|
||||
}
|
263
cmd/loginServer/web.go
Normal file
263
cmd/loginServer/web.go
Normal file
@ -0,0 +1,263 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
type WebRouter struct {
|
||||
server *LoginServer
|
||||
}
|
||||
|
||||
func (wr *WebRouter) Handler(ctx *fasthttp.RequestCtx) {
|
||||
path := string(ctx.Path())
|
||||
|
||||
// Basic auth check
|
||||
if !wr.checkAuth(ctx) {
|
||||
ctx.Response.Header.Set("WWW-Authenticate", `Basic realm="EQ2 Login Server"`)
|
||||
ctx.SetStatusCode(fasthttp.StatusUnauthorized)
|
||||
ctx.SetBodyString("Unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
switch path {
|
||||
case "/":
|
||||
wr.handleStatus(ctx)
|
||||
case "/status":
|
||||
wr.handleStatus(ctx)
|
||||
case "/worlds":
|
||||
wr.handleWorlds(ctx)
|
||||
case "/clients":
|
||||
wr.handleClients(ctx)
|
||||
case "/stats":
|
||||
wr.handleStats(ctx)
|
||||
default:
|
||||
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||
ctx.SetBodyString("Not Found")
|
||||
}
|
||||
}
|
||||
|
||||
func (wr *WebRouter) checkAuth(ctx *fasthttp.RequestCtx) bool {
|
||||
if wr.server.config.Web.Username == "" {
|
||||
return true // No auth required
|
||||
}
|
||||
|
||||
auth := ctx.Request.Header.Peek("Authorization")
|
||||
if len(auth) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(string(auth), "Basic ") {
|
||||
return false
|
||||
}
|
||||
|
||||
encoded := string(auth[6:])
|
||||
decoded, err := base64.StdEncoding.DecodeString(encoded)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
parts := strings.SplitN(string(decoded), ":", 2)
|
||||
if len(parts) != 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
return parts[0] == wr.server.config.Web.Username &&
|
||||
parts[1] == wr.server.config.Web.Password
|
||||
}
|
||||
|
||||
func (wr *WebRouter) handleStatus(ctx *fasthttp.RequestCtx) {
|
||||
ctx.Response.Header.Set("Content-Type", "application/json")
|
||||
|
||||
totalClients, authClients := wr.server.clients.GetStats()
|
||||
totalWorlds, onlineWorlds := wr.server.worlds.GetStats()
|
||||
|
||||
conn := wr.server.db.Get(wr.server.ctx)
|
||||
defer wr.server.db.Put(conn)
|
||||
|
||||
totalAccounts, totalChars, _ := getAccountStats(conn)
|
||||
|
||||
status := map[string]any{
|
||||
"server_name": "EQ2 Login Server",
|
||||
"status": "online",
|
||||
"uptime": time.Since(wr.server.startTime).Seconds(),
|
||||
"uptime_string": formatDuration(time.Since(wr.server.startTime)),
|
||||
"version": "1.0.0-go",
|
||||
"clients": map[string]int{
|
||||
"total": totalClients,
|
||||
"authenticated": authClients,
|
||||
},
|
||||
"worlds": map[string]int{
|
||||
"total": totalWorlds,
|
||||
"online": onlineWorlds,
|
||||
},
|
||||
"database": map[string]int{
|
||||
"accounts": totalAccounts,
|
||||
"characters": totalChars,
|
||||
},
|
||||
"timestamp": time.Now().Unix(),
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(status)
|
||||
ctx.SetBody(data)
|
||||
}
|
||||
|
||||
func (wr *WebRouter) handleWorlds(ctx *fasthttp.RequestCtx) {
|
||||
ctx.Response.Header.Set("Content-Type", "application/json")
|
||||
|
||||
worlds := wr.server.worlds.GetWorldList()
|
||||
|
||||
response := map[string]any{
|
||||
"worlds": worlds,
|
||||
"count": len(worlds),
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(response)
|
||||
ctx.SetBody(data)
|
||||
}
|
||||
|
||||
func (wr *WebRouter) handleClients(ctx *fasthttp.RequestCtx) {
|
||||
ctx.Response.Header.Set("Content-Type", "application/json")
|
||||
|
||||
wr.server.clients.mu.RLock()
|
||||
defer wr.server.clients.mu.RUnlock()
|
||||
|
||||
clients := make([]map[string]any, 0, len(wr.server.clients.clients))
|
||||
|
||||
for _, client := range wr.server.clients.clients {
|
||||
clients = append(clients, map[string]any{
|
||||
"address": client.address,
|
||||
"connected": client.connected.Unix(),
|
||||
"state": stateToString(client.state),
|
||||
"account_name": client.accountName,
|
||||
"version": client.version,
|
||||
})
|
||||
}
|
||||
|
||||
response := map[string]any{
|
||||
"clients": clients,
|
||||
"count": len(clients),
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(response)
|
||||
ctx.SetBody(data)
|
||||
}
|
||||
|
||||
func (wr *WebRouter) handleStats(ctx *fasthttp.RequestCtx) {
|
||||
ctx.Response.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Get comprehensive stats
|
||||
totalClients, authClients := wr.server.clients.GetStats()
|
||||
totalWorlds, onlineWorlds := wr.server.worlds.GetStats()
|
||||
|
||||
conn := wr.server.db.Get(wr.server.ctx)
|
||||
defer wr.server.db.Put(conn)
|
||||
|
||||
totalAccounts, totalChars, _ := getAccountStats(conn)
|
||||
|
||||
stats := map[string]any{
|
||||
"server": map[string]any{
|
||||
"uptime": time.Since(wr.server.startTime).Seconds(),
|
||||
"start_time": wr.server.startTime.Unix(),
|
||||
"version": "1.0.0-go",
|
||||
},
|
||||
"clients": map[string]any{
|
||||
"total": totalClients,
|
||||
"authenticated": authClients,
|
||||
"guest": totalClients - authClients,
|
||||
},
|
||||
"worlds": map[string]any{
|
||||
"total": totalWorlds,
|
||||
"online": onlineWorlds,
|
||||
"offline": totalWorlds - onlineWorlds,
|
||||
},
|
||||
"database": map[string]any{
|
||||
"accounts": totalAccounts,
|
||||
"characters": totalChars,
|
||||
"avg_chars": float64(totalChars) / float64(max(totalAccounts, 1)),
|
||||
},
|
||||
"config": map[string]any{
|
||||
"max_clients": wr.server.config.Server.MaxClients,
|
||||
"max_world_servers": wr.server.config.Server.MaxWorldServers,
|
||||
"allow_account_creation": wr.server.config.Game.AllowAccountCreation,
|
||||
"max_chars_per_account": wr.server.config.Game.MaxCharactersPerAccount,
|
||||
},
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(stats)
|
||||
ctx.SetBody(data)
|
||||
}
|
||||
|
||||
func stateToString(state ClientState) string {
|
||||
switch state {
|
||||
case StateConnected:
|
||||
return "connected"
|
||||
case StateAuthenticated:
|
||||
return "authenticated"
|
||||
case StateCharacterSelect:
|
||||
return "character_select"
|
||||
case StateDisconnected:
|
||||
return "disconnected"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func formatDuration(d time.Duration) string {
|
||||
days := int(d.Hours()) / 24
|
||||
hours := int(d.Hours()) % 24
|
||||
minutes := int(d.Minutes()) % 60
|
||||
|
||||
if days > 0 {
|
||||
return formatTime(days, "day") + ", " + formatTime(hours, "hour") + ", " + formatTime(minutes, "minute")
|
||||
}
|
||||
if hours > 0 {
|
||||
return formatTime(hours, "hour") + ", " + formatTime(minutes, "minute")
|
||||
}
|
||||
return formatTime(minutes, "minute")
|
||||
}
|
||||
|
||||
func formatTime(value int, unit string) string {
|
||||
if value == 1 {
|
||||
return "1 " + unit
|
||||
}
|
||||
return string(rune(value)) + " " + unit + "s"
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Example login_config.json file
|
||||
const ExampleConfig = `{
|
||||
"server": {
|
||||
"port": 5998,
|
||||
"max_clients": 1000,
|
||||
"max_world_servers": 10
|
||||
},
|
||||
"database": {
|
||||
"path": "login.db"
|
||||
},
|
||||
"web": {
|
||||
"enabled": true,
|
||||
"address": "0.0.0.0",
|
||||
"port": 8080,
|
||||
"username": "admin",
|
||||
"password": "password"
|
||||
},
|
||||
"game": {
|
||||
"allow_account_creation": true,
|
||||
"expansion_flag": 32767,
|
||||
"cities_flag": 255,
|
||||
"default_subscription_level": 4294967295,
|
||||
"enabled_races": 65535,
|
||||
"max_characters_per_account": 7
|
||||
}
|
||||
}`
|
103
cmd/loginServer/worlds.go
Normal file
103
cmd/loginServer/worlds.go
Normal file
@ -0,0 +1,103 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
type WorldServer struct {
|
||||
ID uint32
|
||||
Name string
|
||||
Address string
|
||||
Port uint16
|
||||
Status uint8
|
||||
Players uint32
|
||||
MaxPlayers uint32
|
||||
Locked bool
|
||||
LastUpdate time.Time
|
||||
conn gnet.Conn
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
type WorldManager struct {
|
||||
worlds map[uint32]*WorldServer
|
||||
db *sqlitex.Pool
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
func NewWorldManager(db *sqlitex.Pool) *WorldManager {
|
||||
return &WorldManager{
|
||||
worlds: make(map[uint32]*WorldServer),
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *WorldManager) AddWorld(world *WorldServer) {
|
||||
wm.mu.Lock()
|
||||
defer wm.mu.Unlock()
|
||||
wm.worlds[world.ID] = world
|
||||
}
|
||||
|
||||
func (wm *WorldManager) RemoveWorld(id uint32) {
|
||||
wm.mu.Lock()
|
||||
defer wm.mu.Unlock()
|
||||
delete(wm.worlds, id)
|
||||
}
|
||||
|
||||
func (wm *WorldManager) GetWorld(id uint32) *WorldServer {
|
||||
wm.mu.RLock()
|
||||
defer wm.mu.RUnlock()
|
||||
return wm.worlds[id]
|
||||
}
|
||||
|
||||
func (wm *WorldManager) GetWorldList() []*WorldInfo {
|
||||
wm.mu.RLock()
|
||||
defer wm.mu.RUnlock()
|
||||
|
||||
worlds := make([]*WorldInfo, 0, len(wm.worlds))
|
||||
for _, world := range wm.worlds {
|
||||
worlds = append(worlds, &WorldInfo{
|
||||
ID: world.ID,
|
||||
Name: world.Name,
|
||||
Status: world.Status,
|
||||
Players: world.Players,
|
||||
MaxPlayers: world.MaxPlayers,
|
||||
Address: world.Address,
|
||||
Port: world.Port,
|
||||
Locked: world.Locked,
|
||||
})
|
||||
}
|
||||
|
||||
return worlds
|
||||
}
|
||||
|
||||
func (wm *WorldManager) UpdateStats() {
|
||||
wm.mu.Lock()
|
||||
defer wm.mu.Unlock()
|
||||
|
||||
cutoff := time.Now().Add(-5 * time.Minute)
|
||||
for _, world := range wm.worlds {
|
||||
if world.LastUpdate.Before(cutoff) {
|
||||
world.Status = 0 // Offline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *WorldManager) GetStats() (int, int) {
|
||||
wm.mu.RLock()
|
||||
defer wm.mu.RUnlock()
|
||||
|
||||
total := len(wm.worlds)
|
||||
online := 0
|
||||
|
||||
for _, world := range wm.worlds {
|
||||
if world.Status == 1 {
|
||||
online++
|
||||
}
|
||||
}
|
||||
|
||||
return total, online
|
||||
}
|
29
go.mod
Normal file
29
go.mod
Normal file
@ -0,0 +1,29 @@
|
||||
module eq2emu
|
||||
|
||||
go 1.24.1
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.11.3 // indirect
|
||||
github.com/panjf2000/gnet/v2 v2.9.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.63.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
modernc.org/libc v1.65.7 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.37.1 // indirect
|
||||
zombiezen.com/go/sqlite v1.4.2 // indirect
|
||||
)
|
47
go.sum
Normal file
47
go.sum
Normal file
@ -0,0 +1,47 @@
|
||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
|
||||
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
|
||||
github.com/panjf2000/gnet/v2 v2.9.1 h1:bKewICy/0xnQ9PMzNaswpe/Ah14w1TrRk91LHTcbIlA=
|
||||
github.com/panjf2000/gnet/v2 v2.9.1/go.mod h1:WQTxDWYuQ/hz3eccH0FN32IVuvZ19HewEWx0l62fx7E=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.63.0 h1:DisIL8OjB7ul2d7cBaMRcKTQDYnrGy56R4FCiuDP0Ns=
|
||||
github.com/valyala/fasthttp v1.63.0/go.mod h1:REc4IeW+cAEyLrRPa5A81MIjvz0QE1laoTX2EaPHKJM=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
modernc.org/libc v1.65.7 h1:Ia9Z4yzZtWNtUIuiPuQ7Qf7kxYrxP1/jeHZzG8bFu00=
|
||||
modernc.org/libc v1.65.7/go.mod h1:011EQibzzio/VX3ygj1qGFt5kMjP0lHb0qCW5/D/pQU=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/sqlite v1.37.1 h1:EgHJK/FPoqC+q2YBXg7fUmES37pCHFc97sI7zSayBEs=
|
||||
modernc.org/sqlite v1.37.1/go.mod h1:XwdRtsE1MpiBcL54+MbKcaDvcuej+IYSMfLN6gSKV8g=
|
||||
zombiezen.com/go/sqlite v1.4.2 h1:KZXLrBuJ7tKNEm+VJcApLMeQbhmAUOKA5VWS93DfFRo=
|
||||
zombiezen.com/go/sqlite v1.4.2/go.mod h1:5Kd4taTAD4MkBzT25mQ9uaAlLjyR0rFhsR6iINO70jc=
|
469
internal/opcodes/game.go
Normal file
469
internal/opcodes/game.go
Normal file
@ -0,0 +1,469 @@
|
||||
package opcodes
|
||||
|
||||
// Game application opcodes from emu_oplist.h
|
||||
const (
|
||||
OP_Unknown = 0
|
||||
|
||||
// Core game messages
|
||||
OP_ESInitMsg = iota + 100
|
||||
OP_ESReadyForClientsMsg
|
||||
OP_CreateZoneInstanceMsg
|
||||
OP_ZoneInstanceCreateReplyMsg
|
||||
OP_ZoneInstanceDestroyedMsg
|
||||
OP_ExpectClientAsCharacterRequest
|
||||
OP_ExpectClientAsCharacterReplyMsg
|
||||
OP_ZoneInfoMsg
|
||||
OP_DoneLoadingZoneResourcesMsg
|
||||
OP_DoneSendingInitialEntitiesMsg
|
||||
OP_DoneLoadingEntityResourcesMsg
|
||||
OP_DoneLoadingUIResourcesMsg
|
||||
OP_PredictionUpdateMsg
|
||||
OP_RemoteCmdMsg
|
||||
OP_SetRemoteCmdsMsg
|
||||
OP_GameWorldTimeMsg
|
||||
OP_MOTDMsg
|
||||
OP_ZoneMOTDMsg
|
||||
|
||||
// Guild recruiting
|
||||
OP_GuildRecruitingMemberInfo
|
||||
OP_GuildRecruiting
|
||||
OP_GuildRecruitingDetails
|
||||
OP_GuildRecruitingImage
|
||||
|
||||
// Avatar management
|
||||
OP_AvatarCreatedMsg
|
||||
OP_AvatarDestroyedMsg
|
||||
OP_RequestCampMsg
|
||||
OP_MapRequest
|
||||
OP_CampStartedMsg
|
||||
OP_CampAbortedMsg
|
||||
|
||||
// Communication
|
||||
OP_WhoQueryRequestMsg
|
||||
OP_WhoQueryReplyMsg
|
||||
OP_MonitorReplyMsg
|
||||
OP_MonitorCharacterListMsg
|
||||
OP_MonitorCharacterListRequestMsg
|
||||
OP_ClientCmdMsg
|
||||
OP_Lottery
|
||||
OP_DispatchClientCmdMsg
|
||||
OP_DispatchESMsg
|
||||
|
||||
// Updates
|
||||
OP_UpdateTargetMsg
|
||||
OP_UpdateOpportunityMsg
|
||||
OP_UpdateTargetLocMsg
|
||||
OP_UpdateSpellBookMsg
|
||||
OP_UpdateRecipeBookMsg
|
||||
OP_RequestRecipeDetailsMsg
|
||||
OP_RecipeDetailsMsg
|
||||
OP_UpdateSkillBookMsg
|
||||
OP_UpdateSkillsMsg
|
||||
|
||||
// Zone management
|
||||
OP_ChangeZoneMsg
|
||||
OP_ClientTeleportRequestMsg
|
||||
OP_TeleportWithinZoneMsg
|
||||
OP_TeleportWithinZoneNoReloadMsg
|
||||
OP_MigrateClientToZoneRequestMsg
|
||||
OP_MigrateClientToZoneReplyMsg
|
||||
OP_ReadyToZoneMsg
|
||||
|
||||
// Group management
|
||||
OP_RemoveClientFromGroupMsg
|
||||
OP_RemoveGroupFromGroupMsg
|
||||
OP_MakeGroupLeaderMsg
|
||||
OP_GroupCreatedMsg
|
||||
OP_GroupDestroyedMsg
|
||||
OP_GroupMemberAddedMsg
|
||||
OP_GroupMemberRemovedMsg
|
||||
OP_GroupRemovedFromGroupMsg
|
||||
OP_GroupLeaderChangedMsg
|
||||
OP_GroupSettingsChangedMsg
|
||||
|
||||
// Status and control
|
||||
OP_SendLatestRequestMsg
|
||||
OP_ClearDataMsg
|
||||
OP_SetSocialMsg
|
||||
OP_ESStatusMsg
|
||||
OP_ESZoneInstanceStatusMsg
|
||||
OP_ZonesStatusRequestMsg
|
||||
OP_ZonesStatusMsg
|
||||
OP_ESWeatherRequestMsg
|
||||
OP_ESWeatherRequestEndMsg
|
||||
|
||||
// Loot and items
|
||||
OP_LootItemsRequestMsg
|
||||
OP_StoppedLootingMsg
|
||||
|
||||
// Character actions
|
||||
OP_SitMsg
|
||||
OP_StandMsg
|
||||
OP_SatMsg
|
||||
OP_StoodMsg
|
||||
|
||||
// UI and interface
|
||||
OP_DefaultGroupOptionsRequestMsg
|
||||
OP_DefaultGroupOptionsMsg
|
||||
OP_GroupOptionsMsg
|
||||
OP_DisplayGroupOptionsScreenMsg
|
||||
OP_DisplayInnVisitScreenMsg
|
||||
OP_DumpSchedulerMsg
|
||||
OP_RequestHelpRepathMsg
|
||||
OP_UpdateMotdMsg
|
||||
OP_RequestTargetLocMsg
|
||||
|
||||
// Effects and actions
|
||||
OP_PerformPlayerKnockbackMsg
|
||||
OP_PerformCameraShakeMsg
|
||||
OP_PopulateSkillMapsMsg
|
||||
OP_CancelledFeignMsg
|
||||
OP_SignalMsg
|
||||
|
||||
// Skills and crafting
|
||||
OP_SkillInfoRequest
|
||||
OP_SkillInfoResponse
|
||||
OP_ShowCreateFromRecipeUIMsg
|
||||
OP_CancelCreateFromRecipeMsg
|
||||
OP_BeginItemCreationMsg
|
||||
OP_StopItemCreationMsg
|
||||
OP_ShowItemCreationProcessUIMsg
|
||||
OP_UpdateItemCreationProcessUIMsg
|
||||
OP_DisplayTSEventReactionMsg
|
||||
OP_ShowRecipeBookMsg
|
||||
|
||||
// Knowledge and help
|
||||
OP_KnowledgebaseRequestMsg
|
||||
OP_KnowledgebaseResponseMsg
|
||||
|
||||
// Customer service
|
||||
OP_CSTicketHeaderRequestMsg
|
||||
OP_CSTicketInfoMsg
|
||||
OP_CSTicketCommentRequestMsg
|
||||
OP_CSTicketCommentResponseMsg
|
||||
OP_CSTicketCreateMsg
|
||||
OP_CSTicketAddCommentMsg
|
||||
OP_CSTicketDeleteMsg
|
||||
OP_CSTicketChangeNotificationMsg
|
||||
|
||||
// World data
|
||||
OP_WorldDataUpdateMsg
|
||||
OP_WorldDataChangeMsg
|
||||
OP_KnownLanguagesMsg
|
||||
|
||||
// Client management
|
||||
OP_ClientTeleportToLocationMsg
|
||||
OP_UpdateClientPredFlagsMsg
|
||||
OP_ChangeServerControlFlagMsg
|
||||
OP_CSToolsRequestMsg
|
||||
OP_CSToolsResponseMsg
|
||||
|
||||
// Transport
|
||||
OP_CreateBoatTransportsMsg
|
||||
OP_PositionBoatTransportMsg
|
||||
OP_MigrateBoatTransportMsg
|
||||
OP_MigrateBoatTransportReplyMsg
|
||||
|
||||
// Debug and examination
|
||||
OP_DisplayDebugNLLPointsMsg
|
||||
OP_ExamineInfoRequestMsg
|
||||
|
||||
// UI management
|
||||
OP_QuickbarInitMsg
|
||||
OP_QuickbarUpdateMsg
|
||||
OP_MacroInitMsg
|
||||
OP_MacroUpdateMsg
|
||||
OP_QuestionnaireMsg
|
||||
|
||||
// Character progression
|
||||
OP_LevelChangedMsg
|
||||
OP_SpellGainedMsg
|
||||
OP_EncounterBrokenMsg
|
||||
OP_OnscreenMsgMsg
|
||||
OP_DisplayWarningMsg
|
||||
|
||||
// Guild management
|
||||
OP_ModifyGuildMsg
|
||||
OP_GuildEventMsg
|
||||
OP_GuildEventAddMsg
|
||||
OP_GuildEventActionMsg
|
||||
OP_GuildEventListMsg
|
||||
OP_RequestGuildEventDetailsMsg
|
||||
OP_GuildEventDetailsMsg
|
||||
OP_RequestGuildBankEventDetailsMsg
|
||||
OP_GuildBankUpdateMsg
|
||||
OP_RewardPackMsg
|
||||
OP_RenameGuildMsg
|
||||
|
||||
// Social features
|
||||
OP_ZoneToFriendRequestMsg
|
||||
OP_ZoneToFriendReplyMsg
|
||||
OP_WaypointRequestMsg
|
||||
OP_WaypointReplyMsg
|
||||
OP_WaypointSelectMsg
|
||||
OP_WaypointUpdateMsg
|
||||
OP_CharNameChangedMsg
|
||||
|
||||
// Travel
|
||||
OP_ShowZoneTeleporterDestinations
|
||||
OP_SelectZoneTeleporterDestination
|
||||
OP_ReloadLocalizedTxtMsg
|
||||
|
||||
// Guild membership
|
||||
OP_RequestGuildMembershipMsg
|
||||
OP_GuildMembershipResponseMsg
|
||||
OP_LeaveGuildNotifyMsg
|
||||
OP_JoinGuildNotifyMsg
|
||||
OP_RequestGuildInfoMsg
|
||||
OP_GuildBankEventListMsg
|
||||
|
||||
// Character info
|
||||
OP_AvatarUpdateMsg
|
||||
OP_BioUpdateMsg
|
||||
OP_InspectPlayerMsg
|
||||
|
||||
// Server management
|
||||
OP_CsCategoryRequestMsg
|
||||
OP_CsCategoryResponseMsg
|
||||
OP_KnowledgeWindowSlotMappingMsg
|
||||
|
||||
// Status updates
|
||||
OP_LFGUpdateMsg
|
||||
OP_AFKUpdateMsg
|
||||
OP_AnonUpdateMsg
|
||||
OP_UpdateActivePublicZonesMsg
|
||||
OP_UnknownNpcMsg
|
||||
OP_PromoFlagsDetailsMsg
|
||||
|
||||
// Trading and consignment
|
||||
OP_ConsignViewCreateMsg
|
||||
OP_ConsignViewGetPageMsg
|
||||
OP_ConsignViewReleaseMsg
|
||||
OP_UpdateDebugRadiiMsg
|
||||
OP_ConsignRemoveItemsMsg
|
||||
OP_ReportMsg
|
||||
OP_UpdateRaidMsg
|
||||
OP_ConsignViewSortMsg
|
||||
|
||||
// Character features
|
||||
OP_TitleUpdateMsg
|
||||
OP_FlightPathsMsg
|
||||
OP_ClientFellMsg
|
||||
OP_ClientInDeathRegionMsg
|
||||
OP_CampClientMsg
|
||||
|
||||
// Customer service tools
|
||||
OP_GetAvatarAccessRequestForCSTools
|
||||
OP_CSToolAccessResponseMsg
|
||||
OP_DeleteGuildMsg
|
||||
|
||||
// Tracking
|
||||
OP_TrackingUpdateMsg
|
||||
OP_BeginTrackingMsg
|
||||
OP_StopTrackingMsg
|
||||
OP_AdvancementRequestMsg
|
||||
|
||||
// Map data
|
||||
OP_MapFogDataInitMsg
|
||||
OP_MapFogDataUpdateMsg
|
||||
OP_CloseGroupInviteWindowMsg
|
||||
OP_UpdateGroupMemberDataMsg
|
||||
OP_WorldPingMsg
|
||||
OP_MoveLogUpdateMsg
|
||||
OP_OfferQuestMsg
|
||||
|
||||
// Mail system
|
||||
OP_MailGetMessageMsg
|
||||
OP_MailSendMessageMsg
|
||||
OP_MailDeleteMessageMsg
|
||||
OP_MailGetHeadersReplyMsg
|
||||
OP_MailGetMessageReplyMsg
|
||||
OP_MailSendMessageReplyMsg
|
||||
OP_MailCommitSendMessageMsg
|
||||
OP_MailSendSystemMessageMsg
|
||||
OP_MailRemoveAttachFromMailMsg
|
||||
OP_WorldShutdownUpdateMsg
|
||||
OP_ClientIdleBeginMsg
|
||||
OP_ClientIdleEndMsg
|
||||
OP_DisplayMailScreenMsg
|
||||
OP_NotifyApprenticeStoppedMentoring
|
||||
OP_CorruptedClientMsg
|
||||
OP_MailEventNotificationMsg
|
||||
OP_RestartZoneMsg
|
||||
|
||||
// Character transfer
|
||||
OP_CharTransferStartRequestMsg
|
||||
OP_CharTransferStartReplyMsg
|
||||
OP_CharTransferRequestMsg
|
||||
OP_CharTransferReplyMsg
|
||||
OP_CharTransferRollbackRequestMsg
|
||||
OP_CharTransferCommitRequestMsg
|
||||
OP_CharTransferRollbackReplyMsg
|
||||
OP_CharTransferCommitReplyMsg
|
||||
OP_GetCharacterSerializedRequestMsg
|
||||
OP_GetCharacterSerializedReplyMsg
|
||||
OP_CreateCharFromCBBRequestMsg
|
||||
OP_CreateCharFromCBBReplyMsg
|
||||
|
||||
// Housing
|
||||
OP_HousingDataChangedMsg
|
||||
OP_HousingRestoreMsg
|
||||
|
||||
// Auction system
|
||||
OP_AuctionItem
|
||||
OP_AuctionItemReply
|
||||
OP_AuctionCoin
|
||||
OP_AuctionCoinReply
|
||||
OP_AuctionCharacter
|
||||
OP_AuctionCharacterReply
|
||||
OP_AuctionCommitMsg
|
||||
OP_AuctionAbortMsg
|
||||
OP_CharTransferValidateRequestMsg
|
||||
OP_CharTransferValidateReplyMsg
|
||||
OP_CharacterLinkdeadMsg
|
||||
OP_RaceRestrictionMsg
|
||||
OP_SetInstanceDisplayNameMsg
|
||||
|
||||
// EQ command system
|
||||
OP_EqHearChatCmd
|
||||
OP_EqDisplayTextCmd
|
||||
OP_EqCreateGhostCmd
|
||||
OP_EqCreateWidgetCmd
|
||||
OP_EqCreateSignWidgetCmd
|
||||
OP_EqDestroyGhostCmd
|
||||
OP_EqUpdateGhostCmd
|
||||
OP_EqSetControlGhostCmd
|
||||
OP_EqSetPOVGhostCmd
|
||||
OP_EqHearCombatCmd
|
||||
OP_EqHearSpellCastCmd
|
||||
OP_EqHearSpellInterruptCmd
|
||||
OP_EqHearSpellFizzleCmd
|
||||
OP_EqHearConsiderCmd
|
||||
OP_EqUpdateSubClassesCmd
|
||||
OP_EqCreateListBoxCmd
|
||||
OP_EqSetDebugPathPointsCmd
|
||||
OP_EqCannedEmoteCmd
|
||||
OP_EqStateCmd
|
||||
OP_EqPlaySoundCmd
|
||||
OP_EqPlaySound3DCmd
|
||||
OP_EqPlayVoiceCmd
|
||||
OP_EqHearDrowningCmd
|
||||
OP_EqHearDeathCmd
|
||||
OP_EqGroupMemberRemovedCmd
|
||||
OP_EqHearChainEffectCmd
|
||||
OP_EqReceiveOfferCmd
|
||||
OP_EqInspectPCResultsCmd
|
||||
OP_EqDrawablePathGraphCmd
|
||||
OP_EqDialogOpenCmd
|
||||
OP_EqDialogCloseCmd
|
||||
OP_EqCollectionUpdateCmd
|
||||
OP_EqCollectionFilterCmd
|
||||
OP_EqCollectionItemCmd
|
||||
OP_EqQuestJournalUpdateCmd
|
||||
OP_EqQuestJournalReplyCmd
|
||||
OP_EqQuestGroupCmd
|
||||
OP_EqUpdateMerchantCmd
|
||||
OP_EqUpdateStoreCmd
|
||||
OP_EqUpdatePlayerTradeCmd
|
||||
OP_EqHelpPathCmd
|
||||
OP_EqHelpPathClearCmd
|
||||
OP_EqUpdateBankCmd
|
||||
OP_EqExamineInfoCmd
|
||||
OP_EqCloseWindowCmd
|
||||
OP_EqUpdateLootCmd
|
||||
OP_EqJunctionListCmd
|
||||
OP_EqShowDeathWindowCmd
|
||||
OP_EqDisplaySpellFailCmd
|
||||
OP_EqSpellCastStartCmd
|
||||
OP_EqSpellCastEndCmd
|
||||
OP_EqResurrectedCmd
|
||||
OP_EqChoiceWinCmd
|
||||
OP_EqSetDefaultVerbCmd
|
||||
OP_EqInstructionWindowCmd
|
||||
OP_EqInstructionWindowCloseCmd
|
||||
OP_EqInstructionWindowGoalCmd
|
||||
OP_EqInstructionWindowTaskCmd
|
||||
OP_EqEnableGameEventCmd
|
||||
OP_EqShowWindowCmd
|
||||
OP_EqEnableWindowCmd
|
||||
OP_EqFlashWindowCmd
|
||||
OP_EqHearPlayFlavorCmd
|
||||
OP_EqUpdateSignWidgetCmd
|
||||
OP_EqDebugPVDCmd
|
||||
OP_EqShowBookCmd
|
||||
OP_EqQuestionnaireCmd
|
||||
OP_EqGetProbsCmd
|
||||
OP_EqHearHealCmd
|
||||
OP_EqChatChannelUpdateCmd
|
||||
OP_EqWhoChannelQueryReplyCmd
|
||||
OP_EqAvailWorldChannelsCmd
|
||||
OP_EqUpdateTargetCmd
|
||||
OP_EqConsignmentItemsCmd
|
||||
OP_EqStartBrokerCmd
|
||||
OP_EqMapExplorationCmd
|
||||
OP_EqStoreLogCmd
|
||||
OP_EqSpellMoveToRangeAndRetryCmd
|
||||
OP_EqUpdatePlayerMailCmd
|
||||
OP_EqFactionUpdateCmd
|
||||
OP_EQHearThreatCmd
|
||||
OP_EqHearSpellNoLandCmd
|
||||
OP_EQHearDispellCmd
|
||||
OP_EqTargetItemCmd
|
||||
|
||||
// Arena and game features
|
||||
OP_ArenaGameTypesMsg
|
||||
OP_UpdateTitleCmd
|
||||
OP_UpdatePositionMsg
|
||||
OP_AttackNotAllowed
|
||||
OP_AttackAllowed
|
||||
OP_CancelSpellCast
|
||||
OP_BadLanguageFilter
|
||||
OP_DressingRoom
|
||||
OP_TraitsList
|
||||
OP_PointOfInterest
|
||||
OP_AdventureList
|
||||
OP_CharacterAchievements
|
||||
OP_RecipeList
|
||||
OP_BagOptions
|
||||
OP_AchievementUpdateMsg
|
||||
OP_PetOptions
|
||||
OP_BrokerAddBag
|
||||
OP_CharacterPet
|
||||
OP_ClearForTakeOffMsg
|
||||
OP_CharacterCurrency
|
||||
OP_TradeskillList
|
||||
OP_RecipeBook
|
||||
OP_CharacterMerc
|
||||
OP_AfterInvSpellUpdate
|
||||
OP_CharacterCreatedDungeons
|
||||
OP_CharacterHousingList
|
||||
OP_HouseItemsList
|
||||
OP_CharacterMounts
|
||||
OP_LoadCalendarEvents
|
||||
OP_LoadWelcomeWindow
|
||||
OP_DungeonMakerItemRequest
|
||||
OP_SysClient
|
||||
OP_LFGGroupSearch
|
||||
OP_MarketPlacePrices
|
||||
OP_MarketFundsUpdate
|
||||
OP_MarketAddFundsRequest
|
||||
OP_ZoneBgInstanceList
|
||||
OP_UIEvent
|
||||
OP_Launchpad
|
||||
OP_Weakness
|
||||
OP_SavageBarInitMsg
|
||||
OP_PetOptionsResponse
|
||||
OP_CurrentPet
|
||||
OP_JournalQuestStoryline
|
||||
OP_DailyObjectives
|
||||
OP_RecipeListUnknown
|
||||
OP_ClearForLandingMsg
|
||||
OP_LikeOption
|
||||
OP_HeritageMsg
|
||||
OP_OpenCharCust
|
||||
OP_PaperdollImage
|
||||
OP_ReadyForTakeOffMsg
|
||||
OP_EarlyLandingRequestMsg
|
||||
OP_SubmitCharCust
|
||||
OP_DietyAbilityWindow
|
||||
)
|
43
internal/opcodes/login.go
Normal file
43
internal/opcodes/login.go
Normal file
@ -0,0 +1,43 @@
|
||||
package opcodes
|
||||
|
||||
// Login server opcodes from login_oplist.h
|
||||
const (
|
||||
OP_LoginRequestMsg = iota + 1
|
||||
OP_LoginByNumRequestMsg
|
||||
OP_WSLoginRequestMsg
|
||||
OP_ESLoginRequestMsg
|
||||
OP_LoginReplyMsg
|
||||
OP_WorldListMsg
|
||||
OP_WorldStatusChangeMsg
|
||||
OP_AllWSDescRequestMsg
|
||||
OP_WSStatusReplyMsg
|
||||
OP_AllCharactersDescRequestMsg
|
||||
OP_AllCharactersDescReplyMsg
|
||||
OP_CreateCharacterRequestMsg
|
||||
OP_ReskinCharacterRequestMsg
|
||||
OP_CreateCharacterReplyMsg
|
||||
OP_WSCreateCharacterRequestMsg
|
||||
OP_WSCreateCharacterReplyMsg
|
||||
OP_DeleteCharacterRequestMsg
|
||||
OP_DeleteCharacterReplyMsg
|
||||
OP_PlayCharacterRequestMsg
|
||||
OP_PlayCharacterReplyMsg
|
||||
OP_ServerPlayCharacterRequestMsg
|
||||
OP_ServerPlayCharacterReplyMsg
|
||||
OP_KeymapLoadMsg
|
||||
OP_KeymapNoneMsg
|
||||
OP_KeymapDataMsg
|
||||
OP_KeymapSaveMsg
|
||||
OP_LSCheckAcctLockMsg
|
||||
OP_WSAcctLockStatusMsg
|
||||
OP_LsRequestClientCrashLogMsg
|
||||
OP_LsClientBaselogReplyMsg
|
||||
OP_LsClientCrashlogReplyMsg
|
||||
OP_LsClientAlertlogReplyMsg
|
||||
OP_LsClientVerifylogReplyMsg
|
||||
OP_WSServerLockMsg
|
||||
OP_WSServerHideMsg
|
||||
OP_LSServerLockMsg
|
||||
OP_UpdateCharacterSheetMsg
|
||||
OP_UpdateInventoryMsg
|
||||
)
|
19
internal/opcodes/protocol.go
Normal file
19
internal/opcodes/protocol.go
Normal file
@ -0,0 +1,19 @@
|
||||
package opcodes
|
||||
|
||||
// Protocol-level opcodes from op_codes.h
|
||||
const (
|
||||
// Core protocol operations
|
||||
OP_SessionRequest = 0x01
|
||||
OP_SessionResponse = 0x02
|
||||
OP_Combined = 0x03
|
||||
OP_SessionDisconnect = 0x05
|
||||
OP_KeepAlive = 0x06
|
||||
OP_ServerKeyRequest = 0x07
|
||||
OP_SessionStatResponse = 0x08
|
||||
OP_Packet = 0x09
|
||||
OP_Fragment = 0x0d
|
||||
OP_OutOfOrderAck = 0x11
|
||||
OP_Ack = 0x15
|
||||
OP_AppCombined = 0x19
|
||||
OP_OutOfSession = 0x1d
|
||||
)
|
111
internal/opcodes/server.go
Normal file
111
internal/opcodes/server.go
Normal file
@ -0,0 +1,111 @@
|
||||
package opcodes
|
||||
|
||||
// Server communication opcodes from servertalk.h
|
||||
const (
|
||||
// Core server operations
|
||||
ServerOP_KeepAlive = 0x0001
|
||||
ServerOP_ChannelMessage = 0x0002
|
||||
ServerOP_SetZone = 0x0003
|
||||
ServerOP_ShutdownAll = 0x0004
|
||||
ServerOP_ZoneShutdown = 0x0005
|
||||
ServerOP_ZoneBootup = 0x0006
|
||||
ServerOP_ZoneStatus = 0x0007
|
||||
ServerOP_SetConnectInfo = 0x0008
|
||||
ServerOP_EmoteMessage = 0x0009
|
||||
ServerOP_ClientList = 0x000A
|
||||
ServerOP_Who = 0x000B
|
||||
ServerOP_ZonePlayer = 0x000C
|
||||
ServerOP_KickPlayer = 0x000D
|
||||
ServerOP_RefreshGuild = 0x000E
|
||||
ServerOP_GuildKickAll = 0x000F
|
||||
ServerOP_GuildInvite = 0x0010
|
||||
ServerOP_GuildRemove = 0x0011
|
||||
ServerOP_GuildPromote = 0x0012
|
||||
ServerOP_GuildDemote = 0x0013
|
||||
ServerOP_GuildLeader = 0x0014
|
||||
ServerOP_GuildGMSet = 0x0015
|
||||
ServerOP_GuildGMSetRank = 0x0016
|
||||
ServerOP_FlagUpdate = 0x0018
|
||||
ServerOP_GMGoto = 0x0019
|
||||
ServerOP_MultiLineMsg = 0x001A
|
||||
ServerOP_Lock = 0x001B
|
||||
ServerOP_Motd = 0x001C
|
||||
ServerOP_Uptime = 0x001D
|
||||
ServerOP_Petition = 0x001E
|
||||
ServerOP_KillPlayer = 0x001F
|
||||
ServerOP_UpdateGM = 0x0020
|
||||
ServerOP_RezzPlayer = 0x0021
|
||||
ServerOP_ZoneReboot = 0x0022
|
||||
ServerOP_ZoneToZoneRequest = 0x0023
|
||||
ServerOP_AcceptWorldEntrance = 0x0024
|
||||
ServerOP_ZAAuth = 0x0025
|
||||
ServerOP_ZAAuthFailed = 0x0026
|
||||
ServerOP_ZoneIncClient = 0x0027
|
||||
ServerOP_ClientListKA = 0x0028
|
||||
ServerOP_ChangeWID = 0x0029
|
||||
ServerOP_IPLookup = 0x002A
|
||||
ServerOP_LockZone = 0x002B
|
||||
ServerOP_ItemStatus = 0x002C
|
||||
ServerOP_OOCMute = 0x002D
|
||||
ServerOP_Revoke = 0x002E
|
||||
ServerOP_GuildJoin = 0x002F
|
||||
ServerOP_GroupIDReq = 0x0030
|
||||
ServerOP_GroupIDReply = 0x0031
|
||||
ServerOP_GroupLeave = 0x0032
|
||||
ServerOP_RezzPlayerAccept = 0x0033
|
||||
ServerOP_SpawnCondition = 0x0034
|
||||
ServerOP_SpawnEvent = 0x0035
|
||||
|
||||
// Login server operations
|
||||
ServerOP_LSInfo = 0x1000
|
||||
ServerOP_LSStatus = 0x1001
|
||||
ServerOP_LSClientAuth = 0x1002
|
||||
ServerOP_LSFatalError = 0x1003
|
||||
ServerOP_SystemwideMessage = 0x1005
|
||||
ServerOP_ListWorlds = 0x1006
|
||||
ServerOP_PeerConnect = 0x1007
|
||||
|
||||
// Packet management
|
||||
ServerOP_EncapPacket = 0x2007
|
||||
ServerOP_WorldListUpdate = 0x2008
|
||||
ServerOP_WorldListRemove = 0x2009
|
||||
ServerOP_TriggerWorldListRefresh = 0x200A
|
||||
ServerOP_SetWorldTime = 0x200B
|
||||
ServerOP_GetWorldTime = 0x200C
|
||||
ServerOP_SyncWorldTime = 0x200E
|
||||
ServerOP_CharTimeStamp = 0x200F
|
||||
ServerOP_NameFilterCheck = 0x2011
|
||||
ServerOP_BasicCharUpdate = 0x2012
|
||||
ServerOP_CharacterCreate = 0x2013
|
||||
ServerOP_NameCharUpdate = 0x2014
|
||||
ServerOP_GetLatestTables = 0x2015
|
||||
ServerOP_GetTableQuery = 0x2016
|
||||
ServerOP_GetTableData = 0x2017
|
||||
ServerOP_RaceUpdate = 0x2018
|
||||
ServerOP_ZoneUpdate = 0x2019
|
||||
ServerOP_BugReport = 0x201A
|
||||
ServerOP_ResetDatabase = 0x201B
|
||||
ServerOP_ZoneUpdates = 0x201C
|
||||
ServerOP_LoginEquipment = 0x201D
|
||||
ServerOP_CharacterPicture = 0x201E
|
||||
|
||||
// Zone management
|
||||
ServerOP_LSZoneInfo = 0x3001
|
||||
ServerOP_LSZoneStart = 0x3002
|
||||
ServerOP_LSZoneBoot = 0x3003
|
||||
ServerOP_LSZoneShutdown = 0x3004
|
||||
ServerOP_LSZoneSleep = 0x3005
|
||||
ServerOP_LSPlayerLeftWorld = 0x3006
|
||||
ServerOP_LSPlayerJoinWorld = 0x3007
|
||||
ServerOP_LSPlayerZoneChange = 0x3008
|
||||
|
||||
// Update operations
|
||||
UpdateServerOP_Verified = 0x5090
|
||||
UpdateServerOP_DisplayMsg = 0x5091
|
||||
UpdateServerOP_Completed = 0x5092
|
||||
|
||||
// Special operations
|
||||
ServerOP_UsertoWorldReq = 0xAB00
|
||||
ServerOP_UsertoWorldResp = 0xAB01
|
||||
ServerOP_WhoAll = 0x0210
|
||||
)
|
67
internal/opcodes/utils.go
Normal file
67
internal/opcodes/utils.go
Normal file
@ -0,0 +1,67 @@
|
||||
package opcodes
|
||||
|
||||
// Constants for opcode management
|
||||
const (
|
||||
MAX_EQ_OPCODE = 0xFFFF
|
||||
APP_OPCODE_SIZE_1 = 1
|
||||
APP_OPCODE_SIZE_2 = 2
|
||||
)
|
||||
|
||||
// Opcode type definitions
|
||||
type (
|
||||
ProtocolOpcode uint8
|
||||
ServerOpcode uint16
|
||||
AppOpcode uint16
|
||||
EmuOpcode uint16
|
||||
)
|
||||
|
||||
// Quick lookup maps for efficient opcode translation
|
||||
var (
|
||||
ProtocolOpcodeNames = map[ProtocolOpcode]string{
|
||||
OP_SessionRequest: "OP_SessionRequest",
|
||||
OP_SessionResponse: "OP_SessionResponse",
|
||||
OP_Combined: "OP_Combined",
|
||||
OP_SessionDisconnect: "OP_SessionDisconnect",
|
||||
OP_KeepAlive: "OP_KeepAlive",
|
||||
OP_ServerKeyRequest: "OP_ServerKeyRequest",
|
||||
OP_SessionStatResponse: "OP_SessionStatResponse",
|
||||
OP_Packet: "OP_Packet",
|
||||
OP_Fragment: "OP_Fragment",
|
||||
OP_OutOfOrderAck: "OP_OutOfOrderAck",
|
||||
OP_Ack: "OP_Ack",
|
||||
OP_AppCombined: "OP_AppCombined",
|
||||
OP_OutOfSession: "OP_OutOfSession",
|
||||
}
|
||||
|
||||
ServerOpcodeNames = map[ServerOpcode]string{
|
||||
ServerOP_KeepAlive: "ServerOP_KeepAlive",
|
||||
ServerOP_ChannelMessage: "ServerOP_ChannelMessage",
|
||||
ServerOP_SetZone: "ServerOP_SetZone",
|
||||
ServerOP_ShutdownAll: "ServerOP_ShutdownAll",
|
||||
// Add more as needed for performance-critical lookups
|
||||
}
|
||||
)
|
||||
|
||||
// Helper functions for efficient opcode operations
|
||||
func IsProtocolOpcode(op uint8) bool {
|
||||
_, exists := ProtocolOpcodeNames[ProtocolOpcode(op)]
|
||||
return exists
|
||||
}
|
||||
|
||||
func IsServerOpcode(op uint16) bool {
|
||||
return op >= 0x0001 && op <= 0xFFFF
|
||||
}
|
||||
|
||||
func GetProtocolOpcodeName(op ProtocolOpcode) string {
|
||||
if name, exists := ProtocolOpcodeNames[op]; exists {
|
||||
return name
|
||||
}
|
||||
return "OP_Unknown"
|
||||
}
|
||||
|
||||
func GetServerOpcodeName(op ServerOpcode) string {
|
||||
if name, exists := ServerOpcodeNames[op]; exists {
|
||||
return name
|
||||
}
|
||||
return "ServerOP_Unknown"
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EQ2 Login", "Login.vcxproj", "{BE2C1914-FCCC-4F65-A7DD-105142B36104}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
EQ2Login|Win32 = EQ2Login|Win32
|
||||
MiniLogin Release|Win32 = MiniLogin Release|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Debug|Win32.ActiveCfg = EQ2Login|Win32
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Debug|Win32.Build.0 = EQ2Login|Win32
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.EQ2Login|Win32.ActiveCfg = EQ2Login|Win32
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.EQ2Login|Win32.Build.0 = EQ2Login|Win32
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.MiniLogin Release|Win32.ActiveCfg = EQ2Login|Win32
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.MiniLogin Release|Win32.Build.0 = EQ2Login|Win32
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Release|Win32.ActiveCfg = EQ2Login|Win32
|
||||
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Release|Win32.Build.0 = EQ2Login|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Binary file not shown.
@ -1,447 +0,0 @@
|
||||
# Microsoft Developer Studio Project File - Name="Login" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=Login - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "Login.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "Login.mak" CFG="Login - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "Login - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Login - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Login - Win32 MiniLogin" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "Login - Win32 PublicLogin" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "Login - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "../Build"
|
||||
# PROP Intermediate_Dir "../Build/Login"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MT /w /W0 /GX /Zi /O2 /Ob2 /D "LOGINCRYPTO" /D "INVERSEXY" /D _WIN32_WINNT=0x0400 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo /o"../Build/Login/Login.bsc"
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /map:"../Build/Login.map" /debug /machine:I386
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Login___Win32_Debug"
|
||||
# PROP BASE Intermediate_Dir "Login___Win32_Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "../build/login/Debug"
|
||||
# PROP Intermediate_Dir "../build/login/debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /Gm /GX /ZI /Od /D "LOGINCRYPTO" /D "INVERSEXY" /D _WIN32_WINNT=0x0400 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCMT" /out:"../build/login/Debug/LoginDebug.exe" /pdbtype:sept
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Login___Win32_MiniLogin"
|
||||
# PROP BASE Intermediate_Dir "Login___Win32_MiniLogin"
|
||||
# PROP BASE Ignore_Export_Lib 0
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "../Build"
|
||||
# PROP Intermediate_Dir "../Build/MiniLogin"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "BUILD_FOR_WINDOWS" /FR /YX /FD /c
|
||||
# ADD CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D _WIN32_WINNT=0x0400 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "MINILOGIN" /FR /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo /o"../Build/Login/Login.bsc"
|
||||
# ADD BSC32 /nologo /o"../Build/MiniLogin/Login.bsc"
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386
|
||||
# SUBTRACT BASE LINK32 /pdb:none
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386 /out:"../Build/MiniLogin.exe"
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Login___Win32_PublicLogin"
|
||||
# PROP BASE Intermediate_Dir "Login___Win32_PublicLogin"
|
||||
# PROP BASE Ignore_Export_Lib 0
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "../Build"
|
||||
# PROP Intermediate_Dir "../Build/PublicLogin"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "BUILD_FOR_WINDOWS" /FR /YX /FD /c
|
||||
# ADD CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D _WIN32_WINNT=0x0400 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "PUBLICLOGIN" /FR /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo /o"../Build/Login/Login.bsc"
|
||||
# ADD BSC32 /nologo /o"../Build/Login/Login.bsc"
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386
|
||||
# SUBTRACT BASE LINK32 /pdb:none
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386 /out:"../Build/PublicLogin.exe"
|
||||
# SUBTRACT LINK32 /pdb:none
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "Login - Win32 Release"
|
||||
# Name "Login - Win32 Debug"
|
||||
# Name "Login - Win32 MiniLogin"
|
||||
# Name "Login - Win32 PublicLogin"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\client.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EQCrypto.cpp
|
||||
|
||||
!IF "$(CFG)" == "Login - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
|
||||
|
||||
# PROP Exclude_From_Build 1
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
|
||||
|
||||
# PROP Exclude_From_Build 1
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\logindatabase.cpp
|
||||
|
||||
!IF "$(CFG)" == "Login - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
|
||||
|
||||
# PROP Exclude_From_Build 1
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LWorld.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\net.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\client.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\EQCrypto.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\login_opcodes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\login_structs.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LWorld.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\net.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Common Source Files"
|
||||
|
||||
# PROP Default_Filter ".cpp"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\crc32.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\database.cpp
|
||||
|
||||
!IF "$(CFG)" == "Login - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
|
||||
|
||||
# PROP Exclude_From_Build 1
|
||||
|
||||
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\dbcore.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\DBMemLeak.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\debug.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\EQNetwork.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\md5.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\MiscFunctions.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\Mutex.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\packet_dump.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\packet_functions.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\TCPConnection.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\timer.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Common Header Files"
|
||||
|
||||
# PROP Default_Filter ".h"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\classes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\crc32.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\database.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\DBMemLeak.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\debug.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\deity.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\eq_opcodes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\eq_packet_structs.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\EQCheckTable.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\EQFragment.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\EQNetwork.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\EQOpcodes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\EQPacket.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\EQPacketManager.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\errmsg.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\Guilds.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\linked_list.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\md5.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\MiscFunctions.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\moremath.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\Mutex.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\packet_dump.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\packet_dump_file.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\packet_functions.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\queue.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\queues.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\races.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\Seperator.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\servertalk.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\TCPConnection.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\timer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\types.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\version.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Text Files"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Protocol.txt
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Tables.txt
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ThanksTo.txt
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
@ -1,29 +0,0 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "Login"=.\Login.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
@ -1,542 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="EQ2 Login"
|
||||
ProjectGUID="{BE2C1914-FCCC-4F65-A7DD-105142B36104}"
|
||||
RootNamespace="EQ2 Login"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="EQ2Login|Win32"
|
||||
OutputDirectory=".\../Build"
|
||||
IntermediateDirectory=".\../Build/EQ2Login"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TypeLibraryName=".\../Build/Login.tlb"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/D EQDEBUG=5"
|
||||
Optimization="0"
|
||||
InlineFunctionExpansion="0"
|
||||
PreprocessorDefinitions="_WIN32_WINNT=0x0400,WIN32,NDEBUG,_CONSOLE,LOGIN, EQ2, EQN_DEBUG,_CRT_SECURE_NO_DEPRECATE"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
PrecompiledHeaderFile=".\../Build/EQ2Login/Login.pch"
|
||||
AssemblerListingLocation=".\../Build/EQ2Login/"
|
||||
ObjectFile=".\../Build/EQ2Login/"
|
||||
ProgramDataBaseFileName=".\../Build/EQ2Login/"
|
||||
BrowseInformation="1"
|
||||
SuppressStartupBanner="true"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="2"
|
||||
ShowIncludes="false"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalOptions="/MACHINE:I386"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib"
|
||||
OutputFile="../Build/EQ2Login.exe"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreAllDefaultLibraries="false"
|
||||
IgnoreDefaultLibraryNames="libcmtd;msvcrt"
|
||||
GenerateDebugInformation="true"
|
||||
ProgramDatabaseFile=".\../Build/Eq2Login.pdb"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="MiniLogin Release|Win32"
|
||||
OutputDirectory="$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
UseOfMFC="0"
|
||||
ATLMinimizesCRunTimeLibraryUsage="false"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TypeLibraryName=".\../Build/Login.tlb"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/D EQDEBUG=5"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="0"
|
||||
FavorSizeOrSpeed="1"
|
||||
PreprocessorDefinitions="_WIN32_WINNT=0x0400,WIN32,NDEBUG,_CONSOLE,LOGIN, EQ2, EQN_DEBUG,_CRT_SECURE_NO_DEPRECATE,MINILOGIN"
|
||||
StringPooling="true"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
PrecompiledHeaderFile=".\../Build/EQ2Login/Login.pch"
|
||||
AssemblerListingLocation=".\../Build/EQ2Login/"
|
||||
ObjectFile=".\../Build/EQ2Login/"
|
||||
ProgramDataBaseFileName=".\../Build/EQ2Login/"
|
||||
BrowseInformation="1"
|
||||
SuppressStartupBanner="true"
|
||||
DebugInformationFormat="0"
|
||||
CompileAs="2"
|
||||
ShowIncludes="false"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
PreprocessorDefinitions="NDEBUG"
|
||||
Culture="1033"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalOptions="/MACHINE:I386"
|
||||
AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib"
|
||||
OutputFile="../Build/EQ2MiniLogin.exe"
|
||||
LinkIncremental="2"
|
||||
SuppressStartupBanner="true"
|
||||
IgnoreAllDefaultLibraries="false"
|
||||
IgnoreDefaultLibraryNames="libcmtd;msvcrt"
|
||||
GenerateDebugInformation="false"
|
||||
ProgramDatabaseFile=".\../Build/Eq2Login.pdb"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\client.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\LoginAccount.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\LoginDatabase.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\LWorld.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\net.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PacketHeaders.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\client.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\login_opcodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\login_structs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\LoginAccount.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\LoginDatabase.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\LWorld.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\net.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\PacketHeaders.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Common Source Files"
|
||||
Filter=".cpp"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\Character.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\Condition.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\ConfigReader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\CRC16.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\Crypto.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\database.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\dbcore.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\debug.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\emu_opcodes.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQEMuError.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQPacket.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQStream.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQStreamFactory.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\misc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\MiscFunctions.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\Mutex.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\opcodemgr.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\packet_dump.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\packet_functions.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\PacketStruct.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\RC4.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\TCPConnection.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\timer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\xmlParser.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Common Header Files"
|
||||
Filter=".h"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\Character.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\Condition.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\ConfigReader.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\CRC16.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\Crypto.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\database.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\DataBuffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\dbcore.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\debug.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\emu_opcodes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQ2_Common_Structs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQEMuError.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQPacket.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQStream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\EQStreamFactory.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\GlobalHeaders.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\linked_list.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\login_oplist.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\misc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\MiscFunctions.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\Mutex.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\op_codes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\opcodemgr.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\packet_dump.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\packet_functions.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\PacketStruct.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\queue.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\RC4.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\seperator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\servertalk.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\TCPConnection.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\timer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\types.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\version.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\xmlParser.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="World Files"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\World\MutexHelper.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\World\MutexList.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\World\MutexMap.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -1,154 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="EQ2Login|x64">
|
||||
<Configuration>EQ2Login</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>EQ2Login</ProjectName>
|
||||
<ProjectGuid>{BE2C1914-FCCC-4F65-A7DD-105142B36104}</ProjectGuid>
|
||||
<RootNamespace>EQ2 Login</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='EQ2Login|x64'">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='EQ2Login|x64'">
|
||||
<IncludePath>$(SolutionDir)..\source\depends\mariadb-10.1.19\include;$(SolutionDir)..\source\depends\zlib\include;$(SolutionDir)..\source\depends\recastnavigation\Detour\Include;$(SolutionDir)..\source\depends\boost_1_72_0\;$(SolutionDir)..\source\depends\glm\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
|
||||
<LibraryPath>$(SolutionDir)..\source\depends\recastnavigation\RecastDemo\Build\vs2019\lib\Debug;$(SolutionDir)..\source\depends\mariadb-10.1.19\lib\64-debug;$(SolutionDir)..\source\depends\zlib\lib;$(SolutionDir)..\source\depends\boost_1_72_0\lib64-msvc-14.2;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64</LibraryPath>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)loginserver\</OutDir>
|
||||
<IntDir>.\$(ProjectName)__Debug64\</IntDir>
|
||||
<TargetName>$(ProjectName)__Debug64</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='EQ2Login|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0400;WIN32;NDEBUG;_CONSOLE;LOGIN; EQ2; EQN_DEBUG;_CRT_SECURE_NO_DEPRECATE;_HAS_STD_BYTE=0
|
||||
;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<FunctionLevelLinking>false</FunctionLevelLinking>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeaderFile />
|
||||
<PrecompiledHeaderOutputFile />
|
||||
<ProgramDataBaseFileName>$(IntDir)</ProgramDataBaseFileName>
|
||||
<BrowseInformation />
|
||||
<BrowseInformationFile />
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>odbc32.lib;odbccp32.lib;ws2_32.lib;zlib.lib;mysqlclient.lib;DebugUtils.lib;Detour.lib;DetourCrowd.lib;DetourTileCache.lib;Recast.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>LIBCMT;LIBC;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention />
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\common\DatabaseNew.cpp" />
|
||||
<ClCompile Include="..\common\DatabaseResult.cpp" />
|
||||
<ClCompile Include="..\common\Log.cpp" />
|
||||
<ClCompile Include="client.cpp" />
|
||||
<ClCompile Include="LoginAccount.cpp" />
|
||||
<ClCompile Include="LoginDatabase.cpp" />
|
||||
<ClCompile Include="LWorld.cpp" />
|
||||
<ClCompile Include="net.cpp" />
|
||||
<ClCompile Include="PacketHeaders.cpp" />
|
||||
<ClCompile Include="Character.cpp" />
|
||||
<ClCompile Include="..\common\Condition.cpp" />
|
||||
<ClCompile Include="..\common\ConfigReader.cpp" />
|
||||
<ClCompile Include="..\common\CRC16.cpp" />
|
||||
<ClCompile Include="..\common\Crypto.cpp" />
|
||||
<ClCompile Include="..\common\database.cpp" />
|
||||
<ClCompile Include="..\common\dbcore.cpp" />
|
||||
<ClCompile Include="..\common\debug.cpp" />
|
||||
<ClCompile Include="..\common\emu_opcodes.cpp" />
|
||||
<ClCompile Include="..\common\EQEMuError.cpp" />
|
||||
<ClCompile Include="..\common\EQPacket.cpp" />
|
||||
<ClCompile Include="..\common\EQStream.cpp" />
|
||||
<ClCompile Include="..\common\EQStreamFactory.cpp" />
|
||||
<ClCompile Include="..\common\misc.cpp" />
|
||||
<ClCompile Include="..\common\MiscFunctions.cpp" />
|
||||
<ClCompile Include="..\common\Mutex.cpp" />
|
||||
<ClCompile Include="..\common\opcodemgr.cpp" />
|
||||
<ClCompile Include="..\common\packet_dump.cpp" />
|
||||
<ClCompile Include="..\common\packet_functions.cpp" />
|
||||
<ClCompile Include="..\common\PacketStruct.cpp" />
|
||||
<ClCompile Include="..\common\RC4.cpp" />
|
||||
<ClCompile Include="..\common\TCPConnection.cpp" />
|
||||
<ClCompile Include="..\common\timer.cpp" />
|
||||
<ClCompile Include="..\common\xmlParser.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\common\DatabaseNew.h" />
|
||||
<ClInclude Include="..\common\DatabaseResult.h" />
|
||||
<ClInclude Include="..\common\Log.h" />
|
||||
<ClInclude Include="..\common\LogTypes.h" />
|
||||
<ClInclude Include="client.h" />
|
||||
<ClInclude Include="login_opcodes.h" />
|
||||
<ClInclude Include="login_structs.h" />
|
||||
<ClInclude Include="LoginAccount.h" />
|
||||
<ClInclude Include="LoginDatabase.h" />
|
||||
<ClInclude Include="LWorld.h" />
|
||||
<ClInclude Include="net.h" />
|
||||
<ClInclude Include="PacketHeaders.h" />
|
||||
<ClInclude Include="Character.h" />
|
||||
<ClInclude Include="..\common\Condition.h" />
|
||||
<ClInclude Include="..\common\ConfigReader.h" />
|
||||
<ClInclude Include="..\common\CRC16.h" />
|
||||
<ClInclude Include="..\common\Crypto.h" />
|
||||
<ClInclude Include="..\common\database.h" />
|
||||
<ClInclude Include="..\common\DataBuffer.h" />
|
||||
<ClInclude Include="..\common\dbcore.h" />
|
||||
<ClInclude Include="..\common\debug.h" />
|
||||
<ClInclude Include="..\common\emu_opcodes.h" />
|
||||
<ClInclude Include="..\common\EQ2_Common_Structs.h" />
|
||||
<ClInclude Include="..\common\EQEMuError.h" />
|
||||
<ClInclude Include="..\common\EQPacket.h" />
|
||||
<ClInclude Include="..\common\EQStream.h" />
|
||||
<ClInclude Include="..\common\EQStreamFactory.h" />
|
||||
<ClInclude Include="..\common\GlobalHeaders.h" />
|
||||
<ClInclude Include="..\common\linked_list.h" />
|
||||
<ClInclude Include="..\common\login_oplist.h" />
|
||||
<ClInclude Include="..\common\misc.h" />
|
||||
<ClInclude Include="..\common\MiscFunctions.h" />
|
||||
<ClInclude Include="..\common\Mutex.h" />
|
||||
<ClInclude Include="..\common\op_codes.h" />
|
||||
<ClInclude Include="..\common\opcodemgr.h" />
|
||||
<ClInclude Include="..\common\packet_dump.h" />
|
||||
<ClInclude Include="..\common\packet_functions.h" />
|
||||
<ClInclude Include="..\common\PacketStruct.h" />
|
||||
<ClInclude Include="..\common\queue.h" />
|
||||
<ClInclude Include="..\common\RC4.h" />
|
||||
<ClInclude Include="..\common\seperator.h" />
|
||||
<ClInclude Include="..\common\servertalk.h" />
|
||||
<ClInclude Include="..\common\TCPConnection.h" />
|
||||
<ClInclude Include="..\common\timer.h" />
|
||||
<ClInclude Include="..\common\types.h" />
|
||||
<ClInclude Include="..\common\version.h" />
|
||||
<ClInclude Include="..\common\xmlParser.h" />
|
||||
<ClInclude Include="..\World\MutexHelper.h" />
|
||||
<ClInclude Include="..\World\MutexList.h" />
|
||||
<ClInclude Include="..\World\MutexMap.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -1,277 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{bfe8d6b0-594f-4b55-9f95-101bbcf4069c}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{d65b2760-468c-4206-a19a-48323a50ba5a}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Common Source Files">
|
||||
<UniqueIdentifier>{27b769a5-0972-4e9e-b78c-09ad3341579c}</UniqueIdentifier>
|
||||
<Extensions>.cpp</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Common Header Files">
|
||||
<UniqueIdentifier>{11757e5a-691c-49c9-a627-df027ad58326}</UniqueIdentifier>
|
||||
<Extensions>.h</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="World Files">
|
||||
<UniqueIdentifier>{99e7f9f9-abcd-4abf-8200-a4b5a467788c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="client.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LoginAccount.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LoginDatabase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LWorld.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="net.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PacketHeaders.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Character.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\Condition.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\ConfigReader.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\CRC16.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\Crypto.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\database.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\dbcore.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\debug.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\emu_opcodes.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\EQEMuError.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\EQPacket.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\EQStream.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\EQStreamFactory.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\misc.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\MiscFunctions.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\Mutex.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\opcodemgr.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\packet_dump.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\packet_functions.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\PacketStruct.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\RC4.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\TCPConnection.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\timer.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\xmlParser.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\Log.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\DatabaseNew.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\DatabaseResult.cpp">
|
||||
<Filter>Common Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="client.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="login_opcodes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="login_structs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LoginAccount.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LoginDatabase.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LWorld.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="net.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PacketHeaders.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Character.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\Condition.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\ConfigReader.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\CRC16.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\Crypto.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\database.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\DataBuffer.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\dbcore.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\debug.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\emu_opcodes.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\EQ2_Common_Structs.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\EQEMuError.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\EQPacket.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\EQStream.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\EQStreamFactory.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\GlobalHeaders.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\linked_list.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\login_oplist.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\misc.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\MiscFunctions.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\Mutex.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\op_codes.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\opcodemgr.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\packet_dump.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\packet_functions.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\PacketStruct.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\queue.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\RC4.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\seperator.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\servertalk.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\TCPConnection.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\timer.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\types.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\version.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\xmlParser.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\World\MutexHelper.h">
|
||||
<Filter>World Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\World\MutexList.h">
|
||||
<Filter>World Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\World\MutexMap.h">
|
||||
<Filter>World Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\Log.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\LogTypes.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\DatabaseNew.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\DatabaseResult.h">
|
||||
<Filter>Common Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
</Project>
|
Binary file not shown.
@ -1,32 +0,0 @@
|
||||
APP=login
|
||||
SF= ../common/Log.o ../common/timer.o ../common/packet_dump.o ../common/unix.o \
|
||||
../common/Mutex.o ../common/MiscFunctions.o LoginDatabase.o LoginAccount.o \
|
||||
../common/TCPConnection.o ../common/emu_opcodes.o \
|
||||
client.o net.o PacketHeaders.o LWorld.o ../common/md5.o ../common/dbcore.o \
|
||||
Web/LoginWeb.o \
|
||||
../common/EQEMuError.o ../common/misc.o ../common/Crypto.o ../common/RC4.o \
|
||||
.obj/debug.o .obj/database.o .obj/EQStream.o ../common/xmlParser.o \
|
||||
.obj/EQStreamFactory.o .obj/EQPacket.o ../common/CRC16.o ../common/packet_functions.o \
|
||||
../common/Condition.o ../common/opcodemgr.o ../common/PacketStruct.o ../common/ConfigReader.o \
|
||||
../common/DatabaseNew.o ../common/DatabaseResult.o ../common/Web/WebServer.o ../common/JsonParser.o
|
||||
|
||||
CC=g++
|
||||
LINKER=gcc
|
||||
DFLAGS=-DEQ2 -DLOGIN
|
||||
WFLAGS=-Wall -Wuninitialized -Wwrite-strings -Wcast-qual -Wcomment -Wcast-align -Wno-deprecated
|
||||
COPTS=$(WFLAGS) -ggdb -march=native -pthread -pipe -DFX -D_GNU_SOURCE -DINVERSEXY $(DFLAGS) -I/usr/include/mariadb -I/usr/local/include/boost -I/usr/include/lua5.4 -std=c++17
|
||||
LINKOPTS=-rdynamic -L. -lstdc++ -lm -lz -L/usr/lib/x86_64-linux-gnu -lmariadb -lboost_system -lboost_thread -lboost_filesystem -lssl -lcrypto -lpthread -ldl
|
||||
all: $(APP)
|
||||
|
||||
$(APP): $(SF)
|
||||
$(LINKER) $(COPTS) $(OBJS) $^ $(LINKOPTS) -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(SF) $(APP)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) -c $(COPTS) $< -o $@
|
||||
|
||||
.obj/%.o: ../common/%.cpp ../common/%.h
|
||||
mkdir -p .obj
|
||||
$(CC) $(COPTS) -c $< -o $@
|
@ -1,328 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned long IntArray[]={
|
||||
0x00000000,
|
||||
0x77073096,
|
||||
0xEE0E612C,
|
||||
0x990951BA,
|
||||
0x076DC419,
|
||||
0x706AF48F,
|
||||
0xE963A535,
|
||||
0x9E6495A3,
|
||||
0x0EDB8832,
|
||||
0x79DCB8A4,
|
||||
0xE0D5E91E,
|
||||
0x97D2D988,
|
||||
0x09B64C2B,
|
||||
0x7EB17CBD,
|
||||
0xE7B82D07,
|
||||
0x90BF1D91,
|
||||
0x1DB71064,
|
||||
0x6AB020F2,
|
||||
0xF3B97148,
|
||||
0x84BE41DE,
|
||||
0x1ADAD47D,
|
||||
0x6DDDE4EB,
|
||||
0xF4D4B551,
|
||||
0x83D385C7,
|
||||
0x136C9856,
|
||||
0x646BA8C0,
|
||||
0xFD62F97A,
|
||||
0x8A65C9EC,
|
||||
0x14015C4F,
|
||||
0x63066CD9,
|
||||
0xFA0F3D63,
|
||||
0x8D080DF5,
|
||||
0x3B6E20C8,
|
||||
0x4C69105E,
|
||||
0xD56041E4,
|
||||
0xA2677172,
|
||||
0x3C03E4D1,
|
||||
0x4B04D447,
|
||||
0xD20D85FD,
|
||||
0xA50AB56B,
|
||||
0x35B5A8FA,
|
||||
0x42B2986C,
|
||||
0xDBBBC9D6,
|
||||
0xACBCF940,
|
||||
0x32D86CE3,
|
||||
0x45DF5C75,
|
||||
0xDCD60DCF,
|
||||
0xABD13D59,
|
||||
0x26D930AC,
|
||||
0x51DE003A,
|
||||
0xC8D75180,
|
||||
0xBFD06116,
|
||||
0x21B4F4B5,
|
||||
0x56B3C423,
|
||||
0xCFBA9599,
|
||||
0xB8BDA50F,
|
||||
0x2802B89E,
|
||||
0x5F058808,
|
||||
0xC60CD9B2,
|
||||
0xB10BE924,
|
||||
0x2F6F7C87,
|
||||
0x58684C11,
|
||||
0xC1611DAB,
|
||||
0xB6662D3D,
|
||||
0x76DC4190,
|
||||
0x01DB7106,
|
||||
0x98D220BC,
|
||||
0xEFD5102A,
|
||||
0x71B18589,
|
||||
0x06B6B51F,
|
||||
0x9FBFE4A5,
|
||||
0xE8B8D433,
|
||||
0x7807C9A2,
|
||||
0x0F00F934,
|
||||
0x9609A88E,
|
||||
0xE10E9818,
|
||||
0x7F6A0DBB,
|
||||
0x086D3D2D,
|
||||
0x91646C97,
|
||||
0xE6635C01,
|
||||
0x6B6B51F4,
|
||||
0x1C6C6162,
|
||||
0x856530D8,
|
||||
0xF262004E,
|
||||
0x6C0695ED,
|
||||
0x1B01A57B,
|
||||
0x8208F4C1,
|
||||
0xF50FC457,
|
||||
0x65B0D9C6,
|
||||
0x12B7E950,
|
||||
0x8BBEB8EA,
|
||||
0xFCB9887C,
|
||||
0x62DD1DDF,
|
||||
0x15DA2D49,
|
||||
0x8CD37CF3,
|
||||
0xFBD44C65,
|
||||
0x4DB26158,
|
||||
0x3AB551CE,
|
||||
0xA3BC0074,
|
||||
0xD4BB30E2,
|
||||
0x4ADFA541,
|
||||
0x3DD895D7,
|
||||
0xA4D1C46D,
|
||||
0xD3D6F4FB,
|
||||
0x4369E96A,
|
||||
0x346ED9FC,
|
||||
0xAD678846,
|
||||
0xDA60B8D0,
|
||||
0x44042D73,
|
||||
0x33031DE5,
|
||||
0xAA0A4C5F,
|
||||
0xDD0D7CC9,
|
||||
0x5005713C,
|
||||
0x270241AA,
|
||||
0xBE0B1010,
|
||||
0xC90C2086,
|
||||
0x5768B525,
|
||||
0x206F85B3,
|
||||
0xB966D409,
|
||||
0xCE61E49F,
|
||||
0x5EDEF90E,
|
||||
0x29D9C998,
|
||||
0xB0D09822,
|
||||
0xC7D7A8B4,
|
||||
0x59B33D17,
|
||||
0x2EB40D81,
|
||||
0xB7BD5C3B,
|
||||
0xC0BA6CAD,
|
||||
0xEDB88320,
|
||||
0x9ABFB3B6,
|
||||
0x03B6E20C,
|
||||
0x74B1D29A,
|
||||
0xEAD54739,
|
||||
0x9DD277AF,
|
||||
0x04DB2615,
|
||||
0x73DC1683,
|
||||
0xE3630B12,
|
||||
0x94643B84,
|
||||
0x0D6D6A3E,
|
||||
0x7A6A5AA8,
|
||||
0xE40ECF0B,
|
||||
0x9309FF9D,
|
||||
0x0A00AE27,
|
||||
0x7D079EB1,
|
||||
0xF00F9344,
|
||||
0x8708A3D2,
|
||||
0x1E01F268,
|
||||
0x6906C2FE,
|
||||
0xF762575D,
|
||||
0x806567CB,
|
||||
0x196C3671,
|
||||
0x6E6B06E7,
|
||||
0xFED41B76,
|
||||
0x89D32BE0,
|
||||
0x10DA7A5A,
|
||||
0x67DD4ACC,
|
||||
0xF9B9DF6F,
|
||||
0x8EBEEFF9,
|
||||
0x17B7BE43,
|
||||
0x60B08ED5,
|
||||
0xD6D6A3E8,
|
||||
0xA1D1937E,
|
||||
0x38D8C2C4,
|
||||
0x4FDFF252,
|
||||
0xD1BB67F1,
|
||||
0xA6BC5767,
|
||||
0x3FB506DD,
|
||||
0x48B2364B,
|
||||
0xD80D2BDA,
|
||||
0xAF0A1B4C,
|
||||
0x36034AF6,
|
||||
0x41047A60,
|
||||
0xDF60EFC3,
|
||||
0xA867DF55,
|
||||
0x316E8EEF,
|
||||
0x4669BE79,
|
||||
0xCB61B38C,
|
||||
0xBC66831A,
|
||||
0x256FD2A0,
|
||||
0x5268E236,
|
||||
0xCC0C7795,
|
||||
0xBB0B4703,
|
||||
0x220216B9,
|
||||
0x5505262F,
|
||||
0xC5BA3BBE,
|
||||
0xB2BD0B28,
|
||||
0x2BB45A92,
|
||||
0x5CB36A04,
|
||||
0xC2D7FFA7,
|
||||
0xB5D0CF31,
|
||||
0x2CD99E8B,
|
||||
0x5BDEAE1D,
|
||||
0x9B64C2B0,
|
||||
0xEC63F226,
|
||||
0x756AA39C,
|
||||
0x026D930A,
|
||||
0x9C0906A9,
|
||||
0xEB0E363F,
|
||||
0x72076785,
|
||||
0x05005713,
|
||||
0x95BF4A82,
|
||||
0xE2B87A14,
|
||||
0x7BB12BAE,
|
||||
0x0CB61B38,
|
||||
0x92D28E9B,
|
||||
0xE5D5BE0D,
|
||||
0x7CDCEFB7,
|
||||
0x0BDBDF21,
|
||||
0x86D3D2D4,
|
||||
0xF1D4E242,
|
||||
0x68DDB3F8,
|
||||
0x1FDA836E,
|
||||
0x81BE16CD,
|
||||
0xF6B9265B,
|
||||
0x6FB077E1,
|
||||
0x18B74777,
|
||||
0x88085AE6,
|
||||
0xFF0F6A70,
|
||||
0x66063BCA,
|
||||
0x11010B5C,
|
||||
0x8F659EFF,
|
||||
0xF862AE69,
|
||||
0x616BFFD3,
|
||||
0x166CCF45,
|
||||
0xA00AE278,
|
||||
0xD70DD2EE,
|
||||
0x4E048354,
|
||||
0x3903B3C2,
|
||||
0xA7672661,
|
||||
0xD06016F7,
|
||||
0x4969474D,
|
||||
0x3E6E77DB,
|
||||
0xAED16A4A,
|
||||
0xD9D65ADC,
|
||||
0x40DF0B66,
|
||||
0x37D83BF0,
|
||||
0xA9BCAE53,
|
||||
0xDEBB9EC5,
|
||||
0x47B2CF7F,
|
||||
0x30B5FFE9,
|
||||
0xBDBDF21C,
|
||||
0xCABAC28A,
|
||||
0x53B39330,
|
||||
0x24B4A3A6,
|
||||
0xBAD03605,
|
||||
0xCDD70693,
|
||||
0x54DE5729,
|
||||
0x23D967BF,
|
||||
0xB3667A2E,
|
||||
0xC4614AB8,
|
||||
0x5D681B02,
|
||||
0x2A6F2B94,
|
||||
0xB40BBE37,
|
||||
0xC30C8EA1,
|
||||
0x5A05DF1B,
|
||||
0x2D02EF8D,
|
||||
};
|
||||
|
||||
unsigned long CRC16(const unsigned char *buf, int size, int key)
|
||||
{
|
||||
unsigned long ecx = key; //mov ecx, [esp+arg_8]
|
||||
unsigned long eax = ecx; //mov eax, ecx
|
||||
unsigned long edi;
|
||||
|
||||
eax = ~ eax; //not eax
|
||||
eax&=0xFF; //and eax, 0FFh
|
||||
eax=IntArray[eax]; //mov eax, dword_0_10115D38[eax*4] IntArray
|
||||
eax ^= 0x00FFFFFF; //xor eax, 0FFFFFFh
|
||||
int edx = ecx; //mov edx, ecx
|
||||
edx = edx >> 8; //sar edx, 8
|
||||
edx = edx ^ eax; //xor edx, eax
|
||||
eax = eax >> 8; //sar eax, 8
|
||||
edx &= 0xFF; //and edx, 0FFh
|
||||
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
|
||||
eax ^= IntArray[edx]; //xor eax, dword_0_10115D38[edx*4]
|
||||
edx = ecx; //mov edx, ecx
|
||||
edx = edx >> 0x10; //sar edx, 10h
|
||||
edx ^= eax; //xor edx, eax
|
||||
eax = eax >> 8; //sar eax, 8
|
||||
edx &= 0xFF; //and edx, 0FFh
|
||||
int esi = IntArray[edx]; //mov esi, dword_0_10115D38[edx*4]
|
||||
edx = size; //mov edx, [esp+4+arg_4]
|
||||
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
|
||||
eax ^= esi; //xor eax, esi
|
||||
ecx = ecx >> 0x18; //sar ecx, 18h
|
||||
ecx ^= eax; //xor ecx, eax
|
||||
ecx &= 0xFF; //and ecx, 0FFh
|
||||
esi = IntArray[ecx]; //mov esi, dword_0_10115D38[ecx*4]
|
||||
ecx = (int)*buf; //mov ecx, [esp+4+arg_0]
|
||||
eax = eax >> 8; //sar eax, 8
|
||||
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
|
||||
eax ^= esi; //xor eax, esi
|
||||
for(int x = 0; x < size; x++)
|
||||
{ //eax is the crc, ecx is the current part of the buffer
|
||||
int edx = 0; //xor edx, edx
|
||||
edx = buf[x] & 0x00FF; //mov dl, [ecx]
|
||||
|
||||
edx ^= eax; //xor edx, eax
|
||||
eax = eax >> 8; //sar eax, 8
|
||||
edx &= 0xFF; //and edx, 0FFh
|
||||
edi = IntArray[edx]; //mov edi, dword_0_10115D38[edx*4]
|
||||
eax &= 0x00FFFFFF; //and eax, 0FFFFFFh
|
||||
eax ^= edi; //xor eax, edi
|
||||
}
|
||||
return ~eax;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _CRC16_H
|
||||
#define _CRC16_H
|
||||
|
||||
unsigned long CRC16(const unsigned char *buf, int size, int key);
|
||||
|
||||
#endif
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define BASEDIR "./"
|
||||
|
||||
#ifndef DB_INI_FILE
|
||||
#ifdef LOGIN
|
||||
#define DB_INI_FILE BASEDIR "login_db.ini"
|
||||
#else
|
||||
#define DB_INI_FILE BASEDIR "world_db.ini"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAIN_CONFIG_FILE
|
||||
#define MAIN_CONFIG_FILE BASEDIR "server_config.json"
|
||||
#endif
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "debug.h"
|
||||
#include "Condition.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
/*
|
||||
|
||||
Windows does not support condition variables by default.
|
||||
So we use a simple hack of sleeping in wait() and doing
|
||||
nothing anywhere else.
|
||||
|
||||
some possible places to look for ways to do this:
|
||||
http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
|
||||
|
||||
http://sources.redhat.com/pthreads-win32/
|
||||
http://sources.redhat.com/cgi-bin/cvsweb.cgi/pthreads/pthread_cond_signal.c?rev=1.7&content-type=text/x-cvsweb-markup&cvsroot=pthreads-win32
|
||||
|
||||
*/
|
||||
|
||||
#define CONDITION_HACK_GRANULARITY 4
|
||||
|
||||
|
||||
Condition::Condition()
|
||||
{
|
||||
}
|
||||
|
||||
void Condition::Signal()
|
||||
{
|
||||
}
|
||||
|
||||
void Condition::SignalAll()
|
||||
{
|
||||
}
|
||||
|
||||
void Condition::Wait()
|
||||
{
|
||||
Sleep(CONDITION_HACK_GRANULARITY);
|
||||
}
|
||||
|
||||
Condition::~Condition()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#else //!WIN32
|
||||
|
||||
Condition::Condition()
|
||||
{
|
||||
pthread_cond_init(&cond,NULL);
|
||||
pthread_mutex_init(&mutex,NULL);
|
||||
}
|
||||
|
||||
void Condition::Signal()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void Condition::SignalAll()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_broadcast(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void Condition::Wait()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_wait(&cond,&mutex);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
I commented this specifically because I think it might be very
|
||||
difficult to write a windows counterpart to it, so I would like
|
||||
to discourage its use until we can confirm that it can be reasonably
|
||||
implemented on windows.
|
||||
|
||||
bool Condition::TimedWait(unsigned long usec)
|
||||
{
|
||||
struct timeval now;
|
||||
struct timespec timeout;
|
||||
int retcode=0;
|
||||
pthread_mutex_lock(&mutex);
|
||||
gettimeofday(&now,NULL);
|
||||
now.tv_usec+=usec;
|
||||
timeout.tv_sec = now.tv_sec + (now.tv_usec/1000000);
|
||||
timeout.tv_nsec = (now.tv_usec%1000000) *1000;
|
||||
//cout << "now=" << now.tv_sec << "."<<now.tv_usec << endl;
|
||||
//cout << "timeout=" << timeout.tv_sec << "."<<timeout.tv_nsec << endl;
|
||||
retcode=pthread_cond_timedwait(&cond,&mutex,&timeout);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
return retcode!=ETIMEDOUT;
|
||||
}
|
||||
*/
|
||||
|
||||
Condition::~Condition()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_broadcast(&cond);
|
||||
pthread_cond_destroy(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __CONDITION_H
|
||||
#define __CONDITION_H
|
||||
|
||||
#ifndef WIN32
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
//Sombody, someday needs to figure out how to implement a condition
|
||||
//system on windows...
|
||||
|
||||
|
||||
class Condition {
|
||||
private:
|
||||
#ifndef WIN32
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
public:
|
||||
Condition();
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
void Wait();
|
||||
// bool TimedWait(unsigned long usec);
|
||||
~Condition();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Crypto.h"
|
||||
#include <iostream>
|
||||
#include "../common/packet_dump.h"
|
||||
|
||||
using namespace std;
|
||||
void test();
|
||||
int64 Crypto::RSADecrypt(uchar* text, int16 size){
|
||||
int64 ret = 0;
|
||||
uchar* buffer = new uchar[8];
|
||||
for(int i=7;i>=0;i--)
|
||||
buffer[7-i] = text[i];
|
||||
memcpy(&ret, buffer, 8);
|
||||
safe_delete_array(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Crypto::RC4Decrypt(uchar* text, int32 size){
|
||||
MCrypto.lock();
|
||||
client->Cypher(text, size);
|
||||
MCrypto.unlock();
|
||||
}
|
||||
|
||||
void Crypto::RC4Encrypt(uchar* text, int32 size){
|
||||
MCrypto.lock();
|
||||
server->Cypher(text, size);
|
||||
MCrypto.unlock();
|
||||
}
|
||||
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _CRYPTO_H
|
||||
#define _CRYPTO_H
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include "RC4.h"
|
||||
#include "../common/types.h"
|
||||
|
||||
using namespace std;
|
||||
class Crypto {
|
||||
public:
|
||||
~Crypto(){ safe_delete(client); safe_delete(server); }
|
||||
Crypto() { rc4_key = 0; encrypted = false; client = 0; server = 0; };
|
||||
|
||||
static int64 RSADecrypt(uchar* text, int16 size);
|
||||
void RC4Encrypt(uchar* text, int32 size);
|
||||
void RC4Decrypt(uchar* text, int32 size);
|
||||
int64 getRC4Key() { return rc4_key; }
|
||||
void setRC4Key(int64 key) {
|
||||
rc4_key = key;
|
||||
if(key > 0){
|
||||
encrypted = true;
|
||||
client = new RC4(~key);
|
||||
server = new RC4(key);
|
||||
uchar temp[20];
|
||||
client->Cypher(temp, 20);
|
||||
server->Cypher(temp, 20);
|
||||
}
|
||||
else{
|
||||
encrypted = false;
|
||||
safe_delete(client);
|
||||
safe_delete(server);
|
||||
}
|
||||
}
|
||||
bool isEncrypted(){ return encrypted; }
|
||||
void setEncrypted(bool in_val){ encrypted = in_val; }
|
||||
|
||||
|
||||
private:
|
||||
RC4* server;
|
||||
RC4* client;
|
||||
bool encrypted;
|
||||
int64 rc4_key;
|
||||
mutex MCrypto;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __EQ2_DATABUFFER_
|
||||
#define __EQ2_DATABUFFER_
|
||||
#include <string>
|
||||
#include "../common/types.h"
|
||||
#include "../common/EQPacket.h"
|
||||
#include "../common/EQ2_Common_Structs.h"
|
||||
|
||||
#ifdef WORLD
|
||||
#include "../WorldServer/SpawnLists.h"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
class DataBuffer{
|
||||
public:
|
||||
bool changed;
|
||||
uchar* getData(){ return (uchar*)buffer.c_str(); }
|
||||
int32 getDataSize(){ return buffer.length(); }
|
||||
string* getDataString(){ return &buffer; }
|
||||
void CreateEQ2Color(EQ2_Color& color){
|
||||
CreateEQ2Color(&color);
|
||||
}
|
||||
uchar* GetLoadBuffer(){
|
||||
return load_buffer;
|
||||
}
|
||||
int32 GetLoadPos(){
|
||||
return load_pos;
|
||||
}
|
||||
int32 GetLoadLen(){
|
||||
return load_len;
|
||||
}
|
||||
void SetLoadPos(int32 new_pos){
|
||||
load_pos = new_pos;
|
||||
}
|
||||
void CreateEQ2Color(EQ2_Color* color){
|
||||
int8 rgb[3];
|
||||
float* tmp = 0;
|
||||
for(int i=0;i<3;i++){
|
||||
tmp = (float*)(load_buffer + load_pos);
|
||||
rgb[i] = (int8)((*tmp)*255);
|
||||
load_pos += sizeof(float);
|
||||
}
|
||||
color->red = rgb[0];
|
||||
color->green = rgb[1];
|
||||
color->blue = rgb[2];
|
||||
}
|
||||
|
||||
template<class Type> void MakeEQ2_Int8(Type& output){
|
||||
MakeEQ2_Int8(&output);
|
||||
}
|
||||
template<class Type> void MakeEQ2_Int8(Type* output){
|
||||
float* tmp = (float*)(load_buffer + load_pos);
|
||||
if(*tmp < 0)
|
||||
*tmp *= -1;
|
||||
sint8 result = (sint8)((*tmp)*100);
|
||||
memcpy(output, &result, sizeof(sint8));
|
||||
load_pos += sizeof(float);
|
||||
}
|
||||
void InitializeGetData(){
|
||||
get_buffer = (uchar*)buffer.c_str();
|
||||
get_len = buffer.length();
|
||||
get_pos = 0;
|
||||
}
|
||||
void InitializeLoadData(uchar* input, int32 size){
|
||||
buffer = string((char*)input, size);
|
||||
load_buffer = (uchar*)buffer.c_str();
|
||||
load_len = size;
|
||||
load_pos = 0;
|
||||
}
|
||||
template<class String> void LoadDataString(String& output){
|
||||
LoadDataString(&output);
|
||||
}
|
||||
template<class String> void LoadDataString(String* output){
|
||||
if((sizeof(output->size) + load_pos) <= load_len){
|
||||
memcpy(&output->size, load_buffer + load_pos, sizeof(output->size));
|
||||
load_pos += sizeof(output->size);
|
||||
}
|
||||
if((output->size + load_pos) <= load_len){
|
||||
output->data = string((char*)(load_buffer + load_pos), output->size);
|
||||
load_pos += output->size;
|
||||
}
|
||||
}
|
||||
template<class Type> void LoadData(Type& output){
|
||||
LoadData(&output);
|
||||
}
|
||||
template<class Type> void LoadData(Type* output, int32 array_size){
|
||||
if(array_size<=1){
|
||||
LoadData(output);
|
||||
}
|
||||
else{
|
||||
for(int32 i=0;i<array_size;i++)
|
||||
LoadData(&output[i]);
|
||||
}
|
||||
}
|
||||
template<class Type> void LoadData(Type* output){
|
||||
if((sizeof(Type) + load_pos) <= load_len){
|
||||
memcpy(output, load_buffer + load_pos, sizeof(Type));
|
||||
load_pos += sizeof(Type);
|
||||
}
|
||||
}
|
||||
template<class Type> void LoadData(Type& output, int32 array_size){
|
||||
LoadData(&output, array_size);
|
||||
}
|
||||
void LoadSkip(int8 bytes){
|
||||
load_pos += bytes;
|
||||
}
|
||||
template<class Type> void LoadSkip(Type& skip){
|
||||
LoadSkip(&skip);
|
||||
}
|
||||
template<class Type> void LoadSkip(Type* skip){
|
||||
load_pos += sizeof(Type);
|
||||
}
|
||||
template<class Type> void GetData(Type* output){
|
||||
if((sizeof(Type) + get_pos) <= get_len){
|
||||
*output = (Type*)get_buffer;
|
||||
get_pos += sizeof(output);
|
||||
}
|
||||
}
|
||||
void AddZeros(int16 num){
|
||||
int8* data = new int8[num];
|
||||
memset(data, 0, num);
|
||||
AddData(*data);
|
||||
safe_delete_array(data);
|
||||
}
|
||||
template<class Type> void StructAddData(Type input, int16 size, string* datastring){
|
||||
if(datastring)
|
||||
datastring->append((char*)&input, size);
|
||||
else
|
||||
buffer.append((char*)&input, size);
|
||||
}
|
||||
template<class Type> void StructAddData(Type input, int32 array_size, int16 size, string* datastring){
|
||||
if(array_size>0){
|
||||
for(int32 i=0;i<array_size;i++)
|
||||
StructAddData(input[i], size, datastring);
|
||||
}
|
||||
else
|
||||
StructAddData(input, size, datastring);
|
||||
}
|
||||
template<class Type> void AddData(Type input, string* datastring = 0){
|
||||
if(!datastring)
|
||||
datastring = &buffer;
|
||||
datastring->append((char*)&input, sizeof(input));
|
||||
}
|
||||
template<class Type> void AddData(Type input, int32 array_size, string* datastring = 0){
|
||||
if(array_size>0){
|
||||
for(int32 i=0;i<array_size;i++)
|
||||
AddData(input[i], datastring);
|
||||
}
|
||||
else
|
||||
AddData(input, datastring);
|
||||
}
|
||||
template<class String> void AddDataString(String* input, string* datastring = 0){
|
||||
AddDataString(*input, datastring);
|
||||
}
|
||||
template<class String> void AddDataString(String input, string* datastring = 0){
|
||||
input.size = input.data.length();
|
||||
if(!datastring)
|
||||
datastring = &buffer;
|
||||
datastring->append((char*)&input.size, sizeof(input.size));
|
||||
datastring->append(input.data);
|
||||
}
|
||||
void AddCharArray(char* array, string* datastring = 0){
|
||||
if(!datastring)
|
||||
datastring = &buffer;
|
||||
datastring->append(array);
|
||||
}
|
||||
void AddCharArray(char* array, int16 size, string* datastring = 0){
|
||||
if(!datastring)
|
||||
datastring = &buffer;
|
||||
datastring->append(array, size);
|
||||
}
|
||||
void AddData(string data, string* datastring = 0){
|
||||
if(!datastring)
|
||||
datastring = &buffer;
|
||||
datastring->append(data);
|
||||
}
|
||||
void Clear() { buffer.clear(); }
|
||||
private:
|
||||
string buffer;
|
||||
uchar* get_buffer;
|
||||
uchar* load_buffer;
|
||||
int32 get_len;
|
||||
int32 get_pos;
|
||||
int32 load_len;
|
||||
int32 load_pos;
|
||||
};
|
||||
#endif
|
||||
|
@ -1,422 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "Log.h"
|
||||
#include "DatabaseNew.h"
|
||||
#include <errmsg.h>
|
||||
|
||||
//increase this if large queries are being run frequently to make less calls to malloc()
|
||||
#define QUERY_INITIAL_SIZE 512
|
||||
|
||||
#if defined WORLD
|
||||
#define DB_INI "world_db.ini"
|
||||
#elif defined LOGIN
|
||||
#define DB_INI "login_db.ini"
|
||||
#elif defined PARSER
|
||||
#define DB_INI "parser_db.ini"
|
||||
#endif
|
||||
|
||||
DatabaseNew::DatabaseNew() {
|
||||
mysql_init(&mysql);
|
||||
int timeout = 10;
|
||||
mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
|
||||
MMysql.SetName("DatabaseNew::mysql");
|
||||
}
|
||||
|
||||
DatabaseNew::~DatabaseNew() {
|
||||
mysql_close(&mysql);
|
||||
#if MYSQL_VERSION_ID >= 50003
|
||||
mysql_library_end();
|
||||
#else
|
||||
mysql_server_end();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DatabaseNew::Connect() {
|
||||
char line[256], *key, *val;
|
||||
char host[256], user[64], password[64], database[64], port[64];
|
||||
bool found_section = false;
|
||||
FILE *f;
|
||||
|
||||
if ((f = fopen(DB_INI, "r")) == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Unable to read %s\n", DB_INI);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(host, 0, sizeof(host));
|
||||
memset(user, 0, sizeof(user));
|
||||
memset(password, 0, sizeof(password));
|
||||
memset(database, 0, sizeof(database));
|
||||
memset(port, 0, sizeof(port));
|
||||
|
||||
while (fgets(line, sizeof(line), f) != NULL) {
|
||||
if (line[0] == '#' || line[0] == '\n' || line[0] == '\r')
|
||||
continue;
|
||||
|
||||
if (!found_section) {
|
||||
if (strncasecmp(line, "[Database]", 10) == 0)
|
||||
found_section = true;
|
||||
}
|
||||
else {
|
||||
if ((key = strtok(line, "=")) != NULL) {
|
||||
if ((val = strtok(NULL, "\r\n")) != NULL) {
|
||||
if (strncasecmp(line, "host", 4) == 0)
|
||||
strncpy(host, val, sizeof(host) - 1);
|
||||
else if (strncasecmp(line, "user", 4) == 0)
|
||||
strncpy(user, val, sizeof(user) - 1);
|
||||
else if (strncasecmp(line, "password", 8) == 0)
|
||||
strncpy(password, val, sizeof(password) - 1);
|
||||
else if (strncasecmp(line, "database", 8) == 0)
|
||||
strncpy(database, val, sizeof(database) - 1);
|
||||
else if (strncasecmp(line, "port", 4) == 0)
|
||||
strncpy(port, val, sizeof(port) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (host[0] == '\0') {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Unknown 'host' in '%s'\n", DB_INI);
|
||||
return false;
|
||||
}
|
||||
if (user[0] == '\0') {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Unknown 'user' in '%s'\n", DB_INI);
|
||||
return false;
|
||||
}
|
||||
if (password[0] == '\0') {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Unknown 'password' in '%s'\n", DB_INI);
|
||||
return false;
|
||||
}
|
||||
if (database[0] == '\0') {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Unknown 'database' in '%s'\n", DB_INI);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int portnum = atoul(port);
|
||||
return Connect(host, user, password, database, portnum);
|
||||
}
|
||||
|
||||
bool DatabaseNew::Connect(const char *host, const char *user, const char *password, const char *database, unsigned int port) {
|
||||
if (mysql_real_connect(&mysql, host, user, password, database, port, NULL, 0) == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Unable to connect to MySQL server at %s:%u: %s\n", host, port, mysql_error(&mysql));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabaseNew::Query(const char *query, ...) {
|
||||
char *buf;
|
||||
size_t size = QUERY_INITIAL_SIZE;
|
||||
int num_chars;
|
||||
va_list args;
|
||||
bool ret = true;
|
||||
|
||||
MMysql.writelock(__FUNCTION__, __LINE__);
|
||||
while (true) {
|
||||
if ((buf = (char *)malloc(size)) == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Out of memory trying to allocate database query of %u bytes\n", size);
|
||||
MMysql.releasewritelock(__FUNCTION__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
va_start(args, query);
|
||||
num_chars = vsnprintf(buf, size, query, args);
|
||||
va_end(args);
|
||||
|
||||
if (num_chars > -1 && (size_t)num_chars < size)
|
||||
break;
|
||||
|
||||
if (num_chars > -1)
|
||||
size = num_chars + 1;
|
||||
else
|
||||
size *= 2;
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if (mysql_real_query(&mysql, buf, num_chars) != 0) {
|
||||
|
||||
if (mysql_errno(&mysql) == CR_SERVER_LOST || mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Lost connection, attempting to recover and retry query...");
|
||||
Connect();
|
||||
|
||||
// retry attempt of previous query (1 try and we give up)
|
||||
if (mysql_real_query(&mysql, buf, num_chars) != 0) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else if (!IsIgnoredErrno(mysql_errno(&mysql))) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Error %i running MySQL query: %s\n%s\n", mysql_errno(&mysql), mysql_error(&mysql), buf);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
|
||||
MMysql.releasewritelock(__FUNCTION__, __LINE__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DatabaseNew::Select(DatabaseResult *result, const char *query, ...) {
|
||||
char *buf;
|
||||
size_t size = QUERY_INITIAL_SIZE;
|
||||
int num_chars;
|
||||
va_list args;
|
||||
MYSQL_RES *res;
|
||||
bool ret = true;
|
||||
|
||||
MMysql.writelock(__FUNCTION__, __LINE__);
|
||||
while (true) {
|
||||
if ((buf = (char *)malloc(size)) == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Out of memory trying to allocate database query of %u bytes\n", size);
|
||||
MMysql.releasewritelock(__FUNCTION__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
va_start(args, query);
|
||||
num_chars = vsnprintf(buf, size, query, args);
|
||||
va_end(args);
|
||||
|
||||
if (num_chars > -1 && (size_t)num_chars < size)
|
||||
break;
|
||||
|
||||
if (num_chars > -1)
|
||||
size = num_chars + 1;
|
||||
else
|
||||
size *= 2;
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if (mysql_real_query(&mysql, buf, (unsigned long)num_chars) != 0) {
|
||||
|
||||
if (mysql_errno(&mysql) == CR_SERVER_LOST || mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Lost connection, attempting to recover and retry query...");
|
||||
|
||||
mysql_close(&mysql);
|
||||
Connect();
|
||||
|
||||
// retry attempt of previous query (1 try and we give up)
|
||||
if (mysql_real_query(&mysql, buf, (unsigned long)num_chars) != 0) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else if (!IsIgnoredErrno(mysql_errno(&mysql))) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Error %i running MySQL query: %s\n%s\n", mysql_errno(&mysql), mysql_error(&mysql), buf);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && !IsIgnoredErrno(mysql_errno(&mysql))) {
|
||||
res = mysql_store_result(&mysql);
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
// Grab number of rows and number of fields from the query
|
||||
uint8 num_rows = mysql_affected_rows(&mysql);
|
||||
uint8 num_fields = mysql_field_count(&mysql);
|
||||
|
||||
ret = result->StoreResult(res, num_fields, num_rows);
|
||||
}
|
||||
else {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Error storing MySql query result (%d): %s\n%s", mysql_errno(&mysql), mysql_error(&mysql), buf);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
MMysql.releasewritelock(__FUNCTION__, __LINE__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32 DatabaseNew::LastInsertID()
|
||||
{
|
||||
return (int32)mysql_insert_id(&mysql);
|
||||
}
|
||||
|
||||
long DatabaseNew::AffectedRows()
|
||||
{
|
||||
return mysql_affected_rows(&mysql);
|
||||
}
|
||||
|
||||
char * DatabaseNew::Escape(const char *str, size_t len) {
|
||||
char *buf = (char *)malloc(len * 2 + 1);
|
||||
|
||||
if (buf == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Out of memory trying to allocate %u bytes in %s:%u\n", len * 2 + 1, __FUNCTION__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mysql_real_escape_string(&mysql, buf, str, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
char * DatabaseNew::Escape(const char *str) {
|
||||
return Escape(str, strlen(str));
|
||||
}
|
||||
|
||||
string DatabaseNew::EscapeStr(const char *str, size_t len) {
|
||||
char *buf = (char *)malloc(len * 2 + 1);
|
||||
string ret;
|
||||
|
||||
if (buf == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Out of memory trying to allocate %u bytes in %s:%u\n", len * 2 + 1, __FUNCTION__, __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mysql_real_escape_string(&mysql, buf, str, len);
|
||||
ret.append(buf);
|
||||
free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
string DatabaseNew::EscapeStr(const char *str) {
|
||||
return EscapeStr(str, strlen(str));
|
||||
}
|
||||
|
||||
string DatabaseNew::EscapeStr(string str) {
|
||||
return EscapeStr(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
bool DatabaseNew::QueriesFromFile(const char * file) {
|
||||
bool success = true;
|
||||
long size;
|
||||
char *buf;
|
||||
int ret;
|
||||
MYSQL_RES *res;
|
||||
FILE *f;
|
||||
|
||||
f = fopen(file, "rb");
|
||||
if (f == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Unable to open '%s' for reading: %s", file, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
buf = (char *)malloc(size + 1);
|
||||
if (buf == NULL) {
|
||||
fclose(f);
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Out of memory trying to allocate %u bytes in %s:%u\n", size + 1, __FUNCTION__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fread(buf, sizeof(*buf), size, f) != (size_t)size) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Failed to read from '%s': %s", file, strerror(errno));
|
||||
fclose(f);
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
buf[size] = '\0';
|
||||
fclose(f);
|
||||
|
||||
mysql_set_server_option(&mysql, MYSQL_OPTION_MULTI_STATEMENTS_ON);
|
||||
ret = mysql_real_query(&mysql, buf, size);
|
||||
free(buf);
|
||||
|
||||
if (ret != 0) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Error running MySQL queries from file '%s' (%d): %s", file, mysql_errno(&mysql), mysql_error(&mysql));
|
||||
success = false;
|
||||
}
|
||||
else {
|
||||
//all results must be processed
|
||||
do {
|
||||
res = mysql_store_result(&mysql);
|
||||
if (res != NULL)
|
||||
mysql_free_result(res);
|
||||
ret = mysql_next_result(&mysql);
|
||||
|
||||
if (ret > 0) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "Error running MySQL queries from file '%s' (%d): %s", file, mysql_errno(&mysql), mysql_error(&mysql));
|
||||
success = false;
|
||||
}
|
||||
|
||||
} while (ret == 0);
|
||||
}
|
||||
mysql_set_server_option(&mysql, MYSQL_OPTION_MULTI_STATEMENTS_OFF);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void DatabaseNew::SetIgnoredErrno(unsigned int db_errno) {
|
||||
vector<unsigned int>::iterator itr;
|
||||
|
||||
for (itr = ignored_errnos.begin(); itr != ignored_errnos.end(); itr++) {
|
||||
if ((*itr) == db_errno)
|
||||
return;
|
||||
}
|
||||
|
||||
ignored_errnos.push_back(db_errno);
|
||||
}
|
||||
|
||||
void DatabaseNew::RemoveIgnoredErrno(unsigned int db_errno) {
|
||||
vector<unsigned int>::iterator itr;
|
||||
|
||||
for (itr = ignored_errnos.begin(); itr != ignored_errnos.end(); itr++) {
|
||||
if ((*itr) == db_errno) {
|
||||
ignored_errnos.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseNew::IsIgnoredErrno(unsigned int db_errno) {
|
||||
vector<unsigned int>::iterator itr;
|
||||
|
||||
for (itr = ignored_errnos.begin(); itr != ignored_errnos.end(); itr++) {
|
||||
if ((*itr) == db_errno)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sends the MySQL server a keepalive
|
||||
void DatabaseNew::PingNewDB() {
|
||||
MMysql.writelock(__FUNCTION__, __LINE__);
|
||||
mysql_ping(&mysql);
|
||||
|
||||
int32* errnum = new int32;
|
||||
*errnum = mysql_errno(&mysql);
|
||||
|
||||
switch (*errnum)
|
||||
{
|
||||
case CR_COMMANDS_OUT_OF_SYNC:
|
||||
case CR_SERVER_GONE_ERROR:
|
||||
case CR_UNKNOWN_ERROR:
|
||||
{
|
||||
LogWrite(DATABASE__ERROR, 0, "Database", "[Database] We lost connection to the database., errno: %i", errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
safe_delete(errnum);
|
||||
MMysql.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#ifndef COMMON_DATABASE_H_
|
||||
#define COMMON_DATABASE_H_
|
||||
|
||||
#include <string>
|
||||
#include "DatabaseResult.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class DatabaseNew {
|
||||
public:
|
||||
DatabaseNew();
|
||||
virtual ~DatabaseNew();
|
||||
|
||||
unsigned int GetError() {return mysql_errno(&mysql);}
|
||||
const char * GetErrorMsg() {return mysql_error(&mysql);}
|
||||
|
||||
bool Connect();
|
||||
bool Connect(const char *host, const char *user, const char *password, const char *database, unsigned int port = 3306);
|
||||
|
||||
bool Query(const char *query, ...);
|
||||
bool Select(DatabaseResult *result, const char *query, ...);
|
||||
|
||||
int32 LastInsertID();
|
||||
long AffectedRows();
|
||||
|
||||
//these two must free() the return char* after it's used in a query
|
||||
char * Escape(const char *str, size_t len);
|
||||
char * Escape(const char *str);
|
||||
|
||||
//does not need free()
|
||||
string EscapeStr(const char *str, size_t len);
|
||||
string EscapeStr(const char *str);
|
||||
string EscapeStr(string str);
|
||||
|
||||
bool QueriesFromFile(const char *file);
|
||||
void SetIgnoredErrno(unsigned int db_errno);
|
||||
void RemoveIgnoredErrno(unsigned int db_errno);
|
||||
bool IsIgnoredErrno(unsigned int db_errno);
|
||||
|
||||
void PingNewDB();
|
||||
private:
|
||||
MYSQL mysql;
|
||||
Mutex MMysql;
|
||||
|
||||
vector<unsigned int> ignored_errnos;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,234 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "Log.h"
|
||||
#include "DatabaseResult.h"
|
||||
|
||||
//enforced by MySQL...couldn't find a #define in their headers though
|
||||
#define FIELD_NAME_MAX 64
|
||||
|
||||
//return this instead of NULL for certain functions to prevent crashes from coding errors
|
||||
static const char *empty_str = "";
|
||||
|
||||
DatabaseResult::DatabaseResult(): field_map(), result(0), num_fields(0), row(0) {
|
||||
}
|
||||
|
||||
DatabaseResult::~DatabaseResult() {
|
||||
unsigned int i;
|
||||
|
||||
if (result != NULL)
|
||||
mysql_free_result(result);
|
||||
|
||||
if (field_map.size()) {
|
||||
field_map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseResult::StoreResult(MYSQL_RES* res, uint8 field_count, uint8 row_count) {
|
||||
|
||||
//clear any previously stored result
|
||||
if (result != NULL)
|
||||
mysql_free_result(result);
|
||||
|
||||
//clear any field names from a previous result
|
||||
if (field_map.size()) {
|
||||
field_map.clear();
|
||||
}
|
||||
|
||||
result = res;
|
||||
num_rows = row_count;
|
||||
num_fields = field_count;
|
||||
|
||||
// No rows or fields then we don't care
|
||||
if (!num_rows || !num_fields) {
|
||||
mysql_free_result(res);
|
||||
result = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const MYSQL_FIELD* fields = mysql_fetch_fields(result);
|
||||
|
||||
for (uint8 i = 0; i < num_fields; ++i) {
|
||||
field_map.emplace(std::make_pair(std::string_view(fields[i].name), i));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * DatabaseResult::GetFieldValue(unsigned int index) {
|
||||
if (index >= num_fields) {
|
||||
LogWrite(DATABASE__ERROR, 0, "Database Result", "Attempt to access field at index %u but there %s only %u field%s", index, num_fields == 1 ? "is" : "are", num_fields, num_fields == 1 ? "" : "s");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return row[index];
|
||||
}
|
||||
|
||||
const char * DatabaseResult::GetFieldValueStr(const char *field_name) {
|
||||
const auto& map_iterator = field_map.find(std::string_view(field_name));
|
||||
if (map_iterator != field_map.end()) {
|
||||
return row[map_iterator->second];
|
||||
}
|
||||
|
||||
LogWrite(DATABASE__ERROR, 0, "Database Result", "Unknown field name '%s'", field_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool DatabaseResult::Next() {
|
||||
return (result != NULL && (row = mysql_fetch_row(result)) != NULL);
|
||||
}
|
||||
|
||||
bool DatabaseResult::IsNull(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL;
|
||||
}
|
||||
|
||||
bool DatabaseResult::IsNullStr(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL;
|
||||
}
|
||||
|
||||
int8 DatabaseResult::GetInt8(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
int8 DatabaseResult::GetInt8Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
sint8 DatabaseResult::GetSInt8(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
sint8 DatabaseResult::GetSInt8Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
int16 DatabaseResult::GetInt16(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
int16 DatabaseResult::GetInt16Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
sint16 DatabaseResult::GetSInt16(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
sint16 DatabaseResult::GetSInt16Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
int32 DatabaseResult::GetInt32(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? 0U : strtoul(value, NULL, 10);
|
||||
}
|
||||
|
||||
int32 DatabaseResult::GetInt32Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? 0U : strtoul(value, NULL, 10);
|
||||
}
|
||||
|
||||
sint32 DatabaseResult::GetSInt32(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
sint32 DatabaseResult::GetSInt32Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? 0 : atoi(value);
|
||||
}
|
||||
|
||||
uint64 DatabaseResult::GetInt64(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
#ifdef _WIN32
|
||||
return value == NULL ? 0UL : _strtoui64(value, NULL, 10);
|
||||
#else
|
||||
return value == NULL ? 0UL : strtoull(value, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64 DatabaseResult::GetInt64Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
#ifdef _WIN32
|
||||
return value == NULL ? 0UL : _strtoui64(value, NULL, 10);
|
||||
#else
|
||||
return value == NULL ? 0UL : strtoull(value, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
sint64 DatabaseResult::GetSInt64(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
#ifdef _WIN32
|
||||
return value == NULL ? 0L : _strtoi64(value, NULL, 10);
|
||||
#else
|
||||
return value == NULL ? 0L : strtoll(value, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
sint64 DatabaseResult::GetSInt64Str(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
#ifdef _WIN32
|
||||
return value == NULL ? 0L : _strtoi64(value, NULL, 10);
|
||||
#else
|
||||
return value == NULL ? 0L : strtoll(value, NULL, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
float DatabaseResult::GetFloat(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? 0.0F : atof(value);
|
||||
}
|
||||
|
||||
float DatabaseResult::GetFloatStr(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? 0.0F : atof(value);
|
||||
}
|
||||
|
||||
char DatabaseResult::GetChar(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? '\0' : value[0];
|
||||
}
|
||||
|
||||
char DatabaseResult::GetCharStr(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? '\0' : value[0];
|
||||
}
|
||||
|
||||
const char * DatabaseResult::GetString(unsigned int index) {
|
||||
const char *value = GetFieldValue(index);
|
||||
return value == NULL ? empty_str : value;
|
||||
}
|
||||
|
||||
const char * DatabaseResult::GetStringStr(const char *field_name) {
|
||||
const char *value = GetFieldValueStr(field_name);
|
||||
return value == NULL ? empty_str : value;
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
#ifndef COMMON_DATABASERESULT_H_
|
||||
#define COMMON_DATABASERESULT_H_
|
||||
|
||||
#include "types.h"
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h> //#include <my_global.h> when we/if we go to winsock2 :/
|
||||
#endif
|
||||
#include <mysql.h>
|
||||
#include <map>
|
||||
|
||||
class DatabaseResult {
|
||||
public:
|
||||
DatabaseResult();
|
||||
virtual ~DatabaseResult();
|
||||
|
||||
bool StoreResult(MYSQL_RES* result, uint8 field_count, uint8 row_count);
|
||||
bool Next();
|
||||
|
||||
bool IsNull(unsigned int index);
|
||||
bool IsNullStr(const char *field_name);
|
||||
int8 GetInt8(unsigned int index);
|
||||
int8 GetInt8Str(const char *field_name);
|
||||
sint8 GetSInt8(unsigned int index);
|
||||
sint8 GetSInt8Str(const char *field_name);
|
||||
int16 GetInt16(unsigned int index);
|
||||
int16 GetInt16Str(const char *field_name);
|
||||
sint16 GetSInt16(unsigned int index);
|
||||
sint16 GetSInt16Str(const char *field_name);
|
||||
int32 GetInt32(unsigned int index);
|
||||
int32 GetInt32Str(const char *field_name);
|
||||
sint32 GetSInt32(unsigned int index);
|
||||
sint32 GetSInt32Str(const char *field_name);
|
||||
int64 GetInt64(unsigned int index);
|
||||
int64 GetInt64Str(const char *field_name);
|
||||
sint64 GetSInt64(unsigned int index);
|
||||
sint64 GetSInt64Str(const char *field_name);
|
||||
float GetFloat(unsigned int index);
|
||||
float GetFloatStr(const char *field_name);
|
||||
char GetChar(unsigned int index);
|
||||
char GetCharStr(const char *field_name);
|
||||
const char * GetString(unsigned int index);
|
||||
const char * GetStringStr(const char *field_name);
|
||||
|
||||
const unsigned int GetNumRows() { return num_rows; }
|
||||
|
||||
const char * GetFieldValue(unsigned int index);
|
||||
const char * GetFieldValueStr(const char *field_name);
|
||||
private:
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
unsigned int num_rows;
|
||||
unsigned int num_fields;
|
||||
|
||||
std::map<std::string_view,uint8> field_map;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,97 +0,0 @@
|
||||
#include "JsonParser.h"
|
||||
|
||||
JsonParser::JsonParser(const std::string &filename) {
|
||||
is_loaded = false;
|
||||
try {
|
||||
boost::property_tree::read_json(filename, pt);
|
||||
parseTree(pt, "");
|
||||
is_loaded = true;
|
||||
} catch (const boost::property_tree::json_parser_error &e) {
|
||||
std::cerr << "Error reading JSON file: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool JsonParser::convertStringToUnsignedChar(const std::string& str, unsigned char& result) {
|
||||
unsigned long ul;
|
||||
try {
|
||||
ul = std::stoul(str);
|
||||
} catch (const std::invalid_argument&) {
|
||||
return false; // Not a valid number
|
||||
} catch (const std::out_of_range&) {
|
||||
return false; // Number is too large for unsigned long
|
||||
}
|
||||
|
||||
if (ul > std::numeric_limits<unsigned char>::max()) {
|
||||
return false; // Number is too large for unsigned short
|
||||
}
|
||||
|
||||
result = static_cast<unsigned char>(ul);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::convertStringToUnsignedShort(const std::string& str, unsigned short& result) {
|
||||
unsigned long ul;
|
||||
try {
|
||||
ul = std::stoul(str);
|
||||
} catch (const std::invalid_argument&) {
|
||||
return false; // Not a valid number
|
||||
} catch (const std::out_of_range&) {
|
||||
return false; // Number is too large for unsigned long
|
||||
}
|
||||
|
||||
if (ul > std::numeric_limits<unsigned short>::max()) {
|
||||
return false; // Number is too large for unsigned short
|
||||
}
|
||||
|
||||
result = static_cast<unsigned short>(ul);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::convertStringToUnsignedInt(const std::string& str, unsigned int& result) {
|
||||
unsigned long ul;
|
||||
try {
|
||||
ul = std::stoul(str);
|
||||
} catch (const std::invalid_argument&) {
|
||||
return false; // Not a valid number
|
||||
} catch (const std::out_of_range&) {
|
||||
return false; // Number is too large for unsigned long
|
||||
}
|
||||
|
||||
if (ul > std::numeric_limits<unsigned int>::max()) {
|
||||
return false; // Number is too large for unsigned short
|
||||
}
|
||||
|
||||
result = static_cast<unsigned int>(ul);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::convertStringToUnsignedLong(const std::string& str, unsigned long& result) {
|
||||
unsigned long ul;
|
||||
try {
|
||||
ul = std::stoul(str);
|
||||
} catch (const std::invalid_argument&) {
|
||||
return false; // Not a valid number
|
||||
} catch (const std::out_of_range&) {
|
||||
return false; // Number is too large for unsigned long
|
||||
}
|
||||
|
||||
if (ul > std::numeric_limits<unsigned long>::max()) {
|
||||
return false; // Number is too large for unsigned short
|
||||
}
|
||||
|
||||
result = ul;
|
||||
return true;
|
||||
}
|
||||
|
||||
void JsonParser::parseTree(const boost::property_tree::ptree &tree, const std::string &path) {
|
||||
for (const auto &node : tree) {
|
||||
std::string currentPath = path.empty() ? node.first : path + "." + node.first;
|
||||
if (node.second.empty()) {
|
||||
std::string name = currentPath;
|
||||
boost::algorithm::to_lower(name);
|
||||
values[name] = node.second.get_value<std::string>();
|
||||
} else {
|
||||
parseTree(node.second, currentPath);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class JsonParser {
|
||||
public:
|
||||
JsonParser(const std::string &filename);
|
||||
|
||||
std::string getValue(const std::string &path) const {
|
||||
auto it = values.find(path);
|
||||
if (it != values.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static bool convertStringToUnsignedChar(const std::string& str, unsigned char& result);
|
||||
static bool convertStringToUnsignedShort(const std::string& str, unsigned short& result);
|
||||
static bool convertStringToUnsignedInt(const std::string& str, unsigned int& result);
|
||||
static bool convertStringToUnsignedLong(const std::string& str, unsigned long& result);
|
||||
bool IsLoaded() { return is_loaded; }
|
||||
private:
|
||||
boost::property_tree::ptree pt;
|
||||
std::map<std::string, std::string> values;
|
||||
|
||||
void parseTree(const boost::property_tree::ptree &tree, const std::string &path);
|
||||
bool is_loaded;
|
||||
};
|
@ -1,361 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "../common/Log.h"
|
||||
#include "../common/debug.h"
|
||||
#include "../common/Mutex.h"
|
||||
|
||||
Mutex::Mutex() {
|
||||
readers = 0;
|
||||
mlocked = false;
|
||||
writing = false;
|
||||
name = "";
|
||||
#ifdef DEBUG
|
||||
stack.clear();
|
||||
#endif
|
||||
//CSLock is a pointer so we can use a different attribute type on create
|
||||
CSLock = new CriticalSection(MUTEX_ATTRIBUTE_RECURSIVE);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
safe_delete(CSLock);
|
||||
#ifdef DEBUG
|
||||
stack.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::SetName(string in_name) {
|
||||
#ifdef DEBUG
|
||||
name = in_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::lock() {
|
||||
#ifdef DEBUG
|
||||
int i = 0;
|
||||
#endif
|
||||
if (name.length() > 0) {
|
||||
while (mlocked) {
|
||||
#ifdef DEBUG
|
||||
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "Possible deadlock attempt by '%s'!", name.c_str());
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
#endif
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
mlocked = true;
|
||||
CSLock->lock();
|
||||
}
|
||||
|
||||
bool Mutex::trylock() {
|
||||
return CSLock->trylock();
|
||||
}
|
||||
|
||||
void Mutex::unlock() {
|
||||
CSLock->unlock();
|
||||
mlocked = false;
|
||||
}
|
||||
|
||||
void Mutex::readlock(const char* function, int32 line) {
|
||||
#ifdef DEBUG
|
||||
int32 i = 0;
|
||||
#endif
|
||||
while (true) {
|
||||
//Loop until there isn't a writer, then we can read!
|
||||
CSRead.lock();
|
||||
if (!writing) {
|
||||
readers++;
|
||||
CSRead.unlock();
|
||||
#ifdef DEBUG
|
||||
CSStack.lock();
|
||||
if (function)
|
||||
stack[(string)function]++;
|
||||
CSStack.unlock();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
CSRead.unlock();
|
||||
#ifdef DEBUG
|
||||
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out waiting for a readlock!", name.c_str(), function ? function : "name_not_provided", line);
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
|
||||
map<string, int32>::iterator itr;
|
||||
CSStack.lock();
|
||||
for (itr = stack.begin(); itr != stack.end(); itr++) {
|
||||
if (itr->second > 0 && itr->first.length() > 0)
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
|
||||
}
|
||||
CSStack.unlock();
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
#endif
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::releasereadlock(const char* function, int32 line) {
|
||||
//Wait for the readcount lock
|
||||
CSRead.lock();
|
||||
//Lower the readcount by one, when readcount is 0 writers may start writing
|
||||
readers--;
|
||||
CSRead.unlock();
|
||||
#ifdef DEBUG
|
||||
CSStack.lock();
|
||||
if (function) {
|
||||
map<string, int32>::iterator itr = stack.find((string)function);
|
||||
if (itr != stack.end()) {
|
||||
if (--(itr->second) == 0) {
|
||||
stack.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
CSStack.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Mutex::tryreadlock(const char* function) {
|
||||
//This returns true if able to instantly obtain a readlock, false if not
|
||||
CSRead.lock();
|
||||
if (!writing) {
|
||||
readers++;
|
||||
CSRead.unlock();
|
||||
}
|
||||
else {
|
||||
CSRead.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
CSStack.lock();
|
||||
if (function)
|
||||
stack[(string)function]++;
|
||||
CSStack.unlock();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::writelock(const char* function, int32 line) {
|
||||
//Wait until the writer lock becomes available, then we can be the only writer!
|
||||
#ifdef DEBUG
|
||||
int32 i = 0;
|
||||
#endif
|
||||
while (!CSWrite.trylock()) {
|
||||
#ifdef DEBUG
|
||||
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out waiting on another writelock!", name.c_str(), function ? function : "name_not_provided", line);
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
|
||||
map<string, int32>::iterator itr;
|
||||
CSStack.lock();
|
||||
for (itr = stack.begin(); itr != stack.end(); itr++) {
|
||||
if (itr->second > 0 && itr->first.length() > 0)
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
|
||||
}
|
||||
CSStack.unlock();
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
#endif
|
||||
Sleep(1);
|
||||
}
|
||||
waitReaders(function, line);
|
||||
#ifdef DEBUG
|
||||
CSStack.lock();
|
||||
if (function)
|
||||
stack[(string)function]++;
|
||||
CSStack.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::releasewritelock(const char* function, int32 line) {
|
||||
//Wait for the readcount lock
|
||||
CSRead.lock();
|
||||
//Readers are aloud again
|
||||
writing = false;
|
||||
CSRead.unlock();
|
||||
//Allow other writers to write
|
||||
CSWrite.unlock();
|
||||
#ifdef DEBUG
|
||||
CSStack.lock();
|
||||
if (function) {
|
||||
map<string, int32>::iterator itr = stack.find((string)function);
|
||||
if (itr != stack.end()) {
|
||||
if (--(itr->second) == 0) {
|
||||
stack.erase(itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
CSStack.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Mutex::trywritelock(const char* function) {
|
||||
//This returns true if able to instantly obtain a writelock, false if not
|
||||
if (CSWrite.trylock()) {
|
||||
CSRead.lock();
|
||||
if (readers == 0)
|
||||
writing = true;
|
||||
CSRead.unlock();
|
||||
if (!writing) {
|
||||
CSWrite.unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
CSStack.lock();
|
||||
if (function)
|
||||
stack[(string)function]++;
|
||||
CSStack.unlock();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mutex::waitReaders(const char* function, int32 line)
|
||||
{
|
||||
//Wait for all current readers to stop, then we can write!
|
||||
#ifdef DEBUG
|
||||
int32 i = 0;
|
||||
#endif
|
||||
while (true)
|
||||
{
|
||||
CSRead.lock();
|
||||
if (readers == 0)
|
||||
{
|
||||
writing = true;
|
||||
CSRead.unlock();
|
||||
break;
|
||||
}
|
||||
CSRead.unlock();
|
||||
#ifdef DEBUG
|
||||
if (i > MUTEX_TIMEOUT_MILLISECONDS) {
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "The mutex %s called from %s at line %u timed out while waiting on readers!", name.c_str(), function ? function : "name_not_provided", line);
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "The following functions had locks:");
|
||||
map<string, int32>::iterator itr;
|
||||
CSStack.lock();
|
||||
for (itr = stack.begin(); itr != stack.end(); itr++) {
|
||||
if (itr->second > 0 && itr->first.length() > 0)
|
||||
LogWrite(MUTEX__ERROR, 0, "Mutex", "%s, number of locks = %u", itr->first.c_str(), itr->second);
|
||||
}
|
||||
CSStack.unlock();
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
#endif
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
LockMutex::LockMutex(Mutex* in_mut, bool iLock) {
|
||||
mut = in_mut;
|
||||
locked = iLock;
|
||||
if (locked) {
|
||||
mut->lock();
|
||||
}
|
||||
}
|
||||
|
||||
LockMutex::~LockMutex() {
|
||||
if (locked) {
|
||||
mut->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void LockMutex::unlock() {
|
||||
if (locked)
|
||||
mut->unlock();
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void LockMutex::lock() {
|
||||
if (!locked)
|
||||
mut->lock();
|
||||
locked = true;
|
||||
}
|
||||
|
||||
CriticalSection::CriticalSection(int attribute) {
|
||||
#ifdef WIN32
|
||||
InitializeCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutexattr_init(&type_attribute);
|
||||
switch (attribute)
|
||||
{
|
||||
case MUTEX_ATTRIBUTE_FAST:
|
||||
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
|
||||
break;
|
||||
case MUTEX_ATTRIBUTE_RECURSIVE:
|
||||
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||
break;
|
||||
case MUTEX_ATTRIBUTE_ERRORCHK:
|
||||
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_ERRORCHECK_NP);
|
||||
break;
|
||||
default:
|
||||
LogWrite(MUTEX__DEBUG, 0, "Critical Section", "Invalid mutex attribute type! Using PTHREAD_MUTEX_FAST_NP");
|
||||
pthread_mutexattr_settype(&type_attribute, PTHREAD_MUTEX_FAST_NP);
|
||||
break;
|
||||
}
|
||||
pthread_mutex_init(&CSMutex, &type_attribute);
|
||||
#endif
|
||||
}
|
||||
|
||||
CriticalSection::~CriticalSection() {
|
||||
#ifdef WIN32
|
||||
DeleteCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutex_destroy(&CSMutex);
|
||||
pthread_mutexattr_destroy(&type_attribute);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CriticalSection::lock() {
|
||||
//Waits for a lock on this critical section
|
||||
#ifdef WIN32
|
||||
EnterCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutex_lock(&CSMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CriticalSection::unlock() {
|
||||
//Gets rid of one of the current thread's locks on this critical section
|
||||
#ifdef WIN32
|
||||
LeaveCriticalSection(&CSMutex);
|
||||
#else
|
||||
pthread_mutex_unlock(&CSMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CriticalSection::trylock() {
|
||||
//Returns true if able to instantly get a lock on this critical section, false if not
|
||||
#ifdef WIN32
|
||||
return TryEnterCriticalSection(&CSMutex);
|
||||
#else
|
||||
return (pthread_mutex_trylock(&CSMutex) == 0);
|
||||
#endif
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef MYMUTEX_H
|
||||
#define MYMUTEX_H
|
||||
#ifdef WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include "../common/unix.h"
|
||||
#endif
|
||||
#include "../common/types.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#define MUTEX_ATTRIBUTE_FAST 1
|
||||
#define MUTEX_ATTRIBUTE_RECURSIVE 2
|
||||
#define MUTEX_ATTRIBUTE_ERRORCHK 3
|
||||
#define MUTEX_TIMEOUT_MILLISECONDS 10000
|
||||
|
||||
class CriticalSection {
|
||||
public:
|
||||
CriticalSection(int attribute = MUTEX_ATTRIBUTE_FAST);
|
||||
~CriticalSection();
|
||||
void lock();
|
||||
void unlock();
|
||||
bool trylock();
|
||||
private:
|
||||
#ifdef WIN32
|
||||
CRITICAL_SECTION CSMutex;
|
||||
#else
|
||||
pthread_mutex_t CSMutex;
|
||||
pthread_mutexattr_t type_attribute;
|
||||
#endif
|
||||
};
|
||||
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
bool trylock();
|
||||
|
||||
void readlock(const char* function = 0, int32 line = 0);
|
||||
void releasereadlock(const char* function = 0, int32 line = 0);
|
||||
bool tryreadlock(const char* function = 0);
|
||||
|
||||
void writelock(const char* function = 0, int32 line = 0);
|
||||
void releasewritelock(const char* function = 0, int32 line = 0);
|
||||
bool trywritelock(const char* function = 0);
|
||||
|
||||
void waitReaders(const char* function = 0, int32 line = 0);
|
||||
|
||||
void SetName(string in_name);
|
||||
private:
|
||||
CriticalSection CSRead;
|
||||
CriticalSection CSWrite;
|
||||
CriticalSection* CSLock;
|
||||
|
||||
#ifdef DEBUG //Used for debugging only
|
||||
CriticalSection CSStack;
|
||||
map<string, int32> stack;
|
||||
#endif
|
||||
|
||||
int readers;
|
||||
bool writing;
|
||||
volatile bool mlocked;
|
||||
string name;
|
||||
};
|
||||
|
||||
|
||||
class LockMutex {
|
||||
public:
|
||||
LockMutex(Mutex* in_mut, bool iLock = true);
|
||||
~LockMutex();
|
||||
void unlock();
|
||||
void lock();
|
||||
private:
|
||||
bool locked;
|
||||
Mutex* mut;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "RC4.h"
|
||||
#include <string.h>
|
||||
|
||||
static bool g_bInitStateInitialized = false;
|
||||
static uchar g_byInitState[256];
|
||||
|
||||
RC4::RC4(int64 nKey)
|
||||
{
|
||||
if( !g_bInitStateInitialized )
|
||||
{
|
||||
for(int16 i = 0; i < 256; i++ )
|
||||
g_byInitState[i] = i;
|
||||
}
|
||||
Init(nKey);
|
||||
}
|
||||
|
||||
RC4::~RC4()
|
||||
{
|
||||
}
|
||||
|
||||
void RC4::Init(int64 nKey)
|
||||
{
|
||||
memcpy(m_state, g_byInitState, 256);
|
||||
m_x = 0;
|
||||
m_y = 0;
|
||||
|
||||
ulong dwKeyIndex = 0;
|
||||
ulong dwStateIndex = 0;
|
||||
uchar* pKey = (uchar*)&nKey;
|
||||
for(int16 i = 0; i < 256; i++ )
|
||||
{
|
||||
ulong dwTemp = m_state[i];
|
||||
dwStateIndex += pKey[dwKeyIndex] + dwTemp;
|
||||
dwStateIndex &= 0xFF;
|
||||
m_state[i] = m_state[dwStateIndex];
|
||||
m_state[dwStateIndex] = (uchar)dwTemp;
|
||||
dwKeyIndex++;
|
||||
dwKeyIndex &= 7;
|
||||
}
|
||||
}
|
||||
|
||||
// A = m_state[X + 1]
|
||||
// B = m_state[Y + A]
|
||||
// C ^= m_state[(A + B)]
|
||||
|
||||
// X = 20
|
||||
// Y = ?
|
||||
// C = 0
|
||||
// m_state[(A + B)] = Cypher Byte
|
||||
|
||||
void RC4::Cypher(uchar* pBuffer, int32 nLength)
|
||||
{
|
||||
int32 nOffset = 0;
|
||||
uchar byKey1 = m_x;
|
||||
uchar byKey2 = m_y;
|
||||
if( nLength > 0 )
|
||||
{
|
||||
do
|
||||
{
|
||||
byKey1++;
|
||||
uchar byKeyVal1 = m_state[byKey1];
|
||||
|
||||
byKey2 += byKeyVal1;
|
||||
uchar byKeyVal2 = m_state[byKey2];
|
||||
|
||||
m_state[byKey1] = byKeyVal2;
|
||||
m_state[byKey2] = byKeyVal1;
|
||||
|
||||
pBuffer[nOffset++] ^= m_state[(byKeyVal1 + byKeyVal2) & 0xFF];
|
||||
} while( nOffset < nLength );
|
||||
}
|
||||
m_x = byKey1;
|
||||
m_y = byKey2;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _EQ2_RC4_H
|
||||
#define _EQ2_RC4_H
|
||||
#include "../common/types.h"
|
||||
class RC4
|
||||
{
|
||||
public:
|
||||
RC4(int64 nKey);
|
||||
~RC4();
|
||||
|
||||
void Init(int64 nKey);
|
||||
void Cypher(uchar* pData, int32 nLen);
|
||||
|
||||
private:
|
||||
uchar m_state[256];
|
||||
uchar m_x;
|
||||
uchar m_y;
|
||||
};
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,277 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef TCP_CONNECTION_H
|
||||
#define TCP_CONNECTION_H
|
||||
/*
|
||||
Parent classes for interserver TCP Communication.
|
||||
-Quagmire
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
|
||||
#include <process.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#define INVALID_SOCKET -1
|
||||
#define SOCKET_ERROR -1
|
||||
#include "unix.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "Mutex.h"
|
||||
#include "linked_list.h"
|
||||
#include "queue.h"
|
||||
#include "servertalk.h"
|
||||
#include "timer.h"
|
||||
#include "MiscFunctions.h"
|
||||
|
||||
class TCPServer;
|
||||
|
||||
#define TCPConnection_ErrorBufferSize 1024
|
||||
#define MaxTCPReceiveBufferSize 524288
|
||||
|
||||
#define TCPS_Ready 0
|
||||
#define TCPS_Connecting 1
|
||||
#define TCPS_Connected 100
|
||||
#define TCPS_Disconnecting 200
|
||||
#define TCPS_Disconnected 201
|
||||
#define TCPS_Closing 250
|
||||
#define TCPS_Error 255
|
||||
|
||||
#ifndef DEF_eConnectionType
|
||||
#define DEF_eConnectionType
|
||||
enum eConnectionType {Incomming, Outgoing};
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
void TCPServerLoop(void* tmp);
|
||||
void TCPConnectionLoop(void* tmp);
|
||||
#else
|
||||
void* TCPServerLoop(void* tmp);
|
||||
void* TCPConnectionLoop(void* tmp);
|
||||
#endif
|
||||
|
||||
enum eTCPMode { modeConsole, modeTransition, modePacket };
|
||||
class TCPConnection {
|
||||
public:
|
||||
#pragma pack(1)
|
||||
struct TCPNetPacket_Struct {
|
||||
int32 size;
|
||||
struct {
|
||||
int8
|
||||
compressed : 1,
|
||||
destination : 1,
|
||||
flag3 : 1,
|
||||
flag4 : 1,
|
||||
flag5 : 1,
|
||||
flag6 : 1,
|
||||
flag7 : 1,
|
||||
flag8 : 1;
|
||||
} flags;
|
||||
int16 opcode;
|
||||
uchar buffer[0];
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
static TCPNetPacket_Struct* MakePacket(ServerPacket* pack, int32 iDestination = 0);
|
||||
|
||||
TCPConnection(TCPServer* iServer, SOCKET iSock, int32 irIP, int16 irPort, bool iOldFormat = false);
|
||||
TCPConnection(bool iOldFormat = false, TCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections
|
||||
TCPConnection(TCPServer* iServer, TCPConnection* iRelayLink, int32 iRemoteID, int32 irIP, int16 irPort); // for relay connections
|
||||
virtual ~TCPConnection();
|
||||
|
||||
// Functions for outgoing connections
|
||||
bool Connect(char* irAddress, int16 irPort, char* errbuf = 0);
|
||||
bool Connect(int32 irIP, int16 irPort, char* errbuf = 0);
|
||||
void AsyncConnect(char* irAddress, int16 irPort);
|
||||
void AsyncConnect(int32 irIP, int16 irPort);
|
||||
virtual void Disconnect(bool iSendRelayDisconnect = true);
|
||||
|
||||
virtual bool SendPacket(ServerPacket* pack, int32 iDestination = 0);
|
||||
virtual bool SendPacket(TCPNetPacket_Struct* tnps);
|
||||
bool Send(const uchar* data, sint32 size);
|
||||
|
||||
char* PopLine();
|
||||
ServerPacket* PopPacket(); // OutQueuePop()
|
||||
inline int32 GetrIP() { return rIP; }
|
||||
inline int16 GetrPort() { return rPort; }
|
||||
virtual int8 GetState();
|
||||
eTCPMode GetMode() { return TCPMode; }
|
||||
inline bool Connected() { return (GetState() == TCPS_Connected); }
|
||||
inline bool ConnectReady() { return (bool) (GetState() == TCPS_Ready && ConnectionType == Outgoing); }
|
||||
void Free(); // Inform TCPServer that this connection object is no longer referanced
|
||||
|
||||
inline int32 GetID() { return id; }
|
||||
inline bool IsRelayServer() { return RelayServer; }
|
||||
inline int32 GetRemoteID() { return RemoteID; }
|
||||
inline TCPConnection* GetRelayLink() { return RelayLink; }
|
||||
|
||||
bool GetEcho();
|
||||
void SetEcho(bool iValue);
|
||||
protected:
|
||||
friend class TCPServer;
|
||||
virtual bool Process();
|
||||
void SetState(int8 iState);
|
||||
inline bool IsFree() { return pFree; }
|
||||
bool CheckNetActive();
|
||||
|
||||
#ifdef WIN32
|
||||
friend void TCPConnectionLoop(void* tmp);
|
||||
#else
|
||||
friend void* TCPConnectionLoop(void* tmp);
|
||||
#endif
|
||||
SOCKET sock;
|
||||
bool RunLoop();
|
||||
Mutex MLoopRunning;
|
||||
Mutex MAsyncConnect;
|
||||
bool GetAsyncConnect();
|
||||
bool SetAsyncConnect(bool iValue);
|
||||
char* charAsyncConnect;
|
||||
|
||||
#ifdef WIN32
|
||||
friend class TCPConnection;
|
||||
#endif
|
||||
void OutQueuePush(ServerPacket* pack);
|
||||
void RemoveRelay(TCPConnection* relay, bool iSendRelayDisconnect);
|
||||
private:
|
||||
void ProcessNetworkLayerPacket(ServerPacket* pack);
|
||||
void SendNetErrorPacket(const char* reason = 0);
|
||||
TCPServer* Server;
|
||||
TCPConnection* RelayLink;
|
||||
int32 RemoteID;
|
||||
sint32 RelayCount;
|
||||
|
||||
bool pOldFormat;
|
||||
bool SendData(char* errbuf = 0);
|
||||
bool RecvData(char* errbuf = 0);
|
||||
bool ProcessReceivedData(char* errbuf = 0);
|
||||
bool ProcessReceivedDataAsPackets(char* errbuf = 0);
|
||||
bool ProcessReceivedDataAsOldPackets(char* errbuf = 0);
|
||||
void ClearBuffers();
|
||||
|
||||
bool pAsyncConnect;
|
||||
|
||||
eConnectionType ConnectionType;
|
||||
eTCPMode TCPMode;
|
||||
bool RelayServer;
|
||||
Mutex MRunLoop;
|
||||
bool pRunLoop;
|
||||
|
||||
SOCKET connection_socket;
|
||||
int32 id;
|
||||
int32 rIP;
|
||||
int16 rPort; // host byte order
|
||||
bool pFree;
|
||||
|
||||
Mutex MState;
|
||||
int8 pState;
|
||||
|
||||
void LineOutQueuePush(char* line);
|
||||
MyQueue<char> LineOutQueue;
|
||||
MyQueue<ServerPacket> OutQueue;
|
||||
Mutex MOutQueueLock;
|
||||
|
||||
Timer* keepalive_timer;
|
||||
Timer* timeout_timer;
|
||||
|
||||
uchar* recvbuf;
|
||||
sint32 recvbuf_size;
|
||||
sint32 recvbuf_used;
|
||||
|
||||
sint32 recvbuf_echo;
|
||||
bool pEcho;
|
||||
Mutex MEcho;
|
||||
|
||||
void InModeQueuePush(TCPNetPacket_Struct* tnps);
|
||||
MyQueue<TCPNetPacket_Struct> InModeQueue;
|
||||
Mutex MSendQueue;
|
||||
uchar* sendbuf;
|
||||
sint32 sendbuf_size;
|
||||
sint32 sendbuf_used;
|
||||
bool ServerSendQueuePop(uchar** data, sint32* size);
|
||||
void ServerSendQueuePushEnd(const uchar* data, sint32 size);
|
||||
void ServerSendQueuePushEnd(uchar** data, sint32 size);
|
||||
void ServerSendQueuePushFront(uchar* data, sint32 size);
|
||||
};
|
||||
|
||||
class TCPServer {
|
||||
public:
|
||||
TCPServer(int16 iPort = 0, bool iOldFormat = false);
|
||||
virtual ~TCPServer();
|
||||
|
||||
bool Open(int16 iPort = 0, char* errbuf = 0); // opens the port
|
||||
void Close(); // closes the port
|
||||
bool IsOpen();
|
||||
inline int16 GetPort() { return pPort; }
|
||||
|
||||
TCPConnection* NewQueuePop();
|
||||
|
||||
void SendPacket(ServerPacket* pack);
|
||||
void SendPacket(TCPConnection::TCPNetPacket_Struct** tnps);
|
||||
protected:
|
||||
#ifdef WIN32
|
||||
friend void TCPServerLoop(void* tmp);
|
||||
#else
|
||||
friend void* TCPServerLoop(void* tmp);
|
||||
#endif
|
||||
void Process();
|
||||
bool RunLoop();
|
||||
Mutex MLoopRunning;
|
||||
|
||||
friend class TCPConnection;
|
||||
inline int32 GetNextID() { return NextID++; }
|
||||
void AddConnection(TCPConnection* con);
|
||||
TCPConnection* GetConnection(int32 iID);
|
||||
private:
|
||||
void ListenNewConnections();
|
||||
|
||||
int32 NextID;
|
||||
bool pOldFormat;
|
||||
|
||||
Mutex MRunLoop;
|
||||
bool pRunLoop;
|
||||
|
||||
Mutex MSock;
|
||||
SOCKET sock;
|
||||
int16 pPort;
|
||||
|
||||
Mutex MNewQueue;
|
||||
MyQueue<TCPConnection> NewQueue;
|
||||
|
||||
void CheckInQueue();
|
||||
Mutex MInQueue;
|
||||
TCPConnection::TCPNetPacket_Struct* InQueuePop();
|
||||
MyQueue<TCPConnection::TCPNetPacket_Struct> InQueue;
|
||||
|
||||
LinkedList<TCPConnection*>* list;
|
||||
};
|
||||
#endif
|
@ -1,567 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "../common/debug.h"
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errmsg.h>
|
||||
//#include <mysqld_error.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <map>
|
||||
|
||||
// Disgrace: for windows compile
|
||||
#ifdef WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#else
|
||||
#include "unix.h"
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "database.h"
|
||||
#include "EQStream.h"
|
||||
#include "packet_functions.h"
|
||||
#include "emu_opcodes.h"
|
||||
#ifdef WORLD
|
||||
#include "../WorldServer/WorldDatabase.h"
|
||||
extern WorldDatabase database;
|
||||
#endif
|
||||
#ifdef LOGIN
|
||||
#include "../LoginServer/LoginDatabase.h"
|
||||
extern LoginDatabase database;
|
||||
#endif
|
||||
#ifdef PARSER
|
||||
#include "../PacketParser/ParserDatabase.h"
|
||||
extern ParserDatabase database;
|
||||
#endif
|
||||
|
||||
#ifdef PATCHER
|
||||
#include "../PatchServer/PatcherDatabase.h"
|
||||
extern PatcherDatabase database;
|
||||
#endif
|
||||
#include "../common/EQEMuError.h"
|
||||
#include "../common/packet_dump.h"
|
||||
#include "../common/Log.h"
|
||||
|
||||
#ifdef WORLD
|
||||
ThreadReturnType DBAsyncQueries(void* str)
|
||||
{
|
||||
// allow some buffer for multiple queries to collect
|
||||
Sleep(10);
|
||||
DBStruct* data = (DBStruct*)str;
|
||||
database.RunAsyncQueries(data->queryid);
|
||||
delete data;
|
||||
THREAD_RETURN(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
Database::Database()
|
||||
{
|
||||
InitVars();
|
||||
}
|
||||
|
||||
bool Database::Init(bool silentLoad) {
|
||||
char host[200], user[200], passwd[200], database[200];
|
||||
unsigned int port=0;
|
||||
bool compression = false;
|
||||
bool items[6] = {false, false, false, false, false, false};
|
||||
const char* exampleIni[] = { "[Database]", "host = localhost", "user = root", "password = pass", "database = dbname", "### --- Assure each parameter is on a new line!" };
|
||||
|
||||
if(!ReadDBINI(host, user, passwd, database, &port, &compression, items)) {
|
||||
//exit(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!items[0] || !items[1] || !items[2] || !items[3])
|
||||
{
|
||||
LogWrite(DATABASE__ERROR, 0, "DB", "Database file %s is incomplete.", DB_INI_FILE);
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if ( !items[i] )
|
||||
LogWrite(DATABASE__ERROR, 0, "DB", "Could not find parameter %s", exampleIni[i+1]); // offset by 1 because the [Database] entry
|
||||
}
|
||||
LogWrite(DATABASE__ERROR, 0, "DB", "Example File:");
|
||||
int length = sizeof exampleIni / sizeof exampleIni[0];
|
||||
for(i=0;i<length;i++)
|
||||
LogWrite(DATABASE__ERROR, 0, "DB", "%s", exampleIni[i]);
|
||||
//exit (1);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 errnum = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
if (!Open(host, user, passwd, database,port, &errnum, errbuf))
|
||||
{
|
||||
LogWrite(DATABASE__ERROR, 0, "DB", "Failed to connect to database: Error: %s", errbuf);
|
||||
HandleMysqlError(errnum);
|
||||
//exit(1);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!silentLoad)
|
||||
LogWrite(DATABASE__INFO, 0, "DB", "Using database '%s' at %s", database, host);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
map<int16, int16> Database::GetVersions(){
|
||||
map<int16, int16> opcodes;
|
||||
Query query;
|
||||
MYSQL_ROW row;
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "select distinct version_range1, version_range2 from opcodes");
|
||||
while(result && (row = mysql_fetch_row(result))){
|
||||
if(row[0] && row[1])
|
||||
opcodes[atoi(row[0])] = atoi(row[1]);
|
||||
}
|
||||
return opcodes;
|
||||
}
|
||||
|
||||
map<string, uint16> Database::GetOpcodes(int16 version){
|
||||
map<string, uint16> opcodes;
|
||||
Query query;
|
||||
MYSQL_ROW row;
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "select name, opcode from opcodes where %i between version_range1 and version_range2 order by version_range1, id", version);
|
||||
while(result && (row = mysql_fetch_row(result))){
|
||||
opcodes[row[0]] = atoi(row[1]);
|
||||
}
|
||||
return opcodes;
|
||||
}
|
||||
|
||||
int32 Database::AuthenticateWebUser(char* userName, char* passwd, int32* status){
|
||||
if(status) {
|
||||
*status = 0;
|
||||
}
|
||||
Query query;
|
||||
MYSQL_ROW row;
|
||||
int32 id = 0;
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "select id, status from web_users where username='%s' and passwd = sha2('%s', 512)", getSafeEscapeString(userName).c_str(), getSafeEscapeString(passwd).c_str());
|
||||
if(result && (row = mysql_fetch_row(result))){
|
||||
id = atoul(row[0]);
|
||||
if(status) {
|
||||
*status = atoul(row[1]);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
int32 Database::NoAuthRoute(char* route){
|
||||
Query query;
|
||||
MYSQL_ROW row;
|
||||
int32 status = 0xFFFFFFFF;
|
||||
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "select status from web_routes where route='%s'", getSafeEscapeString(route).c_str());
|
||||
if(result && (row = mysql_fetch_row(result))){
|
||||
status = atoul(row[0]);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void Database::HandleMysqlError(int32 errnum) {
|
||||
switch(errnum) {
|
||||
case 0:
|
||||
break;
|
||||
case 1045: // Access Denied
|
||||
case 2001: {
|
||||
AddEQEMuError(EQEMuError_Mysql_1405, true);
|
||||
break;
|
||||
}
|
||||
case 2003: { // Unable to connect
|
||||
AddEQEMuError(EQEMuError_Mysql_2003, true);
|
||||
break;
|
||||
}
|
||||
case 2005: { // Unable to connect
|
||||
AddEQEMuError(EQEMuError_Mysql_2005, true);
|
||||
break;
|
||||
}
|
||||
case 2007: { // Unable to connect
|
||||
AddEQEMuError(EQEMuError_Mysql_2007, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Database::InitVars() {
|
||||
|
||||
}
|
||||
|
||||
Database::~Database()
|
||||
{
|
||||
#ifdef WORLD
|
||||
DBQueryMutex.writelock(__FUNCTION__, __LINE__);
|
||||
activeQuerySessions.clear();
|
||||
DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__);
|
||||
|
||||
DBAsyncMutex.writelock();
|
||||
continueAsync = false;
|
||||
map<int32, deque<Query*>>::iterator itr;
|
||||
for (itr = asyncQueries.begin(); itr != asyncQueries.end(); itr++)
|
||||
{
|
||||
asyncQueriesMutex[itr->first]->writelock();
|
||||
deque<Query*> queries = itr->second;
|
||||
while (queries.size() > 0)
|
||||
{
|
||||
Query* cur = queries.front();
|
||||
queries.pop_front();
|
||||
safe_delete(cur);
|
||||
}
|
||||
asyncQueriesMutex[itr->first]->releasewritelock();
|
||||
Mutex* mutex = asyncQueriesMutex[itr->first];
|
||||
asyncQueriesMutex.erase(itr->first);
|
||||
safe_delete(mutex);
|
||||
}
|
||||
asyncQueries.clear();
|
||||
|
||||
asyncQueriesMutex.clear();
|
||||
DBAsyncMutex.releasewritelock();
|
||||
|
||||
PurgeDBInstances();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WORLD
|
||||
void Query::AddQueryAsync(int32 queryID, Database* db, QUERY_TYPE type, const char* format, ...) {
|
||||
in_type = type;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
#ifdef WIN32
|
||||
char* buffer;
|
||||
int buf_len = _vscprintf(format, args) + 1;
|
||||
buffer = new char[buf_len];
|
||||
vsprintf(buffer, format, args);
|
||||
#else
|
||||
char* buffer;
|
||||
int buf_len;
|
||||
va_list argcopy;
|
||||
va_copy(argcopy, args);
|
||||
buf_len = vsnprintf(NULL, 0, format, argcopy) + 1;
|
||||
va_end(argcopy);
|
||||
|
||||
buffer = new char[buf_len];
|
||||
vsnprintf(buffer, buf_len, format, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
query = string(buffer);
|
||||
|
||||
Query* asyncQuery = new Query(this, queryID);
|
||||
|
||||
safe_delete_array(buffer);
|
||||
|
||||
db->AddAsyncQuery(asyncQuery);
|
||||
}
|
||||
|
||||
void Query::RunQueryAsync(Database* db) {
|
||||
db->RunQuery(query.c_str(), query.length(), errbuf, &result, affected_rows, last_insert_id, &errnum, retry);
|
||||
}
|
||||
#endif
|
||||
|
||||
MYSQL_RES* Query::RunQuery2(QUERY_TYPE type, const char* format, ...){
|
||||
va_list args;
|
||||
va_start( args, format );
|
||||
#ifdef WIN32
|
||||
char * buffer;
|
||||
int buf_len = _vscprintf( format, args ) + 1;
|
||||
buffer = new char[buf_len];
|
||||
vsprintf( buffer, format, args );
|
||||
#else
|
||||
char* buffer;
|
||||
int buf_len;
|
||||
va_list argcopy;
|
||||
va_copy(argcopy, args);
|
||||
buf_len = vsnprintf(NULL, 0, format, argcopy) + 1;
|
||||
va_end(argcopy);
|
||||
|
||||
buffer = new char[buf_len];
|
||||
vsnprintf(buffer, buf_len, format, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
query = string(buffer);
|
||||
|
||||
|
||||
safe_delete_array( buffer );
|
||||
|
||||
|
||||
return RunQuery2(query.c_str(), type);
|
||||
}
|
||||
MYSQL_RES* Query::RunQuery2(string in_query, QUERY_TYPE type){
|
||||
switch(type){
|
||||
case Q_SELECT:
|
||||
break;
|
||||
case Q_DBMS:
|
||||
case Q_REPLACE:
|
||||
case Q_DELETE:
|
||||
case Q_UPDATE:
|
||||
safe_delete(affected_rows);
|
||||
affected_rows = new int32;
|
||||
break;
|
||||
case Q_INSERT:
|
||||
safe_delete(last_insert_id);
|
||||
last_insert_id = new int32;
|
||||
}
|
||||
if(result){
|
||||
if(!multiple_results)
|
||||
multiple_results = new vector<MYSQL_RES*>();
|
||||
multiple_results->push_back(result);
|
||||
}
|
||||
query = in_query;
|
||||
|
||||
#if defined WORLD && defined _DEBUG
|
||||
if (type == Q_UPDATE || type == Q_INSERT || type == Q_DELETE || type == Q_REPLACE)
|
||||
{
|
||||
char* filteredTables[] = { " characters", " character_", " `character_", " statistics", " variables", " char_colors", " `guild", " bugs" };
|
||||
|
||||
bool match = false;
|
||||
for (int i = 0; i < sizeof(filteredTables) / sizeof(filteredTables[0]); i++)
|
||||
{
|
||||
if (query.find(filteredTables[i]) != std::string::npos) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!match)
|
||||
{
|
||||
FILE* pFile;
|
||||
pFile = fopen("sql_updates.sql", "a+");
|
||||
fwrite(query.c_str(), 1, query.length(), pFile);
|
||||
fwrite(";", sizeof(char), 1, pFile);
|
||||
fwrite("\n", sizeof(char), 1, pFile);
|
||||
fclose(pFile);
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
database.RunQuery(query.c_str(), query.length(), errbuf, &result, affected_rows, last_insert_id, &errnum, retry);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef WORLD
|
||||
void Database::RunAsyncQueries(int32 queryid)
|
||||
{
|
||||
Database* asyncdb = FindFreeInstance();
|
||||
DBAsyncMutex.writelock();
|
||||
map<int32, deque<Query*>>::iterator itr = asyncQueries.find(queryid);
|
||||
if (itr == asyncQueries.end())
|
||||
{
|
||||
DBAsyncMutex.releasewritelock();
|
||||
return;
|
||||
}
|
||||
|
||||
asyncQueriesMutex[queryid]->writelock();
|
||||
deque<Query*> queries;
|
||||
while (itr->second.size())
|
||||
{
|
||||
Query* cur = itr->second.front();
|
||||
queries.push_back(cur);
|
||||
itr->second.pop_front();
|
||||
}
|
||||
itr->second.clear();
|
||||
asyncQueries.erase(itr);
|
||||
DBAsyncMutex.releasewritelock();
|
||||
asyncQueriesMutex[queryid]->releasewritelock();
|
||||
|
||||
int32 count = 0;
|
||||
while (queries.size() > 0)
|
||||
{
|
||||
Query* cur = queries.front();
|
||||
cur->RunQueryAsync(asyncdb);
|
||||
this->RemoveActiveQuery(cur);
|
||||
queries.pop_front();
|
||||
safe_delete(cur);
|
||||
}
|
||||
FreeDBInstance(asyncdb);
|
||||
|
||||
bool isActive = IsActiveQuery(queryid);
|
||||
if (isActive)
|
||||
{
|
||||
continueAsync = true;
|
||||
DBStruct* tmp = new DBStruct;
|
||||
tmp->queryid = queryid;
|
||||
#ifdef WIN32
|
||||
_beginthread(DBAsyncQueries, 0, (void*)tmp);
|
||||
#else
|
||||
pthread_t t1;
|
||||
pthread_create(&t1, NULL, DBAsyncQueries, (void*)tmp);
|
||||
pthread_detach(t1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Database::AddAsyncQuery(Query* query)
|
||||
{
|
||||
DBAsyncMutex.writelock();
|
||||
map<int32, Mutex*>::iterator mutexItr = asyncQueriesMutex.find(query->GetQueryID());
|
||||
if (mutexItr == asyncQueriesMutex.end())
|
||||
{
|
||||
Mutex* queryMutex = new Mutex();
|
||||
queryMutex->SetName("AsyncQuery" + query->GetQueryID());
|
||||
asyncQueriesMutex.insert(make_pair(query->GetQueryID(), queryMutex));
|
||||
}
|
||||
map<int32, deque<Query*>>::iterator itr = asyncQueries.find(query->GetQueryID());
|
||||
asyncQueriesMutex[query->GetQueryID()]->writelock();
|
||||
|
||||
if ( itr != asyncQueries.end())
|
||||
itr->second.push_back(query);
|
||||
else
|
||||
{
|
||||
deque<Query*> queue;
|
||||
queue.push_back(query);
|
||||
asyncQueries.insert(make_pair(query->GetQueryID(), queue));
|
||||
}
|
||||
|
||||
AddActiveQuery(query);
|
||||
|
||||
asyncQueriesMutex[query->GetQueryID()]->releasewritelock();
|
||||
DBAsyncMutex.releasewritelock();
|
||||
|
||||
bool isActive = IsActiveQuery(query->GetQueryID(), query);
|
||||
if (!isActive)
|
||||
{
|
||||
continueAsync = true;
|
||||
DBStruct* tmp = new DBStruct;
|
||||
tmp->queryid = query->GetQueryID();
|
||||
#ifdef WIN32
|
||||
_beginthread(DBAsyncQueries, 0, (void*)tmp);
|
||||
#else
|
||||
pthread_t t1;
|
||||
pthread_create(&t1, NULL, DBAsyncQueries, (void*)tmp);
|
||||
pthread_detach(t1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Database* Database::FindFreeInstance()
|
||||
{
|
||||
Database* db_inst = 0;
|
||||
map<Database*, bool>::iterator itr;
|
||||
DBInstanceMutex.writelock(__FUNCTION__, __LINE__);
|
||||
for (itr = dbInstances.begin(); itr != dbInstances.end(); itr++) {
|
||||
if (!itr->second)
|
||||
{
|
||||
db_inst = itr->first;
|
||||
itr->second = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!db_inst)
|
||||
{
|
||||
WorldDatabase* tmp = new WorldDatabase();
|
||||
db_inst = (Database*)tmp;
|
||||
tmp->Init();
|
||||
tmp->ConnectNewDatabase();
|
||||
dbInstances.insert(make_pair(db_inst, true));
|
||||
}
|
||||
DBInstanceMutex.releasewritelock(__FUNCTION__, __LINE__);
|
||||
|
||||
return db_inst;
|
||||
}
|
||||
|
||||
void Database::PurgeDBInstances()
|
||||
{
|
||||
map<Database*, bool>::iterator itr;
|
||||
DBInstanceMutex.writelock(__FUNCTION__, __LINE__);
|
||||
for (itr = dbInstances.begin(); itr != dbInstances.end(); itr++) {
|
||||
WorldDatabase* tmpInst = (WorldDatabase*)itr->first;
|
||||
safe_delete(tmpInst);
|
||||
}
|
||||
dbInstances.clear();
|
||||
DBInstanceMutex.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
|
||||
void Database::PingAsyncDatabase()
|
||||
{
|
||||
map<Database*, bool>::iterator itr;
|
||||
DBInstanceMutex.readlock(__FUNCTION__, __LINE__);
|
||||
for (itr = dbInstances.begin(); itr != dbInstances.end(); itr++) {
|
||||
Database* tmpInst = itr->first;
|
||||
tmpInst->ping();
|
||||
}
|
||||
DBInstanceMutex.releasereadlock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void Database::FreeDBInstance(Database* cur)
|
||||
{
|
||||
DBInstanceMutex.writelock(__FUNCTION__, __LINE__);
|
||||
dbInstances[cur] = false;
|
||||
DBInstanceMutex.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void Database::RemoveActiveQuery(Query* query)
|
||||
{
|
||||
DBQueryMutex.writelock(__FUNCTION__, __LINE__);
|
||||
|
||||
vector<Query*>::iterator itr;
|
||||
for (itr = activeQuerySessions.begin(); itr != activeQuerySessions.end(); itr++)
|
||||
{
|
||||
Query* curQuery = *itr;
|
||||
if (query == curQuery)
|
||||
{
|
||||
activeQuerySessions.erase(itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
void Database::AddActiveQuery(Query* query)
|
||||
{
|
||||
DBQueryMutex.writelock(__FUNCTION__, __LINE__);
|
||||
activeQuerySessions.push_back(query);
|
||||
DBQueryMutex.releasewritelock(__FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
bool Database::IsActiveQuery(int32 id, Query* skip)
|
||||
{
|
||||
bool isActive = false;
|
||||
|
||||
DBQueryMutex.readlock(__FUNCTION__, __LINE__);
|
||||
vector<Query*>::iterator itr;
|
||||
for (itr = activeQuerySessions.begin(); itr != activeQuerySessions.end(); itr++)
|
||||
{
|
||||
Query* query = *itr;
|
||||
if (query == skip)
|
||||
continue;
|
||||
|
||||
if (query->GetQueryID() == id)
|
||||
{
|
||||
isActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBQueryMutex.releasereadlock(__FUNCTION__, __LINE__);
|
||||
|
||||
return isActive;
|
||||
}
|
||||
#endif
|
@ -1,183 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef EQ2EMU_DATABASE_H
|
||||
#define EQ2EMU_DATABASE_H
|
||||
|
||||
#ifdef WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <mysql.h>
|
||||
|
||||
#include "dbcore.h"
|
||||
#include "types.h"
|
||||
#include "linked_list.h"
|
||||
#include "EQStream.h"
|
||||
#include "MiscFunctions.h"
|
||||
#include "Mutex.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
class Query;
|
||||
|
||||
class Database : public DBcore
|
||||
{
|
||||
public:
|
||||
Database();
|
||||
~Database();
|
||||
bool Init(bool silentLoad=false);
|
||||
bool LoadVariables();
|
||||
void HandleMysqlError(int32 errnum);
|
||||
map<string, uint16> GetOpcodes(int16 version);
|
||||
int32 AuthenticateWebUser(char* userName, char* passwd,int32* status = 0);
|
||||
int32 NoAuthRoute(char* route);
|
||||
map<int16, int16> GetVersions();
|
||||
|
||||
#ifdef WORLD
|
||||
void AddAsyncQuery(Query* query);
|
||||
void RunAsyncQueries(int32 queryid);
|
||||
Database* FindFreeInstance();
|
||||
void RemoveActiveQuery(Query* query);
|
||||
void AddActiveQuery(Query* query);
|
||||
bool IsActiveQuery(int32 id, Query* skip=0);
|
||||
void PingAsyncDatabase();
|
||||
#endif
|
||||
protected:
|
||||
|
||||
private:
|
||||
void InitVars();
|
||||
|
||||
#ifdef WORLD
|
||||
void PurgeDBInstances();
|
||||
void FreeDBInstance(Database* cur);
|
||||
bool continueAsync;
|
||||
map<int32, deque<Query*>> asyncQueries;
|
||||
map<int32, Mutex*> asyncQueriesMutex;
|
||||
map<Database*, bool> dbInstances;
|
||||
vector<Query*> activeQuerySessions;
|
||||
Mutex DBAsyncMutex;
|
||||
Mutex DBInstanceMutex;
|
||||
Mutex DBQueryMutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int32 queryid;
|
||||
}DBStruct;
|
||||
|
||||
class Query{
|
||||
public:
|
||||
Query() {
|
||||
result = 0;
|
||||
affected_rows = 0;
|
||||
last_insert_id = 0;
|
||||
errnum = 0;
|
||||
row = 0;
|
||||
retry = true;
|
||||
escaped_name = 0;
|
||||
escaped_pass = 0;
|
||||
escaped_data1 = 0;
|
||||
multiple_results = 0;
|
||||
memset(errbuf, 0, sizeof(errbuf));
|
||||
queryID = 0;
|
||||
}
|
||||
Query(Query* queryPtr, int32 in_id) {
|
||||
result = 0;
|
||||
affected_rows = 0;
|
||||
last_insert_id = 0;
|
||||
errnum = 0;
|
||||
row = 0;
|
||||
retry = true;
|
||||
escaped_name = 0;
|
||||
escaped_pass = 0;
|
||||
escaped_data1 = 0;
|
||||
multiple_results = 0;
|
||||
memset(errbuf, 0, sizeof(errbuf));
|
||||
query = string(queryPtr->GetQuery());
|
||||
in_type = queryPtr->GetQueryType();
|
||||
queryID = in_id;
|
||||
}
|
||||
|
||||
~Query(){
|
||||
if(result)
|
||||
mysql_free_result(result);
|
||||
result = 0;
|
||||
safe_delete(affected_rows);
|
||||
safe_delete(last_insert_id);
|
||||
safe_delete_array(escaped_name);
|
||||
safe_delete_array(escaped_pass);
|
||||
safe_delete_array(escaped_data1);
|
||||
if(multiple_results){
|
||||
vector<MYSQL_RES*>::iterator itr;
|
||||
for(itr = multiple_results->begin(); itr != multiple_results->end(); itr++){
|
||||
mysql_free_result(*itr);
|
||||
}
|
||||
safe_delete(multiple_results);
|
||||
}
|
||||
}
|
||||
int32 GetLastInsertedID() { return *last_insert_id; }
|
||||
int32 GetAffectedRows() { return *affected_rows; }
|
||||
MYSQL_RES* GetResult() { return result; }
|
||||
MYSQL_RES* RunQuery2(string in_query, QUERY_TYPE type);
|
||||
char* GetError() { return errbuf; }
|
||||
int32 GetErrorNumber(){ return errnum; }
|
||||
const char* GetQuery() { return query.c_str(); }
|
||||
char* GetField(int8 field_num) {
|
||||
if(!row && result)
|
||||
*row = mysql_fetch_row(result);
|
||||
if(row && result && field_num < mysql_num_fields(result))
|
||||
return *row[field_num];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
void NextRow(){
|
||||
if(result)
|
||||
*row = mysql_fetch_row(result);
|
||||
}
|
||||
void AddQueryAsync(int32 queryID, Database* db, QUERY_TYPE type, const char* format, ...);
|
||||
void RunQueryAsync(Database* db);
|
||||
MYSQL_RES* RunQuery2(QUERY_TYPE type, const char* format, ...);
|
||||
|
||||
QUERY_TYPE GetQueryType() {
|
||||
return in_type;
|
||||
}
|
||||
|
||||
int32 GetQueryID() { return queryID; }
|
||||
|
||||
char* escaped_name;
|
||||
char* escaped_pass;
|
||||
char* escaped_data1;
|
||||
private:
|
||||
string query;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
vector<MYSQL_RES*>* multiple_results;
|
||||
int32* affected_rows;
|
||||
int32* last_insert_id;
|
||||
int32 errnum;
|
||||
QUERY_TYPE in_type;
|
||||
bool retry;
|
||||
MYSQL_ROW* row;
|
||||
MYSQL mysql;
|
||||
int32 queryID;
|
||||
};
|
||||
#endif
|
@ -1,368 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "debug.h"
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
#include <errmsg.h>
|
||||
//#include <mysqld_error.h>
|
||||
#include <limits.h>
|
||||
#include "dbcore.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "types.h"
|
||||
#include "MiscFunctions.h"
|
||||
#include "Log.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#include <process.h>
|
||||
#else
|
||||
#include "unix.h"
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef _EQDEBUG
|
||||
#define DEBUG_MYSQL_QUERIES 0
|
||||
#else
|
||||
#define DEBUG_MYSQL_QUERIES 0
|
||||
#endif
|
||||
|
||||
DBcore::DBcore() {
|
||||
mysql_init(&mysql);
|
||||
pHost = 0;
|
||||
pPort = 0;
|
||||
pUser = 0;
|
||||
pPassword = 0;
|
||||
pDatabase = 0;
|
||||
pCompress = false;
|
||||
pSSL = false;
|
||||
pStatus = Closed;
|
||||
}
|
||||
|
||||
DBcore::~DBcore() {
|
||||
pStatus = Closed;
|
||||
mysql_close(&mysql);
|
||||
#if MYSQL_VERSION_ID >= 50003
|
||||
mysql_library_end();
|
||||
#else
|
||||
mysql_server_end();
|
||||
#endif
|
||||
safe_delete_array(pHost);
|
||||
safe_delete_array(pUser);
|
||||
safe_delete_array(pPassword);
|
||||
safe_delete_array(pDatabase);
|
||||
}
|
||||
|
||||
|
||||
bool DBcore::ReadDBINI(char* host, char* user, char* passwd, char* database, unsigned int* port, bool* compress, bool* items) {
|
||||
char line[256], * key, * val;
|
||||
bool on_database_section = false;
|
||||
FILE* f;
|
||||
|
||||
if ((f = fopen(DB_INI_FILE, "r")) == NULL) {
|
||||
LogWrite(DATABASE__ERROR, 0, "DBCore", "Unable to open '%s' for reading", DB_INI_FILE);
|
||||
return false;
|
||||
}
|
||||
|
||||
//read each line
|
||||
while (fgets(line, sizeof(line), f) != NULL) {
|
||||
|
||||
//remove any new line or carriage return
|
||||
while ((key = strstr(line, "\n")) != NULL)
|
||||
*key = '\0';
|
||||
while ((key = strstr(line, "\r")) != NULL)
|
||||
*key = '\0';
|
||||
|
||||
//ignore blank lines and commented lines
|
||||
if (strlen(line) == 0 || line[0] == '#')
|
||||
continue;
|
||||
|
||||
key = strtok(line, "=");
|
||||
|
||||
if (key == NULL)
|
||||
continue;
|
||||
|
||||
//don't do anything until we find the [Database] section
|
||||
if (!on_database_section && strncasecmp(key, "[Database]", 10) == 0)
|
||||
on_database_section = true;
|
||||
else {
|
||||
val = strtok(NULL, "=");
|
||||
|
||||
if (val == NULL)
|
||||
{
|
||||
if (strcasecmp(key, "password") == 0) {
|
||||
strcpy(passwd, "");
|
||||
items[2] = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (strcasecmp(key, "host") == 0) {
|
||||
strcpy(host, val);
|
||||
items[0] = true;
|
||||
}
|
||||
else if (strcasecmp(key, "user") == 0) {
|
||||
strcpy(user, val);
|
||||
items[1] = true;
|
||||
}
|
||||
else if (strcasecmp(key, "password") == 0) {
|
||||
strcpy(passwd, val);
|
||||
items[2] = true;
|
||||
}
|
||||
else if (strcasecmp(key, "database") == 0) {
|
||||
strcpy(database, val);
|
||||
items[3] = true;
|
||||
}
|
||||
else if (strcasecmp(key, "port") == 0 && port) {
|
||||
*port = atoul(val);
|
||||
items[4] = true;
|
||||
}
|
||||
else if (strcasecmp(key, "compression") == 0) {
|
||||
if (strcasecmp(val, "on") == 0) {
|
||||
if(compress) {
|
||||
*compress = true;
|
||||
items[5] = true;
|
||||
LogWrite(DATABASE__INFO, 0, "DBCore", "DB Compression on.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
if (!on_database_section) {
|
||||
LogWrite(DATABASE__ERROR, 0, "DBCore", "[Database] section not found in '%s'", DB_INI_FILE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Sends the MySQL server a keepalive
|
||||
void DBcore::ping() {
|
||||
if (!MDatabase.trylock()) {
|
||||
// well, if's it's locked, someone's using it. If someone's using it, it doesnt need a keepalive
|
||||
return;
|
||||
}
|
||||
mysql_ping(&mysql);
|
||||
|
||||
int32* errnum = new int32;
|
||||
*errnum = mysql_errno(&mysql);
|
||||
|
||||
switch (*errnum)
|
||||
{
|
||||
case CR_COMMANDS_OUT_OF_SYNC:
|
||||
case CR_SERVER_GONE_ERROR:
|
||||
case CR_UNKNOWN_ERROR:
|
||||
{
|
||||
LogWrite(DATABASE__ERROR, 0, "DBCore", "[Database] We lost connection to the database., errno: %i", errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
safe_delete(errnum);
|
||||
MDatabase.unlock();
|
||||
}
|
||||
|
||||
bool DBcore::RunQuery(const char* query, int32 querylen, char* errbuf, MYSQL_RES** result, int32* affected_rows, int32* last_insert_id, int32* errnum, bool retry) {
|
||||
if (errnum)
|
||||
*errnum = 0;
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
bool ret = false;
|
||||
LockMutex lock(&MDatabase);
|
||||
if (pStatus != Connected)
|
||||
Open();
|
||||
|
||||
LogWrite(DATABASE__QUERY, 0, "DBCore", query);
|
||||
if (mysql_real_query(&mysql, query, querylen)) {
|
||||
if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR)
|
||||
pStatus = Error;
|
||||
if (mysql_errno(&mysql) == CR_SERVER_LOST || mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) {
|
||||
if (retry) {
|
||||
LogWrite(DATABASE__ERROR, 0, "DBCore", "Lost connection, attempting to recover...");
|
||||
ret = RunQuery(query, querylen, errbuf, result, affected_rows, last_insert_id, errnum, false);
|
||||
}
|
||||
else {
|
||||
pStatus = Error;
|
||||
if (errnum)
|
||||
*errnum = mysql_errno(&mysql);
|
||||
if (errbuf)
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
LogWrite(DATABASE__ERROR, 0, "DBCore", "#%i: %s\nQuery:\n%s", mysql_errno(&mysql), mysql_error(&mysql), query);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (errnum)
|
||||
*errnum = mysql_errno(&mysql);
|
||||
if (errbuf)
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
LogWrite(DATABASE__ERROR, 0, "DBCore", "#%i: %s\nQuery:\n%s", mysql_errno(&mysql), mysql_error(&mysql), query);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (result && mysql_field_count(&mysql)) {
|
||||
*result = mysql_store_result(&mysql);
|
||||
}
|
||||
else if (result)
|
||||
*result = 0;
|
||||
if (affected_rows)
|
||||
*affected_rows = mysql_affected_rows(&mysql);
|
||||
if (last_insert_id)
|
||||
*last_insert_id = mysql_insert_id(&mysql);
|
||||
if (result) {
|
||||
if (*result) {
|
||||
ret = true;
|
||||
}
|
||||
else {
|
||||
if (errnum)
|
||||
*errnum = UINT_MAX;
|
||||
if (errbuf){
|
||||
if((!affected_rows || (affected_rows && *affected_rows == 0)) && (!last_insert_id || (last_insert_id && *last_insert_id == 0)))
|
||||
LogWrite(DATABASE__RESULT, 1, "DBCore", "No Result.");
|
||||
}
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
char tmp1[200] = {0};
|
||||
char tmp2[200] = {0};
|
||||
if (result && (*result))
|
||||
snprintf(tmp1, sizeof(tmp1), ", %i rows returned", (int) mysql_num_rows(*result));
|
||||
if (affected_rows)
|
||||
snprintf(tmp2, sizeof(tmp2), ", %i rows affected", (*affected_rows));
|
||||
|
||||
LogWrite(DATABASE__DEBUG, 0, "DBCore", "Query Successful%s%s", tmp1, tmp2);
|
||||
}
|
||||
else
|
||||
LogWrite(DATABASE__DEBUG, 0, "DBCore", "Query returned no results in %s!\n%s", __FUNCTION__, query);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32 DBcore::DoEscapeString(char* tobuf, const char* frombuf, int32 fromlen) {
|
||||
LockMutex lock(&MDatabase);
|
||||
return mysql_real_escape_string(&mysql, tobuf, frombuf, fromlen);
|
||||
}
|
||||
|
||||
bool DBcore::Open(const char* iHost, const char* iUser, const char* iPassword, const char* iDatabase,int32 iPort, int32* errnum, char* errbuf, bool iCompress, bool iSSL) {
|
||||
LockMutex lock(&MDatabase);
|
||||
safe_delete_array(pHost);
|
||||
safe_delete_array(pUser);
|
||||
safe_delete_array(pPassword);
|
||||
safe_delete_array(pDatabase);
|
||||
pHost = new char[strlen(iHost) + 1];
|
||||
strcpy(pHost, iHost);
|
||||
pUser = new char[strlen(iUser) + 1];
|
||||
strcpy(pUser, iUser);
|
||||
pPassword = new char[strlen(iPassword) + 1];
|
||||
strcpy(pPassword, iPassword);
|
||||
pDatabase = new char[strlen(iDatabase) + 1];
|
||||
strcpy(pDatabase, iDatabase);
|
||||
pCompress = iCompress;
|
||||
pPort = iPort;
|
||||
pSSL = iSSL;
|
||||
return Open(errnum, errbuf);
|
||||
}
|
||||
|
||||
bool DBcore::Open(int32* errnum, char* errbuf) {
|
||||
if (errbuf)
|
||||
errbuf[0] = 0;
|
||||
LockMutex lock(&MDatabase);
|
||||
if (GetStatus() == Connected)
|
||||
return true;
|
||||
if (GetStatus() == Error)
|
||||
mysql_close(&mysql);
|
||||
if (!pHost)
|
||||
return false;
|
||||
/*
|
||||
Quagmire - added CLIENT_FOUND_ROWS flag to the connect
|
||||
otherwise DB update calls would say 0 rows affected when the value already equalled
|
||||
what the function was tring to set it to, therefore the function would think it failed
|
||||
*/
|
||||
int32 flags = CLIENT_FOUND_ROWS;
|
||||
if (pCompress)
|
||||
flags |= CLIENT_COMPRESS;
|
||||
if (pSSL)
|
||||
flags |= CLIENT_SSL;
|
||||
if (mysql_real_connect(&mysql, pHost, pUser, pPassword, pDatabase, pPort, 0, flags)) {
|
||||
pStatus = Connected;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (errnum)
|
||||
*errnum = mysql_errno(&mysql);
|
||||
if (errbuf)
|
||||
snprintf(errbuf, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
pStatus = Error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char* DBcore::getEscapeString(const char* from_string){
|
||||
if(!from_string)
|
||||
from_string ="";
|
||||
int orig_size = strlen(from_string);
|
||||
int escape_size = (orig_size * 2) + 1;
|
||||
char* escaped = new char[escape_size];
|
||||
memset(escaped, 0, escape_size);
|
||||
DoEscapeString(escaped, from_string, orig_size);
|
||||
return escaped;
|
||||
}
|
||||
|
||||
string DBcore::getSafeEscapeString(const char* from_string){
|
||||
if(!from_string)
|
||||
from_string ="";
|
||||
int orig_size = strlen(from_string);
|
||||
int escape_size = (orig_size * 2) + 1;
|
||||
char* escaped = new char[escape_size];
|
||||
memset(escaped, 0, escape_size);
|
||||
DoEscapeString(escaped, from_string, orig_size);
|
||||
string ret = string(escaped);
|
||||
safe_delete_array(escaped);
|
||||
return ret;
|
||||
}
|
||||
|
||||
string DBcore::getSafeEscapeString(string* from_string){
|
||||
if(!from_string)
|
||||
return "";
|
||||
int orig_size = from_string->length();
|
||||
int escape_size = (orig_size * 2) + 1;
|
||||
char* escaped = new char[escape_size];
|
||||
memset(escaped, 0, escape_size);
|
||||
DoEscapeString(escaped, from_string->c_str(), orig_size);
|
||||
string ret = string(escaped);
|
||||
safe_delete_array(escaped);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef DBCORE_H
|
||||
#define DBCORE_H
|
||||
|
||||
#ifdef WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
//#include <WinSock2.h>
|
||||
#endif
|
||||
#include <mysql.h>
|
||||
#include "../common/types.h"
|
||||
#include "../common/Mutex.h"
|
||||
#include "../common/linked_list.h"
|
||||
#include "../common/queue.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/Condition.h"
|
||||
#ifdef LOGIN
|
||||
#define DB_INI_FILE "login_db.ini"
|
||||
#endif
|
||||
#ifdef WORLD
|
||||
#define DB_INI_FILE "world_db.ini"
|
||||
#endif
|
||||
#ifdef PARSER
|
||||
#define DB_INI_FILE "parser_db.ini"
|
||||
#endif
|
||||
#ifdef PATCHER
|
||||
#define DB_INI_FILE "patcher_db.ini"
|
||||
#endif
|
||||
class DBcore{
|
||||
public:
|
||||
enum eStatus { Closed, Connected, Error };
|
||||
DBcore();
|
||||
~DBcore();
|
||||
eStatus GetStatus() { return pStatus; }
|
||||
bool RunQuery(const char* query, int32 querylen, char* errbuf = 0, MYSQL_RES** result = 0, int32* affected_rows = 0, int32* last_insert_id = 0, int32* errnum = 0, bool retry = true);
|
||||
int32 DoEscapeString(char* tobuf, const char* frombuf, int32 fromlen);
|
||||
void ping();
|
||||
char* getEscapeString(const char* from_string);
|
||||
string getSafeEscapeString(const char* from_string);
|
||||
string getSafeEscapeString(string* from_string);
|
||||
|
||||
protected:
|
||||
bool Open(const char* iHost, const char* iUser, const char* iPassword, const char* iDatabase, int32 iPort, int32* errnum = 0, char* errbuf = 0, bool iCompress = false, bool iSSL = false);
|
||||
bool ReadDBINI(char *host, char *user, char *pass, char *db, unsigned int* port, bool* compress, bool *items);
|
||||
private:
|
||||
bool Open(int32* errnum = 0, char* errbuf = 0);
|
||||
|
||||
MYSQL mysql;
|
||||
Mutex MDatabase;
|
||||
eStatus pStatus;
|
||||
|
||||
char* pHost;
|
||||
char* pUser;
|
||||
char* pPassword;
|
||||
char* pDatabase;
|
||||
bool pCompress;
|
||||
int32 pPort;
|
||||
bool pSSL;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1,336 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
JA: File rendered obsolete (2011-08-12)
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#include "../common/MiscFunctions.h"
|
||||
|
||||
EQEMuLog* LogFile = new EQEMuLog;
|
||||
AutoDelete<EQEMuLog> adlf(&LogFile);
|
||||
|
||||
static const char* FileNames[EQEMuLog::MaxLogID] = { "logs/eq2emu", "logs/eq2emu", "logs/eq2emu_error", "logs/eq2emu_debug", "logs/eq2emu_quest", "logs/eq2emu_commands" };
|
||||
static const char* LogNames[EQEMuLog::MaxLogID] = { "Status", "Normal", "Error", "Debug", "Quest", "Command" };
|
||||
|
||||
EQEMuLog::EQEMuLog() {
|
||||
for (int i=0; i<MaxLogID; i++) {
|
||||
fp[i] = 0;
|
||||
#if EQDEBUG >= 2
|
||||
pLogStatus[i] = 1 | 2;
|
||||
#else
|
||||
pLogStatus[i] = 0;
|
||||
#endif
|
||||
logCallbackFmt[i] = NULL;
|
||||
logCallbackBuf[i] = NULL;
|
||||
}
|
||||
#if EQDEBUG < 2
|
||||
pLogStatus[Status] = 3;
|
||||
pLogStatus[Error] = 3;
|
||||
pLogStatus[Debug] = 3;
|
||||
pLogStatus[Quest] = 2;
|
||||
pLogStatus[Commands] = 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
EQEMuLog::~EQEMuLog() {
|
||||
for (int i=0; i<MaxLogID; i++) {
|
||||
if (fp[i])
|
||||
fclose(fp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool EQEMuLog::open(LogIDs id) {
|
||||
if (id >= MaxLogID) {
|
||||
return false;
|
||||
}
|
||||
LockMutex lock(&MOpen);
|
||||
if (pLogStatus[id] & 4) {
|
||||
return false;
|
||||
}
|
||||
if (fp[id]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char exename[200] = "";
|
||||
#if defined(WORLD)
|
||||
snprintf(exename, sizeof(exename), "_world");
|
||||
#elif defined(ZONE)
|
||||
snprintf(exename, sizeof(exename), "_zone");
|
||||
#endif
|
||||
char filename[200];
|
||||
#ifndef NO_PIDLOG
|
||||
snprintf(filename, sizeof(filename), "%s%s_%04i.log", FileNames[id], exename, getpid());
|
||||
#else
|
||||
snprintf(filename, sizeof(filename), "%s%s.log", FileNames[id], exename);
|
||||
#endif
|
||||
fp[id] = fopen(filename, "a");
|
||||
if (!fp[id]) {
|
||||
cerr << "Failed to open log file: " << filename << endl;
|
||||
pLogStatus[id] |= 4; // set file state to error
|
||||
return false;
|
||||
}
|
||||
fputs("---------------------------------------------\n",fp[id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQEMuLog::write(LogIDs id, const char *fmt, ...) {
|
||||
char buffer[4096];
|
||||
|
||||
if (!this) {
|
||||
return false;
|
||||
}
|
||||
if (id >= MaxLogID) {
|
||||
return false;
|
||||
}
|
||||
bool dofile = false;
|
||||
if (pLogStatus[id] & 1) {
|
||||
dofile = open(id);
|
||||
}
|
||||
if (!(dofile || pLogStatus[id] & 2))
|
||||
return false;
|
||||
LockMutex lock(&MLog[id]);
|
||||
|
||||
time_t aclock;
|
||||
struct tm *newtime;
|
||||
|
||||
time( &aclock ); //Get time in seconds
|
||||
newtime = localtime( &aclock ); //Convert time to struct
|
||||
|
||||
if (dofile){
|
||||
#ifndef NO_PIDLOG
|
||||
fprintf(fp[id], "[%04d%02d%02d %02d:%02d:%02d] ", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
|
||||
#else
|
||||
fprintf(fp[id], "%04i [%04d%02d%02d %02d:%02d:%02d] ", getpid(), newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
|
||||
#endif
|
||||
}
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, argptr);
|
||||
va_end(argptr);
|
||||
if (dofile)
|
||||
fprintf(fp[id], "%s\n", buffer);
|
||||
if(logCallbackFmt[id]) {
|
||||
msgCallbackFmt p = logCallbackFmt[id];
|
||||
p(id, fmt, argptr );
|
||||
}
|
||||
|
||||
if (pLogStatus[id] & 2) {
|
||||
if (pLogStatus[id] & 8) {
|
||||
fprintf(stderr, "[%04d%02d%02d %02d:%02d:%02d] [%s] ", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, LogNames[id]);
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "[%04d%02d%02d %02d:%02d:%02d] [%s] ", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec, LogNames[id]);
|
||||
fprintf(stdout, "%s\n", buffer);
|
||||
}
|
||||
}
|
||||
if (dofile)
|
||||
fprintf(fp[id], "\n");
|
||||
if (pLogStatus[id] & 2) {
|
||||
if (pLogStatus[id] & 8)
|
||||
fprintf(stderr, "\n");
|
||||
else
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
if(dofile)
|
||||
fflush(fp[id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQEMuLog::writebuf(LogIDs id, const char *buf, int8 size, int32 count) {
|
||||
if (!this) {
|
||||
return false;
|
||||
}
|
||||
if (id >= MaxLogID) {
|
||||
return false;
|
||||
}
|
||||
bool dofile = false;
|
||||
if (pLogStatus[id] & 1) {
|
||||
dofile = open(id);
|
||||
}
|
||||
if (!(dofile || pLogStatus[id] & 2))
|
||||
return false;
|
||||
LockMutex lock(&MLog[id]);
|
||||
|
||||
time_t aclock;
|
||||
struct tm *newtime;
|
||||
|
||||
time( &aclock ); // Get time in seconds
|
||||
newtime = localtime( &aclock ); // Convert time to struct
|
||||
|
||||
if (dofile){
|
||||
#ifndef NO_PIDLOG
|
||||
fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] ", newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
|
||||
#else
|
||||
fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] ", getpid(), newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (dofile) {
|
||||
fwrite(buf, size, count, fp[id]);
|
||||
fprintf(fp[id], "\n");
|
||||
}
|
||||
if(logCallbackBuf[id]) {
|
||||
msgCallbackBuf p = logCallbackBuf[id];
|
||||
p(id, buf, size, count);
|
||||
}
|
||||
if (pLogStatus[id] & 2) {
|
||||
if (pLogStatus[id] & 8) {
|
||||
fprintf(stderr, "[%s] ", LogNames[id]);
|
||||
fwrite(buf, size, count, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
} else {
|
||||
fprintf(stdout, "[%s] ", LogNames[id]);
|
||||
fwrite(buf, size, count, stdout);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
if(dofile)
|
||||
fflush(fp[id]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EQEMuLog::writeNTS(LogIDs id, bool dofile, const char *fmt, ...) {
|
||||
char buffer[4096];
|
||||
va_list argptr;
|
||||
va_start(argptr, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, argptr);
|
||||
va_end(argptr);
|
||||
if (dofile)
|
||||
fprintf(fp[id], "%s\n", buffer);
|
||||
if (pLogStatus[id] & 2) {
|
||||
if (pLogStatus[id] & 8)
|
||||
fprintf(stderr, "%s\n", buffer);
|
||||
else
|
||||
fprintf(stdout, "%s\n", buffer);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool EQEMuLog::Dump(LogIDs id, int8* data, int32 size, int32 cols, int32 skip) {
|
||||
if (!this) {
|
||||
#if EQDEBUG >= 10
|
||||
cerr << "Error: Dump() from null pointer"<<endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if (size == 0)
|
||||
return true;
|
||||
if (!LogFile)
|
||||
return false;
|
||||
if (id >= MaxLogID)
|
||||
return false;
|
||||
bool dofile = false;
|
||||
if (pLogStatus[id] & 1) {
|
||||
dofile = open(id);
|
||||
}
|
||||
if (!(dofile || pLogStatus[id] & 2))
|
||||
return false;
|
||||
LockMutex lock(&MLog[id]);
|
||||
write(id, "Dumping Packet: %i", size);
|
||||
// Output as HEX
|
||||
int j = 0; char* ascii = new char[cols+1]; memset(ascii, 0, cols+1);
|
||||
int32 i;
|
||||
for(i=skip; i<size; i++) {
|
||||
if ((i-skip)%cols==0) {
|
||||
if (i != skip)
|
||||
writeNTS(id, dofile, " | %s\n", ascii);
|
||||
writeNTS(id, dofile, "%4i: ", i-skip);
|
||||
memset(ascii, 0, cols+1);
|
||||
j = 0;
|
||||
}
|
||||
else if ((i-skip)%(cols/2) == 0) {
|
||||
writeNTS(id, dofile, "- ");
|
||||
}
|
||||
writeNTS(id, dofile, "%02X ", (unsigned char)data[i]);
|
||||
|
||||
if (data[i] >= 32 && data[i] < 127)
|
||||
ascii[j++] = data[i];
|
||||
else
|
||||
ascii[j++] = '.';
|
||||
}
|
||||
int32 k = ((i-skip)-1)%cols;
|
||||
if (k < 8)
|
||||
writeNTS(id, dofile, " ");
|
||||
for (int32 h = k+1; h < cols; h++) {
|
||||
writeNTS(id, dofile, " ");
|
||||
}
|
||||
writeNTS(id, dofile, " | %s\n", ascii);
|
||||
if (dofile)
|
||||
fflush(fp[id]);
|
||||
safe_delete_array(ascii);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EQEMuLog::SetCallback(LogIDs id, msgCallbackFmt proc) {
|
||||
if (!this)
|
||||
return;
|
||||
if (id >= MaxLogID) {
|
||||
return;
|
||||
}
|
||||
logCallbackFmt[id] = proc;
|
||||
}
|
||||
|
||||
void EQEMuLog::SetCallback(LogIDs id, msgCallbackBuf proc) {
|
||||
if (!this)
|
||||
return;
|
||||
if (id >= MaxLogID) {
|
||||
return;
|
||||
}
|
||||
logCallbackBuf[id] = proc;
|
||||
}
|
||||
|
||||
void EQEMuLog::SetAllCallbacks(msgCallbackFmt proc) {
|
||||
if (!this)
|
||||
return;
|
||||
int r;
|
||||
for(r = Status; r < MaxLogID; r++) {
|
||||
SetCallback((LogIDs)r, proc);
|
||||
}
|
||||
}
|
||||
|
||||
void EQEMuLog::SetAllCallbacks(msgCallbackBuf proc) {
|
||||
if (!this)
|
||||
return;
|
||||
int r;
|
||||
for(r = Status; r < MaxLogID; r++) {
|
||||
SetCallback((LogIDs)r, proc);
|
||||
}
|
||||
}
|
||||
*/
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef EQDEBUG_H
|
||||
#define EQDEBUG_H
|
||||
|
||||
// Debug Levels
|
||||
/*
|
||||
1 = Normal
|
||||
3 = Some extended debug info
|
||||
5 = Light DETAIL info
|
||||
7 = Heavy DETAIL info
|
||||
9 = DumpPacket/PrintPacket
|
||||
You should use even numbers too, to define any subset of the above basic template
|
||||
*/
|
||||
#ifndef EQDEBUG
|
||||
#define EQDEBUG 1
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(DEBUG) && defined(WIN32)
|
||||
//#ifndef _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#if (_MSC_VER < 1300)
|
||||
#include <new>
|
||||
#include <memory>
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#endif
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
#ifndef ThrowError
|
||||
void CatchSignal(int);
|
||||
#if defined(CATCH_CRASH) || defined(_EQDEBUG)
|
||||
#define ThrowError(errstr) { cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << endl; LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); throw errstr; }
|
||||
#else
|
||||
#define ThrowError(errstr) { cout << "Fatal error: " << errstr << " (" << __FILE__ << ", line " << __LINE__ << ")" << endl; LogWrite(WORLD__ERROR, 0, "Debug", "Thrown Error: %s (%s:%i)", errstr, __FILE__, __LINE__); CatchSignal(0); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
// VS6 doesn't like the length of STL generated names: disabling
|
||||
#pragma warning(disable:4786)
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#define DebugBreak() if(0) {}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "../common/Mutex.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
class EQEMuLog {
|
||||
public:
|
||||
EQEMuLog();
|
||||
~EQEMuLog();
|
||||
|
||||
enum LogIDs {
|
||||
Status = 0, //this must stay the first entry in this list
|
||||
Normal,
|
||||
Error,
|
||||
Debug,
|
||||
Quest,
|
||||
Commands,
|
||||
MaxLogID
|
||||
};
|
||||
|
||||
//these are callbacks called for each
|
||||
typedef void (* msgCallbackBuf)(LogIDs id, const char *buf, int8 size, int32 count);
|
||||
typedef void (* msgCallbackFmt)(LogIDs id, const char *fmt, va_list ap);
|
||||
|
||||
void SetAllCallbacks(msgCallbackFmt proc);
|
||||
void SetAllCallbacks(msgCallbackBuf proc);
|
||||
void SetCallback(LogIDs id, msgCallbackFmt proc);
|
||||
void SetCallback(LogIDs id, msgCallbackBuf proc);
|
||||
|
||||
bool writebuf(LogIDs id, const char *buf, int8 size, int32 count);
|
||||
bool write(LogIDs id, const char *fmt, ...);
|
||||
bool Dump(LogIDs id, int8* data, int32 size, int32 cols=16, int32 skip=0);
|
||||
private:
|
||||
bool open(LogIDs id);
|
||||
bool writeNTS(LogIDs id, bool dofile, const char *fmt, ...); // no error checking, assumes is open, no locking, no timestamp, no newline
|
||||
|
||||
Mutex MOpen;
|
||||
Mutex MLog[MaxLogID];
|
||||
FILE* fp[MaxLogID];
|
||||
/* LogStatus: bitwise variable
|
||||
1 = output to file
|
||||
2 = output to stdout
|
||||
4 = fopen error, dont retry
|
||||
8 = use stderr instead (2 must be set)
|
||||
*/
|
||||
int8 pLogStatus[MaxLogID];
|
||||
|
||||
msgCallbackFmt logCallbackFmt[MaxLogID];
|
||||
msgCallbackBuf logCallbackBuf[MaxLogID];
|
||||
};
|
||||
|
||||
//extern EQEMuLog* LogFile;
|
||||
|
||||
#ifdef _EQDEBUG
|
||||
class PerformanceMonitor {
|
||||
public:
|
||||
PerformanceMonitor(sint64* ip) {
|
||||
p = ip;
|
||||
QueryPerformanceCounter(&tmp);
|
||||
}
|
||||
~PerformanceMonitor() {
|
||||
LARGE_INTEGER tmp2;
|
||||
QueryPerformanceCounter(&tmp2);
|
||||
*p += tmp2.QuadPart - tmp.QuadPart;
|
||||
}
|
||||
LARGE_INTEGER tmp;
|
||||
sint64* p;
|
||||
};
|
||||
#endif
|
||||
#endif
|
@ -1,445 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LINKEDLIST_H
|
||||
#define LINKEDLIST_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
enum direction{FORWARD,BACKWARD};
|
||||
|
||||
template<class TYPE> class LinkedListIterator;
|
||||
|
||||
template<class TYPE>
|
||||
class ListElement
|
||||
{
|
||||
private:
|
||||
|
||||
TYPE data;
|
||||
ListElement<TYPE>* next;
|
||||
ListElement<TYPE>* prev;
|
||||
public:
|
||||
ListElement ();
|
||||
ListElement (const TYPE&);
|
||||
ListElement (const ListElement<TYPE>&);
|
||||
|
||||
~ListElement ();
|
||||
|
||||
ListElement<TYPE>& operator= (const ListElement<TYPE>&);
|
||||
|
||||
ListElement<TYPE>* GetLast ()
|
||||
{
|
||||
ListElement<TYPE>* tmp = this;
|
||||
while (tmp->GetNext()) {
|
||||
tmp = tmp->GetNext();
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
ListElement<TYPE>* GetNext () const { return next ; }
|
||||
ListElement<TYPE>* GetPrev () const { return prev ; }
|
||||
|
||||
inline TYPE& GetData () { return data ; }
|
||||
inline const TYPE& GetData () const { return data ; }
|
||||
|
||||
void SetData ( const TYPE& d ) { data = d ; } // Quagmire - this may look like a mem leak, but dont change it, this behavior is expected where it's called
|
||||
void SetLastNext ( ListElement<TYPE>* p )
|
||||
{
|
||||
GetLast()->SetNext(p);
|
||||
}
|
||||
void SetNext (ListElement<TYPE>* n) { next = n ; }
|
||||
void SetPrev (ListElement<TYPE>* p) { prev = p ; }
|
||||
|
||||
void ReplaceData(const TYPE&);
|
||||
};
|
||||
|
||||
template<class TYPE>
|
||||
class LinkedList
|
||||
{
|
||||
private:
|
||||
int32 count;
|
||||
ListElement<TYPE>* first;
|
||||
bool list_destructor_invoked;
|
||||
|
||||
public:
|
||||
|
||||
LinkedList();
|
||||
~LinkedList();
|
||||
bool dont_delete;
|
||||
LinkedList<TYPE>& operator= (const LinkedList<TYPE>&);
|
||||
|
||||
void Append (const TYPE&);
|
||||
void Insert (const TYPE&);
|
||||
TYPE Pop();
|
||||
TYPE PeekTop();
|
||||
void Clear();
|
||||
void LCount() { count--; }
|
||||
void ResetCount() { count=0; }
|
||||
int32 Count() { return count; }
|
||||
friend class LinkedListIterator<TYPE>;
|
||||
};
|
||||
|
||||
template<class TYPE>
|
||||
class LinkedListIterator
|
||||
{
|
||||
private:
|
||||
LinkedList<TYPE>& list;
|
||||
ListElement<TYPE>* current_element;
|
||||
direction dir;
|
||||
|
||||
public:
|
||||
LinkedListIterator(LinkedList<TYPE>& l,direction d = FORWARD) : list(l), dir(d) {};
|
||||
|
||||
void Advance();
|
||||
const TYPE& GetData();
|
||||
bool IsFirst()
|
||||
{
|
||||
if (current_element->GetPrev() == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
bool IsLast()
|
||||
{
|
||||
if (current_element->GetNext() == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
bool MoreElements();
|
||||
void MoveFirst();
|
||||
void MoveLast();
|
||||
void RemoveCurrent(bool DeleteData = true);
|
||||
void Replace(const TYPE& new_data);
|
||||
void Reset();
|
||||
void SetDir(direction);
|
||||
};
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedListIterator<TYPE>::Advance()
|
||||
{
|
||||
if (current_element == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (dir == FORWARD)
|
||||
{
|
||||
current_element = current_element->GetNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
current_element = current_element->GetPrev();
|
||||
}
|
||||
|
||||
if (list.list_destructor_invoked)
|
||||
{
|
||||
while(current_element && current_element->GetData() == 0)
|
||||
{
|
||||
// if (current_element == 0)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
if (dir == FORWARD)
|
||||
{
|
||||
current_element = current_element->GetNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
current_element = current_element->GetPrev();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
bool LinkedListIterator<TYPE>::MoreElements()
|
||||
{
|
||||
if (current_element == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
const TYPE& LinkedListIterator<TYPE>::GetData()
|
||||
{
|
||||
return current_element->GetData();
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedListIterator<TYPE>::MoveFirst()
|
||||
{
|
||||
ListElement<TYPE>* prev = current_element->GetPrev();
|
||||
ListElement<TYPE>* next = current_element->GetNext();
|
||||
|
||||
if (prev == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if (prev != 0)
|
||||
// {
|
||||
prev->SetNext(next);
|
||||
// }
|
||||
if (next != 0)
|
||||
{
|
||||
next->SetPrev(prev);
|
||||
}
|
||||
current_element->SetPrev(0);
|
||||
current_element->SetNext(list.first);
|
||||
list.first->SetPrev(current_element);
|
||||
list.first = current_element;
|
||||
}
|
||||
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedListIterator<TYPE>::MoveLast()
|
||||
{
|
||||
ListElement<TYPE>* prev = current_element->GetPrev();
|
||||
ListElement<TYPE>* next = current_element->GetNext();
|
||||
|
||||
if (next == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (prev != 0)
|
||||
{
|
||||
prev->SetNext(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.first = next;
|
||||
}
|
||||
// if (next != 0)
|
||||
// {
|
||||
next->SetPrev(prev);
|
||||
// }
|
||||
current_element->SetNext(0);
|
||||
current_element->SetPrev(next->GetLast());
|
||||
next->GetLast()->SetNext(current_element);
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedListIterator<TYPE>::RemoveCurrent(bool DeleteData)
|
||||
{
|
||||
ListElement<TYPE>* save;
|
||||
|
||||
if (list.first == current_element)
|
||||
{
|
||||
list.first = current_element->GetNext();
|
||||
}
|
||||
|
||||
if (current_element->GetPrev() != 0)
|
||||
{
|
||||
current_element->GetPrev()->SetNext(current_element->GetNext());
|
||||
}
|
||||
if (current_element->GetNext() != 0)
|
||||
{
|
||||
current_element->GetNext()->SetPrev(current_element->GetPrev());
|
||||
}
|
||||
if (dir == FORWARD)
|
||||
{
|
||||
save = current_element->GetNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
save = current_element->GetPrev();
|
||||
}
|
||||
current_element->SetNext(0);
|
||||
current_element->SetPrev(0);
|
||||
if (!DeleteData)
|
||||
current_element->SetData(0);
|
||||
safe_delete(current_element);
|
||||
current_element = save;
|
||||
list.LCount();
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedListIterator<TYPE>::Replace(const TYPE& new_data)
|
||||
{
|
||||
current_element->ReplaceData(new_data);
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedListIterator<TYPE>::Reset()
|
||||
{
|
||||
if (!(&list))
|
||||
{
|
||||
current_element=0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dir == FORWARD)
|
||||
{
|
||||
current_element = list.first;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (list.first == 0)
|
||||
{
|
||||
current_element = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_element = list.first->GetLast();
|
||||
}
|
||||
}
|
||||
|
||||
if (list.list_destructor_invoked)
|
||||
{
|
||||
while(current_element && current_element->GetData() == 0)
|
||||
{
|
||||
// if (current_element == 0)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
if (dir == FORWARD)
|
||||
{
|
||||
current_element = current_element->GetNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
current_element = current_element->GetPrev();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedListIterator<TYPE>::SetDir(direction d)
|
||||
{
|
||||
dir = d;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
ListElement<TYPE>::ListElement(const TYPE& d)
|
||||
{
|
||||
data = d;
|
||||
next = 0;
|
||||
prev = 0;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
ListElement<TYPE>::~ListElement()
|
||||
{
|
||||
// cout << "ListElement<TYPE>::~ListElement()" << endl;
|
||||
|
||||
if (data != 0)
|
||||
safe_delete(data);
|
||||
data = 0;
|
||||
if (next != 0)
|
||||
{
|
||||
safe_delete(next);
|
||||
next = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void ListElement<TYPE>::ReplaceData(const TYPE& new_data)
|
||||
{
|
||||
if (data != 0)
|
||||
safe_delete(data);
|
||||
data = new_data;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
LinkedList<TYPE>::LinkedList()
|
||||
{
|
||||
list_destructor_invoked = false;
|
||||
first = 0;
|
||||
count = 0;
|
||||
dont_delete = false;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
LinkedList<TYPE>::~LinkedList()
|
||||
{
|
||||
list_destructor_invoked = true;
|
||||
if(!dont_delete)
|
||||
Clear();
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedList<TYPE>::Clear() {
|
||||
while (first) {
|
||||
ListElement<TYPE>* tmp = first;
|
||||
first = tmp->GetNext();
|
||||
tmp->SetNext(0);
|
||||
safe_delete(tmp);
|
||||
}
|
||||
ResetCount();
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedList<TYPE>::Append(const TYPE& data)
|
||||
{
|
||||
ListElement<TYPE>* new_element = new ListElement<TYPE>(data);
|
||||
|
||||
if (first == 0)
|
||||
{
|
||||
first = new_element;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_element->SetPrev(first->GetLast());
|
||||
first->SetLastNext(new_element);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
void LinkedList<TYPE>::Insert(const TYPE& data)
|
||||
{
|
||||
ListElement<TYPE>* new_element = new ListElement<TYPE>(data);
|
||||
|
||||
new_element->SetNext(first);
|
||||
if (first != 0)
|
||||
{
|
||||
first->SetPrev(new_element);
|
||||
}
|
||||
first = new_element;
|
||||
count++;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
TYPE LinkedList<TYPE>::Pop() {
|
||||
TYPE ret = 0;
|
||||
if (first) {
|
||||
ListElement<TYPE>* tmpdel = first;
|
||||
first = tmpdel->GetNext();
|
||||
if (first)
|
||||
first->SetPrev(0);
|
||||
ret = tmpdel->GetData();
|
||||
tmpdel->SetData(0);
|
||||
tmpdel->SetNext(0);
|
||||
safe_delete(tmpdel);
|
||||
count--;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class TYPE>
|
||||
TYPE LinkedList<TYPE>::PeekTop() {
|
||||
if (first)
|
||||
return first->GetData();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,281 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <string.h> /* for memcpy() */
|
||||
#include "../common/md5.h"
|
||||
#include "../common/MiscFunctions.h"
|
||||
#include "../common/seperator.h"
|
||||
|
||||
MD5::MD5() {
|
||||
memset(pMD5, 0, 16);
|
||||
}
|
||||
|
||||
MD5::MD5(const uchar* buf, uint32 len) {
|
||||
Generate(buf, len, pMD5);
|
||||
}
|
||||
|
||||
MD5::MD5(const char* buf, uint32 len) {
|
||||
Generate((const uchar*) buf, len, pMD5);
|
||||
}
|
||||
|
||||
MD5::MD5(const int8 buf[16]) {
|
||||
Set(buf);
|
||||
}
|
||||
|
||||
MD5::MD5(const char* iMD5String) {
|
||||
Set(iMD5String);
|
||||
}
|
||||
|
||||
void MD5::Generate(const char* iString) {
|
||||
Generate((const uchar*) iString, strlen(iString));
|
||||
}
|
||||
|
||||
void MD5::Generate(const int8* buf, uint32 len) {
|
||||
Generate(buf, len, pMD5);
|
||||
}
|
||||
|
||||
bool MD5::Set(const int8 buf[16]) {
|
||||
memcpy(pMD5, buf, 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MD5::Set(const char* iMD5String) {
|
||||
char tmp[5] = { '0', 'x', 0, 0, 0 };
|
||||
for (int i=0; i<16; i++) {
|
||||
tmp[2] = iMD5String[i*2];
|
||||
tmp[3] = iMD5String[(i*2) + 1];
|
||||
if (!Seperator::IsHexNumber(tmp))
|
||||
return false;
|
||||
pMD5[i] = hextoi(tmp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MD5::operator const char* () {
|
||||
snprintf(pMD5String, sizeof(pMD5String), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", pMD5[0], pMD5[1], pMD5[2], pMD5[3], pMD5[4], pMD5[5], pMD5[6], pMD5[7], pMD5[8], pMD5[9], pMD5[10], pMD5[11], pMD5[12], pMD5[13], pMD5[14], pMD5[15]);
|
||||
return pMD5String;
|
||||
}
|
||||
|
||||
bool MD5::operator== (const MD5& iMD5) {
|
||||
if (memcmp(pMD5, iMD5.pMD5, 16) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MD5::operator== (const int8* iMD5) {
|
||||
if (memcmp(pMD5, iMD5, 16) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MD5::operator== (const char* iMD5String) {
|
||||
char tmp[5] = { '0', 'x', 0, 0, 0 };
|
||||
for (int i=0; i<16; i++) {
|
||||
tmp[2] = iMD5String[i*2];
|
||||
tmp[3] = iMD5String[(i*2) + 1];
|
||||
if (pMD5[i] != hextoi(tmp))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MD5& MD5::operator= (const MD5& iMD5) {
|
||||
memcpy(pMD5, iMD5.pMD5, 16);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MD5* MD5::operator= (const MD5* iMD5) {
|
||||
memcpy(pMD5, iMD5->pMD5, 16);
|
||||
return this;
|
||||
}
|
||||
|
||||
/* Byte-swap an array of words to little-endian. (Byte-sex independent) */
|
||||
void MD5::byteSwap(uint32 *buf, uint32 words) {
|
||||
int8 *p = (int8 *)buf;
|
||||
do {
|
||||
*buf++ = (uint32)((uint32)p[3]<<8 | p[2]) << 16 |
|
||||
((uint32)p[1]<<8 | p[0]);
|
||||
p += 4;
|
||||
} while (--words);
|
||||
}
|
||||
|
||||
void MD5::Generate(const int8* buf, uint32 len, int8 digest[16]) {
|
||||
MD5Context ctx;
|
||||
Init(&ctx);
|
||||
Update(&ctx, buf, len);
|
||||
Final(digest, &ctx);
|
||||
}
|
||||
|
||||
/* Start MD5 accumulation. */
|
||||
void MD5::Init(struct MD5Context *ctx) {
|
||||
ctx->hash[0] = 0x67452301;
|
||||
ctx->hash[1] = 0xefcdab89;
|
||||
ctx->hash[2] = 0x98badcfe;
|
||||
ctx->hash[3] = 0x10325476;
|
||||
ctx->bytes[1] = ctx->bytes[0] = 0;
|
||||
}
|
||||
|
||||
/* Update ctx to reflect the addition of another buffer full of bytes. */
|
||||
void MD5::Update(struct MD5Context *ctx, int8 const *buf, uint32 len) {
|
||||
uint32 t = ctx->bytes[0];
|
||||
if ((ctx->bytes[0] = t + len) < t) /* Update 64-bit byte count */
|
||||
ctx->bytes[1]++; /* Carry from low to high */
|
||||
|
||||
|
||||
|
||||
t = 64 - (t & 0x3f); /* Bytes available in ctx->input (>= 1) */
|
||||
if (t > len) {
|
||||
memcpy((int8*)ctx->input+64-t, buf, len);
|
||||
return;
|
||||
}
|
||||
/* First chunk is an odd size */
|
||||
memcpy((int8*)ctx->input+64-t, buf, t);
|
||||
byteSwap(ctx->input, 16);
|
||||
Transform(ctx->hash, ctx->input);
|
||||
buf += t;
|
||||
len -= t;
|
||||
/* Process data in 64-byte chunks */
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->input, buf, 64);
|
||||
byteSwap(ctx->input, 16);
|
||||
Transform(ctx->hash, ctx->input);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
/* Buffer any remaining bytes of data */
|
||||
memcpy(ctx->input, buf, len);
|
||||
}
|
||||
|
||||
/* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, LSB-first) */
|
||||
void MD5::Final(int8 digest[16], MD5Context *ctx) {
|
||||
int count = ctx->bytes[0] & 0x3F; /* Bytes mod 64 */
|
||||
int8 *p = (int8*)ctx->input + count;
|
||||
/* Set the first byte of padding to 0x80. There is always room. */
|
||||
*p++ = 0x80;
|
||||
/* Bytes of zero padding needed to make 56 bytes (-8..55) */
|
||||
count = 56 - 1 - count;
|
||||
if (count < 0) { /* Padding forces an extra block */
|
||||
memset(p, 0, count+8);
|
||||
byteSwap(ctx->input, 16);
|
||||
Transform(ctx->hash, ctx->input);
|
||||
p = (int8*)ctx->input;
|
||||
count = 56;
|
||||
}
|
||||
memset(p, 0, count);
|
||||
byteSwap(ctx->input, 14);
|
||||
/* Append 8 bytes of length in *bits* and transform */
|
||||
ctx->input[14] = ctx->bytes[0] << 3;
|
||||
|
||||
ctx->input[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
|
||||
Transform(ctx->hash, ctx->input);
|
||||
byteSwap(ctx->hash, 4);
|
||||
memcpy(digest, ctx->hash, 16);
|
||||
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
/* The four core functions */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f,w,x,y,z,in,s) (w += f(x,y,z)+in, w = (w<<s | w>>(32-s)) + x)
|
||||
|
||||
|
||||
|
||||
/* The heart of the MD5 algorithm. */
|
||||
void MD5::Transform(uint32 hash[4], const uint32 input[16]) {
|
||||
uint32 a = hash[0], b = hash[1], c = hash[2], d = hash[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, input[ 0]+0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, input[ 1]+0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, input[ 2]+0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, input[ 3]+0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, input[ 4]+0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, input[ 5]+0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, input[ 6]+0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, input[ 7]+0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, input[ 8]+0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, input[ 9]+0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, input[10]+0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, input[11]+0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, input[12]+0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, input[13]+0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, input[14]+0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, input[15]+0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, input[ 1]+0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, input[ 6]+0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, input[11]+0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, input[ 0]+0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, input[ 5]+0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, input[10]+0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, input[15]+0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, input[ 4]+0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, input[ 9]+0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, input[14]+0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, input[ 3]+0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, input[ 8]+0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, input[13]+0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, input[ 2]+0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, input[ 7]+0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, input[12]+0x8d2a4c8a, 20);
|
||||
|
||||
|
||||
|
||||
|
||||
MD5STEP(F3, a, b, c, d, input[ 5]+0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, input[ 8]+0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, input[11]+0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, input[14]+0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, input[ 1]+0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, input[ 4]+0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, input[ 7]+0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, input[10]+0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, input[13]+0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, input[ 0]+0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, input[ 3]+0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, input[ 6]+0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, input[ 9]+0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, input[12]+0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, input[15]+0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, input[ 2]+0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, input[ 0]+0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, input[ 7]+0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, input[14]+0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, input[ 5]+0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, input[12]+0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, input[ 3]+0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, input[10]+0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, input[ 1]+0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, input[ 8]+0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, input[15]+0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, input[ 6]+0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, input[13]+0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, input[ 4]+0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, input[11]+0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, input[ 2]+0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, input[ 9]+0xeb86d391, 21);
|
||||
|
||||
hash[0] += a; hash[1] += b; hash[2] += c; hash[3] += d;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
#include "../common/types.h"
|
||||
|
||||
|
||||
class MD5 {
|
||||
public:
|
||||
struct MD5Context {
|
||||
uint32 hash[4];
|
||||
uint32 bytes[2];
|
||||
uint32 input[16];
|
||||
};
|
||||
static void Generate(const int8* buf, uint32 len, int8 digest[16]);
|
||||
|
||||
static void Init(struct MD5Context *context);
|
||||
static void Update(struct MD5Context *context, const int8 *buf, uint32 len);
|
||||
static void Final(int8 digest[16], struct MD5Context *context);
|
||||
|
||||
MD5();
|
||||
MD5(const uchar* buf, uint32 len);
|
||||
MD5(const char* buf, uint32 len);
|
||||
MD5(const int8 buf[16]);
|
||||
MD5(const char* iMD5String);
|
||||
|
||||
void Generate(const char* iString);
|
||||
void Generate(const int8* buf, uint32 len);
|
||||
bool Set(const int8 buf[16]);
|
||||
bool Set(const char* iMD5String);
|
||||
|
||||
bool operator== (const MD5& iMD5);
|
||||
bool operator== (const int8 iMD5[16]);
|
||||
bool operator== (const char* iMD5String);
|
||||
|
||||
MD5& operator= (const MD5& iMD5);
|
||||
MD5* operator= (const MD5* iMD5);
|
||||
MD5* operator= (const int8* iMD5);
|
||||
operator const char* ();
|
||||
protected:
|
||||
int8 pMD5[16];
|
||||
private:
|
||||
static void byteSwap(uint32 *buf, uint32 words);
|
||||
static void Transform(uint32 hash[4], const int32 input[16]);
|
||||
char pMD5String[33];
|
||||
};
|
||||
#endif
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
template<class T>
|
||||
class MyQueue;
|
||||
|
||||
template<class T>
|
||||
class MyQueueNode
|
||||
{
|
||||
public:
|
||||
MyQueueNode(T* data)
|
||||
{
|
||||
next = 0;
|
||||
this->data = data;
|
||||
}
|
||||
|
||||
friend class MyQueue<T>;
|
||||
|
||||
private:
|
||||
T* data;
|
||||
MyQueueNode<T>* next;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class MyQueue
|
||||
{
|
||||
public:
|
||||
MyQueue()
|
||||
{
|
||||
head = tail = 0;
|
||||
}
|
||||
~MyQueue() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void push(T* data)
|
||||
{
|
||||
if (head == 0)
|
||||
{
|
||||
tail = head = new MyQueueNode<T>(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->next = new MyQueueNode<T>(data);
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
T* pop()
|
||||
{
|
||||
if (head == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
T* data = head->data;
|
||||
MyQueueNode<T>* next_node = head->next;
|
||||
delete head;
|
||||
head = next_node;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
T* top()
|
||||
{
|
||||
if (head == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return head->data;
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
if (head == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
T* d = 0;
|
||||
while((d = pop())) {
|
||||
delete d;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int count()
|
||||
{
|
||||
int count = 0;
|
||||
MyQueueNode<T>* d = head;
|
||||
while(d != 0) {
|
||||
count++;
|
||||
d = d->next;
|
||||
}
|
||||
return(count);
|
||||
}
|
||||
|
||||
private:
|
||||
MyQueueNode<T>* head;
|
||||
MyQueueNode<T>* tail;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,155 +0,0 @@
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include "sha512.h"
|
||||
|
||||
const unsigned long long SHA512::sha512_k[80] = //ULL = uint64
|
||||
{0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
|
||||
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
|
||||
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
|
||||
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
|
||||
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
|
||||
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
|
||||
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
|
||||
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
|
||||
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
|
||||
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
|
||||
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
|
||||
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
|
||||
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
|
||||
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
|
||||
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
|
||||
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
|
||||
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
|
||||
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
|
||||
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
|
||||
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
|
||||
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
|
||||
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
|
||||
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
|
||||
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
|
||||
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
|
||||
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
|
||||
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
|
||||
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
|
||||
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
|
||||
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
|
||||
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
|
||||
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
|
||||
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
|
||||
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
|
||||
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
|
||||
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
|
||||
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
|
||||
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
|
||||
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
|
||||
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
|
||||
|
||||
void SHA512::transform(const unsigned char *message, unsigned int block_nb)
|
||||
{
|
||||
uint64 w[80];
|
||||
uint64 wv[8];
|
||||
uint64 t1, t2;
|
||||
const unsigned char *sub_block;
|
||||
int i, j;
|
||||
for (i = 0; i < (int) block_nb; i++) {
|
||||
sub_block = message + (i << 7);
|
||||
for (j = 0; j < 16; j++) {
|
||||
SHA2_PACK64(&sub_block[j << 3], &w[j]);
|
||||
}
|
||||
for (j = 16; j < 80; j++) {
|
||||
w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16];
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
wv[j] = m_h[j];
|
||||
}
|
||||
for (j = 0; j < 80; j++) {
|
||||
t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6])
|
||||
+ sha512_k[j] + w[j];
|
||||
t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]);
|
||||
wv[7] = wv[6];
|
||||
wv[6] = wv[5];
|
||||
wv[5] = wv[4];
|
||||
wv[4] = wv[3] + t1;
|
||||
wv[3] = wv[2];
|
||||
wv[2] = wv[1];
|
||||
wv[1] = wv[0];
|
||||
wv[0] = t1 + t2;
|
||||
}
|
||||
for (j = 0; j < 8; j++) {
|
||||
m_h[j] += wv[j];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SHA512::init()
|
||||
{
|
||||
m_h[0] = 0x6a09e667f3bcc908ULL;
|
||||
m_h[1] = 0xbb67ae8584caa73bULL;
|
||||
m_h[2] = 0x3c6ef372fe94f82bULL;
|
||||
m_h[3] = 0xa54ff53a5f1d36f1ULL;
|
||||
m_h[4] = 0x510e527fade682d1ULL;
|
||||
m_h[5] = 0x9b05688c2b3e6c1fULL;
|
||||
m_h[6] = 0x1f83d9abfb41bd6bULL;
|
||||
m_h[7] = 0x5be0cd19137e2179ULL;
|
||||
m_len = 0;
|
||||
m_tot_len = 0;
|
||||
}
|
||||
|
||||
void SHA512::update(const unsigned char *message, unsigned int len)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int new_len, rem_len, tmp_len;
|
||||
const unsigned char *shifted_message;
|
||||
tmp_len = SHA384_512_BLOCK_SIZE - m_len;
|
||||
rem_len = len < tmp_len ? len : tmp_len;
|
||||
memcpy(&m_block[m_len], message, rem_len);
|
||||
if (m_len + len < SHA384_512_BLOCK_SIZE) {
|
||||
m_len += len;
|
||||
return;
|
||||
}
|
||||
new_len = len - rem_len;
|
||||
block_nb = new_len / SHA384_512_BLOCK_SIZE;
|
||||
shifted_message = message + rem_len;
|
||||
transform(m_block, 1);
|
||||
transform(shifted_message, block_nb);
|
||||
rem_len = new_len % SHA384_512_BLOCK_SIZE;
|
||||
memcpy(m_block, &shifted_message[block_nb << 7], rem_len);
|
||||
m_len = rem_len;
|
||||
m_tot_len += (block_nb + 1) << 7;
|
||||
}
|
||||
|
||||
void SHA512::final(unsigned char *digest)
|
||||
{
|
||||
unsigned int block_nb;
|
||||
unsigned int pm_len;
|
||||
unsigned int len_b;
|
||||
int i;
|
||||
block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17)
|
||||
< (m_len % SHA384_512_BLOCK_SIZE));
|
||||
len_b = (m_tot_len + m_len) << 3;
|
||||
pm_len = block_nb << 7;
|
||||
memset(m_block + m_len, 0, pm_len - m_len);
|
||||
m_block[m_len] = 0x80;
|
||||
SHA2_UNPACK32(len_b, m_block + pm_len - 4);
|
||||
transform(m_block, block_nb);
|
||||
for (i = 0 ; i < 8; i++) {
|
||||
SHA2_UNPACK64(m_h[i], &digest[i << 3]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string sha512(std::string input)
|
||||
{
|
||||
unsigned char digest[SHA512::DIGEST_SIZE];
|
||||
memset(digest,0,SHA512::DIGEST_SIZE);
|
||||
SHA512 ctx = SHA512();
|
||||
ctx.init();
|
||||
ctx.update((unsigned char*)input.c_str(), input.length());
|
||||
ctx.final(digest);
|
||||
|
||||
char buf[2*SHA512::DIGEST_SIZE+1];
|
||||
buf[2*SHA512::DIGEST_SIZE] = 0;
|
||||
for (int i = 0; i < SHA512::DIGEST_SIZE; i++)
|
||||
sprintf(buf+i*2, "%02x", digest[i]);
|
||||
return std::string(buf);
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#ifndef SHA512_H
|
||||
#define SHA512_H
|
||||
#include <string>
|
||||
|
||||
class SHA512
|
||||
{
|
||||
protected:
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned long long uint64;
|
||||
|
||||
const static uint64 sha512_k[];
|
||||
static const unsigned int SHA384_512_BLOCK_SIZE = (1024/8);
|
||||
|
||||
public:
|
||||
void init();
|
||||
void update(const unsigned char *message, unsigned int len);
|
||||
void final(unsigned char *digest);
|
||||
static const unsigned int DIGEST_SIZE = ( 512 / 8);
|
||||
|
||||
protected:
|
||||
void transform(const unsigned char *message, unsigned int block_nb);
|
||||
unsigned int m_tot_len;
|
||||
unsigned int m_len;
|
||||
unsigned char m_block[2 * SHA384_512_BLOCK_SIZE];
|
||||
uint64 m_h[8];
|
||||
};
|
||||
|
||||
|
||||
std::string sha512(std::string input);
|
||||
|
||||
#define SHA2_SHFR(x, n) (x >> n)
|
||||
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
|
||||
#define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
|
||||
#define SHA2_CH(x, y, z) ((x & y) ^ (~x & z))
|
||||
#define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
|
||||
#define SHA512_F1(x) (SHA2_ROTR(x, 28) ^ SHA2_ROTR(x, 34) ^ SHA2_ROTR(x, 39))
|
||||
#define SHA512_F2(x) (SHA2_ROTR(x, 14) ^ SHA2_ROTR(x, 18) ^ SHA2_ROTR(x, 41))
|
||||
#define SHA512_F3(x) (SHA2_ROTR(x, 1) ^ SHA2_ROTR(x, 8) ^ SHA2_SHFR(x, 7))
|
||||
#define SHA512_F4(x) (SHA2_ROTR(x, 19) ^ SHA2_ROTR(x, 61) ^ SHA2_SHFR(x, 6))
|
||||
#define SHA2_UNPACK32(x, str) \
|
||||
{ \
|
||||
*((str) + 3) = (uint8) ((x) ); \
|
||||
*((str) + 2) = (uint8) ((x) >> 8); \
|
||||
*((str) + 1) = (uint8) ((x) >> 16); \
|
||||
*((str) + 0) = (uint8) ((x) >> 24); \
|
||||
}
|
||||
#define SHA2_UNPACK64(x, str) \
|
||||
{ \
|
||||
*((str) + 7) = (uint8) ((x) ); \
|
||||
*((str) + 6) = (uint8) ((x) >> 8); \
|
||||
*((str) + 5) = (uint8) ((x) >> 16); \
|
||||
*((str) + 4) = (uint8) ((x) >> 24); \
|
||||
*((str) + 3) = (uint8) ((x) >> 32); \
|
||||
*((str) + 2) = (uint8) ((x) >> 40); \
|
||||
*((str) + 1) = (uint8) ((x) >> 48); \
|
||||
*((str) + 0) = (uint8) ((x) >> 56); \
|
||||
}
|
||||
#define SHA2_PACK64(str, x) \
|
||||
{ \
|
||||
*(x) = ((uint64) *((str) + 7) ) \
|
||||
| ((uint64) *((str) + 6) << 8) \
|
||||
| ((uint64) *((str) + 5) << 16) \
|
||||
| ((uint64) *((str) + 4) << 24) \
|
||||
| ((uint64) *((str) + 3) << 32) \
|
||||
| ((uint64) *((str) + 2) << 40) \
|
||||
| ((uint64) *((str) + 1) << 48) \
|
||||
| ((uint64) *((str) + 0) << 56); \
|
||||
}
|
||||
|
||||
#endif
|
@ -1,529 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "string_util.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <windows.h>
|
||||
|
||||
#define snprintf _snprintf
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#endif
|
||||
|
||||
// original source:
|
||||
// https://github.com/facebook/folly/blob/master/folly/String.cpp
|
||||
//
|
||||
const std::string vStringFormat(const char* format, va_list args)
|
||||
{
|
||||
std::string output;
|
||||
va_list tmpargs;
|
||||
|
||||
va_copy(tmpargs,args);
|
||||
int characters_used = vsnprintf(nullptr, 0, format, tmpargs);
|
||||
va_end(tmpargs);
|
||||
|
||||
// Looks like we have a valid format string.
|
||||
if (characters_used > 0) {
|
||||
output.resize(characters_used + 1);
|
||||
|
||||
va_copy(tmpargs,args);
|
||||
characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs);
|
||||
va_end(tmpargs);
|
||||
|
||||
output.resize(characters_used);
|
||||
|
||||
// We shouldn't have a format error by this point, but I can't imagine what error we
|
||||
// could have by this point. Still, return empty string;
|
||||
if (characters_used < 0)
|
||||
output.clear();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
const std::string str_tolower(std::string s)
|
||||
{
|
||||
std::transform(
|
||||
s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c) { return ::tolower(c); }
|
||||
);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string str_to_split, char delimiter)
|
||||
{
|
||||
std::stringstream ss(str_to_split);
|
||||
std::string item;
|
||||
std::vector<std::string> exploded_values;
|
||||
while (std::getline(ss, item, delimiter)) {
|
||||
exploded_values.push_back(item);
|
||||
}
|
||||
|
||||
return exploded_values;
|
||||
}
|
||||
|
||||
const std::string str_toupper(std::string s)
|
||||
{
|
||||
std::transform(
|
||||
s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c) { return ::toupper(c); }
|
||||
);
|
||||
return s;
|
||||
}
|
||||
|
||||
const std::string ucfirst(std::string s)
|
||||
{
|
||||
std::string output = s;
|
||||
if (!s.empty())
|
||||
output[0] = static_cast<char>(::toupper(s[0]));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
const std::string StringFormat(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
std::string output = vStringFormat(format, args);
|
||||
va_end(args);
|
||||
return output;
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitString(const std::string &str, char delim) {
|
||||
std::vector<std::string> ret;
|
||||
std::stringstream ss(str);
|
||||
std::string item;
|
||||
|
||||
while(std::getline(ss, item, delim)) {
|
||||
ret.push_back(item);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string implode(std::string glue, std::vector<std::string> src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ostringstream output;
|
||||
std::vector<std::string>::iterator src_iter;
|
||||
|
||||
for (src_iter = src.begin(); src_iter != src.end(); src_iter++) {
|
||||
output << *src_iter << glue;
|
||||
}
|
||||
|
||||
std::string final_output = output.str();
|
||||
final_output.resize (output.str().size () - glue.size());
|
||||
|
||||
return final_output;
|
||||
}
|
||||
|
||||
std::string EscapeString(const std::string &s) {
|
||||
std::string ret;
|
||||
|
||||
size_t sz = s.length();
|
||||
for(size_t i = 0; i < sz; ++i) {
|
||||
char c = s[i];
|
||||
switch(c) {
|
||||
case '\x00':
|
||||
ret += "\\x00";
|
||||
break;
|
||||
case '\n':
|
||||
ret += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
ret += "\\r";
|
||||
break;
|
||||
case '\\':
|
||||
ret += "\\\\";
|
||||
break;
|
||||
case '\'':
|
||||
ret += "\\'";
|
||||
break;
|
||||
case '\"':
|
||||
ret += "\\\"";
|
||||
break;
|
||||
case '\x1a':
|
||||
ret += "\\x1a";
|
||||
break;
|
||||
default:
|
||||
ret.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string EscapeString(const char *src, size_t sz) {
|
||||
std::string ret;
|
||||
|
||||
for(size_t i = 0; i < sz; ++i) {
|
||||
char c = src[i];
|
||||
switch(c) {
|
||||
case '\x00':
|
||||
ret += "\\x00";
|
||||
break;
|
||||
case '\n':
|
||||
ret += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
ret += "\\r";
|
||||
break;
|
||||
case '\\':
|
||||
ret += "\\\\";
|
||||
break;
|
||||
case '\'':
|
||||
ret += "\\'";
|
||||
break;
|
||||
case '\"':
|
||||
ret += "\\\"";
|
||||
break;
|
||||
case '\x1a':
|
||||
ret += "\\x1a";
|
||||
break;
|
||||
default:
|
||||
ret.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool StringIsNumber(const std::string &s) {
|
||||
try {
|
||||
auto r = stod(s);
|
||||
return true;
|
||||
}
|
||||
catch (std::exception &) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ToLowerString(std::string &s) {
|
||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||
}
|
||||
|
||||
void ToUpperString(std::string &s) {
|
||||
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
|
||||
}
|
||||
|
||||
std::string JoinString(const std::vector<std::string>& ar, const std::string &delim) {
|
||||
std::string ret;
|
||||
for (size_t i = 0; i < ar.size(); ++i) {
|
||||
if (i != 0) {
|
||||
ret += delim;
|
||||
}
|
||||
|
||||
ret += ar[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void find_replace(std::string &string_subject, const std::string &search_string, const std::string &replace_string)
|
||||
{
|
||||
if (string_subject.find(search_string) == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t start_pos = 0;
|
||||
while((start_pos = string_subject.find(search_string, start_pos)) != std::string::npos) {
|
||||
string_subject.replace(start_pos, search_string.length(), replace_string);
|
||||
start_pos += replace_string.length();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver)
|
||||
{
|
||||
auto split = SplitString(s, ':');
|
||||
if (split.size() == 2) {
|
||||
loginserver = split[0];
|
||||
account = split[1];
|
||||
}
|
||||
else if(split.size() == 1) {
|
||||
account = split[0];
|
||||
}
|
||||
}
|
||||
|
||||
//Const char based
|
||||
|
||||
// normal strncpy doesnt put a null term on copied strings, this one does
|
||||
// ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp
|
||||
char* strn0cpy(char* dest, const char* source, uint32 size) {
|
||||
if (!dest)
|
||||
return 0;
|
||||
if (size == 0 || source == 0) {
|
||||
dest[0] = 0;
|
||||
return dest;
|
||||
}
|
||||
strncpy(dest, source, size);
|
||||
dest[size - 1] = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
// String N w/null Copy Truncated?
|
||||
// return value =true if entire string(source) fit, false if it was truncated
|
||||
bool strn0cpyt(char* dest, const char* source, uint32 size) {
|
||||
if (!dest)
|
||||
return 0;
|
||||
if (size == 0 || source == 0) {
|
||||
dest[0] = 0;
|
||||
return false;
|
||||
}
|
||||
strncpy(dest, source, size);
|
||||
dest[size - 1] = 0;
|
||||
return (bool)(source[strlen(dest)] == 0);
|
||||
}
|
||||
|
||||
const char *MakeLowerString(const char *source) {
|
||||
static char str[128];
|
||||
if (!source)
|
||||
return nullptr;
|
||||
MakeLowerString(source, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
void MakeLowerString(const char *source, char *target) {
|
||||
if (!source || !target) {
|
||||
*target = 0;
|
||||
return;
|
||||
}
|
||||
while (*source)
|
||||
{
|
||||
*target = tolower(*source);
|
||||
target++; source++;
|
||||
}
|
||||
*target = 0;
|
||||
}
|
||||
|
||||
int MakeAnyLenString(char** ret, const char* format, ...) {
|
||||
int buf_len = 128;
|
||||
int chars = -1;
|
||||
va_list argptr, tmpargptr;
|
||||
va_start(argptr, format);
|
||||
while (chars == -1 || chars >= buf_len) {
|
||||
safe_delete_array(*ret);
|
||||
if (chars == -1)
|
||||
buf_len *= 2;
|
||||
else
|
||||
buf_len = chars + 1;
|
||||
*ret = new char[buf_len];
|
||||
va_copy(tmpargptr, argptr);
|
||||
chars = vsnprintf(*ret, buf_len, format, tmpargptr);
|
||||
}
|
||||
va_end(argptr);
|
||||
return chars;
|
||||
}
|
||||
|
||||
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...) {
|
||||
if (*bufsize == 0)
|
||||
*bufsize = 256;
|
||||
if (*ret == 0)
|
||||
*strlen = 0;
|
||||
int chars = -1;
|
||||
char* oldret = 0;
|
||||
va_list argptr, tmpargptr;
|
||||
va_start(argptr, format);
|
||||
while (chars == -1 || chars >= (int32)(*bufsize - *strlen)) {
|
||||
if (chars == -1)
|
||||
*bufsize += 256;
|
||||
else
|
||||
*bufsize += chars + 25;
|
||||
oldret = *ret;
|
||||
*ret = new char[*bufsize];
|
||||
if (oldret) {
|
||||
if (*strlen)
|
||||
memcpy(*ret, oldret, *strlen);
|
||||
safe_delete_array(oldret);
|
||||
}
|
||||
va_copy(tmpargptr, argptr);
|
||||
chars = vsnprintf(&(*ret)[*strlen], (*bufsize - *strlen), format, tmpargptr);
|
||||
}
|
||||
va_end(argptr);
|
||||
*strlen += chars;
|
||||
return *strlen;
|
||||
}
|
||||
|
||||
uint32 hextoi(const char* num) {
|
||||
if (num == nullptr)
|
||||
return 0;
|
||||
|
||||
int len = strlen(num);
|
||||
if (len < 3)
|
||||
return 0;
|
||||
|
||||
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
|
||||
return 0;
|
||||
|
||||
uint32 ret = 0;
|
||||
int mul = 1;
|
||||
for (int i = len - 1; i >= 2; i--) {
|
||||
if (num[i] >= 'A' && num[i] <= 'F')
|
||||
ret += ((num[i] - 'A') + 10) * mul;
|
||||
else if (num[i] >= 'a' && num[i] <= 'f')
|
||||
ret += ((num[i] - 'a') + 10) * mul;
|
||||
else if (num[i] >= '0' && num[i] <= '9')
|
||||
ret += (num[i] - '0') * mul;
|
||||
else
|
||||
return 0;
|
||||
mul *= 16;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64 hextoi64(const char* num) {
|
||||
if (num == nullptr)
|
||||
return 0;
|
||||
|
||||
int len = strlen(num);
|
||||
if (len < 3)
|
||||
return 0;
|
||||
|
||||
if (num[0] != '0' || (num[1] != 'x' && num[1] != 'X'))
|
||||
return 0;
|
||||
|
||||
uint64 ret = 0;
|
||||
int mul = 1;
|
||||
for (int i = len - 1; i >= 2; i--) {
|
||||
if (num[i] >= 'A' && num[i] <= 'F')
|
||||
ret += ((num[i] - 'A') + 10) * mul;
|
||||
else if (num[i] >= 'a' && num[i] <= 'f')
|
||||
ret += ((num[i] - 'a') + 10) * mul;
|
||||
else if (num[i] >= '0' && num[i] <= '9')
|
||||
ret += (num[i] - '0') * mul;
|
||||
else
|
||||
return 0;
|
||||
mul *= 16;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool atobool(const char* iBool) {
|
||||
|
||||
if (iBool == nullptr)
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "true"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "false"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "yes"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "no"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "on"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "off"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "enable"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "disable"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "enabled"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "disabled"))
|
||||
return false;
|
||||
if (!strcasecmp(iBool, "y"))
|
||||
return true;
|
||||
if (!strcasecmp(iBool, "n"))
|
||||
return false;
|
||||
if (atoi(iBool))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// removes the crap and turns the underscores into spaces.
|
||||
char *CleanMobName(const char *in, char *out)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i = j = 0; i < strlen(in); i++)
|
||||
{
|
||||
// convert _ to space.. any other conversions like this? I *think* this
|
||||
// is the only non alpha char that's not stripped but converted.
|
||||
if (in[i] == '_')
|
||||
{
|
||||
out[j++] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isalpha(in[i]) || (in[i] == '`')) // numbers, #, or any other crap just gets skipped
|
||||
out[j++] = in[i];
|
||||
}
|
||||
}
|
||||
out[j] = 0; // terimnate the string before returning it
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void RemoveApostrophes(std::string &s)
|
||||
{
|
||||
for (unsigned int i = 0; i < s.length(); ++i)
|
||||
if (s[i] == '\'')
|
||||
s[i] = '_';
|
||||
}
|
||||
|
||||
char *RemoveApostrophes(const char *s)
|
||||
{
|
||||
auto NewString = new char[strlen(s) + 1];
|
||||
|
||||
strcpy(NewString, s);
|
||||
|
||||
for (unsigned int i = 0; i < strlen(NewString); ++i)
|
||||
if (NewString[i] == '\'')
|
||||
NewString[i] = '_';
|
||||
|
||||
return NewString;
|
||||
}
|
||||
|
||||
const char *ConvertArray(int input, char *returnchar)
|
||||
{
|
||||
sprintf(returnchar, "%i", input);
|
||||
return returnchar;
|
||||
}
|
||||
|
||||
const char *ConvertArrayF(float input, char *returnchar)
|
||||
{
|
||||
sprintf(returnchar, "%0.2f", input);
|
||||
return returnchar;
|
||||
}
|
||||
|
||||
bool isAlphaNumeric(const char *text)
|
||||
{
|
||||
for (unsigned int charIndex = 0; charIndex<strlen(text); charIndex++) {
|
||||
if ((text[charIndex] < 'a' || text[charIndex] > 'z') &&
|
||||
(text[charIndex] < 'A' || text[charIndex] > 'Z') &&
|
||||
(text[charIndex] < '0' || text[charIndex] > '9'))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _STRINGUTIL_H_
|
||||
#define _STRINGUTIL_H_
|
||||
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <cstdarg>
|
||||
#include <tuple>
|
||||
|
||||
#ifndef _WIN32
|
||||
// this doesn't appear to affect linux-based systems..need feedback for _WIN64
|
||||
#include <fmt/format.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <ctype.h>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
|
||||
//std::string based
|
||||
const std::string str_tolower(std::string s);
|
||||
const std::string str_toupper(std::string s);
|
||||
const std::string ucfirst(std::string s);
|
||||
std::vector<std::string> split(std::string str_to_split, char delimiter);
|
||||
const std::string StringFormat(const char* format, ...);
|
||||
const std::string vStringFormat(const char* format, va_list args);
|
||||
std::string implode(std::string glue, std::vector<std::string> src);
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @param chars
|
||||
* @return
|
||||
*/
|
||||
inline std::string <rim(std::string &str, const std::string &chars = "\t\n\v\f\r ")
|
||||
{
|
||||
str.erase(0, str.find_first_not_of(chars));
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @param chars
|
||||
* @return
|
||||
*/
|
||||
inline std::string &rtrim(std::string &str, const std::string &chars = "\t\n\v\f\r ")
|
||||
{
|
||||
str.erase(str.find_last_not_of(chars) + 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str
|
||||
* @param chars
|
||||
* @return
|
||||
*/
|
||||
inline std::string &trim(std::string &str, const std::string &chars = "\t\n\v\f\r ")
|
||||
{
|
||||
return ltrim(rtrim(str, chars), chars);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string implode(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<T> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
|
||||
for (const T &src_iter : src) {
|
||||
oss << encapsulation.first << src_iter << encapsulation.second << glue;
|
||||
}
|
||||
|
||||
std::string output(oss.str());
|
||||
output.resize(output.size() - glue.size());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
|
||||
template <typename T1, typename T2>
|
||||
std::vector<std::string> join_pair(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::pair<T1, T2>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
||||
for (const std::pair<T1, T2> &src_iter : src) {
|
||||
output.push_back(
|
||||
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}",
|
||||
encapsulation.first,
|
||||
src_iter.first,
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
src_iter.second,
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// _WIN32 builds require that #include<fmt/format.h> be included in whatever code file the invocation is made from (no header files)
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
std::vector<std::string> join_tuple(const std::string &glue, const std::pair<char, char> &encapsulation, const std::vector<std::tuple<T1, T2, T3, T4>> &src)
|
||||
{
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> output;
|
||||
|
||||
for (const std::tuple<T1, T2, T3, T4> &src_iter : src) {
|
||||
|
||||
output.push_back(
|
||||
|
||||
fmt::format(
|
||||
"{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
|
||||
encapsulation.first,
|
||||
std::get<0>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<1>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<2>(src_iter),
|
||||
encapsulation.second,
|
||||
glue,
|
||||
encapsulation.first,
|
||||
std::get<3>(src_iter),
|
||||
encapsulation.second
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitString(const std::string &s, char delim);
|
||||
std::string EscapeString(const char *src, size_t sz);
|
||||
std::string EscapeString(const std::string &s);
|
||||
bool StringIsNumber(const std::string &s);
|
||||
void ToLowerString(std::string &s);
|
||||
void ToUpperString(std::string &s);
|
||||
std::string JoinString(const std::vector<std::string>& ar, const std::string &delim);
|
||||
void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string);
|
||||
void ParseAccountString(const std::string &s, std::string &account, std::string &loginserver);
|
||||
|
||||
//const char based
|
||||
|
||||
bool atobool(const char* iBool);
|
||||
bool isAlphaNumeric(const char *text);
|
||||
bool strn0cpyt(char* dest, const char* source, uint32 size);
|
||||
char *CleanMobName(const char *in, char *out);
|
||||
char *RemoveApostrophes(const char *s);
|
||||
char* strn0cpy(char* dest, const char* source, uint32 size);
|
||||
const char *ConvertArray(int input, char *returnchar);
|
||||
const char *ConvertArrayF(float input, char *returnchar);
|
||||
const char *MakeLowerString(const char *source);
|
||||
int MakeAnyLenString(char** ret, const char* format, ...);
|
||||
uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...);
|
||||
uint32 hextoi(const char* num);
|
||||
uint64 hextoi64(const char* num);
|
||||
void MakeLowerString(const char *source, char *target);
|
||||
void RemoveApostrophes(std::string &s);
|
||||
|
||||
#endif
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "../common/debug.h"
|
||||
// Disgrace: for windows compile
|
||||
#ifndef WIN32
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/timeb.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
int32 started_unix_timestamp = 0;
|
||||
int32 current_time = 0;
|
||||
int32 last_time = 0;
|
||||
|
||||
Timer::Timer(){
|
||||
timer_time = 30000; //default to 30 seconds
|
||||
start_time = current_time;
|
||||
set_at_trigger = timer_time;
|
||||
pUseAcurateTiming = false;
|
||||
enabled = false;
|
||||
}
|
||||
Timer::Timer(int32 in_timer_time, bool iUseAcurateTiming) {
|
||||
timer_time = in_timer_time;
|
||||
start_time = current_time;
|
||||
set_at_trigger = timer_time;
|
||||
pUseAcurateTiming = iUseAcurateTiming;
|
||||
if (timer_time == 0) {
|
||||
enabled = false;
|
||||
}
|
||||
else {
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
Timer::Timer(int32 start, int32 timer, bool iUseAcurateTiming = false) {
|
||||
timer_time = timer;
|
||||
start_time = start;
|
||||
set_at_trigger = timer_time;
|
||||
pUseAcurateTiming = iUseAcurateTiming;
|
||||
if (timer_time == 0) {
|
||||
enabled = false;
|
||||
}
|
||||
else {
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reimplemented for MSVC - Bounce */
|
||||
#ifdef WIN32
|
||||
int gettimeofday (timeval *tp, ...)
|
||||
{
|
||||
timeb tb;
|
||||
|
||||
ftime (&tb);
|
||||
|
||||
tp->tv_sec = tb.time;
|
||||
tp->tv_usec = tb.millitm * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function checks if the timer triggered */
|
||||
bool Timer::Check(bool iReset)
|
||||
{
|
||||
if (enabled && current_time-start_time > timer_time) {
|
||||
if (iReset) {
|
||||
if (pUseAcurateTiming)
|
||||
start_time += timer_time;
|
||||
else
|
||||
start_time = current_time; // Reset timer
|
||||
timer_time = set_at_trigger;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This function disables the timer */
|
||||
void Timer::Disable() {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
void Timer::Enable() {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
/* This function set the timer and restart it */
|
||||
void Timer::Start(int32 set_timer_time, bool ChangeResetTimer) {
|
||||
start_time = current_time;
|
||||
enabled = true;
|
||||
if (set_timer_time != 0)
|
||||
{
|
||||
timer_time = set_timer_time;
|
||||
if (ChangeResetTimer)
|
||||
set_at_trigger = set_timer_time;
|
||||
}
|
||||
}
|
||||
|
||||
/* This timer updates the timer without restarting it */
|
||||
void Timer::SetTimer(int32 set_timer_time) {
|
||||
/* If we were disabled before => restart the timer */
|
||||
if (!enabled) {
|
||||
start_time = current_time;
|
||||
enabled = true;
|
||||
}
|
||||
if (set_timer_time != 0) {
|
||||
timer_time = set_timer_time;
|
||||
set_at_trigger = set_timer_time;
|
||||
}
|
||||
}
|
||||
|
||||
int32 Timer::GetElapsedTime(){
|
||||
if (enabled) {
|
||||
return current_time - start_time;
|
||||
}
|
||||
else {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
int32 Timer::GetRemainingTime() {
|
||||
if (enabled) {
|
||||
if (current_time-start_time > timer_time)
|
||||
return 0;
|
||||
else
|
||||
return (start_time + timer_time) - current_time;
|
||||
}
|
||||
else {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::SetAtTrigger(int32 in_set_at_trigger, bool iEnableIfDisabled) {
|
||||
set_at_trigger = in_set_at_trigger;
|
||||
if (!Enabled() && iEnableIfDisabled) {
|
||||
Enable();
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::Trigger()
|
||||
{
|
||||
enabled = true;
|
||||
|
||||
timer_time = set_at_trigger;
|
||||
start_time = current_time-timer_time-1;
|
||||
}
|
||||
|
||||
const int32& Timer::GetCurrentTime2()
|
||||
{
|
||||
return current_time;
|
||||
}
|
||||
|
||||
const int32& Timer::SetCurrentTime()
|
||||
{
|
||||
struct timeval read_time;
|
||||
int32 this_time;
|
||||
|
||||
gettimeofday(&read_time,0);
|
||||
if(started_unix_timestamp == 0)
|
||||
started_unix_timestamp = read_time.tv_sec;
|
||||
|
||||
this_time = (read_time.tv_sec - started_unix_timestamp) * 1000 + read_time.tv_usec / 1000;
|
||||
|
||||
if (last_time == 0)
|
||||
{
|
||||
current_time = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_time += this_time - last_time;
|
||||
}
|
||||
|
||||
last_time = this_time;
|
||||
|
||||
// cerr << "Current time:" << current_time << endl;
|
||||
return current_time;
|
||||
}
|
||||
|
||||
int32 Timer::GetUnixTimeStamp(){
|
||||
struct timeval read_time;
|
||||
gettimeofday(&read_time,0);
|
||||
return read_time.tv_sec;
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include "types.h"
|
||||
#include <chrono>
|
||||
|
||||
// Disgrace: for windows compile
|
||||
#ifdef WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
int gettimeofday (timeval *tp, ...);
|
||||
#endif
|
||||
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer();
|
||||
Timer(int32 timer_time, bool iUseAcurateTiming = false);
|
||||
Timer(int32 start, int32 timer, bool iUseAcurateTiming);
|
||||
~Timer() { }
|
||||
|
||||
bool Check(bool iReset = true);
|
||||
void Enable();
|
||||
void Disable();
|
||||
void Start(int32 set_timer_time=0, bool ChangeResetTimer = true);
|
||||
void SetTimer(int32 set_timer_time=0);
|
||||
int32 GetRemainingTime();
|
||||
int32 GetElapsedTime();
|
||||
inline const int32& GetTimerTime() { return timer_time; }
|
||||
inline const int32& GetSetAtTrigger() { return set_at_trigger; }
|
||||
void Trigger();
|
||||
void SetAtTrigger(int32 set_at_trigger, bool iEnableIfDisabled = false);
|
||||
|
||||
inline bool Enabled() { return enabled; }
|
||||
inline int32 GetStartTime() { return(start_time); }
|
||||
inline int32 GetDuration() { return(timer_time); }
|
||||
|
||||
static const int32& SetCurrentTime();
|
||||
static const int32& GetCurrentTime2();
|
||||
static int32 GetUnixTimeStamp();
|
||||
|
||||
private:
|
||||
int32 start_time;
|
||||
int32 timer_time;
|
||||
bool enabled;
|
||||
int32 set_at_trigger;
|
||||
|
||||
// Tells the timer to be more acurate about happening every X ms.
|
||||
// Instead of Check() setting the start_time = now,
|
||||
// it it sets it to start_time += timer_time
|
||||
bool pUseAcurateTiming;
|
||||
|
||||
// static int32 current_time;
|
||||
// static int32 last_time;
|
||||
};
|
||||
|
||||
struct BenchTimer
|
||||
{
|
||||
typedef std::chrono::high_resolution_clock clock;
|
||||
|
||||
BenchTimer() : start_time(clock::now()) {}
|
||||
void reset() { start_time = clock::now(); }
|
||||
// this is seconds
|
||||
double elapsed() { return std::chrono::duration<double>(clock::now() - start_time).count(); }
|
||||
private:
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "unix.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void Sleep(unsigned int x) {
|
||||
if (x > 0)
|
||||
usleep(x*1000);
|
||||
}
|
||||
|
||||
char* strupr(char* tmp) {
|
||||
int l = strlen(tmp);
|
||||
for (int x = 0; x < l; x++) {
|
||||
tmp[x] = toupper(tmp[x]);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
char* strlwr(char* tmp) {
|
||||
int l = strlen(tmp);
|
||||
for (int x = 0; x < l; x++) {
|
||||
tmp[x] = tolower(tmp[x]);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef WIN32
|
||||
#ifndef __UNIX_H__
|
||||
#define __UNIX_H__
|
||||
#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER}
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
typedef int SOCKET;
|
||||
|
||||
void Sleep(unsigned int x);
|
||||
char* strupr(char* tmp);
|
||||
char* strlwr(char* tmp);
|
||||
#endif
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,732 +0,0 @@
|
||||
/****************************************************************************/
|
||||
/*! \mainpage XMLParser library
|
||||
* \section intro_sec Introduction
|
||||
*
|
||||
* This is a basic XML parser written in ANSI C++ for portability.
|
||||
* It works by using recursion and a node tree for breaking
|
||||
* down the elements of an XML document.
|
||||
*
|
||||
* @version V2.44
|
||||
* @author Frank Vanden Berghen
|
||||
*
|
||||
* Copyright (c) 2002, Frank Vanden Berghen - All rights reserved.<br/>
|
||||
* Commercialized by <a href="http://www.Business-Insight.com">Business-Insight</a><br/>
|
||||
* See the file <a href="../../AFPL-license.txt">AFPL-license.txt</a> about the licensing terms
|
||||
*
|
||||
* \section tutorial First Tutorial
|
||||
* You can follow a simple <a href="../../xmlParser.html">Tutorial</a> to know the basics...
|
||||
*
|
||||
* \section usage General usage: How to include the XMLParser library inside your project.
|
||||
*
|
||||
* The library is composed of two files: <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
|
||||
* <a href="../../xmlParser.h">xmlParser.h</a>. These are the ONLY 2 files that you need when
|
||||
* using the library inside your own projects.
|
||||
*
|
||||
* All the functions of the library are documented inside the comments of the file
|
||||
* <a href="../../xmlParser.h">xmlParser.h</a>. These comments can be transformed in
|
||||
* full-fledged HTML documentation using the DOXYGEN software: simply type: "doxygen doxy.cfg"
|
||||
*
|
||||
* By default, the XMLParser library uses (char*) for string representation.To use the (wchar_t*)
|
||||
* version of the library, you need to define the "_UNICODE" preprocessor definition variable
|
||||
* (this is usually done inside your project definition file) (This is done automatically for you
|
||||
* when using Visual Studio).
|
||||
*
|
||||
* \section example Advanced Tutorial and Many Examples of usage.
|
||||
*
|
||||
* Some very small introductory examples are described inside the Tutorial file
|
||||
* <a href="../../xmlParser.html">xmlParser.html</a>
|
||||
*
|
||||
* Some additional small examples are also inside the file <a href="../../xmlTest.cpp">xmlTest.cpp</a>
|
||||
* (for the "char*" version of the library) and inside the file
|
||||
* <a href="../../xmlTestUnicode.cpp">xmlTestUnicode.cpp</a> (for the "wchar_t*"
|
||||
* version of the library). If you have a question, please review these additionnal examples
|
||||
* before sending an e-mail to the author.
|
||||
*
|
||||
* To build the examples:
|
||||
* - linux/unix: type "make"
|
||||
* - solaris: type "make -f makefile.solaris"
|
||||
* - windows: Visual Studio: double-click on xmlParser.dsw
|
||||
* (under Visual Studio .NET, the .dsp and .dsw files will be automatically converted to .vcproj and .sln files)
|
||||
*
|
||||
* In order to build the examples you need some additional files:
|
||||
* - linux/unix: makefile
|
||||
* - solaris: makefile.solaris
|
||||
* - windows: Visual Studio: *.dsp, xmlParser.dsw and also xmlParser.lib and xmlParser.dll
|
||||
*
|
||||
* \section debugging Debugging with the XMLParser library
|
||||
*
|
||||
* \subsection debugwin Debugging under WINDOWS
|
||||
*
|
||||
* Inside Visual C++, the "debug versions" of the memory allocation functions are
|
||||
* very slow: Do not forget to compile in "release mode" to get maximum speed.
|
||||
* When I had to debug a software that was using the XMLParser Library, it was usually
|
||||
* a nightmare because the library was sooOOOoooo slow in debug mode (because of the
|
||||
* slow memory allocations in Debug mode). To solve this
|
||||
* problem, during all the debugging session, I am now using a very fast DLL version of the
|
||||
* XMLParser Library (the DLL is compiled in release mode). Using the DLL version of
|
||||
* the XMLParser Library allows me to have lightening XML parsing speed even in debug!
|
||||
* Other than that, the DLL version is useless: In the release version of my tool,
|
||||
* I always use the normal, ".cpp"-based, XMLParser Library (I simply include the
|
||||
* <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
|
||||
* <a href="../../xmlParser.h">xmlParser.h</a> files into the project).
|
||||
*
|
||||
* The file <a href="../../XMLNodeAutoexp.txt">XMLNodeAutoexp.txt</a> contains some
|
||||
* "tweaks" that improve substancially the display of the content of the XMLNode objects
|
||||
* inside the Visual Studio Debugger. Believe me, once you have seen inside the debugger
|
||||
* the "smooth" display of the XMLNode objects, you cannot live without it anymore!
|
||||
*
|
||||
* \subsection debuglinux Debugging under LINUX/UNIX
|
||||
*
|
||||
* The speed of the debug version of the XMLParser library is tolerable so no extra
|
||||
* work.has been done.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_XML_NODE__
|
||||
#define __INCLUDE_XML_NODE__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(UNICODE) || defined(_UNICODE)
|
||||
// If you comment the next "define" line then the library will never "switch to" _UNICODE (wchar_t*) mode (16/32 bits per characters).
|
||||
// This is useful when you get error messages like:
|
||||
// 'XMLNode::openFileHelper' : cannot convert parameter 2 from 'const char [5]' to 'const wchar_t *'
|
||||
// The _XMLWIDECHAR preprocessor variable force the XMLParser library into either utf16/32-mode (the proprocessor variable
|
||||
// must be defined) or utf8-mode(the pre-processor variable must be undefined).
|
||||
#define _XMLWIDECHAR
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(UNDER_CE) || defined(_WIN32) || defined(WIN64) || defined(__BORLANDC__)
|
||||
// comment the next line if you are under windows and the compiler is not Microsoft Visual Studio (6.0 or .NET) or Borland
|
||||
#define _XMLWINDOWS
|
||||
#endif
|
||||
|
||||
#ifdef XMLDLLENTRY
|
||||
#undef XMLDLLENTRY
|
||||
#endif
|
||||
#ifdef _USE_XMLPARSER_DLL
|
||||
#ifdef _DLL_EXPORTS_
|
||||
#define XMLDLLENTRY __declspec(dllexport)
|
||||
#else
|
||||
#define XMLDLLENTRY __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define XMLDLLENTRY
|
||||
#endif
|
||||
|
||||
// uncomment the next line if you want no support for wchar_t* (no need for the <wchar.h> or <tchar.h> libraries anymore to compile)
|
||||
//#define XML_NO_WIDE_CHAR
|
||||
|
||||
#ifdef XML_NO_WIDE_CHAR
|
||||
#undef _XMLWINDOWS
|
||||
#undef _XMLWIDECHAR
|
||||
#endif
|
||||
|
||||
#ifdef _XMLWINDOWS
|
||||
#include <tchar.h>
|
||||
#else
|
||||
#define XMLDLLENTRY
|
||||
#ifndef XML_NO_WIDE_CHAR
|
||||
#include <wchar.h> // to have 'wcsrtombs' for ANSI version
|
||||
// to have 'mbsrtowcs' for WIDECHAR version
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Some common types for char set portable code
|
||||
#ifdef _XMLWIDECHAR
|
||||
#define _CXML(c) L ## c
|
||||
#define XMLCSTR const wchar_t *
|
||||
#define XMLSTR wchar_t *
|
||||
#define XMLCHAR wchar_t
|
||||
#else
|
||||
#define _CXML(c) c
|
||||
#define XMLCSTR const char *
|
||||
#define XMLSTR char *
|
||||
#define XMLCHAR char
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif /* FALSE */
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif /* TRUE */
|
||||
|
||||
|
||||
/// Enumeration for XML parse errors.
|
||||
typedef enum XMLError
|
||||
{
|
||||
eXMLErrorNone = 0,
|
||||
eXMLErrorMissingEndTag,
|
||||
eXMLErrorNoXMLTagFound,
|
||||
eXMLErrorEmpty,
|
||||
eXMLErrorMissingTagName,
|
||||
eXMLErrorMissingEndTagName,
|
||||
eXMLErrorUnmatchedEndTag,
|
||||
eXMLErrorUnmatchedEndClearTag,
|
||||
eXMLErrorUnexpectedToken,
|
||||
eXMLErrorNoElements,
|
||||
eXMLErrorFileNotFound,
|
||||
eXMLErrorFirstTagNotFound,
|
||||
eXMLErrorUnknownCharacterEntity,
|
||||
eXMLErrorCharacterCodeAbove255,
|
||||
eXMLErrorCharConversionError,
|
||||
eXMLErrorCannotOpenWriteFile,
|
||||
eXMLErrorCannotWriteFile,
|
||||
|
||||
eXMLErrorBase64DataSizeIsNotMultipleOf4,
|
||||
eXMLErrorBase64DecodeIllegalCharacter,
|
||||
eXMLErrorBase64DecodeTruncatedData,
|
||||
eXMLErrorBase64DecodeBufferTooSmall
|
||||
} XMLError;
|
||||
|
||||
|
||||
/// Enumeration used to manage type of data. Use in conjunction with structure XMLNodeContents
|
||||
typedef enum XMLElementType
|
||||
{
|
||||
eNodeChild=0,
|
||||
eNodeAttribute=1,
|
||||
eNodeText=2,
|
||||
eNodeClear=3,
|
||||
eNodeNULL=4
|
||||
} XMLElementType;
|
||||
|
||||
/// Structure used to obtain error details if the parse fails.
|
||||
typedef struct XMLResults
|
||||
{
|
||||
enum XMLError error;
|
||||
int nLine,nColumn;
|
||||
} XMLResults;
|
||||
|
||||
/// Structure for XML clear (unformatted) node (usually comments)
|
||||
typedef struct XMLClear {
|
||||
XMLCSTR lpszValue; XMLCSTR lpszOpenTag; XMLCSTR lpszCloseTag;
|
||||
} XMLClear;
|
||||
|
||||
/// Structure for XML attribute.
|
||||
typedef struct XMLAttribute {
|
||||
XMLCSTR lpszName; XMLCSTR lpszValue;
|
||||
} XMLAttribute;
|
||||
|
||||
/// XMLElementPosition are not interchangeable with simple indexes
|
||||
typedef int XMLElementPosition;
|
||||
|
||||
struct XMLNodeContents;
|
||||
|
||||
/** @defgroup XMLParserGeneral The XML parser */
|
||||
|
||||
/// Main Class representing a XML node
|
||||
/**
|
||||
* All operations are performed using this class.
|
||||
* \note The constructors of the XMLNode class are protected, so use instead one of these four methods to get your first instance of XMLNode:
|
||||
* <ul>
|
||||
* <li> XMLNode::parseString </li>
|
||||
* <li> XMLNode::parseFile </li>
|
||||
* <li> XMLNode::openFileHelper </li>
|
||||
* <li> XMLNode::createXMLTopNode (or XMLNode::createXMLTopNode_WOSD)</li>
|
||||
* </ul> */
|
||||
typedef struct XMLDLLENTRY XMLNode
|
||||
{
|
||||
private:
|
||||
|
||||
struct XMLNodeDataTag;
|
||||
|
||||
/// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
|
||||
XMLNode(struct XMLNodeDataTag *pParent, XMLSTR lpszName, char isDeclaration);
|
||||
/// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
|
||||
XMLNode(struct XMLNodeDataTag *p);
|
||||
|
||||
public:
|
||||
static XMLCSTR getVersion();///< Return the XMLParser library version number
|
||||
|
||||
/** @defgroup conversions Parsing XML files/strings to an XMLNode structure and Rendering XMLNode's to files/string.
|
||||
* @ingroup XMLParserGeneral
|
||||
* @{ */
|
||||
|
||||
/// Parse an XML string and return the root of a XMLNode tree representing the string.
|
||||
static XMLNode parseString (XMLCSTR lpXMLString, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
|
||||
/**< The "parseString" function parse an XML string and return the root of a XMLNode tree. The "opposite" of this function is
|
||||
* the function "createXMLString" that re-creates an XML string from an XMLNode tree. If the XML document is corrupted, the
|
||||
* "parseString" method will initialize the "pResults" variable with some information that can be used to trace the error.
|
||||
* If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
|
||||
* beginning of the "xmlParser.cpp" file.
|
||||
*
|
||||
* @param lpXMLString the XML string to parse
|
||||
* @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
|
||||
* @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
|
||||
*/
|
||||
|
||||
/// Parse an XML file and return the root of a XMLNode tree representing the file.
|
||||
static XMLNode parseFile (XMLCSTR filename, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
|
||||
/**< The "parseFile" function parse an XML file and return the root of a XMLNode tree. The "opposite" of this function is
|
||||
* the function "writeToFile" that re-creates an XML file from an XMLNode tree. If the XML document is corrupted, the
|
||||
* "parseFile" method will initialize the "pResults" variable with some information that can be used to trace the error.
|
||||
* If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
|
||||
* beginning of the "xmlParser.cpp" file.
|
||||
*
|
||||
* @param filename the path to the XML file to parse
|
||||
* @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
|
||||
* @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
|
||||
*/
|
||||
|
||||
/// Parse an XML file and return the root of a XMLNode tree representing the file. A very crude error checking is made. An attempt to guess the Char Encoding used in the file is made.
|
||||
static XMLNode openFileHelper(XMLCSTR filename, XMLCSTR tag=NULL);
|
||||
/**< The "openFileHelper" function reports to the screen all the warnings and errors that occurred during parsing of the XML file.
|
||||
* This function also tries to guess char Encoding (UTF-8, ASCII or SHIT-JIS) based on the first 200 bytes of the file. Since each
|
||||
* application has its own way to report and deal with errors, you should rather use the "parseFile" function to parse XML files
|
||||
* and program yourself thereafter an "error reporting" tailored for your needs (instead of using the very crude "error reporting"
|
||||
* mechanism included inside the "openFileHelper" function).
|
||||
*
|
||||
* If the XML document is corrupted, the "openFileHelper" method will:
|
||||
* - display an error message on the console (or inside a messageBox for windows).
|
||||
* - stop execution (exit).
|
||||
*
|
||||
* I strongly suggest that you write your own "openFileHelper" method tailored to your needs. If you still want to parse
|
||||
* the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the beginning of the "xmlParser.cpp" file.
|
||||
*
|
||||
* @param filename the path of the XML file to parse.
|
||||
* @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
|
||||
*/
|
||||
|
||||
static XMLCSTR getError(XMLError error); ///< this gives you a user-friendly explanation of the parsing error
|
||||
|
||||
/// Create an XML string starting from the current XMLNode.
|
||||
XMLSTR createXMLString(int nFormat=1, int *pnSize=NULL) const;
|
||||
/**< The returned string should be free'd using the "freeXMLString" function.
|
||||
*
|
||||
* If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element
|
||||
* with appropriate white spaces and carriage returns. if pnSize is given it returns the size in character of the string. */
|
||||
|
||||
/// Save the content of an xmlNode inside a file
|
||||
XMLError writeToFile(XMLCSTR filename,
|
||||
const char *encoding=NULL,
|
||||
char nFormat=1) const;
|
||||
/**< If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element with appropriate white spaces and carriage returns.
|
||||
* If the global parameter "characterEncoding==encoding_UTF8", then the "encoding" parameter is ignored and always set to "utf-8".
|
||||
* If the global parameter "characterEncoding==encoding_ShiftJIS", then the "encoding" parameter is ignored and always set to "SHIFT-JIS".
|
||||
* If "_XMLWIDECHAR=1", then the "encoding" parameter is ignored and always set to "utf-16".
|
||||
* If no "encoding" parameter is given the "ISO-8859-1" encoding is used. */
|
||||
/** @} */
|
||||
|
||||
/** @defgroup navigate Navigate the XMLNode structure
|
||||
* @ingroup XMLParserGeneral
|
||||
* @{ */
|
||||
XMLCSTR getName() const; ///< name of the node
|
||||
XMLCSTR getText(int i=0) const; ///< return ith text field
|
||||
int nText() const; ///< nbr of text field
|
||||
XMLNode getParentNode() const; ///< return the parent node
|
||||
XMLNode getChildNode(int i=0) const; ///< return ith child node
|
||||
XMLNode getChildNode(XMLCSTR name, int i) const; ///< return ith child node with specific name (return an empty node if failing). If i==-1, this returns the last XMLNode with the given name.
|
||||
XMLNode getChildNode(XMLCSTR name, int *i=NULL) const; ///< return next child node with specific name (return an empty node if failing)
|
||||
XMLNode getChildNodeWithAttribute(XMLCSTR tagName,
|
||||
XMLCSTR attributeName,
|
||||
XMLCSTR attributeValue=NULL,
|
||||
int *i=NULL) const; ///< return child node with specific name/attribute (return an empty node if failing)
|
||||
XMLNode getChildNodeByPath(XMLCSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
|
||||
///< return the first child node with specific path
|
||||
XMLNode getChildNodeByPathNonConst(XMLSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
|
||||
///< return the first child node with specific path.
|
||||
|
||||
int nChildNode(XMLCSTR name) const; ///< return the number of child node with specific name
|
||||
int nChildNode() const; ///< nbr of child node
|
||||
XMLAttribute getAttribute(int i=0) const; ///< return ith attribute
|
||||
XMLCSTR getAttributeName(int i=0) const; ///< return ith attribute name
|
||||
XMLCSTR getAttributeValue(int i=0) const; ///< return ith attribute value
|
||||
char isAttributeSet(XMLCSTR name) const; ///< test if an attribute with a specific name is given
|
||||
XMLCSTR getAttribute(XMLCSTR name, int i) const; ///< return ith attribute content with specific name (return a NULL if failing)
|
||||
XMLCSTR getAttribute(XMLCSTR name, int *i=NULL) const; ///< return next attribute content with specific name (return a NULL if failing)
|
||||
int nAttribute() const; ///< nbr of attribute
|
||||
XMLClear getClear(int i=0) const; ///< return ith clear field (comments)
|
||||
int nClear() const; ///< nbr of clear field
|
||||
XMLNodeContents enumContents(XMLElementPosition i) const; ///< enumerate all the different contents (attribute,child,text, clear) of the current XMLNode. The order is reflecting the order of the original file/string. NOTE: 0 <= i < nElement();
|
||||
int nElement() const; ///< nbr of different contents for current node
|
||||
char isEmpty() const; ///< is this node Empty?
|
||||
char isDeclaration() const; ///< is this node a declaration <? .... ?>
|
||||
XMLNode deepCopy() const; ///< deep copy (duplicate/clone) a XMLNode
|
||||
static XMLNode emptyNode(); ///< return XMLNode::emptyXMLNode;
|
||||
/** @} */
|
||||
|
||||
~XMLNode();
|
||||
XMLNode(const XMLNode &A); ///< to allow shallow/fast copy:
|
||||
XMLNode& operator=( const XMLNode& A ); ///< to allow shallow/fast copy:
|
||||
|
||||
XMLNode(): d(NULL){};
|
||||
static XMLNode emptyXMLNode;
|
||||
static XMLClear emptyXMLClear;
|
||||
static XMLAttribute emptyXMLAttribute;
|
||||
|
||||
/** @defgroup xmlModify Create or Update the XMLNode structure
|
||||
* @ingroup XMLParserGeneral
|
||||
* The functions in this group allows you to create from scratch (or update) a XMLNode structure. Start by creating your top
|
||||
* node with the "createXMLTopNode" function and then add new nodes with the "addChild" function. The parameter 'pos' gives
|
||||
* the position where the childNode, the text or the XMLClearTag will be inserted. The default value (pos=-1) inserts at the
|
||||
* end. The value (pos=0) insert at the beginning (Insertion at the beginning is slower than at the end). <br>
|
||||
*
|
||||
* REMARK: 0 <= pos < nChild()+nText()+nClear() <br>
|
||||
*/
|
||||
|
||||
/** @defgroup creation Creating from scratch a XMLNode structure
|
||||
* @ingroup xmlModify
|
||||
* @{ */
|
||||
static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
|
||||
XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
|
||||
XMLNode addChild(XMLNode nodeToAdd, XMLElementPosition pos=-1); ///< If the "nodeToAdd" has some parents, it will be detached from it's parents before being attached to the current XMLNode
|
||||
XMLAttribute *addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev); ///< Add a new attribute
|
||||
XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
|
||||
XMLClear *addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1);
|
||||
/**< Add a new clear tag
|
||||
* @param lpszOpen default value "<![CDATA["
|
||||
* @param lpszClose default value "]]>"
|
||||
*/
|
||||
/** @} */
|
||||
|
||||
/** @defgroup xmlUpdate Updating Nodes
|
||||
* @ingroup xmlModify
|
||||
* Some update functions:
|
||||
* @{
|
||||
*/
|
||||
XMLCSTR updateName(XMLCSTR lpszName); ///< change node's name
|
||||
XMLAttribute *updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
|
||||
XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
|
||||
XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName);///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
|
||||
XMLCSTR updateText(XMLCSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
|
||||
XMLCSTR updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
|
||||
XMLClear *updateClear(XMLCSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
|
||||
XMLClear *updateClear(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
|
||||
XMLClear *updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
|
||||
/** @} */
|
||||
|
||||
/** @defgroup xmlDelete Deleting Nodes or Attributes
|
||||
* @ingroup xmlModify
|
||||
* Some deletion functions:
|
||||
* @{
|
||||
*/
|
||||
/// The "deleteNodeContent" function forces the deletion of the content of this XMLNode and the subtree.
|
||||
void deleteNodeContent();
|
||||
/**< \note The XMLNode instances that are referring to the part of the subtree that has been deleted CANNOT be used anymore!!. Unexpected results will occur if you continue using them. */
|
||||
void deleteAttribute(int i=0); ///< Delete the ith attribute of the current XMLNode
|
||||
void deleteAttribute(XMLCSTR lpszName); ///< Delete the attribute with the given name (the "strcmp" function is used to find the right attribute)
|
||||
void deleteAttribute(XMLAttribute *anAttribute); ///< Delete the attribute with the name "anAttribute->lpszName" (the "strcmp" function is used to find the right attribute)
|
||||
void deleteText(int i=0); ///< Delete the Ith text content of the current XMLNode
|
||||
void deleteText(XMLCSTR lpszValue); ///< Delete the text content "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the right text)
|
||||
void deleteClear(int i=0); ///< Delete the Ith clear tag inside the current XMLNode
|
||||
void deleteClear(XMLCSTR lpszValue); ///< Delete the clear tag "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the clear tag)
|
||||
void deleteClear(XMLClear *p); ///< Delete the clear tag "p" inside the current XMLNode (direct "pointer-to-pointer" comparison on the lpszName of the clear tag is used to find the clear tag)
|
||||
/** @} */
|
||||
|
||||
/** @defgroup xmlWOSD ???_WOSD functions.
|
||||
* @ingroup xmlModify
|
||||
* The strings given as parameters for the "add" and "update" methods that have a name with
|
||||
* the postfix "_WOSD" (that means "WithOut String Duplication")(for example "addText_WOSD")
|
||||
* will be free'd by the XMLNode class. For example, it means that this is incorrect:
|
||||
* \code
|
||||
* xNode.addText_WOSD("foo");
|
||||
* xNode.updateAttribute_WOSD("#newcolor" ,NULL,"color");
|
||||
* \endcode
|
||||
* In opposition, this is correct:
|
||||
* \code
|
||||
* xNode.addText("foo");
|
||||
* xNode.addText_WOSD(stringDup("foo"));
|
||||
* xNode.updateAttribute("#newcolor" ,NULL,"color");
|
||||
* xNode.updateAttribute_WOSD(stringDup("#newcolor"),NULL,"color");
|
||||
* \endcode
|
||||
* Typically, you will never do:
|
||||
* \code
|
||||
* char *b=(char*)malloc(...);
|
||||
* xNode.addText(b);
|
||||
* free(b);
|
||||
* \endcode
|
||||
* ... but rather:
|
||||
* \code
|
||||
* char *b=(char*)malloc(...);
|
||||
* xNode.addText_WOSD(b);
|
||||
* \endcode
|
||||
* ('free(b)' is performed by the XMLNode class)
|
||||
* @{ */
|
||||
static XMLNode createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
|
||||
XMLNode addChild_WOSD(XMLSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
|
||||
XMLAttribute *addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValue); ///< Add a new attribute
|
||||
XMLCSTR addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
|
||||
XMLClear *addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1); ///< Add a new clear Tag
|
||||
|
||||
XMLCSTR updateName_WOSD(XMLSTR lpszName); ///< change node's name
|
||||
XMLAttribute *updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
|
||||
XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
|
||||
XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,XMLCSTR lpszOldName); ///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
|
||||
XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
|
||||
XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
|
||||
XMLClear *updateClear_WOSD(XMLSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
|
||||
XMLClear *updateClear_WOSD(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
|
||||
XMLClear *updateClear_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
|
||||
/** @} */
|
||||
|
||||
/** @defgroup xmlPosition Position helper functions (use in conjunction with the update&add functions
|
||||
* @ingroup xmlModify
|
||||
* These are some useful functions when you want to insert a childNode, a text or a XMLClearTag in the
|
||||
* middle (at a specified position) of a XMLNode tree already constructed. The value returned by these
|
||||
* methods is to be used as last parameter (parameter 'pos') of addChild, addText or addClear.
|
||||
* @{ */
|
||||
XMLElementPosition positionOfText(int i=0) const;
|
||||
XMLElementPosition positionOfText(XMLCSTR lpszValue) const;
|
||||
XMLElementPosition positionOfClear(int i=0) const;
|
||||
XMLElementPosition positionOfClear(XMLCSTR lpszValue) const;
|
||||
XMLElementPosition positionOfClear(XMLClear *a) const;
|
||||
XMLElementPosition positionOfChildNode(int i=0) const;
|
||||
XMLElementPosition positionOfChildNode(XMLNode x) const;
|
||||
XMLElementPosition positionOfChildNode(XMLCSTR name, int i=0) const; ///< return the position of the ith childNode with the specified name if (name==NULL) return the position of the ith childNode
|
||||
/** @} */
|
||||
|
||||
/// Enumeration for XML character encoding.
|
||||
typedef enum XMLCharEncoding
|
||||
{
|
||||
char_encoding_error=0,
|
||||
char_encoding_UTF8=1,
|
||||
char_encoding_legacy=2,
|
||||
char_encoding_ShiftJIS=3,
|
||||
char_encoding_GB2312=4,
|
||||
char_encoding_Big5=5,
|
||||
char_encoding_GBK=6 // this is actually the same as Big5
|
||||
} XMLCharEncoding;
|
||||
|
||||
/** \addtogroup conversions
|
||||
* @{ */
|
||||
|
||||
/// Sets the global options for the conversions
|
||||
static char setGlobalOptions(XMLCharEncoding characterEncoding=XMLNode::char_encoding_UTF8, char guessWideCharChars=1,
|
||||
char dropWhiteSpace=1, char removeCommentsInMiddleOfText=1);
|
||||
/**< The "setGlobalOptions" function allows you to change four global parameters that affect string & file
|
||||
* parsing. First of all, you most-probably will never have to change these 3 global parameters.
|
||||
*
|
||||
* @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in WideChar mode, then the
|
||||
* XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains ASCII
|
||||
* characters. If this is the case, then the file will be loaded and converted in memory to
|
||||
* WideChar before being parsed. If 0, no conversion will be performed.
|
||||
*
|
||||
* @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in ASCII/UTF8/char* mode, then the
|
||||
* XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains WideChar
|
||||
* characters. If this is the case, then the file will be loaded and converted in memory to
|
||||
* ASCII/UTF8/char* before being parsed. If 0, no conversion will be performed.
|
||||
*
|
||||
* @param characterEncoding This parameter is only meaningful when compiling in char* mode (multibyte character mode).
|
||||
* In wchar_t* (wide char mode), this parameter is ignored. This parameter should be one of the
|
||||
* three currently recognized encodings: XMLNode::encoding_UTF8, XMLNode::encoding_ascii,
|
||||
* XMLNode::encoding_ShiftJIS.
|
||||
*
|
||||
* @param dropWhiteSpace In most situations, text fields containing only white spaces (and carriage returns)
|
||||
* are useless. Even more, these "empty" text fields are annoying because they increase the
|
||||
* complexity of the user's code for parsing. So, 99% of the time, it's better to drop
|
||||
* the "empty" text fields. However The XML specification indicates that no white spaces
|
||||
* should be lost when parsing the file. So to be perfectly XML-compliant, you should set
|
||||
* dropWhiteSpace=0. A note of caution: if you set "dropWhiteSpace=0", the parser will be
|
||||
* slower and your code will be more complex.
|
||||
*
|
||||
* @param removeCommentsInMiddleOfText To explain this parameter, let's consider this code:
|
||||
* \code
|
||||
* XMLNode x=XMLNode::parseString("<a>foo<!-- hello -->bar<!DOCTYPE world >chu</a>","a");
|
||||
* \endcode
|
||||
* If removeCommentsInMiddleOfText=0, then we will have:
|
||||
* \code
|
||||
* x.getText(0) -> "foo"
|
||||
* x.getText(1) -> "bar"
|
||||
* x.getText(2) -> "chu"
|
||||
* x.getClear(0) --> "<!-- hello -->"
|
||||
* x.getClear(1) --> "<!DOCTYPE world >"
|
||||
* \endcode
|
||||
* If removeCommentsInMiddleOfText=1, then we will have:
|
||||
* \code
|
||||
* x.getText(0) -> "foobar"
|
||||
* x.getText(1) -> "chu"
|
||||
* x.getClear(0) --> "<!DOCTYPE world >"
|
||||
* \endcode
|
||||
*
|
||||
* \return "0" when there are no errors. If you try to set an unrecognized encoding then the return value will be "1" to signal an error.
|
||||
*
|
||||
* \note Sometime, it's useful to set "guessWideCharChars=0" to disable any conversion
|
||||
* because the test to detect the file-type (ASCII/UTF8/char* or WideChar) may fail (rarely). */
|
||||
|
||||
/// Guess the character encoding of the string (ascii, utf8 or shift-JIS)
|
||||
static XMLCharEncoding guessCharEncoding(void *buffer, int bufLen, char useXMLEncodingAttribute=1);
|
||||
/**< The "guessCharEncoding" function try to guess the character encoding. You most-probably will never
|
||||
* have to use this function. It then returns the appropriate value of the global parameter
|
||||
* "characterEncoding" described in the XMLNode::setGlobalOptions. The guess is based on the content of a buffer of length
|
||||
* "bufLen" bytes that contains the first bytes (minimum 25 bytes; 200 bytes is a good value) of the
|
||||
* file to be parsed. The XMLNode::openFileHelper function is using this function to automatically compute
|
||||
* the value of the "characterEncoding" global parameter. There are several heuristics used to do the
|
||||
* guess. One of the heuristic is based on the "encoding" attribute. The original XML specifications
|
||||
* forbids to use this attribute to do the guess but you can still use it if you set
|
||||
* "useXMLEncodingAttribute" to 1 (this is the default behavior and the behavior of most parsers).
|
||||
* If an inconsistency in the encoding is detected, then the return value is "0". */
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
// these are functions and structures used internally by the XMLNode class (don't bother about them):
|
||||
|
||||
typedef struct XMLNodeDataTag // to allow shallow copy and "intelligent/smart" pointers (automatic delete):
|
||||
{
|
||||
XMLCSTR lpszName; // Element name (=NULL if root)
|
||||
int nChild, // Number of child nodes
|
||||
nText, // Number of text fields
|
||||
nClear, // Number of Clear fields (comments)
|
||||
nAttribute; // Number of attributes
|
||||
char isDeclaration; // Whether node is an XML declaration - '<?xml ?>'
|
||||
struct XMLNodeDataTag *pParent; // Pointer to parent element (=NULL if root)
|
||||
XMLNode *pChild; // Array of child nodes
|
||||
XMLCSTR *pText; // Array of text fields
|
||||
XMLClear *pClear; // Array of clear fields
|
||||
XMLAttribute *pAttribute; // Array of attributes
|
||||
int *pOrder; // order of the child_nodes,text_fields,clear_fields
|
||||
int ref_count; // for garbage collection (smart pointers)
|
||||
} XMLNodeData;
|
||||
XMLNodeData *d;
|
||||
|
||||
char parseClearTag(void *px, void *pa);
|
||||
char maybeAddTxT(void *pa, XMLCSTR tokenPStr);
|
||||
int ParseXMLElement(void *pXML);
|
||||
void *addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype);
|
||||
int indexText(XMLCSTR lpszValue) const;
|
||||
int indexClear(XMLCSTR lpszValue) const;
|
||||
XMLNode addChild_priv(int,XMLSTR,char,int);
|
||||
XMLAttribute *addAttribute_priv(int,XMLSTR,XMLSTR);
|
||||
XMLCSTR addText_priv(int,XMLSTR,int);
|
||||
XMLClear *addClear_priv(int,XMLSTR,XMLCSTR,XMLCSTR,int);
|
||||
void emptyTheNode(char force);
|
||||
static inline XMLElementPosition findPosition(XMLNodeData *d, int index, XMLElementType xtype);
|
||||
static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat);
|
||||
static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index);
|
||||
static void exactMemory(XMLNodeData *d);
|
||||
static int detachFromParent(XMLNodeData *d);
|
||||
} XMLNode;
|
||||
|
||||
/// This structure is given by the function XMLNode::enumContents.
|
||||
typedef struct XMLNodeContents
|
||||
{
|
||||
/// This dictates what's the content of the XMLNodeContent
|
||||
enum XMLElementType etype;
|
||||
/**< should be an union to access the appropriate data. Compiler does not allow union of object with constructor... too bad. */
|
||||
XMLNode child;
|
||||
XMLAttribute attrib;
|
||||
XMLCSTR text;
|
||||
XMLClear clear;
|
||||
|
||||
} XMLNodeContents;
|
||||
|
||||
/** @defgroup StringAlloc String Allocation/Free functions
|
||||
* @ingroup xmlModify
|
||||
* @{ */
|
||||
/// Duplicate (copy in a new allocated buffer) the source string.
|
||||
XMLDLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData=-1);
|
||||
/**< This is
|
||||
* a very handy function when used with all the "XMLNode::*_WOSD" functions (\link xmlWOSD \endlink).
|
||||
* @param cbData If !=0 then cbData is the number of chars to duplicate. New strings allocated with
|
||||
* this function should be free'd using the "freeXMLString" function. */
|
||||
|
||||
/// to free the string allocated inside the "stringDup" function or the "createXMLString" function.
|
||||
XMLDLLENTRY void freeXMLString(XMLSTR t); // {free(t);}
|
||||
/** @} */
|
||||
|
||||
/** @defgroup atoX ato? like functions
|
||||
* @ingroup XMLParserGeneral
|
||||
* The "xmlto?" functions are equivalents to the atoi, atol, atof functions.
|
||||
* The only difference is: If the variable "xmlString" is NULL, than the return value
|
||||
* is "defautValue". These 6 functions are only here as "convenience" functions for the
|
||||
* user (they are not used inside the XMLparser). If you don't need them, you can
|
||||
* delete them without any trouble.
|
||||
*
|
||||
* @{ */
|
||||
XMLDLLENTRY char xmltob(XMLCSTR xmlString,char defautValue=0);
|
||||
XMLDLLENTRY int xmltoi(XMLCSTR xmlString,int defautValue=0);
|
||||
XMLDLLENTRY long long xmltol(XMLCSTR xmlString,long long defautValue=0);
|
||||
XMLDLLENTRY double xmltof(XMLCSTR xmlString,double defautValue=.0);
|
||||
XMLDLLENTRY XMLCSTR xmltoa(XMLCSTR xmlString,XMLCSTR defautValue=_CXML(""));
|
||||
XMLDLLENTRY XMLCHAR xmltoc(XMLCSTR xmlString,const XMLCHAR defautValue=_CXML('\0'));
|
||||
/** @} */
|
||||
|
||||
/** @defgroup ToXMLStringTool Helper class to create XML files using "printf", "fprintf", "cout",... functions.
|
||||
* @ingroup XMLParserGeneral
|
||||
* @{ */
|
||||
/// Helper class to create XML files using "printf", "fprintf", "cout",... functions.
|
||||
/** The ToXMLStringTool class helps you creating XML files using "printf", "fprintf", "cout",... functions.
|
||||
* The "ToXMLStringTool" class is processing strings so that all the characters
|
||||
* &,",',<,> are replaced by their XML equivalent:
|
||||
* \verbatim &, ", ', <, > \endverbatim
|
||||
* Using the "ToXMLStringTool class" and the "fprintf function" is THE most efficient
|
||||
* way to produce VERY large XML documents VERY fast.
|
||||
* \note If you are creating from scratch an XML file using the provided XMLNode class
|
||||
* you must not use the "ToXMLStringTool" class (because the "XMLNode" class does the
|
||||
* processing job for you during rendering).*/
|
||||
typedef struct XMLDLLENTRY ToXMLStringTool
|
||||
{
|
||||
public:
|
||||
ToXMLStringTool(): buf(NULL),buflen(0){}
|
||||
~ToXMLStringTool();
|
||||
void freeBuffer();///<call this function when you have finished using this object to release memory used by the internal buffer.
|
||||
|
||||
XMLSTR toXML(XMLCSTR source);///< returns a pointer to an internal buffer that contains a XML-encoded string based on the "source" parameter.
|
||||
|
||||
/** The "toXMLUnSafe" function is deprecated because there is a possibility of
|
||||
* "destination-buffer-overflow". It converts the string
|
||||
* "source" to the string "dest". */
|
||||
static XMLSTR toXMLUnSafe(XMLSTR dest,XMLCSTR source); ///< deprecated: use "toXML" instead
|
||||
static int lengthXMLString(XMLCSTR source); ///< deprecated: use "toXML" instead
|
||||
|
||||
private:
|
||||
XMLSTR buf;
|
||||
int buflen;
|
||||
} ToXMLStringTool;
|
||||
/** @} */
|
||||
|
||||
/** @defgroup XMLParserBase64Tool Helper class to include binary data inside XML strings using "Base64 encoding".
|
||||
* @ingroup XMLParserGeneral
|
||||
* @{ */
|
||||
/// Helper class to include binary data inside XML strings using "Base64 encoding".
|
||||
/** The "XMLParserBase64Tool" class allows you to include any binary data (images, sounds,...)
|
||||
* into an XML document using "Base64 encoding". This class is completely
|
||||
* separated from the rest of the xmlParser library and can be removed without any problem.
|
||||
* To include some binary data into an XML file, you must convert the binary data into
|
||||
* standard text (using "encode"). To retrieve the original binary data from the
|
||||
* b64-encoded text included inside the XML file, use "decode". Alternatively, these
|
||||
* functions can also be used to "encrypt/decrypt" some critical data contained inside
|
||||
* the XML (it's not a strong encryption at all, but sometimes it can be useful). */
|
||||
typedef struct XMLDLLENTRY XMLParserBase64Tool
|
||||
{
|
||||
public:
|
||||
XMLParserBase64Tool(): buf(NULL),buflen(0){}
|
||||
~XMLParserBase64Tool();
|
||||
void freeBuffer();///< Call this function when you have finished using this object to release memory used by the internal buffer.
|
||||
|
||||
/**
|
||||
* @param formatted If "formatted"=true, some space will be reserved for a carriage-return every 72 chars. */
|
||||
static int encodeLength(int inBufLen, char formatted=0); ///< return the length of the base64 string that encodes a data buffer of size inBufLen bytes.
|
||||
|
||||
/**
|
||||
* The "base64Encode" function returns a string containing the base64 encoding of "inByteLen" bytes
|
||||
* from "inByteBuf". If "formatted" parameter is true, then there will be a carriage-return every 72 chars.
|
||||
* The string will be free'd when the XMLParserBase64Tool object is deleted.
|
||||
* All returned strings are sharing the same memory space. */
|
||||
XMLSTR encode(unsigned char *inByteBuf, unsigned int inByteLen, char formatted=0); ///< returns a pointer to an internal buffer containing the base64 string containing the binary data encoded from "inByteBuf"
|
||||
|
||||
/// returns the number of bytes which will be decoded from "inString".
|
||||
static unsigned int decodeSize(XMLCSTR inString, XMLError *xe=NULL);
|
||||
|
||||
/**
|
||||
* The "decode" function returns a pointer to a buffer containing the binary data decoded from "inString"
|
||||
* The output buffer will be free'd when the XMLParserBase64Tool object is deleted.
|
||||
* All output buffer are sharing the same memory space.
|
||||
* @param inString If "instring" is malformed, NULL will be returned */
|
||||
unsigned char* decode(XMLCSTR inString, int *outByteLen=NULL, XMLError *xe=NULL); ///< returns a pointer to an internal buffer containing the binary data decoded from "inString"
|
||||
|
||||
/**
|
||||
* decodes data from "inString" to "outByteBuf". You need to provide the size (in byte) of "outByteBuf"
|
||||
* in "inMaxByteOutBuflen". If "outByteBuf" is not large enough or if data is malformed, then "FALSE"
|
||||
* will be returned; otherwise "TRUE". */
|
||||
static unsigned char decode(XMLCSTR inString, unsigned char *outByteBuf, int inMaxByteOutBuflen, XMLError *xe=NULL); ///< deprecated.
|
||||
|
||||
private:
|
||||
void *buf;
|
||||
int buflen;
|
||||
void alloc(int newsize);
|
||||
}XMLParserBase64Tool;
|
||||
/** @} */
|
||||
|
||||
#undef XMLDLLENTRY
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user