source: CoolStreaming/UVarBlockSerializer.pas

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