source: CoolStreaming/VarBlockSerializer.pas

Last change on this file was 572, checked in by chronos, 5 months ago
File size: 29.0 KB
Line 
1unit VarBlockSerializer;
2
3// One level of recursive VarInt size supported
4// Biggest UInt type is QWord (64-bit)
5
6interface
7
8uses
9 Classes, DateUtils, StreamHelper, Math, SysUtils, SubStream, LazUTF8,
10 SpecializedList, LCLProc;
11
12const
13 BitAlignment = 8;
14
15type
16
17 { TVarBlockSerializer }
18
19 TVarBlockSerializer = class
20 private
21 FStream: TStream;
22 procedure SetStream(const AValue: TStream);
23 procedure TrimLeft;
24 function GetUnaryLengthMask(Length: Integer): Byte;
25 function DecodeUnaryLength(Data: Byte): Integer;
26 public
27 OwnsStream: Boolean;
28
29 // Base
30 procedure WriteVarUInt(Value: QWord);
31 function ReadVarUInt: QWord;
32 procedure WriteVarBlock(Block: TVarBlockSerializer);
33 procedure ReadVarBlock(Block: TVarBlockSerializer);
34 procedure WriteVarStream(AStream: TStream);
35 procedure ReadVarStream(AStream: TStream);
36 procedure WriteVarList(List: TListByte);
37 procedure ReadVarList(List: TListByte);
38 procedure WriteVarBuffer(var Buffer; Count: Integer);
39 procedure ReadVarBuffer(var Buffer; Count: Integer);
40 function GetVarSize: Integer;
41 function GetVarCount: Integer;
42 function TryVarBlock: Boolean;
43
44 // Advanced data types
45 procedure WriteVarSInt(Value: Int64);
46 function ReadVarSInt: Int64;
47 procedure WriteVarFloat(Value: Double; Base: Integer = 2);
48 function ReadVarFloat(Base: Integer = 2): Double;
49 procedure WriteVarString(Value: string);
50 function ReadVarString: string;
51 procedure WriteVarDouble(Value: Double);
52 function ReadVarDouble: Double;
53
54 // Misc methods
55 function TestMask(Mask: QWord; BitIndex: Byte): Boolean;
56 function BuildMask(Bits: array of Integer): Integer;
57 procedure ReadItemByMaskIndex(Index: Integer; Data: TVarBlockSerializer);
58 procedure ReadItemRefByMaskIndex(Index: Integer; Data: TSubStream);
59 procedure BlockEnclose;
60 procedure BlockUnclose;
61 procedure Assign(Source: TVarBlockSerializer);
62 constructor Create;
63 destructor Destroy; override;
64 property Stream: TStream read FStream write SetStream;
65 end;
66
67 { TVarBlockIndexed }
68
69 TVarBlockIndexed = class
70 private
71 public
72 Items: TListObject; // TListObject<TVarBlockSerializer>
73 Enclose: Boolean;
74 procedure CheckItem(Index: Integer);
75 procedure Assign(Source: TVarBlockIndexed);
76
77 // Base
78 procedure WriteVarUInt(Index: Integer; Value: QWord);
79 function ReadVarUInt(Index: Integer): QWord;
80 procedure WriteVarBlock(Index: Integer; Block: TVarBlockSerializer);
81 procedure ReadVarBlock(Index: Integer; Block: TVarBlockSerializer);
82 procedure WriteVarStream(Index: Integer; Stream: TStream);
83 procedure ReadVarStream(Index: Integer; Stream: TStream);
84 procedure WriteVarList(Index: Integer; List: TListByte);
85 procedure ReadVarList(Index: Integer; List: TListByte);
86 procedure WriteVarIndexedBlock(Index: Integer; Block: TVarBlockIndexed);
87 procedure ReadVarIndexedBlock(Index: Integer; Block: TVarBlockIndexed);
88 procedure WriteVarBuffer(Index: Integer; var Buffer; Count: Integer);
89 procedure ReadVarBuffer(Index: Integer; var Buffer; Count: Integer);
90
91 // Advanced data types
92 procedure WriteVarSInt(Index: Integer; Value: Int64);
93 function ReadVarSInt(Index: Integer): Int64;
94 procedure WriteVarFloat(Index: Integer; Value: Double; Base: Integer = 2);
95 function ReadVarFloat(Index: Integer; Base: Integer = 2): Double;
96 procedure WriteVarDouble(Index: Integer; Value: Double);
97 function ReadVarDouble(Index: Integer): Double;
98 procedure WriteVarString(Index: Integer; Value: string);
99 function ReadVarString(Index: Integer): string;
100 procedure WriteVarUIntArray(Index: Integer; List: TListInteger);
101 procedure ReadVarUIntArray(Index: Integer; List: TListInteger);
102 procedure WriteVarStringArray(Index: Integer; List: TListString);
103 procedure ReadVarStringArray(Index: Integer; List: TListString);
104
105 procedure Clear;
106 function TestIndex(Index: Integer): Boolean;
107 procedure WriteToVarBlock(VarBlock: TVarBlockSerializer);
108 procedure ReadFromVarBlock(VarBlock: TVarBlockSerializer);
109 procedure WriteToStream(Stream: TStream);
110 procedure ReadFromStream(Stream: TStream);
111 procedure WriteToList(List: TListByte);
112 procedure ReadFromList(List: TListByte);
113 constructor Create;
114 destructor Destroy; override;
115 end;
116
117
118implementation
119
120resourcestring
121 SMaskedValueReadError = 'Error reading masked variable length block.';
122 SUInt64Overflow = '64-bit UInt read overflow.';
123 SReadError = 'Stream read error. Expected length %d, read %d. Source stream size %d.';
124 SErrorGetVarSize = 'Error reading variable block size';
125
126{ TVarBlockSerializer }
127
128procedure TVarBlockSerializer.TrimLeft;
129var
130 Temp: TVarBlockSerializer;
131 Length: Integer;
132 Data: Byte;
133 StreamHelper: TStreamHelper;
134begin
135 try
136 Temp := TVarBlockSerializer.Create;
137 Stream.Position := 0;
138 Length := Stream.Size * 8;
139 Data := 0;
140 while (Length > 0) and
141 (((Data shr (Length and 7)) and 1) = 0) do begin
142 Data := Stream.ReadByte;
143 Dec(Length); // set 7. bit in byte
144 while (((Data shr (Length and 7)) and 1) = 0) and ((Length and 7) > 0) do
145 Dec(Length);
146 end;
147 Inc(Length);
148 Length := Ceil(Length / 8);
149 Stream.Position := Stream.Size - Length;
150 StreamHelper := TStreamHelper.Create(Stream);
151 StreamHelper.ReadStream(Temp.Stream, Length);
152 Temp.Stream.Size := 0;
153 Stream.Position := 0;
154 StreamHelper.WriteStream(Temp.Stream, Temp.Stream.Size);
155 finally
156 StreamHelper.Free;
157 Temp.Free;
158 end;
159end;
160
161procedure TVarBlockSerializer.SetStream(const AValue: TStream);
162begin
163 if OwnsStream and Assigned(FStream) then
164 FStream.Free;
165 OwnsStream := False;
166 FStream := AValue;
167end;
168
169function TVarBlockSerializer.GetUnaryLengthMask(Length: Integer): Byte;
170begin
171 Result := ((1 shl (BitAlignment - Length)) - 1) xor $ff;
172end;
173
174function TVarBlockSerializer.DecodeUnaryLength(Data:Byte):Integer;
175begin
176 Result := 1;
177 while (((Data shr (BitAlignment - Result)) and 1) = 1) and
178 (Result < (BitAlignment + 1)) do Inc(Result);
179end;
180
181procedure TVarBlockSerializer.WriteVarUInt(Value: QWord);
182var
183 Length: Byte;
184 Data: Byte;
185 I: Integer;
186 LengthMask: Byte;
187begin
188 // Get bit length
189 Length := SizeOf(QWord) * BitAlignment;
190 while ((Value and (QWord(1) shl (Length - 1))) = 0) and (Length > 0) do
191 Dec(Length);
192 Inc(Length);
193 Length := Ceil(Length / (BitAlignment - 1));
194 LengthMask := GetUnaryLengthMask(Length);
195
196 // Copy data
197 for I := Length downto 1 do begin
198 Data := (Value shr (BitAlignment * (I - 1))) and $ff;
199 if I = Length then Data := (Data and
200 (LengthMask xor $ff)) or ((LengthMask shl 1) and $ff);
201 Stream.WriteByte(Data);
202 end;
203end;
204
205function TVarBlockSerializer.ReadVarUInt: QWord;
206var
207 Data: Byte;
208 Length: Integer;
209 I: Integer;
210 LengthMask: Byte;
211begin
212 Result := 0;
213 Length := 1;
214 I := 0;
215 while I < Length do begin
216 Data := Stream.ReadByte;
217 if I = 0 then begin
218 if Data = $ff then begin
219 // Read recursive length
220 Length := ReadVarUInt;
221 if Length > BitAlignment then
222 raise Exception.Create(SUInt64Overflow);
223 if Length > 0 then Data := Stream.ReadByte else
224 Data := 0;
225 end else begin
226 Length := DecodeUnaryLength(Data);
227 LengthMask := GetUnaryLengthMask(Length);
228 Data := Data and (LengthMask xor $ff);
229 end;
230 end;
231 Result := Result or (QWord(Data) shl ((Length - I - 1) * BitAlignment));
232 Inc(I);
233 end;
234end;
235
236procedure TVarBlockSerializer.WriteVarBlock(Block: TVarBlockSerializer);
237begin
238 WriteVarStream(Block.Stream);
239end;
240
241procedure TVarBlockSerializer.ReadVarBlock(Block: TVarBlockSerializer);
242begin
243 ReadVarStream(Block.Stream);
244end;
245
246procedure TVarBlockSerializer.WriteVarFloat(Value: Double; Base: Integer = 2);
247var
248 Exponent: Integer;
249 Block: TVarBlockSerializer;
250begin
251 try
252 Block := TVarBlockSerializer.Create;
253
254 // Normalize to integer number with base 10 exponent
255 Exponent := 0;
256 if Value <> 0 then begin
257 if Frac(Value) > 0 then begin
258 while Frac(Value) > 0 do begin
259 Value := Value * Base;
260 Dec(Exponent);
261 end;
262 end else
263 while Frac(Value / Base) = 0 do begin
264 Value := Value / Base;
265 Inc(Exponent);
266 end;
267 end;
268 Block.WriteVarSInt(Trunc(Value));
269 Block.WriteVarSInt(Exponent);
270 WriteVarBlock(Block);
271 finally
272 Block.Free;
273 end;
274end;
275
276function TVarBlockSerializer.ReadVarFloat(Base: Integer = 2): Double;
277var
278 Significant: Int64;
279 Exponent: Integer;
280 Block: TVarBlockSerializer;
281begin
282 try
283 Block := TVarBlockSerializer.Create;
284 ReadVarBlock(Block);
285 Significant := Block.ReadVarSInt;
286 Exponent := Block.ReadVarSInt;
287 Result := Significant * IntPower(Base, Exponent);
288 finally
289 Block.Free;
290 end;
291end;
292
293procedure TVarBlockSerializer.WriteVarString(Value: string);
294var
295 Stream: TVarBlockSerializer;
296 I: Integer;
297 P: PChar;
298 Unicode: Cardinal;
299 CharLen: Integer;
300begin
301 try
302 Stream := TVarBlockSerializer.Create;
303 P := PChar(Value);
304 for I := 0 to UTF8Length(Value) - 1 do begin
305 Unicode := UTF8CharacterToUnicode(P, CharLen);
306 Stream.WriteVarUInt(Unicode);
307 Inc(P, CharLen);
308 end;
309 WriteVarBlock(Stream);
310 finally
311 Stream.Free;
312 end;
313end;
314
315function TVarBlockSerializer.ReadVarString: string;
316var
317 Block: TVarBlockSerializer;
318 Character: Integer;
319begin
320 try
321 Block := TVarBlockSerializer.Create;
322 ReadVarBlock(Block);
323 Block.Stream.Position := 0;
324 while Block.Stream.Position < Block.Stream.Size do begin
325 Character := Block.ReadVarUInt;
326 Result := Result + UnicodeToUTF8(Character);
327 end;
328 finally
329 Block.Free;
330 end;
331end;
332
333procedure TVarBlockSerializer.WriteVarDouble(Value: Double);
334begin
335 WriteVarBuffer(Value, 8);
336end;
337
338function TVarBlockSerializer.ReadVarDouble: Double;
339begin
340 Result := 0;
341 ReadVarBuffer(Result, 8);
342end;
343
344procedure TVarBlockSerializer.WriteVarStream(AStream: TStream);
345var
346 Length: Integer; // Count of data bytes
347 Data: Byte;
348 I: Integer;
349 LengthMask: Byte;
350begin
351 AStream.Position := 0;
352 Length := AStream.Size;
353
354 // Copy data
355 if Length = 0 then Stream.WriteByte(0)
356 else begin
357 if AStream.Size > 0 then Data := AStream.ReadByte
358 else Data := 0;
359 if (Length < BitAlignment) then begin
360 LengthMask := GetUnaryLengthMask(Length);
361 if ((Data and (LengthMask xor $ff)) <> Data) or (Data = 0) then begin
362 // First data starts by zero or
363 // first data byte not fit to length byte
364 Inc(Length);
365 if Length < 8 then begin
366 LengthMask := GetUnaryLengthMask(Length);
367 Stream.WriteByte((LengthMask shl 1) and $ff);
368 Stream.WriteByte(Data);
369 end;
370 end else begin
371 // First data byte fit to length byte
372 Stream.WriteByte((Data and (LengthMask xor $ff)) or ((LengthMask shl 1) and $ff));
373 end;
374 end;
375 if Length >= BitAlignment then begin
376 // Recursive length
377 Stream.WriteByte($ff);
378 WriteVarUInt(AStream.Size);
379 Stream.WriteByte(Data);
380 end;
381
382 // Copy rest of data
383 for I := 1 to AStream.Size - 1 do begin
384 if I < AStream.Size then Data := AStream.ReadByte
385 else Data := 0;
386 Stream.WriteByte(Data);
387 end;
388 end;
389end;
390
391procedure TVarBlockSerializer.ReadVarStream(AStream: TStream);
392var
393 Data: Byte;
394 Length: Cardinal;
395 RealLength: Cardinal;
396 LengthMask: Byte;
397begin
398 AStream.Size := 0;
399 Length := 1;
400
401 Data := Stream.ReadByte;
402 if Data = $ff then begin
403 // Read recursive length
404 Length := ReadVarUInt;
405 AStream.Size := Length;
406 if Length > 0 then begin
407 Data := Stream.ReadByte;
408 AStream.WriteByte(Data);
409 end;
410 end else begin
411 // Read unary length
412 Length := DecodeUnaryLength(Data);
413 AStream.Size := Length;
414 LengthMask := GetUnaryLengthMask(Length);
415 Data := Data and (LengthMask xor $ff);
416 // Drop first byte if first data is zero
417 if Data <> 0 then AStream.WriteByte(Data)
418 else begin
419 Dec(Length);
420 AStream.Size := Length;
421 if Length > 0 then begin
422 Data := Stream.ReadByte;
423 AStream.WriteByte(Data);
424 end;
425 end;
426 end;
427
428 // If CopyFrom parameter count is zero then whole source is copied
429 if Length > 1 then begin
430 RealLength := AStream.CopyFrom(Stream, Length - 1);
431 if RealLength < (Length - 1) then
432 raise EReadError.Create(Format(SReadError, [Length - 1, RealLength, Stream.Size]));
433 end;
434 AStream.Position := 0;
435end;
436
437procedure TVarBlockSerializer.WriteVarList(List: TListByte);
438var
439 Mem: TMemoryStream;
440begin
441 try
442 Mem := TMemoryStream.Create;
443 List.WriteToStream(Mem);
444 WriteVarStream(Mem);
445 finally
446 Mem.Free;
447 end;
448end;
449
450procedure TVarBlockSerializer.ReadVarList(List: TListByte);
451var
452 Mem: TMemoryStream;
453begin
454 try
455 Mem := TMemoryStream.Create;
456 ReadVarStream(Mem);
457 Mem.Position := 0;
458 List.Count := Mem.Size;
459 List.ReplaceStream(Mem);
460 finally
461 Mem.Free;
462 end;
463end;
464
465procedure TVarBlockSerializer.WriteVarBuffer(var Buffer; Count: Integer);
466var
467 Mem: TMemoryStream;
468begin
469 try
470 Mem := TMemoryStream.Create;
471 Mem.WriteBuffer(Buffer, Count);
472 WriteVarStream(Mem);
473 finally
474 Mem.Free;
475 end;
476end;
477
478procedure TVarBlockSerializer.ReadVarBuffer(var Buffer; Count: Integer);
479var
480 Mem: TMemoryStream;
481begin
482 try
483 Mem := TMemoryStream.Create;
484 ReadVarStream(Mem);
485 Mem.Position := 0;
486 Mem.ReadBuffer(Buffer, Count);
487 finally
488 Mem.Free;
489 end;
490end;
491
492function TVarBlockSerializer.GetVarSize: Integer;
493var
494 Data: Byte;
495 StoredPosition: Integer;
496begin
497 try
498 StoredPosition := Stream.Position;
499 Result := 1; // Byte block length
500 Data := Stream.ReadByte;
501
502 if Data = $ff then Result := GetVarSize + ReadVarUInt + 1
503 else begin
504 Result := DecodeUnaryLength(Data);
505 end;
506 Stream.Position := StoredPosition;
507 except
508 raise Exception.Create(SErrorGetVarSize);
509 end;
510end;
511
512function TVarBlockSerializer.GetVarCount: Integer;
513var
514 Data: Byte;
515 StoredPosition: Integer;
516 Skip: Integer;
517begin
518 StoredPosition := Stream.Position;
519 Result := 0;
520 while Stream.Position < Stream.Size do begin
521 Data := Stream.ReadByte;
522 if Data = $ff then Skip := ReadVarUInt
523 else Skip := DecodeUnaryLength(Data) - 1;
524 Stream.Seek(Skip, soCurrent);
525 Inc(Result);
526 end;
527 Stream.Position := StoredPosition;
528end;
529
530function TVarBlockSerializer.TryVarBlock: Boolean;
531var
532 Data: Byte;
533 StoredPosition: Integer;
534 Count: Integer;
535begin
536 if Stream.Position < Stream.Size then
537 try
538 StoredPosition := Stream.Position;
539 Data := Stream.ReadByte;
540 if Data = $ff then begin
541 if TryVarBlock then begin
542 Count := ReadVarUInt;
543 Result := Count <= Stream.Size - Stream.Position;
544 end else Result := False;
545 end else begin
546 Count := DecodeUnaryLength(Data) - 1;
547 Result := Count <= Stream.Size - Stream.Position;
548 end;
549 Stream.Position := StoredPosition;
550 except
551 raise Exception.Create(SErrorGetVarSize);
552 end else Result := False;
553end;
554
555procedure TVarBlockSerializer.WriteVarSInt(Value: Int64);
556begin
557 if Value < 0 then WriteVarUInt(((-Value) shl 1) - 1)
558 else WriteVarUInt((Value shl 1))
559end;
560
561function TVarBlockSerializer.ReadVarSInt: Int64;
562begin
563 Result := ReadVarUInt;
564 if (Result and 1) = 0 then Result := Result shr 1
565 else Result := -((Result + 1) shr 1);
566end;
567
568function TVarBlockSerializer.TestMask(Mask: QWord; BitIndex: Byte): Boolean;
569begin
570 Result := ((Mask shr BitIndex) and 1) = 1;
571end;
572
573function TVarBlockSerializer.BuildMask(Bits:array of Integer):Integer;
574var
575 I: Integer;
576begin
577 Result := 0;
578 for I := 0 to High(Bits) do
579 Result := Result or (1 shl Bits[I]);
580end;
581
582procedure TVarBlockSerializer.ReadItemByMaskIndex(Index:Integer; Data:
583 TVarBlockSerializer);
584var
585 Mask: Integer;
586 I: Integer;
587 StreamHelper: TStreamHelper;
588begin
589 try
590 StreamHelper := TStreamHelper.Create(Stream);
591 try
592 Stream.Position := 0;
593 Data.Stream.Size := 0;
594 Mask := ReadVarUInt;
595 I := 0;
596 while (Stream.Position < Stream.Size) and (I < Index) do begin
597 if TestMask(Mask, I) then
598 Stream.Position := Stream.Position + GetVarSize;
599 Inc(I);
600 end;
601 if TestMask(Mask, Index) then
602 StreamHelper.ReadStream(Data.Stream, GetVarSize);
603 except
604 //raise Exception.Create(SMaskedValueReadError);
605 // Error recovery for not enough source data in stream
606 Data.Stream.Size := 0;
607 Data.Stream.WriteByte(0);
608 end;
609 finally
610 StreamHelper.Free;
611 Data.Stream.Position := 0;
612 end;
613end;
614
615procedure TVarBlockSerializer.ReadItemRefByMaskIndex(Index:Integer;Data:TSubStream
616 );
617var
618 Mask: Integer;
619 I: Integer;
620begin
621 try
622 Stream.Position := 0;
623 Data.Size := 0;
624 Mask := ReadVarUInt;
625 I := 0;
626 while (Stream.Position < Stream.Size) and (I < Index) do begin
627 if TestMask(Mask, I) then Stream.Position := Stream.Position + GetVarSize;
628 Inc(I);
629 end;
630 if TestMask(Mask, Index) then begin
631 if Stream is TSubStream then begin
632 // Recalculate substream
633 Data.Source := TSubStream(Stream).Source;
634 Data.SourcePosition := TSubStream(Stream).SourcePosition + Stream.Position;
635 end else begin
636 Data.Source := Self.Stream;
637 Data.SourcePosition := Stream.Position;
638 end;
639 Data.Size := GetVarSize;
640 end;
641 Data.Position := 0;
642 except
643 raise Exception.Create(SMaskedValueReadError);
644 end;
645end;
646
647procedure TVarBlockSerializer.BlockEnclose;
648var
649 Temp: TVarBlockSerializer;
650 StreamHelper: TStreamHelper;
651begin
652 try
653 Temp := TVarBlockSerializer.Create;
654 StreamHelper := TStreamHelper.Create(Temp.Stream);
655 StreamHelper.WriteStream(Stream, Stream.Size);
656 Stream.Size := 0;
657 WriteVarBlock(Temp);
658 finally
659 StreamHelper.Free;
660 Temp.Free;
661 end;
662end;
663
664procedure TVarBlockSerializer.BlockUnclose;
665var
666 Temp: TVarBlockSerializer;
667 StreamHelper: TStreamHelper;
668begin
669 try
670 Temp := TVarBlockSerializer.Create;
671 StreamHelper := TStreamHelper.Create(Stream);
672 Stream.Position := 0;
673 ReadVarBlock(Temp);
674 Stream.Size := 0;
675 StreamHelper.WriteStream(Temp.Stream, Temp.Stream.Size);
676 finally
677 Stream.Position := 0;
678 StreamHelper.Free;
679 Temp.Free;
680 end;
681end;
682
683procedure TVarBlockSerializer.Assign(Source: TVarBlockSerializer);
684var
685 OldPos: Integer;
686begin
687 OwnsStream := Source.OwnsStream;
688 FStream.Size := 0;
689 OldPos := Source.FStream.Position;
690 FStream.CopyFrom(Source.FStream, Source.FStream.Size);
691 Source.FStream.Position := OldPos;
692 FStream.Position := OldPos;
693end;
694
695constructor TVarBlockSerializer.Create;
696begin
697 inherited;
698 Stream := TStreamHelper.Create;
699 OwnsStream := True;
700 TStreamHelper(Stream).Endianness := enBig;
701end;
702
703destructor TVarBlockSerializer.Destroy;
704begin
705 if OwnsStream then begin
706 FreeAndNil(FStream);
707 end;
708 inherited;
709end;
710
711{ TVarBlockIndexed }
712
713procedure TVarBlockIndexed.CheckItem(Index:Integer);
714begin
715 if Items.Count > Index then begin
716 if not Assigned(Items[Index]) then
717 Items[Index] := TVarBlockSerializer.Create;
718 TVarBlockSerializer(Items[Index]).Stream.Size := 0;
719 end else begin
720 Items.Count := Index + 1;
721 Items[Index] := TVarBlockSerializer.Create;
722 end;
723end;
724
725procedure TVarBlockIndexed.Assign(Source: TVarBlockIndexed);
726var
727 I: Integer;
728begin
729 Enclose := Source.Enclose;
730 Items.Count := 0;
731 Items.Count := Source.Items.Count;
732 for I := 0 to Items.Count - 1 do begin
733 Items[I] := TVarBlockSerializer.Create;
734 TVarBlockSerializer(Items[I]).Assign(TVarBlockSerializer(Source.Items[I]));
735 end;
736end;
737
738procedure TVarBlockIndexed.WriteVarUInt(Index:Integer;Value:QWord);
739begin
740 CheckItem(Index);
741 TVarBlockSerializer(Items[Index]).WriteVarUInt(Value);
742end;
743
744function TVarBlockIndexed.ReadVarUInt(Index:Integer):QWord;
745begin
746 TVarBlockSerializer(Items[Index]).Stream.Position := 0;
747 Result := TVarBlockSerializer(Items[Index]).ReadVarUInt;
748end;
749
750procedure TVarBlockIndexed.WriteVarBlock(Index: Integer; Block: TVarBlockSerializer);
751begin
752 CheckItem(Index);
753 TVarBlockSerializer(Items[Index]).WriteVarBlock(Block);
754end;
755
756procedure TVarBlockIndexed.ReadVarBlock(Index: Integer; Block: TVarBlockSerializer);
757begin
758 with TVarBlockSerializer(Items[Index]) do begin
759 Stream.Position := 0;
760 ReadVarBlock(Block);
761 end;
762end;
763
764procedure TVarBlockIndexed.WriteVarStream(Index: Integer; Stream: TStream);
765begin
766 CheckItem(Index);
767 TVarBlockSerializer(Items[Index]).WriteVarStream(Stream);
768end;
769
770procedure TVarBlockIndexed.ReadVarStream(Index: Integer; Stream: TStream);
771begin
772 TVarBlockSerializer(Items[Index]).Stream.Position := 0;
773 TVarBlockSerializer(Items[Index]).ReadVarStream(Stream);
774end;
775
776procedure TVarBlockIndexed.WriteVarList(Index: Integer; List: TListByte);
777begin
778 CheckItem(Index);
779 TVarBlockSerializer(Items[Index]).WriteVarList(List);
780end;
781
782procedure TVarBlockIndexed.ReadVarList(Index: Integer; List: TListByte);
783begin
784 TVarBlockSerializer(Items[Index]).Stream.Position := 0;
785 TVarBlockSerializer(Items[Index]).ReadVarList(List);
786end;
787
788procedure TVarBlockIndexed.WriteVarIndexedBlock(Index: Integer;
789 Block: TVarBlockIndexed);
790var
791 Temp: TStreamHelper;
792begin
793 try
794 Temp := TStreamHelper.Create;
795 Block.Enclose := False;
796 Block.WriteToStream(Temp);
797 WriteVarStream(Index, Temp);
798 finally
799 Temp.Free;
800 end;
801end;
802
803procedure TVarBlockIndexed.ReadVarIndexedBlock(Index: Integer;
804 Block: TVarBlockIndexed);
805var
806 Temp: TStreamHelper;
807begin
808 try
809 Temp := TStreamHelper.Create;
810 Block.Enclose := False;
811 ReadVarStream(Index, Temp);
812 Block.ReadFromStream(Temp);
813 finally
814 Temp.Free;
815 end;
816end;
817
818procedure TVarBlockIndexed.WriteVarBuffer(Index: Integer; var Buffer;
819 Count: Integer);
820begin
821 CheckItem(Index);
822 TVarBlockSerializer(Items[Index]).WriteVarBuffer(Buffer, Count);
823end;
824
825procedure TVarBlockIndexed.ReadVarBuffer(Index: Integer; var Buffer;
826 Count: Integer);
827begin
828 CheckItem(Index);
829 TVarBlockSerializer(Items[Index]).ReadVarBuffer(Buffer, Count);
830end;
831
832procedure TVarBlockIndexed.WriteVarSInt(Index: Integer; Value:Int64);
833begin
834 CheckItem(Index);
835 TVarBlockSerializer(Items[Index]).WriteVarSInt(Value);
836end;
837
838function TVarBlockIndexed.ReadVarSInt(Index: Integer): Int64;
839begin
840 TVarBlockSerializer(Items[Index]).Stream.Position := 0;
841 Result := TVarBlockSerializer(Items[Index]).ReadVarSInt;
842end;
843
844procedure TVarBlockIndexed.WriteVarFloat(Index: Integer; Value:Double; Base: Integer = 2);
845begin
846 CheckItem(Index);
847 TVarBlockSerializer(Items[Index]).WriteVarFloat(Value, Base);
848end;
849
850function TVarBlockIndexed.ReadVarFloat(Index: Integer; Base: Integer = 2):Double;
851begin
852 TVarBlockSerializer(Items[Index]).Stream.Position := 0;
853 Result := TVarBlockSerializer(Items[Index]).ReadVarFloat(Base);
854end;
855
856procedure TVarBlockIndexed.WriteVarDouble(Index: Integer; Value: Double);
857begin
858 CheckItem(Index);
859 TVarBlockSerializer(Items[Index]).WriteVarDouble(Value);
860end;
861
862function TVarBlockIndexed.ReadVarDouble(Index: Integer): Double;
863begin
864 TVarBlockSerializer(Items[Index]).Stream.Position := 0;
865 Result := TVarBlockSerializer(Items[Index]).ReadVarDouble;
866end;
867
868procedure TVarBlockIndexed.WriteVarString(Index: Integer; Value:string);
869begin
870 CheckItem(Index);
871 TVarBlockSerializer(Items[Index]).WriteVarString(Value);
872end;
873
874function TVarBlockIndexed.ReadVarString(Index: Integer):string;
875begin
876 with TVarBlockSerializer(Items[Index]) do begin
877 Stream.Position := 0;
878 Result := ReadVarString;
879 end;
880end;
881
882procedure TVarBlockIndexed.WriteVarUIntArray(Index: Integer;
883 List: TListInteger);
884var
885 I: Integer;
886 Temp: TVarBlockSerializer;
887begin
888 try
889 Temp := TVarBlockSerializer.Create;
890 for I := 0 to List.Count - 1 do
891 Temp.WriteVarUInt(Integer(List[I]));
892 WriteVarBlock(Index, Temp);
893 finally
894 Temp.Free;
895 end;
896end;
897
898procedure TVarBlockIndexed.ReadVarUIntArray(Index: Integer;
899 List: TListInteger);
900var
901 Temp: TVarBlockSerializer;
902begin
903 try
904 Temp := TVarBlockSerializer.Create;
905 List.Clear;
906 ReadVarBlock(Index, Temp);
907 while Temp.Stream.Position < Temp.Stream.Size do begin
908 List.Add(Temp.ReadVarUInt);
909 end;
910 finally
911 Temp.Free;
912 end;
913end;
914
915procedure TVarBlockIndexed.WriteVarStringArray(Index: Integer;
916 List: TListString);
917var
918 I: Integer;
919 Temp: TVarBlockSerializer;
920begin
921 try
922 Temp := TVarBlockSerializer.Create;
923 for I := 0 to List.Count - 1 do
924 Temp.WriteVarString(List[I]);
925 WriteVarBlock(Index, Temp);
926 finally
927 Temp.Free;
928 end;
929end;
930
931procedure TVarBlockIndexed.ReadVarStringArray(Index: Integer; List: TListString
932 );
933var
934 Temp: TVarBlockSerializer;
935begin
936 try
937 Temp := TVarBlockSerializer.Create;
938 List.Clear;
939 ReadVarBlock(Index, Temp);
940 while Temp.Stream.Position < Temp.Stream.Size do begin
941 List.Add(Temp.ReadVarString);
942 end;
943 finally
944 Temp.Free;
945 end;
946end;
947
948procedure TVarBlockIndexed.Clear;
949begin
950 Items.Clear;
951end;
952
953function TVarBlockIndexed.TestIndex(Index: Integer):Boolean;
954begin
955 if (Index >= 0) and (Index < Items.Count) then
956 Result := Assigned(Items[Index])
957 else Result := False
958end;
959
960procedure TVarBlockIndexed.WriteToVarBlock(VarBlock: TVarBlockSerializer);
961var
962 Mask: Integer;
963 I: Integer;
964 StreamHelper: TStreamHelper;
965 Temp: TVarBlockSerializer;
966 Output: TVarBlockSerializer;
967begin
968 try
969 if Enclose then begin
970 Temp := TVarBlockSerializer.Create;
971 Output := Temp;
972 end else begin
973 Temp := nil;
974 Output := VarBlock;
975 end;
976 StreamHelper := TStreamHelper.Create(Output.Stream);
977
978 Output.Stream.Size := 0;
979 Mask := 0;
980 for I := 0 to Items.Count - 1 do
981 if Assigned(Items[I]) then Mask := Mask or (1 shl I);
982 Output.WriteVarUInt(Mask);
983 for I := 0 to Items.Count - 1 do
984 if Assigned(Items[I]) then
985 StreamHelper.WriteStream(TVarBlockSerializer(Items[I]).Stream,
986 TVarBlockSerializer(Items[I]).Stream.Size);
987
988 if Enclose then VarBlock.WriteVarBlock(Temp);
989 finally
990 if Assigned(Temp) then Temp.Free;
991 StreamHelper.Free;
992 end;
993end;
994
995procedure TVarBlockIndexed.ReadFromVarBlock(VarBlock: TVarBlockSerializer);
996var
997 Mask: Integer;
998 I: Integer;
999 Temp: TVarBlockSerializer;
1000 Input: TVarBlockSerializer;
1001 StreamHelper: TStreamHelper;
1002begin
1003 try
1004 StreamHelper := TStreamHelper.Create;
1005 if Enclose then begin
1006 Temp := TVarBlockSerializer.Create;
1007 Temp.ReadVarBlock(VarBlock);
1008 Input := Temp;
1009 end else begin
1010 Temp := nil;
1011 Input := VarBlock;
1012 end;
1013 StreamHelper.Stream := Input.Stream;
1014
1015 Input.Stream.Position := 0;
1016 Mask := Input.ReadVarUInt;
1017 Items.Clear;
1018 I := 0;
1019 while (Mask <> 0) and (Input.Stream.Position < Input.Stream.Size) do begin
1020 if Input.TestMask(Mask, I) then begin
1021 CheckItem(I);
1022 TVarBlockSerializer(Items[I]).Stream.Size := 0;
1023 StreamHelper.ReadStream(TVarBlockSerializer(Items[I]).Stream, Input.GetVarSize);
1024 //Input.ReadItemByMaskIndex(I, TVarBlockSerializer(Items[I]));
1025 Mask := Mask xor (1 shl I); // Clear bit on current index
1026 end;
1027 Inc(I);
1028 end;
1029 finally
1030 if Assigned(Temp) then Temp.Free;
1031 StreamHelper.Free;
1032 end;
1033end;
1034
1035procedure TVarBlockIndexed.WriteToStream(Stream: TStream);
1036var
1037 Temp: TVarBlockSerializer;
1038 StreamHelper: TStreamHelper;
1039begin
1040 try
1041 Temp := TVarBlockSerializer.Create;
1042 StreamHelper := TStreamHelper.Create(Stream);
1043 WriteToVarBlock(Temp);
1044 StreamHelper.WriteStream(Temp.Stream, Temp.Stream.Size);
1045 finally
1046 StreamHelper.Free;
1047 Temp.Free;
1048 end;
1049end;
1050
1051procedure TVarBlockIndexed.ReadFromStream(Stream: TStream);
1052var
1053 VarBlock: TVarBlockSerializer;
1054begin
1055 try
1056 VarBlock := TVarBlockSerializer.Create;
1057 VarBlock.Stream := Stream;
1058 ReadFromVarBlock(VarBlock);
1059 finally
1060 VarBlock.Free;
1061 end;
1062end;
1063
1064procedure TVarBlockIndexed.WriteToList(List: TListByte);
1065var
1066 Mem: TMemoryStream;
1067begin
1068 try
1069 Mem := TMemoryStream.Create;
1070 WriteToStream(Mem);
1071 List.Count := Mem.Size;
1072 List.ReplaceStream(Mem);
1073 finally
1074 Mem.Free;
1075 end;
1076end;
1077
1078procedure TVarBlockIndexed.ReadFromList(List: TListByte);
1079var
1080 Mem: TMemoryStream;
1081begin
1082 try
1083 Mem := TMemoryStream.Create;
1084 List.WriteToStream(Mem);
1085 ReadFromStream(Mem);
1086 finally
1087 Mem.Free;
1088 end;
1089end;
1090
1091constructor TVarBlockIndexed.Create;
1092begin
1093 Items := TListObject.Create;
1094 Enclose := True;
1095end;
1096
1097destructor TVarBlockIndexed.Destroy;
1098begin
1099 FreeAndNil(Items);
1100 inherited;
1101end;
1102
1103end.
Note: See TracBrowser for help on using the repository browser.