1
0

forgot to commit lol

This commit is contained in:
Sky Johnson 2025-07-02 13:14:42 -05:00
parent 4e43c73f9c
commit 6612d0731f
65 changed files with 2238 additions and 13510 deletions

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
)

View 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
View 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
View 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"
}

View File

@ -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.

View File

@ -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

View File

@ -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>
{{{
}}}
###############################################################################

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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.

View File

@ -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 $@

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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__);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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;
};

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}
*/

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 &ltrim(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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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 &amp;, &quot;, &apos;, &lt;, &gt; \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