diff --git a/cmd/loginServer/clients.go b/cmd/loginServer/clients.go new file mode 100644 index 0000000..c6a903f --- /dev/null +++ b/cmd/loginServer/clients.go @@ -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 +} diff --git a/cmd/loginServer/config.go b/cmd/loginServer/config.go new file mode 100644 index 0000000..2c37e03 --- /dev/null +++ b/cmd/loginServer/config.go @@ -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, + }, + } +} diff --git a/cmd/loginServer/database.go b/cmd/loginServer/database.go new file mode 100644 index 0000000..3c81315 --- /dev/null +++ b/cmd/loginServer/database.go @@ -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 +} diff --git a/cmd/loginServer/main.go b/cmd/loginServer/main.go new file mode 100644 index 0000000..2ef5a80 --- /dev/null +++ b/cmd/loginServer/main.go @@ -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...") +} diff --git a/cmd/loginServer/opcodes.go b/cmd/loginServer/opcodes.go new file mode 100644 index 0000000..d8d01e7 --- /dev/null +++ b/cmd/loginServer/opcodes.go @@ -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) +} diff --git a/cmd/loginServer/tcp.go b/cmd/loginServer/tcp.go new file mode 100644 index 0000000..b14f2a9 --- /dev/null +++ b/cmd/loginServer/tcp.go @@ -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) +} diff --git a/cmd/loginServer/web.go b/cmd/loginServer/web.go new file mode 100644 index 0000000..a695eb2 --- /dev/null +++ b/cmd/loginServer/web.go @@ -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 + } +}` diff --git a/cmd/loginServer/worlds.go b/cmd/loginServer/worlds.go new file mode 100644 index 0000000..63b66fc --- /dev/null +++ b/cmd/loginServer/worlds.go @@ -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 +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2170441 --- /dev/null +++ b/go.mod @@ -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 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..90e8082 --- /dev/null +++ b/go.sum @@ -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= diff --git a/internal/opcodes/game.go b/internal/opcodes/game.go new file mode 100644 index 0000000..6e01e30 --- /dev/null +++ b/internal/opcodes/game.go @@ -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 +) diff --git a/internal/opcodes/login.go b/internal/opcodes/login.go new file mode 100644 index 0000000..e3ed760 --- /dev/null +++ b/internal/opcodes/login.go @@ -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 +) diff --git a/internal/opcodes/protocol.go b/internal/opcodes/protocol.go new file mode 100644 index 0000000..3e32551 --- /dev/null +++ b/internal/opcodes/protocol.go @@ -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 +) diff --git a/internal/opcodes/server.go b/internal/opcodes/server.go new file mode 100644 index 0000000..02f40de --- /dev/null +++ b/internal/opcodes/server.go @@ -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 +) diff --git a/internal/opcodes/utils.go b/internal/opcodes/utils.go new file mode 100644 index 0000000..1f45b68 --- /dev/null +++ b/internal/opcodes/utils.go @@ -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" +} diff --git a/source/LoginServer/EQ2 Login.sln b/source/LoginServer/EQ2 Login.sln deleted file mode 100644 index 48169c7..0000000 --- a/source/LoginServer/EQ2 Login.sln +++ /dev/null @@ -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 diff --git a/source/LoginServer/EQ2 Login.suo b/source/LoginServer/EQ2 Login.suo deleted file mode 100644 index d090a9e..0000000 Binary files a/source/LoginServer/EQ2 Login.suo and /dev/null differ diff --git a/source/LoginServer/Login.dsp b/source/LoginServer/Login.dsp deleted file mode 100644 index cf66e51..0000000 --- a/source/LoginServer/Login.dsp +++ /dev/null @@ -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 diff --git a/source/LoginServer/Login.dsw b/source/LoginServer/Login.dsw deleted file mode 100644 index 4ed0adf..0000000 --- a/source/LoginServer/Login.dsw +++ /dev/null @@ -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> -{{{ -}}} - -############################################################################### - diff --git a/source/LoginServer/Login.vcproj b/source/LoginServer/Login.vcproj deleted file mode 100644 index 7c1f7a6..0000000 --- a/source/LoginServer/Login.vcproj +++ /dev/null @@ -1,542 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/LoginServer/Login.vcxproj b/source/LoginServer/Login.vcxproj deleted file mode 100644 index 5622e75..0000000 --- a/source/LoginServer/Login.vcxproj +++ /dev/null @@ -1,154 +0,0 @@ - - - - - EQ2Login - x64 - - - - EQ2Login - {BE2C1914-FCCC-4F65-A7DD-105142B36104} - EQ2 Login - 10.0 - - - - v142 - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - $(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); - $(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 - false - $(SolutionDir)loginserver\ - .\$(ProjectName)__Debug64\ - $(ProjectName)__Debug64 - - - - Disabled - AnySuitable - _WIN32_WINNT=0x0400;WIN32;NDEBUG;_CONSOLE;LOGIN; EQ2; EQN_DEBUG;_CRT_SECURE_NO_DEPRECATE;_HAS_STD_BYTE=0 -;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebug - false - false - - - $(IntDir) - - - 4996;%(DisableSpecificWarnings) - stdcpp17 - - - odbc32.lib;odbccp32.lib;ws2_32.lib;zlib.lib;mysqlclient.lib;DebugUtils.lib;Detour.lib;DetourCrowd.lib;DetourTileCache.lib;Recast.lib;%(AdditionalDependencies) - LIBCMT;LIBC;%(IgnoreSpecificDefaultLibraries) - true - $(IntDir)$(TargetName).pdb - true - true - Default - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/LoginServer/Login.vcxproj.filters b/source/LoginServer/Login.vcxproj.filters deleted file mode 100644 index fae3865..0000000 --- a/source/LoginServer/Login.vcxproj.filters +++ /dev/null @@ -1,277 +0,0 @@ - - - - - {bfe8d6b0-594f-4b55-9f95-101bbcf4069c} - cpp;c;cxx;rc;def;r;odl;idl;hpj;bat - - - {d65b2760-468c-4206-a19a-48323a50ba5a} - h;hpp;hxx;hm;inl - - - {27b769a5-0972-4e9e-b78c-09ad3341579c} - .cpp - - - {11757e5a-691c-49c9-a627-df027ad58326} - .h - - - {99e7f9f9-abcd-4abf-8200-a4b5a467788c} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - Common Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - World Files - - - World Files - - - World Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - Common Header Files - - - \ No newline at end of file diff --git a/source/LoginServer/Login.vcxproj.user b/source/LoginServer/Login.vcxproj.user deleted file mode 100644 index ace9a86..0000000 --- a/source/LoginServer/Login.vcxproj.user +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/source/LoginServer/Web/LoginWeb.o b/source/LoginServer/Web/LoginWeb.o deleted file mode 100644 index 29c26ff..0000000 Binary files a/source/LoginServer/Web/LoginWeb.o and /dev/null differ diff --git a/source/LoginServer/makefile b/source/LoginServer/makefile deleted file mode 100644 index 5071072..0000000 --- a/source/LoginServer/makefile +++ /dev/null @@ -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 $@ diff --git a/source/common/CRC16.cpp b/source/common/CRC16.cpp deleted file mode 100644 index f7b43ad..0000000 --- a/source/common/CRC16.cpp +++ /dev/null @@ -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 . -*/ -#include - -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; -} diff --git a/source/common/CRC16.h b/source/common/CRC16.h deleted file mode 100644 index 7aacd36..0000000 --- a/source/common/CRC16.h +++ /dev/null @@ -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 . -*/ -#ifndef _CRC16_H -#define _CRC16_H - -unsigned long CRC16(const unsigned char *buf, int size, int key); - -#endif diff --git a/source/common/Common_Defines.h b/source/common/Common_Defines.h deleted file mode 100644 index 4600d97..0000000 --- a/source/common/Common_Defines.h +++ /dev/null @@ -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 . -*/ -#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 \ No newline at end of file diff --git a/source/common/Condition.cpp b/source/common/Condition.cpp deleted file mode 100644 index 348c90a..0000000 --- a/source/common/Condition.cpp +++ /dev/null @@ -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 . -*/ -#include "debug.h" -#include "Condition.h" - -#ifdef WIN32 -#else -#include -#include -#include -#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 << "."<. -*/ -#ifndef __CONDITION_H -#define __CONDITION_H - -#ifndef WIN32 -#include -#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 - - diff --git a/source/common/Crypto.cpp b/source/common/Crypto.cpp deleted file mode 100644 index 369390e..0000000 --- a/source/common/Crypto.cpp +++ /dev/null @@ -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 . -*/ -#include "Crypto.h" -#include -#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(); -} - diff --git a/source/common/Crypto.h b/source/common/Crypto.h deleted file mode 100644 index d2c478b..0000000 --- a/source/common/Crypto.h +++ /dev/null @@ -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 . -*/ -#ifndef _CRYPTO_H -#define _CRYPTO_H -#include -#include -#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 - diff --git a/source/common/DataBuffer.h b/source/common/DataBuffer.h deleted file mode 100644 index f40486d..0000000 --- a/source/common/DataBuffer.h +++ /dev/null @@ -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 . -*/ -#ifndef __EQ2_DATABUFFER_ -#define __EQ2_DATABUFFER_ -#include -#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 void MakeEQ2_Int8(Type& output){ - MakeEQ2_Int8(&output); - } - template 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 void LoadDataString(String& output){ - LoadDataString(&output); - } - template 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 void LoadData(Type& output){ - LoadData(&output); - } - template void LoadData(Type* output, int32 array_size){ - if(array_size<=1){ - LoadData(output); - } - else{ - for(int32 i=0;i void LoadData(Type* output){ - if((sizeof(Type) + load_pos) <= load_len){ - memcpy(output, load_buffer + load_pos, sizeof(Type)); - load_pos += sizeof(Type); - } - } - template void LoadData(Type& output, int32 array_size){ - LoadData(&output, array_size); - } - void LoadSkip(int8 bytes){ - load_pos += bytes; - } - template void LoadSkip(Type& skip){ - LoadSkip(&skip); - } - template void LoadSkip(Type* skip){ - load_pos += sizeof(Type); - } - template 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 void StructAddData(Type input, int16 size, string* datastring){ - if(datastring) - datastring->append((char*)&input, size); - else - buffer.append((char*)&input, size); - } - template void StructAddData(Type input, int32 array_size, int16 size, string* datastring){ - if(array_size>0){ - for(int32 i=0;i void AddData(Type input, string* datastring = 0){ - if(!datastring) - datastring = &buffer; - datastring->append((char*)&input, sizeof(input)); - } - template void AddData(Type input, int32 array_size, string* datastring = 0){ - if(array_size>0){ - for(int32 i=0;i void AddDataString(String* input, string* datastring = 0){ - AddDataString(*input, datastring); - } - template 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 - diff --git a/source/common/DatabaseNew.cpp b/source/common/DatabaseNew.cpp deleted file mode 100644 index e1e2450..0000000 --- a/source/common/DatabaseNew.cpp +++ /dev/null @@ -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 . -*/ -#include -#include -#include -#include -#include "Log.h" -#include "DatabaseNew.h" -#include - -//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::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::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::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__); -} \ No newline at end of file diff --git a/source/common/DatabaseNew.h b/source/common/DatabaseNew.h deleted file mode 100644 index 2e2e002..0000000 --- a/source/common/DatabaseNew.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef COMMON_DATABASE_H_ -#define COMMON_DATABASE_H_ - -#include -#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 ignored_errnos; -}; - -#endif diff --git a/source/common/DatabaseResult.cpp b/source/common/DatabaseResult.cpp deleted file mode 100644 index 05df1a8..0000000 --- a/source/common/DatabaseResult.cpp +++ /dev/null @@ -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 . -*/ -#include -#include -#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; -} diff --git a/source/common/DatabaseResult.h b/source/common/DatabaseResult.h deleted file mode 100644 index 36b3c3e..0000000 --- a/source/common/DatabaseResult.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef COMMON_DATABASERESULT_H_ -#define COMMON_DATABASERESULT_H_ - -#include "types.h" -#ifdef _WIN32 -#include //#include when we/if we go to winsock2 :/ -#endif -#include -#include - -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 field_map; -}; - -#endif diff --git a/source/common/JsonParser.cpp b/source/common/JsonParser.cpp deleted file mode 100644 index cca065a..0000000 --- a/source/common/JsonParser.cpp +++ /dev/null @@ -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::max()) { - return false; // Number is too large for unsigned short - } - - result = static_cast(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::max()) { - return false; // Number is too large for unsigned short - } - - result = static_cast(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::max()) { - return false; // Number is too large for unsigned short - } - - result = static_cast(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::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(); - } else { - parseTree(node.second, currentPath); - } - } -} \ No newline at end of file diff --git a/source/common/JsonParser.h b/source/common/JsonParser.h deleted file mode 100644 index f92b07d..0000000 --- a/source/common/JsonParser.h +++ /dev/null @@ -1,33 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include - -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 values; - - void parseTree(const boost::property_tree::ptree &tree, const std::string &path); - bool is_loaded; -}; diff --git a/source/common/Mutex.cpp b/source/common/Mutex.cpp deleted file mode 100644 index 732e451..0000000 --- a/source/common/Mutex.cpp +++ /dev/null @@ -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 . -*/ -#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::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::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::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::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::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 -} - diff --git a/source/common/Mutex.h b/source/common/Mutex.h deleted file mode 100644 index ae96333..0000000 --- a/source/common/Mutex.h +++ /dev/null @@ -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 . -*/ -#ifndef MYMUTEX_H -#define MYMUTEX_H -#ifdef WIN32 - #include - #include -#else - #include - #include "../common/unix.h" -#endif -#include "../common/types.h" -#include -#include - -#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 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 diff --git a/source/common/RC4.cpp b/source/common/RC4.cpp deleted file mode 100644 index 15d9f78..0000000 --- a/source/common/RC4.cpp +++ /dev/null @@ -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 . -*/ -#include "RC4.h" -#include - -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; -} diff --git a/source/common/RC4.h b/source/common/RC4.h deleted file mode 100644 index 52a3ea9..0000000 --- a/source/common/RC4.h +++ /dev/null @@ -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 . -*/ -#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 - diff --git a/source/common/TCPConnection.cpp b/source/common/TCPConnection.cpp deleted file mode 100644 index 81493b2..0000000 --- a/source/common/TCPConnection.cpp +++ /dev/null @@ -1,1729 +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 . -*/ -#include "../common/debug.h" - -#include -using namespace std; -#include -#include -#include -using namespace std; - -#include "TCPConnection.h" -#include "../common/servertalk.h" -#include "../common/timer.h" -#include "../common/packet_dump.h" -#include "Log.h" - -#ifdef FREEBSD //Timothy Whitman - January 7, 2003 -#define MSG_NOSIGNAL 0 -#endif - -#ifdef WIN32 -InitWinsock winsock; -#endif - -#define LOOP_GRANULARITY 3 //# of ms between checking our socket/queues -#define SERVER_LOOP_GRANULARITY 3 //# of ms between checking our socket/queues - -#define TCPN_DEBUG 0 -#define TCPN_DEBUG_Console 0 -#define TCPN_DEBUG_Memory 0 -#define TCPN_LOG_PACKETS 0 -#define TCPN_LOG_RAW_DATA_OUT 0 -#define TCPN_LOG_RAW_DATA_IN 0 - -TCPConnection::TCPNetPacket_Struct* TCPConnection::MakePacket(ServerPacket* pack, int32 iDestination) { - sint32 size = sizeof(TCPNetPacket_Struct) + pack->size; - if (pack->compressed) { - size += 4; - } - if (iDestination) { - size += 4; - } - TCPNetPacket_Struct* tnps = (TCPNetPacket_Struct*) new uchar[size]; - tnps->size = size; - tnps->opcode = pack->opcode; - *((int8*) &tnps->flags) = 0; - uchar* buffer = tnps->buffer; - if (pack->compressed) { - tnps->flags.compressed = 1; - *((sint32*) buffer) = pack->InflatedSize; - buffer += 4; - } - if (iDestination) { - tnps->flags.destination = 1; - *((sint32*) buffer) = iDestination; - buffer += 4; - } - memcpy(buffer, pack->pBuffer, pack->size); - return tnps; -} - -TCPConnection::TCPConnection(bool iOldFormat, TCPServer* iRelayServer, eTCPMode iMode) { - id = 0; - Server = iRelayServer; - if (Server) - RelayServer = true; - else - RelayServer = false; - RelayLink = 0; - RelayCount = 0; - RemoteID = 0; - pOldFormat = iOldFormat; - ConnectionType = Outgoing; - TCPMode = iMode; - pState = TCPS_Ready; - pFree = false; - pEcho = false; - sock = 0; - rIP = 0; - rPort = 0; - keepalive_timer = new Timer(SERVER_TIMEOUT); - timeout_timer = new Timer(SERVER_TIMEOUT * 2); - recvbuf = 0; - sendbuf = 0; - pRunLoop = false; - charAsyncConnect = 0; - pAsyncConnect = false; - connection_socket = 0; - recvbuf_size = 0; - recvbuf_used = 0; - recvbuf_echo = 0; - sendbuf_size = 0; - sendbuf_used = 0; -#if TCPN_DEBUG_Memory >= 7 - cout << "Constructor #1 on outgoing TCP# " << GetID() << endl; -#endif -} - -TCPConnection::TCPConnection(TCPServer* iServer, SOCKET in_socket, int32 irIP, int16 irPort, bool iOldFormat) { - Server = iServer; - RelayLink = 0; - RelayServer = false; - RelayCount = 0; - RemoteID = 0; - id = Server->GetNextID(); - ConnectionType = Incomming; - pOldFormat = iOldFormat; - TCPMode = modePacket; - pState = TCPS_Connected; - pFree = false; - pEcho = false; - sock = 0; - connection_socket = in_socket; - rIP = irIP; - rPort = irPort; - keepalive_timer = new Timer(SERVER_TIMEOUT); - timeout_timer = new Timer(SERVER_TIMEOUT * 2); - recvbuf = 0; - sendbuf = 0; - pRunLoop = false; - charAsyncConnect = 0; - pAsyncConnect = false; - recvbuf_size = 0; - recvbuf_used = 0; - recvbuf_echo = 0; - sendbuf_size = 0; - sendbuf_used = 0; -#if TCPN_DEBUG_Memory >= 7 - cout << "Constructor #2 on outgoing TCP# " << GetID() << endl; -#endif -} - -TCPConnection::TCPConnection(TCPServer* iServer, TCPConnection* iRelayLink, int32 iRemoteID, int32 irIP, int16 irPort) { - Server = iServer; - RelayLink = iRelayLink; - RelayServer = true; - id = Server->GetNextID(); - RelayCount = 0; - RemoteID = iRemoteID; - if (!RemoteID) - ThrowError("Error: TCPConnection: RemoteID == 0 on RelayLink constructor"); - pOldFormat = false; - ConnectionType = Incomming; - TCPMode = modePacket; - pState = TCPS_Connected; - pFree = false; - pEcho = false; - sock = 0; - connection_socket = 0; - rIP = irIP; - rPort = irPort; - keepalive_timer = 0; - timeout_timer = 0; - recvbuf = 0; - sendbuf = 0; - pRunLoop = false; - charAsyncConnect = 0; - pAsyncConnect = false; - recvbuf_size = 0; - recvbuf_used = 0; - recvbuf_echo = 0; - sendbuf_size = 0; - sendbuf_used = 0; -#if TCPN_DEBUG_Memory >= 7 - cout << "Constructor #3 on outgoing TCP# " << GetID() << endl; -#endif -} - -TCPConnection::~TCPConnection() { - Disconnect(); - ClearBuffers(); - if (ConnectionType == Outgoing) { - MRunLoop.lock(); - pRunLoop = false; - MRunLoop.unlock(); - MLoopRunning.lock(); - MLoopRunning.unlock(); -#if TCPN_DEBUG_Memory >= 6 - cout << "Deconstructor on outgoing TCP# " << GetID() << endl; -#endif - } -#if TCPN_DEBUG_Memory >= 5 - else { - cout << "Deconstructor on incomming TCP# " << GetID() << endl; - } -#endif - safe_delete(keepalive_timer); - safe_delete(timeout_timer); - safe_delete_array(recvbuf); - safe_delete_array(sendbuf); - safe_delete_array(charAsyncConnect); -} - -void TCPConnection::SetState(int8 in_state) { - MState.lock(); - pState = in_state; - MState.unlock(); -} - -int8 TCPConnection::GetState() { - int8 ret; - MState.lock(); - ret = pState; - MState.unlock(); - return ret; -} - -void TCPConnection::Free() { - if (ConnectionType == Outgoing) { - ThrowError("TCPConnection::Free() called on an Outgoing connection"); - } -#if TCPN_DEBUG_Memory >= 5 - cout << "Free on TCP# " << GetID() << endl; -#endif - Disconnect(); - pFree = true; -} - -bool TCPConnection::SendPacket(ServerPacket* pack, int32 iDestination) { - LockMutex lock(&MState); - if (!Connected()) - return false; - eTCPMode tmp = GetMode(); - if (tmp != modePacket && tmp != modeTransition) - return false; - if (RemoteID) - return RelayLink->SendPacket(pack, RemoteID); - else { - TCPNetPacket_Struct* tnps = MakePacket(pack, iDestination); - if (tmp == modeTransition) { - InModeQueuePush(tnps); - } - else { -#if TCPN_LOG_PACKETS >= 1 - if (pack && pack->opcode != 0) { - struct in_addr in; - in.s_addr = GetrIP(); - CoutTimestamp(true); - cout << ": Logging outgoing TCP packet. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << endl; -#if TCPN_LOG_PACKETS == 2 - if (pack->size >= 32) - DumpPacket(pack->pBuffer, 32); - else - DumpPacket(pack); -#endif -#if TCPN_LOG_PACKETS >= 3 - DumpPacket(pack); -#endif - } -#endif - ServerSendQueuePushEnd((uchar**) &tnps, tnps->size); - } - } - return true; -} - -bool TCPConnection::SendPacket(TCPNetPacket_Struct* tnps) { - LockMutex lock(&MState); - if (RemoteID) - return false; - if (!Connected()) - return false; - eTCPMode tmp = GetMode(); - if (tmp == modeTransition) { - TCPNetPacket_Struct* tnps2 = (TCPNetPacket_Struct*) new uchar[tnps->size]; - memcpy(tnps2, tnps, tnps->size); - InModeQueuePush(tnps2); - return true; - } - if (GetMode() != modePacket) - return false; -#if TCPN_LOG_PACKETS >= 1 - if (tnps && tnps->opcode != 0) { - struct in_addr in; - in.s_addr = GetrIP(); - CoutTimestamp(true); - cout << ": Logging outgoing TCP NetPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << tnps->opcode << dec << ", size: " << setw(5) << setfill(' ') << tnps->size << " " << inet_ntoa(in) << ":" << GetrPort(); - if (pOldFormat) - cout << " (OldFormat)"; - cout << endl; -#if TCPN_LOG_PACKETS == 2 - if (tnps->size >= 32) - DumpPacket((uchar*) tnps, 32); - else - DumpPacket((uchar*) tnps, tnps->size); -#endif -#if TCPN_LOG_PACKETS >= 3 - DumpPacket((uchar*) tnps, tnps->size); -#endif - } -#endif - ServerSendQueuePushEnd((const uchar*) tnps, tnps->size); - return true; -} - -bool TCPConnection::Send(const uchar* data, sint32 size) { - if (!Connected()) - return false; - if (GetMode() != modeConsole) - return false; - if (!size) - return true; - ServerSendQueuePushEnd(data, size); - return true; -} - -void TCPConnection::InModeQueuePush(TCPNetPacket_Struct* tnps) { - MSendQueue.lock(); - InModeQueue.push(tnps); - MSendQueue.unlock(); -} - -void TCPConnection::ServerSendQueuePushEnd(const uchar* data, sint32 size) { - MSendQueue.lock(); - if (sendbuf == 0) { - sendbuf = new uchar[size]; - sendbuf_size = size; - sendbuf_used = 0; - } - else if (size > (sendbuf_size - sendbuf_used)) { - sendbuf_size += size + 1024; - uchar* tmp = new uchar[sendbuf_size]; - memcpy(tmp, sendbuf, sendbuf_used); - safe_delete_array(sendbuf); - sendbuf = tmp; - } - memcpy(&sendbuf[sendbuf_used], data, size); - sendbuf_used += size; - MSendQueue.unlock(); -} - -void TCPConnection::ServerSendQueuePushEnd(uchar** data, sint32 size) { - MSendQueue.lock(); - if (sendbuf == 0) { - sendbuf = *data; - sendbuf_size = size; - sendbuf_used = size; - MSendQueue.unlock(); - *data = 0; - return; - } - if (size > (sendbuf_size - sendbuf_used)) { - sendbuf_size += size; - uchar* tmp = new uchar[sendbuf_size]; - memcpy(tmp, sendbuf, sendbuf_used); - safe_delete_array(sendbuf); - sendbuf = tmp; - } - memcpy(&sendbuf[sendbuf_used], *data, size); - sendbuf_used += size; - MSendQueue.unlock(); - delete[] (TCPNetPacket_Struct*)*data; -} - -void TCPConnection::ServerSendQueuePushFront(uchar* data, sint32 size) { - MSendQueue.lock(); - if (sendbuf == 0) { - sendbuf = new uchar[size]; - sendbuf_size = size; - sendbuf_used = 0; - } - else if (size > (sendbuf_size - sendbuf_used)) { - sendbuf_size += size; - uchar* tmp = new uchar[sendbuf_size]; - memcpy(&tmp[size], sendbuf, sendbuf_used); - safe_delete_array(sendbuf); - sendbuf = tmp; - } - memcpy(sendbuf, data, size); - sendbuf_used += size; - MSendQueue.unlock(); -} - -bool TCPConnection::ServerSendQueuePop(uchar** data, sint32* size) { - bool ret; - if (!MSendQueue.trylock()) - return false; - if (sendbuf) { - *data = sendbuf; - *size = sendbuf_used; - sendbuf = 0; - ret = true; - } - else { - ret = false; - } - MSendQueue.unlock(); - return ret; -} - -ServerPacket* TCPConnection::PopPacket() { - ServerPacket* ret; - if (!MOutQueueLock.trylock()) - return 0; - ret = OutQueue.pop(); - MOutQueueLock.unlock(); - return ret; -} - -char* TCPConnection::PopLine() { - char* ret; - if (!MOutQueueLock.trylock()) - return 0; - ret = (char*) LineOutQueue.pop(); - MOutQueueLock.unlock(); - return ret; -} - -void TCPConnection::OutQueuePush(ServerPacket* pack) { - MOutQueueLock.lock(); - OutQueue.push(pack); - MOutQueueLock.unlock(); -} - -void TCPConnection::LineOutQueuePush(char* line) { -#if defined(GOTFRAGS) && 0 - if (strcmp(line, "**CRASHME**") == 0) { - int i = 0; - cout << (5 / i) << endl; - } -#endif - if (strcmp(line, "**PACKETMODE**") == 0) { - MSendQueue.lock(); - safe_delete_array(sendbuf); - if (TCPMode == modeConsole) - Send((const uchar*) "\0**PACKETMODE**\r", 16); - TCPMode = modePacket; - TCPNetPacket_Struct* tnps = 0; - while ((tnps = InModeQueue.pop())) { - SendPacket(tnps); - safe_delete_array(tnps); - } - MSendQueue.unlock(); - safe_delete_array(line); - return; - } - MOutQueueLock.lock(); - LineOutQueue.push(line); - MOutQueueLock.unlock(); -} - -void TCPConnection::Disconnect(bool iSendRelayDisconnect) { - if (connection_socket != INVALID_SOCKET && connection_socket != 0) { - MState.lock(); - if (pState == TCPS_Connected || pState == TCPS_Disconnecting || pState == TCPS_Disconnected) - SendData(); - pState = TCPS_Closing; - MState.unlock(); - shutdown(connection_socket, 0x01); - shutdown(connection_socket, 0x00); -#ifdef WIN32 - closesocket(connection_socket); -#else - close(connection_socket); -#endif - connection_socket = 0; - rIP = 0; - rPort = 0; - ClearBuffers(); - } - SetState(TCPS_Ready); - if (RelayLink) { - RelayLink->RemoveRelay(this, iSendRelayDisconnect); - RelayLink = 0; - } -} - -bool TCPConnection::GetAsyncConnect() { - bool ret; - MAsyncConnect.lock(); - ret = pAsyncConnect; - MAsyncConnect.unlock(); - return ret; -} - -bool TCPConnection::SetAsyncConnect(bool iValue) { - bool ret; - MAsyncConnect.lock(); - ret = pAsyncConnect; - pAsyncConnect = iValue; - MAsyncConnect.unlock(); - return ret; -} - -void TCPConnection::AsyncConnect(char* irAddress, int16 irPort) { - if (ConnectionType != Outgoing) { - // If this code runs, we got serious problems - // Crash and burn. - ThrowError("TCPConnection::AsyncConnect() call on a Incomming connection object!"); - return; - } - if (GetState() != TCPS_Ready) - return; - MAsyncConnect.lock(); - if (pAsyncConnect) { - MAsyncConnect.unlock(); - return; - } - pAsyncConnect = true; - safe_delete_array(charAsyncConnect); - charAsyncConnect = new char[strlen(irAddress) + 1]; - strcpy(charAsyncConnect, irAddress); - rPort = irPort; - MAsyncConnect.unlock(); - if (!pRunLoop) { - pRunLoop = true; -#ifdef WIN32 - _beginthread(TCPConnectionLoop, 0, this); -#else - pthread_t thread; - pthread_create(&thread, NULL, TCPConnectionLoop, this); - pthread_detach(thread); -#endif - } - return; -} - -void TCPConnection::AsyncConnect(int32 irIP, int16 irPort) { - if (ConnectionType != Outgoing) { - // If this code runs, we got serious problems - // Crash and burn. - ThrowError("TCPConnection::AsyncConnect() call on a Incomming connection object!"); - return; - } - if (GetState() != TCPS_Ready) - return; - MAsyncConnect.lock(); - if (pAsyncConnect) { - MAsyncConnect.unlock(); - return; - } - pAsyncConnect = true; - safe_delete(charAsyncConnect); - rIP = irIP; - rPort = irPort; - MAsyncConnect.unlock(); - if (!pRunLoop) { - pRunLoop = true; -#ifdef WIN32 - _beginthread(TCPConnectionLoop, 0, this); -#else - pthread_t thread; - pthread_create(&thread, NULL, TCPConnectionLoop, this); - pthread_detach(thread); -#endif - } - return; -} - -bool TCPConnection::Connect(char* irAddress, int16 irPort, char* errbuf) { - if (errbuf) - errbuf[0] = 0; - int32 tmpIP = ResolveIP(irAddress); - if (!tmpIP) { - if (errbuf) { -#ifdef WIN32 - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error: %i", WSAGetLastError()); -#else - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Couldnt resolve hostname. Error #%i: %s", errno, strerror(errno)); -#endif - } - return false; - } - return Connect(tmpIP, irPort, errbuf); -} - -bool TCPConnection::Connect(int32 in_ip, int16 in_port, char* errbuf) { - if (errbuf) - errbuf[0] = 0; - if (ConnectionType != Outgoing) { - // If this code runs, we got serious problems - // Crash and burn. - ThrowError("TCPConnection::Connect() call on a Incomming connection object!"); - return false; - } - MState.lock(); - if (pState == TCPS_Ready) { - pState = TCPS_Connecting; - } - else { - MState.unlock(); - SetAsyncConnect(false); - return false; - } - MState.unlock(); - if (!pRunLoop) { - pRunLoop = true; -#ifdef WIN32 - _beginthread(TCPConnectionLoop, 0, this); -#else - pthread_t thread; - pthread_create(&thread, NULL, TCPConnectionLoop, this); - pthread_detach(thread); -#endif - } - - connection_socket = INVALID_SOCKET; - struct sockaddr_in server_sin; - // struct in_addr in; - - if ((connection_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET || connection_socket == 0) { -#ifdef WIN32 - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %i", WSAGetLastError()); -#else - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): Allocating socket failed. Error: %s", strerror(errno)); -#endif - SetState(TCPS_Ready); - SetAsyncConnect(false); - return false; - } - server_sin.sin_family = AF_INET; - server_sin.sin_addr.s_addr = in_ip; - server_sin.sin_port = htons(in_port); - - // Establish a connection to the server socket. -#ifdef WIN32 - if (connect(connection_socket, (PSOCKADDR) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %i", WSAGetLastError()); - closesocket(connection_socket); - connection_socket = 0; - SetState(TCPS_Ready); - SetAsyncConnect(false); - return false; - } -#else - if (connect(connection_socket, (struct sockaddr *) &server_sin, sizeof (server_sin)) == SOCKET_ERROR) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::Connect(): connect() failed. Error: %s", strerror(errno)); - close(connection_socket); - connection_socket = 0; - SetState(TCPS_Ready); - SetAsyncConnect(false); - return false; - } -#endif - int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k - setsockopt(connection_socket, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize)); -#ifdef WIN32 - unsigned long nonblocking = 1; - ioctlsocket(connection_socket, FIONBIO, &nonblocking); -#else - fcntl(connection_socket, F_SETFL, O_NONBLOCK); -#endif - - SetEcho(false); - MSendQueue.lock(); - ClearBuffers(); - TCPMode = modePacket; - - MSendQueue.unlock(); - - rIP = in_ip; - rPort = in_port; - SetState(TCPS_Connected); - SetAsyncConnect(false); - return true; -} - -void TCPConnection::ClearBuffers() { - LockMutex lock1(&MSendQueue); - LockMutex lock2(&MOutQueueLock); - LockMutex lock3(&MRunLoop); - LockMutex lock4(&MState); - safe_delete_array(recvbuf); - safe_delete_array(sendbuf); - ServerPacket* pack = 0; - while ((pack = PopPacket())) - safe_delete(pack); - TCPNetPacket_Struct* tnps = 0; - while ((tnps = InModeQueue.pop())) - safe_delete(tnps); - char* line = 0; - while ((line = LineOutQueue.pop())) - safe_delete_array(line); - keepalive_timer->Start(); - timeout_timer->Start(); -} - -bool TCPConnection::CheckNetActive() { - MState.lock(); - if (pState == TCPS_Connected || pState == TCPS_Disconnecting) { - MState.unlock(); - return true; - } - MState.unlock(); - return false; -} - -bool TCPConnection::Process() { - char errbuf[TCPConnection_ErrorBufferSize]; - if (!CheckNetActive()) { - if (ConnectionType == Outgoing) { - if (GetAsyncConnect()) { - if (charAsyncConnect) - rIP = ResolveIP(charAsyncConnect); - Connect(rIP, rPort); - } - } - if (GetState() == TCPS_Disconnected) { - Disconnect(); - return false; - } - else if (GetState() == TCPS_Connecting) - return true; - else - return false; - } - if (!SendData(errbuf)) { - struct in_addr in; - in.s_addr = GetrIP(); - cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl; - return false; - } - if (!Connected()) - return false; - if (!RecvData(errbuf)) { - struct in_addr in; - in.s_addr = GetrIP(); - cout << inet_ntoa(in) << ":" << GetrPort() << ": " << errbuf << endl; - return false; - } - return true; -} - -bool TCPConnection::RecvData(char* errbuf) { - if (errbuf) - errbuf[0] = 0; - if (!Connected()) { - return false; - } - - int status = 0; - if (recvbuf == 0) { - recvbuf = new uchar[5120]; - recvbuf_size = 5120; - recvbuf_used = 0; - recvbuf_echo = 0; - } - else if ((recvbuf_size - recvbuf_used) < 2048) { - uchar* tmpbuf = new uchar[recvbuf_size + 5120]; - memcpy(tmpbuf, recvbuf, recvbuf_used); - recvbuf_size += 5120; - safe_delete_array(recvbuf); - recvbuf = tmpbuf; - if (recvbuf_size >= MaxTCPReceiveBufferSize) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): recvbuf_size >= MaxTCPReceiveBufferSize"); - return false; - } - } - - status = recv(connection_socket, (char *) &recvbuf[recvbuf_used], (recvbuf_size - recvbuf_used), 0); - if (status >= 1) { -#if TCPN_LOG_RAW_DATA_IN >= 1 - struct in_addr in; - in.s_addr = GetrIP(); - CoutTimestamp(true); - cout << ": Read " << status << " bytes from network. (recvbuf_used = " << recvbuf_used << ") " << inet_ntoa(in) << ":" << GetrPort(); - if (pOldFormat) - cout << " (OldFormat)"; - cout << endl; -#if TCPN_LOG_RAW_DATA_IN == 2 - sint32 tmp = status; - if (tmp > 32) - tmp = 32; - DumpPacket(&recvbuf[recvbuf_used], status); -#elif TCPN_LOG_RAW_DATA_IN >= 3 - DumpPacket(&recvbuf[recvbuf_used], status); -#endif -#endif - recvbuf_used += status; - timeout_timer->Start(); - if (!ProcessReceivedData(errbuf)) - return false; - } - else if (status == SOCKET_ERROR) { -#ifdef WIN32 - if (!(WSAGetLastError() == WSAEWOULDBLOCK)) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %i", WSAGetLastError()); - return false; - } -#else - if (!(errno == EWOULDBLOCK)) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Error: %s", strerror(errno)); - return false; - } -#endif - } - if ((TCPMode == modePacket || TCPMode == modeTransition) && timeout_timer->Check()) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::RecvData(): Connection timeout"); - return false; - } - - return true; -} - - -bool TCPConnection::GetEcho() { - bool ret; - MEcho.lock(); - ret = pEcho; - MEcho.unlock(); - return ret; -} - -void TCPConnection::SetEcho(bool iValue) { - MEcho.lock(); - pEcho = iValue; - MEcho.unlock(); -} - -bool TCPConnection::ProcessReceivedData(char* errbuf) { - if (errbuf) - errbuf[0] = 0; - if (!recvbuf) - return true; - if (TCPMode == modePacket) { - //if (pOldFormat) - // return ProcessReceivedDataAsOldPackets(errbuf); - //else - return ProcessReceivedDataAsPackets(errbuf); - } - else { -#if TCPN_DEBUG_Console >= 4 - if (recvbuf_used) { - cout << "Starting Processing: recvbuf=" << recvbuf_used << endl; - DumpPacket(recvbuf, recvbuf_used); - } -#endif - for (int i=0; i < recvbuf_used; i++) { - if (GetEcho() && i >= recvbuf_echo) { - Send(&recvbuf[i], 1); - recvbuf_echo = i + 1; - } - switch(recvbuf[i]) { - case 0: { // 0 is the code for clear buffer - if (i==0) { - recvbuf_used--; - recvbuf_echo--; - memcpy(recvbuf, &recvbuf[1], recvbuf_used); - i = -1; - } else { - if (i == recvbuf_used) { - safe_delete_array(recvbuf); - i = -1; - } - else { - uchar* tmpdel = recvbuf; - recvbuf = new uchar[recvbuf_size]; - memcpy(recvbuf, &tmpdel[i+1], recvbuf_used-i); - recvbuf_used -= i + 1; - recvbuf_echo -= i + 1; - safe_delete(tmpdel); - i = -1; - } - } -#if TCPN_DEBUG_Console >= 5 - cout << "Removed 0x00" << endl; - if (recvbuf_used) { - cout << "recvbuf left: " << recvbuf_used << endl; - DumpPacket(recvbuf, recvbuf_used); - } - else - cout << "recbuf left: None" << endl; -#endif - break; - } - case 10: - case 13: // newline marker - { - if (i==0) { // empty line - recvbuf_used--; - recvbuf_echo--; - memcpy(recvbuf, &recvbuf[1], recvbuf_used); - i = -1; - } else { - char* line = new char[i+1]; - memset(line, 0, i+1); - memcpy(line, recvbuf, i); -#if TCPN_DEBUG_Console >= 3 - cout << "Line Out: " << endl; - DumpPacket((uchar*) line, i); -#endif - //line[i] = 0; - uchar* tmpdel = recvbuf; - recvbuf = new uchar[recvbuf_size]; - recvbuf_used -= i+1; - recvbuf_echo -= i+1; - memcpy(recvbuf, &tmpdel[i+1], recvbuf_used); -#if TCPN_DEBUG_Console >= 5 - cout << "i+1=" << i+1 << endl; - if (recvbuf_used) { - cout << "recvbuf left: " << recvbuf_used << endl; - DumpPacket(recvbuf, recvbuf_used); - } - else - cout << "recbuf left: None" << endl; -#endif - safe_delete(tmpdel); - if (strlen(line) > 0) - LineOutQueuePush(line); - else - safe_delete_array(line); - if (TCPMode == modePacket) { - return ProcessReceivedDataAsPackets(errbuf); - } - i = -1; - } - break; - } - case 8: // backspace - { - if (i==0) { // nothin to backspace - recvbuf_used--; - recvbuf_echo--; - memcpy(recvbuf, &recvbuf[1], recvbuf_used); - i = -1; - } else { - uchar* tmpdel = recvbuf; - recvbuf = new uchar[recvbuf_size]; - memcpy(recvbuf, tmpdel, i-1); - memcpy(&recvbuf[i-1], &tmpdel[i+1], recvbuf_used-i); - recvbuf_used -= 2; - recvbuf_echo -= 2; - safe_delete(tmpdel); - i -= 2; - } - break; - } - } - } - if (recvbuf_used < 0) - safe_delete_array(recvbuf); - } - return true; -} - -bool TCPConnection::ProcessReceivedDataAsPackets(char* errbuf) { - if (errbuf) - errbuf[0] = 0; - sint32 base = 0; - sint32 size = 0; - uchar* buffer; - sint32 sizeReq = sizeof(TCPNetPacket_Struct); - ServerPacket* pack = 0; - while ((recvbuf_used - base) >= size) { - TCPNetPacket_Struct* tnps = (TCPNetPacket_Struct*) &recvbuf[base]; - buffer = tnps->buffer; - size = tnps->size; - - if (size < sizeReq || recvbuf_used < sizeReq || size >= MaxTCPReceiveBufferSize) { -#if TCPN_DEBUG_Memory >= 1 - cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBufferSize" << endl; -#endif - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::ProcessReceivedDataAsPackets(): size provided %i, recvbuf_used %i, checks failed: struct_size < %i || recvbuf_used < sizeReq || size >= MaxTCPReceiveBufferSize", size, recvbuf_used, sizeReq); - return false; - } - if ((recvbuf_used - base) >= size) { - // ok, we got enough data to make this packet! - safe_delete(pack); - pack = new ServerPacket; - pack->size = size - sizeof(TCPNetPacket_Struct); - // read headers - pack->opcode = tnps->opcode; - if (tnps->flags.compressed) { - sizeReq += 4; - if(size < sizeReq || recvbuf_used < sizeReq) - { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::ProcessReceivedDataAsPackets(Flags.Compressed): size provided %i, recvbuf_used %i, checks failed: struct_size < %i || recvbuf_used < sizeReq", size, recvbuf_used, sizeReq); - safe_delete(pack); - return false; - } - pack->compressed = true; - pack->InflatedSize = *((sint32*)buffer); - pack->size -= 4; - buffer += 4; - } - if (tnps->flags.destination) { - sizeReq += 4; - if(size < sizeReq || recvbuf_used < sizeReq) - { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::ProcessReceivedDataAsPackets(Flags.Destination): size provided %i, recvbuf_used %i, checks failed: struct_size < %i || recvbuf_used < sizeReq", size, recvbuf_used, sizeReq); - safe_delete(pack); - return false; - } - pack->destination = *((sint32*)buffer); - pack->size -= 4; - buffer += 4; - } - // end read headers - if (pack->size > 0) { - if (tnps->flags.compressed) { - // Lets decompress the packet here - pack->compressed = false; - if(pack->InflatedSize < MaxTCPReceiveBufferSize) - { - pack->pBuffer = new uchar[pack->InflatedSize]; - pack->size = InflatePacket(buffer, pack->size, pack->pBuffer, pack->InflatedSize); - if(!pack->size) - { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::ProcessReceivedDataAsPackets(InflatePacket): size provided %i, recvbuf_used: %i, sizeReq: %i, could not inflate packet", size, recvbuf_used, sizeReq); - - safe_delete(pack); - return false; - } - } - else - { - cout << "Invalid inflated packet." << endl; - safe_delete(pack); - return false; - } - } - else { - pack->pBuffer = new uchar[pack->size]; - memcpy(pack->pBuffer, buffer, pack->size); - } - } - if (pack->opcode == 0) { - if (pack->size) { -#if TCPN_DEBUG >= 2 - cout << "Received TCP Network layer packet" << endl; -#endif - ProcessNetworkLayerPacket(pack); - } -#if TCPN_DEBUG >= 5 - else { - cout << "Received TCP keepalive packet. (opcode=0)" << endl; - } -#endif - } - else { -#if TCPN_LOG_PACKETS >= 1 - if (pack && pack->opcode != 0) { - struct in_addr in; - in.s_addr = GetrIP(); - CoutTimestamp(true); - cout << ": Logging incoming TCP packet. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << endl; -#if TCPN_LOG_PACKETS == 2 - if (pack->size >= 32) - DumpPacket(pack->pBuffer, 32); - else - DumpPacket(pack); -#endif -#if TCPN_LOG_PACKETS >= 3 - DumpPacket(pack); -#endif - } -#endif - if (RelayServer && Server && pack->destination) { - TCPConnection* con = Server->GetConnection(pack->destination); - if (!con) { -#if TCPN_DEBUG >= 1 - cout << "Error relaying packet: con = 0" << endl; -#endif - } - else{ - con->OutQueuePush(pack); - pack = 0; - } - } - else{ - OutQueuePush(pack); - pack = 0; - } - } - base += size; - size = 7; - } - } - safe_delete(pack); - if (base != 0) { - if (base >= recvbuf_used) { - safe_delete_array(recvbuf); - } - else { - uchar* tmpbuf = new uchar[recvbuf_size - base]; - memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base); - safe_delete_array(recvbuf); - recvbuf = tmpbuf; - recvbuf_used -= base; - recvbuf_size -= base; - } - } - return true; -} - -bool TCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) { - sint32 base = 0; - sint32 size = 4; - uchar* buffer; - ServerPacket* pack = 0; - while ((recvbuf_used - base) >= size) { - buffer = &recvbuf[base]; - memcpy(&size, &buffer[2], 2); - if (size >= MaxTCPReceiveBufferSize) { -#if TCPN_DEBUG_Memory >= 1 - cout << "TCPConnection[" << GetID() << "]::ProcessReceivedDataAsPackets(): size[" << size << "] >= MaxTCPReceiveBufferSize" << endl; -#endif - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::ProcessReceivedDataAsPackets(): size >= MaxTCPReceiveBufferSize"); - return false; - } - if ((recvbuf_used - base) >= size) { - // ok, we got enough data to make this packet! - pack = new ServerPacket; - memcpy(&pack->opcode, &buffer[0], 2); - pack->size = size - 4; - - LogWrite(MISC__TODO, 1, "TODO", "Checksum or size check or something similar\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__); - /* - if () { // TODO: Checksum or size check or something similar - // Datastream corruption, get the hell outta here! - delete pack; - return false; - } - */ - - if (pack->size > 0) { - pack->pBuffer = new uchar[pack->size]; - memcpy(pack->pBuffer, &buffer[4], pack->size); - } - if (pack->opcode == 0) { - // keepalive, no need to process - safe_delete(pack); - } - else { -#if TCPN_LOG_PACKETS >= 1 - if (pack && pack->opcode != 0) { - struct in_addr in; - in.s_addr = GetrIP(); - CoutTimestamp(true); - cout << ": Logging incoming TCP OldPacket. OPCode: 0x" << hex << setw(4) << setfill('0') << pack->opcode << dec << ", size: " << setw(5) << setfill(' ') << pack->size << " " << inet_ntoa(in) << ":" << GetrPort() << endl; -#if TCPN_LOG_PACKETS == 2 - if (pack->size >= 32) - DumpPacket(pack->pBuffer, 32); - else - DumpPacket(pack); -#endif -#if TCPN_LOG_PACKETS >= 3 - DumpPacket(pack); -#endif - } -#endif - OutQueuePush(pack); - } - base += size; - size = 4; - } - } - if (base != 0) { - if (base >= recvbuf_used) { - safe_delete_array(recvbuf); - } - else { - uchar* tmpbuf = new uchar[recvbuf_size - base]; - memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base); - safe_delete_array(recvbuf); - recvbuf = tmpbuf; - recvbuf_used -= base; - recvbuf_size -= base; - } - } - return true; -} - -void TCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) { - int8 opcode = pack->pBuffer[0]; - - - /** disabling RELAY capabilities, this functionality is poorly implemented - even if such a feature needs to be re-used need authentication BEFORE allowing relay to take place - secondly we need to protect the LS accepting new connections as bogus data can be passed to open - fake TCP connections - opcode 0 is OK, that is Keep-Alive - **/ - - if (opcode > 0) - { - Disconnect(); - return; - } - - int8* data = &pack->pBuffer[1]; - switch (opcode) { - case 0: { - break; - } - case 1: { // Switch to RelayServer mode - if (pack->size != 1) { - SendNetErrorPacket("New RelayClient: wrong size, expected 1"); - break; - } - if (RelayServer) { - SendNetErrorPacket("Switch to RelayServer mode when already in RelayServer mode"); - break; - } - if (RemoteID) { - SendNetErrorPacket("Switch to RelayServer mode by a Relay Client"); - break; - } - if (ConnectionType != Incomming) { - SendNetErrorPacket("Switch to RelayServer mode on outgoing connection"); - break; - } -#if TCPC_DEBUG >= 3 - struct in_addr in; - in.s_addr = GetrIP(); - cout << "Switching to RelayServer mode: " << inet_ntoa(in) << ":" << GetPort() << endl; -#endif - RelayServer = true; - break; - } - case 2: { // New Relay Client - if (!RelayServer) { - SendNetErrorPacket("New RelayClient when not in RelayServer mode"); - break; - } - if (pack->size != 11) { - SendNetErrorPacket("New RelayClient: wrong size, expected 11"); - break; - } - if (ConnectionType != Incomming) { - SendNetErrorPacket("New RelayClient: illegal on outgoing connection"); - break; - } - TCPConnection* con = new TCPConnection(Server, this, *((int32*) data), *((int32*) &data[4]), *((int16*) &data[8])); - Server->AddConnection(con); - RelayCount++; - break; - } - case 3: { // Delete Relay Client - if (!RelayServer) { - SendNetErrorPacket("Delete RelayClient when not in RelayServer mode"); - break; - } - if (pack->size != 5) { - SendNetErrorPacket("Delete RelayClient: wrong size, expected 5"); - break; - } - TCPConnection* con = Server->GetConnection(*((int32*)data)); - if (con) { - if (ConnectionType == Incomming) { - if (con->GetRelayLink() != this) { - SendNetErrorPacket("Delete RelayClient: RelayLink != this"); - break; - } - } - con->Disconnect(false); - } - break; - } - case 255: { -#if TCPC_DEBUG >= 1 - struct in_addr in; - in.s_addr = GetrIP(); - cout "Received NetError: '"; - if (pack->size > 1) - cout << (char*) data; - cout << "': " << inet_ntoa(in) << ":" << GetPort() << endl; -#endif - break; - } - } -} - -void TCPConnection::SendNetErrorPacket(const char* reason) { -#if TCPC_DEBUG >= 1 - struct in_addr in; - in.s_addr = GetrIP(); - cout "NetError: '"; - if (reason) - cout << reason; - cout << "': " << inet_ntoa(in) << ":" << GetPort() << endl; -#endif - ServerPacket* pack = new ServerPacket(0); - pack->size = 1; - if (reason) - pack->size += strlen(reason) + 1; - pack->pBuffer = new uchar[pack->size]; - memset(pack->pBuffer, 0, pack->size); - pack->pBuffer[0] = 255; - strcpy((char*) &pack->pBuffer[1], reason); - SendPacket(pack); - safe_delete(pack); -} - -void TCPConnection::RemoveRelay(TCPConnection* relay, bool iSendRelayDisconnect) { - if (iSendRelayDisconnect) { - ServerPacket* pack = new ServerPacket(0, 5); - pack->pBuffer[0] = 3; - *((int32*) &pack->pBuffer[1]) = relay->GetRemoteID(); - SendPacket(pack); - safe_delete(pack); - } - RelayCount--; -} - -bool TCPConnection::SendData(char* errbuf) { - if (errbuf) - errbuf[0] = 0; - /************ Get first send packet on queue and send it! ************/ - uchar* data = 0; - sint32 size = 0; - int status = 0; - if (ServerSendQueuePop(&data, &size)) { -#ifdef WIN32 - status = send(connection_socket, (const char *) data, size, 0); -#else - status = send(connection_socket, data, size, MSG_NOSIGNAL); - if(errno==EPIPE) status = SOCKET_ERROR; -#endif - if (status >= 1) { -#if TCPN_LOG_RAW_DATA_OUT >= 1 - struct in_addr in; - in.s_addr = GetrIP(); - CoutTimestamp(true); - cout << ": Wrote " << status << " bytes to network. " << inet_ntoa(in) << ":" << GetrPort(); - if (pOldFormat) - cout << " (OldFormat)"; - cout << endl; -#if TCPN_LOG_RAW_DATA_OUT == 2 - sint32 tmp = status; - if (tmp > 32) - tmp = 32; - DumpPacket(data, status); -#elif TCPN_LOG_RAW_DATA_OUT >= 3 - DumpPacket(data, status); -#endif -#endif - keepalive_timer->Start(); - if (status < (signed)size) { -#if TCPN_LOG_RAW_DATA_OUT >= 1 - struct in_addr in; - in.s_addr = GetrIP(); - CoutTimestamp(true); - cout << ": Pushed " << (size - status) << " bytes back onto the send queue. " << inet_ntoa(in) << ":" << GetrPort(); - if (pOldFormat) - cout << " (OldFormat)"; - cout << endl; -#endif - // If there's network congestion, the number of bytes sent can be less than - // what we tried to give it... Push the extra back on the queue for later - ServerSendQueuePushFront(&data[status], size - status); - } - else if (status > (signed)size) { - ThrowError("TCPConnection::SendData(): WTF! status > size"); - return false; - } - // else if (status == size) {} - } - else { - ServerSendQueuePushFront(data, size); - } - - safe_delete_array(data); - if (status == SOCKET_ERROR) { -#ifdef WIN32 - if (WSAGetLastError() != WSAEWOULDBLOCK) -#else - if (errno != EWOULDBLOCK) -#endif - { - if (errbuf) { -#ifdef WIN32 - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %i", WSAGetLastError()); -#else - snprintf(errbuf, TCPConnection_ErrorBufferSize, "TCPConnection::SendData(): send(): Errorcode: %s", strerror(errno)); -#endif - } - return false; - } - } - } - if (TCPMode == modePacket && keepalive_timer->Check()) { - ServerPacket* pack = new ServerPacket(0, 0); - SendPacket(pack); - safe_delete(pack); -#if TCPN_DEBUG >= 5 - cout << "Sending TCP keepalive packet. (timeout=" << timeout_timer->GetRemainingTime() << " remaining)" << endl; -#endif - } - return true; -} - -ThreadReturnType TCPConnectionLoop(void* tmp) { -#ifdef WIN32 - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); -#endif - if (tmp == 0) { - ThrowError("TCPConnectionLoop(): tmp = 0!"); - THREAD_RETURN(NULL); - } - TCPConnection* tcpc = (TCPConnection*) tmp; - tcpc->MLoopRunning.lock(); - while (tcpc->RunLoop()) { - Sleep(LOOP_GRANULARITY); - if (tcpc->GetState() != TCPS_Ready) { - if (!tcpc->Process()) { - tcpc->Disconnect(); - } - } - else if (tcpc->GetAsyncConnect()) { - if (tcpc->charAsyncConnect) - tcpc->Connect(tcpc->charAsyncConnect, tcpc->GetrPort()); - else - tcpc->Connect(tcpc->GetrIP(), tcpc->GetrPort()); - tcpc->SetAsyncConnect(false); - } - else - Sleep(10); - } - tcpc->MLoopRunning.unlock(); - - THREAD_RETURN(NULL); -} - -bool TCPConnection::RunLoop() { - bool ret; - MRunLoop.lock(); - ret = pRunLoop; - MRunLoop.unlock(); - return ret; -} - - - - - -TCPServer::TCPServer(int16 in_port, bool iOldFormat) { - NextID = 1; - pPort = in_port; - sock = 0; - pOldFormat = iOldFormat; - list = new LinkedList; - pRunLoop = true; -#ifdef WIN32 - _beginthread(TCPServerLoop, 0, this); -#else - pthread_t thread; - pthread_create(&thread, NULL, &TCPServerLoop, this); - pthread_detach(thread); -#endif -} - -TCPServer::~TCPServer() { - MRunLoop.lock(); - pRunLoop = false; - MRunLoop.unlock(); - MLoopRunning.lock(); - MLoopRunning.unlock(); - - while (NewQueue.pop()); // the objects are deleted with the list, clear this queue so it doesnt try to delete them again - safe_delete(list); -} - -bool TCPServer::RunLoop() { - bool ret; - MRunLoop.lock(); - ret = pRunLoop; - MRunLoop.unlock(); - return ret; -} - -ThreadReturnType TCPServerLoop(void* tmp) { -#ifdef WIN32 - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); -#endif - if (tmp == 0) { - ThrowError("TCPServerLoop(): tmp = 0!"); - THREAD_RETURN(NULL); - } - TCPServer* tcps = (TCPServer*) tmp; - tcps->MLoopRunning.lock(); - while (tcps->RunLoop()) { - Sleep(SERVER_LOOP_GRANULARITY); - tcps->Process(); - } - tcps->MLoopRunning.unlock(); - - THREAD_RETURN(NULL); -} - -void TCPServer::Process() { - CheckInQueue(); - ListenNewConnections(); - LinkedListIterator iterator(*list); - - iterator.Reset(); - while(iterator.MoreElements()) { - if (iterator.GetData()->IsFree() && (!iterator.GetData()->CheckNetActive())) { -#if _DEBUG - LogWrite(NET__DEBUG, 0, "Net", "EQStream Connection deleted."); -#endif - iterator.RemoveCurrent(); - } - else { - if (!iterator.GetData()->Process()) - iterator.GetData()->Disconnect(); - iterator.Advance(); - } - } -} - -void TCPServer::ListenNewConnections() { - SOCKET tmpsock; - struct sockaddr_in from; - struct in_addr in; - unsigned int fromlen; - - TCPConnection* con; - - from.sin_family = AF_INET; - fromlen = sizeof(from); - LockMutex lock(&MSock); - if (!sock) - return; - - // Check for pending connects -#ifdef WIN32 - unsigned long nonblocking = 1; - while ((tmpsock = accept(sock, (struct sockaddr*) &from, (int *) &fromlen)) != INVALID_SOCKET) { - ioctlsocket (tmpsock, FIONBIO, &nonblocking); -#else - while ((tmpsock = accept(sock, (struct sockaddr*) &from, &fromlen)) != INVALID_SOCKET) { - fcntl(tmpsock, F_SETFL, O_NONBLOCK); -#endif - int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k - setsockopt(tmpsock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize)); - in.s_addr = from.sin_addr.s_addr; - - // New TCP connection - con = new TCPConnection(this, tmpsock, in.s_addr, ntohs(from.sin_port), pOldFormat); -#if TCPN_DEBUG >= 1 - cout << "New TCP connection: " << inet_ntoa(in) << ":" << con->GetrPort() << endl; -#endif - AddConnection(con); - } -} - -bool TCPServer::Open(int16 in_port, char* errbuf) { - if (errbuf) - errbuf[0] = 0; - LockMutex lock(&MSock); - if (sock != 0) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "Listening socket already open"); - return false; - } - if (in_port != 0) { - pPort = in_port; - } - -#ifdef WIN32 - SOCKADDR_IN address; - unsigned long nonblocking = 1; -#else - struct sockaddr_in address; -#endif - int reuse_addr = 1; - - // Setup internet address information. - // This is used with the bind() call - memset((char *) &address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_port = htons(pPort); - address.sin_addr.s_addr = htonl(INADDR_ANY); - - // Setting up TCP port for new TCP connections - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "socket(): INVALID_SOCKET"); - return false; - } - - // Quag: dont think following is good stuff for TCP, good for UDP - // Mis: SO_REUSEADDR shouldn't be a problem for tcp--allows you to restart - // without waiting for conns in TIME_WAIT to die - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr)); - - - if (::bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) { -#ifdef WIN32 - closesocket(sock); -#else - close(sock); -#endif - sock = 0; - if (errbuf) - sprintf(errbuf, "bind(): <0"); - return false; - } - - int bufsize = 64 * 1024; // 64kbyte recieve buffer, up from default of 8k - setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*) &bufsize, sizeof(bufsize)); -#ifdef WIN32 - ioctlsocket (sock, FIONBIO, &nonblocking); -#else - fcntl(sock, F_SETFL, O_NONBLOCK); -#endif - - if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { -#ifdef WIN32 - closesocket(sock); - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "listen() failed, Error: %d", WSAGetLastError()); -#else - close(sock); - if (errbuf) - snprintf(errbuf, TCPConnection_ErrorBufferSize, "listen() failed, Error: %s", strerror(errno)); -#endif - sock = 0; - return false; - } - - return true; -} - -void TCPServer::Close() { - LockMutex lock(&MSock); - if (sock) { -#ifdef WIN32 - closesocket(sock); -#else - close(sock); -#endif - } - sock = 0; -} - -bool TCPServer::IsOpen() { - MSock.lock(); - bool ret = (bool) (sock != 0); - MSock.unlock(); - return ret; -} - -TCPConnection* TCPServer::NewQueuePop() { - TCPConnection* ret; - MNewQueue.lock(); - ret = NewQueue.pop(); - MNewQueue.unlock(); - return ret; -} - -void TCPServer::AddConnection(TCPConnection* con) { - list->Append(con); - MNewQueue.lock(); - NewQueue.push(con); - MNewQueue.unlock(); -} - -TCPConnection* TCPServer::GetConnection(int32 iID) { - LinkedListIterator iterator(*list); - - iterator.Reset(); - while(iterator.MoreElements()) { - if (iterator.GetData()->GetID() == iID) - return iterator.GetData(); - iterator.Advance(); - } - return 0; -} - -void TCPServer::SendPacket(ServerPacket* pack) { - TCPConnection::TCPNetPacket_Struct* tnps = TCPConnection::MakePacket(pack); - SendPacket(&tnps); -} - -void TCPServer::SendPacket(TCPConnection::TCPNetPacket_Struct** tnps) { - MInQueue.lock(); - InQueue.push(*tnps); - MInQueue.unlock(); - tnps = 0; -} - -void TCPServer::CheckInQueue() { - LinkedListIterator iterator(*list); - TCPConnection::TCPNetPacket_Struct* tnps = 0; - - while (( tnps = InQueuePop() )) { - iterator.Reset(); - while(iterator.MoreElements()) { - if (iterator.GetData()->GetMode() != modeConsole && iterator.GetData()->GetRemoteID() == 0) - iterator.GetData()->SendPacket(tnps); - iterator.Advance(); - } - safe_delete(tnps); - } -} - -TCPConnection::TCPNetPacket_Struct* TCPServer::InQueuePop() { - TCPConnection::TCPNetPacket_Struct* ret; - MInQueue.lock(); - ret = InQueue.pop(); - MInQueue.unlock(); - return ret; -} - - diff --git a/source/common/TCPConnection.h b/source/common/TCPConnection.h deleted file mode 100644 index ae47526..0000000 --- a/source/common/TCPConnection.h +++ /dev/null @@ -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 . -*/ -#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 -#else - #include - #include - #include - #include - #include - #include - #include - #include - #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 LineOutQueue; - MyQueue 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 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 NewQueue; - - void CheckInQueue(); - Mutex MInQueue; - TCPConnection::TCPNetPacket_Struct* InQueuePop(); - MyQueue InQueue; - - LinkedList* list; -}; -#endif diff --git a/source/common/database.cpp b/source/common/database.cpp deleted file mode 100644 index 9a88a5e..0000000 --- a/source/common/database.cpp +++ /dev/null @@ -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 . -*/ -#include "../common/debug.h" - -#include -using namespace std; -#include -#include -#include -#include -//#include -#include -#include -#include -#include - -// Disgrace: for windows compile -#ifdef WIN32 -#include -#include -#define snprintf _snprintf -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#else -#include "unix.h" -#include -#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 Database::GetVersions(){ - map 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 Database::GetOpcodes(int16 version){ - map 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>::iterator itr; - for (itr = asyncQueries.begin(); itr != asyncQueries.end(); itr++) - { - asyncQueriesMutex[itr->first]->writelock(); - deque 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(); - 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>::iterator itr = asyncQueries.find(queryid); - if (itr == asyncQueries.end()) - { - DBAsyncMutex.releasewritelock(); - return; - } - - asyncQueriesMutex[queryid]->writelock(); - deque 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::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>::iterator itr = asyncQueries.find(query->GetQueryID()); - asyncQueriesMutex[query->GetQueryID()]->writelock(); - - if ( itr != asyncQueries.end()) - itr->second.push_back(query); - else - { - deque 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::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::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::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::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::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 \ No newline at end of file diff --git a/source/common/database.h b/source/common/database.h deleted file mode 100644 index 4a5fbd2..0000000 --- a/source/common/database.h +++ /dev/null @@ -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 . -*/ -#ifndef EQ2EMU_DATABASE_H -#define EQ2EMU_DATABASE_H - -#ifdef WIN32 - #include - #include -#endif -#include - -#include "dbcore.h" -#include "types.h" -#include "linked_list.h" -#include "EQStream.h" -#include "MiscFunctions.h" -#include "Mutex.h" -#include -#include -#include - -using namespace std; -class Query; - -class Database : public DBcore -{ -public: - Database(); - ~Database(); - bool Init(bool silentLoad=false); - bool LoadVariables(); - void HandleMysqlError(int32 errnum); - map GetOpcodes(int16 version); - int32 AuthenticateWebUser(char* userName, char* passwd,int32* status = 0); - int32 NoAuthRoute(char* route); - map 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> asyncQueries; - map asyncQueriesMutex; - map dbInstances; - vector 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::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* 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 diff --git a/source/common/dbcore.cpp b/source/common/dbcore.cpp deleted file mode 100644 index e200e9d..0000000 --- a/source/common/dbcore.cpp +++ /dev/null @@ -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 . -*/ -#include "debug.h" - -#include -using namespace std; -#include -//#include -#include -#include "dbcore.h" -#include -#include -#include -#include "types.h" -#include "MiscFunctions.h" -#include "Log.h" - -#ifdef WIN32 - #define snprintf _snprintf - #define strncasecmp _strnicmp - #define strcasecmp _stricmp - #include -#else - #include "unix.h" - #include -#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; -} - diff --git a/source/common/dbcore.h b/source/common/dbcore.h deleted file mode 100644 index b6cbfd2..0000000 --- a/source/common/dbcore.h +++ /dev/null @@ -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 . -*/ -#ifndef DBCORE_H -#define DBCORE_H - -#ifdef WIN32 - #include - #include - //#include -#endif -#include -#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 - - diff --git a/source/common/debug.cpp b/source/common/debug.cpp deleted file mode 100644 index 3f2f98b..0000000 --- a/source/common/debug.cpp +++ /dev/null @@ -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 . -*/ - -/* - JA: File rendered obsolete (2011-08-12) - -#include "debug.h" - -#include -using namespace std; -#include -#include -#ifdef WIN32 - #include - - #define snprintf _snprintf - #define vsnprintf _vsnprintf - #define strncasecmp _strnicmp - #define strcasecmp _stricmp -#else - #include - #include - #include -#endif -#include "../common/MiscFunctions.h" - -EQEMuLog* LogFile = new EQEMuLog; -AutoDelete 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= 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) { - 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"<= 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= 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); - } -} -*/ \ No newline at end of file diff --git a/source/common/debug.h b/source/common/debug.h deleted file mode 100644 index 7422d5e..0000000 --- a/source/common/debug.h +++ /dev/null @@ -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 . -*/ -#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 - #include - #if (_MSC_VER < 1300) - #include - #include - #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 - #include -#endif - -#include "../common/Mutex.h" -#include -#include - - -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 diff --git a/source/common/linked_list.h b/source/common/linked_list.h deleted file mode 100644 index 023a9d2..0000000 --- a/source/common/linked_list.h +++ /dev/null @@ -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 . -*/ -#ifndef LINKEDLIST_H -#define LINKEDLIST_H - -#include "types.h" - -enum direction{FORWARD,BACKWARD}; - -template class LinkedListIterator; - -template -class ListElement -{ -private: - - TYPE data; - ListElement* next; - ListElement* prev; -public: - ListElement (); - ListElement (const TYPE&); - ListElement (const ListElement&); - - ~ListElement (); - - ListElement& operator= (const ListElement&); - - ListElement* GetLast () - { - ListElement* tmp = this; - while (tmp->GetNext()) { - tmp = tmp->GetNext(); - } - return tmp; - } - ListElement* GetNext () const { return next ; } - ListElement* 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* p ) - { - GetLast()->SetNext(p); - } - void SetNext (ListElement* n) { next = n ; } - void SetPrev (ListElement* p) { prev = p ; } - - void ReplaceData(const TYPE&); -}; - -template -class LinkedList -{ -private: - int32 count; - ListElement* first; - bool list_destructor_invoked; - -public: - - LinkedList(); - ~LinkedList(); - bool dont_delete; - LinkedList& operator= (const LinkedList&); - - 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; -}; - -template -class LinkedListIterator -{ -private: - LinkedList& list; - ListElement* current_element; - direction dir; - -public: - LinkedListIterator(LinkedList& 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 -void LinkedListIterator::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 -bool LinkedListIterator::MoreElements() -{ - if (current_element == 0) - return false; - return true; -} - -template -const TYPE& LinkedListIterator::GetData() -{ - return current_element->GetData(); -} - -template -void LinkedListIterator::MoveFirst() -{ - ListElement* prev = current_element->GetPrev(); - ListElement* 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 -void LinkedListIterator::MoveLast() -{ - ListElement* prev = current_element->GetPrev(); - ListElement* 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 -void LinkedListIterator::RemoveCurrent(bool DeleteData) -{ - ListElement* 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 -void LinkedListIterator::Replace(const TYPE& new_data) -{ - current_element->ReplaceData(new_data); -} - -template -void LinkedListIterator::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 -void LinkedListIterator::SetDir(direction d) -{ - dir = d; -} - -template -ListElement::ListElement(const TYPE& d) -{ - data = d; - next = 0; - prev = 0; -} - -template -ListElement::~ListElement() -{ -// cout << "ListElement::~ListElement()" << endl; - - if (data != 0) - safe_delete(data); - data = 0; - if (next != 0) - { - safe_delete(next); - next = 0; - } -} - -template -void ListElement::ReplaceData(const TYPE& new_data) -{ - if (data != 0) - safe_delete(data); - data = new_data; -} - -template -LinkedList::LinkedList() -{ - list_destructor_invoked = false; - first = 0; - count = 0; - dont_delete = false; -} - -template -LinkedList::~LinkedList() -{ - list_destructor_invoked = true; - if(!dont_delete) - Clear(); -} - -template -void LinkedList::Clear() { - while (first) { - ListElement* tmp = first; - first = tmp->GetNext(); - tmp->SetNext(0); - safe_delete(tmp); - } - ResetCount(); -} - -template -void LinkedList::Append(const TYPE& data) -{ - ListElement* new_element = new ListElement(data); - - if (first == 0) - { - first = new_element; - } - else - { - new_element->SetPrev(first->GetLast()); - first->SetLastNext(new_element); - } - count++; -} - -template -void LinkedList::Insert(const TYPE& data) -{ - ListElement* new_element = new ListElement(data); - - new_element->SetNext(first); - if (first != 0) - { - first->SetPrev(new_element); - } - first = new_element; - count++; -} - -template -TYPE LinkedList::Pop() { - TYPE ret = 0; - if (first) { - ListElement* 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 -TYPE LinkedList::PeekTop() { - if (first) - return first->GetData(); - return 0; -} - -#endif - - diff --git a/source/common/md5.cpp b/source/common/md5.cpp deleted file mode 100644 index 1244c8c..0000000 --- a/source/common/md5.cpp +++ /dev/null @@ -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 . -*/ -#include /* 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<>(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; -} diff --git a/source/common/md5.h b/source/common/md5.h deleted file mode 100644 index 6c54f94..0000000 --- a/source/common/md5.h +++ /dev/null @@ -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 . -*/ -#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 diff --git a/source/common/queue.h b/source/common/queue.h deleted file mode 100644 index e29ea05..0000000 --- a/source/common/queue.h +++ /dev/null @@ -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 . -*/ -#ifndef QUEUE_H -#define QUEUE_H - -template -class MyQueue; - -template -class MyQueueNode -{ -public: - MyQueueNode(T* data) - { - next = 0; - this->data = data; - } - - friend class MyQueue; - -private: - T* data; - MyQueueNode* next; -}; - -template -class MyQueue -{ -public: - MyQueue() - { - head = tail = 0; - } - ~MyQueue() { - clear(); - } - - void push(T* data) - { - if (head == 0) - { - tail = head = new MyQueueNode(data); - } - else - { - tail->next = new MyQueueNode(data); - tail = tail->next; - } - } - - T* pop() - { - if (head == 0) - { - return 0; - } - - T* data = head->data; - MyQueueNode* 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* d = head; - while(d != 0) { - count++; - d = d->next; - } - return(count); - } - -private: - MyQueueNode* head; - MyQueueNode* tail; -}; - -#endif diff --git a/source/common/sha512.cpp b/source/common/sha512.cpp deleted file mode 100644 index 10b9592..0000000 --- a/source/common/sha512.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include -#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); -} \ No newline at end of file diff --git a/source/common/sha512.h b/source/common/sha512.h deleted file mode 100644 index 72ce5a8..0000000 --- a/source/common/sha512.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef SHA512_H -#define SHA512_H -#include - -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 \ No newline at end of file diff --git a/source/common/string_util.cpp b/source/common/string_util.cpp deleted file mode 100644 index df3790d..0000000 --- a/source/common/string_util.cpp +++ /dev/null @@ -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 - -#ifdef _WINDOWS - #include - - #define snprintf _snprintf - #define strncasecmp _strnicmp - #define strcasecmp _stricmp - -#else - #include - #include -#include - -#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 split(std::string str_to_split, char delimiter) -{ - std::stringstream ss(str_to_split); - std::string item; - std::vector 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(::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 SplitString(const std::string &str, char delim) { - std::vector 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 src) -{ - if (src.empty()) { - return {}; - } - - std::ostringstream output; - std::vector::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& 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 'z') && - (text[charIndex] < 'A' || text[charIndex] > 'Z') && - (text[charIndex] < '0' || text[charIndex] > '9')) - return false; - } - - return true; -} diff --git a/source/common/string_util.h b/source/common/string_util.h deleted file mode 100644 index 037d6a2..0000000 --- a/source/common/string_util.h +++ /dev/null @@ -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 -#include -#include -#include -#include - -#ifndef _WIN32 -// this doesn't appear to affect linux-based systems..need feedback for _WIN64 -#include -#endif - -#ifdef _WINDOWS -#include -#include -#include -#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 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 src); - -/** - * @param str - * @param chars - * @return - */ -inline std::string <rim(std::string &str, const std::string &chars = "\t\n\v\f\r ") -{ - str.erase(0, str.find_first_not_of(chars)); - return str; -} - -/** - * @param str - * @param chars - * @return - */ -inline std::string &rtrim(std::string &str, const std::string &chars = "\t\n\v\f\r ") -{ - str.erase(str.find_last_not_of(chars) + 1); - return str; -} - -/** - * @param str - * @param chars - * @return - */ -inline std::string &trim(std::string &str, const std::string &chars = "\t\n\v\f\r ") -{ - return ltrim(rtrim(str, chars), chars); -} - -template -std::string implode(const std::string &glue, const std::pair &encapsulation, const std::vector &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 be included in whatever code file the invocation is made from (no header files) -template -std::vector join_pair(const std::string &glue, const std::pair &encapsulation, const std::vector> &src) -{ - if (src.empty()) { - return {}; - } - - std::vector output; - - for (const std::pair &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 be included in whatever code file the invocation is made from (no header files) -template -std::vector join_tuple(const std::string &glue, const std::pair &encapsulation, const std::vector> &src) -{ - if (src.empty()) { - return {}; - } - - std::vector output; - - for (const std::tuple &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 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& 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 diff --git a/source/common/timer.cpp b/source/common/timer.cpp deleted file mode 100644 index e9c08ef..0000000 --- a/source/common/timer.cpp +++ /dev/null @@ -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 . -*/ -#include "../common/debug.h" -// Disgrace: for windows compile -#ifndef WIN32 - #include -#else - #include -#endif - -#include -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; -} diff --git a/source/common/timer.h b/source/common/timer.h deleted file mode 100644 index a70a2d2..0000000 --- a/source/common/timer.h +++ /dev/null @@ -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 . -*/ -#ifndef TIMER_H -#define TIMER_H - -#include "types.h" -#include - -// Disgrace: for windows compile -#ifdef WIN32 - #include - #include - 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(clock::now() - start_time).count(); } -private: - std::chrono::time_point start_time; -}; - -#endif diff --git a/source/common/unix.cpp b/source/common/unix.cpp deleted file mode 100644 index 6476c3a..0000000 --- a/source/common/unix.cpp +++ /dev/null @@ -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 . -*/ -#include "unix.h" -#include -#include - -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; -} - - diff --git a/source/common/unix.h b/source/common/unix.h deleted file mode 100644 index 82560a1..0000000 --- a/source/common/unix.h +++ /dev/null @@ -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 . -*/ -#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 - -typedef int SOCKET; - -void Sleep(unsigned int x); -char* strupr(char* tmp); -char* strlwr(char* tmp); -#endif -#endif diff --git a/source/common/xmlParser.cpp b/source/common/xmlParser.cpp deleted file mode 100644 index e0f7f33..0000000 --- a/source/common/xmlParser.cpp +++ /dev/null @@ -1,2974 +0,0 @@ -/** - **************************************************************************** - *

XML.c - implementation file for 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 - * - * NOTE: - * - * If you add "#define STRICT_PARSING", on the first line of this file - * the parser will see the following XML-stream: - * some textother text - * as an error. Otherwise, this tring will be equivalent to: - * some textother text - * - * NOTE: - * - * If you add "#define APPROXIMATE_PARSING" on the first line of this file - * the parser will see the following XML-stream: - * - * - * - * as equivalent to the following XML-stream: - * - * - * - * This can be useful for badly-formed XML-streams but prevent the use - * of the following XML-stream (problem is: tags at contiguous levels - * have the same names): - * - * - * - * - * - * - * NOTE: - * - * If you add "#define _XMLPARSER_NO_MESSAGEBOX_" on the first line of this file - * the "openFileHelper" function will always display error messages inside the - * console instead of inside a message-box-window. Message-box-windows are - * available on windows 9x/NT/2000/XP/Vista only. - * - * Copyright (c) 2002, Frank Vanden Berghen - All rights reserved. - * Commercialized by Business-Insight - * See the file "AFPL-license.txt about the licensing terms - * - **************************************************************************** - */ -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE -#endif -#include "xmlParser.h" -#ifdef _XMLWINDOWS -//#ifdef _DEBUG -//#define _CRTDBG_MAP_ALLOC -//#include -//#endif -#define WIN32_LEAN_AND_MEAN -#include // to have IsTextUnicode, MultiByteToWideChar, WideCharToMultiByte to handle unicode files - // to have "MessageBoxA" to display error messages for openFilHelper -#endif - -#include -#include -#include -#include -#include - -XMLCSTR XMLNode::getVersion() { return _CXML("v2.44"); } -void freeXMLString(XMLSTR t){if(t)free(t);} - -static XMLNode::XMLCharEncoding characterEncoding=XMLNode::char_encoding_UTF8; -static char guessWideCharChars=1, dropWhiteSpace=1, removeCommentsInMiddleOfText=1; - -inline int mmin( const int t1, const int t2 ) { return t1 < t2 ? t1 : t2; } - -// You can modify the initialization of the variable "XMLClearTags" below -// to change the clearTags that are currently recognized by the library. -// The number on the second columns is the length of the string inside the -// first column. -// The "") }, - { _CXML("") }, - { _CXML("") }, - { _CXML("
")    ,5,  _CXML("
") }, -// { _CXML("")}, - { NULL ,0, NULL } -}; - -// You can modify the initialization of the variable "XMLEntities" below -// to change the character entities that are currently recognized by the library. -// The number on the second columns is the length of the string inside the -// first column. Additionally, the syntaxes " " and " " are recognized. -typedef struct { XMLCSTR s; int l; XMLCHAR c;} XMLCharacterEntity; -static XMLCharacterEntity XMLEntities[] = -{ - { _CXML("&" ), 5, _CXML('&' )}, - { _CXML("<" ), 4, _CXML('<' )}, - { _CXML(">" ), 4, _CXML('>' )}, - { _CXML("""), 6, _CXML('\"')}, - { _CXML("'"), 6, _CXML('\'')}, - { NULL , 0, '\0' } -}; - -// When rendering the XMLNode to a string (using the "createXMLString" function), -// you can ask for a beautiful formatting. This formatting is using the -// following indentation character: -#define INDENTCHAR _CXML('\t') - -// The following function parses the XML errors into a user friendly string. -// You can edit this to change the output language of the library to something else. -XMLCSTR XMLNode::getError(XMLError xerror) -{ - switch (xerror) - { - case eXMLErrorNone: return _CXML("No error"); - case eXMLErrorMissingEndTag: return _CXML("Warning: Unmatched end tag"); - case eXMLErrorNoXMLTagFound: return _CXML("Warning: No XML tag found"); - case eXMLErrorEmpty: return _CXML("Error: No XML data"); - case eXMLErrorMissingTagName: return _CXML("Error: Missing start tag name"); - case eXMLErrorMissingEndTagName: return _CXML("Error: Missing end tag name"); - case eXMLErrorUnmatchedEndTag: return _CXML("Error: Unmatched end tag"); - case eXMLErrorUnmatchedEndClearTag: return _CXML("Error: Unmatched clear tag end"); - case eXMLErrorUnexpectedToken: return _CXML("Error: Unexpected token found"); - case eXMLErrorNoElements: return _CXML("Error: No elements found"); - case eXMLErrorFileNotFound: return _CXML("Error: File not found"); - case eXMLErrorFirstTagNotFound: return _CXML("Error: First Tag not found"); - case eXMLErrorUnknownCharacterEntity:return _CXML("Error: Unknown character entity"); - case eXMLErrorCharacterCodeAbove255: return _CXML("Error: Character code above 255 is forbidden in MultiByte char mode."); - case eXMLErrorCharConversionError: return _CXML("Error: unable to convert between WideChar and MultiByte chars"); - case eXMLErrorCannotOpenWriteFile: return _CXML("Error: unable to open file for writing"); - case eXMLErrorCannotWriteFile: return _CXML("Error: cannot write into file"); - - case eXMLErrorBase64DataSizeIsNotMultipleOf4: return _CXML("Warning: Base64-string length is not a multiple of 4"); - case eXMLErrorBase64DecodeTruncatedData: return _CXML("Warning: Base64-string is truncated"); - case eXMLErrorBase64DecodeIllegalCharacter: return _CXML("Error: Base64-string contains an illegal character"); - case eXMLErrorBase64DecodeBufferTooSmall: return _CXML("Error: Base64 decode output buffer is too small"); - }; - return _CXML("Unknown"); -} - -///////////////////////////////////////////////////////////////////////// -// Here start the abstraction layer to be OS-independent // -///////////////////////////////////////////////////////////////////////// - -// Here is an abstraction layer to access some common string manipulation functions. -// The abstraction layer is currently working for gcc, Microsoft Visual Studio 6.0, -// Microsoft Visual Studio .NET, CC (sun compiler) and Borland C++. -// If you plan to "port" the library to a new system/compiler, all you have to do is -// to edit the following lines. -#ifdef XML_NO_WIDE_CHAR -char myIsTextWideChar(const void *b, int len) { return FALSE; } -#else - #if defined (UNDER_CE) || !defined(_XMLWINDOWS) - char myIsTextWideChar(const void *b, int len) // inspired by the Wine API: RtlIsTextUnicode - { -#ifdef sun - // for SPARC processors: wchar_t* buffers must always be alligned, otherwise it's a char* buffer. - if ((((unsigned long)b)%sizeof(wchar_t))!=0) return FALSE; -#endif - const wchar_t *s=(const wchar_t*)b; - - // buffer too small: - if (len<(int)sizeof(wchar_t)) return FALSE; - - // odd length test - if (len&1) return FALSE; - - /* only checks the first 256 characters */ - len=mmin(256,len/sizeof(wchar_t)); - - // Check for the special byte order: - if (*((unsigned short*)s) == 0xFFFE) return TRUE; // IS_TEXT_UNICODE_REVERSE_SIGNATURE; - if (*((unsigned short*)s) == 0xFEFF) return TRUE; // IS_TEXT_UNICODE_SIGNATURE - - // checks for ASCII characters in the UNICODE stream - int i,stats=0; - for (i=0; ilen/2) return TRUE; - - // Check for UNICODE NULL chars - for (i=0; i - static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return wsncasecmp(c1,c2,l);} - static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return wsncmp(c1,c2,l);} - static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return wscasecmp(c1,c2); } - #else - static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return wcsncmp(c1,c2,l);} - #ifdef __linux__ - // for gcc/linux - static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return wcsncasecmp(c1,c2,l);} - static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return wcscasecmp(c1,c2); } - #else - #include - // for gcc/non-linux (MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 4.3.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Cygwin, mingw) - static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) - { - wchar_t left,right; - do - { - left=towlower(*c1++); right=towlower(*c2++); - } while (left&&(left==right)); - return (int)left-(int)right; - } - static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) - { - wchar_t left,right; - while(l--) - { - left=towlower(*c1++); right=towlower(*c2++); - if ((!left)||(left!=right)) return (int)left-(int)right; - } - return 0; - } - #endif - #endif - static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)wcsstr(c1,c2); } - static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)wcscpy(c1,c2); } - static inline FILE *xfopen(XMLCSTR filename,XMLCSTR mode) - { - char *filenameAscii=myWideCharToMultiByte(filename); - FILE *f; - if (mode[0]==_CXML('r')) f=fopen(filenameAscii,"rb"); - else f=fopen(filenameAscii,"wb"); - free(filenameAscii); - return f; - } - #else - static inline FILE *xfopen(XMLCSTR filename,XMLCSTR mode) { return fopen(filename,mode); } - static inline int xstrlen(XMLCSTR c) { return strlen(c); } - static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return strncasecmp(c1,c2,l);} - static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return strncmp(c1,c2,l);} - static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return strcasecmp(c1,c2); } - static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)strstr(c1,c2); } - static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)strcpy(c1,c2); } - #endif - static inline int _strnicmp(const char *c1,const char *c2, int l) { return strncasecmp(c1,c2,l);} -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// the "xmltoc,xmltob,xmltoi,xmltol,xmltof,xmltoa" functions // -/////////////////////////////////////////////////////////////////////////////// -// These 6 functions are not used inside the XMLparser. -// There are only here as "convenience" functions for the user. -// If you don't need them, you can delete them without any trouble. -#ifdef _XMLWIDECHAR - #ifdef _XMLWINDOWS - // for Microsoft Visual Studio 6.0 and Microsoft Visual Studio .NET and Borland C++ Builder 6.0 - char xmltob(XMLCSTR t,char v){ if (t&&(*t)) return (char)_wtoi(t); return v; } - int xmltoi(XMLCSTR t,int v){ if (t&&(*t)) return _wtoi(t); return v; } - long long xmltol(XMLCSTR t,long long v){ if (t&&(*t)) return _wtoi64(t); return v; } - double xmltof(XMLCSTR t,double v){ if (t&&(*t)) swscanf(t, L"%lf", &v); /*v=_wtof(t);*/ return v; } - #else - #ifdef sun - // for CC - #include - char xmltob(XMLCSTR t,char v){ if (t) return (char)wstol(t,NULL,10); return v; } - int xmltoi(XMLCSTR t,int v){ if (t) return (int)wstol(t,NULL,10); return v; } - long long xmltol(XMLCSTR t,long long v){ if (t) return wstol(t,NULL,10); return v; } - #else - // for gcc - char xmltob(XMLCSTR t,char v){ if (t) return (char)wcstol(t,NULL,10); return v; } - int xmltoi(XMLCSTR t,int v){ if (t) return (int)wcstol(t,NULL,10); return v; } - long long xmltol(XMLCSTR t,long long v){ if (t) return wcstol(t,NULL,10); return v; } - #endif - double xmltof(XMLCSTR t,double v){ if (t&&(*t)) swscanf(t, L"%lf", &v); /*v=_wtof(t);*/ return v; } - #endif -#else - #ifdef _XMLWINDOWS - long long xmltol(XMLCSTR t,long long v){ if (t&&(*t)) return _atoi64(t); return v; } - #else - long long xmltol(XMLCSTR t,long long v){ if (t&&(*t)) return atoll(t); return v; } - #endif - char xmltob(XMLCSTR t,char v){ if (t&&(*t)) return (char)atoi(t); return v; } - int xmltoi(XMLCSTR t,int v){ if (t&&(*t)) return atoi(t); return v; } - double xmltof(XMLCSTR t,double v){ if (t&&(*t)) return atof(t); return v; } -#endif -XMLCSTR xmltoa(XMLCSTR t, XMLCSTR v){ if (t) return t; return v; } -XMLCHAR xmltoc(XMLCSTR t,const XMLCHAR v){ if (t&&(*t)) return *t; return v; } - -///////////////////////////////////////////////////////////////////////// -// the "openFileHelper" function // -///////////////////////////////////////////////////////////////////////// - -// Since each application has its own way to report and deal with errors, you should modify & rewrite -// the following "openFileHelper" function to get an "error reporting mechanism" tailored to your needs. -XMLNode XMLNode::openFileHelper(XMLCSTR filename, XMLCSTR tag) -{ - // guess the value of the global parameter "characterEncoding" - // (the guess is based on the first 200 bytes of the file). - FILE *f=xfopen(filename,_CXML("rb")); - if (f) - { - char bb[205]; - int l=(int)fread(bb,1,200,f); - setGlobalOptions(guessCharEncoding(bb,l),guessWideCharChars,dropWhiteSpace,removeCommentsInMiddleOfText); - fclose(f); - } - - // parse the file - XMLResults pResults; - XMLNode xnode=XMLNode::parseFile(filename,tag,&pResults); - - // display error message (if any) - if (pResults.error != eXMLErrorNone) - { - // create message - char message[2000],*s1=(char*)"",*s3=(char*)""; XMLCSTR s2=_CXML(""); - if (pResults.error==eXMLErrorFirstTagNotFound) { s1=(char*)"First Tag should be '"; s2=tag; s3=(char*)"'.\n"; } -#ifdef _XMLWINDOWS - _snprintf(message,2000, -#else - snprintf(message,2000, -#endif -#ifdef _XMLWIDECHAR - "XML Parsing error inside file '%S'.\n%S\nAt line %i, column %i.\n%s%S%s" -#else - "XML Parsing error inside file '%s'.\n%s\nAt line %i, column %i.\n%s%s%s" -#endif - ,filename,XMLNode::getError(pResults.error),pResults.nLine,pResults.nColumn,s1,s2,s3); - - // display message -#if defined(_XMLWINDOWS) && !defined(UNDER_CE) && !defined(_XMLPARSER_NO_MESSAGEBOX_) - MessageBoxA(NULL,message,"XML Parsing error",MB_OK|MB_ICONERROR|MB_TOPMOST); -#else - printf("%s",message); -#endif - exit(255); - } - return xnode; -} - -///////////////////////////////////////////////////////////////////////// -// Here start the core implementation of the XMLParser library // -///////////////////////////////////////////////////////////////////////// - -// You should normally not change anything below this point. - -#ifndef _XMLWIDECHAR -// If "characterEncoding=ascii" then we assume that all characters have the same length of 1 byte. -// If "characterEncoding=UTF8" then the characters have different lengths (from 1 byte to 4 bytes). -// If "characterEncoding=ShiftJIS" then the characters have different lengths (from 1 byte to 2 bytes). -// This table is used as lookup-table to know the length of a character (in byte) based on the -// content of the first byte of the character. -// (note: if you modify this, you must always have XML_utf8ByteTable[0]=0 ). -static const char XML_utf8ByteTable[256] = -{ - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70 End of ASCII range - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x80 0x80 to 0xc1 invalid - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x90 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xa0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xb0 - 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xc0 0xc2 to 0xdf 2 byte - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xd0 - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,// 0xe0 0xe0 to 0xef 3 byte - 4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid -}; -static const char XML_legacyByteTable[256] = -{ - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 -}; -static const char XML_sjisByteTable[256] = -{ - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70 - 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x80 0x81 to 0x9F 2 bytes - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x90 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xa0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xb0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xc0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xd0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xe0 0xe0 to 0xef 2 bytes - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 // 0xf0 -}; -static const char XML_gb2312ByteTable[256] = -{ -// 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x80 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x90 - 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xa0 0xa1 to 0xf7 2 bytes - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xb0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xc0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xd0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xe0 - 2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1 // 0xf0 -}; -static const char XML_gbk_big5_ByteTable[256] = -{ - // 0 1 2 3 4 5 6 7 8 9 a b c d e f - 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70 - 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x80 0x81 to 0xfe 2 bytes - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x90 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xa0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xb0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xc0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xd0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xe0 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1 // 0xf0 -}; -static const char *XML_ByteTable=(const char *)XML_utf8ByteTable; // the default is "characterEncoding=XMLNode::encoding_UTF8" -#endif - - -XMLNode XMLNode::emptyXMLNode; -XMLClear XMLNode::emptyXMLClear={ NULL, NULL, NULL}; -XMLAttribute XMLNode::emptyXMLAttribute={ NULL, NULL}; - -// Enumeration used to decipher what type a token is -typedef enum XMLTokenTypeTag -{ - eTokenText = 0, - eTokenQuotedText, - eTokenTagStart, /* "<" */ - eTokenTagEnd, /* "" */ - eTokenEquals, /* "=" */ - eTokenDeclaration, /* "" */ - eTokenClear, - eTokenError -} XMLTokenType; - -// Main structure used for parsing XML -typedef struct XML -{ - XMLCSTR lpXML; - XMLCSTR lpszText; - int nIndex,nIndexMissigEndTag; - enum XMLError error; - XMLCSTR lpEndTag; - int cbEndTag; - XMLCSTR lpNewElement; - int cbNewElement; - int nFirst; -} XML; - -typedef struct -{ - ALLXMLClearTag *pClr; - XMLCSTR pStr; -} NextToken; - -// Enumeration used when parsing attributes -typedef enum Attrib -{ - eAttribName = 0, - eAttribEquals, - eAttribValue -} Attrib; - -// Enumeration used when parsing elements to dictate whether we are currently -// inside a tag -typedef enum XMLStatus -{ - eInsideTag = 0, - eOutsideTag -} XMLStatus; - -XMLError XMLNode::writeToFile(XMLCSTR filename, const char *encoding, char nFormat) const -{ - if (!d) return eXMLErrorNone; - FILE *f=xfopen(filename,_CXML("wb")); - if (!f) return eXMLErrorCannotOpenWriteFile; -#ifdef _XMLWIDECHAR - unsigned char h[2]={ 0xFF, 0xFE }; - if (!fwrite(h,2,1,f)) - { - fclose(f); - return eXMLErrorCannotWriteFile; - } - if ((!isDeclaration())&&((d->lpszName)||(!getChildNode().isDeclaration()))) - { - if (!fwrite(L"\n",sizeof(wchar_t)*40,1,f)) - { - fclose(f); - return eXMLErrorCannotWriteFile; - } - } -#else - if ((!isDeclaration())&&((d->lpszName)||(!getChildNode().isDeclaration()))) - { - if (characterEncoding==char_encoding_UTF8) - { - // header so that windows recognize the file as UTF-8: - unsigned char h[3]={0xEF,0xBB,0xBF}; - if (!fwrite(h,3,1,f)) - { - fclose(f); - return eXMLErrorCannotWriteFile; - } - encoding="utf-8"; - } else if (characterEncoding==char_encoding_ShiftJIS) encoding="SHIFT-JIS"; - - if (!encoding) encoding="ISO-8859-1"; - if (fprintf(f,"\n",encoding)<0) - { - fclose(f); - return eXMLErrorCannotWriteFile; - } - } else - { - if (characterEncoding==char_encoding_UTF8) - { - unsigned char h[3]={0xEF,0xBB,0xBF}; - if (!fwrite(h,3,1,f)) - { - fclose(f); - return eXMLErrorCannotWriteFile; - } - } - } -#endif - int i; - XMLSTR t=createXMLString(nFormat,&i); - if (!fwrite(t,sizeof(XMLCHAR)*i,1,f)) - { - free(t); - fclose(f); - return eXMLErrorCannotWriteFile; - } - if (fclose(f)!=0) - { - free(t); - return eXMLErrorCannotWriteFile; - } - free(t); - return eXMLErrorNone; -} - -// Duplicate a given string. -XMLSTR stringDup(XMLCSTR lpszData, int cbData) -{ - if (lpszData==NULL) return NULL; - - XMLSTR lpszNew; - if (cbData==-1) cbData=(int)xstrlen(lpszData); - lpszNew = (XMLSTR)malloc((cbData+1) * sizeof(XMLCHAR)); - if (lpszNew) - { - memcpy(lpszNew, lpszData, (cbData) * sizeof(XMLCHAR)); - lpszNew[cbData] = (XMLCHAR)NULL; - } - return lpszNew; -} - -XMLSTR ToXMLStringTool::toXMLUnSafe(XMLSTR dest,XMLCSTR source) -{ - XMLSTR dd=dest; - XMLCHAR ch; - XMLCharacterEntity *entity; - while ((ch=*source)) - { - entity=XMLEntities; - do - { - if (ch==entity->c) {xstrcpy(dest,entity->s); dest+=entity->l; source++; goto out_of_loop1; } - entity++; - } while(entity->s); -#ifdef _XMLWIDECHAR - *(dest++)=*(source++); -#else - switch(XML_ByteTable[(unsigned char)ch]) - { - case 4: - if ((!(source[1]))||(!(source[2]))||(!(source[3]))) { *(dest++)='_'; source++; } - else - { - *dest=*source; - dest[1]=source[1]; - dest[2]=source[2]; - dest[3]=source[3]; - dest+=4; source+=4; - } - break; - case 3: - if ((!(source[1]))||(!(source[2]))) { *(dest++)='_'; source++; } - else - { - *dest=*source; - dest[1]=source[1]; - dest[2]=source[2]; - dest+=3; source+=3; - } - break; - case 2: - if (!(source[1])) { *(dest++)='_'; source++; } - else - { - *dest=*source; - dest[1]=source[1]; - dest+=2; source+=2; - } - break; - case 1: *(dest++)=*(source++); - } -#endif -out_of_loop1: - ; - } - *dest=0; - return dd; -} - -// private (used while rendering): -int ToXMLStringTool::lengthXMLString(XMLCSTR source) -{ - int r=0; - XMLCharacterEntity *entity; - XMLCHAR ch; - while ((ch=*source)) - { - entity=XMLEntities; - do - { - if (ch==entity->c) { r+=entity->l; source++; goto out_of_loop1; } - entity++; - } while(entity->s); -#ifdef _XMLWIDECHAR - r++; source++; -#else - ch=XML_ByteTable[(unsigned char)ch]; r+=ch; source+=ch; -#endif -out_of_loop1: - ; - } - return r; -} - -ToXMLStringTool::~ToXMLStringTool(){ freeBuffer(); } -void ToXMLStringTool::freeBuffer(){ if (buf) free(buf); buf=NULL; buflen=0; } -XMLSTR ToXMLStringTool::toXML(XMLCSTR source) -{ - if (!source) - { - if (buflen<1) { buflen=1; buf=(XMLSTR)malloc(sizeof(XMLCHAR)); } - *buf=0; - return buf; - } - int l=lengthXMLString(source)+1; - if (l>buflen) { freeBuffer(); buflen=l; buf=(XMLSTR)malloc(l*sizeof(XMLCHAR)); } - return toXMLUnSafe(buf,source); -} - -// private: -XMLSTR fromXMLString(XMLCSTR s, int lo, XML *pXML) -{ - // This function is the opposite of the function "toXMLString". It decodes the escape - // sequences &, ", ', <, > and replace them by the characters - // &,",',<,>. This function is used internally by the XML Parser. All the calls to - // the XML library will always gives you back "decoded" strings. - // - // in: string (s) and length (lo) of string - // out: new allocated string converted from xml - if (!s) return NULL; - - int ll=0,j; - XMLSTR d; - XMLCSTR ss=s; - XMLCharacterEntity *entity; - while ((lo>0)&&(*s)) - { - if (*s==_CXML('&')) - { - if ((lo>2)&&(s[1]==_CXML('#'))) - { - s+=2; lo-=2; - if ((*s==_CXML('X'))||(*s==_CXML('x'))) { s++; lo--; } - while ((*s)&&(*s!=_CXML(';'))&&((lo--)>0)) s++; - if (*s!=_CXML(';')) - { - pXML->error=eXMLErrorUnknownCharacterEntity; - return NULL; - } - s++; lo--; - } else - { - entity=XMLEntities; - do - { - if ((lo>=entity->l)&&(xstrnicmp(s,entity->s,entity->l)==0)) { s+=entity->l; lo-=entity->l; break; } - entity++; - } while(entity->s); - if (!entity->s) - { - pXML->error=eXMLErrorUnknownCharacterEntity; - return NULL; - } - } - } else - { -#ifdef _XMLWIDECHAR - s++; lo--; -#else - j=XML_ByteTable[(unsigned char)*s]; s+=j; lo-=j; ll+=j-1; -#endif - } - ll++; - } - - d=(XMLSTR)malloc((ll+1)*sizeof(XMLCHAR)); - s=d; - while (ll-->0) - { - if (*ss==_CXML('&')) - { - if (ss[1]==_CXML('#')) - { - ss+=2; j=0; - if ((*ss==_CXML('X'))||(*ss==_CXML('x'))) - { - ss++; - while (*ss!=_CXML(';')) - { - if ((*ss>=_CXML('0'))&&(*ss<=_CXML('9'))) j=(j<<4)+*ss-_CXML('0'); - else if ((*ss>=_CXML('A'))&&(*ss<=_CXML('F'))) j=(j<<4)+*ss-_CXML('A')+10; - else if ((*ss>=_CXML('a'))&&(*ss<=_CXML('f'))) j=(j<<4)+*ss-_CXML('a')+10; - else { free((void*)s); pXML->error=eXMLErrorUnknownCharacterEntity;return NULL;} - ss++; - } - } else - { - while (*ss!=_CXML(';')) - { - if ((*ss>=_CXML('0'))&&(*ss<=_CXML('9'))) j=(j*10)+*ss-_CXML('0'); - else { free((void*)s); pXML->error=eXMLErrorUnknownCharacterEntity;return NULL;} - ss++; - } - } -#ifndef _XMLWIDECHAR - if (j>255) { free((void*)s); pXML->error=eXMLErrorCharacterCodeAbove255;return NULL;} -#endif - (*d++)=(XMLCHAR)j; ss++; - } else - { - entity=XMLEntities; - do - { - if (xstrnicmp(ss,entity->s,entity->l)==0) { *(d++)=entity->c; ss+=entity->l; break; } - entity++; - } while(entity->s); - } - } else - { -#ifdef _XMLWIDECHAR - *(d++)=*(ss++); -#else - switch(XML_ByteTable[(unsigned char)*ss]) - { - case 4: *(d++)=*(ss++); ll--; - case 3: *(d++)=*(ss++); ll--; - case 2: *(d++)=*(ss++); ll--; - case 1: *(d++)=*(ss++); - } -#endif - } - } - *d=0; - return (XMLSTR)s; -} - -#define XML_isSPACECHAR(ch) ((ch==_CXML('\n'))||(ch==_CXML(' '))||(ch== _CXML('\t'))||(ch==_CXML('\r'))) - -// private: -char myTagCompare(XMLCSTR cclose, XMLCSTR copen) -// !!!! WARNING strange convention&: -// return 0 if equals -// return 1 if different -{ - if (!cclose) return 1; - int l=(int)xstrlen(cclose); - if (xstrnicmp(cclose, copen, l)!=0) return 1; - const XMLCHAR c=copen[l]; - if (XML_isSPACECHAR(c)|| - (c==_CXML('/' ))|| - (c==_CXML('<' ))|| - (c==_CXML('>' ))|| - (c==_CXML('=' ))) return 0; - return 1; -} - -// Obtain the next character from the string. -static inline XMLCHAR getNextChar(XML *pXML) -{ - XMLCHAR ch = pXML->lpXML[pXML->nIndex]; -#ifdef _XMLWIDECHAR - if (ch!=0) pXML->nIndex++; -#else - pXML->nIndex+=XML_ByteTable[(unsigned char)ch]; -#endif - return ch; -} - -// Find the next token in a string. -// pcbToken contains the number of characters that have been read. -static NextToken GetNextToken(XML *pXML, int *pcbToken, enum XMLTokenTypeTag *pType) -{ - NextToken result; - XMLCHAR ch; - XMLCHAR chTemp; - int indexStart,nFoundMatch,nIsText=FALSE; - result.pClr=NULL; // prevent warning - - // Find next non-white space character - do { indexStart=pXML->nIndex; ch=getNextChar(pXML); } while XML_isSPACECHAR(ch); - - if (ch) - { - // Cache the current string pointer - result.pStr = &pXML->lpXML[indexStart]; - - // check for standard tokens - switch(ch) - { - // Check for quotes - case _CXML('\''): - case _CXML('\"'): - // Type of token - *pType = eTokenQuotedText; - chTemp = ch; - - // Set the size - nFoundMatch = FALSE; - - // Search through the string to find a matching quote - while((ch = getNextChar(pXML))) - { - if (ch==chTemp) { nFoundMatch = TRUE; break; } - if (ch==_CXML('<')) break; - } - - // If we failed to find a matching quote - if (nFoundMatch == FALSE) - { - pXML->nIndex=indexStart+1; - nIsText=TRUE; - break; - } - -// 4.02.2002 -// if (FindNonWhiteSpace(pXML)) pXML->nIndex--; - - break; - - // Equals (used with attribute values) - case _CXML('='): - *pType = eTokenEquals; - break; - - // Close tag - case _CXML('>'): - *pType = eTokenCloseTag; - break; - - // Check for tag start and tag end - case _CXML('<'): - - { - // First check whether the token is in the clear tag list (meaning it - // does not need formatting). - ALLXMLClearTag *ctag=XMLClearTags; - do - { - if (!xstrncmp(ctag->lpszOpen, result.pStr, ctag->openTagLen)) - { - result.pClr=ctag; - pXML->nIndex+=ctag->openTagLen-1; - *pType=eTokenClear; - return result; - } - ctag++; - } while(ctag->lpszOpen); - - // Peek at the next character to see if we have an end tag 'lpXML[pXML->nIndex]; - - // If we have a tag end... - if (chTemp == _CXML('/')) - { - // Set the type and ensure we point at the next character - getNextChar(pXML); - *pType = eTokenTagEnd; - } - - // If we have an XML declaration tag - else if (chTemp == _CXML('?')) - { - - // Set the type and ensure we point at the next character - getNextChar(pXML); - *pType = eTokenDeclaration; - } - - // Otherwise we must have a start tag - else - { - *pType = eTokenTagStart; - } - break; - } - - // Check to see if we have a short hand type end tag ('/>'). - case _CXML('/'): - - // Peek at the next character to see if we have a short end tag '/>' - chTemp = pXML->lpXML[pXML->nIndex]; - - // If we have a short hand end tag... - if (chTemp == _CXML('>')) - { - // Set the type and ensure we point at the next character - getNextChar(pXML); - *pType = eTokenShortHandClose; - break; - } - - // If we haven't found a short hand closing tag then drop into the - // text process - - // Other characters - default: - nIsText = TRUE; - } - - // If this is a TEXT node - if (nIsText) - { - // Indicate we are dealing with text - *pType = eTokenText; - while((ch = getNextChar(pXML))) - { - if XML_isSPACECHAR(ch) - { - indexStart++; break; - - } else if (ch==_CXML('/')) - { - // If we find a slash then this maybe text or a short hand end tag - // Peek at the next character to see it we have short hand end tag - ch=pXML->lpXML[pXML->nIndex]; - // If we found a short hand end tag then we need to exit the loop - if (ch==_CXML('>')) { pXML->nIndex--; break; } - - } else if ((ch==_CXML('<'))||(ch==_CXML('>'))||(ch==_CXML('='))) - { - pXML->nIndex--; break; - } - } - } - *pcbToken = pXML->nIndex-indexStart; - } else - { - // If we failed to obtain a valid character - *pcbToken = 0; - *pType = eTokenError; - result.pStr=NULL; - } - - return result; -} - -XMLCSTR XMLNode::updateName_WOSD(XMLSTR lpszName) -{ - if (!d) { free(lpszName); return NULL; } - if (d->lpszName&&(lpszName!=d->lpszName)) free((void*)d->lpszName); - d->lpszName=lpszName; - return lpszName; -} - -// private: -XMLNode::XMLNode(struct XMLNodeDataTag *p){ d=p; (p->ref_count)++; } -XMLNode::XMLNode(XMLNodeData *pParent, XMLSTR lpszName, char isDeclaration) -{ - d=(XMLNodeData*)malloc(sizeof(XMLNodeData)); - d->ref_count=1; - - d->lpszName=NULL; - d->nChild= 0; - d->nText = 0; - d->nClear = 0; - d->nAttribute = 0; - - d->isDeclaration = isDeclaration; - - d->pParent = pParent; - d->pChild= NULL; - d->pText= NULL; - d->pClear= NULL; - d->pAttribute= NULL; - d->pOrder= NULL; - - updateName_WOSD(lpszName); -} - -XMLNode XMLNode::createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration) { return XMLNode(NULL,lpszName,isDeclaration); } -XMLNode XMLNode::createXMLTopNode(XMLCSTR lpszName, char isDeclaration) { return XMLNode(NULL,stringDup(lpszName),isDeclaration); } - -#define MEMORYINCREASE 50 - -static inline void myFree(void *p) { if (p) free(p); } -static inline void *myRealloc(void *p, int newsize, int memInc, int sizeofElem) -{ - if (p==NULL) { if (memInc) return malloc(memInc*sizeofElem); return malloc(sizeofElem); } - if ((memInc==0)||((newsize%memInc)==0)) p=realloc(p,(newsize+memInc)*sizeofElem); -// if (!p) -// { -// printf("XMLParser Error: Not enough memory! Aborting...\n"); exit(220); -// } - return p; -} - -// private: -XMLElementPosition XMLNode::findPosition(XMLNodeData *d, int index, XMLElementType xxtype) -{ - if (index<0) return -1; - int i=0,j=(int)((index<<2)+xxtype),*o=d->pOrder; while (o[i]!=j) i++; return i; -} - -// private: -// update "order" information when deleting a content of a XMLNode -int XMLNode::removeOrderElement(XMLNodeData *d, XMLElementType t, int index) -{ - int n=d->nChild+d->nText+d->nClear, *o=d->pOrder,i=findPosition(d,index,t); - memmove(o+i, o+i+1, (n-i)*sizeof(int)); - for (;ipOrder=(int)realloc(d->pOrder,n*sizeof(int)); - // but we skip reallocation because it's too time consuming. - // Anyway, at the end, it will be free'd completely at once. - return i; -} - -void *XMLNode::addToOrder(int memoryIncrease,int *_pos, int nc, void *p, int size, XMLElementType xtype) -{ - // in: *_pos is the position inside d->pOrder ("-1" means "EndOf") - // out: *_pos is the index inside p - p=myRealloc(p,(nc+1),memoryIncrease,size); - int n=d->nChild+d->nText+d->nClear; - d->pOrder=(int*)myRealloc(d->pOrder,n+1,memoryIncrease*3,sizeof(int)); - int pos=*_pos,*o=d->pOrder; - - if ((pos<0)||(pos>=n)) { *_pos=nc; o[n]=(int)((nc<<2)+xtype); return p; } - - int i=pos; - memmove(o+i+1, o+i, (n-i)*sizeof(int)); - - while ((pos>2; - memmove(((char*)p)+(pos+1)*size,((char*)p)+pos*size,(nc-pos)*size); - - return p; -} - -// Add a child node to the given element. -XMLNode XMLNode::addChild_priv(int memoryIncrease, XMLSTR lpszName, char isDeclaration, int pos) -{ - if (!lpszName) return emptyXMLNode; - d->pChild=(XMLNode*)addToOrder(memoryIncrease,&pos,d->nChild,d->pChild,sizeof(XMLNode),eNodeChild); - d->pChild[pos].d=NULL; - d->pChild[pos]=XMLNode(d,lpszName,isDeclaration); - d->nChild++; - return d->pChild[pos]; -} - -// Add an attribute to an element. -XMLAttribute *XMLNode::addAttribute_priv(int memoryIncrease,XMLSTR lpszName, XMLSTR lpszValuev) -{ - if (!lpszName) return &emptyXMLAttribute; - if (!d) { myFree(lpszName); myFree(lpszValuev); return &emptyXMLAttribute; } - int nc=d->nAttribute; - d->pAttribute=(XMLAttribute*)myRealloc(d->pAttribute,(nc+1),memoryIncrease,sizeof(XMLAttribute)); - XMLAttribute *pAttr=d->pAttribute+nc; - pAttr->lpszName = lpszName; - pAttr->lpszValue = lpszValuev; - d->nAttribute++; - return pAttr; -} - -// Add text to the element. -XMLCSTR XMLNode::addText_priv(int memoryIncrease, XMLSTR lpszValue, int pos) -{ - if (!lpszValue) return NULL; - if (!d) { myFree(lpszValue); return NULL; } - d->pText=(XMLCSTR*)addToOrder(memoryIncrease,&pos,d->nText,d->pText,sizeof(XMLSTR),eNodeText); - d->pText[pos]=lpszValue; - d->nText++; - return lpszValue; -} - -// Add clear (unformatted) text to the element. -XMLClear *XMLNode::addClear_priv(int memoryIncrease, XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, int pos) -{ - if (!lpszValue) return &emptyXMLClear; - if (!d) { myFree(lpszValue); return &emptyXMLClear; } - d->pClear=(XMLClear *)addToOrder(memoryIncrease,&pos,d->nClear,d->pClear,sizeof(XMLClear),eNodeClear); - XMLClear *pNewClear=d->pClear+pos; - pNewClear->lpszValue = lpszValue; - if (!lpszOpen) lpszOpen=XMLClearTags->lpszOpen; - if (!lpszClose) lpszClose=XMLClearTags->lpszClose; - pNewClear->lpszOpenTag = lpszOpen; - pNewClear->lpszCloseTag = lpszClose; - d->nClear++; - return pNewClear; -} - -// private: -// Parse a clear (unformatted) type node. -char XMLNode::parseClearTag(void *px, void *_pClear) -{ - XML *pXML=(XML *)px; - ALLXMLClearTag pClear=*((ALLXMLClearTag*)_pClear); - int cbTemp=0; - XMLCSTR lpszTemp=NULL; - XMLCSTR lpXML=&pXML->lpXML[pXML->nIndex]; - static XMLCSTR docTypeEnd=_CXML("]>"); - - // Find the closing tag - // Seems the ')) { lpszTemp=pCh; break; } -#ifdef _XMLWIDECHAR - pCh++; -#else - pCh+=XML_ByteTable[(unsigned char)(*pCh)]; -#endif - } - } else lpszTemp=xstrstr(lpXML, pClear.lpszClose); - - if (lpszTemp) - { - // Cache the size and increment the index - cbTemp = (int)(lpszTemp - lpXML); - - pXML->nIndex += cbTemp+(int)xstrlen(pClear.lpszClose); - - // Add the clear node to the current element - addClear_priv(MEMORYINCREASE,cbTemp?stringDup(lpXML,cbTemp):NULL, pClear.lpszOpen, pClear.lpszClose,-1); - return 0; - } - - // If we failed to find the end tag - pXML->error = eXMLErrorUnmatchedEndClearTag; - return 1; -} - -void XMLNode::exactMemory(XMLNodeData *d) -{ - if (d->pOrder) d->pOrder=(int*)realloc(d->pOrder,(d->nChild+d->nText+d->nClear)*sizeof(int)); - if (d->pChild) d->pChild=(XMLNode*)realloc(d->pChild,d->nChild*sizeof(XMLNode)); - if (d->pAttribute) d->pAttribute=(XMLAttribute*)realloc(d->pAttribute,d->nAttribute*sizeof(XMLAttribute)); - if (d->pText) d->pText=(XMLCSTR*)realloc(d->pText,d->nText*sizeof(XMLSTR)); - if (d->pClear) d->pClear=(XMLClear *)realloc(d->pClear,d->nClear*sizeof(XMLClear)); -} - -char XMLNode::maybeAddTxT(void *pa, XMLCSTR tokenPStr) -{ - XML *pXML=(XML *)pa; - XMLCSTR lpszText=pXML->lpszText; - if (!lpszText) return 0; - if (dropWhiteSpace) while (XML_isSPACECHAR(*lpszText)&&(lpszText!=tokenPStr)) lpszText++; - int cbText = (int)(tokenPStr - lpszText); - if (!cbText) { pXML->lpszText=NULL; return 0; } - if (dropWhiteSpace) { cbText--; while ((cbText)&&XML_isSPACECHAR(lpszText[cbText])) cbText--; cbText++; } - if (!cbText) { pXML->lpszText=NULL; return 0; } - XMLSTR lpt=fromXMLString(lpszText,cbText,pXML); - if (!lpt) return 1; - pXML->lpszText=NULL; - if (removeCommentsInMiddleOfText && d->nText && d->nClear) - { - // if the previous insertion was a comment () AND - // if the previous previous insertion was a text then, delete the comment and append the text - int n=d->nChild+d->nText+d->nClear-1,*o=d->pOrder; - if (((o[n]&3)==eNodeClear)&&((o[n-1]&3)==eNodeText)) - { - int i=o[n]>>2; - if (d->pClear[i].lpszOpenTag==XMLClearTags[2].lpszOpen) - { - deleteClear(i); - i=o[n-1]>>2; - n=xstrlen(d->pText[i]); - int n2=xstrlen(lpt)+1; - d->pText[i]=(XMLSTR)realloc((void*)d->pText[i],(n+n2)*sizeof(XMLCHAR)); - if (!d->pText[i]) return 1; - memcpy((void*)(d->pText[i]+n),lpt,n2*sizeof(XMLCHAR)); - free(lpt); - return 0; - } - } - } - addText_priv(MEMORYINCREASE,lpt,-1); - return 0; -} -// private: -// Recursively parse an XML element. -int XMLNode::ParseXMLElement(void *pa) -{ - XML *pXML=(XML *)pa; - int cbToken; - enum XMLTokenTypeTag xtype; - NextToken token; - XMLCSTR lpszTemp=NULL; - int cbTemp=0; - char nDeclaration; - XMLNode pNew; - enum XMLStatus status; // inside or outside a tag - enum Attrib attrib = eAttribName; - - assert(pXML); - - // If this is the first call to the function - if (pXML->nFirst) - { - // Assume we are outside of a tag definition - pXML->nFirst = FALSE; - status = eOutsideTag; - } else - { - // If this is not the first call then we should only be called when inside a tag. - status = eInsideTag; - } - - // Iterate through the tokens in the document - for(;;) - { - // Obtain the next token - token = GetNextToken(pXML, &cbToken, &xtype); - - if (xtype != eTokenError) - { - // Check the current status - switch(status) - { - - // If we are outside of a tag definition - case eOutsideTag: - - // Check what type of token we obtained - switch(xtype) - { - // If we have found text or quoted text - case eTokenText: - case eTokenCloseTag: /* '>' */ - case eTokenShortHandClose: /* '/>' */ - case eTokenQuotedText: - case eTokenEquals: - break; - - // If we found a start tag '<' and declarations 'error = eXMLErrorMissingTagName; - return FALSE; - } - - // If we found a new element which is the same as this - // element then we need to pass this back to the caller.. - -#ifdef APPROXIMATE_PARSING - if (d->lpszName && - myTagCompare(d->lpszName, token.pStr) == 0) - { - // Indicate to the caller that it needs to create a - // new element. - pXML->lpNewElement = token.pStr; - pXML->cbNewElement = cbToken; - return TRUE; - } else -#endif - { - // If the name of the new element differs from the name of - // the current element we need to add the new element to - // the current one and recurse - pNew = addChild_priv(MEMORYINCREASE,stringDup(token.pStr,cbToken), nDeclaration,-1); - - while (!pNew.isEmpty()) - { - // Callself to process the new node. If we return - // FALSE this means we dont have any more - // processing to do... - - if (!pNew.ParseXMLElement(pXML)) return FALSE; - else - { - // If the call to recurse this function - // evented in a end tag specified in XML then - // we need to unwind the calls to this - // function until we find the appropriate node - // (the element name and end tag name must - // match) - if (pXML->cbEndTag) - { - // If we are back at the root node then we - // have an unmatched end tag - if (!d->lpszName) - { - pXML->error=eXMLErrorUnmatchedEndTag; - return FALSE; - } - - // If the end tag matches the name of this - // element then we only need to unwind - // once more... - - if (myTagCompare(d->lpszName, pXML->lpEndTag)==0) - { - pXML->cbEndTag = 0; - } - - return TRUE; - } else - if (pXML->cbNewElement) - { - // If the call indicated a new element is to - // be created on THIS element. - - // If the name of this element matches the - // name of the element we need to create - // then we need to return to the caller - // and let it process the element. - - if (myTagCompare(d->lpszName, pXML->lpNewElement)==0) - { - return TRUE; - } - - // Add the new element and recurse - pNew = addChild_priv(MEMORYINCREASE,stringDup(pXML->lpNewElement,pXML->cbNewElement),0,-1); - pXML->cbNewElement = 0; - } - else - { - // If we didn't have a new element to create - pNew = emptyXMLNode; - - } - } - } - } - break; - - // If we found an end tag - case eTokenTagEnd: - - // If we have node text then add this to the element - if (maybeAddTxT(pXML,token.pStr)) return FALSE; - - // Find the name of the end tag - token = GetNextToken(pXML, &cbTemp, &xtype); - - // The end tag should be text - if (xtype != eTokenText) - { - pXML->error = eXMLErrorMissingEndTagName; - return FALSE; - } - lpszTemp = token.pStr; - - // After the end tag we should find a closing tag - token = GetNextToken(pXML, &cbToken, &xtype); - if (xtype != eTokenCloseTag) - { - pXML->error = eXMLErrorMissingEndTagName; - return FALSE; - } - pXML->lpszText=pXML->lpXML+pXML->nIndex; - - // We need to return to the previous caller. If the name - // of the tag cannot be found we need to keep returning to - // caller until we find a match - if (myTagCompare(d->lpszName, lpszTemp) != 0) -#ifdef STRICT_PARSING - { - pXML->error=eXMLErrorUnmatchedEndTag; - pXML->nIndexMissigEndTag=pXML->nIndex; - return FALSE; - } -#else - { - pXML->error=eXMLErrorMissingEndTag; - pXML->nIndexMissigEndTag=pXML->nIndex; - pXML->lpEndTag = lpszTemp; - pXML->cbEndTag = cbTemp; - } -#endif - - // Return to the caller - exactMemory(d); - return TRUE; - - // If we found a clear (unformatted) token - case eTokenClear: - // If we have node text then add this to the element - if (maybeAddTxT(pXML,token.pStr)) return FALSE; - if (parseClearTag(pXML, token.pClr)) return FALSE; - pXML->lpszText=pXML->lpXML+pXML->nIndex; - break; - - default: - break; - } - break; - - // If we are inside a tag definition we need to search for attributes - case eInsideTag: - - // Check what part of the attribute (name, equals, value) we - // are looking for. - switch(attrib) - { - // If we are looking for a new attribute - case eAttribName: - - // Check what the current token type is - switch(xtype) - { - // If the current type is text... - // Eg. 'attribute' - case eTokenText: - // Cache the token then indicate that we are next to - // look for the equals - lpszTemp = token.pStr; - cbTemp = cbToken; - attrib = eAttribEquals; - break; - - // If we found a closing tag... - // Eg. '>' - case eTokenCloseTag: - // We are now outside the tag - status = eOutsideTag; - pXML->lpszText=pXML->lpXML+pXML->nIndex; - break; - - // If we found a short hand '/>' closing tag then we can - // return to the caller - case eTokenShortHandClose: - exactMemory(d); - pXML->lpszText=pXML->lpXML+pXML->nIndex; - return TRUE; - - // Errors... - case eTokenQuotedText: /* '"SomeText"' */ - case eTokenTagStart: /* '<' */ - case eTokenTagEnd: /* 'error = eXMLErrorUnexpectedToken; - return FALSE; - default: break; - } - break; - - // If we are looking for an equals - case eAttribEquals: - // Check what the current token type is - switch(xtype) - { - // If the current type is text... - // Eg. 'Attribute AnotherAttribute' - case eTokenText: - // Add the unvalued attribute to the list - addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp), NULL); - // Cache the token then indicate. We are next to - // look for the equals attribute - lpszTemp = token.pStr; - cbTemp = cbToken; - break; - - // If we found a closing tag 'Attribute >' or a short hand - // closing tag 'Attribute />' - case eTokenShortHandClose: - case eTokenCloseTag: - // If we are a declaration element 'lpszText=pXML->lpXML+pXML->nIndex; - - if (d->isDeclaration && - (lpszTemp[cbTemp-1]) == _CXML('?')) - { - cbTemp--; - if (d->pParent && d->pParent->pParent) xtype = eTokenShortHandClose; - } - - if (cbTemp) - { - // Add the unvalued attribute to the list - addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp), NULL); - } - - // If this is the end of the tag then return to the caller - if (xtype == eTokenShortHandClose) - { - exactMemory(d); - return TRUE; - } - - // We are now outside the tag - status = eOutsideTag; - break; - - // If we found the equals token... - // Eg. 'Attribute =' - case eTokenEquals: - // Indicate that we next need to search for the value - // for the attribute - attrib = eAttribValue; - break; - - // Errors... - case eTokenQuotedText: /* 'Attribute "InvalidAttr"'*/ - case eTokenTagStart: /* 'Attribute <' */ - case eTokenTagEnd: /* 'Attribute error = eXMLErrorUnexpectedToken; - return FALSE; - default: break; - } - break; - - // If we are looking for an attribute value - case eAttribValue: - // Check what the current token type is - switch(xtype) - { - // If the current type is text or quoted text... - // Eg. 'Attribute = "Value"' or 'Attribute = Value' or - // 'Attribute = 'Value''. - case eTokenText: - case eTokenQuotedText: - // If we are a declaration element 'isDeclaration && - (token.pStr[cbToken-1]) == _CXML('?')) - { - cbToken--; - } - - if (cbTemp) - { - // Add the valued attribute to the list - if (xtype==eTokenQuotedText) { token.pStr++; cbToken-=2; } - XMLSTR attrVal=(XMLSTR)token.pStr; - if (attrVal) - { - attrVal=fromXMLString(attrVal,cbToken,pXML); - if (!attrVal) return FALSE; - } - addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp),attrVal); - } - - // Indicate we are searching for a new attribute - attrib = eAttribName; - break; - - // Errors... - case eTokenTagStart: /* 'Attr = <' */ - case eTokenTagEnd: /* 'Attr = ' */ - case eTokenShortHandClose: /* "Attr = />" */ - case eTokenEquals: /* 'Attr = =' */ - case eTokenDeclaration: /* 'Attr = error = eXMLErrorUnexpectedToken; - return FALSE; - break; - default: break; - } - } - } - } - // If we failed to obtain the next token - else - { - if ((!d->isDeclaration)&&(d->pParent)) - { -#ifdef STRICT_PARSING - pXML->error=eXMLErrorUnmatchedEndTag; -#else - pXML->error=eXMLErrorMissingEndTag; -#endif - pXML->nIndexMissigEndTag=pXML->nIndex; - } - maybeAddTxT(pXML,pXML->lpXML+pXML->nIndex); - return FALSE; - } - } -} - -// Count the number of lines and columns in an XML string. -static void CountLinesAndColumns(XMLCSTR lpXML, int nUpto, XMLResults *pResults) -{ - XMLCHAR ch; - assert(lpXML); - assert(pResults); - - struct XML xml={ lpXML,lpXML, 0, 0, eXMLErrorNone, NULL, 0, NULL, 0, TRUE }; - - pResults->nLine = 1; - pResults->nColumn = 1; - while (xml.nIndexnColumn++; - else - { - pResults->nLine++; - pResults->nColumn=1; - } - } -} - -// Parse XML and return the root element. -XMLNode XMLNode::parseString(XMLCSTR lpszXML, XMLCSTR tag, XMLResults *pResults) -{ - if (!lpszXML) - { - if (pResults) - { - pResults->error=eXMLErrorNoElements; - pResults->nLine=0; - pResults->nColumn=0; - } - return emptyXMLNode; - } - - XMLNode xnode(NULL,NULL,FALSE); - struct XML xml={ lpszXML, lpszXML, 0, 0, eXMLErrorNone, NULL, 0, NULL, 0, TRUE }; - - // Create header element - xnode.ParseXMLElement(&xml); - enum XMLError error = xml.error; - if (!xnode.nChildNode()) error=eXMLErrorNoXMLTagFound; - if ((xnode.nChildNode()==1)&&(xnode.nElement()==1)) xnode=xnode.getChildNode(); // skip the empty node - - // If no error occurred - if ((error==eXMLErrorNone)||(error==eXMLErrorMissingEndTag)||(error==eXMLErrorNoXMLTagFound)) - { - XMLCSTR name=xnode.getName(); - if (tag&&(*tag)&&((!name)||(xstricmp(name,tag)))) - { - xnode=xnode.getChildNode(tag); - if (xnode.isEmpty()) - { - if (pResults) - { - pResults->error=eXMLErrorFirstTagNotFound; - pResults->nLine=0; - pResults->nColumn=0; - } - return emptyXMLNode; - } - } - } else - { - // Cleanup: this will destroy all the nodes - xnode = emptyXMLNode; - } - - - // If we have been given somewhere to place results - if (pResults) - { - pResults->error = error; - - // If we have an error - if (error!=eXMLErrorNone) - { - if (error==eXMLErrorMissingEndTag) xml.nIndex=xml.nIndexMissigEndTag; - // Find which line and column it starts on. - CountLinesAndColumns(xml.lpXML, xml.nIndex, pResults); - } - } - return xnode; -} - -XMLNode XMLNode::parseFile(XMLCSTR filename, XMLCSTR tag, XMLResults *pResults) -{ - if (pResults) { pResults->nLine=0; pResults->nColumn=0; } - FILE *f=xfopen(filename,_CXML("rb")); - if (f==NULL) { if (pResults) pResults->error=eXMLErrorFileNotFound; return emptyXMLNode; } - fseek(f,0,SEEK_END); - int l=(int)ftell(f),headerSz=0; - if (!l) { if (pResults) pResults->error=eXMLErrorEmpty; fclose(f); return emptyXMLNode; } - fseek(f,0,SEEK_SET); - unsigned char *buf=(unsigned char*)malloc(l+4); - l=(int)fread(buf,1,l,f); - fclose(f); - buf[l]=0;buf[l+1]=0;buf[l+2]=0;buf[l+3]=0; -#ifdef _XMLWIDECHAR - if (guessWideCharChars) - { - if (!myIsTextWideChar(buf,l)) - { - XMLNode::XMLCharEncoding ce=XMLNode::char_encoding_legacy; - if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) { headerSz=3; ce=XMLNode::char_encoding_UTF8; } - XMLSTR b2=myMultiByteToWideChar((const char*)(buf+headerSz),ce); - if (!b2) - { - // todo: unable to convert - } - free(buf); buf=(unsigned char*)b2; headerSz=0; - } else - { - if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2; - if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2; - } - } else - { - if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2; - if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2; - if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3; - } -#else - if (guessWideCharChars) - { - if (myIsTextWideChar(buf,l)) - { - if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2; - if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2; - char *b2=myWideCharToMultiByte((const wchar_t*)(buf+headerSz)); - free(buf); buf=(unsigned char*)b2; headerSz=0; - } else - { - if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3; - } - } else - { - if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2; - if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2; - if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3; - } -#endif - - if (!buf) { if (pResults) pResults->error=eXMLErrorCharConversionError; return emptyXMLNode; } - XMLNode x=parseString((XMLSTR)(buf+headerSz),tag,pResults); - free(buf); - return x; -} - -static inline void charmemset(XMLSTR dest,XMLCHAR c,int l) { while (l--) *(dest++)=c; } -// private: -// Creates an user friendly XML string from a given element with -// appropriate white space and carriage returns. -// -// This recurses through all subnodes then adds contents of the nodes to the -// string. -int XMLNode::CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat) -{ - int nResult = 0; - int cb=nFormat<0?0:nFormat; - int cbElement; - int nChildFormat=-1; - int nElementI=pEntry->nChild+pEntry->nText+pEntry->nClear; - int i,j; - if ((nFormat>=0)&&(nElementI==1)&&(pEntry->nText==1)&&(!pEntry->isDeclaration)) nFormat=-2; - - assert(pEntry); - -#define LENSTR(lpsz) (lpsz ? xstrlen(lpsz) : 0) - - // If the element has no name then assume this is the head node. - cbElement = (int)LENSTR(pEntry->lpszName); - - if (cbElement) - { - // "isDeclaration) lpszMarker[nResult++]=_CXML('?'); - xstrcpy(&lpszMarker[nResult], pEntry->lpszName); - nResult+=cbElement; - lpszMarker[nResult++]=_CXML(' '); - - } else - { - nResult+=cbElement+2+cb; - if (pEntry->isDeclaration) nResult++; - } - - // Enumerate attributes and add them to the string - XMLAttribute *pAttr=pEntry->pAttribute; - for (i=0; inAttribute; i++) - { - // "Attrib - cb = (int)LENSTR(pAttr->lpszName); - if (cb) - { - if (lpszMarker) xstrcpy(&lpszMarker[nResult], pAttr->lpszName); - nResult += cb; - // "Attrib=Value " - if (pAttr->lpszValue) - { - cb=(int)ToXMLStringTool::lengthXMLString(pAttr->lpszValue); - if (lpszMarker) - { - lpszMarker[nResult]=_CXML('='); - lpszMarker[nResult+1]=_CXML('"'); - if (cb) ToXMLStringTool::toXMLUnSafe(&lpszMarker[nResult+2],pAttr->lpszValue); - lpszMarker[nResult+cb+2]=_CXML('"'); - } - nResult+=cb+3; - } - if (lpszMarker) lpszMarker[nResult] = _CXML(' '); - nResult++; - } - pAttr++; - } - - if (pEntry->isDeclaration) - { - if (lpszMarker) - { - lpszMarker[nResult-1]=_CXML('?'); - lpszMarker[nResult]=_CXML('>'); - } - nResult++; - if (nFormat!=-1) - { - if (lpszMarker) lpszMarker[nResult]=_CXML('\n'); - nResult++; - } - } else - // If there are child nodes we need to terminate the start tag - if (nElementI) - { - if (lpszMarker) lpszMarker[nResult-1]=_CXML('>'); - if (nFormat>=0) - { - if (lpszMarker) lpszMarker[nResult]=_CXML('\n'); - nResult++; - } - } else nResult--; - } - - // Calculate the child format for when we recurse. This is used to - // determine the number of spaces used for prefixes. - if (nFormat!=-1) - { - if (cbElement&&(!pEntry->isDeclaration)) nChildFormat=nFormat+1; - else nChildFormat=nFormat; - } - - // Enumerate through remaining children - for (i=0; ipOrder[i]; - switch((XMLElementType)(j&3)) - { - // Text nodes - case eNodeText: - { - // "Text" - XMLCSTR pChild=pEntry->pText[j>>2]; - cb = (int)ToXMLStringTool::lengthXMLString(pChild); - if (cb) - { - if (nFormat>=0) - { - if (lpszMarker) - { - charmemset(&lpszMarker[nResult],INDENTCHAR,nFormat+1); - ToXMLStringTool::toXMLUnSafe(&lpszMarker[nResult+nFormat+1],pChild); - lpszMarker[nResult+nFormat+1+cb]=_CXML('\n'); - } - nResult+=cb+nFormat+2; - } else - { - if (lpszMarker) ToXMLStringTool::toXMLUnSafe(&lpszMarker[nResult], pChild); - nResult += cb; - } - } - break; - } - - // Clear type nodes - case eNodeClear: - { - XMLClear *pChild=pEntry->pClear+(j>>2); - // "OpenTag" - cb = (int)LENSTR(pChild->lpszOpenTag); - if (cb) - { - if (nFormat!=-1) - { - if (lpszMarker) - { - charmemset(&lpszMarker[nResult], INDENTCHAR, nFormat+1); - xstrcpy(&lpszMarker[nResult+nFormat+1], pChild->lpszOpenTag); - } - nResult+=cb+nFormat+1; - } - else - { - if (lpszMarker)xstrcpy(&lpszMarker[nResult], pChild->lpszOpenTag); - nResult += cb; - } - } - - // "OpenTag Value" - cb = (int)LENSTR(pChild->lpszValue); - if (cb) - { - if (lpszMarker) xstrcpy(&lpszMarker[nResult], pChild->lpszValue); - nResult += cb; - } - - // "OpenTag Value CloseTag" - cb = (int)LENSTR(pChild->lpszCloseTag); - if (cb) - { - if (lpszMarker) xstrcpy(&lpszMarker[nResult], pChild->lpszCloseTag); - nResult += cb; - } - - if (nFormat!=-1) - { - if (lpszMarker) lpszMarker[nResult] = _CXML('\n'); - nResult++; - } - break; - } - - // Element nodes - case eNodeChild: - { - // Recursively add child nodes - nResult += CreateXMLStringR(pEntry->pChild[j>>2].d, lpszMarker ? lpszMarker + nResult : 0, nChildFormat); - break; - } - default: break; - } - } - - if ((cbElement)&&(!pEntry->isDeclaration)) - { - // If we have child entries we need to use long XML notation for - // closing the element - "blah blah blah" - if (nElementI) - { - // "\0" - if (lpszMarker) - { - if (nFormat >=0) - { - charmemset(&lpszMarker[nResult], INDENTCHAR,nFormat); - nResult+=nFormat; - } - - lpszMarker[nResult]=_CXML('<'); lpszMarker[nResult+1]=_CXML('/'); - nResult += 2; - xstrcpy(&lpszMarker[nResult], pEntry->lpszName); - nResult += cbElement; - - lpszMarker[nResult]=_CXML('>'); - if (nFormat == -1) nResult++; - else - { - lpszMarker[nResult+1]=_CXML('\n'); - nResult+=2; - } - } else - { - if (nFormat>=0) nResult+=cbElement+4+nFormat; - else if (nFormat==-1) nResult+=cbElement+3; - else nResult+=cbElement+4; - } - } else - { - // If there are no children we can use shorthand XML notation - - // "" - // "/>\0" - if (lpszMarker) - { - lpszMarker[nResult]=_CXML('/'); lpszMarker[nResult+1]=_CXML('>'); - if (nFormat != -1) lpszMarker[nResult+2]=_CXML('\n'); - } - nResult += nFormat == -1 ? 2 : 3; - } - } - - return nResult; -} - -#undef LENSTR - -// Create an XML string -// @param int nFormat - 0 if no formatting is required -// otherwise nonzero for formatted text -// with carriage returns and indentation. -// @param int *pnSize - [out] pointer to the size of the -// returned string not including the -// NULL terminator. -// @return XMLSTR - Allocated XML string, you must free -// this with free(). -XMLSTR XMLNode::createXMLString(int nFormat, int *pnSize) const -{ - if (!d) { if (pnSize) *pnSize=0; return NULL; } - - XMLSTR lpszResult = NULL; - int cbStr; - - // Recursively Calculate the size of the XML string - if (!dropWhiteSpace) nFormat=0; - nFormat = nFormat ? 0 : -1; - cbStr = CreateXMLStringR(d, 0, nFormat); - // Alllocate memory for the XML string + the NULL terminator and - // create the recursively XML string. - lpszResult=(XMLSTR)malloc((cbStr+1)*sizeof(XMLCHAR)); - CreateXMLStringR(d, lpszResult, nFormat); - lpszResult[cbStr]=_CXML('\0'); - if (pnSize) *pnSize = cbStr; - return lpszResult; -} - -int XMLNode::detachFromParent(XMLNodeData *d) -{ - XMLNode *pa=d->pParent->pChild; - int i=0; - while (((void*)(pa[i].d))!=((void*)d)) i++; - d->pParent->nChild--; - if (d->pParent->nChild) memmove(pa+i,pa+i+1,(d->pParent->nChild-i)*sizeof(XMLNode)); - else { free(pa); d->pParent->pChild=NULL; } - return removeOrderElement(d->pParent,eNodeChild,i); -} - -XMLNode::~XMLNode() -{ - if (!d) return; - d->ref_count--; - emptyTheNode(0); -} -void XMLNode::deleteNodeContent() -{ - if (!d) return; - if (d->pParent) { detachFromParent(d); d->pParent=NULL; d->ref_count--; } - emptyTheNode(1); -} -void XMLNode::emptyTheNode(char force) -{ - XMLNodeData *dd=d; // warning: must stay this way! - if ((dd->ref_count==0)||force) - { - if (d->pParent) detachFromParent(d); - int i; - XMLNode *pc; - for(i=0; inChild; i++) - { - pc=dd->pChild+i; - pc->d->pParent=NULL; - pc->d->ref_count--; - pc->emptyTheNode(force); - } - myFree(dd->pChild); - for(i=0; inText; i++) free((void*)dd->pText[i]); - myFree(dd->pText); - for(i=0; inClear; i++) free((void*)dd->pClear[i].lpszValue); - myFree(dd->pClear); - for(i=0; inAttribute; i++) - { - free((void*)dd->pAttribute[i].lpszName); - if (dd->pAttribute[i].lpszValue) free((void*)dd->pAttribute[i].lpszValue); - } - myFree(dd->pAttribute); - myFree(dd->pOrder); - myFree((void*)dd->lpszName); - dd->nChild=0; dd->nText=0; dd->nClear=0; dd->nAttribute=0; - dd->pChild=NULL; dd->pText=NULL; dd->pClear=NULL; dd->pAttribute=NULL; - dd->pOrder=NULL; dd->lpszName=NULL; dd->pParent=NULL; - } - if (dd->ref_count==0) - { - free(dd); - d=NULL; - } -} - -XMLNode& XMLNode::operator=( const XMLNode& A ) -{ - // shallow copy - if (this != &A) - { - if (d) { d->ref_count--; emptyTheNode(0); } - d=A.d; - if (d) (d->ref_count) ++ ; - } - return *this; -} - -XMLNode::XMLNode(const XMLNode &A) -{ - // shallow copy - d=A.d; - if (d) (d->ref_count)++ ; -} - -XMLNode XMLNode::deepCopy() const -{ - if (!d) return XMLNode::emptyXMLNode; - XMLNode x(NULL,stringDup(d->lpszName),d->isDeclaration); - XMLNodeData *p=x.d; - int n=d->nAttribute; - if (n) - { - p->nAttribute=n; p->pAttribute=(XMLAttribute*)malloc(n*sizeof(XMLAttribute)); - while (n--) - { - p->pAttribute[n].lpszName=stringDup(d->pAttribute[n].lpszName); - p->pAttribute[n].lpszValue=stringDup(d->pAttribute[n].lpszValue); - } - } - if (d->pOrder) - { - n=(d->nChild+d->nText+d->nClear)*sizeof(int); p->pOrder=(int*)malloc(n); memcpy(p->pOrder,d->pOrder,n); - } - n=d->nText; - if (n) - { - p->nText=n; p->pText=(XMLCSTR*)malloc(n*sizeof(XMLCSTR)); - while(n--) p->pText[n]=stringDup(d->pText[n]); - } - n=d->nClear; - if (n) - { - p->nClear=n; p->pClear=(XMLClear*)malloc(n*sizeof(XMLClear)); - while (n--) - { - p->pClear[n].lpszCloseTag=d->pClear[n].lpszCloseTag; - p->pClear[n].lpszOpenTag=d->pClear[n].lpszOpenTag; - p->pClear[n].lpszValue=stringDup(d->pClear[n].lpszValue); - } - } - n=d->nChild; - if (n) - { - p->nChild=n; p->pChild=(XMLNode*)malloc(n*sizeof(XMLNode)); - while (n--) - { - p->pChild[n].d=NULL; - p->pChild[n]=d->pChild[n].deepCopy(); - p->pChild[n].d->pParent=p; - } - } - return x; -} - -XMLNode XMLNode::addChild(XMLNode childNode, int pos) -{ - XMLNodeData *dc=childNode.d; - if ((!dc)||(!d)) return childNode; - if (!dc->lpszName) - { - // this is a root node: todo: correct fix - int j=pos; - while (dc->nChild) - { - addChild(dc->pChild[0],j); - if (pos>=0) j++; - } - return childNode; - } - if (dc->pParent) { if ((detachFromParent(dc)<=pos)&&(dc->pParent==d)) pos--; } else dc->ref_count++; - dc->pParent=d; -// int nc=d->nChild; -// d->pChild=(XMLNode*)myRealloc(d->pChild,(nc+1),memoryIncrease,sizeof(XMLNode)); - d->pChild=(XMLNode*)addToOrder(0,&pos,d->nChild,d->pChild,sizeof(XMLNode),eNodeChild); - d->pChild[pos].d=dc; - d->nChild++; - return childNode; -} - -void XMLNode::deleteAttribute(int i) -{ - if ((!d)||(i<0)||(i>=d->nAttribute)) return; - d->nAttribute--; - XMLAttribute *p=d->pAttribute+i; - free((void*)p->lpszName); - if (p->lpszValue) free((void*)p->lpszValue); - if (d->nAttribute) memmove(p,p+1,(d->nAttribute-i)*sizeof(XMLAttribute)); else { free(p); d->pAttribute=NULL; } -} - -void XMLNode::deleteAttribute(XMLAttribute *a){ if (a) deleteAttribute(a->lpszName); } -void XMLNode::deleteAttribute(XMLCSTR lpszName) -{ - int j=0; - getAttribute(lpszName,&j); - if (j) deleteAttribute(j-1); -} - -XMLAttribute *XMLNode::updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,int i) -{ - if (!d) { if (lpszNewValue) free(lpszNewValue); if (lpszNewName) free(lpszNewName); return NULL; } - if (i>=d->nAttribute) - { - if (lpszNewName) return addAttribute_WOSD(lpszNewName,lpszNewValue); - return NULL; - } - XMLAttribute *p=d->pAttribute+i; - if (p->lpszValue&&p->lpszValue!=lpszNewValue) free((void*)p->lpszValue); - p->lpszValue=lpszNewValue; - if (lpszNewName&&p->lpszName!=lpszNewName) { free((void*)p->lpszName); p->lpszName=lpszNewName; }; - return p; -} - -XMLAttribute *XMLNode::updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute) -{ - if (oldAttribute) return updateAttribute_WOSD((XMLSTR)newAttribute->lpszValue,(XMLSTR)newAttribute->lpszName,oldAttribute->lpszName); - return addAttribute_WOSD((XMLSTR)newAttribute->lpszName,(XMLSTR)newAttribute->lpszValue); -} - -XMLAttribute *XMLNode::updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,XMLCSTR lpszOldName) -{ - int j=0; - getAttribute(lpszOldName,&j); - if (j) return updateAttribute_WOSD(lpszNewValue,lpszNewName,j-1); - else - { - if (lpszNewName) return addAttribute_WOSD(lpszNewName,lpszNewValue); - else return addAttribute_WOSD(stringDup(lpszOldName),lpszNewValue); - } -} - -int XMLNode::indexText(XMLCSTR lpszValue) const -{ - if (!d) return -1; - int i,l=d->nText; - if (!lpszValue) { if (l) return 0; return -1; } - XMLCSTR *p=d->pText; - for (i=0; i=d->nText)) return; - d->nText--; - XMLCSTR *p=d->pText+i; - free((void*)*p); - if (d->nText) memmove(p,p+1,(d->nText-i)*sizeof(XMLCSTR)); else { free(p); d->pText=NULL; } - removeOrderElement(d,eNodeText,i); -} - -void XMLNode::deleteText(XMLCSTR lpszValue) { deleteText(indexText(lpszValue)); } - -XMLCSTR XMLNode::updateText_WOSD(XMLSTR lpszNewValue, int i) -{ - if (!d) { if (lpszNewValue) free(lpszNewValue); return NULL; } - if (i>=d->nText) return addText_WOSD(lpszNewValue); - XMLCSTR *p=d->pText+i; - if (*p!=lpszNewValue) { free((void*)*p); *p=lpszNewValue; } - return lpszNewValue; -} - -XMLCSTR XMLNode::updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue) -{ - if (!d) { if (lpszNewValue) free(lpszNewValue); return NULL; } - int i=indexText(lpszOldValue); - if (i>=0) return updateText_WOSD(lpszNewValue,i); - return addText_WOSD(lpszNewValue); -} - -void XMLNode::deleteClear(int i) -{ - if ((!d)||(i<0)||(i>=d->nClear)) return; - d->nClear--; - XMLClear *p=d->pClear+i; - free((void*)p->lpszValue); - if (d->nClear) memmove(p,p+1,(d->nClear-i)*sizeof(XMLClear)); else { free(p); d->pClear=NULL; } - removeOrderElement(d,eNodeClear,i); -} - -int XMLNode::indexClear(XMLCSTR lpszValue) const -{ - if (!d) return -1; - int i,l=d->nClear; - if (!lpszValue) { if (l) return 0; return -1; } - XMLClear *p=d->pClear; - for (i=0; ilpszValue); } - -XMLClear *XMLNode::updateClear_WOSD(XMLSTR lpszNewContent, int i) -{ - if (!d) { if (lpszNewContent) free(lpszNewContent); return NULL; } - if (i>=d->nClear) return addClear_WOSD(lpszNewContent); - XMLClear *p=d->pClear+i; - if (lpszNewContent!=p->lpszValue) { free((void*)p->lpszValue); p->lpszValue=lpszNewContent; } - return p; -} - -XMLClear *XMLNode::updateClear_WOSD(XMLSTR lpszNewContent, XMLCSTR lpszOldValue) -{ - if (!d) { if (lpszNewContent) free(lpszNewContent); return NULL; } - int i=indexClear(lpszOldValue); - if (i>=0) return updateClear_WOSD(lpszNewContent,i); - return addClear_WOSD(lpszNewContent); -} - -XMLClear *XMLNode::updateClear_WOSD(XMLClear *newP,XMLClear *oldP) -{ - if (oldP) return updateClear_WOSD((XMLSTR)newP->lpszValue,(XMLSTR)oldP->lpszValue); - return NULL; -} - -int XMLNode::nChildNode(XMLCSTR name) const -{ - if (!d) return 0; - int i,j=0,n=d->nChild; - XMLNode *pc=d->pChild; - for (i=0; id->lpszName, name)==0) j++; - pc++; - } - return j; -} - -XMLNode XMLNode::getChildNode(XMLCSTR name, int *j) const -{ - if (!d) return emptyXMLNode; - int i=0,n=d->nChild; - if (j) i=*j; - XMLNode *pc=d->pChild+i; - for (; id->lpszName, name)) - { - if (j) *j=i+1; - return *pc; - } - pc++; - } - return emptyXMLNode; -} - -XMLNode XMLNode::getChildNode(XMLCSTR name, int j) const -{ - if (!d) return emptyXMLNode; - if (j>=0) - { - int i=0; - while (j-->0) getChildNode(name,&i); - return getChildNode(name,&i); - } - int i=d->nChild; - while (i--) if (!xstricmp(name,d->pChild[i].d->lpszName)) break; - if (i<0) return emptyXMLNode; - return getChildNode(i); -} - -XMLNode XMLNode::getChildNodeByPath(XMLCSTR _path, char createMissing, XMLCHAR sep) -{ - XMLSTR path=stringDup(_path); - XMLNode x=getChildNodeByPathNonConst(path,createMissing,sep); - if (path) free(path); - return x; -} - -XMLNode XMLNode::getChildNodeByPathNonConst(XMLSTR path, char createIfMissing, XMLCHAR sep) -{ - if ((!path)||(!(*path))) return *this; - XMLNode xn,xbase=*this; - XMLCHAR *tend1,sepString[2]; sepString[0]=sep; sepString[1]=0; - tend1=xstrstr(path,sepString); - while(tend1) - { - *tend1=0; - xn=xbase.getChildNode(path); - if (xn.isEmpty()) - { - if (createIfMissing) xn=xbase.addChild(path); - else { *tend1=sep; return XMLNode::emptyXMLNode; } - } - *tend1=sep; - xbase=xn; - path=tend1+1; - tend1=xstrstr(path,sepString); - } - xn=xbase.getChildNode(path); - if (xn.isEmpty()&&createIfMissing) xn=xbase.addChild(path); - return xn; -} - -XMLElementPosition XMLNode::positionOfText (int i) const { if (i>=d->nText ) i=d->nText-1; return findPosition(d,i,eNodeText ); } -XMLElementPosition XMLNode::positionOfClear (int i) const { if (i>=d->nClear) i=d->nClear-1; return findPosition(d,i,eNodeClear); } -XMLElementPosition XMLNode::positionOfChildNode(int i) const { if (i>=d->nChild) i=d->nChild-1; return findPosition(d,i,eNodeChild); } -XMLElementPosition XMLNode::positionOfText (XMLCSTR lpszValue) const { return positionOfText (indexText (lpszValue)); } -XMLElementPosition XMLNode::positionOfClear(XMLCSTR lpszValue) const { return positionOfClear(indexClear(lpszValue)); } -XMLElementPosition XMLNode::positionOfClear(XMLClear *a) const { if (a) return positionOfClear(a->lpszValue); return positionOfClear(); } -XMLElementPosition XMLNode::positionOfChildNode(XMLNode x) const -{ - if ((!d)||(!x.d)) return -1; - XMLNodeData *dd=x.d; - XMLNode *pc=d->pChild; - int i=d->nChild; - while (i--) if (pc[i].d==dd) return findPosition(d,i,eNodeChild); - return -1; -} -XMLElementPosition XMLNode::positionOfChildNode(XMLCSTR name, int count) const -{ - if (!name) return positionOfChildNode(count); - int j=0; - do { getChildNode(name,&j); if (j<0) return -1; } while (count--); - return findPosition(d,j-1,eNodeChild); -} - -XMLNode XMLNode::getChildNodeWithAttribute(XMLCSTR name,XMLCSTR attributeName,XMLCSTR attributeValue, int *k) const -{ - int i=0,j; - if (k) i=*k; - XMLNode x; - XMLCSTR t; - do - { - x=getChildNode(name,&i); - if (!x.isEmpty()) - { - if (attributeValue) - { - j=0; - do - { - t=x.getAttribute(attributeName,&j); - if (t&&(xstricmp(attributeValue,t)==0)) { if (k) *k=i; return x; } - } while (t); - } else - { - if (x.isAttributeSet(attributeName)) { if (k) *k=i; return x; } - } - } - } while (!x.isEmpty()); - return emptyXMLNode; -} - -// Find an attribute on an node. -XMLCSTR XMLNode::getAttribute(XMLCSTR lpszAttrib, int *j) const -{ - if (!d) return NULL; - int i=0,n=d->nAttribute; - if (j) i=*j; - XMLAttribute *pAttr=d->pAttribute+i; - for (; ilpszName, lpszAttrib)==0) - { - if (j) *j=i+1; - return pAttr->lpszValue; - } - pAttr++; - } - return NULL; -} - -char XMLNode::isAttributeSet(XMLCSTR lpszAttrib) const -{ - if (!d) return FALSE; - int i,n=d->nAttribute; - XMLAttribute *pAttr=d->pAttribute; - for (i=0; ilpszName, lpszAttrib)==0) - { - return TRUE; - } - pAttr++; - } - return FALSE; -} - -XMLCSTR XMLNode::getAttribute(XMLCSTR name, int j) const -{ - if (!d) return NULL; - int i=0; - while (j-->0) getAttribute(name,&i); - return getAttribute(name,&i); -} - -XMLNodeContents XMLNode::enumContents(int i) const -{ - XMLNodeContents c; - if (!d) { c.etype=eNodeNULL; return c; } - if (inAttribute) - { - c.etype=eNodeAttribute; - c.attrib=d->pAttribute[i]; - return c; - } - i-=d->nAttribute; - c.etype=(XMLElementType)(d->pOrder[i]&3); - i=(d->pOrder[i])>>2; - switch (c.etype) - { - case eNodeChild: c.child = d->pChild[i]; break; - case eNodeText: c.text = d->pText[i]; break; - case eNodeClear: c.clear = d->pClear[i]; break; - default: break; - } - return c; -} - -XMLCSTR XMLNode::getName() const { if (!d) return NULL; return d->lpszName; } -int XMLNode::nText() const { if (!d) return 0; return d->nText; } -int XMLNode::nChildNode() const { if (!d) return 0; return d->nChild; } -int XMLNode::nAttribute() const { if (!d) return 0; return d->nAttribute; } -int XMLNode::nClear() const { if (!d) return 0; return d->nClear; } -int XMLNode::nElement() const { if (!d) return 0; return d->nAttribute+d->nChild+d->nText+d->nClear; } -XMLClear XMLNode::getClear (int i) const { if ((!d)||(i>=d->nClear )) return emptyXMLClear; return d->pClear[i]; } -XMLAttribute XMLNode::getAttribute (int i) const { if ((!d)||(i>=d->nAttribute)) return emptyXMLAttribute; return d->pAttribute[i]; } -XMLCSTR XMLNode::getAttributeName (int i) const { if ((!d)||(i>=d->nAttribute)) return NULL; return d->pAttribute[i].lpszName; } -XMLCSTR XMLNode::getAttributeValue(int i) const { if ((!d)||(i>=d->nAttribute)) return NULL; return d->pAttribute[i].lpszValue; } -XMLCSTR XMLNode::getText (int i) const { if ((!d)||(i>=d->nText )) return NULL; return d->pText[i]; } -XMLNode XMLNode::getChildNode (int i) const { if ((!d)||(i>=d->nChild )) return emptyXMLNode; return d->pChild[i]; } -XMLNode XMLNode::getParentNode ( ) const { if ((!d)||(!d->pParent )) return emptyXMLNode; return XMLNode(d->pParent); } -char XMLNode::isDeclaration ( ) const { if (!d) return 0; return d->isDeclaration; } -char XMLNode::isEmpty ( ) const { return (d==NULL); } -XMLNode XMLNode::emptyNode ( ) { return XMLNode::emptyXMLNode; } - -XMLNode XMLNode::addChild(XMLCSTR lpszName, char isDeclaration, XMLElementPosition pos) - { return addChild_priv(0,stringDup(lpszName),isDeclaration,pos); } -XMLNode XMLNode::addChild_WOSD(XMLSTR lpszName, char isDeclaration, XMLElementPosition pos) - { return addChild_priv(0,lpszName,isDeclaration,pos); } -XMLAttribute *XMLNode::addAttribute(XMLCSTR lpszName, XMLCSTR lpszValue) - { return addAttribute_priv(0,stringDup(lpszName),stringDup(lpszValue)); } -XMLAttribute *XMLNode::addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValuev) - { return addAttribute_priv(0,lpszName,lpszValuev); } -XMLCSTR XMLNode::addText(XMLCSTR lpszValue, XMLElementPosition pos) - { return addText_priv(0,stringDup(lpszValue),pos); } -XMLCSTR XMLNode::addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos) - { return addText_priv(0,lpszValue,pos); } -XMLClear *XMLNode::addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, XMLElementPosition pos) - { return addClear_priv(0,stringDup(lpszValue),lpszOpen,lpszClose,pos); } -XMLClear *XMLNode::addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, XMLElementPosition pos) - { return addClear_priv(0,lpszValue,lpszOpen,lpszClose,pos); } -XMLCSTR XMLNode::updateName(XMLCSTR lpszName) - { return updateName_WOSD(stringDup(lpszName)); } -XMLAttribute *XMLNode::updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute) - { return updateAttribute_WOSD(stringDup(newAttribute->lpszValue),stringDup(newAttribute->lpszName),oldAttribute->lpszName); } -XMLAttribute *XMLNode::updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,int i) - { return updateAttribute_WOSD(stringDup(lpszNewValue),stringDup(lpszNewName),i); } -XMLAttribute *XMLNode::updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName) - { return updateAttribute_WOSD(stringDup(lpszNewValue),stringDup(lpszNewName),lpszOldName); } -XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, int i) - { return updateText_WOSD(stringDup(lpszNewValue),i); } -XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue) - { return updateText_WOSD(stringDup(lpszNewValue),lpszOldValue); } -XMLClear *XMLNode::updateClear(XMLCSTR lpszNewContent, int i) - { return updateClear_WOSD(stringDup(lpszNewContent),i); } -XMLClear *XMLNode::updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue) - { return updateClear_WOSD(stringDup(lpszNewValue),lpszOldValue); } -XMLClear *XMLNode::updateClear(XMLClear *newP,XMLClear *oldP) - { return updateClear_WOSD(stringDup(newP->lpszValue),oldP->lpszValue); } - -char XMLNode::setGlobalOptions(XMLCharEncoding _characterEncoding, char _guessWideCharChars, - char _dropWhiteSpace, char _removeCommentsInMiddleOfText) -{ - guessWideCharChars=_guessWideCharChars; dropWhiteSpace=_dropWhiteSpace; removeCommentsInMiddleOfText=_removeCommentsInMiddleOfText; -#ifdef _XMLWIDECHAR - if (_characterEncoding) characterEncoding=_characterEncoding; -#else - switch(_characterEncoding) - { - case char_encoding_UTF8: characterEncoding=_characterEncoding; XML_ByteTable=XML_utf8ByteTable; break; - case char_encoding_legacy: characterEncoding=_characterEncoding; XML_ByteTable=XML_legacyByteTable; break; - case char_encoding_ShiftJIS: characterEncoding=_characterEncoding; XML_ByteTable=XML_sjisByteTable; break; - case char_encoding_GB2312: characterEncoding=_characterEncoding; XML_ByteTable=XML_gb2312ByteTable; break; - case char_encoding_Big5: - case char_encoding_GBK: characterEncoding=_characterEncoding; XML_ByteTable=XML_gbk_big5_ByteTable; break; - default: return 1; - } -#endif - return 0; -} - -XMLNode::XMLCharEncoding XMLNode::guessCharEncoding(void *buf,int l, char useXMLEncodingAttribute) -{ -#ifdef _XMLWIDECHAR - return (XMLCharEncoding)0; -#else - if (l<25) return (XMLCharEncoding)0; - if (guessWideCharChars&&(myIsTextWideChar(buf,l))) return (XMLCharEncoding)0; - unsigned char *b=(unsigned char*)buf; - if ((b[0]==0xef)&&(b[1]==0xbb)&&(b[2]==0xbf)) return char_encoding_UTF8; - - // Match utf-8 model ? - XMLCharEncoding bestGuess=char_encoding_UTF8; - int i=0; - while (i>2 ]; - *(curr++)=base64EncodeTable[(inbuf[0]<<4)&0x3F]; - *(curr++)=base64Fillchar; - *(curr++)=base64Fillchar; - } else if (eLen==2) - { - j=(inbuf[0]<<8)|inbuf[1]; - *(curr++)=base64EncodeTable[ j>>10 ]; - *(curr++)=base64EncodeTable[(j>> 4)&0x3f]; - *(curr++)=base64EncodeTable[(j<< 2)&0x3f]; - *(curr++)=base64Fillchar; - } - *(curr++)=0; - return (XMLSTR)buf; -} - -unsigned int XMLParserBase64Tool::decodeSize(XMLCSTR data,XMLError *xe) -{ - if (!data) return 0; - if (xe) *xe=eXMLErrorNone; - int size=0; - unsigned char c; - //skip any extra characters (e.g. newlines or spaces) - while (*data) - { -#ifdef _XMLWIDECHAR - if (*data>255) { if (xe) *xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } -#endif - c=base64DecodeTable[(unsigned char)(*data)]; - if (c<97) size++; - else if (c==98) { if (xe) *xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } - data++; - } - if (xe&&(size%4!=0)) *xe=eXMLErrorBase64DataSizeIsNotMultipleOf4; - if (size==0) return 0; - do { data--; size--; } while(*data==base64Fillchar); size++; - return (unsigned int)((size*3)/4); -} - -unsigned char XMLParserBase64Tool::decode(XMLCSTR data, unsigned char *buf, int len, XMLError *xe) -{ - if (!data) return 0; - if (xe) *xe=eXMLErrorNone; - int i=0,p=0; - unsigned char d,c; - for(;;) - { - -#ifdef _XMLWIDECHAR -#define BASE64DECODE_READ_NEXT_CHAR(c) \ - do { \ - if (data[i]>255){ c=98; break; } \ - c=base64DecodeTable[(unsigned char)data[i++]]; \ - }while (c==97); \ - if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } -#else -#define BASE64DECODE_READ_NEXT_CHAR(c) \ - do { c=base64DecodeTable[(unsigned char)data[i++]]; }while (c==97); \ - if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; } -#endif - - BASE64DECODE_READ_NEXT_CHAR(c) - if (c==99) { return 2; } - if (c==96) - { - if (p==(int)len) return 2; - if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; - return 1; - } - - BASE64DECODE_READ_NEXT_CHAR(d) - if ((d==99)||(d==96)) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } - if (p==(int)len) { if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall; return 0; } - buf[p++]=(unsigned char)((c<<2)|((d>>4)&0x3)); - - BASE64DECODE_READ_NEXT_CHAR(c) - if (c==99) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } - if (p==(int)len) - { - if (c==96) return 2; - if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall; - return 0; - } - if (c==96) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } - buf[p++]=(unsigned char)(((d<<4)&0xf0)|((c>>2)&0xf)); - - BASE64DECODE_READ_NEXT_CHAR(d) - if (d==99 ) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } - if (p==(int)len) - { - if (d==96) return 2; - if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall; - return 0; - } - if (d==96) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; } - buf[p++]=(unsigned char)(((c<<6)&0xc0)|d); - } -} -#undef BASE64DECODE_READ_NEXT_CHAR - -void XMLParserBase64Tool::alloc(int newsize) -{ - if ((!buf)&&(newsize)) { buf=malloc(newsize); buflen=newsize; return; } - if (newsize>buflen) { buf=realloc(buf,newsize); buflen=newsize; } -} - -unsigned char *XMLParserBase64Tool::decode(XMLCSTR data, int *outlen, XMLError *xe) -{ - if (xe) *xe=eXMLErrorNone; - if (!data) { *outlen=0; return (unsigned char*)""; } - unsigned int len=decodeSize(data,xe); - if (outlen) *outlen=len; - if (!len) return NULL; - alloc(len+1); - if(!decode(data,(unsigned char*)buf,len,xe)){ return NULL; } - return (unsigned char*)buf; -} - diff --git a/source/common/xmlParser.h b/source/common/xmlParser.h deleted file mode 100644 index 1187165..0000000 --- a/source/common/xmlParser.h +++ /dev/null @@ -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.
- * Commercialized by Business-Insight
- * See the file AFPL-license.txt about the licensing terms - * - * \section tutorial First Tutorial - * You can follow a simple Tutorial to know the basics... - * - * \section usage General usage: How to include the XMLParser library inside your project. - * - * The library is composed of two files: xmlParser.cpp and - * xmlParser.h. 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 - * xmlParser.h. 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 - * xmlParser.html - * - * Some additional small examples are also inside the file xmlTest.cpp - * (for the "char*" version of the library) and inside the file - * xmlTestUnicode.cpp (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 - * xmlParser.cpp and - * xmlParser.h files into the project). - * - * The file XMLNodeAutoexp.txt 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 - -#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 or libraries anymore to compile) -//#define XML_NO_WIDE_CHAR - -#ifdef XML_NO_WIDE_CHAR -#undef _XMLWINDOWS -#undef _XMLWIDECHAR -#endif - -#ifdef _XMLWINDOWS -#include -#else -#define XMLDLLENTRY -#ifndef XML_NO_WIDE_CHAR -#include // 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: - *
    - *
  • XMLNode::parseString
  • - *
  • XMLNode::parseFile
  • - *
  • XMLNode::openFileHelper
  • - *
  • XMLNode::createXMLTopNode (or XMLNode::createXMLTopNode_WOSD)
  • - *
*/ -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).
- * - * REMARK: 0 <= pos < nChild()+nText()+nClear()
- */ - - /** @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 "" - */ - /** @} */ - - /** @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("foobarchu","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) --> "" - * x.getClear(1) --> "" - * \endcode - * If removeCommentsInMiddleOfText=1, then we will have: - * \code - * x.getText(0) -> "foobar" - * x.getText(1) -> "chu" - * x.getClear(0) --> "" - * \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 - '' - struct XMLNodeDataTag *pParent; // Pointer to parent element (=NULL if root) - XMLNode *pChild; // Array of child nodes - XMLCSTR *pText; // Array of text fields - XMLClear *pClear; // Array of clear fields - XMLAttribute *pAttribute; // Array of attributes - int *pOrder; // order of the child_nodes,text_fields,clear_fields - int ref_count; // for garbage collection (smart pointers) - } XMLNodeData; - XMLNodeData *d; - - char parseClearTag(void *px, void *pa); - char maybeAddTxT(void *pa, XMLCSTR tokenPStr); - int ParseXMLElement(void *pXML); - void *addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype); - int indexText(XMLCSTR lpszValue) const; - int indexClear(XMLCSTR lpszValue) const; - XMLNode addChild_priv(int,XMLSTR,char,int); - XMLAttribute *addAttribute_priv(int,XMLSTR,XMLSTR); - XMLCSTR addText_priv(int,XMLSTR,int); - XMLClear *addClear_priv(int,XMLSTR,XMLCSTR,XMLCSTR,int); - void emptyTheNode(char force); - static inline XMLElementPosition findPosition(XMLNodeData *d, int index, XMLElementType xtype); - static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat); - static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index); - static void exactMemory(XMLNodeData *d); - static int detachFromParent(XMLNodeData *d); -} XMLNode; - -/// This structure is given by the function XMLNode::enumContents. -typedef struct XMLNodeContents -{ - /// This dictates what's the content of the XMLNodeContent - enum XMLElementType etype; - /**< should be an union to access the appropriate data. Compiler does not allow union of object with constructor... too bad. */ - XMLNode child; - XMLAttribute attrib; - XMLCSTR text; - XMLClear clear; - -} XMLNodeContents; - -/** @defgroup StringAlloc String Allocation/Free functions - * @ingroup xmlModify - * @{ */ -/// Duplicate (copy in a new allocated buffer) the source string. -XMLDLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData=-1); -/**< This is - * a very handy function when used with all the "XMLNode::*_WOSD" functions (\link xmlWOSD \endlink). - * @param cbData If !=0 then cbData is the number of chars to duplicate. New strings allocated with - * this function should be free'd using the "freeXMLString" function. */ - -/// to free the string allocated inside the "stringDup" function or the "createXMLString" function. -XMLDLLENTRY void freeXMLString(XMLSTR t); // {free(t);} -/** @} */ - -/** @defgroup atoX ato? like functions - * @ingroup XMLParserGeneral - * The "xmlto?" functions are equivalents to the atoi, atol, atof functions. - * The only difference is: If the variable "xmlString" is NULL, than the return value - * is "defautValue". These 6 functions are only here as "convenience" functions for the - * user (they are not used inside the XMLparser). If you don't need them, you can - * delete them without any trouble. - * - * @{ */ -XMLDLLENTRY char xmltob(XMLCSTR xmlString,char defautValue=0); -XMLDLLENTRY int xmltoi(XMLCSTR xmlString,int defautValue=0); -XMLDLLENTRY long long xmltol(XMLCSTR xmlString,long long defautValue=0); -XMLDLLENTRY double xmltof(XMLCSTR xmlString,double defautValue=.0); -XMLDLLENTRY XMLCSTR xmltoa(XMLCSTR xmlString,XMLCSTR defautValue=_CXML("")); -XMLDLLENTRY XMLCHAR xmltoc(XMLCSTR xmlString,const XMLCHAR defautValue=_CXML('\0')); -/** @} */ - -/** @defgroup ToXMLStringTool Helper class to create XML files using "printf", "fprintf", "cout",... functions. - * @ingroup XMLParserGeneral - * @{ */ -/// Helper class to create XML files using "printf", "fprintf", "cout",... functions. -/** The ToXMLStringTool class helps you creating XML files using "printf", "fprintf", "cout",... functions. - * The "ToXMLStringTool" class is processing strings so that all the characters - * &,",',<,> are replaced by their XML equivalent: - * \verbatim &, ", ', <, > \endverbatim - * Using the "ToXMLStringTool class" and the "fprintf function" is THE most efficient - * way to produce VERY large XML documents VERY fast. - * \note If you are creating from scratch an XML file using the provided XMLNode class - * you must not use the "ToXMLStringTool" class (because the "XMLNode" class does the - * processing job for you during rendering).*/ -typedef struct XMLDLLENTRY ToXMLStringTool -{ -public: - ToXMLStringTool(): buf(NULL),buflen(0){} - ~ToXMLStringTool(); - void freeBuffer();///