2 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 // Created: Sun Sep 07 2003
8 // Copyright: 2003 Chaz McGarvey. All rights reserved.
9 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 #import "CheatServer.h"
13 #import "SearchResults.h"
20 BOOL inline compare_float( float a
, float b
);
21 BOOL inline compare_double( double a
, double b
);
24 @implementation CheatServer
27 + (NSConnection
*)serverWithDelegate
:(id)delegate socket
:(int)sock
29 NSPort
*rPort
= [NSPort port
], *sPort
= [NSPort port
];
30 NSConnection
*connection
;
33 connection
= [[NSConnection alloc
] initWithReceivePort
:rPort sendPort
:sPort
];
34 [connection setRootObject
:delegate
];
36 array
= [NSArray arrayWithObjects
:sPort
, rPort
, [NSNumber numberWithInt
:sock
], nil];
37 [NSThread detachNewThreadSelector
:@selector(serverThread
:) toTarget
:self withObject
:array
];
39 return [connection autorelease
];
42 + (void)serverThread
:(NSArray
*)array
44 NSAutoreleasePool
*pool
= [[NSAutoreleasePool alloc
] init
];
45 NSConnection
*connection
= [NSConnection connectionWithReceivePort
:[array objectAtIndex
:0] sendPort
:[array objectAtIndex
:1]];
46 CheatServer
*object
= [[self alloc
] initWithRootProxy
:[connection rootProxy
]];
48 [object handleSocket
:[[array objectAtIndex
:2] intValue
]];
56 - (id)initWithRootProxy
:(id)proxy
58 if ( self = [super init
] )
60 NSNotificationCenter
*nc
= [[NSWorkspace sharedWorkspace
] notificationCenter
];
64 [nc addObserver
:self selector
:@selector(processListChanged
:) name
:@
"NSWorkspaceDidLaunchApplicationNotification" object
:nil];
65 [nc addObserver
:self selector
:@selector(processListChanged
:) name
:@
"NSWorkspaceDidTerminateApplicationNotification" object
:nil];
67 [self setPID
:[rootProxy serverFirstProcess
]];
71 searchResults
= [[NSMutableArray alloc
] init
];
72 searchResultsUndone
= [[NSMutableArray alloc
] init
];
79 - (void)handleSocket
:(int)sock
81 struct sockaddr identifier
;
82 int addrLen
= sizeof(identifier
);
89 if ( getpeername( sockfd
, &identifier
, &addrLen
) == -1 )
91 NSLog( @
"ERROR: getpeername() failed" );
94 if ( identifier.sa_family
== AF_INET
)
96 struct sockaddr_in addr
;
98 addrLen
= sizeof(addr
);
100 if ( getpeername( sockfd
, (struct sockaddr
*)(&addr
), &addrLen
) == -1 )
102 NSLog( @
"ERROR: getpeername() failed" );
105 if ( (addressCString
= inet_ntoa( addr.sin_addr
)) == NULL
)
107 NSLog( @
"ERROR: inet_ntoa() failed" );
110 address
= [NSString stringWithCString
:addressCString
];
114 struct sockaddr_un addr
;
116 addrLen
= sizeof(addr
);
118 if ( getpeername( sockfd
, (struct sockaddr
*)(&addr
), &addrLen
) == -1 )
120 NSLog( @
"ERROR: getpeername() failed" );
123 NSLog( @
"client connection: %s", addr.sun_path
);
125 address
= [NSString stringWithString
:@
"127.0.0.1"];
128 [rootProxy server
:self connectedWithSocket
:sockfd
];
130 [self setAddress
:address
];
131 [self setAction
:nil];
137 fd_set fdset
, master
;
150 FD_SET( sockfd
, &master
);
154 NSLog( @
"SERVER start" );
160 select( numfds
, &fdset
, NULL
, NULL
, &tv
);
162 if ( FD_ISSET( sockfd
, &fdset
) )
164 if ( (result
= ReadBuffer( sockfd
, (char *)(&header
), sizeof(header
) )) != sizeof(header
) )
169 if ( !VerifyChecksum( header.checksum
) )
171 NSLog( @
"checksum failed" );
174 if ( header.size
!= 0 )
176 if ( (data
= (char *)malloc( header.size
)) == NULL
)
178 NSLog( @
"failed to allocate buffer for reading a network packet" );
182 if ( (result
= ReadBuffer( sockfd
, data
, header.size
)) != header.size
)
184 NSLog( @
"failed to read the data of a network packet" );
190 NSLog( @
"SERVER message %i/%i/%i", header.checksum
, header.function
, header.size
);
192 switch ( header.function
)
195 [self sendProcessList
];
199 [self handleClearSearch
];
203 [self handleSearch
:data size
:header.size
];
207 [self handleChange
:data size
:header.size
];
211 [self handlePauseTarget
];
223 [self handleSetTargetPID
:data size
:header.size
];
228 if ( header.size
!= 0 )
237 NSLog( @
"SERVER close" );
239 [rootProxy serverDisconnected
:self];
243 - (void)setAddress
:(NSString
*)address
245 [rootProxy server
:self changedAddress
:address
];
248 - (void)setAction
:(NSString
*)action
252 [rootProxy server
:self changedAction
:@
"Idle"];
256 [rootProxy server
:self changedAction
:action
];
260 - (void)firstSearchString8bit
:(char const *)value size
:(int)vsize
262 kern_return_t result
;
264 vm_address_t address
= 0x0;
266 vm_region_basic_info_data_t info
;
267 mach_msg_type_number_t infoCnt
= 8;
268 mach_port_t object_name
= 0;
271 vm_size_t dataLength
;
273 TCaddress
*results
= NULL
;
274 int resultsAmount
= 0;
276 NSLog( @
"string search: %s", value
);
280 if ( (result
= vm_region( processTask
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
282 if ( result
!= KERN_INVALID_ADDRESS
)
284 NSLog( @
"vm_region returned error: %i", result
);
289 if ( (info.protection
& VM_PROT_READ
) && (info.protection
& VM_PROT_WRITE
))
291 data
= (char *)malloc( size
);
294 if ( (result
= vm_read_overwrite( processTask
, address
, size
, (vm_address_t
)data
, &dataLength
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
296 NSLog( @
"vm_read_overwrite returned error: %i", result
);
301 if ( result
== KERN_SUCCESS
)
303 int i
, top
= dataLength
- vsize
;
305 if ( (results
= realloc( results
, TCAddressSize
*resultsAmount
+ dataLength
)) == NULL
)
307 NSLog( @
"ERROR: could not expand buffer" );
311 for ( i
= 0; i
< top
; i
++ )
313 if ( strncmp( value
, data
+i
, vsize
) == 0 )
315 results
[resultsAmount
++] = (TCaddress
)address
+ i
;
326 realloc( results
, TCAddressSize
*resultsAmount
);
327 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_8_BIT data
:results amount
:resultsAmount
]];
329 NSLog( @
"found %i of %i", resultsAmount
, value
);
332 - (void)firstSearchIntegerChar
:(int8_t
)value
334 kern_return_t result
;
336 vm_address_t address
= 0x0;
338 vm_region_basic_info_data_t info
;
339 mach_msg_type_number_t infoCnt
= 8;
340 mach_port_t object_name
= 0;
343 vm_size_t dataLength
;
345 TCaddress
*results
= NULL
;
346 int resultsAmount
= 0;
350 if ( (result
= vm_region( processTask
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
352 if ( result
!= KERN_INVALID_ADDRESS
)
354 NSLog( @
"vm_region returned error: %i", result
);
359 if ( (info.protection
& VM_PROT_READ
) && (info.protection
& VM_PROT_WRITE
))
361 data
= (int8_t
*)malloc( size
);
364 if ( (result
= vm_read_overwrite( processTask
, address
, size
, (vm_address_t
)data
, &dataLength
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
366 NSLog( @
"vm_read_overwrite returned error: %i", result
);
371 if ( result
== KERN_SUCCESS
)
375 if ( (results
= (TCaddress
*)realloc( results
, TCAddressSize
*resultsAmount
+ TCAddressSize
*dataLength
)) == NULL
)
377 NSLog( @
"ERROR: could not expand buffer" );
381 for ( i
= 0; i
< dataLength
; i
++ )
383 if ( *(data
+i
) == value
)
385 results
[resultsAmount
++] = (TCaddress
)address
+ i
;
396 realloc( results
, TCAddressSize
*resultsAmount
);
397 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_8_BIT data
:results amount
:resultsAmount
]];
399 NSLog( @
"found %i of %i", resultsAmount
, value
);
402 - (void)firstSearchIntegerShort
:(int16_t
)value
404 kern_return_t result
;
406 vm_address_t address
= 0x0;
408 vm_region_basic_info_data_t info
;
409 mach_msg_type_number_t infoCnt
= 8;
410 mach_port_t object_name
= 0;
413 vm_size_t dataLength
;
415 TCaddress
*results
= NULL
;
416 int resultsAmount
= 0;
420 if ( (result
= vm_region( processTask
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
422 if ( result
!= KERN_INVALID_ADDRESS
)
424 NSLog( @
"vm_region returned error: %i", result
);
429 if ( (info.protection
& VM_PROT_READ
) && (info.protection
& VM_PROT_WRITE
))
431 data
= (int16_t
*)malloc( size
);
434 if ( (result
= vm_read_overwrite( processTask
, address
, size
, (vm_address_t
)data
, &dataLength
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
436 NSLog( @
"vm_read_overwrite returned error: %i", result
);
441 if ( result
== KERN_SUCCESS
)
443 int i
, top
= dataLength
/ sizeof(value
);
445 if ( (results
= (TCaddress
*)realloc( results
, TCAddressSize
*resultsAmount
+ 2*dataLength
)) == NULL
)
447 NSLog( @
"ERROR: could not expand buffer" );
451 for ( i
= 0; i
< top
; i
++ )
453 if ( *(data
+i
) == value
)
455 results
[resultsAmount
++] = (TCaddress
)address
+ i
* sizeof(value
);
466 realloc( results
, TCAddressSize
*resultsAmount
);
467 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_16_BIT data
:results amount
:resultsAmount
]];
469 NSLog( @
"found %i of %i", resultsAmount
, value
);
472 - (void)firstSearchIntegerLong
:(int32_t
)value
474 kern_return_t result
;
476 vm_address_t address
= 0x0;
478 vm_region_basic_info_data_t info
;
479 mach_msg_type_number_t infoCnt
= 8;
480 mach_port_t object_name
= 0;
483 vm_size_t dataLength
;
485 TCaddress
*results
= NULL
;
486 int resultsAmount
= 0;
488 unsigned zone_count
= 10;
489 vm_address_t
*zones
= (vm_address_t
*)malloc( zone_count
* sizeof(vm_address_t
) );
490 //memory_reader_t reader;
492 if ( (result
= malloc_get_all_zones( processTask
, NULL
, &zones
, &zone_count
)) != KERN_SUCCESS
)
494 NSLog( @
"malloc_get_all_zones error: %i", result
);
498 //address = zones[0];
502 for ( i = 0; i < 10; i++ )
504 NSLog( @"malloc_get_all_zones[%i] = %X", i, (vm_address_t)zones[i] );
510 if ( (result
= vm_region( processTask
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
512 if ( result
!= KERN_INVALID_ADDRESS
)
514 NSLog( @
"vm_region returned error: %i", result
);
519 if ( (info.protection
& VM_PROT_READ
) && (info.protection
& VM_PROT_WRITE
) )
521 data
= (int32_t
*)malloc( size
);
524 NSLog( @
"address: %.8X size: %i", address
, size
);
526 if ( (result
= vm_read_overwrite( processTask
, address
, size
, (vm_address_t
)data
, &dataLength
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
528 NSLog( @
"vm_read_overwrite returned error: %i", result
);
533 if ( result
== KERN_SUCCESS
)
535 int i
, top
= dataLength
/ sizeof(value
);
537 if ( (results
= (TCaddress
*)realloc( results
, TCAddressSize
*resultsAmount
+ dataLength
)) == NULL
)
539 NSLog( @
"ERROR: could not expand buffer" );
543 for ( i
= 0; i
< top
; i
++ )
545 if ( *(data
+i
) == value
)
547 results
[resultsAmount
++] = (TCaddress
)address
+ i
* sizeof(value
);
558 realloc( results
, TCAddressSize
*resultsAmount
);
559 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_32_BIT data
:results amount
:resultsAmount
]];
561 NSLog( @
"found %i of %i", resultsAmount
, value
);
565 - (void)firstSearchDecimalFloat
:(float)value
567 kern_return_t result
;
569 vm_address_t address
= 0x0;
571 vm_region_basic_info_data_t info
;
572 mach_msg_type_number_t infoCnt
= 8;
573 mach_port_t object_name
= 0;
576 vm_size_t dataLength
;
578 TCaddress
*results
= NULL
;
579 int resultsAmount
= 0;
583 if ( (result
= vm_region( processTask
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
585 if ( result
!= KERN_INVALID_ADDRESS
)
587 NSLog( @
"vm_region returned error: %i", result
);
592 if ( (info.protection
& VM_PROT_READ
) && (info.protection
& VM_PROT_WRITE
))
594 data
= (float *)malloc( size
);
597 if ( (result
= vm_read_overwrite( processTask
, address
, size
, (vm_address_t
)data
, &dataLength
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
599 NSLog( @
"vm_read_overwrite returned error: %i", result
);
604 if ( result
== KERN_SUCCESS
)
606 int i
, top
= dataLength
/ sizeof(value
);
608 if ( (results
= realloc( results
, TCAddressSize
*resultsAmount
+ dataLength
)) == NULL
)
610 NSLog( @
"ERROR: could not expand buffer" );
614 for ( i
= 0; i
< top
; i
++ )
616 if ( compare_float( *(data
+i
), value
) )
618 results
[resultsAmount
++] = (TCaddress
)address
+ i
* sizeof(value
);
629 realloc( results
, TCAddressSize
*resultsAmount
);
630 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_DECIMAL size
:SIZE_32_BIT data
:results amount
:resultsAmount
]];
632 NSLog( @
"found %i of %i", resultsAmount
, value
);
635 - (void)firstSearchDecimalDouble
:(double)value
637 kern_return_t result
;
639 vm_address_t address
= 0x0;
641 vm_region_basic_info_data_t info
;
642 mach_msg_type_number_t infoCnt
= 8;
643 mach_port_t object_name
= 0;
646 vm_size_t dataLength
;
648 TCaddress
*results
= NULL
;
649 int resultsAmount
= 0;
651 NSLog( @
"float search" );
655 if ( (result
= vm_region( processTask
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)(&info
), &infoCnt
, &object_name
)) != KERN_SUCCESS
)
657 if ( result
!= KERN_INVALID_ADDRESS
)
659 NSLog( @
"vm_region returned error: %i", result
);
664 if ( (info.protection
& VM_PROT_READ
) && (info.protection
& VM_PROT_WRITE
))
666 data
= (double *)malloc( size
);
669 if ( (result
= vm_read_overwrite( processTask
, address
, size
, (vm_address_t
)data
, &dataLength
)) != KERN_SUCCESS
&& result
!= KERN_PROTECTION_FAILURE
)
671 NSLog( @
"vm_read_overwrite returned error: %i", result
);
676 if ( result
== KERN_SUCCESS
)
678 int i
, top
= dataLength
/ sizeof(value
);
680 if ( (results
= realloc( results
, TCAddressSize
*resultsAmount
+ dataLength
)) == NULL
)
682 NSLog( @
"ERROR: could not expand buffer" );
686 for ( i
= 0; i
< top
; i
++ )
688 if ( compare_double( *(data
+i
), value
) )
690 results
[resultsAmount
++] = (TCaddress
)address
+ i
* sizeof(value
);
701 realloc( results
, TCAddressSize
*resultsAmount
);
702 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_DECIMAL size
:SIZE_64_BIT data
:results amount
:resultsAmount
]];
704 NSLog( @
"found %i of %i", resultsAmount
, value
);
708 - (void)searchString8bit
:(char const *)value size
:(int)vsize
710 kern_return_t result
;
713 vm_size_t dataLength
;
716 int resultsAmount
= 0;
718 SearchResults
*lastResults
= [searchResults lastObject
];
719 TCaddress
*lastResultsData
= [lastResults data
];
720 int i
, lastResultsAmount
= [lastResults amount
];
722 if ( [lastResults type
] != TYPE_INTEGER ||
[lastResults size
] != SIZE_8_BIT
)
724 [self sendError
:@
"This search is incompatible with the previous search." fatal
:NO
];
728 if ( (results
= (TCaddress
*)malloc( TCAddressSize
*lastResultsAmount
)) == NULL
)
730 NSLog( @
"ERROR: could not create buffer" );
732 [self sendError
:@
"The server cancelled the search because it ran out of memory." fatal
:NO
];
736 for ( i
= 0; i
< lastResultsAmount
; i
++ )
738 TCaddress address
= lastResultsData
[i
];
740 dataLength
= sizeof(data
);
742 if ( (result
= vm_read_overwrite( processTask
, address
, sizeof(data
), (vm_address_t
)(&data
), &dataLength
)) == KERN_SUCCESS
)
744 if ( data
== value
[0] )
746 results
[resultsAmount
++] = address
;
751 if ( result
!= KERN_PROTECTION_FAILURE
)
753 NSLog( @
"vm_read_overwrite returned error: %i", result
);
759 realloc( results
, TCAddressSize
*resultsAmount
);
760 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_8_BIT data
:results amount
:resultsAmount
]];
762 NSLog( @
"found %i of %i", resultsAmount
, value
);
765 - (void)searchIntegerChar
:(int8_t
)value
767 kern_return_t result
;
770 vm_size_t dataLength
;
773 int resultsAmount
= 0;
775 SearchResults
*lastResults
= [searchResults lastObject
];
776 TCaddress
*lastResultsData
= [lastResults data
];
777 int i
, lastResultsAmount
= [lastResults amount
];
779 if ( [lastResults type
] != TYPE_INTEGER ||
[lastResults size
] != SIZE_8_BIT
)
781 [self sendError
:@
"This search is incompatible with the previous search." fatal
:NO
];
785 if ( (results
= (TCaddress
*)malloc( TCAddressSize
*lastResultsAmount
)) == NULL
)
787 NSLog( @
"ERROR: could not create buffer" );
789 [self sendError
:@
"The server cancelled the search because it ran out of memory." fatal
:NO
];
793 for ( i
= 0; i
< lastResultsAmount
; i
++ )
795 TCaddress address
= lastResultsData
[i
];
797 dataLength
= sizeof(data
);
799 if ( (result
= vm_read_overwrite( processTask
, address
, sizeof(data
), (vm_address_t
)(&data
), &dataLength
)) == KERN_SUCCESS
)
803 results
[resultsAmount
++] = address
;
808 if ( result
!= KERN_PROTECTION_FAILURE
)
810 NSLog( @
"vm_read_overwrite returned error: %i", result
);
816 realloc( results
, TCAddressSize
*resultsAmount
);
817 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_8_BIT data
:results amount
:resultsAmount
]];
819 NSLog( @
"found %i of %i", resultsAmount
, value
);
822 - (void)searchIntegerShort
:(int16_t
)value
824 kern_return_t result
;
827 vm_size_t dataLength
;
830 int resultsAmount
= 0;
832 SearchResults
*lastResults
= [searchResults lastObject
];
833 TCaddress
*lastResultsData
= [lastResults data
];
834 int i
, lastResultsAmount
= [lastResults amount
];
836 if ( [lastResults type
] != TYPE_INTEGER ||
[lastResults size
] != SIZE_16_BIT
)
838 [self sendError
:@
"This search is incompatible with the previous search." fatal
:NO
];
842 if ( (results
= (TCaddress
*)malloc( TCAddressSize
*lastResultsAmount
)) == NULL
)
844 NSLog( @
"ERROR: could not create buffer" );
846 [self sendError
:@
"The server cancelled the search because it ran out of memory." fatal
:NO
];
850 for ( i
= 0; i
< lastResultsAmount
; i
++ )
852 TCaddress address
= lastResultsData
[i
];
854 dataLength
= sizeof(data
);
856 if ( (result
= vm_read_overwrite( processTask
, address
, sizeof(data
), (vm_address_t
)(&data
), &dataLength
)) == KERN_SUCCESS
)
860 results
[resultsAmount
++] = address
;
865 if ( result
!= KERN_PROTECTION_FAILURE
)
867 NSLog( @
"vm_read_overwrite returned error: %i", result
);
873 realloc( results
, TCAddressSize
*resultsAmount
);
874 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_16_BIT data
:results amount
:resultsAmount
]];
876 NSLog( @
"found %i of %i", resultsAmount
, value
);
879 - (void)searchIntegerLong
:(int32_t
)value
881 kern_return_t result
;
884 vm_size_t dataLength
;
887 int resultsAmount
= 0;
889 SearchResults
*lastResults
= [searchResults lastObject
];
890 TCaddress
*lastResultsData
= [lastResults data
];
891 int i
, lastResultsAmount
= [lastResults amount
];
893 if ( [lastResults type
] != TYPE_INTEGER ||
[lastResults size
] != SIZE_32_BIT
)
895 [self sendError
:@
"This search is incompatible with the previous search." fatal
:NO
];
899 if ( (results
= (TCaddress
*)malloc( TCAddressSize
*lastResultsAmount
)) == NULL
)
901 NSLog( @
"ERROR: could not create buffer" );
903 [self sendError
:@
"The server cancelled the search because it ran out of memory." fatal
:NO
];
907 for ( i
= 0; i
< lastResultsAmount
; i
++ )
909 TCaddress address
= lastResultsData
[i
];
911 dataLength
= sizeof(data
);
913 if ( (result
= vm_read_overwrite( processTask
, address
, sizeof(data
), (vm_address_t
)(&data
), &dataLength
)) == KERN_SUCCESS
)
917 results
[resultsAmount
++] = address
;
922 if ( result
!= KERN_PROTECTION_FAILURE
)
924 NSLog( @
"vm_read_overwrite returned error: %i", result
);
930 realloc( results
, TCAddressSize
*resultsAmount
);
931 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_INTEGER size
:SIZE_32_BIT data
:results amount
:resultsAmount
]];
933 NSLog( @
"found %i of %i", resultsAmount
, value
);
936 - (void)searchDecimalFloat
:(float)value
938 kern_return_t result
;
941 vm_size_t dataLength
;
944 int resultsAmount
= 0;
946 SearchResults
*lastResults
= [searchResults lastObject
];
947 TCaddress
*lastResultsData
= [lastResults data
];
948 int i
, lastResultsAmount
= [lastResults amount
];
950 if ( [lastResults type
] != TYPE_DECIMAL ||
[lastResults size
] != SIZE_32_BIT
)
952 [self sendError
:@
"This search is incompatible with the previous search." fatal
:NO
];
956 if ( (results
= (TCaddress
*)malloc( TCAddressSize
*lastResultsAmount
)) == NULL
)
958 NSLog( @
"ERROR: could not create buffer" );
960 [self sendError
:@
"The server cancelled the search because it ran out of memory." fatal
:NO
];
964 for ( i
= 0; i
< lastResultsAmount
; i
++ )
966 TCaddress address
= lastResultsData
[i
];
968 dataLength
= sizeof(data
);
970 if ( (result
= vm_read_overwrite( processTask
, address
, sizeof(data
), (vm_address_t
)(&data
), &dataLength
)) == KERN_SUCCESS
)
972 if ( compare_float( data
, value
) )
974 results
[resultsAmount
++] = address
;
979 if ( result
!= KERN_PROTECTION_FAILURE
)
981 NSLog( @
"vm_read_overwrite returned error: %i", result
);
987 realloc( results
, TCAddressSize
*resultsAmount
);
988 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_DECIMAL size
:SIZE_32_BIT data
:results amount
:resultsAmount
]];
990 NSLog( @
"found %i of %i", resultsAmount
, value
);
993 - (void)searchDecimalDouble
:(double)value
995 kern_return_t result
;
998 vm_size_t dataLength
;
1001 int resultsAmount
= 0;
1003 SearchResults
*lastResults
= [searchResults lastObject
];
1004 TCaddress
*lastResultsData
= [lastResults data
];
1005 int i
, lastResultsAmount
= [lastResults amount
];
1007 if ( [lastResults type
] != TYPE_DECIMAL ||
[lastResults size
] != SIZE_64_BIT
)
1009 [self sendError
:@
"This search is incompatible with the previous search." fatal
:NO
];
1013 if ( (results
= (TCaddress
*)malloc( TCAddressSize
*lastResultsAmount
)) == NULL
)
1015 NSLog( @
"ERROR: could not create buffer" );
1017 [self sendError
:@
"The server cancelled the search because it ran out of memory." fatal
:NO
];
1021 for ( i
= 0; i
< lastResultsAmount
; i
++ )
1023 TCaddress address
= lastResultsData
[i
];
1025 dataLength
= sizeof(data
);
1027 if ( (result
= vm_read_overwrite( processTask
, address
, sizeof(data
), (vm_address_t
)(&data
), &dataLength
)) == KERN_SUCCESS
)
1029 if ( compare_double( data
, value
) )
1031 results
[resultsAmount
++] = address
;
1036 if ( result
!= KERN_PROTECTION_FAILURE
)
1038 NSLog( @
"vm_read_overwrite returned error: %i", result
);
1044 realloc( results
, TCAddressSize
*resultsAmount
);
1045 [searchResults addObject
:[SearchResults resultsWithType
:TYPE_DECIMAL size
:SIZE_64_BIT data
:results amount
:resultsAmount
]];
1047 NSLog( @
"found %i of %i", resultsAmount
, value
);
1051 - (void)changeString8bit
:(char const *)value size
:(int)vsize addresses
:(TCaddress
*)addresses count
:(int)count
1056 NSLog( @
"change string: %s", value
);
1058 for ( i
= 0; i
< count
; i
++ )
1060 if ( vm_write( processTask
, (vm_address_t
)addresses
[i
], (vm_offset_t
)value
, vsize
) != KERN_SUCCESS
)
1066 if ( failCount
> 0 )
1068 [self sendError
:[NSString stringWithFormat
:@
"%i of the selected variables could not be changed.", failCount
] fatal
:NO
];
1072 - (void)changeIntegerChar
:(int8_t
)value addresses
:(TCaddress
*)addresses count
:(int)count
1077 for ( i
= 0; i
< count
; i
++ )
1079 if ( vm_write( processTask
, (vm_address_t
)addresses
[i
], (vm_offset_t
)(&value
), sizeof(value
) ) != KERN_SUCCESS
)
1085 if ( failCount
> 0 )
1087 [self sendError
:[NSString stringWithFormat
:@
"%i of the selected variables could not be changed.", failCount
] fatal
:NO
];
1091 - (void)changeIntegerShort
:(int16_t
)value addresses
:(TCaddress
*)addresses count
:(int)count
1096 for ( i
= 0; i
< count
; i
++ )
1098 if ( vm_write( processTask
, (vm_address_t
)addresses
[i
], (vm_offset_t
)(&value
), sizeof(value
) ) != KERN_SUCCESS
)
1104 if ( failCount
> 0 )
1106 [self sendError
:[NSString stringWithFormat
:@
"%i of the selected variables could not be changed.", failCount
] fatal
:NO
];
1110 - (void)changeIntegerLong
:(int32_t
)value addresses
:(TCaddress
*)addresses count
:(int)count
1115 for ( i
= 0; i
< count
; i
++ )
1117 if ( vm_write( processTask
, (vm_address_t
)addresses
[i
], (vm_offset_t
)(&value
), sizeof(value
) ) != KERN_SUCCESS
)
1123 if ( failCount
> 0 )
1125 [self sendError
:[NSString stringWithFormat
:@
"%i of the selected variables could not be changed.", failCount
] fatal
:NO
];
1129 - (void)changeDecimalFloat
:(float)value addresses
:(TCaddress
*)addresses count
:(int)count
1134 for ( i
= 0; i
< count
; i
++ )
1136 if ( vm_write( processTask
, (vm_address_t
)addresses
[i
], (vm_offset_t
)(&value
), sizeof(value
) ) != KERN_SUCCESS
)
1142 if ( failCount
> 0 )
1144 [self sendError
:[NSString stringWithFormat
:@
"%i of the selected variables could not be changed.", failCount
] fatal
:NO
];
1148 - (void)changeDecimalDouble
:(double)value addresses
:(TCaddress
*)addresses count
:(int)count
1153 for ( i
= 0; i
< count
; i
++ )
1155 if ( vm_write( processTask
, (vm_address_t
)addresses
[i
], (vm_offset_t
)(&value
), sizeof(value
) ) != KERN_SUCCESS
)
1161 if ( failCount
> 0 )
1163 [self sendError
:[NSString stringWithFormat
:@
"%i of the selected variables could not be changed.", failCount
] fatal
:NO
];
1168 - (void)sendProcessList
1170 NSArray
*processList
= [rootProxy serverProcessList
];
1176 PacketHeader header
;
1181 int length
= sizeof(u_int32_t
);
1184 u_int32_t processCount
= [processList count
];
1186 int i
, max
= processCount
;
1188 header.checksum
= RandomChecksum();
1189 header.function
= 2;
1191 for ( i
= 0; i
< max
; i
++ )
1193 pid
= [[processList objectAtIndex
:i
] objectForKey
:@
"NSApplicationProcessIdentifier"];
1194 name
= [[processList objectAtIndex
:i
] objectForKey
:@
"NSApplicationName"];
1197 length
+= sizeof(u_int32_t
) + [name length
] + 1;
1200 header.size
= length
;
1201 length
+= sizeof(header
);
1204 if ( (buffer
= (char *)malloc( length
))==NULL
)
1206 NSLog( @
"sendProcessList failed" );
1212 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
1213 COPY_TO_BUFFER( ptr
, &processCount
, sizeof(processCount
) );
1215 for ( i
= 0; i
< max
; i
++ )
1217 pidNum
= [[[processList objectAtIndex
:i
] objectForKey
:@
"NSApplicationProcessIdentifier"] unsignedLongValue
];
1218 name
= [[processList objectAtIndex
:i
] objectForKey
:@
"NSApplicationName"];
1220 COPY_TO_BUFFER( ptr
, &pidNum
, sizeof(pid
) );
1221 COPY_TO_BUFFER( ptr
, [name lossyCString
], [name length
] + 1 );
1224 lengthAfter
= length
;
1226 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
1228 NSLog( @
"sendProcessList failed" );
1235 - (void)sendSearchFinished
1237 PacketHeader header
;
1238 int length
= sizeof(header
);
1240 header.checksum
= RandomChecksum();
1241 header.function
= 6;
1244 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
1246 NSLog( @
"sendSearchFinished failed" );
1250 - (void)sendVariableList
:(TCaddress
const *)data amount
:(int)amount
1252 PacketHeader header
;
1258 header.checksum
= RandomChecksum();
1259 header.function
= 7;
1260 header.size
= sizeof(amount
) + TCAddressSize
*amount
;
1263 lengthAfter
= length
= header.size
+ sizeof(header
);
1265 if ( (buffer
= (char *)malloc( length
)) == NULL
)
1267 NSLog( @
"sendVariableList:amount: failed" );
1273 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
1274 COPY_TO_BUFFER( ptr
, &amount
, sizeof(amount
) );
1275 COPY_TO_BUFFER( ptr
, data
, TCAddressSize
*amount
);
1277 if ( SendBuffer( sockfd
, buffer
, &length
) == -1 || lengthAfter
!= length
)
1279 NSLog( @
"sendVariableList:amount: failed" );
1285 - (void)sendChangeFinished
1287 PacketHeader header
;
1288 int length
= sizeof(header
);
1290 header.checksum
= RandomChecksum();
1291 header.function
= 9;
1294 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
1296 NSLog( @
"sendChangeFinished failed" );
1300 - (void)sendError
:(NSString
*)msg fatal
:(BOOL)fatal
1302 PacketHeader header
;
1306 u_int32_t type
= (fatal
)?
1:0;
1310 header.checksum
= RandomChecksum();
1311 header.function
= 11;
1312 header.size
= sizeof(type
) + [msg length
] + 1;
1315 lengthAfter
= length
= header.size
+ sizeof(header
);
1317 if ( (buffer
= (char *)malloc( length
)) == NULL
)
1319 NSLog( @
"sendError:fatal: failed" );
1325 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
1326 COPY_TO_BUFFER( ptr
, &type
, sizeof(type
) );
1327 COPY_TO_BUFFER( ptr
, [msg lossyCString
], [msg length
] + 1 );
1329 if ( SendBuffer( sockfd
, buffer
, &length
) == -1 || lengthAfter
!= length
)
1331 NSLog( @
"sendError:fatal: failed" );
1337 - (void)sendVariableValue
:(u_int32_t
)index
1342 - (void)sendUndoFinished
1344 PacketHeader header
;
1345 int length
= sizeof(header
);
1347 header.checksum
= RandomChecksum();
1348 header.function
= 15;
1351 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
1353 NSLog( @
"sendUndoFinished failed" );
1357 - (void)sendRedoFinished
1359 PacketHeader header
;
1360 int length
= sizeof(header
);
1362 header.checksum
= RandomChecksum();
1363 header.function
= 17;
1366 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
1368 NSLog( @
"sendRedoFinished failed" );
1372 - (void)sendUndoRedoStatus
1374 PacketHeader header
;
1378 u_int32_t undoCount
= (u_int32_t
)[searchResults count
];
1379 u_int32_t redoCount
= (u_int32_t
)[searchResultsUndone count
];
1383 header.checksum
= RandomChecksum();
1384 header.function
= 19;
1385 header.size
= 2 * sizeof(u_int32_t
);
1387 length
= lengthAfter
= sizeof(header
) + header.size
;
1389 if ( (buffer
= (char *)malloc( length
)) == NULL
)
1391 NSLog( @
"sendSetTargetPID: failed" );
1396 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
1397 COPY_TO_BUFFER( ptr
, &undoCount
, sizeof(undoCount
) );
1398 COPY_TO_BUFFER( ptr
, &redoCount
, sizeof(redoCount
) );
1400 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
1402 NSLog( @
"sendUndoRedoStatus: failed" );
1408 - (void)sendAppLaunched
:(NSDictionary
*)appInfo
1410 PacketHeader header
;
1417 u_int32_t pid
= [[appInfo objectForKey
:@
"NSApplicationProcessIdentifier"] unsignedLongValue
];
1418 NSString
*name
= [appInfo objectForKey
:@
"NSApplicationName"];
1421 length
+= sizeof(u_int32_t
) + [name length
] + 1;
1423 header.checksum
= RandomChecksum();
1424 header.function
= 21;
1425 header.size
= length
;
1427 length
+= sizeof(header
);
1430 if ( (buffer
= (char *)malloc( length
))==NULL
)
1432 NSLog( @
"sendAppLaunched: failed" );
1439 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
1440 COPY_TO_BUFFER( ptr
, &pid
, sizeof(pid
) );
1441 COPY_TO_BUFFER( ptr
, [name lossyCString
], [name length
] + 1 );
1443 lengthAfter
= length
;
1445 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
1447 NSLog( @
"sendAppLaunched: failed" );
1454 - (void)sendAppQuit
:(NSDictionary
*)appInfo
1456 PacketHeader header
;
1463 u_int32_t pid
= [[appInfo objectForKey
:@
"NSApplicationProcessIdentifier"] unsignedLongValue
];
1466 length
+= sizeof(pid
);
1468 header.checksum
= RandomChecksum();
1469 header.function
= 22;
1470 header.size
= length
;
1472 length
+= sizeof(header
);
1475 if ( (buffer
= (char *)malloc( length
))==NULL
)
1477 NSLog( @
"sendAppQuit: failed" );
1484 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
1485 COPY_TO_BUFFER( ptr
, &pid
, sizeof(pid
) );
1487 lengthAfter
= length
;
1489 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
1491 NSLog( @
"sendAppQuit: failed" );
1497 - (void)sendTargetAppQuit
1499 PacketHeader header
;
1500 int length
= sizeof(header
);
1502 header.checksum
= RandomChecksum();
1503 header.function
= 23;
1506 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
1508 NSLog( @
"sendTargetAppQuit failed" );
1512 - (void)sendPauseFinished
:(BOOL)paused
1514 PacketHeader header
;
1519 int length
= sizeof(paused
);
1522 header.checksum
= RandomChecksum();
1523 header.function
= 24;
1524 header.size
= length
;
1526 length
+= sizeof(header
);
1529 if ( (buffer
= (char *)malloc( length
))==NULL
)
1531 NSLog( @
"sendPauseFinished: failed" );
1538 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
1539 COPY_TO_BUFFER( ptr
, &paused
, sizeof(paused
) );
1541 lengthAfter
= length
;
1543 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
1545 NSLog( @
"sendPauseFinished: failed" );
1552 - (void)handleClearSearch
1554 [searchResults removeAllObjects
];
1555 [searchResultsUndone removeAllObjects
];
1560 - (void)handleSearch
:(char const *)data size
:(int)dataSize
1565 char *ptr
= (char *)data
;
1567 [self setAction
:@
"Searching"];
1569 COPY_FROM_BUFFER( &type
, ptr
, sizeof(type
) );
1570 COPY_FROM_BUFFER( &size
, ptr
, sizeof(size
) );
1572 if ( ![searchResults lastObject
] )
1582 [self firstSearchString8bit
:ptr size
:(dataSize
- (ptr
- data
))];
1597 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1598 [self firstSearchIntegerChar
:value
];
1606 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1607 [self firstSearchIntegerShort
:value
];
1615 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1616 [self firstSearchIntegerLong
:value
];
1631 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1632 [self firstSearchDecimalFloat
:value
];
1640 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1641 [self firstSearchDecimalDouble
:value
];
1659 [self searchString8bit
:ptr size
:(dataSize
- (ptr
- data
))];
1675 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1676 [self searchIntegerChar
:value
];
1685 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1686 [self searchIntegerShort
:value
];
1695 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1696 [self searchIntegerLong
:value
];
1712 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1713 [self searchDecimalFloat
:value
];
1721 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1722 [self searchDecimalDouble
:value
];
1731 [self sendVariableList
:[(SearchResults
*)[searchResults lastObject
] data
] amount
:[[searchResults lastObject
] amount
]];
1732 [self sendSearchFinished
];
1733 [self sendUndoRedoStatus
];
1735 [self setAction
:nil];
1738 - (void)handleChange
:(char const *)data size
:(int)dataSize
1743 TCaddress
*addresses
= NULL
;
1746 char *ptr
= (char *)data
;
1748 [self setAction
:@
"Changing"];
1750 // read out the type and size of the variable.
1751 COPY_FROM_BUFFER( &type
, ptr
, sizeof(type
) );
1752 COPY_FROM_BUFFER( &size
, ptr
, sizeof(size
) );
1754 // read the amount of addresses.
1755 COPY_FROM_BUFFER( &count
, ptr
, sizeof(count
) );
1757 // save the pointer to the addresses.
1758 addresses
= (TCaddress
*)ptr
;
1759 ptr
+= TCAddressSize
*count
;
1769 [self changeString8bit
:ptr size
:(dataSize
- (ptr
- data
)) addresses
:addresses count
:count
];
1784 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1785 [self changeIntegerChar
:value addresses
:addresses count
:count
];
1793 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1794 [self changeIntegerShort
:value addresses
:addresses count
:count
];
1802 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1803 [self changeIntegerLong
:value addresses
:addresses count
:count
];
1818 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1819 [self changeDecimalFloat
:value addresses
:addresses count
:count
];
1827 COPY_FROM_BUFFER( &value
, ptr
, sizeof(value
) );
1828 [self changeDecimalDouble
:value addresses
:addresses count
:count
];
1836 [self sendChangeFinished
];
1838 [self setAction
:nil];
1841 - (void)handlePauseTarget
1843 if ( !processPaused
)
1847 if ( ptrace( PT_ATTACH
, processID
, 0, 0 ) != -1 )
1849 if ( waitpid( processID
, &wait_status
, WUNTRACED
) == processID
)
1851 if ( WIFSTOPPED(wait_status
) )
1853 processPaused
= YES
;
1854 [self sendPauseFinished
:YES
];
1858 NSLog( @
"ERROR: process couldn't be paused" );
1859 [self sendPauseFinished
:NO
];
1860 [self sendError
:@
"Process couldn't be paused." fatal
:NO
];
1865 NSLog( @
"ERROR: process couldn't be paused" );
1866 [self sendPauseFinished
:NO
];
1867 [self sendError
:@
"Process couldn't be paused." fatal
:NO
];
1872 NSLog( @
"ERROR: process couldn't be paused" );
1873 [self sendPauseFinished
:NO
];
1874 [self sendError
:@
"Process couldn't be paused." fatal
:NO
];
1879 ptrace( PT_DETACH
, processID
, 0, 0 );
1882 [self sendPauseFinished
:NO
];
1888 SearchResults
*results
= [searchResults lastObject
];
1892 [searchResultsUndone addObject
:results
];
1893 [searchResults removeLastObject
];
1896 results
= [searchResults lastObject
];
1899 [self sendVariableList
:[results data
] amount
:[results amount
]];
1903 [self sendVariableList
:NULL amount
:0];
1906 [self sendUndoFinished
];
1907 [self sendUndoRedoStatus
];
1912 SearchResults
*results
= [searchResultsUndone lastObject
];
1916 [searchResults addObject
:results
];
1917 [searchResultsUndone removeLastObject
];
1920 results
= [searchResults lastObject
];
1923 [self sendVariableList
:[results data
] amount
:[results amount
]];
1927 [self sendVariableList
:NULL amount
:0];
1930 [self sendRedoFinished
];
1931 [self sendUndoRedoStatus
];
1934 - (void)handleSetTargetPID
:(char const *)data size
:(int)size
1936 char *ptr
= (char *)data
;
1940 COPY_FROM_BUFFER( &pid
, ptr
, sizeof(pid
) );
1948 if ( processPaused
)
1950 [self handlePauseTarget
];
1954 - (void)setPID
:(pid_t
)pid
1956 kern_return_t result
;
1962 if ( (result
= task_for_pid( current_task(), processID
, &processTask
)) != KERN_SUCCESS
)
1964 NSLog( @
"task_for_pid returned error: %i", result
);
1973 [[[NSWorkspace sharedWorkspace
] notificationCenter
] removeObserver
:self];
1975 [searchResults release
];
1976 [searchResultsUndone release
];
1982 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983 %%%%%%%%%%%%%%%%%%%%%% NSWorkspaceDidLaunchApplicationNotification Notification
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1987 - (void)processListChanged
:(NSNotification
*)note
1989 pid_t pid
= [[[note userInfo
] objectForKey
:@
"NSApplicationProcessIdentifier"] intValue
];
1991 if ( /*pid != getpid()*/ sockfd
!= -1 )
1993 if ( [[note name
] isEqualToString
:@
"NSWorkspaceDidLaunchApplicationNotification"] )
1995 [self sendAppLaunched
:[note userInfo
]];
1999 [self sendAppQuit
:[note userInfo
]];
2001 if ( pid
== processID
)
2003 [self sendTargetAppQuit
];
2005 // we can't set the new target here because this method is not called
2006 // in the server thread. the client will have to change it.
2007 //[self setPID:[rootProxy serverFirstProcess]];
2018 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 %%%%%%%%%%%%%%%%%%%%%% Internal Functions
2020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
2023 BOOL compare_float( float a
, float b
)
2025 float const feps
= 0.0001f
;
2027 return feps
> fabsf( a
- b
);
2030 BOOL compare_double( double a
, double b
)
2032 double const deps
= 0.0000001;
2034 return deps
> fabs( a
- b
);