From 514721c24c7212c084ad2530e8239ff121097818 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 6 Apr 2009 19:13:51 +0000 Subject: Ok, I rearranged some things, we have a tools dir now, those build by default. Also I added a bunch of classes that I've been tinkering with that are almost ready for use, so I figured I may as well throw them in here. --- src/fastcgi.cpp | 277 +++++++++++++++++++++++++++++++++++++++++++++++++ src/fastcgi.h | 120 +++++++++++++++++++++ src/tests/fastcgi.cpp | 81 +++++++++++++++ src/tests/nidstool.cpp | 241 ------------------------------------------ src/tests/url.cpp | 45 ++++---- src/tools/nidstool.cpp | 241 ++++++++++++++++++++++++++++++++++++++++++ src/unit/array.unit | 4 +- src/urn.cpp | 0 src/urn.h | 0 9 files changed, 746 insertions(+), 263 deletions(-) create mode 100644 src/fastcgi.cpp create mode 100644 src/fastcgi.h create mode 100644 src/tests/fastcgi.cpp delete mode 100644 src/tests/nidstool.cpp create mode 100644 src/tools/nidstool.cpp create mode 100644 src/urn.cpp create mode 100644 src/urn.h (limited to 'src') diff --git a/src/fastcgi.cpp b/src/fastcgi.cpp new file mode 100644 index 0000000..aba3b71 --- /dev/null +++ b/src/fastcgi.cpp @@ -0,0 +1,277 @@ +#include "bu/fastcgi.h" + +#include +#include + +#include "bu/membuf.h" + +#include "bu/sio.h" +using Bu::sio; +using Bu::Fmt; + +Bu::FastCgi::FastCgi() : + pSrv( NULL ), + bRunning( true ) +{ + pSrv = new Bu::ServerSocket( STDIN_FILENO, false ); +} + +Bu::FastCgi::FastCgi( int iPort ) : + pSrv( NULL ), + bRunning( true ) +{ + pSrv = new Bu::ServerSocket( iPort ); +} + +Bu::FastCgi::~FastCgi() +{ +} + +bool Bu::FastCgi::isEmbedded() +{ + struct sockaddr name; + socklen_t namelen = sizeof(name); + if( getpeername( STDIN_FILENO, &name, &namelen ) != 0 && + errno == ENOTCONN ) + { + sio << "errno = " << errno << " (" << strerror( errno ) << ")" << + sio.nl; + sio << "Socket found" << sio.nl; + return true; + } + else + { + sio << "errno = " << errno << " (" << strerror( errno ) << ")" << + sio.nl; + sio << "No socket detected, running in standalone mode" << sio.nl; + return false; + } +} + +void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::Record &r ) +{ + s.read( &r, sizeof(Record) ); + r.uRequestId = ntohs( r.uRequestId ); + r.uContentLength = ntohs( r.uContentLength ); +} + +void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) +{ + r.uRequestId = htons( r.uRequestId ); + r.uContentLength = htons( r.uContentLength ); + s.write( &r, sizeof(Record) ); +} + +void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::BeginRequestBody &b ) +{ + s.read( &b, sizeof(BeginRequestBody) ); + b.uRole = ntohs( b.uRole ); +} + +void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::EndRequestBody b ) +{ + b.uStatus = htonl( b.uStatus ); + s.write( &b, sizeof(b) ); +} + +uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) +{ + uint8_t uByte[4]; + s.read( uByte, 1 ); + uRead++; + if( uByte[0] >> 7 == 0 ) + return uByte[0]; + + s.read( uByte+1, 3 ); + uRead += 3; + return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); +} + +void Bu::FastCgi::readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uRead ) +{ + uint32_t uName = readLen( s, uRead ); + uint32_t uValue = readLen( s, uRead ); + uRead += uName + uValue; + unsigned char *sName = new unsigned char[uName]; + s.read( sName, uName ); + Bu::FString fsName( (char *)sName, uName ); + delete[] sName; + + if( uValue > 0 ) + { + unsigned char *sValue = new unsigned char[uValue]; + s.read( sValue, uValue ); + Bu::FString fsValue( (char *)sValue, uValue ); + hParams.insert( fsName, fsValue ); + delete[] sValue; + } + else + { + hParams.insert( fsName, "" ); + } +} + +void Bu::FastCgi::run() +{ + bRunning = true; + while( bRunning ) + { + int iSock = pSrv->accept( 5 ); + if( iSock < 0 ) + continue; + + Bu::Socket s( iSock ); + s.setBlocking( true ); + try + { + for(;;) + { + Record r; + read( s, r ); + while( aChannel.getSize() < r.uRequestId ) + aChannel.append( NULL ); + Channel *pChan = NULL; + if( r.uRequestId > 0 ) + pChan = aChannel[r.uRequestId-1]; + + sio << "Record (id=" << r.uRequestId << ", len=" << + r.uContentLength << ", pad=" << + (int)r.uPaddingLength << "): "; + fflush( stdout ); + + switch( (RequestType)r.uType ) + { + case typeBeginRequest: + sio << "Begin Request."; + { + BeginRequestBody b; + read( s, b ); + if( pChan != NULL ) + { + sio << "Error!!!" << sio.nl; + return; + } + pChan = aChannel[r.uRequestId-1] = new Channel(); + } + break; + + case typeParams: + sio << "Params."; + if( r.uContentLength == 0 ) + { + pChan->uFlags |= chflgParamsDone; + } + else + { + uint16_t uUsed = 0; + while( uUsed < r.uContentLength ) + { + readPair( s, pChan->hParams, uUsed ); + } + } + break; + + case typeStdIn: + sio << "StdIn."; + if( r.uContentLength == 0 ) + { + pChan->uFlags |= chflgStdInDone; + } + else + { + char *buf = new char[r.uContentLength]; + sio << " (read " << s.read( buf, r.uContentLength ) + << ")"; + pChan->sStdIn.append( buf, r.uContentLength ); + delete[] buf; + } + break; + + case typeData: + sio << "Data."; + if( r.uContentLength == 0 ) + { + pChan->uFlags |= chflgDataDone; + } + else + { + char *buf = new char[r.uContentLength]; + s.read( buf, r.uContentLength ); + pChan->sData.append( buf, r.uContentLength ); + delete[] buf; + } + break; + + case typeStdOut: + case typeStdErr: + case typeEndRequest: + case typeAbortRequest: + case typeGetValuesResult: + sio << "Scary."; + // ??? we shouldn't get these. + break; + + } + + sio << sio.nl; + + if( pChan ) + { + if( pChan->uFlags == chflgAllDone ) + { + Bu::MemBuf mStdOut, mStdErr; + int iRet = request( + pChan->hParams, pChan->sStdIn, + mStdOut, mStdErr + ); + + Bu::FString &sStdOut = mStdOut.getString(); + Bu::FString &sStdErr = mStdErr.getString(); + + Record rOut; + rOut.uVersion = 1; + rOut.uRequestId = r.uRequestId; + rOut.uPaddingLength = 0; + if( sStdOut.getSize() > 0 ) + { + rOut.uType = typeStdOut; + rOut.uContentLength = sStdOut.getSize(); + write( s, rOut ); + s.write( sStdOut ); + } + rOut.uType = typeStdOut; + rOut.uContentLength = 0; + write( s, rOut ); + if( sStdErr.getSize() > 0 ) + { + rOut.uType = typeStdErr; + rOut.uContentLength = sStdErr.getSize(); + write( s, rOut ); + s.write( sStdOut ); + } + rOut.uType = typeStdErr; + rOut.uContentLength = 0; + write( s, rOut ); + + rOut.uType = typeEndRequest; + rOut.uContentLength = 8; + write( s, rOut ); + + EndRequestBody b; + memset( &b, 0, sizeof(b) ); + b.uStatus = iRet; + write( s, b ); + + delete pChan; + aChannel[r.uRequestId-1] = NULL; + } + } + } + } + catch( Bu::SocketException &e ) + { + //sio << "Bu::SocketException: " << e.what() << sio.nl; + } + } +} + diff --git a/src/fastcgi.h b/src/fastcgi.h new file mode 100644 index 0000000..83e9b83 --- /dev/null +++ b/src/fastcgi.h @@ -0,0 +1,120 @@ +#ifndef BU_FAST_CGI_H +#define BU_FAST_CGI_H + +#include "bu/fstring.h" +#include "bu/hash.h" +#include "bu/array.h" +#include "bu/socket.h" +#include "bu/serversocket.h" + +namespace Bu +{ + class Stream; + + class FastCgi + { + public: + FastCgi( int iPort ); + FastCgi(); + virtual ~FastCgi(); + + static bool isEmbedded(); + + typedef Bu::Hash StrHash; + enum RequestType + { + typeBeginRequest = 1, + typeAbortRequest = 2, + typeEndRequest = 3, + typeParams = 4, + typeStdIn = 5, + typeStdOut = 6, + typeStdErr = 7, + typeData = 8, + typeGetValues = 9, + typeGetValuesResult = 10 + }; + + enum Role + { + roleResponder = 1, + roleAuthorizer = 2, + roleFilter = 3 + }; + + enum Flags + { + flagsKeepConn = 1 + }; + + enum Status + { + statusRequestComplete = 0, + statusCantMpxConn = 1, + statusOverloaded = 2, + statusUnknownRole = 3 + }; + + typedef struct { + uint8_t uVersion; + uint8_t uType; + uint16_t uRequestId; + uint16_t uContentLength; + uint8_t uPaddingLength; + uint8_t uReserved; + } Record; + + typedef struct { + uint16_t uRole; + uint8_t uFlags; + uint8_t reserved[5]; + } BeginRequestBody; + + typedef struct { + uint32_t uStatus; + uint8_t uProtocolStatus; + uint8_t reserved[3]; + } EndRequestBody; + + typedef struct Channel { + Channel() : uFlags( 0 ) { } + StrHash hParams; + Bu::FString sStdIn; + Bu::FString sData; + uint8_t uFlags; + } Channel; + + enum ChannelFlags + { + chflgParamsDone = 0x01, + chflgStdInDone = 0x02, + chflgDataDone = 0x04, + + chflgAllDone = 0x03 + }; + + virtual void run(); + + virtual void init() { }; + virtual int request( const StrHash &hParams, + const Bu::FString &sStdIn, Bu::Stream &sStdOut, + Bu::Stream &sStdErr )=0; + virtual void deinit() { }; + + private: + void read( Bu::Socket &s, Record &r ); + void read( Bu::Socket &s, BeginRequestBody &b ); + uint32_t readLen( Bu::Socket &s, uint16_t &uUsed ); + void readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uUsed ); + + void write( Bu::Socket &s, Record r ); + void write( Bu::Socket &s, EndRequestBody b ); + + private: + Bu::ServerSocket *pSrv; + bool bRunning; + Bu::Array aChannel; + }; +}; + +#endif diff --git a/src/tests/fastcgi.cpp b/src/tests/fastcgi.cpp new file mode 100644 index 0000000..53dd68a --- /dev/null +++ b/src/tests/fastcgi.cpp @@ -0,0 +1,81 @@ +#include "bu/fastcgi.h" + +class Cgi : public Bu::FastCgi +{ +public: + Cgi() : + Bu::FastCgi::FastCgi() + { + } + + Cgi( int iPort ) : + Bu::FastCgi::FastCgi( iPort ) + { + } + + virtual ~Cgi() + { + } + + virtual int request( const StrHash &hParams, + const Bu::FString &sStdIn, Bu::Stream &sStdOut, + Bu::Stream &sStdErr ) + { + Bu::FString sOut("Content-Type: text/html\r\n\r\n"); + sOut += "

Environment:

    "; + for( StrHash::const_iterator i = hParams.begin(); i; i++ ) + { + sOut += "
  • " + i.getKey() + " = " + + i.getValue() + "
  • "; + } + sOut += "
"; + char buf[2048]; + sOut += "

Cwd:

  • "; + sOut += getcwd( buf, 2048 ); + sOut += "
"; + sOut += "

Stdin:

"; + sOut.formatAppend("%d bytes
", sStdIn.getSize() );
+		Bu::FString sL, sR;
+		for( Bu::FString::const_iterator i = sStdIn.begin();
+			i; i++ )
+		{
+			sL.formatAppend("%02X ",
+				(unsigned int)((unsigned char)*i) );
+			if( *i < 27 )
+				sR += ". ";
+			else
+				sR.formatAppend("&#%d; ",
+					(unsigned int)((unsigned char)*i) );
+			if( sL.getSize()/3 == 8 )
+			{
+				sOut += sL + " | " + sR + "\n";
+				sL = sR = "";
+			}
+		}
+		if( sL != "" )
+		{
+			while( sL.getSize()/3 < 8 )
+				sL += "   ";
+			sOut += sL + " | " + sR + "\n";
+		}
+		sOut += "

";
+		sOut += sStdIn;
+		sOut += "
"; + sOut += "


"; + sOut += ""; + + sStdOut.write( sOut ); + + return 0; + } +}; + +int main() +{ + Cgi c( 8789 ); + + c.run(); + + return 0; +} + diff --git a/src/tests/nidstool.cpp b/src/tests/nidstool.cpp deleted file mode 100644 index d1465ce..0000000 --- a/src/tests/nidstool.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "bu/file.h" -#include "bu/nids.h" -#include "bu/nidsstream.h" -#include "bu/paramproc.h" - -#include - -typedef struct Block -{ - uint32_t uFirstBlock; - uint32_t uNextBlock; - uint32_t uBytesUsed; -} Block; - -class Param : public Bu::ParamProc -{ -public: - Param( int argc, char *argv[] ) - { - addHelpBanner("nidstool - Do stuff with nids files.\n\n"); - addParam("info", 'i', mkproc(Param::procInfo), - "Print some info about the file."); - addParam("dump", 'd', mkproc(Param::procDump), - "Dump a stream to a file."); - addParam("analyze", 'a', mkproc(Param::procAnalyze), - "Analyze a nids file."); - addParam("copy", 'c', mkproc(Param::procCopy), - "Copy a nids file, changing settings."); - addParam("help", 'h', mkproc(Bu::ParamProc::help), "This help."); - process( argc, argv ); - } - - virtual ~Param() - { - } - - void printInfo( Bu::Nids &n ) - { - printf("File info:\n"); - printf(" Header overhead: %db\n", n.getBlockStart() ); - printf(" Block size: %db\n", n.getBlockSize() ); - printf(" Block count: %d\n", n.getNumBlocks() ); - printf(" Blocks used: %d (%d%%)\n", n.getNumUsedBlocks(), - n.getNumUsedBlocks()*100/n.getNumBlocks() ); - printf(" Block overhead: %db\n", n.getBlockOverhead() ); - printf(" Block storage: %db (%d%%)\n", - n.getBlockSize()-n.getBlockOverhead(), - (n.getBlockSize()-n.getBlockOverhead())*100/n.getBlockSize() ); - } - - int procInfo( int argc, char *argv[] ) - { - if( argc < 1 ) - { - printf("You must provide a file name.\n"); - exit( 1 ); - } - - Bu::File fIn( argv[0], Bu::File::Read ); - Bu::Nids n( fIn ); - n.initialize(); - - printInfo( n ); - - if( argc >= 2 ) - { - uint32_t uStream = strtoul( argv[1], NULL, 0 ); - uint32_t uBlock = uStream; - - Block b; - - for(;;) - { - fIn.setPos( n.getBlockStart()+n.getBlockSize()*uBlock ); - fIn.read( &b, sizeof(Block) ); - printf("Stream %u: block %u, next %u, %ub used.\n", - uStream, uBlock, b.uNextBlock, b.uBytesUsed - ); - if( b.uNextBlock == 0xFFFFFFFFUL ) - break; - uBlock = b.uNextBlock; - } - printf("Stream End.\n"); - - return 2; - } - - return 1; - } - - int procDump( int argc, char *argv[] ) - { - if( argc < 3 ) - { - printf("You must provide a nids file, a stream id, and an output " - "file.\n"); - exit( 1 ); - } - - Bu::File fIn( argv[0], Bu::File::Read ); - Bu::Nids n( fIn ); - n.initialize(); - - int iStream = strtol( argv[1], NULL, 0 ); - Bu::NidsStream sIn = n.openStream( iStream ); - - Bu::File fOut( argv[2], Bu::File::Write|Bu::File::Create ); - int iTotal = 0; - char buf[100]; - for(;;) - { - int iRead = sIn.read( buf, 100 ); - iTotal += fOut.write( buf, iRead ); - if( iRead < 100 ) - break; - } - - printf("Wrote %db from stream %d in %s to %s.\n", - iTotal, iStream, argv[0], argv[2] ); - return 3; - } - - int procAnalyze( int argc, char *argv[] ) - { - if( argc < 1 ) - { - printf("You must provide a file name.\n"); - exit( 1 ); - } - - Bu::File fIn( argv[0], Bu::File::Read ); - Bu::Nids n( fIn ); - n.initialize(); - - printInfo( n ); - - int iStreamCnt = 0; - int iStreamTotal = 0; - int iOneBlock = 0; - uint32_t iLargest = 0; - uint32_t iSmallest = 0; - int iWaste = 0; - int iUsable = n.getBlockSize()-n.getBlockOverhead(); - Block b; - for( int j = 0; j < n.getNumBlocks(); j++ ) - { - fIn.setPos( n.getBlockStart()+n.getBlockSize()*j ); - fIn.read( &b, sizeof(Block) ); - if( b.uFirstBlock != (uint32_t)j ) - continue; - - iStreamCnt++; - iStreamTotal += b.uBytesUsed; - - if( b.uNextBlock == 0xFFFFFFFFUL ) - { - iOneBlock++; - iWaste += iUsable - b.uBytesUsed; - } - else - { - iWaste += iUsable - (b.uBytesUsed%iUsable); - } - - if( j == 0 ) - { - iSmallest = iLargest = b.uBytesUsed; - } - else - { - if( iLargest < b.uBytesUsed ) - iLargest = b.uBytesUsed; - if( iSmallest > b.uBytesUsed ) - iSmallest = b.uBytesUsed; - } - } - printf("Steam analysis:\n"); - printf(" Stream count: %d\n", iStreamCnt ); - printf(" Stream size: %db/%db/%db (min/avr/max)\n", - iSmallest, iStreamTotal/iStreamCnt, iLargest ); - printf(" One-block streams: %d (%d%%)\n", - iOneBlock, iOneBlock*100/iStreamCnt ); - printf(" Total wasted space: %db (%d%%)\n", - iWaste, iWaste*100/iStreamTotal ); - printf(" Avr blocks-per-stream: %f%%\n", - (float)n.getNumBlocks()/(float)iStreamCnt ); - - return 1; - } - - int procCopy( int argc, char *argv[] ) - { - if( argc < 3 ) - { - printf("You must provide source stream, blocksize, destination.\n"); - exit( 1 ); - } - - Bu::File fIn( argv[0], Bu::File::Read ); - Bu::Nids nIn( fIn ); - nIn.initialize(); - - Bu::File fOut( argv[2], Bu::File::Read|Bu::File::Write|Bu::File::Create| - Bu::File::Truncate ); - Bu::Nids nOut( fOut ); - nOut.initialize( strtol( argv[1], 0, NULL ) ); - - Block b; - for( int j = 0; j < nIn.getNumBlocks(); j++ ) - { - fIn.setPos( nIn.getBlockStart()+nIn.getBlockSize()*j ); - fIn.read( &b, sizeof(Block) ); - if( b.uFirstBlock != (uint32_t)j ) - continue; - - Bu::NidsStream sIn = nIn.openStream( j ); - int iNew = nOut.createStream(); - Bu::NidsStream sOut = nOut.openStream( iNew ); - - char buf[1024]; - for(;;) - { - int iRead = sIn.read( buf, 1024 ); - sOut.write( buf, iRead ); - if( iRead < 1024 ) - break; - } - } - - return 3; - } -}; - - -int main( int argc, char *argv[] ) -{ - Param p( argc, argv ); - - return 0; -} - diff --git a/src/tests/url.cpp b/src/tests/url.cpp index c9af676..4dc8c46 100644 --- a/src/tests/url.cpp +++ b/src/tests/url.cpp @@ -4,28 +4,31 @@ int main( int argc, char *argv[] ) { - printf("encodede: %s\n", Bu::Url::encode( argv[1] ).getStr() ); - printf("decodede: %s\n", Bu::Url::decode( argv[1] ).getStr() ); - Bu::Url u( argv[1] ); - - printf("Protocol: %s\n", u.getProtocol().getStr() ); - printf("User: %s\n", u.getUser().getStr() ); - printf("Pass: %s\n", u.getPass().getStr() ); - printf("Host: %s\n", u.getHost().getStr() ); - printf("Path: %s\n", u.getPath().getStr() ); - try - { - printf("Port: %d\n", u.getPort() ); - } catch( Bu::ExceptionBase &e ) + for( argc--, argv++; argc >= 0; argc--, argv++ ) { - printf("Port: not set.\n"); - } - printf("Parameters:\n"); - for( Bu::Url::ParamList::const_iterator i = u.getParamBegin(); i; i++ ) - { - printf(" \"%s\" = \"%s\"\n", - (*i).sName.getStr(), (*i).sValue.getStr() - ); + printf("encodede: %s\n", Bu::Url::encode( *argv ).getStr() ); + printf("decodede: %s\n", Bu::Url::decode( *argv ).getStr() ); + Bu::Url u( *argv ); + + printf("Protocol: %s\n", u.getProtocol().getStr() ); + printf("User: %s\n", u.getUser().getStr() ); + printf("Pass: %s\n", u.getPass().getStr() ); + printf("Host: %s\n", u.getHost().getStr() ); + printf("Path: %s\n", u.getPath().getStr() ); + try + { + printf("Port: %d\n", u.getPort() ); + } catch( Bu::ExceptionBase &e ) + { + printf("Port: not set.\n"); + } + printf("Parameters:\n"); + for( Bu::Url::ParamList::const_iterator i = u.getParamBegin(); i; i++ ) + { + printf(" \"%s\" = \"%s\"\n", + (*i).sName.getStr(), (*i).sValue.getStr() + ); + } } return 0; diff --git a/src/tools/nidstool.cpp b/src/tools/nidstool.cpp new file mode 100644 index 0000000..d1465ce --- /dev/null +++ b/src/tools/nidstool.cpp @@ -0,0 +1,241 @@ +#include "bu/file.h" +#include "bu/nids.h" +#include "bu/nidsstream.h" +#include "bu/paramproc.h" + +#include + +typedef struct Block +{ + uint32_t uFirstBlock; + uint32_t uNextBlock; + uint32_t uBytesUsed; +} Block; + +class Param : public Bu::ParamProc +{ +public: + Param( int argc, char *argv[] ) + { + addHelpBanner("nidstool - Do stuff with nids files.\n\n"); + addParam("info", 'i', mkproc(Param::procInfo), + "Print some info about the file."); + addParam("dump", 'd', mkproc(Param::procDump), + "Dump a stream to a file."); + addParam("analyze", 'a', mkproc(Param::procAnalyze), + "Analyze a nids file."); + addParam("copy", 'c', mkproc(Param::procCopy), + "Copy a nids file, changing settings."); + addParam("help", 'h', mkproc(Bu::ParamProc::help), "This help."); + process( argc, argv ); + } + + virtual ~Param() + { + } + + void printInfo( Bu::Nids &n ) + { + printf("File info:\n"); + printf(" Header overhead: %db\n", n.getBlockStart() ); + printf(" Block size: %db\n", n.getBlockSize() ); + printf(" Block count: %d\n", n.getNumBlocks() ); + printf(" Blocks used: %d (%d%%)\n", n.getNumUsedBlocks(), + n.getNumUsedBlocks()*100/n.getNumBlocks() ); + printf(" Block overhead: %db\n", n.getBlockOverhead() ); + printf(" Block storage: %db (%d%%)\n", + n.getBlockSize()-n.getBlockOverhead(), + (n.getBlockSize()-n.getBlockOverhead())*100/n.getBlockSize() ); + } + + int procInfo( int argc, char *argv[] ) + { + if( argc < 1 ) + { + printf("You must provide a file name.\n"); + exit( 1 ); + } + + Bu::File fIn( argv[0], Bu::File::Read ); + Bu::Nids n( fIn ); + n.initialize(); + + printInfo( n ); + + if( argc >= 2 ) + { + uint32_t uStream = strtoul( argv[1], NULL, 0 ); + uint32_t uBlock = uStream; + + Block b; + + for(;;) + { + fIn.setPos( n.getBlockStart()+n.getBlockSize()*uBlock ); + fIn.read( &b, sizeof(Block) ); + printf("Stream %u: block %u, next %u, %ub used.\n", + uStream, uBlock, b.uNextBlock, b.uBytesUsed + ); + if( b.uNextBlock == 0xFFFFFFFFUL ) + break; + uBlock = b.uNextBlock; + } + printf("Stream End.\n"); + + return 2; + } + + return 1; + } + + int procDump( int argc, char *argv[] ) + { + if( argc < 3 ) + { + printf("You must provide a nids file, a stream id, and an output " + "file.\n"); + exit( 1 ); + } + + Bu::File fIn( argv[0], Bu::File::Read ); + Bu::Nids n( fIn ); + n.initialize(); + + int iStream = strtol( argv[1], NULL, 0 ); + Bu::NidsStream sIn = n.openStream( iStream ); + + Bu::File fOut( argv[2], Bu::File::Write|Bu::File::Create ); + int iTotal = 0; + char buf[100]; + for(;;) + { + int iRead = sIn.read( buf, 100 ); + iTotal += fOut.write( buf, iRead ); + if( iRead < 100 ) + break; + } + + printf("Wrote %db from stream %d in %s to %s.\n", + iTotal, iStream, argv[0], argv[2] ); + return 3; + } + + int procAnalyze( int argc, char *argv[] ) + { + if( argc < 1 ) + { + printf("You must provide a file name.\n"); + exit( 1 ); + } + + Bu::File fIn( argv[0], Bu::File::Read ); + Bu::Nids n( fIn ); + n.initialize(); + + printInfo( n ); + + int iStreamCnt = 0; + int iStreamTotal = 0; + int iOneBlock = 0; + uint32_t iLargest = 0; + uint32_t iSmallest = 0; + int iWaste = 0; + int iUsable = n.getBlockSize()-n.getBlockOverhead(); + Block b; + for( int j = 0; j < n.getNumBlocks(); j++ ) + { + fIn.setPos( n.getBlockStart()+n.getBlockSize()*j ); + fIn.read( &b, sizeof(Block) ); + if( b.uFirstBlock != (uint32_t)j ) + continue; + + iStreamCnt++; + iStreamTotal += b.uBytesUsed; + + if( b.uNextBlock == 0xFFFFFFFFUL ) + { + iOneBlock++; + iWaste += iUsable - b.uBytesUsed; + } + else + { + iWaste += iUsable - (b.uBytesUsed%iUsable); + } + + if( j == 0 ) + { + iSmallest = iLargest = b.uBytesUsed; + } + else + { + if( iLargest < b.uBytesUsed ) + iLargest = b.uBytesUsed; + if( iSmallest > b.uBytesUsed ) + iSmallest = b.uBytesUsed; + } + } + printf("Steam analysis:\n"); + printf(" Stream count: %d\n", iStreamCnt ); + printf(" Stream size: %db/%db/%db (min/avr/max)\n", + iSmallest, iStreamTotal/iStreamCnt, iLargest ); + printf(" One-block streams: %d (%d%%)\n", + iOneBlock, iOneBlock*100/iStreamCnt ); + printf(" Total wasted space: %db (%d%%)\n", + iWaste, iWaste*100/iStreamTotal ); + printf(" Avr blocks-per-stream: %f%%\n", + (float)n.getNumBlocks()/(float)iStreamCnt ); + + return 1; + } + + int procCopy( int argc, char *argv[] ) + { + if( argc < 3 ) + { + printf("You must provide source stream, blocksize, destination.\n"); + exit( 1 ); + } + + Bu::File fIn( argv[0], Bu::File::Read ); + Bu::Nids nIn( fIn ); + nIn.initialize(); + + Bu::File fOut( argv[2], Bu::File::Read|Bu::File::Write|Bu::File::Create| + Bu::File::Truncate ); + Bu::Nids nOut( fOut ); + nOut.initialize( strtol( argv[1], 0, NULL ) ); + + Block b; + for( int j = 0; j < nIn.getNumBlocks(); j++ ) + { + fIn.setPos( nIn.getBlockStart()+nIn.getBlockSize()*j ); + fIn.read( &b, sizeof(Block) ); + if( b.uFirstBlock != (uint32_t)j ) + continue; + + Bu::NidsStream sIn = nIn.openStream( j ); + int iNew = nOut.createStream(); + Bu::NidsStream sOut = nOut.openStream( iNew ); + + char buf[1024]; + for(;;) + { + int iRead = sIn.read( buf, 1024 ); + sOut.write( buf, iRead ); + if( iRead < 1024 ) + break; + } + } + + return 3; + } +}; + + +int main( int argc, char *argv[] ) +{ + Param p( argc, argv ); + + return 0; +} + diff --git a/src/unit/array.unit b/src/unit/array.unit index 3a777d3..b6528eb 100644 --- a/src/unit/array.unit +++ b/src/unit/array.unit @@ -36,7 +36,7 @@ const Bu::Array &ci = ai; j = 0; - for( Bu::Array::const_iterator i = ci.begin(); i != ci.end(); i++ ) + for( Bu::Array::const_iterator i = ci.begin(); i; i++ ) unitTest( (*i) == j++ ); unitTest( j == 10 ); } @@ -46,6 +46,8 @@ Bu::Array ai; for( Bu::Array::iterator i = ai.begin(); i != ai.end(); i++ ) unitFailed("Empty lists shouldn't be iterated through."); + for( Bu::Array::iterator i = ai.begin(); i; i++ ) + unitFailed("Empty lists shouldn't be iterated through."); } {%copy} diff --git a/src/urn.cpp b/src/urn.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/urn.h b/src/urn.h new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3