applefork.h #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2014-1/
  • sys/
  • applefork.h
  • View
  • Commits
  • Open Download .zip Download (8 KB)
/*
 * Copyright 1995, 1996 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 */

/*
 * appleforks.h - build/split an AppleSingle/Double stream
 *
 * These classes provide the pieces for manipulating AppleSingle and
 * AppleDouble format files.  Nothing in this interface or implementation
 * is Macintosh specific, save the rediculous file format.
 *
 * We refer to each piece of a AppleSingle file as a fork, but really
 * only the resource and data portions are forks.  Unfortunately, Apple
 * didn't really name the pieces except as "entries".
 *
 * To combine forks into a single stream:
 *
 *	AppleForkCombine combine;
 *
 *	for( <each fork> )
 *	{
 *	    combine.WriteOpen( id, e );
 *	    // can repeat next line
 *	    combine.Write( buf, len, e );
 *	    combine.WriteClose( e );
 *	}
 *
 *	// read the combined data
 *
 *	while( len = combine.Read( buf, sizeof( buf ), &e )
 *		; // have data
 *
 * To split an AppleSingle stream:
 *
 *	// Assume we want to handle two forks and combine the
 *	// rest into another AppleSingle stream.
 *
 *	Special1AppleFork special1;
 *	Special2AppleFork special2;
 *	AppleForkCombine combine;
 *	AppleForkSplit split;
 *	Error e;
 *
 *	split.AddHandler( &special1 );
 *	split.AddHandler( &special2 );
 *	split.AddHandler( &combine );
 *
 *	// Write the AppleSingle stream into the splitter
 *	// special1 and special2 will be called for their pieces.
 *	// combine will get the rest.
 *
 *	while( <data> )
 *		split.Write( buf, len, &e );
 *	split.Done( &e );
 *
 *	// just for fun, read the combined data
 *
 *	while( len = combine.Read( buf, sizeof( buf ), &e )
 *		; // have data
 *
 * Note that because of the layout of the AppleSingle data (with Offs
 * embedded in the header), AppleForkCombine must buffer its results before 
 * it can make them available via Read().  It will resort to a temp
 * file if it buffers more than 100K.
 *
 * See applefile.h for the low-down on AppleSingle format.  We don't
 * use it ourselves.  rfc1740 describes the format as well.
 *
 * Classes defined:
 *
 *	AppleData - just a StrBuf with calls to access big-endian ints
 *
 *	AppleFork - a handle for dispatching a single fork
 *	AppleForkSplit - process a stream, calling AppleForks for each fork
 *	AppleForkCombine - build a stream (subclass of AppleFork)
 *
 * Public methods:
 *
 *	AppleFork::WillHandle() - return 1 if this handler will accept
 *		this entry type.  AppleForkSplit calls this for each
 *		AppleFork handler registered with it until it finds a
 *		willing handler.
 *
 *	AppleFork::Open/Write/Close() - write out fork data.  AppleForkSplit
 *		calls these (if WillHandle() has returned 1) to dispose
 *		of the fork's data.
 *
 *	AppleForkSplit::AddHandler() - register a AppleFork handler.  The
 *		last handler should accept any entry types.
 *
 *	AppleForkSplit::Write() - dispose of AppleSingle data.  Write()
 *		buffers the AppleSingle header and then starts calling
 *		AppleFork handlers to dispose of the actual data.
 *
 *	AppleForkSplit::Done() - called after the last Write() to verify
 *		that AppleForkSplit is actually done (it is a data error
 *		if not).
 *
 *	AppleForkCombine::WillHandle() - returns 1, indicating that it
 *		(a AppleFork handler) will accept any type of fork.
 *
 *	AppleForkCombine::Open/Write/Close() - consumes individual fork
 *		data, buffering the result.
 *
 *	AppleForkCombine::Read() - return AppleSingle/Double data from the
 *		combined forks.  The magic header is set to AppleSingle
 *		if a data fork is included; if not, the type is set to
 *		AppleDouble (assuming the data fork lives elsewhere).
 */

typedef unsigned int EntryId;

const int SizeHeader = 26;
const int SizeEntry = 12;

const int MagicAppleSingle = 0x00051600;
const int MagicAppleDouble = 0x00051607;
const int MagicVersion = 0x00020000;
const int EntryIdData = 1;
const int EntryIdResource = 2;
const int EntryIdRealname = 3;
const int EntryIdComment = 4;
const int EntryIdFinderInfo = 9;

// Offsets into header, Entry

const int OffHeaderMagic = 0;
const int OffHeaderVersion = 4;
const int OffHeaderNumEntries = 24;

const int OffEntryId = 0;
const int OffEntryOff = 4;
const int OffEntryLength = 8;

class AppleData : public StrBuf {

    public:

	int	GetMagic() { return Get32( OffHeaderMagic ); }
	int	GetVersion() { return Get32( OffHeaderVersion ); }
	int	GetNumEntries() { return Get16( OffHeaderNumEntries ); }
	int	GetEntryId( int x ) { return Get32( x, OffEntryId ); }
	int	GetEntryLen( int x ) { return Get32( x, OffEntryLength ); }

	void	SetMagic( int v ) { Set32( OffHeaderMagic, v ); }
	void	SetVersion( int v ) { Set32( OffHeaderVersion, v ); }
	void	SetNumEntries( int v ) { Set16( OffHeaderNumEntries, v ); }

	void	SetEntryId( int x, int v ) { Set32( x, OffEntryId, v ); }
	void	SetEntryOff( int x, int v ) { Set32( x, OffEntryOff, v ); }
	void	SetEntryLen( int x, int v ) { Set32( x, OffEntryLength, v ); }

	void	AllocHeader()
		{
		    Alloc( SizeHeader );
		    memset( Text(), 0, SizeHeader );
		    SetMagic( MagicAppleDouble );
		    SetVersion( MagicVersion );
		    SetNumEntries( 0 );
		}

	void	AllocEntry( int x, EntryId id )
		{
		    Alloc( SizeEntry );
		    SetEntryId( x, id );
		    SetEntryOff( x, 0 );
		    SetEntryLen( x, 0 );
		}

    private:

	int	Get32( int x, int o ) 
		{ 
		    return Get32( SizeHeader + x * SizeEntry + o ); 
		}

	void	Set32( int x, int o, int v ) 
		{
		    Set32( SizeHeader + x * SizeEntry + o, v ); 
		}

	int	Get32( int off )
		{
		    return 
			C( off + 0 ) * 0x1000000 + 
			C( off + 1 ) * 0x10000 +
			C( off + 2 ) * 0x100 + 
			C( off + 3 ) * 0x1;
		}

	int	Get16( int off )
		{
		    return C( off + 0 ) * 0x100 + C( off + 1 ) * 0x1;
		}

	void	Set32( int off, int val )
		{
			S( off + 0 ) = ( val / 0x1000000 ) % 0x100;
			S( off + 1 ) = ( val / 0x10000 ) % 0x100;
			S( off + 2 ) = ( val / 0x100 ) % 0x100;
			S( off + 3 ) = ( val / 0x1 ) % 0x100;
		}

	void	Set16( int off, int val )
		{
			S( off + 0 ) = ( val / 0x100 ) % 0x100;
			S( off + 1 ) = ( val / 0x1 ) % 0x100;
		}

	char &		S(int x) { return Text()[x]; }
	unsigned char 	C(int x) { return UText()[x]; }

} ;

class AppleFork {

    public:
	virtual		~AppleFork();

	virtual int	WillHandle( EntryId id ) = 0;

	virtual void	WriteOpen( EntryId id, Error *e ) = 0;
	virtual void	Write( const char *buf, int length, Error *e ) = 0;
	virtual void	WriteClose( Error *e ) = 0;

} ;

class AppleForkSplit {

    public:
			AppleForkSplit();

	void		AddHandler( AppleFork *handler );
	void		Write( const char *buf, int length, Error *e );
	void		Done( Error *e );

    private:

	AppleFork	*handler[ 5 ];
	int		numHandlers;

	AppleData	header;
	int		needed;

	int		numEntries;
	int		currentEntry;
	AppleFork	*currentHandler;

	enum State {
		BeforeEndOfHeader,	// filling header
		BeforeEndOfIndex,	// filling entry index
		StartingFork,		// looking to fill a fork
		InFork			// filling a fork
	} state;
} ;

class AppleForkCombine : public AppleFork {

    public:
			AppleForkCombine();
			~AppleForkCombine();

	// from AppleFork

	virtual int	WillHandle( EntryId id );
	virtual void	WriteOpen( EntryId id, Error *e );
	virtual void	Write( const char *buf, int length, Error *e );
	virtual void	WriteClose( Error *e );

	// to read the results

	int		Read( char *buf, int length, Error *e );
	int		IsAppleSingle() { return isSingle; }

    private:

	AppleData	header;		// apple header and entries
	StrBuf		data;		// fork contents
	int		numEntries;	// number of entries in header
	int		dataLength;	// track per-fork length
	int		isSingle;	// has data fork

	class FileSys 	*dataBack;	// for big data

	enum State {
		Start,		// initialize for Read()
		Header,		// Read() from header
		Data,		// Read() from data
		Done		// Read() returns 0
	} state ;
} ;
# Change User Description Committed
#1 15902 Matt Attaway A second renaming that I will not obliterate as a badge of shame
//guest/perforce_software/p4/2014_1/sys/applefork.h
#1 15901 Matt Attaway Clean up code to fit modern Workshop naming standards
//guest/perforce_software/p4/2014.1/sys/applefork.h
#1 12188 Matt Attaway Move 'main' p4 into a release specific directory in prep for new releases
//guest/perforce_software/p4/sys/applefork.h
#1 9129 Matt Attaway Initial commit of the 2014.1 p4/p4api source code