Task: Parse an IP Address

C: #include <string.h>
#include <memory.h>


static unsigned int _parseDecimal ( const char** pchCursor )
{
    unsigned int nVal = 0;
    char chNow;
    while ( chNow = **pchCursor, chNow >= '0' && chNow <= '9' )
    {
        
        nVal *= 10;
        nVal += chNow - '0';

        ++*pchCursor;
    }
    return nVal;
}



static unsigned int _parseHex ( const char** pchCursor )
{
    unsigned int nVal = 0;
    char chNow;
    while ( chNow = **pchCursor & 0x5f, 
            (chNow >= ('0'&0x5f) && chNow <= ('9'&0x5f)) || 
            (chNow >= 'A' && chNow <= 'F') 
            )
    {
        unsigned char nybbleValue;
        chNow -= 0x10;  
        nybbleValue = ( chNow > 9 ? chNow - (0x31-0x0a) : chNow );
        
        nVal <<= 4;
        nVal += nybbleValue;

        ++*pchCursor;
    }
    return nVal;
}














int ParseIPv4OrIPv6 ( const char** ppszText, 
        unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
    unsigned char* abyAddrLocal;
    unsigned char abyDummyAddr[16];

    
    const char* pchColon = strchr ( *ppszText, ':' );
    const char* pchDot = strchr ( *ppszText, '.' );
    const char* pchOpenBracket = strchr ( *ppszText, '[' );
    const char* pchCloseBracket = NULL;


    
    
    
    int bIsIPv6local = NULL != pchOpenBracket || NULL == pchDot ||
            ( NULL != pchColon && ( NULL == pchDot || pchColon < pchDot ) );
    
    if ( bIsIPv6local )
    {
        
        pchCloseBracket = strchr ( *ppszText, ']' );
        if ( NULL != pchOpenBracket && ( NULL == pchCloseBracket ||
                pchCloseBracket < pchOpenBracket ) )
            return 0;
    }
    else    
    {
        
        if ( NULL == pchDot || ( NULL != pchColon && pchColon < pchDot ) )
            return 0;
    }

    
    if ( NULL != pbIsIPv6 )
        *pbIsIPv6 = bIsIPv6local;
    
    
    
    
    abyAddrLocal = abyAddr; 
    if ( NULL == abyAddrLocal ) 
        abyAddrLocal = abyDummyAddr;

    
    
    
    if ( ! bIsIPv6local )   
    {
        
        
        
        unsigned char* pbyAddrCursor = abyAddrLocal;
        unsigned int nVal;
        const char* pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )    
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;  
        ++(*ppszText);  

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;
        ++(*ppszText);  

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;
        ++(*ppszText);  

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           
        if ( nVal > 255 || pszTextBefore == *ppszText ) 
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;

        if ( ':' == **ppszText && NULL != pnPort )  
        {
            unsigned short usPortNetwork;   
            ++(*ppszText);  
            pszTextBefore = *ppszText;
            nVal =_parseDecimal ( ppszText );
            if ( nVal > 65535 || pszTextBefore == *ppszText )
                return 0;
            ((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
            ((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
            *pnPort = usPortNetwork;
            return 1;
        }
        else    
        {
            if ( NULL != pnPort )
                *pnPort = 0;    
            return 1;
        }
    }
    else    
    {
        unsigned char* pbyAddrCursor;
        unsigned char* pbyZerosLoc;
        int bIPv4Detected;
        int nIdx;
        
        
        
        
        
        if ( NULL != pchOpenBracket )   
            *ppszText = pchOpenBracket + 1;
        pbyAddrCursor = abyAddrLocal;
        pbyZerosLoc = NULL; 
        bIPv4Detected = 0;
        for ( nIdx = 0; nIdx < 8; ++nIdx )  
        {
            const char* pszTextBefore = *ppszText;
            unsigned nVal =_parseHex ( ppszText );      
            if ( pszTextBefore == *ppszText )   
            {
                if ( NULL != pbyZerosLoc )  
                {
                    
                    if ( pbyZerosLoc == pbyAddrCursor )
                    {
                        --nIdx;
                        break;
                    }
                    return 0;   
                }
                if ( ':' != **ppszText )    
                    return 0;
                if ( 0 == nIdx )    
                {
                    ++(*ppszText);
                    if ( ':' != **ppszText )
                        return 0;
                }

                pbyZerosLoc = pbyAddrCursor;
                ++(*ppszText);
            }
            else
            {
                if ( '.' == **ppszText )    
                {
                    
                    const char* pszTextlocal = pszTextBefore;   
                    unsigned char abyAddrlocal[16];
                    int bIsIPv6local;
                    int bParseResultlocal = ParseIPv4OrIPv6 ( &pszTextlocal, abyAddrlocal, NULL, &bIsIPv6local );
                    *ppszText = pszTextlocal;   
                    if ( ! bParseResultlocal || bIsIPv6local )  
                        return 0;
                    
                    *(pbyAddrCursor++) = abyAddrlocal[0];
                    *(pbyAddrCursor++) = abyAddrlocal[1];
                    *(pbyAddrCursor++) = abyAddrlocal[2];
                    *(pbyAddrCursor++) = abyAddrlocal[3];
                    ++nIdx; 
                    bIPv4Detected = 1;  
                    break;  
                }

                if ( nVal > 65535 ) 
                    return 0;
                *(pbyAddrCursor++) = nVal >> 8;     
                *(pbyAddrCursor++) = nVal & 0xff;
                if ( ':' == **ppszText )    
                {
                    ++(*ppszText);
                }
                else    
                {
                    break;
                }
            }
        }
        
        
        if ( NULL != pbyZerosLoc )
        {
            int nHead = (int)( pbyZerosLoc - abyAddrLocal );    
            int nTail = nIdx * 2 - (int)( pbyZerosLoc - abyAddrLocal ); 
            int nZeros = 16 - nTail - nHead;        
            memmove ( &abyAddrLocal[16-nTail], pbyZerosLoc, nTail );    
            memset ( pbyZerosLoc, 0, nZeros );      
        }
        
        
        if ( bIPv4Detected )
        {
            static const unsigned char abyPfx[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
            if ( 0 != memcmp ( abyAddrLocal, abyPfx, sizeof(abyPfx) ) )
                return 0;
        }

        
        if ( NULL != pchOpenBracket )
        {
            if ( ']' != **ppszText )
                return 0;
            ++(*ppszText);
        }

        if ( ':' == **ppszText && NULL != pnPort )  
        {
            const char* pszTextBefore;
            unsigned int nVal;
            unsigned short usPortNetwork;   
            ++(*ppszText);  
            pszTextBefore = *ppszText;
            pszTextBefore = *ppszText;
            nVal =_parseDecimal ( ppszText );
            if ( nVal > 65535 || pszTextBefore == *ppszText )
                return 0;
            ((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
            ((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
            *pnPort = usPortNetwork;
            return 1;
        }
        else    
        {
            if ( NULL != pnPort )
                *pnPort = 0;    
            return 1;
        }
    }

}



int ParseIPv4OrIPv6_2 ( const char* pszText, 
        unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
    const char* pszTextLocal = pszText;
    return ParseIPv4OrIPv6 ( &pszTextLocal, abyAddr, pnPort, pbIsIPv6);
}





Java: import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ParseIPAddress {

    public static void main(String[] args) {
        String [] tests = new String[] {"192.168.0.1", "127.0.0.1", "256.0.0.1", "127.0.0.1:80", "::1", "[::1]:80", "[32e::12f]:80", "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80", "2001:db8:85a3:0:0:8a2e:370:7334"};
        System.out.printf("%-40s %-32s   %s%n", "Test Case", "Hex Address", "Port");
        for ( String ip : tests ) {
            try {
                String [] parsed = parseIP(ip);
                System.out.printf("%-40s %-32s   %s%n", ip, parsed[0], parsed[1]);
            }
            catch (IllegalArgumentException e) {
                System.out.printf("%-40s Invalid address:  %s%n", ip, e.getMessage());
            }
        }
    }
    
    private static final Pattern IPV4_PAT = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(?::(\\d+)){0,1}$");
    private static final Pattern IPV6_DOUBL_COL_PAT = Pattern.compile("^\\[{0,1}([0-9a-f:]*)::([0-9a-f:]*)(?:\\]:(\\d+)){0,1}$");
    private static String ipv6Pattern;
    static {
        ipv6Pattern = "^\\[{0,1}";
        for ( int i = 1 ; i <= 7 ; i ++ ) {
            ipv6Pattern += "([0-9a-f]+):";
        }
        ipv6Pattern += "([0-9a-f]+)(?:\\]:(\\d+)){0,1}$";
    }
    private static final Pattern IPV6_PAT = Pattern.compile(ipv6Pattern);
    
    private static String[] parseIP(String ip) {
        String hex = "";
        String port = "";
        
        
        Matcher ipv4Matcher = IPV4_PAT.matcher(ip);
        if ( ipv4Matcher.matches() ) {
            for ( int i = 1 ; i <= 4 ; i++ ) {
                hex += toHex4(ipv4Matcher.group(i));
            }
            if ( ipv4Matcher.group(5) != null ) {
                port = ipv4Matcher.group(5);
            }
            return new String[] {hex, port};
        }
        
        
        Matcher ipv6DoubleColonMatcher = IPV6_DOUBL_COL_PAT.matcher(ip);
        if ( ipv6DoubleColonMatcher.matches() ) {
            String p1 = ipv6DoubleColonMatcher.group(1);
            if ( p1.isEmpty() ) {
                p1 = "0";
            }
            String p2 = ipv6DoubleColonMatcher.group(2);
            if ( p2.isEmpty() ) {
                p2 = "0";
            }
            ip =  p1 + getZero(8 - numCount(p1) - numCount(p2)) + p2;
            if ( ipv6DoubleColonMatcher.group(3) != null ) {
                ip = "[" + ip + "]:" + ipv6DoubleColonMatcher.group(3);
            }
        }
        
        
        Matcher ipv6Matcher = IPV6_PAT.matcher(ip);
        if ( ipv6Matcher.matches() ) {
            for ( int i = 1 ; i <= 8 ; i++ ) {
                hex += String.format("%4s", toHex6(ipv6Matcher.group(i))).replace(" ", "0");
            }
            if ( ipv6Matcher.group(9) != null ) {
                port = ipv6Matcher.group(9);
            }
            return new String[] {hex, port};
        }
        
        throw new IllegalArgumentException("ERROR 103: Unknown address: " + ip);
    }
    
    private static int numCount(String s) {
        return s.split(":").length;
    }
    
    private static String getZero(int count) {
        StringBuilder sb = new StringBuilder();
        sb.append(":");
        while ( count > 0 ) {
            sb.append("0:");
            count--;
        }
        return sb.toString();
    }

    private static String toHex4(String s) {
        int val = Integer.parseInt(s);
        if ( val < 0 || val > 255 ) {
            throw new IllegalArgumentException("ERROR 101:  Invalid value : " + s);
        }
        return String.format("%2s", Integer.toHexString(val)).replace(" ", "0");
    }

    private static String toHex6(String s) {
        int val = Integer.parseInt(s, 16);
        if ( val < 0 || val > 65536 ) {
            throw new IllegalArgumentException("ERROR 102:  Invalid hex value : " + s);
        }
        return s;
    }

}