git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
406 lines
8.8 KiB
C++
406 lines
8.8 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: URL parsing.
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1998-2000,2002-2003,2005-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program 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 this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: furl.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
#define FLAIM_PROTOCOL_NAME "x-flaim"
|
|
#define FLAIM_PROTOCOL_NAME_LEN 7
|
|
#define TCP_SUB_PROTOCOL_NAME ":tcp://"
|
|
#define TCP_SUB_PROTOCOL_NAME_LEN 7
|
|
#define STREAM_SUB_PROTOCOL_NAME ":stream://"
|
|
#define STREAM_SUB_PROTOCOL_NAME_LEN 10
|
|
#define NO_SUB_PROTOCOL_NAME "://"
|
|
#define NO_SUB_PROTOCOL_NAME_LEN 3
|
|
#define FLAIM_DEFAULT_PORT 1677
|
|
|
|
/****************************************************************************
|
|
Public: FUrl constructor, destructor
|
|
****************************************************************************/
|
|
FUrl::FUrl()
|
|
{
|
|
m_iPort = -1;
|
|
m_iSubProtocol = NO_SUB_PROTOCOL;
|
|
m_bRelative = FALSE;
|
|
m_pucAlloc = NULL;
|
|
m_pszHostName = NULL;
|
|
m_pszFileName = NULL;
|
|
m_uiAddrType = FLM_CS_NO_ADDR;
|
|
m_pszIPName = NULL;
|
|
m_ui32IPAddr = 0;
|
|
f_memset( m_pszAddr, 0, FLM_CS_MAX_ADDR_LEN);
|
|
}
|
|
|
|
FUrl::~FUrl()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
/****************************************************************************
|
|
Public: FUrl::Reset
|
|
Desc: Reset members of the URL - freeing memory, etc.
|
|
****************************************************************************/
|
|
void FUrl::Reset()
|
|
{
|
|
m_iPort = -1;
|
|
m_iSubProtocol = NO_SUB_PROTOCOL;
|
|
m_bRelative = FALSE;
|
|
f_free( &m_pucAlloc);
|
|
m_pszHostName = NULL;
|
|
m_pszFileName = NULL;
|
|
m_bLocal = FALSE;
|
|
f_free( (void **)&m_pszIPName);
|
|
m_ui32IPAddr = 0;
|
|
m_uiAddrType = FLM_CS_NO_ADDR;
|
|
f_memset( m_pszAddr, 0, FLM_CS_MAX_ADDR_LEN);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Public: FUrl::SetUrl
|
|
Desc: Parse the string passed in and setup the members of the URL.
|
|
****************************************************************************/
|
|
RCODE FUrl::SetUrl(
|
|
const char * pszUrlStr)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiAllocLen;
|
|
char * pucTmp;
|
|
const char * pucCurrent;
|
|
const char * pszFileName = NULL;
|
|
const char * pszHostName = NULL;
|
|
FLMINT iHostNameLen = 0;
|
|
FLMINT iPort = -1;
|
|
FLMINT iSubProtocol = NO_SUB_PROTOCOL;
|
|
FLMBOOL bRelative = FALSE;
|
|
|
|
/* Clear out the current URL. */
|
|
|
|
Reset();
|
|
|
|
/*
|
|
See if the string begins with our protocol name. If not, assume that
|
|
it is a file name.
|
|
*/
|
|
|
|
if ((f_strncmp( pszUrlStr, FLAIM_PROTOCOL_NAME,
|
|
FLAIM_PROTOCOL_NAME_LEN) != 0) ||
|
|
((f_strncmp( pszUrlStr + FLAIM_PROTOCOL_NAME_LEN,
|
|
TCP_SUB_PROTOCOL_NAME,
|
|
TCP_SUB_PROTOCOL_NAME_LEN) != 0) &&
|
|
(f_strncmp( pszUrlStr + FLAIM_PROTOCOL_NAME_LEN,
|
|
STREAM_SUB_PROTOCOL_NAME,
|
|
STREAM_SUB_PROTOCOL_NAME_LEN) != 0) &&
|
|
(f_strncmp( pszUrlStr + FLAIM_PROTOCOL_NAME_LEN,
|
|
NO_SUB_PROTOCOL_NAME,
|
|
NO_SUB_PROTOCOL_NAME_LEN) != 0)))
|
|
{
|
|
bRelative = FALSE;
|
|
pszFileName = pszUrlStr;
|
|
m_bLocal = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pucCurrent = pszUrlStr + FLAIM_PROTOCOL_NAME_LEN;
|
|
if( f_strncmp( pucCurrent, TCP_SUB_PROTOCOL_NAME,
|
|
TCP_SUB_PROTOCOL_NAME_LEN) == 0)
|
|
{
|
|
iSubProtocol = TCP_SUB_PROTOCOL;
|
|
pucCurrent += TCP_SUB_PROTOCOL_NAME_LEN;
|
|
}
|
|
else if( f_strncmp( pucCurrent, STREAM_SUB_PROTOCOL_NAME,
|
|
STREAM_SUB_PROTOCOL_NAME_LEN) == 0)
|
|
{
|
|
iSubProtocol = STREAM_SUB_PROTOCOL;
|
|
pucCurrent += STREAM_SUB_PROTOCOL_NAME_LEN;
|
|
m_uiAddrType = FLM_CS_STREAM_ADDR;
|
|
}
|
|
else
|
|
{
|
|
iSubProtocol = NO_SUB_PROTOCOL;
|
|
pucCurrent += NO_SUB_PROTOCOL_NAME_LEN;
|
|
}
|
|
|
|
/*
|
|
If the next character is NOT a slash, we have a host name
|
|
(or stream name) and optionally a port number
|
|
*/
|
|
|
|
if( *pucCurrent != '/')
|
|
{
|
|
FLMINT iAddrPos;
|
|
FLMINT iAddrSlot;
|
|
FLMUINT uiTmpVal;
|
|
const char * pucNamePos;
|
|
|
|
iPort = FLAIM_DEFAULT_PORT;
|
|
pszHostName = pucCurrent;
|
|
while( (*pucCurrent) && (*pucCurrent != '/') && (*pucCurrent != ':'))
|
|
{
|
|
iHostNameLen++;
|
|
pucCurrent++;
|
|
}
|
|
|
|
/*
|
|
It is invalid to have an empty host name
|
|
*/
|
|
|
|
if( !iHostNameLen)
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
If this is a URL that does not include a file path,
|
|
we are done
|
|
*/
|
|
|
|
if( !(*pucCurrent))
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
/* See if we got a colon. If so, extract the port number. */
|
|
|
|
if( *pucCurrent == ':')
|
|
{
|
|
iPort = 0;
|
|
|
|
/* Increment past colon. */
|
|
|
|
pucCurrent++;
|
|
|
|
/* Make sure we have at least one digit. */
|
|
|
|
if( (*pucCurrent < '0') || (*pucCurrent > '9'))
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
|
|
/* Go until string termination or another backslash. */
|
|
|
|
while( (*pucCurrent) && (*pucCurrent != '/'))
|
|
{
|
|
if ((*pucCurrent < '0') || (*pucCurrent > '9'))
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
|
|
iPort *= 10;
|
|
iPort += (FLMINT)(*pucCurrent - '0');
|
|
pucCurrent++;
|
|
}
|
|
}
|
|
|
|
if( iSubProtocol != STREAM_SUB_PROTOCOL)
|
|
{
|
|
m_uiAddrType = FLM_CS_IP_ADDR;
|
|
}
|
|
|
|
/*
|
|
See if the host name is an IP address. If it is an
|
|
address, extract it.
|
|
*/
|
|
|
|
/*
|
|
Dotted IP Address. The format of an IP address is
|
|
000.000.000.000 where each dot-separated value can vary
|
|
in length from 1 to 3 characters.
|
|
*/
|
|
|
|
iAddrSlot = 0;
|
|
uiTmpVal = 0;
|
|
pucNamePos = pszHostName;
|
|
for( iAddrPos = 0; iAddrPos < iHostNameLen; iAddrPos++)
|
|
{
|
|
switch( *pucNamePos)
|
|
{
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
{
|
|
uiTmpVal *= 10;
|
|
uiTmpVal += (FLMUINT)(*pucNamePos - '0');
|
|
break;
|
|
}
|
|
case '.':
|
|
{
|
|
if( iAddrSlot >= 4)
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
|
|
((FLMBYTE *)(&m_ui32IPAddr))[ iAddrSlot++] = (FLMBYTE)uiTmpVal;
|
|
uiTmpVal = 0;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
// The buffer does not contain an address. Cause the
|
|
// loop to terminate.
|
|
|
|
iAddrPos = iHostNameLen;
|
|
iAddrSlot = 3;
|
|
continue;
|
|
}
|
|
}
|
|
pucNamePos++;
|
|
}
|
|
|
|
if( iAddrSlot != 3)
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
|
|
/* By now we better be on another slash */
|
|
|
|
if( *pucCurrent != '/')
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
/* Increment past slash. */
|
|
|
|
pucCurrent++;
|
|
|
|
/* See if there are any keywords. */
|
|
|
|
if( f_strnicmp( pucCurrent, "RELATIVE.", 9) == 0)
|
|
{
|
|
pucCurrent += 9;
|
|
|
|
/*
|
|
Better have specified a host name - RELATIVE is only valid when
|
|
talking to a server.
|
|
*/
|
|
|
|
if (!iHostNameLen)
|
|
{
|
|
rc = RC_SET( FERR_IO_INVALID_PATH);
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
Treat the rest of the string after the "RELATIVE."
|
|
as a relative file name.
|
|
*/
|
|
|
|
bRelative = TRUE;
|
|
pszFileName = pucCurrent;
|
|
}
|
|
else if( f_strnicmp( pucCurrent, "ABSOLUTE.", 9) == 0)
|
|
{
|
|
pucCurrent += 9;
|
|
|
|
/*
|
|
Treat the rest of the string after the "ABSOLUTE."
|
|
as an absolute file name.
|
|
*/
|
|
|
|
bRelative = FALSE;
|
|
pszFileName = pucCurrent;
|
|
}
|
|
else
|
|
{
|
|
|
|
/*
|
|
No keywords, so default case is to treat the rest of the
|
|
string as a relative file name.
|
|
*/
|
|
|
|
bRelative = TRUE;
|
|
pszFileName = pucCurrent;
|
|
}
|
|
}
|
|
|
|
/* Make one allocation for everything that is to be copied. */
|
|
|
|
Done:
|
|
|
|
uiAllocLen = 0;
|
|
if( pszFileName)
|
|
{
|
|
uiAllocLen += (FLMUINT)(f_strlen( pszFileName) + 1);
|
|
}
|
|
|
|
if (iHostNameLen)
|
|
{
|
|
uiAllocLen += (FLMUINT)(iHostNameLen + 1);
|
|
}
|
|
|
|
if (RC_BAD( rc = f_alloc( uiAllocLen, &m_pucAlloc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_iSubProtocol = iSubProtocol;
|
|
m_bRelative = bRelative;
|
|
pucTmp = m_pucAlloc;
|
|
m_iPort = iPort;
|
|
|
|
if (iHostNameLen)
|
|
{
|
|
f_memcpy( pucTmp, pszHostName, iHostNameLen);
|
|
pucTmp[ iHostNameLen] = 0;
|
|
m_pszHostName = pucTmp;
|
|
pucTmp += (iHostNameLen + 1);
|
|
|
|
if( iHostNameLen + 1 <= FLM_CS_MAX_ADDR_LEN)
|
|
{
|
|
f_strcpy( m_pszAddr, m_pszHostName);
|
|
}
|
|
else
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( pszFileName)
|
|
{
|
|
f_strcpy( pucTmp, pszFileName);
|
|
m_pszFileName = pucTmp;
|
|
}
|
|
else
|
|
{
|
|
m_pszFileName = NULL;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|