Changeset 11 for ProtocolBuffers/UProtocolBuffers.pas
- Timestamp:
- Oct 20, 2009, 11:06:34 AM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
ProtocolBuffers/UProtocolBuffers.pas
r10 r11 1 // http://code.google.com/intl/cs/apis/protocolbuffers/docs/overview.html1 // Specification: http://code.google.com/intl/cs/apis/protocolbuffers/docs/overview.html 2 2 unit UProtocolBuffers; 3 3 … … 7 7 8 8 uses 9 Classes, SysUtils ;9 Classes, SysUtils, Dialogs; 10 10 11 11 type 12 12 TPBItemMode = (imRequired, imOptional, imRepeated); 13 TPBItemType = (itVariant, it64bit, itLengthDelimited, itStartGroup, 14 itEndGroup, it32bit); 13 TPBWireType = (wtVariant, wt64bit, wtLengthDelimited, wtStartGroup, 14 wtEndGroup, wt32bit); 15 TPBItemType = (itInteger, itString, itMessage, itFloat, itDouble, itBlock); 15 16 16 17 TPBEnumeration = class 17 18 end; 18 19 19 { TPBItem } 20 TPBItem = class 20 { TPBDefinition } 21 TPBDefinition = class 22 private 23 function GetWireType: TPBWireType; 24 public 21 25 Name: string; 22 26 Tag: Integer; 23 27 ItemType: TPBItemType; 24 28 ItemMode: TPBItemMode; 29 Items: TList; // TList<TPBDefinition> 30 DefaultString: string; 31 DefaultInteger: Integer; 32 constructor Create; 33 destructor Destroy; override; 34 function SearchItemByTag(Tag: Integer): Integer; 35 property WireType: TPBWireType read GetWireType; 36 end; 37 38 { TPBItemHead } 39 TPBItemHead = record 40 Tag: Integer; 41 WireType: TPBWireType; 42 end; 43 44 { TPBItem } 45 TPBItem = class 25 46 procedure SaveVariantToStream(Stream: TStream; Value: Integer); 26 47 function LoadVariantFromStream(Stream: TStream): Integer; 27 48 procedure SaveLengthDelimitedToStream(Stream: TStream; Block: TStream); 28 49 procedure LoadLengthDelimitedFromStream(Stream: TStream; Block: TStream); 29 procedure SaveHeadToStream(Stream: TStream); 30 procedure LoadHeadFromStream(Stream: TStream); 31 procedure SaveToStream(Stream: TStream); virtual; 32 procedure LoadFromStream(Stream: TStream); virtual; 50 procedure SaveHeadToStream(Stream: TStream; Definition: TPBDefinition); 51 function LoadHeadFromStream(Stream: TStream; Definition: TPBDefinition): TPBItemHead; 52 procedure SaveToStream(Stream: TStream; Definition: TPBDefinition); virtual; 53 procedure LoadFromStream(Stream: TStream; Definition: TPBDefinition); virtual; 54 procedure Clear(Definition: TPBDefinition); virtual; 55 procedure Assign(Source: TPBItem); virtual; 33 56 end; 34 57 … … 38 61 TPBStringItem = class(TPBItem) 39 62 Value: string; 40 procedure SaveToStream(Stream: TStream ); override;41 procedure LoadFromStream(Stream: TStream ); override;63 procedure SaveToStream(Stream: TStream; Definition: TPBDefinition); override; 64 procedure LoadFromStream(Stream: TStream; Definition: TPBDefinition); override; 42 65 constructor Create; 66 procedure Assign(Source: TPBItem); override; 43 67 end; 44 68 … … 46 70 TPBIntegerItem = class(TPBItem) 47 71 Value: Integer; 48 procedure SaveToStream(Stream: TStream ); override;49 procedure LoadFromStream(Stream: TStream ); override;72 procedure SaveToStream(Stream: TStream; Definition: TPBDefinition); override; 73 procedure LoadFromStream(Stream: TStream; Definition: TPBDefinition); override; 50 74 constructor Create; 75 procedure Assign(Source: TPBItem); override; 51 76 end; 52 77 … … 54 79 TPBMessageItem = class(TPBItem) 55 80 GenerateHead: Boolean; 56 Items: TList; // TList<T PBItem>;57 function SearchItemByTag(Tag: Integer): TPBItem;58 procedure SaveToStream(Stream: TStream ); override;59 procedure LoadFromStream(Stream: TStream ); override;81 Items: TList; // TList<TList<TPBItem>>; 82 procedure Clear(Definition: TPBDefinition); override; 83 procedure SaveToStream(Stream: TStream; Definition: TPBDefinition); override; 84 procedure LoadFromStream(Stream: TStream; Definition: TPBDefinition); override; 60 85 constructor Create; 61 86 destructor Destroy; override; 87 procedure Assign(Source: TPBItem); override; 88 end; 89 90 { TPBRepeatedItem } 91 92 TPBRepeatedItem = class(TPBItem) 93 Items: TList; 94 procedure Clear(Definition: TPBDefinition); override; 95 procedure SaveToStream(Stream: TStream; Definition: TPBDefinition); override; 96 procedure LoadFromStream(Stream: TStream; Definition: TPBDefinition); override; 97 constructor Create; 98 destructor Destroy; override; 99 procedure Assign(Source: TPBItem); override; 62 100 end; 63 101 64 102 { TProtocolBuffer } 65 103 TProtocolBuffer = class 104 Definition: TPBDefinition; 66 105 BaseMessage: TPBMessageItem; 67 106 procedure LoadFromStream(Stream: TStream); … … 82 121 begin 83 122 BaseMessage.GenerateHead := False; 84 BaseMessage.LoadFromStream(Stream );123 BaseMessage.LoadFromStream(Stream, Definition); 85 124 end; 86 125 … … 88 127 begin 89 128 BaseMessage.GenerateHead := False; 90 BaseMessage.SaveToStream(Stream );129 BaseMessage.SaveToStream(Stream, Definition); 91 130 end; 92 131 … … 99 138 begin 100 139 BaseMessage := TPBMessageItem.Create; 140 Definition := TPBDefinition.Create; 141 Definition.ItemType := itMessage; 101 142 end; 102 143 103 144 destructor TProtocolBuffer.Destroy; 104 145 begin 105 if Assigned(BaseMessage) then BaseMessage.Free; 146 Definition.Destroy; 147 BaseMessage.Free; 106 148 inherited Destroy; 107 149 end; … … 109 151 { TPBMessageItem } 110 152 111 function TPBMessageItem.SearchItemByTag(Tag: Integer): TPBItem; 112 var 113 I: Integer; 114 begin 115 I := 0; 116 while (I < Items.Count) and (TPBItem(Items[I]).Tag <> Tag) do Inc(I); 117 if I < Items.Count then Result := Items[I] 118 else Result := nil; 119 end; 120 121 procedure TPBMessageItem.SaveToStream(Stream: TStream); 122 var 123 I: Integer; 153 procedure TPBMessageItem.Clear(Definition: TPBDefinition); 154 var 155 I: Integer; 156 Q: Integer; 157 begin 158 for I := 0 to Items.Count - 1 do 159 TPBItem(Items[I]).Clear(Definition); 160 Items.Clear; 161 Items.Count := Definition.Items.Count; 162 for I := 0 to Items.Count - 1 do begin 163 if TPBDefinition(Definition.Items[I]).ItemMode = imRepeated then 164 Items[I] := TPBRepeatedItem.Create 165 else 166 if TPBDefinition(Definition.Items[I]).ItemType = itInteger then begin 167 Items[I] := TPBIntegerItem.Create; 168 TPBIntegerItem(Items[I]).Value := TPBDefinition(Definition.Items[I]).DefaultInteger; 169 end else 170 if TPBDefinition(Definition.Items[I]).ItemType = itString then begin 171 Items[I] := TPBStringItem.Create; 172 TPBStringItem(Items[I]).Value := TPBDefinition(Definition.Items[I]).DefaultString; 173 end else 174 if TPBDefinition(Definition.Items[I]).ItemType = itMessage then begin 175 Items[I] := TPBMessageItem.Create; 176 TPBMessageItem(Items[I]).Clear(Definition.Items[I]); 177 end; 178 end; 179 end; 180 181 procedure TPBMessageItem.SaveToStream(Stream: TStream; Definition: TPBDefinition); 182 var 183 I: Integer; 184 Q: Integer; 124 185 TempStream: TMemoryStream; 125 186 begin … … 127 188 // Generate message content to temporary stream 128 189 TempStream := TMemoryStream.Create; 129 for I := 0 to Items.Count - 1 do 130 TPBItem(Items[I]).SaveToStream(TempStream); 131 // if head is used than write lenght-delimited head type with block byte length 190 if Items.Count <> Definition.Items.Count then 191 raise Exception.Create('Definition and value items count mismatch.'); 192 for I := 0 to Definition.Items.Count - 1 do 193 TPBItem(Items[I]).SaveToStream(TempStream, Definition.Items[I]); 194 195 // If head is used than write lenght-delimited head type with block byte length 132 196 if GenerateHead then begin 133 SaveHeadToStream(Stream );197 SaveHeadToStream(Stream, Definition); 134 198 SaveVariantToStream(Stream, TempStream.Size); 135 199 end; … … 139 203 end; 140 204 141 procedure TPBMessageItem.LoadFromStream(Stream: TStream );205 procedure TPBMessageItem.LoadFromStream(Stream: TStream; Definition: TPBDefinition); 142 206 var 143 207 I: Integer; 144 208 TempItem: TPBItem; 145 SearchItem: TPBItem;209 ItemIndex: Integer; 146 210 EndIndex: Integer; 147 211 TempStream: TMemoryStream; 212 ItemHead: TPBItemHead; 213 NewItem: TPBItem; 148 214 begin 149 215 inherited; … … 156 222 157 223 TempItem := TPBItem.Create; 224 Clear(Definition); 158 225 while Stream.Position < EndIndex do begin 159 TempItem.LoadHeadFromStream(Stream); 160 SearchItem := SearchItemByTag(TempItem.Tag); 161 if Assigned(SearchItem) then begin 162 if SearchItem.ItemType <> TempItem.ItemType then 163 raise Exception.Create('Bad type for item "' + SearchItem.Name + 164 '" with tag ' + IntToStr(SearchItem.Tag)); 165 if SearchItem is TPBIntegerItem then 166 TPBIntegerItem(SearchItem).LoadFromStream(Stream) 167 else if SearchItem is TPBStringItem then 168 TPBStringItem(SearchItem).LoadFromStream(Stream) 169 else if SearchItem is TPBMessageItem then 170 TPBMessageItem(SearchItem).LoadFromStream(Stream); 226 ItemHead := TempItem.LoadHeadFromStream(Stream, Definition); 227 ItemIndex := Definition.SearchItemByTag(ItemHead.Tag); 228 if ItemIndex <> -1 then 229 with TPBDefinition(Definition.Items[ItemIndex]) do begin 230 if WireType <> ItemHead.WireType then 231 raise Exception.Create('Bad type for item "' + TPBDefinition(Definition.Items[ItemIndex]).Name + 232 '" with tag ' + IntToStr(ItemHead.Tag)); 233 if ItemType = itInteger then begin 234 NewItem := TPBIntegerItem.Create; 235 TPBIntegerItem(NewItem).LoadFromStream(Stream, Definition.Items[ItemIndex]); 236 end else 237 if TPBDefinition(Definition.Items[ItemIndex]).ItemType = itString then begin 238 NewItem := TPBStringItem.Create; 239 TPBStringItem(NewItem).LoadFromStream(Stream, Definition.Items[ItemIndex]) 240 end else 241 if TPBDefinition(Definition.Items[ItemIndex]).ItemType = itMessage then begin 242 NewItem := TPBMessageItem.Create; 243 TPBMessageItem(NewItem).LoadFromStream(Stream, Definition.Items[ItemIndex]); 244 end; 245 246 if ItemMode = imRepeated then begin 247 TPBRepeatedItem(Items[ItemIndex]).Items.Add(NewItem); 248 end else begin 249 TPBItem(Self.Items[ItemIndex]).Assign(NewItem); 250 NewItem.Free; 251 end; 171 252 end else begin 172 if TempItem.ItemType = itVariant then 253 // Skip item data 254 if ItemHead.WireType = wtVariant then 173 255 TempItem.LoadVariantFromStream(Stream) 174 else if TempItem.ItemType = itLengthDelimited then256 else if ItemHead.WireType = wtLengthDelimited then 175 257 TempItem.LoadLengthDelimitedFromStream(Stream, TempStream); 176 258 end; … … 181 263 constructor TPBMessageItem.Create; 182 264 begin 183 ItemType := itLengthDelimited;184 265 Items := TList.Create; 185 266 GenerateHead := True; … … 194 275 Items.Free; 195 276 inherited Destroy; 277 end; 278 279 procedure TPBMessageItem.Assign(Source: TPBItem); 280 var 281 I: Integer; 282 begin 283 if Source is TPBMessageItem then begin 284 GenerateHead := TPBMessageItem(Source).GenerateHead; 285 for I := 0 to Items.Count - 1 do 286 TPBItem(Items[I]).Assign(TPBMessageItem(Source).Items[I]); 287 end; 196 288 end; 197 289 … … 215 307 end; 216 308 217 procedure TPBItem.SaveHeadToStream(Stream: TStream );309 procedure TPBItem.SaveHeadToStream(Stream: TStream; Definition: TPBDefinition); 218 310 var 219 311 ByteIndex: Byte; … … 221 313 begin 222 314 with TMemoryStreamEx(Stream) do begin 223 Data := (( Tag and $f) shl 3) or (Integer(ItemType) and $7);315 Data := ((Definition.Tag and $f) shl 3) or (Integer(Definition.WireType) and $7); 224 316 ByteIndex := 0; 225 while Tag > (1 shl (ByteIndex * 7 + 4)) do begin317 while Definition.Tag > (1 shl (ByteIndex * 7 + 4)) do begin 226 318 WriteByte(Data or $80); 227 Data := ( Tag shr (ByteIndex * 7 + 4)) and $7f;319 Data := (Definition.Tag shr (ByteIndex * 7 + 4)) and $7f; 228 320 Inc(ByteIndex); 229 321 end; … … 232 324 end; 233 325 234 procedure TPBItem.LoadHeadFromStream(Stream: TStream);326 function TPBItem.LoadHeadFromStream(Stream: TStream; Definition: TPBDefinition): TPBItemHead; 235 327 var 236 328 Data: Byte; … … 238 330 begin 239 331 Data := TMemoryStreamEx(Stream).ReadByte; 240 ItemType := TPBItemType(Data and 3);241 Tag := (Data shr 3) and $f;332 Result.WireType := TPBWireType(Data and 3); 333 Result.Tag := (Data shr 3) and $f; 242 334 ByteIndex := 0; 243 335 while Data > $7f do begin 244 336 Data := TMemoryStreamEx(Stream).ReadByte; 245 Tag :=Tag or ((Data and $7f) shl (ByteIndex * 7 + 4));337 Result.Tag := Result.Tag or ((Data and $7f) shl (ByteIndex * 7 + 4)); 246 338 Inc(ByteIndex); 247 339 end; 248 340 end; 249 341 250 procedure TPBItem.SaveToStream(Stream: TStream); 251 begin 252 253 end; 254 255 procedure TPBItem.LoadFromStream(Stream: TStream); 342 procedure TPBItem.SaveToStream(Stream: TStream; Definition: TPBDefinition); 343 begin 344 345 end; 346 347 procedure TPBItem.LoadFromStream(Stream: TStream; Definition: TPBDefinition); 348 begin 349 350 end; 351 352 procedure TPBItem.Clear(Definition: TPBDefinition); 353 begin 354 355 end; 356 357 procedure TPBItem.Assign(Source: TPBItem); 256 358 begin 257 359 … … 291 393 { TPBIntegerItem } 292 394 293 procedure TPBIntegerItem.SaveToStream(Stream: TStream );294 begin 295 inherited; 296 SaveHeadToStream(Stream );395 procedure TPBIntegerItem.SaveToStream(Stream: TStream; Definition: TPBDefinition); 396 begin 397 inherited; 398 SaveHeadToStream(Stream, Definition); 297 399 SaveVariantToStream(Stream, Value); 298 400 end; 299 401 300 procedure TPBIntegerItem.LoadFromStream(Stream: TStream );402 procedure TPBIntegerItem.LoadFromStream(Stream: TStream; Definition: TPBDefinition); 301 403 begin 302 404 inherited; … … 306 408 constructor TPBIntegerItem.Create; 307 409 begin 308 ItemType := itVariant; 410 end; 411 412 procedure TPBIntegerItem.Assign(Source: TPBItem); 413 begin 414 if Source is TPBIntegerItem then 415 Value := TPBIntegerItem(Source).Value; 309 416 end; 310 417 311 418 { TPBStringItem } 312 419 313 procedure TPBStringItem.SaveToStream(Stream: TStream );314 begin 315 inherited; 316 SaveHeadToStream(Stream );420 procedure TPBStringItem.SaveToStream(Stream: TStream; Definition: TPBDefinition); 421 begin 422 inherited; 423 SaveHeadToStream(Stream, Definition); 317 424 SaveVariantToStream(Stream, Length(Value)); 318 TMemoryStreamEx(Stream).Write(Value[1], Length(Value)); 319 end; 320 321 procedure TPBStringItem.LoadFromStream(Stream: TStream); 425 if Length(Value) > 0 then 426 TMemoryStreamEx(Stream).Write(Value[1], Length(Value)); 427 end; 428 429 procedure TPBStringItem.LoadFromStream(Stream: TStream; Definition: TPBDefinition); 322 430 begin 323 431 inherited; 324 432 SetLength(Value, LoadVariantFromStream(Stream)); 325 TMemoryStreamEx(Stream).Read(Value[1], Length(Value)); 433 if Length(Value) > 0 then 434 TMemoryStreamEx(Stream).Read(Value[1], Length(Value)); 326 435 end; 327 436 328 437 constructor TPBStringItem.Create; 329 438 begin 330 ItemType := itLengthDelimited; 439 end; 440 441 procedure TPBStringItem.Assign(Source: TPBItem); 442 begin 443 if Source is TPBStringItem then 444 Value := TPBStringItem(Source).Value; 445 inherited Assign(Source); 446 end; 447 448 { TPBDefinition } 449 450 function TPBDefinition.SearchItemByTag(Tag: Integer): Integer; 451 var 452 I: Integer; 453 begin 454 I := 0; 455 while (I < Items.Count) and (TPBDefinition(Items[I]).Tag <> Tag) do Inc(I); 456 if I < Items.Count then Result := I 457 else Result := -1; 458 end; 459 460 function TPBDefinition.GetWireType: TPBWireType; 461 begin 462 case ItemType of 463 itInteger: Result := wtVariant; 464 itFloat: Result := wt64bit; 465 itDouble: Result := wt32bit; 466 itString: Result := wtLengthDelimited; 467 itMessage: Result := wtLengthDelimited; 468 end; 469 end; 470 471 constructor TPBDefinition.Create; 472 begin 473 Items := TList.Create; 474 end; 475 476 destructor TPBDefinition.Destroy; 477 var 478 I: Integer; 479 begin 480 for I := 0 to Items.Count - 1 do 481 TPBDefinition(Items[I]).Destroy; 482 Items.Free; 483 inherited Destroy; 484 end; 485 486 { TPBRepeatedItem } 487 488 procedure TPBRepeatedItem.Clear(Definition: TPBDefinition); 489 var 490 I: Integer; 491 begin 492 for I := 0 to Items.Count - 1 do 493 TPBItem(Items[I]).Free; 494 inherited; 495 end; 496 497 procedure TPBRepeatedItem.SaveToStream(Stream: TStream; 498 Definition: TPBDefinition); 499 var 500 I: Integer; 501 begin 502 for I := 0 to Items.Count - 1 do begin 503 TPBItem(Items[I]).SaveToStream(Stream, Definition); 504 end; 505 end; 506 507 procedure TPBRepeatedItem.LoadFromStream(Stream: TStream; 508 Definition: TPBDefinition); 509 begin 510 inherited LoadFromStream(Stream, Definition); 511 end; 512 513 constructor TPBRepeatedItem.Create; 514 begin 515 Items := TList.Create; 516 end; 517 518 destructor TPBRepeatedItem.Destroy; 519 var 520 I: Integer; 521 begin 522 for I := 0 to Items.Count - 1 do 523 TPBItem(Items[I]).Free; 524 Items.Free; 525 inherited Destroy; 526 end; 527 528 procedure TPBRepeatedItem.Assign(Source: TPBItem); 529 var 530 I: Integer; 531 begin 532 if Source is TPBRepeatedItem then begin 533 for I := 0 to Items.Count - 1 do 534 TPBItem(Items[I]).Assign(TPBRepeatedItem(Source).Items[I]); 535 end; 536 inherited Assign(Source); 331 537 end; 332 538
Note:
See TracChangeset
for help on using the changeset viewer.