fpspreadsheet: Improved OLE storage code
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@651 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
a52fbe2039
commit
99057104e2
@ -38,7 +38,7 @@
|
||||
<CursorPos X="16" Y="16"/>
|
||||
<TopLine Value="1"/>
|
||||
<EditorIndex Value="0"/>
|
||||
<UsageCount Value="51"/>
|
||||
<UsageCount Value="96"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
@ -46,61 +46,61 @@
|
||||
<UnitName Value="fpspreadsheet"/>
|
||||
<CursorPos X="32" Y="414"/>
|
||||
<TopLine Value="388"/>
|
||||
<UsageCount Value="25"/>
|
||||
<UsageCount Value="20"/>
|
||||
</Unit1>
|
||||
<Unit2>
|
||||
<Filename Value="..\xlsbiff5.pas"/>
|
||||
<UnitName Value="xlsbiff5"/>
|
||||
<CursorPos X="16" Y="320"/>
|
||||
<TopLine Value="300"/>
|
||||
<UsageCount Value="25"/>
|
||||
<UsageCount Value="20"/>
|
||||
</Unit2>
|
||||
<Unit3>
|
||||
<Filename Value="..\..\..\..\..\FPC220\source\packages\base\winunits\activex.pp"/>
|
||||
<UnitName Value="ActiveX"/>
|
||||
<CursorPos X="27" Y="29"/>
|
||||
<TopLine Value="6"/>
|
||||
<UsageCount Value="9"/>
|
||||
<UsageCount Value="4"/>
|
||||
</Unit3>
|
||||
<Unit4>
|
||||
<Filename Value="..\fpolestorage.pas"/>
|
||||
<UnitName Value="fpolestorage"/>
|
||||
<CursorPos X="1" Y="1"/>
|
||||
<TopLine Value="1"/>
|
||||
<UsageCount Value="45"/>
|
||||
<UsageCount Value="40"/>
|
||||
</Unit4>
|
||||
<Unit5>
|
||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\inc\objpash.inc"/>
|
||||
<CursorPos X="21" Y="141"/>
|
||||
<TopLine Value="131"/>
|
||||
<UsageCount Value="9"/>
|
||||
<UsageCount Value="4"/>
|
||||
</Unit5>
|
||||
<Unit6>
|
||||
<Filename Value="..\xlsbiff2.pas"/>
|
||||
<UnitName Value="xlsbiff2"/>
|
||||
<CursorPos X="20" Y="277"/>
|
||||
<TopLine Value="260"/>
|
||||
<UsageCount Value="18"/>
|
||||
<UsageCount Value="13"/>
|
||||
</Unit6>
|
||||
<Unit7>
|
||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\classes\classesh.inc"/>
|
||||
<CursorPos X="22" Y="1602"/>
|
||||
<TopLine Value="1598"/>
|
||||
<UsageCount Value="11"/>
|
||||
<UsageCount Value="6"/>
|
||||
</Unit7>
|
||||
<Unit8>
|
||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\win32\buildrtl.pp"/>
|
||||
<UnitName Value="buildrtl"/>
|
||||
<CursorPos X="29" Y="5"/>
|
||||
<TopLine Value="1"/>
|
||||
<UsageCount Value="9"/>
|
||||
<UsageCount Value="4"/>
|
||||
</Unit8>
|
||||
<Unit9>
|
||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\fgl.pp"/>
|
||||
<UnitName Value="fgl"/>
|
||||
<CursorPos X="15" Y="86"/>
|
||||
<TopLine Value="55"/>
|
||||
<UsageCount Value="18"/>
|
||||
<UsageCount Value="13"/>
|
||||
</Unit9>
|
||||
<Unit10>
|
||||
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
||||
@ -108,7 +108,7 @@
|
||||
<CursorPos X="11" Y="737"/>
|
||||
<TopLine Value="713"/>
|
||||
<EditorIndex Value="6"/>
|
||||
<UsageCount Value="15"/>
|
||||
<UsageCount Value="37"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit10>
|
||||
<Unit11>
|
||||
@ -116,14 +116,14 @@
|
||||
<UnitName Value="Win32WSControls"/>
|
||||
<CursorPos X="13" Y="206"/>
|
||||
<TopLine Value="199"/>
|
||||
<UsageCount Value="12"/>
|
||||
<UsageCount Value="7"/>
|
||||
</Unit11>
|
||||
<Unit12>
|
||||
<Filename Value="..\..\..\..\..\lazarus\components\sqlite\registersqlite3.pas"/>
|
||||
<UnitName Value="registersqlite3"/>
|
||||
<CursorPos X="15" Y="5"/>
|
||||
<TopLine Value="1"/>
|
||||
<UsageCount Value="11"/>
|
||||
<UsageCount Value="6"/>
|
||||
</Unit12>
|
||||
<Unit13>
|
||||
<Filename Value="..\..\..\..\..\lazarus\ideintf\componenteditors.pas"/>
|
||||
@ -131,22 +131,22 @@
|
||||
<CursorPos X="54" Y="353"/>
|
||||
<TopLine Value="330"/>
|
||||
<EditorIndex Value="5"/>
|
||||
<UsageCount Value="13"/>
|
||||
<UsageCount Value="35"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit13>
|
||||
<Unit14>
|
||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\classes\cregist.inc"/>
|
||||
<CursorPos X="17" Y="124"/>
|
||||
<TopLine Value="121"/>
|
||||
<UsageCount Value="11"/>
|
||||
<UsageCount Value="6"/>
|
||||
</Unit14>
|
||||
<Unit15>
|
||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||
<UnitName Value="xlsbiff5"/>
|
||||
<CursorPos X="41" Y="218"/>
|
||||
<TopLine Value="209"/>
|
||||
<CursorPos X="28" Y="62"/>
|
||||
<TopLine Value="59"/>
|
||||
<EditorIndex Value="2"/>
|
||||
<UsageCount Value="11"/>
|
||||
<UsageCount Value="33"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit15>
|
||||
<Unit16>
|
||||
@ -155,7 +155,7 @@
|
||||
<CursorPos X="1" Y="49"/>
|
||||
<TopLine Value="30"/>
|
||||
<EditorIndex Value="1"/>
|
||||
<UsageCount Value="11"/>
|
||||
<UsageCount Value="33"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit16>
|
||||
<Unit17>
|
||||
@ -164,80 +164,140 @@
|
||||
<CursorPos X="1" Y="69"/>
|
||||
<TopLine Value="57"/>
|
||||
<EditorIndex Value="3"/>
|
||||
<UsageCount Value="11"/>
|
||||
<UsageCount Value="33"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit17>
|
||||
<Unit18>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<UnitName Value="fpolestorage"/>
|
||||
<CursorPos X="33" Y="133"/>
|
||||
<TopLine Value="121"/>
|
||||
<CursorPos X="1" Y="471"/>
|
||||
<TopLine Value="458"/>
|
||||
<EditorIndex Value="4"/>
|
||||
<UsageCount Value="11"/>
|
||||
<UsageCount Value="33"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit18>
|
||||
</Units>
|
||||
<JumpHistory Count="15" HistoryIndex="14">
|
||||
<JumpHistory Count="30" HistoryIndex="29">
|
||||
<Position1>
|
||||
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
||||
<Caret Line="1" Column="1" TopLine="1"/>
|
||||
<Caret Line="737" Column="11" TopLine="713"/>
|
||||
</Position1>
|
||||
<Position2>
|
||||
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
||||
<Caret Line="737" Column="11" TopLine="713"/>
|
||||
</Position2>
|
||||
<Position3>
|
||||
<Filename Value="..\..\..\..\..\lazarus\ideintf\componenteditors.pas"/>
|
||||
<Caret Line="353" Column="54" TopLine="330"/>
|
||||
</Position3>
|
||||
<Position4>
|
||||
</Position2>
|
||||
<Position3>
|
||||
<Filename Value="excel5demo.lpr"/>
|
||||
<Caret Line="49" Column="12" TopLine="30"/>
|
||||
</Position4>
|
||||
<Position5>
|
||||
</Position3>
|
||||
<Position4>
|
||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||
<Caret Line="365" Column="37" TopLine="354"/>
|
||||
</Position4>
|
||||
<Position5>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="38" Column="20" TopLine="21"/>
|
||||
</Position5>
|
||||
<Position6>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="38" Column="20" TopLine="21"/>
|
||||
<Caret Line="60" Column="54" TopLine="49"/>
|
||||
</Position6>
|
||||
<Position7>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="60" Column="54" TopLine="49"/>
|
||||
<Caret Line="44" Column="24" TopLine="32"/>
|
||||
</Position7>
|
||||
<Position8>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="44" Column="24" TopLine="32"/>
|
||||
<Caret Line="51" Column="25" TopLine="34"/>
|
||||
</Position8>
|
||||
<Position9>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="51" Column="25" TopLine="34"/>
|
||||
<Caret Line="157" Column="21" TopLine="151"/>
|
||||
</Position9>
|
||||
<Position10>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="157" Column="21" TopLine="151"/>
|
||||
<Caret Line="155" Column="5" TopLine="136"/>
|
||||
</Position10>
|
||||
<Position11>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="155" Column="5" TopLine="136"/>
|
||||
<Caret Line="65" Column="3" TopLine="58"/>
|
||||
</Position11>
|
||||
<Position12>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="65" Column="3" TopLine="58"/>
|
||||
<Caret Line="25" Column="11" TopLine="16"/>
|
||||
</Position12>
|
||||
<Position13>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="25" Column="11" TopLine="16"/>
|
||||
</Position13>
|
||||
<Position14>
|
||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||
<Caret Line="194" Column="15" TopLine="60"/>
|
||||
</Position14>
|
||||
<Position15>
|
||||
</Position13>
|
||||
<Position14>
|
||||
<Filename Value="..\..\fpsutils.pas"/>
|
||||
<Caret Line="45" Column="5" TopLine="26"/>
|
||||
</Position14>
|
||||
<Position15>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="150" Column="5" TopLine="131"/>
|
||||
</Position15>
|
||||
<Position16>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="191" Column="5" TopLine="172"/>
|
||||
</Position16>
|
||||
<Position17>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="49" Column="15" TopLine="39"/>
|
||||
</Position17>
|
||||
<Position18>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="331" Column="45" TopLine="326"/>
|
||||
</Position18>
|
||||
<Position19>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="24" Column="27" TopLine="19"/>
|
||||
</Position19>
|
||||
<Position20>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="247" Column="1" TopLine="229"/>
|
||||
</Position20>
|
||||
<Position21>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="224" Column="5" TopLine="205"/>
|
||||
</Position21>
|
||||
<Position22>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="231" Column="1" TopLine="219"/>
|
||||
</Position22>
|
||||
<Position23>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="377" Column="5" TopLine="358"/>
|
||||
</Position23>
|
||||
<Position24>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="225" Column="1" TopLine="211"/>
|
||||
</Position24>
|
||||
<Position25>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="246" Column="12" TopLine="237"/>
|
||||
</Position25>
|
||||
<Position26>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="79" Column="16" TopLine="78"/>
|
||||
</Position26>
|
||||
<Position27>
|
||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||
<Caret Line="87" Column="16" TopLine="77"/>
|
||||
</Position27>
|
||||
<Position28>
|
||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||
<Caret Line="218" Column="24" TopLine="207"/>
|
||||
</Position28>
|
||||
<Position29>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="235" Column="30" TopLine="224"/>
|
||||
</Position29>
|
||||
<Position30>
|
||||
<Filename Value="..\..\fpolestorage.pas"/>
|
||||
<Caret Line="80" Column="28" TopLine="68"/>
|
||||
</Position30>
|
||||
</JumpHistory>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
|
@ -4,6 +4,29 @@ fpolestorage.pas
|
||||
Writes an OLE document
|
||||
|
||||
AUTHORS: Felipe Monteiro de Carvalho
|
||||
|
||||
Limitations of this unit for creating OLE documents:
|
||||
|
||||
* Can only create documents with an array of streams. It's not possible
|
||||
to create real directory structures like the OLE format supports.
|
||||
This is no problem for most applications.
|
||||
|
||||
The Windows only code, which calls COM to write the documents
|
||||
should work very well. It's limitations are:
|
||||
|
||||
* Supports only 1 stream in the file
|
||||
|
||||
The cross-platform code at this moment has several limitations,
|
||||
but should work for most documents. Some limitations are:
|
||||
|
||||
* Supports only 1 stream in the file
|
||||
* Fixed sectors size of 512 bytes
|
||||
* Fixed short sector size of 64 bytes
|
||||
* Never allocates more space for the MSAT, limiting the SAT to 109 sectors,
|
||||
which means a total
|
||||
* Never allocates more then 1 sector for the SAT, so the document may have
|
||||
only up to 512 / 4 = 128 sectors
|
||||
|
||||
}
|
||||
unit fpolestorage;
|
||||
|
||||
@ -21,7 +44,7 @@ uses
|
||||
{$ifdef FPOLESTORAGE_USE_COM}
|
||||
ActiveX, ComObj,
|
||||
{$endif}
|
||||
Classes, SysUtils,
|
||||
Classes, SysUtils, Math,
|
||||
fpsutils;
|
||||
|
||||
type
|
||||
@ -29,7 +52,11 @@ type
|
||||
{ Describes an OLE Document }
|
||||
|
||||
TOLEDocument = record
|
||||
Sections: array of TMemoryStream;
|
||||
// Information about the streams
|
||||
// All arrays here should have the same length
|
||||
// Actually at the time all of them should have length 1
|
||||
Streams: array of TMemoryStream;
|
||||
StreamsNumSectors: array of Cardinal;
|
||||
end;
|
||||
|
||||
|
||||
@ -43,10 +70,15 @@ type
|
||||
{$endif}
|
||||
{ Information filled by the write routines for the helper routines }
|
||||
FOLEDocument: TOLEDocument;
|
||||
FNumSectors: Cardinal;
|
||||
FNumStreams, FNumSATSectors, FNumStreamSectors, FNumTotalSectors: Cardinal;
|
||||
{ Helper routines }
|
||||
procedure WriteOLEHeader(AStream: TStream);
|
||||
procedure WriteSectorAllocationTable(AStream: TStream);
|
||||
procedure WriteDirectoryStream(AStream: TStream);
|
||||
procedure WriteDirectoryEntry(AStream: TStream; AName: widestring;
|
||||
EntryType, EntryColor: Byte; AIsStorage: Boolean;
|
||||
AStreamSize: Cardinal);
|
||||
procedure WriteShortSectorAllocationTable(AStream: TStream);
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
@ -55,6 +87,18 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
INT_OLE_SECTOR_SIZE = 512; // in bytes
|
||||
INT_OLE_SECTOR_DWORD_SIZE = 512 div 4; // in dwords
|
||||
INT_OLE_SHORT_SECTOR_SIZE = 64; // in bytes
|
||||
|
||||
INT_OLE_DIR_ENTRY_TYPE_EMPTY = 0;
|
||||
INT_OLE_DIR_ENTRY_TYPE_USER_STREAM = 2;
|
||||
INT_OLE_DIR_ENTRY_TYPE_ROOT_STORAGE = 5;
|
||||
|
||||
INT_OLE_DIR_COLOR_RED = 0;
|
||||
INT_OLE_DIR_COLOR_BLACK = 1;
|
||||
|
||||
{ TOLEStorage }
|
||||
|
||||
{
|
||||
@ -111,7 +155,7 @@ begin
|
||||
AStream.WriteWord($0);
|
||||
|
||||
{ 44 4 Total number of sectors used for the sector allocation table (➜5.2) }
|
||||
AStream.WriteDWord(DWordToLE(FNumSectors));
|
||||
AStream.WriteDWord(DWordToLE(1));
|
||||
|
||||
{ 48 4 SecID of first sector of the directory stream (➜7) }
|
||||
AStream.WriteDWord(DWordToLE($01));
|
||||
@ -151,37 +195,207 @@ begin
|
||||
{ Simple copy of an example OLE file
|
||||
|
||||
00000200H FD FF FF FF FF FF FF FF FE FF FF FF 04 00 00 00
|
||||
00000210H 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00
|
||||
00000220H 09 00 00 00 FE FF FF FF 0B 00 00 00 FE FF FF FF
|
||||
00000210H FE FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
|
||||
And from now on only $FFFFFFFF covering $230 to $3FF
|
||||
for a total of $400 - $230 bytes of $FF }
|
||||
And from now on only $FFFFFFFF covering $220 to $3FF
|
||||
for a total of $400 - $220 bytes of $FF }
|
||||
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFD));
|
||||
AStream.WriteDWord($FFFFFFFF);
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFE));
|
||||
AStream.WriteDWord(DWordToLE($00000004));
|
||||
AStream.WriteDWord(DWordToLE($00000005));
|
||||
AStream.WriteDWord(DWordToLE($00000006));
|
||||
AStream.WriteDWord(DWordToLE($00000007));
|
||||
AStream.WriteDWord(DWordToLE($00000008));
|
||||
AStream.WriteDWord(DWordToLE($00000009));
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFE));
|
||||
AStream.WriteDWord(DWordToLE($0000000B));
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFE));
|
||||
AStream.WriteDWord($FFFFFFFF);
|
||||
AStream.WriteDWord($FFFFFFFF);
|
||||
AStream.WriteDWord($FFFFFFFF);
|
||||
|
||||
for i := 1 to ($400 - $230) do AStream.WriteByte($FF);
|
||||
for i := 1 to ($400 - $220) do AStream.WriteByte($FF);
|
||||
|
||||
{
|
||||
This results in the following SecID array for the SAT:
|
||||
|
||||
Array indexes 0 1 2 3 4 5 6 7 8 9 10 11 12 ...
|
||||
SecID array –3 –1 –2 4 5 6 7 8 9 –2 11 –2 –1 ...
|
||||
Array indexes 0 1 2 3 4 5 ...
|
||||
SecID array –3 –1 –2 4 -2 -1 ...
|
||||
|
||||
As expected, sector 0 is marked with the special SAT SecID (➜3.1). Sector 1 and all sectors starting with sector 12 are
|
||||
As expected, sector 0 is marked with the special SAT SecID (➜3.1).
|
||||
Sector 1 and all sectors starting with sector 5 are
|
||||
not used (special Free SecID with value –1). }
|
||||
end;
|
||||
|
||||
{
|
||||
7.2.1 Directory Entry Structure
|
||||
The size of each directory entry is exactly 128 bytes. The formula to calculate an offset in the directory stream from a
|
||||
DirID is as follows:
|
||||
dir_entry_pos(DirID) = DirID ∙ 128
|
||||
}
|
||||
procedure TOLEStorage.WriteDirectoryEntry(AStream: TStream; AName: widestring;
|
||||
EntryType, EntryColor: Byte; AIsStorage: Boolean;
|
||||
AStreamSize: Cardinal);
|
||||
var
|
||||
i: Integer;
|
||||
EntryName: array[0..31] of WideChar;
|
||||
begin
|
||||
{ Contents of the directory entry structure:
|
||||
Offset Size Contents
|
||||
0 64 Character array of the name of the entry, always 16-bit Unicode characters, with trailing
|
||||
zero character (results in a maximum name length of 31 characters)
|
||||
|
||||
00000400H 52 00 6F 00 6F 00 74 00 20 00 45 00 6E 00 74 00 }
|
||||
|
||||
EntryName := AName;
|
||||
|
||||
AStream.WriteBuffer(EntryName, 64);
|
||||
|
||||
{Root Storage #1
|
||||
00000440H 16 00 05 00 FF FF FF FF FF FF FF FF 01 00 00 00
|
||||
|
||||
Book #2
|
||||
000004C0H 0A 00 02 01 FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
|
||||
Item #3 e #4
|
||||
00000540H 00 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF
|
||||
|
||||
Root Storage #5
|
||||
00000640H 16 00 05 00 FF FF FF FF FF FF FF FF 01 00 00 00
|
||||
|
||||
64 2 Size of the used area of the character buffer of the name (not character count), including
|
||||
the trailing zero character (e.g. 12 for a name with 5 characters: (5+1)∙2 = 12)
|
||||
66 1 Type of the entry: 00H = Empty 03H = LockBytes (unknown)
|
||||
01H = User storage 04H = Property (unknown)
|
||||
02H = User stream 05H = Root storage
|
||||
67 1 Node colour of the entry: 00H = Red 01H = Black
|
||||
68 4 DirID of the left child node inside the red-black tree of all direct members of the parent
|
||||
storage (if this entry is a user storage or stream, ➜7.1), –1 if there is no left child
|
||||
72 4 DirID of the right child node inside the red-black tree of all direct members of the parent
|
||||
storage (if this entry is a user storage or stream, ➜7.1), –1 if there is no right child
|
||||
76 4 DirID of the root node entry of the red-black tree of all storage members (if this entry is a
|
||||
storage, ➜7.1), –1 otherwise
|
||||
}
|
||||
|
||||
AStream.WriteWord(WordToLE(Length(AName) * 2));
|
||||
AStream.WriteByte(EntryType);
|
||||
AStream.WriteByte(EntryColor);
|
||||
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFF));
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFF));
|
||||
|
||||
if AIsStorage then AStream.WriteDWord(DWordToLE($00000001))
|
||||
else AStream.WriteDWord(DWordToLE($FFFFFFFF));;
|
||||
|
||||
{00000450H 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
80 16 Unique identifier, if this is a storage (not of interest in the following, may be all 0)
|
||||
|
||||
00000460H 00 00 00 00 00 00 00 00 00 00 00 00 00 4E 67 0E
|
||||
00000470H 39 6F C9 01
|
||||
|
||||
96 4 User flags (not of interest in the following, may be all 0)
|
||||
100 8 Time stamp of creation of this entry (➜7.2.3). Most implementations do not write a valid
|
||||
time stamp, but fill up this space with zero bytes.
|
||||
108 8 Time stamp of last modification of this entry (➜7.2.3). Most implementations do not write
|
||||
a valid time stamp, but fill up this space with zero bytes.
|
||||
}
|
||||
|
||||
for i := 1 to ($474 - $450) do AStream.WriteByte($00);
|
||||
|
||||
{Root Storage #1
|
||||
00000470H XX XX XX XX 03 00 00 00 40 03 00 00 00 00 00 00
|
||||
|
||||
Book #2
|
||||
000004F0H XX XX XX XX 00 00 00 00 3F 03 00 00 00 00 00 00
|
||||
|
||||
Item #3 e #4
|
||||
00000570H XX XX XX XX 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
Root Storage #5
|
||||
00000670H XX XX XX XX 03 00 00 00 40 03 00 00 00 00 00 00
|
||||
|
||||
Book #6
|
||||
000004F0H XX XX XX XX 00 00 00 00 3F 03 00 00 00 00 00 00
|
||||
|
||||
First 4 bytes still with the timestamp.
|
||||
|
||||
116 4 SecID of first sector or short-sector, if this entry refers to a stream (➜7.2.2), SecID of first
|
||||
sector of the short-stream container stream (➜6.1), if this is the root storage entry, 0
|
||||
otherwise
|
||||
120 4 Total stream size in bytes, if this entry refers to a stream (➜7.2.2), total size of the short-
|
||||
stream container stream (➜6.1), if this is the root storage entry, 0 otherwise
|
||||
124 4 Not used
|
||||
}
|
||||
|
||||
if AIsStorage then AStream.WriteDWord(DWordToLE($00000003))
|
||||
else AStream.WriteDWord(0);
|
||||
|
||||
AStream.WriteDWord(DWordToLE(AStreamSize));
|
||||
|
||||
AStream.WriteDWord(DWordToLE($00000000));
|
||||
end;
|
||||
|
||||
procedure TOLEStorage.WriteDirectoryStream(AStream: TStream);
|
||||
begin
|
||||
WriteDirectoryEntry(AStream, 'Root Entry'#0,
|
||||
INT_OLE_DIR_ENTRY_TYPE_ROOT_STORAGE, INT_OLE_DIR_COLOR_RED,
|
||||
True, $00000340);
|
||||
|
||||
WriteDirectoryEntry(AStream, 'Book'#0,
|
||||
INT_OLE_DIR_ENTRY_TYPE_USER_STREAM, INT_OLE_DIR_COLOR_BLACK,
|
||||
False, $0000033F);
|
||||
|
||||
WriteDirectoryEntry(AStream, #0,
|
||||
INT_OLE_DIR_ENTRY_TYPE_EMPTY, INT_OLE_DIR_COLOR_RED,
|
||||
False, $00000000);
|
||||
|
||||
WriteDirectoryEntry(AStream, #0,
|
||||
INT_OLE_DIR_ENTRY_TYPE_EMPTY, INT_OLE_DIR_COLOR_RED,
|
||||
False, $00000000);
|
||||
end;
|
||||
|
||||
{
|
||||
8.4 Short-Sector Allocation Table
|
||||
|
||||
The short-sector allocation table (SSAT) is an array of SecIDs and contains the SecID chains (➜3.2) of all short-
|
||||
streams, similar to the sector allocation table (➜5.2) that contains the SecID chains of standard streams.
|
||||
The first SecID of the SSAT is contained in the header (➜4.1), the remaining SecID chain is contained in the SAT. The
|
||||
SSAT is built by reading and concatenating the contents of all sectors.
|
||||
Contents of a sector of the SSAT (sec_size is the size of a sector in bytes, see ➜4.1):
|
||||
Offset Size Contents
|
||||
0 sec_size Array of sec_size/4 SecIDs of the SSAT
|
||||
The SSAT will be used similarly to the SAT (➜5.2) with the difference that the SecID chains refer to short-sectors in the
|
||||
short-stream container stream (➜6.1).
|
||||
|
||||
This results in the following SecID array for the SSAT:
|
||||
Array
|
||||
indexes 0 1 2 3 4 5 6 7 8 9 1011...4142434445464748495051525354...
|
||||
SecID array 1 2 3 4 5 6 7 8 9 101112...42434445–247–2–250515253–2–1...
|
||||
All short-sectors starting with sector 54 are not used (special Free SecID with value –1).
|
||||
}
|
||||
procedure TOLEStorage.WriteShortSectorAllocationTable(AStream: TStream);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
AStream.WriteDWord(DWordToLE($00000001));
|
||||
AStream.WriteDWord(DWordToLE($00000002));
|
||||
AStream.WriteDWord(DWordToLE($00000003));
|
||||
AStream.WriteDWord(DWordToLE($00000004));
|
||||
|
||||
AStream.WriteDWord(DWordToLE($00000005));
|
||||
AStream.WriteDWord(DWordToLE($00000006));
|
||||
AStream.WriteDWord(DWordToLE($00000007));
|
||||
AStream.WriteDWord(DWordToLE($00000008));
|
||||
|
||||
AStream.WriteDWord(DWordToLE($00000009));
|
||||
AStream.WriteDWord(DWordToLE($0000000A));
|
||||
AStream.WriteDWord(DWordToLE($0000000B));
|
||||
AStream.WriteDWord(DWordToLE($0000000C));
|
||||
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFE));
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFF));
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFF));
|
||||
AStream.WriteDWord(DWordToLE($FFFFFFFF));
|
||||
|
||||
for i := 1 to ($A00 - $840) do AStream.WriteByte($FF);
|
||||
end;
|
||||
|
||||
constructor TOLEStorage.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
@ -198,11 +412,25 @@ procedure TOLEStorage.WriteOLEFile(AFileName: string; AOLEDocument: TOLEDocument
|
||||
var
|
||||
cbWritten: Cardinal;
|
||||
AFileStream: TFileStream;
|
||||
i: Cardinal;
|
||||
i, x: Cardinal;
|
||||
begin
|
||||
{ Fill information for helper routines }
|
||||
FOLEDocument := AOLEDocument;
|
||||
FNumSectors := Length(AOLEDocument.Sections);
|
||||
FNumStreams := Length(AOLEDocument.Streams);
|
||||
|
||||
{ Calculate the number of sectors necessary for each stream }
|
||||
SetLength(FOLEDocument.StreamsNumSectors, FNumStreams);
|
||||
|
||||
FNumStreamSectors := 0;
|
||||
|
||||
for i := 0 to FNumStreams - 1 do
|
||||
begin
|
||||
x := Ceil(AOLEDocument.Streams[i].Size / INT_OLE_SECTOR_SIZE);
|
||||
FOLEDocument.StreamsNumSectors[i] := x;
|
||||
FNumStreamSectors := FNumStreamSectors + x;
|
||||
end;
|
||||
|
||||
FNumSATSectors := 1; // Ceil(FNumStreamSectors / INT_OLE_SECTOR_DWORD_SIZE);
|
||||
|
||||
{$ifdef FPOLESTORAGE_USE_COM}
|
||||
{ Initialize the Component Object Model (COM) before calling s functions }
|
||||
@ -213,7 +441,7 @@ begin
|
||||
STGM_READWRITE or STGM_FAILIFTHERE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT,
|
||||
0, FStorage));
|
||||
|
||||
for i := 0 to FNumSectors do
|
||||
for i := 0 to FNumStreams - 1 do
|
||||
begin
|
||||
{ Create a workbook stream in the storage. A BIFF5 file must
|
||||
have at least a workbook stream. This stream *must* be named 'Book' }
|
||||
@ -221,13 +449,27 @@ begin
|
||||
STGM_READWRITE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT, 0, 0, FStream));
|
||||
|
||||
{ Write all data }
|
||||
FStream.Write(FOLEDocument.Sections[i].Memory,
|
||||
FOLEDocument.Sections[i].Size, @cbWritten);
|
||||
FStream.Write(FOLEDocument.Streams[i].Memory,
|
||||
FOLEDocument.Streams[i].Size, @cbWritten);
|
||||
end;
|
||||
{$else}
|
||||
AFileStream := TFileStream.Create(AFileName, fmOpenWrite or fmCreate);
|
||||
try
|
||||
// Header
|
||||
WriteOLEHeader(AFileStream);
|
||||
|
||||
// Record 0, the SAT
|
||||
WriteSectorAllocationTable(AFileStream);
|
||||
|
||||
// Records 1 and 2, the directory stream
|
||||
WriteDirectoryStream(AFileStream);
|
||||
WriteDirectoryStream(AFileStream);
|
||||
|
||||
// Record 3, the Short SAT
|
||||
WriteShortSectorAllocationTable(AFileStream);
|
||||
|
||||
// Records 4 and on, the user data
|
||||
AFileStream.CopyFrom(FOLEDocument.Streams[0]);
|
||||
finally
|
||||
AFileStream.Free;
|
||||
end;
|
||||
|
@ -214,15 +214,15 @@ begin
|
||||
try
|
||||
WriteToStream(MemStream, AData);
|
||||
|
||||
SetLength(OLEDocument.Sections, 1);
|
||||
OLEDocument.Sections[0] := MemStream;
|
||||
SetLength(OLEDocument.Streams, 1);
|
||||
OLEDocument.Streams[0] := MemStream;
|
||||
|
||||
OutputStorage.WriteOLEFile(AFileName, OLEDocument);
|
||||
finally
|
||||
MemStream.Free;
|
||||
OutputStorage.Free;
|
||||
|
||||
SetLength(OLEDocument.Sections, 0);
|
||||
SetLength(OLEDocument.Streams, 0);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user