home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 October / Chip_2002-10_cd1.bin / zkuste / delphi / kolekce / d56 / FLEXCEL.ZIP / XLSAdapter / USST.pas < prev    next >
Pascal/Delphi Source File  |  2002-07-01  |  10KB  |  413 lines

  1. unit USST;
  2.  
  3. interface
  4. uses UXlsBaseRecordLists, UXlsBaseRecords, UXlsOtherRecords, XLSMessages, sysutils,
  5.      contnrs, classes, UXlsStrings, UXlsBaseList;
  6. type
  7.   TSST=class;
  8.  
  9.   TSSTEntry   = class
  10.   private
  11.     Refs: integer;
  12.     Value: TExcelString;
  13.  
  14.     AbsStreamPos: Cardinal;
  15.     RecordStreamPos: Word;
  16.   public
  17.     PosInTable:Cardinal;
  18.  
  19.     function TotalSize: int64;
  20.     procedure AddRef;
  21.     procedure ReleaseRef;
  22.     constructor Create(const s: TExcelString); overload;
  23.     constructor Create(const s: Widestring); overload;
  24.     constructor CreateAndAddRef(const s: TExcelString; dummy : integer = 0);overload;  //Dummy parameter is for not having C++ warning
  25.     constructor CreateAndAddRef(const s: WideString; dummy : integer = 0);overload;
  26.     destructor Destroy;override;
  27.  
  28.     procedure SaveToStream(const DataStream: TStream; const BeginRecordPos: Cardinal);
  29.   end;
  30.  
  31.   TLabelSSTRecord= class(TCellRecord)
  32.   private
  33.     pSSTEntry: TSSTEntry;
  34.     SST: TSST;
  35.     function GetAsString: WideString;
  36.     procedure SetAsString(const Value: WideString);
  37.   protected
  38.     function GetValue: Variant; override;
  39.     procedure SetValue(const Value: Variant); override;
  40.     function DoCopyTo: TBaseRecord; override;
  41.   public
  42.     constructor  Create(const aId: word; const aData: PArrayOfByte; const aDataSize: integer);override;
  43.     constructor CreateFromData(const aRow, aCol, aXF: word; const aSST: TSST);
  44.  
  45.     procedure AttachToSST(const aSST: TSST);
  46.     procedure SaveToStream(const Workbook: TStream); override;
  47.  
  48.     destructor Destroy;override;
  49.  
  50.     property AsString: WideString read GetAsString write SetAsString;
  51.   end;
  52.  
  53.  
  54.  
  55.   TSST = class (TBaseList)
  56.     {$INCLUDE inc\TSSTHdr.inc}
  57.     function Find(const s:TExcelString; var Index: integer): boolean;
  58.     procedure Load(const aSSTRecord: TSSTRecord);
  59.     procedure SaveToStream(const DataStream: TStream);
  60.     procedure WriteExtSST(const DataStream: TStream);
  61.     function AddString(const s:Widestring):integer;
  62.     procedure Sort;
  63.     function TotalSize: int64;
  64.     function SSTRecordSize: int64;
  65.     function ExtSSTRecordSize: int64;
  66.     procedure FixRefs;
  67.   private
  68.     procedure CalcNextContinue(const First: integer; var Last: integer;
  69.       var RecordSize: word);
  70.   end;
  71.  
  72. implementation
  73.  
  74. { TSSTEntry }
  75.  
  76. procedure TSSTEntry.AddRef;
  77. begin
  78.   inc(Refs);
  79. end;
  80.  
  81. constructor TSSTEntry.Create(const s: TExcelString);
  82. begin
  83.   inherited Create;
  84.   Value:= s;    //Last statment
  85. end;
  86.  
  87. constructor TSSTEntry.Create(const s: Widestring);
  88. begin
  89.   inherited Create;
  90.   Value:= TExcelString.Create(2,s);
  91. end;
  92.  
  93. constructor TSSTEntry.CreateAndAddRef(const s: TExcelString; dummy : integer = 0);
  94. begin
  95.   Create(s);
  96.   AddRef;
  97. end;
  98.  
  99. constructor TSSTEntry.CreateAndAddRef(const s: WideString; dummy : integer = 0);
  100. begin
  101.   Create(s);
  102.   AddRef;
  103. end;
  104.  
  105. destructor TSSTEntry.Destroy;
  106. begin
  107.   FreeAndNil(Value);
  108.   inherited;
  109. end;
  110.  
  111. procedure TSSTEntry.ReleaseRef;
  112. begin
  113.   dec(Refs);
  114. end;
  115.  
  116. procedure TSSTEntry.SaveToStream(const DataStream: TStream; const BeginRecordPos: Cardinal);
  117. begin
  118.   AbsStreamPos:=DataStream.Position;
  119.   RecordStreamPos:= AbsStreamPos- BeginRecordPos;
  120.   Value.SaveToStream(DataStream);
  121. end;
  122.  
  123. function TSSTEntry.TotalSize: int64;
  124. begin
  125.   Result:=Value.TotalSize;
  126. end;
  127.  
  128. function CompareSSTEntries(Item1, Item2: Pointer): Integer;
  129. begin
  130.   CompareSSTEntries:= TSSTEntry(Item1).Value.Compare(TSSTEntry(Item2).Value);
  131. end;
  132.  
  133.  
  134. { TSST }
  135. {$INCLUDE inc\TSSTImp.inc}
  136.  
  137. function TSST.AddString(const s: Widestring): integer;
  138. var
  139.   es: TExcelString;
  140. begin
  141.   es:= TExcelString.Create(2,s);
  142.   try
  143.     if Find(es, Result) then Items[Result].AddRef else
  144.     begin
  145.       Insert(Result, TSSTEntry.CreateAndAddRef(es));
  146.       es:=nil;  //so we dont free it
  147.     end;
  148.   finally
  149.     FreeAndNil(es);
  150.   end;
  151. end;
  152.  
  153. function TSST.Find(const S: TExcelString; var Index: Integer): Boolean;
  154. var
  155.   L, H, I, C: Integer;
  156. begin
  157.   Result := False;
  158.   L := 0;
  159.   H := Count - 1;
  160.   while L <= H do
  161.   begin
  162.     I := (L + H) shr 1;
  163.     C := Items[I].Value.Compare(S);
  164.     if C < 0 then L := I + 1 else
  165.     begin
  166.       H := I - 1;
  167.       if C = 0 then
  168.       begin
  169.         Result := True;
  170.         L := I;
  171.       end;
  172.     end;
  173.   end;
  174.   Index := L;
  175. end;
  176.  
  177. procedure TSST.Load(const aSSTRecord: TSSTRecord);
  178. var
  179.   i, Ofs:integer;
  180.   Es: TExcelString;
  181.   TmpSSTRecord: TBaseRecord;
  182. begin
  183.   Ofs:=8;
  184.   TmpSSTRecord:= aSSTRecord;
  185.   for i:=0 to aSSTRecord.Count-1 do
  186.   begin
  187.     Es:= TExcelString.Create(2, TmpSSTRecord, Ofs);
  188.     try
  189.       Add(TSSTEntry.Create(Es));
  190.       Es:=nil;
  191.     finally
  192.       FreeAndNil(Es);
  193.     end; //Finally
  194.   end;
  195.   //We can't sort now, this should be done after all the LABELSST records have been loaded
  196. end;
  197.  
  198. procedure TSST.FixRefs;
  199. var
  200.   i: integer;
  201. begin
  202.   for i:=count-1 downto 0 do
  203.     if Items[i].Refs<=0 then Delete(i);
  204. end;
  205.  
  206. procedure TSST.SaveToStream(const DataStream: TStream);
  207. var
  208.   i:integer;
  209.   TotalRefs, aCount: Cardinal;
  210.   RecordHeader: TRecordHeader;
  211.   BeginRecordPos: Cardinal;
  212.   First, Last: integer;
  213. begin
  214.   BeginRecordPos:=DataStream.Position;
  215.   RecordHeader.Id:= xlr_SST;
  216.  
  217.   //Renum the items
  218.   i:=0; TotalRefs:=0;
  219.   while i< Count do
  220.   begin
  221.     Assert(Items[i].Refs>0,'Refs should be >0');
  222.     Items[i].PosInTable:=i;
  223.     TotalRefs:=TotalRefs+Cardinal(Items[i].Refs);
  224.     inc(i);
  225.    end;
  226.  
  227.  
  228.   First:=0;
  229.   RecordHeader.Size:=8;
  230.   CalcNextContinue(First, Last, RecordHeader.Size);
  231.  
  232.   DataStream.Write(RecordHeader, SizeOf(RecordHeader));
  233.   DataStream.Write(TotalRefs, SizeOf(TotalRefs));
  234.   aCount:=Count;
  235.   DataStream.Write(aCount, Sizeof(aCount));
  236.  
  237.   while First<Count do
  238.   begin
  239.     for i:= First to Last-1 do
  240.     begin
  241.       Items[i].SaveToStream(DataStream, BeginRecordPos);
  242.     end;
  243.  
  244.     //Write continue
  245.     First:=Last;
  246.     if First<Count then
  247.     begin
  248.       BeginRecordPos:= DataStream.Position;
  249.       RecordHeader.Id:= xlr_CONTINUE;
  250.       RecordHeader.Size:=0;
  251.       CalcNextContinue(First, Last, RecordHeader.Size);
  252.       DataStream.Write(RecordHeader, SizeOf(RecordHeader));
  253.     end;
  254.   end;
  255.  
  256.   WriteExtSST(DataStream);
  257. end;
  258.  
  259. procedure TSST.WriteExtSST(const DataStream: TStream);
  260. var
  261.   n, nBuckets, Dummy: Word;
  262.   i: integer;
  263.   RecordHeader: TRecordHeader;
  264. begin
  265.   // Calc number of strings per hash bucket
  266.   n:=Count div 128+1;
  267.   if n<8 then n:=8;
  268.  
  269.   if Count=0 then nBuckets:=0 else nBuckets:= (Count-1) div n + 1;
  270.  
  271.   RecordHeader.Id:= xlr_EXTSST;
  272.   RecordHeader.Size:= 2+8*nBuckets;
  273.   DataStream.Write(RecordHeader, SizeOf(RecordHeader));
  274.   DataStream.Write(n, SizeOf(n));
  275.   i:= 0; Dummy:=0;
  276.   while i<Count do
  277.   begin
  278.     DataStream.Write(Items[i].AbsStreamPos, SizeOf(Items[i].AbsStreamPos));
  279.     DataStream.Write(Items[i].RecordStreamPos, SizeOf(Items[i].RecordStreamPos));
  280.     DataStream.Write(Dummy, SizeOf(Dummy));
  281.     inc(i,n);
  282.   end;
  283.  
  284. end;
  285.  
  286. procedure TSST.Sort;
  287. begin
  288.   inherited Sort(CompareSSTEntries)
  289. end;
  290.  
  291. function TSST.ExtSSTRecordSize: int64;
  292. var
  293.   n, nBuckets: word;
  294. begin
  295.   n:=Count div 128+1;
  296.   if n<8 then n:=8;
  297.  
  298.   if Count=0 then nBuckets:=0 else nBuckets:= (Count-1) div n + 1;
  299.   Result:= 2+8*nBuckets;
  300. end;
  301.  
  302. function TSST.SSTRecordSize: int64;
  303. //Has to handle continue records
  304. var
  305.   First, Last: integer;
  306.   Rs: Word;
  307. begin
  308.   Result:=8;
  309.   Rs:=0;
  310.   First:=0;
  311.   while First<Count do
  312.   begin
  313.     CalcNextContinue(First,Last, Rs);
  314.     First:=Last;
  315.     Result:=Result+Rs;
  316.     if Last< Count then Result:=Result+SizeOf(TRecordHeader);
  317.     Rs:=0;
  318.   end;
  319. end;
  320.  
  321.  
  322. function TSST.TotalSize: int64;
  323. begin
  324.   Result:= SSTRecordSize + ExtSSTRecordSize + 2* SizeOf(TRecordHeader);
  325. end;
  326.  
  327. procedure TSST.CalcNextContinue(const First: integer; var Last: integer; var RecordSize: word);
  328. var
  329.  RSize: integer;
  330. begin
  331.   Last:=First;
  332.   if Last<Count then RSize:=Items[Last].TotalSize else RSize:=0;
  333.   while (Last<Count) and (RecordSize+ RSize< MaxRecordDataSize) do
  334.   begin
  335.     inc(RecordSize, RSize);
  336.     inc(Last);
  337.     if Last<Count then RSize:=Items[Last].TotalSize;
  338.   end;
  339.   if (First=Last) and (Last<Count) then raise Exception.Create(ErrStringTooLarge);
  340. end;
  341.  
  342. { TLabelSSTRecord }
  343.  
  344. constructor TLabelSSTRecord.Create(const aId: word;
  345.   const aData: PArrayOfByte; const aDataSize: integer);
  346. begin
  347.   inherited Create(aId, aData, aDataSize);
  348. end;
  349.  
  350. procedure TLabelSSTRecord.AttachToSST(const aSST: TSST);
  351. var
  352.   a:int64;
  353. begin
  354.   SST:=aSST;
  355.   a:=GetCardinal(Data,6);
  356.   if a> SST.Count then raise Exception.Create(ErrExcelInvalid);
  357.   pSSTEntry:= SST[a];
  358.   pSSTEntry.AddRef;
  359. end;
  360.  
  361. destructor TLabelSSTRecord.Destroy;
  362. begin
  363.   if pSSTEntry<>nil then pSSTEntry.ReleaseRef;
  364.   inherited;
  365. end;
  366.  
  367. procedure TLabelSSTRecord.SaveToStream(const Workbook: TStream);
  368. begin
  369.   SetCardinal(Data, 6, pSSTEntry.PosInTable);
  370.   inherited;
  371. end;
  372.  
  373. function TLabelSSTRecord.DoCopyTo: TBaseRecord;
  374. begin
  375.   Result:= inherited DoCopyTo;
  376.   (Result as TLabelSSTRecord).SST:= SST;
  377.   (Result as TLabelSSTRecord).pSSTEntry:= pSSTEntry;
  378.   (Result as TLabelSSTRecord).pSSTEntry.AddRef;
  379.  
  380. end;
  381.  
  382. function TLabelSSTRecord.GetValue: Variant;
  383. begin
  384.   Result:=GetAsString;
  385. end;
  386.  
  387. procedure TLabelSSTRecord.SetValue(const Value: Variant);
  388. begin
  389.   SetAsString(Value);
  390. end;
  391.  
  392. function TLabelSSTRecord.GetAsString: WideString;
  393. begin
  394.   Result:=pSSTEntry.Value.Value;
  395. end;
  396.  
  397. procedure TLabelSSTRecord.SetAsString(const Value: WideString);
  398. var
  399.   OldpSSTEntry: TSSTEntry;
  400. begin
  401.   OldpSSTEntry:=pSSTEntry;
  402.   pSSTEntry:= SST[SST.AddString(Value)];
  403.   if OldpSSTEntry<>nil then OldpSSTEntry.ReleaseRef;
  404. end;
  405.  
  406. constructor TLabelSSTRecord.CreateFromData(const aRow, aCol, aXF: word; const aSST: TSST);
  407. begin
  408.   inherited CreateFromData(xlr_LABELSST, 10, aRow, aCol, aXF);
  409.   SST:=aSST;
  410. end;
  411.  
  412. end.
  413.