You've already forked lazarus-ccr
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:
@@ -38,7 +38,7 @@
|
|||||||
<CursorPos X="16" Y="16"/>
|
<CursorPos X="16" Y="16"/>
|
||||||
<TopLine Value="1"/>
|
<TopLine Value="1"/>
|
||||||
<EditorIndex Value="0"/>
|
<EditorIndex Value="0"/>
|
||||||
<UsageCount Value="51"/>
|
<UsageCount Value="96"/>
|
||||||
<Loaded Value="True"/>
|
<Loaded Value="True"/>
|
||||||
</Unit0>
|
</Unit0>
|
||||||
<Unit1>
|
<Unit1>
|
||||||
@@ -46,61 +46,61 @@
|
|||||||
<UnitName Value="fpspreadsheet"/>
|
<UnitName Value="fpspreadsheet"/>
|
||||||
<CursorPos X="32" Y="414"/>
|
<CursorPos X="32" Y="414"/>
|
||||||
<TopLine Value="388"/>
|
<TopLine Value="388"/>
|
||||||
<UsageCount Value="25"/>
|
<UsageCount Value="20"/>
|
||||||
</Unit1>
|
</Unit1>
|
||||||
<Unit2>
|
<Unit2>
|
||||||
<Filename Value="..\xlsbiff5.pas"/>
|
<Filename Value="..\xlsbiff5.pas"/>
|
||||||
<UnitName Value="xlsbiff5"/>
|
<UnitName Value="xlsbiff5"/>
|
||||||
<CursorPos X="16" Y="320"/>
|
<CursorPos X="16" Y="320"/>
|
||||||
<TopLine Value="300"/>
|
<TopLine Value="300"/>
|
||||||
<UsageCount Value="25"/>
|
<UsageCount Value="20"/>
|
||||||
</Unit2>
|
</Unit2>
|
||||||
<Unit3>
|
<Unit3>
|
||||||
<Filename Value="..\..\..\..\..\FPC220\source\packages\base\winunits\activex.pp"/>
|
<Filename Value="..\..\..\..\..\FPC220\source\packages\base\winunits\activex.pp"/>
|
||||||
<UnitName Value="ActiveX"/>
|
<UnitName Value="ActiveX"/>
|
||||||
<CursorPos X="27" Y="29"/>
|
<CursorPos X="27" Y="29"/>
|
||||||
<TopLine Value="6"/>
|
<TopLine Value="6"/>
|
||||||
<UsageCount Value="9"/>
|
<UsageCount Value="4"/>
|
||||||
</Unit3>
|
</Unit3>
|
||||||
<Unit4>
|
<Unit4>
|
||||||
<Filename Value="..\fpolestorage.pas"/>
|
<Filename Value="..\fpolestorage.pas"/>
|
||||||
<UnitName Value="fpolestorage"/>
|
<UnitName Value="fpolestorage"/>
|
||||||
<CursorPos X="1" Y="1"/>
|
<CursorPos X="1" Y="1"/>
|
||||||
<TopLine Value="1"/>
|
<TopLine Value="1"/>
|
||||||
<UsageCount Value="45"/>
|
<UsageCount Value="40"/>
|
||||||
</Unit4>
|
</Unit4>
|
||||||
<Unit5>
|
<Unit5>
|
||||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\inc\objpash.inc"/>
|
<Filename Value="..\..\..\..\..\FPC220\source\rtl\inc\objpash.inc"/>
|
||||||
<CursorPos X="21" Y="141"/>
|
<CursorPos X="21" Y="141"/>
|
||||||
<TopLine Value="131"/>
|
<TopLine Value="131"/>
|
||||||
<UsageCount Value="9"/>
|
<UsageCount Value="4"/>
|
||||||
</Unit5>
|
</Unit5>
|
||||||
<Unit6>
|
<Unit6>
|
||||||
<Filename Value="..\xlsbiff2.pas"/>
|
<Filename Value="..\xlsbiff2.pas"/>
|
||||||
<UnitName Value="xlsbiff2"/>
|
<UnitName Value="xlsbiff2"/>
|
||||||
<CursorPos X="20" Y="277"/>
|
<CursorPos X="20" Y="277"/>
|
||||||
<TopLine Value="260"/>
|
<TopLine Value="260"/>
|
||||||
<UsageCount Value="18"/>
|
<UsageCount Value="13"/>
|
||||||
</Unit6>
|
</Unit6>
|
||||||
<Unit7>
|
<Unit7>
|
||||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\classes\classesh.inc"/>
|
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\classes\classesh.inc"/>
|
||||||
<CursorPos X="22" Y="1602"/>
|
<CursorPos X="22" Y="1602"/>
|
||||||
<TopLine Value="1598"/>
|
<TopLine Value="1598"/>
|
||||||
<UsageCount Value="11"/>
|
<UsageCount Value="6"/>
|
||||||
</Unit7>
|
</Unit7>
|
||||||
<Unit8>
|
<Unit8>
|
||||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\win32\buildrtl.pp"/>
|
<Filename Value="..\..\..\..\..\FPC220\source\rtl\win32\buildrtl.pp"/>
|
||||||
<UnitName Value="buildrtl"/>
|
<UnitName Value="buildrtl"/>
|
||||||
<CursorPos X="29" Y="5"/>
|
<CursorPos X="29" Y="5"/>
|
||||||
<TopLine Value="1"/>
|
<TopLine Value="1"/>
|
||||||
<UsageCount Value="9"/>
|
<UsageCount Value="4"/>
|
||||||
</Unit8>
|
</Unit8>
|
||||||
<Unit9>
|
<Unit9>
|
||||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\fgl.pp"/>
|
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\fgl.pp"/>
|
||||||
<UnitName Value="fgl"/>
|
<UnitName Value="fgl"/>
|
||||||
<CursorPos X="15" Y="86"/>
|
<CursorPos X="15" Y="86"/>
|
||||||
<TopLine Value="55"/>
|
<TopLine Value="55"/>
|
||||||
<UsageCount Value="18"/>
|
<UsageCount Value="13"/>
|
||||||
</Unit9>
|
</Unit9>
|
||||||
<Unit10>
|
<Unit10>
|
||||||
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
<CursorPos X="11" Y="737"/>
|
<CursorPos X="11" Y="737"/>
|
||||||
<TopLine Value="713"/>
|
<TopLine Value="713"/>
|
||||||
<EditorIndex Value="6"/>
|
<EditorIndex Value="6"/>
|
||||||
<UsageCount Value="15"/>
|
<UsageCount Value="37"/>
|
||||||
<Loaded Value="True"/>
|
<Loaded Value="True"/>
|
||||||
</Unit10>
|
</Unit10>
|
||||||
<Unit11>
|
<Unit11>
|
||||||
@@ -116,14 +116,14 @@
|
|||||||
<UnitName Value="Win32WSControls"/>
|
<UnitName Value="Win32WSControls"/>
|
||||||
<CursorPos X="13" Y="206"/>
|
<CursorPos X="13" Y="206"/>
|
||||||
<TopLine Value="199"/>
|
<TopLine Value="199"/>
|
||||||
<UsageCount Value="12"/>
|
<UsageCount Value="7"/>
|
||||||
</Unit11>
|
</Unit11>
|
||||||
<Unit12>
|
<Unit12>
|
||||||
<Filename Value="..\..\..\..\..\lazarus\components\sqlite\registersqlite3.pas"/>
|
<Filename Value="..\..\..\..\..\lazarus\components\sqlite\registersqlite3.pas"/>
|
||||||
<UnitName Value="registersqlite3"/>
|
<UnitName Value="registersqlite3"/>
|
||||||
<CursorPos X="15" Y="5"/>
|
<CursorPos X="15" Y="5"/>
|
||||||
<TopLine Value="1"/>
|
<TopLine Value="1"/>
|
||||||
<UsageCount Value="11"/>
|
<UsageCount Value="6"/>
|
||||||
</Unit12>
|
</Unit12>
|
||||||
<Unit13>
|
<Unit13>
|
||||||
<Filename Value="..\..\..\..\..\lazarus\ideintf\componenteditors.pas"/>
|
<Filename Value="..\..\..\..\..\lazarus\ideintf\componenteditors.pas"/>
|
||||||
@@ -131,22 +131,22 @@
|
|||||||
<CursorPos X="54" Y="353"/>
|
<CursorPos X="54" Y="353"/>
|
||||||
<TopLine Value="330"/>
|
<TopLine Value="330"/>
|
||||||
<EditorIndex Value="5"/>
|
<EditorIndex Value="5"/>
|
||||||
<UsageCount Value="13"/>
|
<UsageCount Value="35"/>
|
||||||
<Loaded Value="True"/>
|
<Loaded Value="True"/>
|
||||||
</Unit13>
|
</Unit13>
|
||||||
<Unit14>
|
<Unit14>
|
||||||
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\classes\cregist.inc"/>
|
<Filename Value="..\..\..\..\..\FPC220\source\rtl\objpas\classes\cregist.inc"/>
|
||||||
<CursorPos X="17" Y="124"/>
|
<CursorPos X="17" Y="124"/>
|
||||||
<TopLine Value="121"/>
|
<TopLine Value="121"/>
|
||||||
<UsageCount Value="11"/>
|
<UsageCount Value="6"/>
|
||||||
</Unit14>
|
</Unit14>
|
||||||
<Unit15>
|
<Unit15>
|
||||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||||
<UnitName Value="xlsbiff5"/>
|
<UnitName Value="xlsbiff5"/>
|
||||||
<CursorPos X="41" Y="218"/>
|
<CursorPos X="28" Y="62"/>
|
||||||
<TopLine Value="209"/>
|
<TopLine Value="59"/>
|
||||||
<EditorIndex Value="2"/>
|
<EditorIndex Value="2"/>
|
||||||
<UsageCount Value="11"/>
|
<UsageCount Value="33"/>
|
||||||
<Loaded Value="True"/>
|
<Loaded Value="True"/>
|
||||||
</Unit15>
|
</Unit15>
|
||||||
<Unit16>
|
<Unit16>
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
<CursorPos X="1" Y="49"/>
|
<CursorPos X="1" Y="49"/>
|
||||||
<TopLine Value="30"/>
|
<TopLine Value="30"/>
|
||||||
<EditorIndex Value="1"/>
|
<EditorIndex Value="1"/>
|
||||||
<UsageCount Value="11"/>
|
<UsageCount Value="33"/>
|
||||||
<Loaded Value="True"/>
|
<Loaded Value="True"/>
|
||||||
</Unit16>
|
</Unit16>
|
||||||
<Unit17>
|
<Unit17>
|
||||||
@@ -164,80 +164,140 @@
|
|||||||
<CursorPos X="1" Y="69"/>
|
<CursorPos X="1" Y="69"/>
|
||||||
<TopLine Value="57"/>
|
<TopLine Value="57"/>
|
||||||
<EditorIndex Value="3"/>
|
<EditorIndex Value="3"/>
|
||||||
<UsageCount Value="11"/>
|
<UsageCount Value="33"/>
|
||||||
<Loaded Value="True"/>
|
<Loaded Value="True"/>
|
||||||
</Unit17>
|
</Unit17>
|
||||||
<Unit18>
|
<Unit18>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<UnitName Value="fpolestorage"/>
|
<UnitName Value="fpolestorage"/>
|
||||||
<CursorPos X="33" Y="133"/>
|
<CursorPos X="1" Y="471"/>
|
||||||
<TopLine Value="121"/>
|
<TopLine Value="458"/>
|
||||||
<EditorIndex Value="4"/>
|
<EditorIndex Value="4"/>
|
||||||
<UsageCount Value="11"/>
|
<UsageCount Value="33"/>
|
||||||
<Loaded Value="True"/>
|
<Loaded Value="True"/>
|
||||||
</Unit18>
|
</Unit18>
|
||||||
</Units>
|
</Units>
|
||||||
<JumpHistory Count="15" HistoryIndex="14">
|
<JumpHistory Count="30" HistoryIndex="29">
|
||||||
<Position1>
|
<Position1>
|
||||||
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
||||||
<Caret Line="1" Column="1" TopLine="1"/>
|
<Caret Line="737" Column="11" TopLine="713"/>
|
||||||
</Position1>
|
</Position1>
|
||||||
<Position2>
|
<Position2>
|
||||||
<Filename Value="..\..\..\..\..\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/>
|
|
||||||
<Caret Line="737" Column="11" TopLine="713"/>
|
|
||||||
</Position2>
|
|
||||||
<Position3>
|
|
||||||
<Filename Value="..\..\..\..\..\lazarus\ideintf\componenteditors.pas"/>
|
<Filename Value="..\..\..\..\..\lazarus\ideintf\componenteditors.pas"/>
|
||||||
<Caret Line="353" Column="54" TopLine="330"/>
|
<Caret Line="353" Column="54" TopLine="330"/>
|
||||||
</Position3>
|
</Position2>
|
||||||
<Position4>
|
<Position3>
|
||||||
<Filename Value="excel5demo.lpr"/>
|
<Filename Value="excel5demo.lpr"/>
|
||||||
<Caret Line="49" Column="12" TopLine="30"/>
|
<Caret Line="49" Column="12" TopLine="30"/>
|
||||||
</Position4>
|
</Position3>
|
||||||
<Position5>
|
<Position4>
|
||||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||||
<Caret Line="365" Column="37" TopLine="354"/>
|
<Caret Line="365" Column="37" TopLine="354"/>
|
||||||
|
</Position4>
|
||||||
|
<Position5>
|
||||||
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
|
<Caret Line="38" Column="20" TopLine="21"/>
|
||||||
</Position5>
|
</Position5>
|
||||||
<Position6>
|
<Position6>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<Caret Line="38" Column="20" TopLine="21"/>
|
<Caret Line="60" Column="54" TopLine="49"/>
|
||||||
</Position6>
|
</Position6>
|
||||||
<Position7>
|
<Position7>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<Caret Line="60" Column="54" TopLine="49"/>
|
<Caret Line="44" Column="24" TopLine="32"/>
|
||||||
</Position7>
|
</Position7>
|
||||||
<Position8>
|
<Position8>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<Caret Line="44" Column="24" TopLine="32"/>
|
<Caret Line="51" Column="25" TopLine="34"/>
|
||||||
</Position8>
|
</Position8>
|
||||||
<Position9>
|
<Position9>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<Caret Line="51" Column="25" TopLine="34"/>
|
<Caret Line="157" Column="21" TopLine="151"/>
|
||||||
</Position9>
|
</Position9>
|
||||||
<Position10>
|
<Position10>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<Caret Line="157" Column="21" TopLine="151"/>
|
<Caret Line="155" Column="5" TopLine="136"/>
|
||||||
</Position10>
|
</Position10>
|
||||||
<Position11>
|
<Position11>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<Caret Line="155" Column="5" TopLine="136"/>
|
<Caret Line="65" Column="3" TopLine="58"/>
|
||||||
</Position11>
|
</Position11>
|
||||||
<Position12>
|
<Position12>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
<Caret Line="65" Column="3" TopLine="58"/>
|
<Caret Line="25" Column="11" TopLine="16"/>
|
||||||
</Position12>
|
</Position12>
|
||||||
<Position13>
|
<Position13>
|
||||||
<Filename Value="..\..\fpolestorage.pas"/>
|
|
||||||
<Caret Line="25" Column="11" TopLine="16"/>
|
|
||||||
</Position13>
|
|
||||||
<Position14>
|
|
||||||
<Filename Value="..\..\xlsbiff5.pas"/>
|
<Filename Value="..\..\xlsbiff5.pas"/>
|
||||||
<Caret Line="194" Column="15" TopLine="60"/>
|
<Caret Line="194" Column="15" TopLine="60"/>
|
||||||
</Position14>
|
</Position13>
|
||||||
<Position15>
|
<Position14>
|
||||||
<Filename Value="..\..\fpsutils.pas"/>
|
<Filename Value="..\..\fpsutils.pas"/>
|
||||||
<Caret Line="45" Column="5" TopLine="26"/>
|
<Caret Line="45" Column="5" TopLine="26"/>
|
||||||
|
</Position14>
|
||||||
|
<Position15>
|
||||||
|
<Filename Value="..\..\fpolestorage.pas"/>
|
||||||
|
<Caret Line="150" Column="5" TopLine="131"/>
|
||||||
</Position15>
|
</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>
|
</JumpHistory>
|
||||||
</ProjectOptions>
|
</ProjectOptions>
|
||||||
<CompilerOptions>
|
<CompilerOptions>
|
||||||
|
@@ -4,6 +4,29 @@ fpolestorage.pas
|
|||||||
Writes an OLE document
|
Writes an OLE document
|
||||||
|
|
||||||
AUTHORS: Felipe Monteiro de Carvalho
|
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;
|
unit fpolestorage;
|
||||||
|
|
||||||
@@ -21,7 +44,7 @@ uses
|
|||||||
{$ifdef FPOLESTORAGE_USE_COM}
|
{$ifdef FPOLESTORAGE_USE_COM}
|
||||||
ActiveX, ComObj,
|
ActiveX, ComObj,
|
||||||
{$endif}
|
{$endif}
|
||||||
Classes, SysUtils,
|
Classes, SysUtils, Math,
|
||||||
fpsutils;
|
fpsutils;
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -29,7 +52,11 @@ type
|
|||||||
{ Describes an OLE Document }
|
{ Describes an OLE Document }
|
||||||
|
|
||||||
TOLEDocument = record
|
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;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@@ -43,10 +70,15 @@ type
|
|||||||
{$endif}
|
{$endif}
|
||||||
{ Information filled by the write routines for the helper routines }
|
{ Information filled by the write routines for the helper routines }
|
||||||
FOLEDocument: TOLEDocument;
|
FOLEDocument: TOLEDocument;
|
||||||
FNumSectors: Cardinal;
|
FNumStreams, FNumSATSectors, FNumStreamSectors, FNumTotalSectors: Cardinal;
|
||||||
{ Helper routines }
|
{ Helper routines }
|
||||||
procedure WriteOLEHeader(AStream: TStream);
|
procedure WriteOLEHeader(AStream: TStream);
|
||||||
procedure WriteSectorAllocationTable(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
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@@ -55,6 +87,18 @@ type
|
|||||||
|
|
||||||
implementation
|
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 }
|
{ TOLEStorage }
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -111,7 +155,7 @@ begin
|
|||||||
AStream.WriteWord($0);
|
AStream.WriteWord($0);
|
||||||
|
|
||||||
{ 44 4 Total number of sectors used for the sector allocation table (➜5.2) }
|
{ 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) }
|
{ 48 4 SecID of first sector of the directory stream (➜7) }
|
||||||
AStream.WriteDWord(DWordToLE($01));
|
AStream.WriteDWord(DWordToLE($01));
|
||||||
@@ -151,37 +195,207 @@ begin
|
|||||||
{ Simple copy of an example OLE file
|
{ Simple copy of an example OLE file
|
||||||
|
|
||||||
00000200H FD FF FF FF FF FF FF FF FE FF FF FF 04 00 00 00
|
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
|
00000210H FE FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
|
||||||
00000220H 09 00 00 00 FE FF FF FF 0B 00 00 00 FE FF FF FF
|
|
||||||
|
|
||||||
And from now on only $FFFFFFFF covering $230 to $3FF
|
And from now on only $FFFFFFFF covering $220 to $3FF
|
||||||
for a total of $400 - $230 bytes of $FF }
|
for a total of $400 - $220 bytes of $FF }
|
||||||
|
|
||||||
AStream.WriteDWord(DWordToLE($FFFFFFFD));
|
AStream.WriteDWord(DWordToLE($FFFFFFFD));
|
||||||
AStream.WriteDWord($FFFFFFFF);
|
AStream.WriteDWord($FFFFFFFF);
|
||||||
AStream.WriteDWord(DWordToLE($FFFFFFFE));
|
AStream.WriteDWord(DWordToLE($FFFFFFFE));
|
||||||
AStream.WriteDWord(DWordToLE($00000004));
|
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(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:
|
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 ...
|
Array indexes 0 1 2 3 4 5 ...
|
||||||
SecID array –3 –1 –2 4 5 6 7 8 9 –2 11 –2 –1 ...
|
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). }
|
not used (special Free SecID with value –1). }
|
||||||
end;
|
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;
|
constructor TOLEStorage.Create;
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
@@ -198,11 +412,25 @@ procedure TOLEStorage.WriteOLEFile(AFileName: string; AOLEDocument: TOLEDocument
|
|||||||
var
|
var
|
||||||
cbWritten: Cardinal;
|
cbWritten: Cardinal;
|
||||||
AFileStream: TFileStream;
|
AFileStream: TFileStream;
|
||||||
i: Cardinal;
|
i, x: Cardinal;
|
||||||
begin
|
begin
|
||||||
{ Fill information for helper routines }
|
{ Fill information for helper routines }
|
||||||
FOLEDocument := AOLEDocument;
|
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}
|
{$ifdef FPOLESTORAGE_USE_COM}
|
||||||
{ Initialize the Component Object Model (COM) before calling s functions }
|
{ 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,
|
STGM_READWRITE or STGM_FAILIFTHERE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT,
|
||||||
0, FStorage));
|
0, FStorage));
|
||||||
|
|
||||||
for i := 0 to FNumSectors do
|
for i := 0 to FNumStreams - 1 do
|
||||||
begin
|
begin
|
||||||
{ Create a workbook stream in the storage. A BIFF5 file must
|
{ Create a workbook stream in the storage. A BIFF5 file must
|
||||||
have at least a workbook stream. This stream *must* be named 'Book' }
|
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));
|
STGM_READWRITE or STGM_SHARE_EXCLUSIVE or STGM_DIRECT, 0, 0, FStream));
|
||||||
|
|
||||||
{ Write all data }
|
{ Write all data }
|
||||||
FStream.Write(FOLEDocument.Sections[i].Memory,
|
FStream.Write(FOLEDocument.Streams[i].Memory,
|
||||||
FOLEDocument.Sections[i].Size, @cbWritten);
|
FOLEDocument.Streams[i].Size, @cbWritten);
|
||||||
end;
|
end;
|
||||||
{$else}
|
{$else}
|
||||||
AFileStream := TFileStream.Create(AFileName, fmOpenWrite or fmCreate);
|
AFileStream := TFileStream.Create(AFileName, fmOpenWrite or fmCreate);
|
||||||
try
|
try
|
||||||
|
// Header
|
||||||
WriteOLEHeader(AFileStream);
|
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
|
finally
|
||||||
AFileStream.Free;
|
AFileStream.Free;
|
||||||
end;
|
end;
|
||||||
|
@@ -214,15 +214,15 @@ begin
|
|||||||
try
|
try
|
||||||
WriteToStream(MemStream, AData);
|
WriteToStream(MemStream, AData);
|
||||||
|
|
||||||
SetLength(OLEDocument.Sections, 1);
|
SetLength(OLEDocument.Streams, 1);
|
||||||
OLEDocument.Sections[0] := MemStream;
|
OLEDocument.Streams[0] := MemStream;
|
||||||
|
|
||||||
OutputStorage.WriteOLEFile(AFileName, OLEDocument);
|
OutputStorage.WriteOLEFile(AFileName, OLEDocument);
|
||||||
finally
|
finally
|
||||||
MemStream.Free;
|
MemStream.Free;
|
||||||
OutputStorage.Free;
|
OutputStorage.Free;
|
||||||
|
|
||||||
SetLength(OLEDocument.Sections, 0);
|
SetLength(OLEDocument.Streams, 0);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user