|
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_*/ |