Changeset 317 for GraphicTest/BGRABitmap/bgradnetdeserial.pas
- Timestamp:
- Feb 1, 2012, 3:02:33 PM (13 years ago)
- Location:
- GraphicTest/BGRABitmap
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/BGRABitmap
-
Property svn:ignore
set to
lib
-
Property svn:ignore
set to
-
GraphicTest/BGRABitmap/bgradnetdeserial.pas
r210 r317 4 4 5 5 interface 6 7 { This unit allow to read .Net serialized classes with BinaryFormatter of 8 namespace System.Runtime.Serialization.Formatters.Binary. 9 10 Serialization is a process by which objects in memory are saved according 11 to their structure. 12 13 This unit is used by BGRAPaintNet to read Paint.NET images. } 6 14 7 15 uses … … 9 17 10 18 type 19 arrayOfLongword = array of longword; 20 11 21 TTypeCategory = (ftPrimitiveType = 0, ftString = 1, ftObjectType = 12 22 2, ftRuntimeType = 3, … … 17 27 ptDouble = 6, ptInt16 = 7, ptInt32 = 8, ptInt64 = 9, ptSByte = 10, ptSingle = 11, 18 28 ptDateTime = 13, ptUInt16 = 14, ptUInt32 = 15, ptUInt64 = 16, ptString = 18); 29 30 TGenericArrayType = (gatSingleDimension, gatJagged, gatMultidimensional); 31 32 TDotNetDeserialization = class; 19 33 20 34 ArrayOfNameValue = array of record … … 43 57 end; 44 58 45 PSerializedObject = ^TSerializedObject; 46 47 TSerializedObject = record 59 { TCustomSerializedObject } 60 61 TCustomSerializedObject = class 62 protected 63 FContainer: TDotNetDeserialization; 64 function GetTypeAsString: string; virtual; abstract; 65 function GetFieldAsString(Index: longword): string; virtual; abstract; 66 function GetFieldAsString(Name: string): string; 67 function GetFieldCount: longword; virtual; abstract; 68 function GetFieldName(Index: longword): string; virtual; abstract; 69 function GetFieldTypeAsString(Index: longword): string; virtual; abstract; 70 function IsReferenceType(index: longword): boolean; virtual; abstract; 71 public 48 72 idObject: longword; 49 numType: integer;50 fields: ArrayOfNameValue;51 73 refCount: integer; 52 74 inToString: boolean; 75 constructor Create(container: TDotNetDeserialization); virtual; 76 property FieldCount: longword read GetFieldCount; 77 property FieldName[Index: longword]:string read GetFieldName; 78 property FieldAsString[Index: longword]: string read GetFieldAsString; 79 property FieldByNameAsString[Name: string]: string read GetFieldAsString; 80 property FieldTypeAsString[Index: longword]: string read GetFieldTypeAsString; 81 property TypeAsString: string read GetTypeAsString; 82 function GetFieldIndex(Name: string): integer; 83 end; 84 85 { TSerializedClass } 86 87 TSerializedClass = class(TCustomSerializedObject) 88 protected 89 function GetFieldAsString(Index: longword): string; override; 90 function GetFieldCount: longword; override; 91 function GetFieldName(Index: longword): string; override; 92 function GetFieldTypeAsString(Index: longword): string; override; 93 function IsReferenceType(index: longword): boolean; override; 94 function GetTypeAsString: string; override; 95 public 96 numType: integer; 97 fields: ArrayOfNameValue; 98 end; 99 100 { TSerializedArray } 101 102 TSerializedArray = class(TCustomSerializedObject) 103 private 104 data: pointer; 105 FItemSize: longword; 106 function GetItemPtr(Index: longword): pointer; 107 procedure InitData; 108 protected 109 FArrayType: TGenericArrayType; 110 function GetFieldAsString(Index: longword): string; override; 111 function GetFieldCount: longword; override; 112 function GetFieldName(Index: longword): string; override; 113 function GetFieldTypeAsString(Index: longword): string; override; 114 function IsReferenceType(index: longword): boolean; override; 115 function GetTypeAsString: string; override; 116 public 117 dimensions: array of longword; 118 itemType: TFieldType; 119 nbItems: longword; 120 constructor Create(AContainer: TDotNetDeserialization; AItemType: TFieldType; ALength: longword); overload; 121 constructor Create(AContainer: TDotNetDeserialization; AArrayType: TGenericArrayType; AItemType: TFieldType; ADimensions: arrayOfLongword); overload; 122 destructor Destroy; override; 123 property ItemPtr[Index:longword]: pointer read GetItemPtr; 124 property ItemSize: longword read FItemSize; 125 end; 126 127 { TSerializedValue } 128 129 TSerializedValue = class(TSerializedArray) 130 protected 131 function GetIsReferenceType: boolean; 132 function GetValueAsString: string; 133 function GetTypeAsString: string; override; 134 public 135 constructor Create(AContainer: TDotNetDeserialization; AItemType: TFieldType); overload; 136 property ValueAsString: string read GetValueAsString; 137 property IsReferenceType: boolean read GetIsReferenceType; 53 138 end; 54 139 … … 57 142 objectTypes: array of TSerializedType; 58 143 assemblies: array of TAssemblyReference; 59 objects: array of TSerializedObject; 60 61 function FindObject(typeName: string): PSerializedObject; 62 function GetSimpleField(obj: TSerializedObject; Name: string): string; 63 function FieldIndex(obj: TSerializedObject; Name: string): integer; 64 function GetObjectField(obj: TSerializedObject; Name: string): PSerializedObject; 65 function GetObject(id: string): PSerializedObject; 66 function GetObject(id: longword): PSerializedObject; 67 function GetObjectType(obj: PSerializedObject): string; 68 function PrimitiveTypeName(pt: TPrimitiveType): string; 69 function IsBoxedValue(obj: TSerializedObject; index: integer): boolean; 70 function GetBoxedValue(obj: TSerializedObject; index: integer): string; 71 function IsReferenceType(numType: integer; index: integer): boolean; 144 objects: array of TCustomSerializedObject; 145 146 function FindClass(typeName: string): TSerializedClass; 147 function FindObject(typeName: string): TCustomSerializedObject; 148 function GetSimpleField(obj: TCustomSerializedObject; Name: string): string; 149 function GetObjectField(obj: TCustomSerializedObject; Name: string): TCustomSerializedObject; 150 function GetObjectField(obj: TCustomSerializedObject; index: integer): TCustomSerializedObject; 151 function GetObject(id: string): TCustomSerializedObject; 152 function GetObject(id: longword): TCustomSerializedObject; 153 function IsBoxedValue(obj: TCustomSerializedObject; index: integer): boolean; 154 function GetBoxedValue(obj: TCustomSerializedObject; index: integer): string; 72 155 procedure LoadFromStream(Stream: TStream); 73 156 procedure LoadFromFile(filename: string); 74 157 function ToString: string; 75 158 constructor Create; 159 destructor Destroy; override; 160 function GetTypeOfClassObject(idObject: longword): integer; 76 161 private 77 162 EndOfStream: boolean; 78 ArrayFillerCount: integer;163 ArrayFillerCount: Longword; 79 164 currentAutoObjectValue: longword; 80 165 function nextAutoObjectId: longword; 81 166 function LoadNextFromStream(Stream: TStream): longword; 82 167 function LoadStringFromStream(Stream: TStream): string; 168 function LoadDotNetCharFromStream(Stream: TStream): string; 83 169 function LoadTypeFromStream(Stream: TStream; IsRuntimeType: boolean): integer; 84 170 function LoadValuesFromStream(Stream: TStream; numType: integer): ArrayOfNameValue; 85 function LoadValueFromStream(Stream: TStream; fieldType: TFieldType): string; 86 function GetTypeOfObject(idObject: longword): integer; 87 end; 88 171 function LoadValueFromStream(Stream: TStream; const fieldType: TFieldType): string; 172 function LoadFieldType(Stream: TStream; category: TTypeCategory): TFieldType; 173 end; 174 175 function WinReadByte(stream: TStream): byte; 89 176 function WinReadWord(Stream: TStream): word; 90 177 function WinReadSmallInt(Stream: TStream): smallint; … … 119 206 120 207 {$hints off} 208 209 function WinReadByte(stream: TStream): byte; 210 begin 211 stream.Read(Result, sizeof(Result)); 212 end; 213 121 214 function WinReadWord(Stream: TStream): word; 122 215 begin … … 155 248 end; 156 249 157 {$hints on} 158 159 { TDotNetDeserialization } 160 161 function TDotNetDeserialization.FindObject(typeName: string): PSerializedObject; 162 var 163 i, numType: integer; 164 comparedType: string; 165 begin 166 for i := 0 to high(objects) do 250 function GetFieldTypeSize(const fieldType: TFieldType): longword; 251 begin 252 case fieldType.category of 253 ftPrimitiveType: 254 case fieldType.primitiveType of 255 ptBoolean, ptByte,ptSByte: result := 1; 256 ptChar,ptString, ptDecimal: Result := sizeof(string); 257 ptSingle: result := sizeof(single); 258 ptDouble: result := sizeof(double); 259 ptInt16,ptUInt16: result := 2; 260 ptInt32,ptUInt32: result := 4; 261 ptInt64,ptUInt64,ptDateTime: result := 8; 262 else 263 raise Exception.Create('Unknown primitive type (' + IntToStr( 264 byte(fieldType.primitiveType)) + ')'); 265 end; 266 ftString, ftObjectType, ftRuntimeType, ftGenericType, ftArrayOfObject, 267 ftArrayOfString, ftArrayOfPrimitiveType: result := 4; 268 else 269 raise Exception.Create('Unknown field type (' + IntToStr( 270 byte(fieldType.category)) + ')'); 271 end; 272 end; 273 274 function IsDotNetTypeStoredAsString(const fieldType: TFieldType): boolean; 275 begin 276 result := (fieldType.category = ftPrimitiveType) and 277 (fieldType.primitiveType in [ptChar,ptString,ptDecimal]); 278 end; 279 280 function DotNetValueToString(var value; const fieldType: TFieldType): string; 281 var 282 tempByte: byte; 283 value2bytes: record 284 case byte of 285 2: (tempWord: word); 286 3: (tempInt16: smallint); 287 end; 288 value4bytes: record 289 case byte of 290 1: (tempSingle: single); 291 2: (tempLongWord: longword); 292 3: (tempLongInt: longint); 293 end; 294 value8bytes: record 295 case byte of 296 1: (tempDouble: double); 297 2: (tempInt64: Int64); 298 2: (tempUInt64: QWord); 299 end; 300 tempIdObject: longword; 301 302 begin 303 if IsDotNetTypeStoredAsString(fieldType) then 167 304 begin 168 numType := objects[i].numType; 169 if numType >= 0 then 170 begin 171 comparedType := objectTypes[numType].ClassName; 172 if (comparedType = typeName) or (length(typeName) < 173 length(comparedType)) and 174 (copy(comparedType, length(comparedType) - length(typeName), 175 length(typeName) + 1) = '.' + typeName) then 176 begin 177 Result := @objects[i]; 178 exit; 179 end; 180 end; 181 end; 182 Result := nil; 183 end; 184 185 function TDotNetDeserialization.GetSimpleField(obj: TSerializedObject; 186 Name: string): string; 187 var 188 i: integer; 189 begin 190 i := FieldIndex(obj, Name); 191 if i = -1 then 192 Result := '' 193 else 194 begin 195 if IsBoxedValue(obj, i) then 196 Result := GetBoxedValue(obj, i) 305 Result := pstring(@value)^; 306 exit; 307 end; 308 case fieldType.category of 309 ftPrimitiveType: case fieldType.primitiveType of 310 ptBoolean: 311 begin 312 {$hints off} 313 move(value,tempByte,sizeof(tempByte)); 314 {$hints on} 315 if tempByte = 0 then 316 Result := 'False' 317 else 318 if tempByte = 1 then 319 Result := 'True' 320 else 321 raise Exception.Create('Invalid boolean value (' + 322 IntToStr(tempByte) + ')'); 323 end; 324 ptByte: Result := inttostr(pbyte(@value)^); 325 ptSByte: Result := inttostr(pshortint(@value)^); 326 ptInt16,ptUInt16: 327 begin 328 {$hints off} 329 move(value, value2bytes.tempWord,sizeof(word)); 330 {$hints on} 331 value2bytes.tempWord := LEtoN(value2bytes.tempWord); 332 if fieldType.primitiveType = ptInt16 then 333 Result := IntToStr(value2bytes.tempInt16) 334 else 335 Result := IntToStr(value2bytes.tempWord); 336 end; 337 ptInt32,ptUInt32,ptSingle: 338 begin 339 {$hints off} 340 move(value, value4bytes.tempLongWord,sizeof(longword)); 341 {$hints on} 342 value4bytes.tempLongWord := LEtoN(value4bytes.tempLongWord); 343 if fieldType.primitiveType = ptInt32 then 344 Result := IntToStr(value4bytes.tempLongInt) 345 else if fieldType.primitiveType = ptUInt32 then 346 Result := IntToStr(value4bytes.tempLongWord) 347 else 348 result := FloatToStr(value4bytes.tempSingle); 349 end; 350 351 ptInt64,ptUInt64,ptDouble,ptDateTime: 352 begin 353 {$hints off} 354 move(value, value8bytes.tempUInt64,8); 355 {$hints on} 356 value8bytes.tempUInt64 := LEtoN(value8bytes.tempUInt64); 357 if fieldType.primitiveType = ptInt64 then 358 Result := IntToStr(value8bytes.tempInt64) 359 else if fieldType.primitiveType = ptUInt64 then 360 Result := IntToStr(value8bytes.tempUInt64) 361 else if fieldType.primitiveType = ptDouble then 362 result := FloatToStr(value8bytes.tempDouble) 363 else 364 Result := DateTimeToStr( 365 (value8bytes.tempUInt64 and $7FFFFFFFFFFFFFFF - 599264352000000000) / 864000000000); 366 end; 367 else 368 raise Exception.Create('Unknown primitive type (' + IntToStr( 369 byte(fieldType.primitiveType)) + ')'); 370 end; 371 ftString, ftObjectType, ftRuntimeType, ftGenericType, ftArrayOfObject, 372 ftArrayOfString, ftArrayOfPrimitiveType: 373 begin 374 {$hints off} 375 move(value,tempIdObject,sizeof(tempIdObject)); 376 {$hints on} 377 result := '#' + IntToStr(tempIdObject); 378 end; 197 379 else 198 Result := obj.fields[i].Value; 199 end; 200 end; 201 202 function TDotNetDeserialization.FieldIndex(obj: TSerializedObject; 203 Name: string): integer; 204 var 205 i: integer; 206 begin 207 //case sensitive 208 for i := 0 to high(obj.fields) do 209 if obj.fields[i].Name = Name then 210 begin 211 Result := i; 212 exit; 213 end; 214 //case insensitive 215 for i := 0 to high(obj.fields) do 216 if compareText(obj.fields[i].Name, Name) = 0 then 217 begin 218 Result := i; 219 exit; 220 end; 221 //case sensitive inner member 222 for i := 0 to high(obj.fields) do 223 if (length(Name) < length(obj.fields[i].Name)) and 224 (copy(obj.fields[i].Name, length(obj.fields[i].Name) - length(Name), 225 length(Name) + 1) = '+' + Name) then 226 begin 227 Result := i; 228 exit; 229 end; 230 //case insensitive inner member 231 for i := 0 to high(obj.fields) do 232 if (length(Name) < length(obj.fields[i].Name)) and 233 (compareText(copy(obj.fields[i].Name, length(obj.fields[i].Name) - 234 length(Name), length(Name) + 1), '+' + Name) = 0) then 235 begin 236 Result := i; 237 exit; 238 end; 239 Result := -1; 240 end; 241 242 function TDotNetDeserialization.GetObjectField(obj: TSerializedObject; 243 Name: string): PSerializedObject; 244 var 245 i: integer; 246 begin 247 i := FieldIndex(obj, Name); 248 if i = -1 then 249 Result := nil 250 else 251 begin 252 if not IsReferenceType(obj.numType, i) then 253 raise Exception.Create('GetObjectMember: Not a reference type'); 254 Result := GetObject(obj.fields[i].Value); 255 end; 256 end; 257 258 function TDotNetDeserialization.GetObject(id: string): PSerializedObject; 259 var 260 idObj: longword; 261 begin 262 if copy(id, 1, 1) = '#' then 263 Delete(id, 1, 1); 264 idObj := StrToInt(id); 265 Result := GetObject(idObj); 266 end; 267 268 function TDotNetDeserialization.GetObject(id: longword): PSerializedObject; 269 var 270 i: integer; 271 begin 272 for i := 0 to high(objects) do 273 if objects[i].idObject = id then 274 begin 275 Result := @objects[i]; 276 exit; 277 end; 278 Result := nil; 279 end; 280 281 function TDotNetDeserialization.GetObjectType(obj: PSerializedObject): string; 282 begin 283 if (obj^.numType = -btString) then 284 Result := 'String' 285 else 286 if (obj^.numType = -btArrayOfObject) then 287 Result := 'Object[]' 288 else 289 if (obj^.numType = -btArrayOfString) then 290 Result := 'String[]' 291 else 292 if (obj^.numType < 0) or (obj^.numType > high(objectTypes)) then 293 Result := '' 294 else 295 begin 296 Result := objectTypes[obj^.numType].ClassName; 297 end; 298 end; 299 300 function TDotNetDeserialization.PrimitiveTypeName(pt: TPrimitiveType): string; 380 raise Exception.Create('Unknown field type (' + IntToStr( 381 byte(fieldType.category)) + ')'); 382 end; 383 end; 384 385 function PrimitiveTypeName(pt: TPrimitiveType): string; 301 386 begin 302 387 case pt of … … 317 402 ptString: Result := 'String'; 318 403 else 319 raise Exception.Create('Unknown primitive type (' + IntToStr(byte(pt)) + ')'); 320 end; 321 end; 322 323 function TDotNetDeserialization.IsBoxedValue(obj: TSerializedObject; 404 raise Exception.Create('Unknown primitive type (' + IntToStr(integer(pt)) + ')'); 405 end; 406 end; 407 408 Function DotNetTypeToString(ft: TFieldType): string; 409 begin 410 if ft.category = ftPrimitiveType then 411 result := PrimitiveTypeName(ft.primitiveType) 412 else 413 case ft.category of 414 ftString: result := 'String'; 415 ftObjectType: result := 'Object'; 416 ftRuntimeType: result := 'RuntimeType'; 417 ftGenericType: result := 'GenericType'; 418 ftArrayOfObject: result := 'Object[]'; 419 ftArrayOfString: result := 'String[]'; 420 ftArrayOfPrimitiveType: result := 'PrimitiveType[]'; 421 else 422 raise Exception.Create('Unknown field type (' + IntToStr( 423 byte(ft.category)) + ')'); 424 end; 425 end; 426 427 { TCustomSerializedObject } 428 429 function TCustomSerializedObject.GetFieldAsString(Name: string): string; 430 begin 431 result := GetFieldAsString(GetFieldIndex(Name)); 432 end; 433 434 constructor TCustomSerializedObject.Create(container: TDotNetDeserialization); 435 begin 436 FContainer := container; 437 refCount := 0; 438 end; 439 440 function TCustomSerializedObject.GetFieldIndex(Name: string): integer; 441 var 442 i: integer; 443 fn: string; 444 begin 445 if FieldCount = 0 then 446 begin 447 result := -1; 448 exit; 449 end; 450 //case sensitive 451 for i := 0 to FieldCount-1 do 452 if FieldName[i] = Name then 453 begin 454 Result := i; 455 exit; 456 end; 457 //case insensitive 458 for i := 0 to FieldCount-1 do 459 if compareText(FieldName[i], Name) = 0 then 460 begin 461 Result := i; 462 exit; 463 end; 464 //case sensitive inner member 465 for i := 0 to FieldCount-1 do 466 begin 467 fn := FieldName[i]; 468 if (length(Name) < length(fn)) and 469 (copy(fn, length(fn) - length(Name), 470 length(Name) + 1) = '+' + Name) then 471 begin 472 Result := i; 473 exit; 474 end; 475 end; 476 //case insensitive inner member 477 for i := 0 to FieldCount-1 do 478 begin 479 fn := FieldName[i]; 480 if (length(Name) < length(fn)) and 481 (compareText(copy(fn, length(fn) - 482 length(Name), length(Name) + 1), '+' + Name) = 0) then 483 begin 484 Result := i; 485 exit; 486 end; 487 end; 488 Result := -1; 489 end; 490 491 { TSerializedClass } 492 493 function TSerializedClass.GetFieldAsString(Index: longword): string; 494 begin 495 result := fields[Index].Value; 496 end; 497 498 function TSerializedClass.GetFieldCount: longword; 499 begin 500 Result:= length(fields); 501 end; 502 503 function TSerializedClass.GetFieldName(Index: longword): string; 504 begin 505 result := fields[Index].Name; 506 end; 507 508 function TSerializedClass.GetFieldTypeAsString(Index: longword): string; 509 begin 510 result := fields[Index].valueType; 511 end; 512 513 function TSerializedClass.IsReferenceType(index: longword): boolean; 514 begin 515 Result:= FContainer.objectTypes[numType].fieldTypes[index].category <> ftPrimitiveType; 516 end; 517 518 function TSerializedClass.GetTypeAsString: string; 519 begin 520 Result:= FContainer.objectTypes[numType].ClassName; 521 end; 522 523 { TSerializedArray } 524 525 procedure TSerializedArray.InitData; 526 begin 527 FItemSize := GetFieldTypeSize(itemType); 528 getmem(data, itemSize*nbItems); 529 fillchar(data^, itemSize*nbItems, 0); 530 end; 531 532 function TSerializedArray.GetItemPtr(Index: longword): pointer; 533 begin 534 if index >= nbItems then 535 raise exception.Create('Index out of bounds'); 536 result := pointer(pbyte(data)+Index*itemsize); 537 end; 538 539 function TSerializedArray.GetFieldAsString(Index: longword): string; 540 begin 541 if data = nil then 542 result := '' 543 else 544 result := DotNetValueToString(ItemPtr[index]^, itemType); 545 end; 546 547 function TSerializedArray.GetFieldCount: longword; 548 begin 549 Result:= nbItems; 550 end; 551 552 function TSerializedArray.GetFieldName(Index: longword): string; 553 var 554 r: longword; 555 begin 556 result := '['; 557 for r := 1 to length(dimensions) do 558 begin 559 if r <> 1 then result+=','; 560 result += inttostr(index mod dimensions[r-1]); 561 index := index div dimensions[r-1]; 562 end; 563 result += ']'; 564 end; 565 566 {$hints off} 567 function TSerializedArray.GetFieldTypeAsString(Index: longword): string; 568 begin 569 Result:= DotNetTypeToString(itemType); 570 end; 571 {$hints on} 572 573 {$hints off} 574 function TSerializedArray.IsReferenceType(index: longword): boolean; 575 begin 576 Result:= itemType.category <> ftPrimitiveType; 577 end; 578 {$hints on} 579 580 function TSerializedArray.GetTypeAsString: string; 581 var 582 i: Integer; 583 begin 584 Result:= DotNetTypeToString(itemType)+'['; 585 for i := 2 to length(dimensions) do 586 result += ','; 587 result += ']'; 588 end; 589 590 constructor TSerializedArray.Create(AContainer: TDotNetDeserialization; AItemType: TFieldType; ALength: longword); 591 begin 592 inherited Create(AContainer); 593 setlength(dimensions,1); 594 dimensions[0] := ALength; 595 nbItems := ALength; 596 FArrayType := gatSingleDimension; 597 itemType := AItemType; 598 InitData; 599 end; 600 601 constructor TSerializedArray.Create(AContainer: TDotNetDeserialization; AArrayType: TGenericArrayType; AItemType: TFieldType; 602 ADimensions: arrayOfLongword); 603 var n: longword; 604 begin 605 inherited Create(AContainer); 606 setlength(dimensions, length(ADimensions)); 607 nbItems := 1; 608 if length(ADimensions) <> 0 then 609 for n := 0 to length(ADimensions)-1 do 610 begin 611 dimensions[n] := ADimensions[n]; 612 nbItems *= ADimensions[n]; 613 end; 614 FArrayType := AArrayType; 615 itemType := AItemType; 616 InitData; 617 end; 618 619 destructor TSerializedArray.Destroy; 620 var ps: PString; 621 n: longword; 622 begin 623 if IsDotNetTypeStoredAsString(itemType) and (nbItems <> 0) then 624 begin 625 ps := PString(data); 626 for n := 1 to nbItems do 627 begin 628 ps^ := ''; 629 inc(ps); 630 end; 631 end; 632 freemem(data); 633 inherited Destroy; 634 end; 635 636 { TSerializedValue } 637 638 function TSerializedValue.GetIsReferenceType: boolean; 639 begin 640 result := inherited IsReferenceType(0); 641 end; 642 643 function TSerializedValue.GetValueAsString: string; 644 begin 645 result := GetFieldAsString(0); 646 end; 647 648 function TSerializedValue.GetTypeAsString: string; 649 begin 650 Result:= GetFieldTypeAsString(0); 651 end; 652 653 constructor TSerializedValue.Create(AContainer: TDotNetDeserialization; 654 AItemType: TFieldType); 655 begin 656 inherited Create(AContainer,AItemType,1); 657 end; 658 659 {$hints on} 660 661 { TDotNetDeserialization } 662 663 function TDotNetDeserialization.FindClass(typeName: string): TSerializedClass; 664 var obj: TCustomSerializedObject; 665 begin 666 obj := FindObject(typeName); 667 if obj is TSerializedClass then 668 result := obj as TSerializedClass 669 else 670 raise exception.Create('FindClass: found object is not a class'); 671 end; 672 673 function TDotNetDeserialization.FindObject(typeName: string): TCustomSerializedObject; 674 var 675 i: integer; 676 comparedType: string; 677 begin 678 for i := 0 to high(objects) do 679 begin 680 comparedType := objects[i].TypeAsString; 681 if (comparedType = typeName) or 682 ( (length(typeName) < length(comparedType) ) and 683 (copy(comparedType, length(comparedType) - length(typeName), 684 length(typeName) + 1) = '.' + typeName) ) then 685 begin 686 Result := objects[i]; 687 exit; 688 end; 689 end; 690 Result := nil; 691 end; 692 693 function TDotNetDeserialization.GetSimpleField(obj: TCustomSerializedObject; 694 Name: string): string; 695 var 696 i,idxSlash: integer; 697 tempSub: TCustomSerializedObject; 698 begin 699 i := obj.GetFieldIndex(Name); 700 if i = -1 then 701 begin 702 idxSlash := pos('\',name); 703 if idxSlash <> 0 then 704 begin 705 tempSub := GetObjectField(obj,copy(name,1,idxSlash-1)); 706 if tempSub <> nil then 707 begin 708 result := GetSimpleField(tempSub,copy(name,idxSlash+1,length(name)-idxSlash)); 709 exit; 710 end; 711 end; 712 Result := '' 713 end 714 else 715 begin 716 if IsBoxedValue(obj, i) then 717 Result := GetBoxedValue(obj, i) 718 else 719 Result := obj.FieldAsString[i]; 720 end; 721 end; 722 723 function TDotNetDeserialization.GetObjectField(obj: TCustomSerializedObject; 724 Name: string): TCustomSerializedObject; 725 var 726 i: integer; 727 idxSlash: LongInt; 728 tempSub: TCustomSerializedObject; 729 begin 730 i := obj.GetFieldIndex(Name); 731 if i = -1 then 732 begin 733 idxSlash := pos('\',name); 734 if idxSlash <> 0 then 735 begin 736 tempSub := GetObjectField(obj,copy(name,1,idxSlash-1)); 737 if tempSub <> nil then 738 begin 739 result := GetObjectField(tempSub,copy(name,idxSlash+1,length(name)-idxSlash)); 740 exit; 741 end; 742 end; 743 Result := nil 744 end 745 else 746 begin 747 if not obj.IsReferenceType(i) then 748 raise Exception.Create('GetObjectField: Not a reference type'); 749 Result := GetObject(obj.FieldAsString[i]); 750 end; 751 end; 752 753 function TDotNetDeserialization.GetObjectField(obj: TCustomSerializedObject; 754 index: integer): TCustomSerializedObject; 755 begin 756 if not obj.IsReferenceType(index) then 757 raise Exception.Create('GetObjectField: Not a reference type'); 758 Result := GetObject(obj.FieldAsString[index]); 759 end; 760 761 function TDotNetDeserialization.GetObject(id: string): TCustomSerializedObject; 762 var 763 idObj: longword; 764 begin 765 if copy(id, 1, 1) = '#' then 766 Delete(id, 1, 1); 767 idObj := StrToInt64(id); 768 Result := GetObject(idObj); 769 end; 770 771 function TDotNetDeserialization.GetObject(id: longword): TCustomSerializedObject; 772 var 773 i: integer; 774 begin 775 for i := 0 to high(objects) do 776 if objects[i].idObject = id then 777 begin 778 Result := objects[i]; 779 exit; 780 end; 781 Result := nil; 782 end; 783 784 function TDotNetDeserialization.IsBoxedValue(obj: TCustomSerializedObject; 324 785 index: integer): boolean; 325 786 var 326 subObj: PSerializedObject;327 begin 328 if not IsReferenceType(obj.numType,index) then787 subObj: TCustomSerializedObject; 788 begin 789 if not obj.IsReferenceType(index) then 329 790 begin 330 791 Result := False; 331 792 exit; 332 793 end; 333 subObj := GetObject(obj. fields[index].Value);334 if subObj = nil then 794 subObj := GetObject(obj.FieldAsString[index]); 795 if subObj = nil then //suppose Nothing is a boxed value 335 796 begin 336 797 Result := True; 337 798 exit; 338 799 end; 339 Result := (length(subObj^.fields) = 1) and (subObj^.fields[0].Name = '');340 end; 341 342 function TDotNetDeserialization.GetBoxedValue(obj: T SerializedObject;800 Result := subObj is TSerializedValue; 801 end; 802 803 function TDotNetDeserialization.GetBoxedValue(obj: TCustomSerializedObject; 343 804 index: integer): string; 344 805 var 345 subObj: PSerializedObject;346 begin 347 if not IsReferenceType(obj.numType,index) then806 subObj: TCustomSerializedObject; 807 begin 808 if not obj.IsReferenceType(index) then 348 809 raise Exception.Create('GetBoxedValue: Not a reference type'); 349 subObj := GetObject(obj. fields[index].Value);810 subObj := GetObject(obj.FieldAsString[index]); 350 811 if subObj = nil then 351 812 begin … … 353 814 exit; 354 815 end; 355 if ( length(subObj^.fields) = 1) and (subObj^.fields[0].Name = '')then356 Result := subObj^.fields[0].Value816 if (subObj is TSerializedValue) and not (subObj as TSerializedValue).IsReferenceType then 817 Result := (subObj as TSerializedValue).ValueAsString 357 818 else 358 819 raise Exception.Create('GetBoxedValue: Not a primitive type'); 359 end;360 361 function TDotNetDeserialization.IsReferenceType(numType: integer;362 index: integer): boolean;363 begin364 if numType >= length(objectTypes) then365 raise Exception.Create('IsReferenceType: Type number out of bounds');366 367 if (numType < 0) then368 begin369 Result := (numType = -btArrayOfObject) or (numtype = -btArrayOfString);370 end371 else372 begin373 if (index < 0) or (index >= objecttypes[numType].nbFields) then374 raise Exception.Create('IsReferenceType: Index out of bounds');375 376 Result := (objecttypes[numType].fieldTypes[index].category <> ftPrimitiveType);377 end;378 820 end; 379 821 … … 433 875 subNum: integer; 434 876 objType, subExpectedType: string; 877 fieldTypeStr: string; 435 878 begin 436 879 Result := ''; … … 448 891 end; 449 892 inToString := True; 893 objType := TypeAsString; 450 894 if main then 451 895 begin 452 if numType < 0 then453 objType := ''454 else455 objType := objectTypes[numType].ClassName;456 896 Result += tab + 'Object'; 457 if refCount > 0 then 458 Result += ' #' + IntToStr(idObject); 897 Result += ' #' + IntToStr(idObject); 459 898 if (objType = '') or (objType = expectedType) then 460 899 Result += ' = ' … … 464 903 else 465 904 begin 466 objType := GetObjectType(@objects[num]);467 905 if (objType = '') or (objType = expectedType) then 468 906 Result := '' … … 477 915 subExpectedType := ''; 478 916 479 if not main and ( length(fields) = 1) and (fields[0].Name = '') then917 if not main and (objects[num] is TSerializedValue) then 480 918 begin 481 Result += fields[0].Value+ LineEnding;919 Result += (objects[num] as TSerializedValue).ValueAsString + LineEnding; 482 920 end 483 921 else 484 if ( length(fields)= 0) then922 if (FieldCount = 0) then 485 923 begin 486 924 Result += '{}' + LineEnding; … … 489 927 begin 490 928 Result += '{' + LineEnding; 491 for j := 0 to High(fields)do929 for j := 0 to FieldCount-1 do 492 930 begin 493 Result += tab + ' ' + fields[j].Name; 494 if (fields[j].valueType <> '') and (fields[j].valueType <> subExpectedType) and 495 not ((subExpectedType = '') and ((fields[j].valueType = 'Int32') or 496 (fields[j].valueType = 'Boolean'))) then 497 Result += ' As ' + fields[j].valueType; 931 Result += tab + ' ' + FieldName[j]; 932 fieldTypeStr := FieldTypeAsString[j]; 933 if (fieldTypeStr <> '') and (fieldTypeStr <> subExpectedType) and 934 not ((subExpectedType = '') and ((fieldTypeStr = 'Int32') or 935 (fieldTypeStr = 'Boolean') or (fieldTypeStr = 'Double'))) then 936 Result += ' As ' + fieldTypeStr; 498 937 Result += ' = '; 499 if not IsReferenceType(numType, j) or (copy(fields[j].Value, 1, 1) <> '#') or 500 (fields[j].Value = '#0') then 501 Result += fields[j].Value + lineending 938 if not IsReferenceType(j) then 939 Result += FieldAsString[j] + lineending 502 940 else 503 941 begin 504 subId := StrToInt(copy(fields[j].Value, 2, length(fields[j].Value) - 1)); 505 subNum := -1; 506 for k := 0 to high(objects) do 507 if (objects[k].idObject = subId) then 942 try 943 subId := StrToInt64(copy(fieldAsString[j], 2, length(fieldAsString[j]) - 1)); 944 if subId = 0 then result += 'null'+LineEnding else 508 945 begin 509 subNum := k; 510 break; 946 begin 947 subNum := -1; 948 for k := 0 to high(objects) do 949 if (objects[k].idObject = subId) then 950 begin 951 subNum := k; 952 break; 953 end; 954 end; 955 if subNum = -1 then 956 Result += '(Not found) #' + IntToStr(subId)+LineEnding 957 else 958 Result += objectToString(subNum, fieldTypeStr, tab + ' ', False); 511 959 end; 512 if subNum = -1 then 513 Result += '#' + IntToStr(subId) + '!' + LineEnding 514 else 515 Result += objectToString(subNum, fields[j].valueType, tab + ' ', False); 960 except 961 result += '!' + fieldAsString[j]+'!' +LineEnding 962 end; 516 963 end; 517 964 end; … … 541 988 end; 542 989 990 destructor TDotNetDeserialization.Destroy; 991 var 992 i: Integer; 993 begin 994 for i := 0 to high(objects) do 995 objects[i].Free; 996 inherited Destroy; 997 end; 998 999 function TDotNetDeserialization.GetTypeOfClassObject(idObject: longword 1000 ): integer; 1001 var 1002 i: Integer; 1003 begin 1004 for i := 0 to high(objects) do 1005 if objects[i].idObject = idObject then 1006 begin 1007 if objects[i] is TSerializedClass then 1008 begin 1009 result := (objects[i] as TSerializedClass).numType; 1010 exit; 1011 end 1012 else 1013 raise exception.Create('GetTypeOfClassObject: Specified object is not of class type'); 1014 end; 1015 raise exception.Create('GetTypeOfClassObject: Object not found'); 1016 end; 1017 543 1018 function TDotNetDeserialization.nextAutoObjectId: longword; 544 1019 begin … … 552 1027 idRefObject, tempIdObject: longword; 553 1028 tempType: TFieldType; 554 arrayCount, i, idx, FillZeroCount: integer; 555 tempObj: TSerializedObject; 556 tempTypeName: string; 557 tempPObj: PSerializedObject; 1029 arrayCount, arrayIndex,FillZeroCount : longword; 1030 tempAnyObj: TCustomSerializedObject; 1031 newClassObj: TSerializedClass; 1032 newValueObj: TSerializedValue; 1033 newArrayObj: TSerializedArray; 1034 genericArrayType: TGenericArrayType; 1035 genericArrayRank: longword; 1036 genericArrayDims: array of longword; 1037 genericArrayItemType: TFieldType; 1038 1039 function GetArrayCellNumber(index: longword): string; 1040 var r: longword; 1041 begin 1042 result := ''; 1043 for r := 1 to genericArrayRank do 1044 begin 1045 if r <> 1 then result+=','; 1046 result += inttostr(index mod genericArrayDims[r-1]); 1047 index := index div genericArrayDims[r-1]; 1048 end; 1049 end; 1050 558 1051 begin 559 1052 Result := 0; //idObject or zero 560 {$hints off} 561 Stream.Read(blockType, sizeof(blockType)); 562 {$hints on} 1053 blockType := WinReadByte(Stream); 563 1054 case blockType of 564 1055 … … 568 1059 with assemblies[high(assemblies)] do 569 1060 begin 570 Stream.Read(idAssembly, 4);1061 idAssembly := WinReadLongword(Stream); 571 1062 Name := LoadStringFromStream(Stream); 572 1063 end; … … 575 1066 btRuntimeObject, btExternalObject: 576 1067 begin 1068 newClassObj := TSerializedClass.Create(self); 577 1069 setlength(objects, length(objects) + 1); 578 idx := high(objects);579 with tempObj do //use temp because array address may change1070 objects[high(objects)] := newClassObj; 1071 with newClassObj do 580 1072 begin 581 refCount := 0; 582 Stream.Read(idObject, 4); 583 Result := idObject; 584 numType := LoadTypeFromStream(Stream, blockType = btRuntimeObject); 585 end; 586 objects[idx] := tempObj; 587 tempObj.fields := LoadValuesFromStream(Stream, objects[idx].numType); 588 objects[idx].fields := tempObj.fields; 1073 idObject := WinReadLongword(Stream); 1074 Result := idObject; 1075 numType := LoadTypeFromStream(Stream, blockType = btRuntimeObject); 1076 fields := LoadValuesFromStream(Stream, numType); 1077 end; 589 1078 end; 590 1079 591 1080 btRefTypeObject: 592 1081 begin 1082 newClassObj := TSerializedClass.Create(self); 593 1083 setlength(objects, length(objects) + 1); 594 idx := high(objects);595 with tempObj do //use temp because array address may change1084 objects[high(objects)] := newClassObj; 1085 with newClassObj do 596 1086 begin 597 refCount := 0;598 1087 idObject := WinReadLongword(Stream); 599 1088 Result := idObject; 600 1089 idRefObject := WinReadLongword(Stream); 601 numType := GetTypeOfObject(idRefObject); 602 end; 603 objects[idx] := tempObj; 604 tempObj.fields := LoadValuesFromStream(Stream, objects[idx].numType); 605 objects[idx].fields := tempObj.fields; 1090 numType := GetTypeOfClassObject(idRefObject); 1091 fields := LoadValuesFromStream(Stream, numType); 1092 end; 606 1093 end; 607 1094 608 1095 btString: 609 1096 begin 1097 tempType.primitiveType := ptString; 1098 tempType.category := ftPrimitiveType; 1099 tempType.Name := PrimitiveTypeName(ptString); 1100 tempType.refAssembly := 0; 1101 1102 newValueObj := TSerializedValue.Create(self,tempType); 610 1103 setlength(objects, length(objects) + 1); 611 idx := high(objects);612 with tempObj do //use temp because array address may change1104 objects[high(objects)] := newValueObj; 1105 with newValueObj do 613 1106 begin 614 refCount := 0; 615 Stream.Read(idObject, 4); 1107 idObject := WinReadLongword(Stream); 616 1108 Result := idObject; 617 numType := -blockType; 618 setlength(fields, 1); 619 fields[0].Name := ''; 620 fields[0].valueType := 'String'; 621 fields[0].Value := LoadStringFromStream(Stream); 622 end; 623 objects[idx] := tempObj; 1109 pstring(data)^ := LoadStringFromStream(Stream); 1110 end; 624 1111 end; 625 1112 … … 627 1114 begin 628 1115 try 1116 tempType.category := ftPrimitiveType; 1117 tempType.refAssembly := 0; 1118 tempType.primitiveType := TPrimitiveType(WinReadByte(stream)); 1119 tempType.Name := PrimitiveTypeName(tempType.primitiveType); 1120 1121 newValueObj := TSerializedValue.Create(self,tempType); 629 1122 setlength(objects, length(objects) + 1); 630 idx := high(objects); 631 with tempObj do //use temp because array address may change 1123 objects[high(objects)] := newValueObj; 1124 1125 with newValueObj do 632 1126 begin 633 refCount := 0;634 1127 idObject := nextAutoObjectId; 635 1128 Result := idObject; 636 numType := -blockType; 637 638 tempType.category := ftPrimitiveType; 639 tempType.refAssembly := 0; 640 Stream.Read(tempType.primitiveType, 1); 641 tempType.Name := PrimitiveTypeName(tempType.primitiveType); 642 643 setlength(fields, 1); 644 fields[0].Name := ''; 645 fields[0].Value := LoadValueFromStream(Stream, tempType); 646 fields[0].valueType := tempType.Name; 1129 1130 if IsDotNetTypeStoredAsString(tempType) then 1131 pstring(data)^ := LoadValueFromStream(Stream, tempType) 1132 else 1133 Stream.Read(data^, itemSize); 647 1134 end; 648 objects[idx] := tempObj;649 1135 except 650 1136 on ex: Exception do … … 656 1142 btObjectReference: 657 1143 begin 658 Stream.Read(Result, 4);659 temp PObj := GetObject(Result);660 if temp PObj <> nil then661 Inc(temp PObj^.refCount);1144 result := WinReadLongword(Stream); 1145 tempAnyObj := GetObject(Result); 1146 if tempAnyObj <> nil then 1147 Inc(tempAnyObj.refCount); 662 1148 end; 663 1149 … … 667 1153 begin 668 1154 try 1155 result := WinReadLongword(Stream); 1156 arrayCount := WinReadLongword(Stream); 1157 1158 tempType.category := ftPrimitiveType; 1159 tempType.refAssembly := 0; 1160 tempType.primitiveType := TPrimitiveType(WinReadByte(stream)); 1161 tempType.Name := PrimitiveTypeName(tempType.primitiveType); 1162 1163 newArrayObj := TSerializedArray.Create(self,tempType,arrayCount); 669 1164 setlength(objects, length(objects) + 1); 670 idx := high(objects);671 with tempObj do //use temp because array address may change1165 objects[high(objects)] := newArrayObj; 1166 with newArrayObj do 672 1167 begin 673 refCount := 0; 674 Stream.Read(idObject, 4); 675 Result := idObject; 676 arrayCount := WinReadLongint(Stream); 677 678 tempType.category := ftPrimitiveType; 679 tempType.refAssembly := 0; 680 Stream.Read(tempType.primitiveType, 1); 681 tempType.Name := PrimitiveTypeName(tempType.primitiveType); 682 683 setlength(fields, arrayCount); 684 for i := 0 to arrayCount - 1 do 1168 idObject := result; 1169 1170 if arrayCount <> 0 then 685 1171 begin 686 fields[i].Name := '[' + IntToStr(i) + ']'; 687 fields[i].Value := LoadValueFromStream(Stream, tempType); 688 fields[i].valueType := tempType.Name; 689 end; 690 691 setlength(objectTypes, length(objecttypes) + 1); 692 numType := high(objectTypes); 693 with objectTypes[numType] do 694 begin 695 ClassName := tempType.Name + '[]'; 696 nbFields := arrayCount; 697 setlength(fieldNames, nbFields); 698 setlength(fieldTypes, nbFields); 699 for i := 0 to arrayCount - 1 do 1172 if IsDotNetTypeStoredAsString(tempType) then 700 1173 begin 701 fieldNames[i] := fields[i].Name; 702 fieldTypes[i] := tempType; 1174 for arrayIndex := 0 to arrayCount - 1 do 1175 pstring(ItemPtr[arrayIndex])^ := LoadValueFromStream(Stream, tempType); 1176 end else 1177 begin 1178 for arrayIndex := 0 to arrayCount - 1 do 1179 stream.Read(ItemPtr[arrayIndex]^, itemSize); 703 1180 end; 704 refAssembly := 0;705 1181 end; 706 1182 end; 707 objects[idx] := tempObj;708 1183 except 709 1184 on ex: Exception do … … 713 1188 end; 714 1189 715 btArrayOfObject, 1190 btArrayOfObject,btArrayOfString: 716 1191 begin 717 1192 try 1193 result := WinReadLongword(Stream); 1194 arrayCount := WinReadLongword(Stream); 1195 1196 if blockType = btArrayOfObject then 1197 tempType.category := ftObjectType 1198 else 1199 tempType.category := ftString; 1200 1201 tempType.refAssembly := 0; 1202 tempType.primitiveType := ptNone; 1203 tempType.Name := DotNetTypeToString(tempType); 1204 1205 newArrayObj := TSerializedArray.Create(self,tempType,arrayCount); 718 1206 setlength(objects, length(objects) + 1); 719 idx := high(objects); 720 with tempObj do //use temp because array address may change 1207 objects[high(objects)] := newArrayObj; 1208 1209 with newArrayObj do 721 1210 begin 722 refCount := 0; 723 Stream.Read(idObject, 4); 724 Result := idObject; 725 numType := -blockType; 726 Stream.Read(arrayCount, 4); 727 end; 728 objects[idx] := tempObj; 729 with tempObj do 730 begin 731 setlength(fields, arrayCount); 1211 idObject:= result; 732 1212 FillZeroCount := 0; 733 if blockType = btArrayOfObject then 734 tempTypeName := 'Object' 735 else 736 tempTypeName := 'String'; 737 for i := 0 to arrayCount - 1 do 738 begin 739 fields[i].Name := '[' + IntToStr(i) + ']'; 740 fields[i].valueType := tempTypeName; 741 if FillZeroCount > 0 then 1213 if arrayCount <> 0 then 1214 for arrayIndex := 0 to arrayCount - 1 do 742 1215 begin 743 fields[i].Value := '#0';744 Dec(FillZeroCount);745 end746 else747 begin748 tempIdObject := LoadNextFromStream(Stream);749 if tempIdObject = idArrayFiller then750 begin751 tempIdObject := 0;752 FillZeroCount := ArrayFillerCount;753 ArrayFillerCount := 0;754 end;755 1216 if FillZeroCount > 0 then 756 begin 757 fields[i].Value := '#0'; 758 Dec(FillZeroCount); 759 end 1217 Dec(FillZeroCount) 760 1218 else 761 1219 begin 762 fields[i].Value := '#' + IntToStr(tempIdObject); 1220 tempIdObject := LoadNextFromStream(Stream); 1221 if tempIdObject = idArrayFiller then 1222 begin 1223 tempIdObject := 0; 1224 FillZeroCount := ArrayFillerCount; 1225 ArrayFillerCount := 0; 1226 end; 1227 if FillZeroCount > 0 then 1228 Dec(FillZeroCount) 1229 else 1230 plongword(ItemPtr[arrayIndex])^ := tempIdObject; 763 1231 end; 764 1232 end; 765 end;766 1233 end; 767 objects[idx].fields := tempObj.fields;768 1234 except 769 1235 on ex: Exception do … … 777 1243 arrayCount := 0; 778 1244 if blockType = btArrayFiller8b then 779 begin 780 Stream.Read(arrayCount, 1); 781 end 1245 arrayCount := WinReadByte(Stream) 782 1246 else 783 Stream.Read(arrayCount, 3); 784 arrayCount := LEtoN(arrayCount); 1247 arrayCount := WinReadLongWord(Stream); 785 1248 ArrayFillerCount := arraycount; 786 1249 end; 787 1250 788 1251 btGenericArray: 789 raise Exception.Create('Generic array not supported'); 1252 begin 1253 try 1254 result := WinReadLongword(Stream); 1255 genericArrayType := TGenericArrayType( WinReadByte(Stream) ); 1256 genericArrayRank := WinReadLongword(Stream); 1257 setlength(genericArrayDims,genericArrayRank); 1258 arrayCount := 0; 1259 if genericArrayRank <> 0 then 1260 for arrayIndex := 0 to genericArrayRank-1 do 1261 begin 1262 genericArrayDims[arrayIndex] := WinReadLongword(Stream); 1263 if arrayIndex=0 then 1264 arrayCount := genericArrayDims[arrayIndex] 1265 else 1266 arrayCount *= genericArrayDims[arrayIndex]; 1267 end; 1268 genericArrayItemType.category := TTypeCategory(WinReadByte(Stream)); 1269 genericArrayItemType := LoadFieldType(stream,genericArrayItemType.category); 1270 1271 newArrayObj := TSerializedArray.Create(self,genericArrayType,genericArrayItemType,genericArrayDims); 1272 setlength(objects, length(objects) + 1); 1273 objects[high(objects)] := newArrayObj; 1274 newArrayObj.idObject := result; 1275 1276 FillZeroCount := 0; 1277 if arrayCount <> 0 then 1278 for arrayIndex := 0 to arrayCount - 1 do 1279 begin 1280 if IsDotNetTypeStoredAsString(genericArrayItemType) then 1281 PString(newArrayObj.ItemPtr[arrayIndex])^ := LoadValueFromStream(Stream,genericArrayItemType) 1282 else 1283 if genericArrayItemType.category = ftPrimitiveType then 1284 Stream.Read(newArrayObj.ItemPtr[arrayIndex]^, newArrayObj.ItemSize) 1285 else 1286 begin 1287 if FillZeroCount > 0 then 1288 Dec(FillZeroCount) 1289 else 1290 begin 1291 tempIdObject := LoadNextFromStream(Stream); 1292 if tempIdObject = idArrayFiller then 1293 begin 1294 tempIdObject := 0; 1295 FillZeroCount := ArrayFillerCount; 1296 ArrayFillerCount := 0; 1297 end; 1298 if FillZeroCount > 0 then 1299 Dec(FillZeroCount) 1300 else 1301 plongword(newArrayObj.ItemPtr[arrayIndex])^ := tempIdObject; 1302 end; 1303 end; 1304 end; 1305 except 1306 on ex: Exception do 1307 raise Exception.Create('Error while reading array of object. ' + ex.Message); 1308 end; 1309 end; 790 1310 791 1311 btMethodCall, btMethodResponse: 792 raise Exception.Create('Method or not supported');1312 raise Exception.Create('Method or method response not supported'); 793 1313 794 1314 btEndOfStream: EndOfStream := True; … … 802 1322 var 803 1323 byteLength, shift: byte; 804 fullLength: longword;1324 fullLength: integer; 805 1325 utf8value: string; 806 1326 begin … … 817 1337 if Stream.Read(utf8value[1], fullLength) <> fullLength then 818 1338 raise Exception.Create('String length error'); 819 Result := Utf8ToAnsi(utf8value); 1339 Result := utf8value; 1340 end; 1341 1342 function TDotNetDeserialization.LoadDotNetCharFromStream(Stream: TStream 1343 ): string; 1344 var 1345 tempByte: byte; 1346 dataLen: Byte; 1347 utf8value: string; 1348 begin 1349 tempByte:= WinReadByte(Stream); 1350 1351 if tempByte and $80 = 0 then 1352 dataLen := 1 1353 else 1354 if tempByte and $E0 = $C0 then 1355 dataLen := 2 1356 else 1357 if tempByte and $F0 = $E0 then 1358 dataLen := 3 1359 else 1360 if tempByte and $F8 = $F0 then 1361 dataLen := 4 1362 else 1363 raise Exception.Create('Invalid UTF8 char'); 1364 1365 setlength(utf8value, dataLen); 1366 utf8value[1] := char(tempByte); 1367 Stream.Read(utf8value[2], dataLen - 1); 1368 Result := utf8value; 820 1369 end; 821 1370 … … 831 1380 begin 832 1381 ClassName := LoadStringFromStream(Stream); 833 Stream.Read(nbFields, 4);1382 nbFields := WinReadLongword(Stream); 834 1383 setlength(fieldNames, nbFields); 835 1384 setlength(fieldTypes, nbFields); … … 837 1386 fieldNames[i] := LoadStringFromStream(Stream); 838 1387 for i := 0 to nbFields - 1 do 839 Stream.Read(fieldTypes[i].category, 1);1388 fieldTypes[i].category := TTypeCategory(WinReadByte(Stream)); 840 1389 for i := 0 to nbFields - 1 do 841 begin 842 fieldTypes[i].Name := ''; 843 fieldTypes[i].refAssembly := 0; 844 fieldTypes[i].primitiveType := ptNone; 845 case fieldTypes[i].category of 846 ftPrimitiveType, ftArrayOfPrimitiveType: 847 begin 848 Stream.Read(fieldTypes[i].primitiveType, 1); 849 fieldTypes[i].Name := PrimitiveTypeName(fieldTypes[i].primitiveType); 850 if fieldTypes[i].category = ftArrayOfPrimitiveType then 851 fieldTypes[i].Name += '[]'; 852 end; 853 ftString: fieldTypes[i].Name := 'String'; 854 ftObjectType: fieldTypes[i].Name := 'Object'; 855 ftRuntimeType: fieldTypes[i].Name := LoadStringFromStream(Stream); 856 ftGenericType: 857 begin 858 fieldTypes[i].Name := LoadStringFromStream(Stream); 859 Stream.Read(fieldTypes[i].refAssembly, 4); 860 end; 861 ftArrayOfObject: fieldTypes[i].Name := 'Object[]'; 862 ftArrayOfString: fieldTypes[i].Name := 'String[]'; 863 else 864 raise Exception.Create('Unknown field type tag (' + IntToStr( 865 byte(fieldTypes[i].category)) + ')'); 866 end; 867 end; 1390 fieldTypes[i] := LoadFieldType(Stream,fieldTypes[i].category); 868 1391 if isRuntimeType then 869 1392 refAssembly := 0 870 1393 else 871 Stream.Read(refAssembly, 4);1394 refAssembly := WinReadLongword(Stream); 872 1395 end; 873 1396 except … … 906 1429 907 1430 function TDotNetDeserialization.LoadValueFromStream(Stream: TStream; 908 fieldType: TFieldType): string; 909 var 910 utf8value: string; 911 utf8len: byte; 912 tempByte: byte; 913 tempDouble: double; 914 tempSingle: single; 915 tempSByte: shortint; 916 tempUInt64: QWord; 1431 const fieldType: TFieldType): string; 1432 var 1433 data : record 1434 case byte of 1435 1: (ptr: pointer); 1436 2: (bytes: array[0..7] of byte); 1437 end; 1438 dataLen: longword; 917 1439 tempIdObject: longword; 918 1440 begin 919 1441 try 920 case fieldType.category of 921 ftPrimitiveType: case fieldType.primitiveType of 922 ptBoolean: 923 begin 924 {$hints off} 925 Stream.Read(tempByte, 1); 926 {$hints on} 927 if tempByte = 0 then 928 Result := 'False' 929 else 930 if tempByte = 1 then 931 Result := 'True' 932 else 933 raise Exception.Create('Invalid boolean value (' + 934 IntToStr(tempByte) + ')'); 935 end; 936 ptByte: 937 begin 938 {$hints off} 939 Stream.Read(tempByte, 1); 940 {$hints on} 941 Result := IntToStr(tempByte); 942 end; 943 ptChar: 944 begin 945 {$hints off} 946 Stream.Read(tempByte, 1); 947 {$hints on} 948 if tempByte and $80 = 0 then 949 utf8len := 1 950 else 951 if tempByte and $E0 = $C0 then 952 utf8len := 2 953 else 954 if tempByte and $F0 = $E0 then 955 utf8len := 3 956 else 957 if tempByte and $F8 = $F0 then 958 utf8len := 4 959 else 960 raise Exception.Create('Invalid UTF8 char'); 961 setlength(utf8value, utf8len); 962 utf8value[1] := char(tempByte); 963 Stream.Read(utf8value[2], utf8len - 1); 964 Result := Utf8ToAnsi(utf8value); 965 end; 966 ptString, ptDecimal: Result := LoadStringFromStream(Stream); 967 ptDouble: 968 begin 969 {$hints off} 970 stream.Read(tempDouble, sizeof(tempDouble)); 971 {$hints on} 972 Result := FloatToStr(tempDouble); 973 end; 974 ptInt16: 975 begin 976 Result := IntToStr(WinReadSmallInt(stream)); 977 end; 978 ptInt32: 979 begin 980 Result := IntToStr(WinReadLongInt(stream)); 981 end; 982 ptInt64: 983 begin 984 Result := IntToStr(WinReadInt64(stream)); 985 end; 986 ptSByte: 987 begin 988 {$hints off} 989 stream.Read(tempSByte, sizeof(tempSByte)); 990 {$hints on} 991 Result := IntToStr(tempSByte); 992 end; 993 ptSingle: 994 begin 995 {$hints off} 996 stream.Read(tempSingle, sizeof(tempSingle)); 997 {$hints on} 998 Result := FloatToStr(tempSingle); 999 end; 1000 ptUInt16: 1001 begin 1002 Result := IntToStr(WinReadWord(stream)); 1003 end; 1004 ptUInt32: 1005 begin 1006 Result := IntToStr(WinReadLongword(stream)); 1007 end; 1008 ptUInt64: 1009 begin 1010 Result := IntToStr(WinReadQWord(stream)); 1011 end; 1012 ptDateTime: 1013 begin 1014 tempUInt64 := WinReadQWord(stream); 1015 Result := DateTimeToStr( 1016 (tempUInt64 and $7FFFFFFFFFFFFFFF - 599264352000000000) / 864000000000); 1017 end; 1018 else 1019 raise Exception.Create('Unknown primitive type (' + IntToStr( 1020 byte(fieldType.primitiveType)) + ')'); 1442 if fieldType.Category = ftPrimitiveType then 1443 begin 1444 case fieldType.primitiveType of 1445 ptChar: Result := LoadDotNetCharFromStream(Stream); 1446 ptString, ptDecimal: Result := LoadStringFromStream(Stream); 1447 else 1448 begin 1449 dataLen := GetFieldTypeSize(fieldType); 1450 {$hints off} 1451 stream.read(data,dataLen); 1452 {$hints on} 1453 result := DotNetValueToString(data,fieldType); 1021 1454 end; 1022 ftString, ftObjectType, ftRuntimeType, ftGenericType, ftArrayOfObject, 1023 ftArrayOfString, ftArrayOfPrimitiveType: 1024 begin 1025 tempIdObject := LoadNextFromStream(stream); 1026 Result := '#' + IntToStr(tempIdObject); 1027 1028 end; 1029 else 1030 raise Exception.Create('Unknown field type (' + IntToStr( 1031 byte(fieldType.category)) + ')'); 1032 end; 1455 end; 1456 end else 1457 if fieldType.Category in [ftString, ftObjectType, ftRuntimeType, ftGenericType, ftArrayOfObject, 1458 ftArrayOfString, ftArrayOfPrimitiveType] then 1459 begin 1460 tempIdObject := LoadNextFromStream(stream); 1461 Result := '#' + IntToStr(tempIdObject); 1462 end else 1463 raise Exception.Create('Unknown field type (' + IntToStr( 1464 byte(fieldType.category)) + ')'); 1033 1465 except 1034 1466 on ex: Exception do … … 1037 1469 end; 1038 1470 1039 function TDotNetDeserialization.GetTypeOfObject(idObject: longword): integer; 1040 var 1041 i: integer; 1042 begin 1043 for i := 0 to high(objects) do 1044 if objects[i].idObject = idObject then 1045 begin 1046 Result := objects[i].numType; 1047 exit; 1048 end; 1049 raise Exception.Create('Object not found (' + IntToStr(idObject) + ')'); 1471 function TDotNetDeserialization.LoadFieldType(Stream: TStream; category: TTypeCategory 1472 ): TFieldType; 1473 begin 1474 result.category := category; 1475 result.Name := ''; 1476 result.refAssembly := 0; 1477 result.primitiveType := ptNone; 1478 case category of 1479 ftPrimitiveType, ftArrayOfPrimitiveType: 1480 begin 1481 result.primitiveType := TPrimitiveType(WinReadByte(stream)); 1482 result.Name := PrimitiveTypeName(result.primitiveType); 1483 if result.category = ftArrayOfPrimitiveType then 1484 result.Name += '[]'; 1485 end; 1486 ftString: result.Name := 'String'; 1487 ftObjectType: result.Name := 'Object'; 1488 ftRuntimeType: result.Name := LoadStringFromStream(Stream); 1489 ftGenericType: 1490 begin 1491 result.Name := LoadStringFromStream(Stream); 1492 result.refAssembly := WinReadLongword(Stream); 1493 end; 1494 ftArrayOfObject: result.Name := 'Object[]'; 1495 ftArrayOfString: result.Name := 'String[]'; 1496 else 1497 raise Exception.Create('Unknown field type tag (' + IntToStr( 1498 byte(result.category)) + ')'); 1499 end; 1050 1500 end; 1051 1501
Note:
See TracChangeset
for help on using the changeset viewer.