// // File: hzDomain.cpp // // Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com) // // The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free // Software Foundation, either version 3 of the License, or any later version. // // The HadronZoo C++ Class Library 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses. //
// // Implimentation of the hzDomain (domain name) class. //
#include <iostream>
#include <stdarg.h>
#include "hzChars.h" #include "hzTextproc.h" #include "hzProcess.h" #include "hzSSR.h"
/* ** Definitions */
struct _dom_space { // Internal structure for domain name stringspace. Note there is no constructor as string spaces are allocated by Alloc() from superblocks.
uchar m_copy ; // Copy counter uchar m_len ; // Length uchar m_tld ; // Offset to top-level domain (right of the last period) char m_data[5] ; // First part of data } ;
#define DOM_FACTOR 4 // This is added to the domain string size to accomodate the copy count and the size of the domain name string plus the null terminator.
/* ** Global constants */
global const hzDomain _hz_null_hzDomain ; // Null domain name
/* ** Small String Regime */
extern hzSSR g_ssrInet ;
/* ** hzDomain public methods */
void hzDomain::Clear (void) { // Clear the contents // // Arguments: None // Returns: None
_hzfunc("hzDomain::Clear") ;
_dom_space* thisCtl ; // This domain name space
if (m_addr) { thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; if (!thisCtl) hzexit(E_CORRUPT, "Illegal domain address %u:%u", (m_addr&0x7ffff0000)>>16, m_addr&0xffff) ;
if (!thisCtl->m_len) hzexit(E_CORRUPT, "Zero domain length %u:%u", (m_addr&0x7ffff0000)>>16, m_addr&0xffff) ;
if (_hzGlobal_MT) { //__sync_add_and_fetch(&(thisCtl->m_copy), -1) ;
thisCtl->m_copy-- ; if (!thisCtl->m_copy) g_ssrInet.Free(m_addr, thisCtl->m_len + DOM_FACTOR) ; } else { thisCtl->m_copy-- ; if (!thisCtl->m_copy) g_ssrInet.Free(m_addr, thisCtl->m_len + DOM_FACTOR) ; }
m_addr = 0 ; } }
uint32_t hzDomain::Length (void) const { // Return length in bytes of the whole domain name
_hzfunc("hzDomain::Length") ;
_dom_space* thisCtl ; // This domain name space
if (!m_addr) return 0 ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; return thisCtl->m_len ; }
uint32_t hzDomain::Copies (void) const { // Return number of copies for diagnostics
_hzfunc("hzDomain::Copies") ;
_dom_space* thisCtl ; // This email address space
if (!m_addr) return 0 ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; if (!thisCtl) { threadLog("Ivalid domain space %u:%u\n", (m_addr&0x7fff000)>>16, m_addr&0xffff) ; return 0 ; }
return thisCtl->m_copy ; }
void hzDomain::_inc_copy (void) const { _dom_space* thisCtl ; // This string's control area
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; if (thisCtl->m_copy < 100) thisCtl->m_copy++ ; }
void hzDomain::_dec_copy (void) const { _dom_space* thisCtl ; // This string's control area
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ;
if (thisCtl->m_copy == 1) threadLog("WARNING: DOM _dec_copy would zero copy count\n") ; else thisCtl->m_copy-- ; }
bool hzDomain::valid (void) const { _dom_space* pCtrl ; // This string's control area //g_ssrInet.FLE* pSlot ; // Item cast to g_ssrInet.FLE (to self point on free and to check it is not already free)
pCtrl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; //pSlot = (g_ssrInet.FLE*) pCtrl ;
if (pCtrl->m_copy == 0 || pCtrl->m_copy == 0xff || !pCtrl->m_len || !pCtrl->m_tld) // || pSlot->m_fleSelf == m_addr) return false ; return true ; }
const char* hzDomain::GetDomain (void) const { // Return domain name as null terminated string
_hzfunc("hzDomain::GetDomain") ;
_dom_space* thisCtl ; // This domain name space
if (!m_addr) return 0 ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; return thisCtl->m_data ; }
const char* hzDomain::GetTLD (void) const { // Return whole domain name as null terminated string
_hzfunc("hzDomain::GetAddress") ;
_dom_space* thisCtl ; // This domain name space
if (!m_addr) return 0 ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; return thisCtl->m_data + thisCtl->m_tld + 1 ; }
static uint32_t _ckDomain (uint32_t& lastPeriod, const char* cpStr) { // Tests if a supplied string (or text at a hzChain iterator) is of the form of an domain name. // // Permitted chars are: [a-z], [A-Z], [0-9] and the period (.) or minus sign (-) if they are not the last character in the string. // // Arguments: 1) cpStr The char pointer to be tested // // Returns: True If the supplied cstr sets the domain name // False Otherwise
_hzfunc("IsDomain") ;
const char* i ; // Source string iterator uint32_t nC ; // Char count uint32_t nPeriod ; // Confirmed period, last position
if (!cpStr || !cpStr[0]) return false ;
// Count chars beyond @ for (nC = nPeriod = 0, i = cpStr ; *i && nC < 256 ; i++) { if (*i == CHAR_PERIOD) nPeriod = nC ;
if ((*i >= 'a' && *i <= 'z') || (*i >= 'A' && *i <= 'Z') || (*i >= '0' && *i <= '9') || (*i == CHAR_MINUS && i[1] > CHAR_SPACE && nC) || (*i == CHAR_PERIOD && i[1] > CHAR_SPACE && nC)) { nC++ ; continue ; } return 0 ; }
if (nC < 2 || nC > 253) return 0 ;
lastPeriod = nPeriod ; return nC ; }
hzDomain& hzDomain::operator= (const char* cpStr) { // Assign the hzDomain to an domain name held in a character string // // Arguments: 1) cpStr A null terminated string assumed to be an domain name // // Returns: Reference to this email adress instance in all cases. // // Note: This function will record an E_FORMAT error if the supplied cstr did not amount to an domain name
_hzfunc("hzDomain::operator=(cstr)") ;
_dom_space* destCtl ; // This domain name space const char* i ; // Email iterator char* j ; // Email iterator uint32_t nLen = 0 ; // Length of domain name uint32_t nLP = 0 ; // Offset to last period
Clear() ;
if (!cpStr || !cpStr[0]) return *this ;
nLen = _ckDomain(nLP, cpStr) ; if (!nLen) { hzerr(E_FORMAT, "Cannot assign %s", cpStr) ; return *this ; }
m_addr = g_ssrInet.Alloc(nLen + DOM_FACTOR) ; if (!m_addr) hzexit(E_MEMORY, "Cannot assign %s", cpStr) ; destCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ;
// Assign the value destCtl->m_copy = 1 ; destCtl->m_len = nLen & 0xff ; destCtl->m_tld = nLP & 0xff ; for (j = destCtl->m_data, i = cpStr ; *i ; *j++ = _tolower(*i++)) ; *j = 0 ; return *this ; }
hzDomain& hzDomain::operator= (const hzString& S) { // Assign the hzDomain to an domain name held in a hzString instance // // Arguments: 1) S A string assumed to be an domain name // // Returns: Reference to this email adress instance in all cases. // // Note: This function will record an E_FORMAT error if the supplied cstr did not amount to an domain name
_hzfunc("hzDomain::operator=(hzStr)") ;
Clear() ; return operator=(*S) ; }
hzDomain& hzDomain::operator= (const hzChain::Iter& ci) { // Determines if the supplied iterator is at the start of a valid domain name and if it is, assignes this as the value to the calling instance. // // Arguments: 1) ci Chain iterator // // Returns: Reference to this domain name instance. This will be empty if the input did not amount to an domain name
_hzfunc("hzDomain::operator=(chIter)") ;
hzChain::Iter xi ; // External chain iterator
_dom_space* thisCtl ; // This domain name space char* i ; // For populating string uint32_t n ; // Counter uchar nC ; // Chars count uint32_t nPeriod ; // Position of last period
Clear() ; if (ci.eof()) return *this ;
// Process the string and set char incidence aggregates for (nC = nPeriod = 0, xi = ci ; !xi.eof() && *xi > CHAR_SPACE & nC < 256 ; nC++, *xi, xi++) { if (*xi == CHAR_PERIOD) nPeriod = nC ;
if (!((*xi >= 'a' && *xi <= 'z') || (*xi >= 'A' && *xi <= 'Z') || (*xi >= '0' && *xi <= '9') || (*xi == CHAR_MINUS && i[1] > CHAR_SPACE && nC) || (*xi == CHAR_PERIOD && i[1] > CHAR_SPACE && nC))) break ; }
if (*xi > CHAR_SPACE || !nPeriod || nC > 253 || nC < 2) { hzerr(E_FORMAT, "Cannot assign") ; return *this ; }
m_addr = g_ssrInet.Alloc(nC + DOM_FACTOR) ; if (!m_addr) hzexit(E_MEMORY, "Cannot assign %d bytes", nC + 5) ; thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ;
i = (char*) thisCtl->m_data ;
for (xi = ci, n = 0 ; n <= nC ; n++, xi++) { i[n] = _tolower(*xi) ; } i[n] = 0 ;
thisCtl->m_copy = 1 ; thisCtl->m_len = nC & 0xff ; thisCtl->m_tld = nPeriod & 0xff ;
return *this ; }
hzDomain& hzDomain::operator= (const hzDomain& dom) { // Assign the hzDomain to an domain name held in another hzDomain instance // // Arguments: 1) E The supplied domain name as a hzEmail instance // // Returns: Reference to this hzEmail instance
// It this internal pointer and that of the operand already point to the same space in memory, do nothing
_hzfunc("hzDomain::operator=(hzDomain)") ;
_dom_space* suppCtl ; // Supplied domain name space
if (m_addr == dom.m_addr) return *this ;
Clear() ;
if (dom.m_addr) { //_copyadd() ; suppCtl = (_dom_space*) g_ssrInet.Xlate(dom.m_addr) ;
if (_hzGlobal_MT) suppCtl->m_copy++ ; //__sync_add_and_fetch(&(suppCtl->m_copy), 1) ; else suppCtl->m_copy++ ;
m_addr = dom.m_addr ; }
return *this ; }
/* ** Compare operators */
bool hzDomain::operator== (const hzDomain& E) const { // Test for equality between this hzDomain and an operand instance // // Arguments: 1) E Test domain name // // Returns: True If this addesss is equal to the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator==") ;
_dom_space* thisCtl ; // This domain name space _dom_space* suppCtl ; // Supplied domain name space
if (m_addr == E.m_addr) return true ; if (m_addr && E.m_addr == 0) return false ; if (E.m_addr && m_addr == 0) return false ;
// Compare domains first then LHS thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; suppCtl = (_dom_space*) g_ssrInet.Xlate(E.m_addr) ;
if (!strcmp(thisCtl->m_data, suppCtl->m_data)) return true ; return false ; }
bool hzDomain::operator< (const hzDomain& E) const { // Return true if this hzDomain instance is lexically less than the operand. Note that comparison is first done on the domain part (the RHS // of the @) and then done on the address part (the LHS of the @) // // Arguments: 1) E Test domain name // // Returns: True If this addesss is lexically less than the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator<") ;
int32_t res ;
// Are this and the operand connected? if (m_addr == E.m_addr) return false ; if (m_addr && E.m_addr == 0) return false ; if (E.m_addr && m_addr == 0) return true ;
// Compare domains first res = strcmp(GetDomain(), E.GetDomain()) ; if (res < 0) return true ; return false ; }
bool hzDomain::operator<= (const hzDomain& E) const { // Return true if this hzDomain instance is lexically less than or equal to the operand. Note that comparison is first done on the domain // part (the RHS of the @) and then done on the address part (the LHS of the @) // // Arguments: 1) E Test domain name // // Returns: True If this addesss is lexically less than or equal to the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator<=") ;
int32_t res ; // Comparison result
// Are this and the operand connected? if (m_addr == E.m_addr) return true ; if (m_addr && E.m_addr == 0) return false ; if (E.m_addr && m_addr == 0) return true ;
// Compare domains first res = strcmp(GetDomain(), E.GetDomain()) ; if (res > 0) return false ; return true ; }
bool hzDomain::operator> (const hzDomain& E) const { // Return true if this hzDomain instance is lexically greater than the operand. Note that comparison is first done on the domain // part (the RHS of the @) and then done on the address part (the LHS of the @) // // Arguments: 1) E Test domain name // // Returns: True If this addesss is lexically greater than the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator>") ;
int32_t res ; // Comparison result
// Are this and the operand connected? if (m_addr == E.m_addr) return false ; if (m_addr && E.m_addr == 0) return true ; if (E.m_addr && m_addr == 0) return false ;
// Compare domains first res = strcmp(GetDomain(), E.GetDomain()) ; if (res > 0) return true ; return false ; }
bool hzDomain::operator>= (const hzDomain& E) const { // Return true if this hzDomain instance is lexically greater than or equal to the operand. Note that comparison is first done on the domain // part (the RHS of the @) and then done on the address part (the LHS of the @) // // Arguments: 1) E Test domain name // // Returns: True If this addesss is lexically greater than or equal to the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator>=") ;
int32_t res ; // Comparison result
// Are this and the operand connected? if (m_addr == E.m_addr) return true ; if (m_addr && E.m_addr == 0) return true ; if (E.m_addr && m_addr == 0) return false ;
// Compare domains first res = strcmp(GetDomain(), E.GetDomain()) ; if (res < 0) return false ; return true ; }
bool hzDomain::operator== (const hzString& S) const { // Test for equality between this hzDomain and an domain name held in a hzString // // Arguments: 1) E Test domain name // // Returns: True If this addesss is lexically equal to the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator==") ;
_dom_space* thisCtl ; // This domain name space
if (!S && !m_addr) return true ; if (!S) return false ; if (!m_addr) return false ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) thisCtl->m_data, *S) == 0 ? true : false ; }
bool hzDomain::operator!= (const hzString& S) const { // Test for inequality between this hzDomain and an domain name held in a hzString // // Arguments: 1) E Test domain name // // Returns: True If this addesss is not lexically equal to the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator!=") ;
_dom_space* thisCtl ; // This domain name space
if (!S && !m_addr) return false ; if (!S) return true ; if (!m_addr) return true ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) thisCtl->m_data, *S) == 0 ? false : true ; }
bool hzDomain::operator== (const char* cpStr) const { // Test for equality between this hzDomain and an domain name held in a character string // // Arguments: 1) E Test domain name // // Returns: True If this addesss is lexically equal to the supplied test domain name // False Otherwise
_hzfunc("hzDomain::operator==") ;
_dom_space* thisCtl ; // This domain name space
if ((!cpStr || !cpStr[0]) && !m_addr) return true ; if (!cpStr || !cpStr[0]) return false ; if (!m_addr) return false ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) thisCtl->m_data, cpStr) == 0 ? true : false ; }
bool hzDomain::operator!= (const char* cpStr) const { // Test for inequality between this hzDomain and an domain name held in a character string // // Arguments: 1) E Test domain name // // Returns: True If this email addesss is not lexically equal to the supplied // False If this domain name has the same value as the supplied
_hzfunc("hzDomain::operator!=") ;
_dom_space* thisCtl ; // This domain name space
if ((!cpStr || !cpStr[0]) && !m_addr) return false ; if (!cpStr || !cpStr[0]) return true ; if (!m_addr) return true ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ;
return CstrCompare((char*) thisCtl->m_data, cpStr) == 0 ? false:true ; }
const char* hzDomain::operator* (void) const { // Returns the URL data (a null terminated string) // // Arguments: None // Returns: Content as null terminated string
_hzfunc("hzDomain::operator*") ;
_dom_space* thisCtl ; // This string's control area
if (!m_addr) return 0 ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; return thisCtl->m_data ; }
hzDomain::operator const char* (void) const { // Returns the string data (a null terminated string) // // Arguments: None // Returns: Content as null terminated string
_hzfunc("hzDomain::operator const char*") ;
_dom_space* thisCtl ; // This string's control area
if (!m_addr) return 0 ;
thisCtl = (_dom_space*) g_ssrInet.Xlate(m_addr) ; return thisCtl->m_data ; }
/* ** Stream operator */
std::ostream& operator<< (std::ostream& os, const hzDomain& obj) { // Category: Data Output // // Friend function to hzDomain class to stream out the domain name. // // Arguments: 1) os Reference to output stream // 2) ema Const reference to an domain name // // Returns: Reference to the supplied output stream
_hzfunc("operator<<(ostream,hzDomain)") ;
os << *obj ; return os ; }
bool IsDomain (const char* cpStr) { // Category: Text Processing // // Tests if a supplied string (or text at a hzChain iterator) is of the form of an domain name. // // Permitted chars are: [a-z], [A-Z], [0-9] and the period (.) or minus sign (-) if they are not the last character in the string. // // Arguments: 1) cpStr The char pointer to be tested // // Returns: True If the supplied cstr sets the domain name // False Otherwise
_hzfunc("IsDomain") ;
const char* i ; // Source string iterator uint32_t nC = 0 ; // Char count bool bPeriod = false ; // Confirmed period
if (!cpStr || !cpStr[0]) return false ;
// Count chars beyond @ for (i = cpStr ; *i ; i++) { if (*i == CHAR_PERIOD) bPeriod = true ;
if ((*i >= 'a' && *i <= 'z') || (*i >= 'A' && *i <= 'Z') || (*i >= '0' && *i <= '9') || (*i == CHAR_MINUS && i[1] > CHAR_SPACE && nC) || (*i == CHAR_PERIOD && i[1] > CHAR_SPACE && nC)) { nC++ ; continue ; } return false ; }
if (bPeriod && nC > 2) return true ; return false ; }
bool AtDomain (hzDomain& dom, uint32_t& nLen, hzChain::Iter& ci) { // Category: Text Processing // // If the supplied iterator is at the start of a valid domain name, then the supplied domain name instance will be populated with this // address as the value and the supplied length will be set. // // Arguments: 1) dom Reference to an domain name, populated by this function // 2) nLen Reference to an integer set to the dom length // 3) ci Input chain iterator // // Returns: True If the supplied cstr sets the domain name // False Otherwise
_hzfunc("AtDomain") ;
dom.Clear() ; dom = ci ; if (!dom) return false ; nLen = dom.Length() ; return true ; }