commands/fed/inc/filebuffer.h
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // filebuffer.h
       
     2 // 
       
     3 // Copyright (c) 2009 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 #ifndef FILEBUFFER_H_
       
    13 #define FILEBUFFER_H_
       
    14 
       
    15 #include <f32file.h>
       
    16 #include <Babitflags.h>
       
    17 #include "bufferbase.h"
       
    18 
       
    19 class CFileBlock;
       
    20 class CCnvCharacterSetConverter;
       
    21 
       
    22 _LIT8(KBigEndianBom,    "\xFE\xFF");
       
    23 _LIT8(KLittleEndianBom, "\xFF\xFE");
       
    24 _LIT8(KUtf8Bom,         "\xEF\xBB\xBF");
       
    25 
       
    26 #ifdef __BIG_ENDIAN__
       
    27 static const TDesC8& KNativeBom(KBigEndianBom);
       
    28 #else
       
    29 static const TDesC8& KNativeBom(KLittleEndianBom);
       
    30 #endif
       
    31 
       
    32 /*
       
    33  An efficient backing store for document data, that allows files larger than available memory to be shown.
       
    34  Data is paged in and out of the store depending on what part of the document is being viewed. The
       
    35  granularity of paging is the CFileBlock object, which can represent up to 64KB of on-disk data. Blocks that
       
    36  have been modified are kept in memory until the file is saved, whereas unmodified blocks can be flushed
       
    37  whenever it is required. We take care to ensure that UTF-8 and CRLF sequences are never split across blocks,
       
    38  and that blocks are split if they become too large to page out (ie >64KB)
       
    39 
       
    40  CFileBlock keeps some metadata about the block it represents in memory at all times - the extent and number of
       
    41  lines in the block. This is so we can support efficient per-character and per-line seeking through the file
       
    42  without having to page the whole thing into memory.
       
    43 
       
    44  In principle CFileBuffer supports file sizes up to 2GB, but in practice the CFileBlock metadata will probably
       
    45  fill the default 1MB heap after around 50-100MB.
       
    46 */
       
    47 
       
    48 class CFileBuffer : public CFedBufferBase
       
    49 	{
       
    50 public:
       
    51 
       
    52 	static CFileBuffer* NewL(RFs& aFs, CCnvCharacterSetConverter* aCharconv, const TDesC& aName, TBool aAllowNonexistantName);
       
    53 	~CFileBuffer();
       
    54 
       
    55 protected:
       
    56 	CFileBuffer(RFs& aFs, CCnvCharacterSetConverter* aCharconv);
       
    57 	void ConstructL(const TDesC& aName, TBool aAllowNonexistantName);
       
    58 	void ConstructL();
       
    59 	void CommonConstructL();
       
    60 
       
    61 public:
       
    62 	const TDesC& Title() const;
       
    63 	TBool Modified() const;
       
    64 	TDelimiterType DelimiterType() const;
       
    65 	TEncodingType Encoding() const;
       
    66 	TBool Editable() const;
       
    67 	TBool IsOpen() const;
       
    68 
       
    69 	TInt GetData(MSharedCacheClient& aClient, TInt aDocumentPosition); // "Get me the block containing aDocumentPosition".
       
    70 	TInt SeekFromOffset(MSharedCacheClient& aClient, TInt aOffset, TInt aNumLinesFromOffset, TInt aLineLength); 
       
    71 	TBool DocumentPositionIsEof(TInt aDocumentPosition) const; // The block containing aDocumentPosition MUST have already have been loaded (otherwise we could not guarantee const-ness)
       
    72 
       
    73 	void InsertTextL(TInt aDocumentPosition, const TDesC& aText);
       
    74 	void DeleteTextL(TRange aRange);
       
    75 	void SaveL(const TDesC& aName, TBool aReplace);
       
    76 	TInt Find(TInt aStartingPosition, const TDesC& aSearchString, TBool aBackwards);
       
    77 
       
    78 protected:
       
    79 	static TInt CalculateCacheBufSize(TInt aFileSize);
       
    80 	void TidyCache(); // Calls UnloadBlockIfPossible on all blocks
       
    81 	void UnloadBlockIfPossible(CFileBlock* aBlock);
       
    82 	CFileBlock* FindBlockForDocumentPosition(TInt aPosition, TInt* aOffset, TInt* aLineCountToDocPos=NULL); // If aOffset isn't null, it is set to the offset from the block start to the specified document position. If aLineCountToDocPos is nonnull the line count to the offset is calculated (may load the block if necessary)
       
    83 	TInt LoadBlock(CFileBlock* aBlock);
       
    84 	static void DeleteTempFile(TAny* aSelf);
       
    85 	static void SetFinalNameToTemporary(TAny* aSelf);
       
    86 	TInt DoFindL(TInt aStartingPosition, const TDesC& aSearchString, TBool aBackwards);
       
    87 
       
    88 protected:
       
    89 	TDelimiterType iDelimType;
       
    90 	TEncodingType iEncoding;
       
    91 	RFs& iFs;
       
    92 	RFile iFile;
       
    93 	TInt iCacheBufSize;
       
    94 	TFileName iFinalName;
       
    95 	TFileName* iTempName; // Used during saving, if we're writing to a temporary.
       
    96 
       
    97 	CFileBlock* iFirstBlock;
       
    98 	CFileBlock* iCurrentBlock; // For a given (currently, unimportant) value of current
       
    99 	RBuf8 iNarrowBuf;
       
   100 	TBool iUnsaved;
       
   101 	CCnvCharacterSetConverter* iCharconv; // This wouldn't be needed if the exported version of CnvUtfConverter::ConvertToUnicodeFromUtf8 ACTUALLY WORKED
       
   102 	};
       
   103 
       
   104 class CFileBlock : public CBase
       
   105 	{
       
   106 public:
       
   107 	CFileBlock(TInt aFilePosition, TInt aBlockSize);
       
   108 	~CFileBlock();
       
   109 	void InsertAfterBlock(CFileBlock* aBlock);
       
   110 	CFileBlock* Next() const;
       
   111 	CFileBlock* Prev() const;
       
   112 	TInt BlockDidLoad(TEncodingType& aFileEncoding, TDelimiterType& aDelimType, const TDesC8& aData, CCnvCharacterSetConverter* aCharconvForUtf8Conversion);
       
   113 	TInt ConvertToEightBit(TEncodingType aEncoding, TDelimiterType aDelimeter, RBuf8& aResultBuf);
       
   114 	void FileHasBeenSaved(); // Only call on the first block of the file - it will update other blocks as needed
       
   115 	
       
   116 	/* Return the buffer position after the aTarget'th newline, or KErrNotFound.
       
   117 	 * On return, aTarget is set to the number of newlines actually read.
       
   118 	 * Pass in KMaxTInt as aTarget to count how many newlines in the buffer. (target passes back the resulting number read, the function returns KErrNotFound in this case because your 'target' of KMaxTInt was not reached)
       
   119 	 * Pass in negative target to count backwards from end of block
       
   120 	 * Pass in KMaxTInt as aSoftWrapLineLength if you don't want lines to soft wrap
       
   121 	 * If non-null, aDelimType is set to the first type of newline encountered in the block
       
   122 	 */
       
   123 	static TInt CountNewLines(const TDesC& aDes, TInt& aTarget, TInt aSoftWrapLineLength, TDelimiterType* aDelimType=NULL);
       
   124 	void Unload();
       
   125 
       
   126 	TBool IsLoaded() const; // Returns true if the block is in memory, ie if iData.Size() != 0.
       
   127 	TBool HasBeenLoaded() const; // Indicates that cached data (such as num newlines etc) is valid
       
   128 	TBool IsDirty() const; // Returns true if the block has been modified
       
   129 	const TDesC16& Text() const; // block must be loaded
       
   130 
       
   131 	void CalculateBlockPositions(TInt& aCharacterPos, TInt& aLineCount) const; // Requires iterating block list
       
   132 	TInt FilePosition() const; // Returns the on-disk location (in bytes) of this block (constant-time operation)
       
   133 	TInt BlockSize() const; // block size in bytes
       
   134 	TInt CharacterCount() const; // block must have been loaded, as knowing block size is not sufficient to calculate number of chars
       
   135 	TInt NewlineCount() const; // block must have been loaded
       
   136 	TInt CountNewLinesUpToOffset(TInt aOffset) const;
       
   137 
       
   138 	void InsertTextL(TInt aBlockOffset, const TDesC16& aText);
       
   139 	void DeleteText(TInt aPos, TInt aLen);
       
   140 
       
   141 private:
       
   142 	TInt TransferDataFromPreviousBlock(CFileBlock* aPrev, const TDesC8& aData);
       
   143 	TInt ReplaceAll(const TDesC& aFrom, const TDesC& aTo);
       
   144 	TInt SplitBufferAt(TInt aCharacterPosition); // Splits one buffer in to two
       
   145 
       
   146 private:
       
   147 	enum TFlags
       
   148 		{
       
   149 		EHasBeenLoaded = 0,
       
   150 		EDirty = 1,
       
   151 		EHaveCalculatedLineEndings = 2, // We can't use iNumLineEndings=-1 to indicate it's not valid because it's unsigned, and it's unsigned because we need every bit
       
   152 		};
       
   153 	TInt iFilePosition; // in bytes
       
   154 	TUint16 iBlockSize; // in bytes
       
   155 	TUint16 iNumCharacters; // Cached first time block is loaded. Will never be more than iBlockSize because one byte can never represent more than one character (in any encoding we support)
       
   156 	// We cache the number of line endings so that "Go to line" operations are fast, the correct block for a particular line can be calculated just by iterating the CFileBlocks
       
   157 	mutable TUint16 iNumLineEndings; // Number of line endings *in this block*. Mutable so NewlineCount can update it 
       
   158 	mutable TBitFlags16 iFlags; // Only the EHaveCalculatedLineEndings flag needs to be mutable but no avoiding it
       
   159 	
       
   160 	HBufC16* iData;
       
   161 	CFileBlock* iPrev;
       
   162 	CFileBlock* iNext;
       
   163 	};
       
   164 
       
   165 #endif /*FILEBUFFER_H_*/