Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support exporting Mach-o segment via copy action #25

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions DataController.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct MVNodeSaver;
@property (nonatomic) NSString * valueStr;

+(MVColoumns *) coloumnsWithData:(NSString *)col0 :(NSString *)col1 :(NSString *)col2 :(NSString *)col3;
-(NSString *)fullString;

@end

Expand Down Expand Up @@ -95,6 +96,8 @@ struct MVNodeSaver;
@property (nonatomic) FILE * swapFile;

- (NSUInteger) rowCountToDisplay;
- (NSString *)allContents;
- (void)showAllRows;
- (MVRow *) getRowToDisplay:(NSUInteger)rowIndex;

- (void) popRow;
Expand Down
20 changes: 20 additions & 0 deletions DataController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ -(id)initWithData:(NSString *)col0 :(NSString *)col1 :(NSString *)col2 :(NSStrin
return self;
}

-(NSString *)fullString {
return [NSString stringWithFormat:@"%@ %@ %@ %@", offsetStr, dataStr, descriptionStr, valueStr];
}

//-----------------------------------------------------------------------------
+(MVColoumns *) coloumnsWithData:(NSString *)col0 :(NSString *)col1 :(NSString *)col2 :(NSString *)col3
{
Expand Down Expand Up @@ -455,6 +459,22 @@ - (NSUInteger)rowCountToDisplay
return [displayRows count];
}

- (NSString *)allContents {
NSMutableString *str = [NSMutableString new];
for(MVRow *row in displayRows) {
if (row.coloumns == nil ){
[row loadFromFile:swapFile];
}
[str appendString:row.coloumns.fullString];
[str appendString:@"\n"];
}
return str;
}

- (void)showAllRows {
NSLog(@"%@", [self allContents]);
}

//----------------------------------------------------------------------------
- (MVRow *)getRowToDisplay: (NSUInteger)rowIndex
{
Expand Down
2 changes: 2 additions & 0 deletions DataSources.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ extern NSString * const MVScannerErrorMessage;


@interface MVDataSourceDetails : NSObject;
- (NSString *)fullBinaryData:(NSTableView *)tableView;
- (NSString *)fullDetailData:(NSTableView *)tableView;
@end

220 changes: 135 additions & 85 deletions DataSources.mm
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ @implementation MVDataSourceDetails

#pragma mark NSTableView must-have delegates

- (NSInteger)numberOfBinaryRows:(MVNode *)node {
NSInteger numRows = node.dataRange.length / 16;
if (node.dataRange.length % 16 != 0)
{
++numRows;
}
return numRows;
}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
MVDocument * document = [[[aTableView window] windowController] document];
Expand All @@ -89,16 +98,11 @@ - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
// if there is no details, then provide binary dump
if (selectedNode.details == nil)
{
NSInteger numRows = selectedNode.dataRange.length / 16;
if (selectedNode.dataRange.length % 16 != 0)
{
++numRows;
}
return numRows;
return [self numberOfBinaryRows:selectedNode];
}

return selectedNode.details.rowCountToDisplay;
}

//----------------------------------------------------------------------------

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
Expand All @@ -119,87 +123,11 @@ - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColu
// if it has no details then show binary data at given range
if (selectedNode.details == nil)
{
NSUInteger offset = selectedNode.dataRange.location + rowIndex * 16;

// file offset
if (colIndex == OFFSET_COLUMN)
{
NSString * cellContent = [NSString stringWithFormat:@"%.8lX", offset];
if ([document isRVA] == YES)
{
id layout = [selectedNode.userInfo objectForKey:MVLayoutUserInfoKey];
return [layout performSelector:@selector(convertToRVA:) withObject:cellContent];
}
return cellContent;
}

// binary data
uint8_t buffer[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

NSUInteger len = MIN(selectedNode.dataRange.length - rowIndex * 16, (NSUInteger)16);

memcpy(buffer, (uint8_t *)[document.dataController.fileData bytes] + offset, len);

if (colIndex == DATA_LO_COLUMN)
{
NSUInteger index = (len > 8 ? 8 : len);

return [[NSString stringWithFormat:@"%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X ",
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]]
substringToIndex:index*3];
}

if (colIndex == DATA_HI_COLUMN)
{
NSUInteger index = (len > 8 ? len - 8 : 0);

return [[NSString stringWithFormat:@"%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X ",
buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15]]
substringToIndex:index*3];
}

// textual data (where possible)
for (NSUInteger i = 0; i < len; ++i)
{
// keep the output in ASCII
if (buffer[i] < 32 || buffer[i] > 126)
{
buffer[i] = '.';
}
}

return NSSTRING(buffer);
return [self getBinaryString:rowIndex column:colIndex doc:document];
}

// if it has descripion then show it
MVRow * row = [selectedNode.details getRowToDisplay:rowIndex];
if (row != nil)
{
NSString * cellContent = [row coloumnAtIndex:colIndex];

// special column is the offset column:
// if RVA is selected then subtitute the content on the fly
if (colIndex == OFFSET_COLUMN && [cellContent length] > 0)
{
if ([document isRVA] == YES)
{
id layout = [selectedNode.userInfo objectForKey:MVLayoutUserInfoKey];
cellContent = [layout performSelector:@selector(convertToRVA:) withObject:cellContent];
}
}

// put formatting on display text
NSColor * color = [row.attributes objectForKey:MVTextColorAttributeName];
if (color != nil)
{
NSDictionary * attributes = [NSDictionary dictionaryWithObject:color forKey:NSForegroundColorAttributeName];
return [[NSAttributedString alloc] initWithString:cellContent
attributes:attributes];
}
return cellContent;
}

return nil;
return [self getDetailString:rowIndex column:colIndex doc:document];
}
//----------------------------------------------------------------------------

Expand Down Expand Up @@ -308,6 +236,128 @@ - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTable
}
//----------------------------------------------------------------------------

#pragma mark Utils

- (NSString *)getBinaryString:(NSInteger)rowIndex column:(NSInteger)colIndex doc:(MVDocument *)document {
MVNode * selectedNode = document.dataController.selectedNode;
NSUInteger offset = selectedNode.dataRange.location + rowIndex * 16;

// file offset
if (colIndex == OFFSET_COLUMN)
{
NSString * cellContent = [NSString stringWithFormat:@"%.8lX", offset];
if ([document isRVA] == YES)
{
id layout = [selectedNode.userInfo objectForKey:MVLayoutUserInfoKey];
return [layout performSelector:@selector(convertToRVA:) withObject:cellContent];
}
return cellContent;
}

// binary data
uint8_t buffer[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

NSUInteger len = MIN(selectedNode.dataRange.length - rowIndex * 16, (NSUInteger)16);

memcpy(buffer, (uint8_t *)[document.dataController.fileData bytes] + offset, len);

if (colIndex == DATA_LO_COLUMN)
{
NSUInteger index = (len > 8 ? 8 : len);

return [[NSString stringWithFormat:@"%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X ",
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]]
substringToIndex:index*3];
}

if (colIndex == DATA_HI_COLUMN)
{
NSUInteger index = (len > 8 ? len - 8 : 0);

return [[NSString stringWithFormat:@"%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X ",
buffer[8], buffer[9], buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15]]
substringToIndex:index*3];
}

// textual data (where possible)
for (NSUInteger i = 0; i < len; ++i)
{
// keep the output in ASCII
if (buffer[i] < 32 || buffer[i] > 126)
{
buffer[i] = '.';
}
}

return NSSTRING(buffer);
}

- (id)getDetailString:(NSInteger)rowIndex column:(NSInteger)colIndex doc:(MVDocument *)document {
MVNode * selectedNode = document.dataController.selectedNode;
MVRow * row = [selectedNode.details getRowToDisplay:rowIndex];
if (row != nil)
{
NSString * cellContent = [row coloumnAtIndex:colIndex];

// special column is the offset column:
// if RVA is selected then subtitute the content on the fly
if (colIndex == OFFSET_COLUMN && [cellContent length] > 0)
{
if ([document isRVA] == YES)
{
id layout = [selectedNode.userInfo objectForKey:MVLayoutUserInfoKey];
cellContent = [layout performSelector:@selector(convertToRVA:) withObject:cellContent];
}
}

// put formatting on display text
NSColor * color = [row.attributes objectForKey:MVTextColorAttributeName];
if (color != nil)
{
NSDictionary * attributes = [NSDictionary dictionaryWithObject:color forKey:NSForegroundColorAttributeName];
return [[NSAttributedString alloc] initWithString:cellContent
attributes:attributes];
}
return cellContent;
}
return nil;
}

- (NSString *)fullBinaryData:(NSTableView *)tableView {
MVDocument * document = [[[tableView window] windowController] document];
MVNode * selectedNode = document.dataController.selectedNode;

NSInteger numRow = [self numberOfBinaryRows:selectedNode];
NSMutableString *result = [NSMutableString new];
for (NSInteger i = 0; i<numRow; ++i) {
[result appendString:
[NSString stringWithFormat:@"%@ %@ %@ %@\n",
[self getBinaryString:i column:OFFSET_COLUMN doc:document],
[self getBinaryString:i column:DATA_LO_COLUMN doc:document],
[self getBinaryString:i column:DATA_HI_COLUMN doc:document],
[self getBinaryString:i column:VALUE_COLUMN doc:document]
]
];
}
return result;
}

- (NSString *)fullDetailData:(NSTableView *)tableView {
MVDocument * document = [[[tableView window] windowController] document];
MVNode * selectedNode = document.dataController.selectedNode;

NSInteger numRow = selectedNode.details.rowCountToDisplay;
NSMutableString *result = [NSMutableString new];
for (NSInteger i = 0; i<numRow; ++i) {
[result appendString:
[NSString stringWithFormat:@"%@ %@ %@ %@\n",
[self getDetailString:i column:OFFSET_COLUMN doc:document],
[self getDetailString:i column:DATA_COLUMN doc:document],
[self getDetailString:i column:DESCRIPTION_COLUMN doc:document],
[self getDetailString:i column:VALUE_COLUMN doc:document]]
];
}
return result;
}

@end
44 changes: 38 additions & 6 deletions Document.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#import "Common.h"
#import "Document.h"
#import "DataController.h"
#import "DataSources.h"
#import "Layout.h"
#include <unistd.h>

Expand Down Expand Up @@ -49,6 +50,9 @@ - (void)mouseDown:(NSEvent *)theEvent


//============================================================================
@interface MVTable()<NSMenuItemValidation>
@end

@implementation MVTableView

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -131,6 +135,30 @@ - (void)cancelOperation:(id)sender
}
}

- (void)copy:(NSMenuItem *)menuItem {
MVDataSourceDetails *ds = self.dataSource;
if (![ds isKindOfClass:[MVDataSourceDetails class]]) {
assert(0);
return;
}

MVDocument * document = [[[self window] windowController] document];
MVNode * selectedNode = document.dataController.selectedNode;

[[NSPasteboard generalPasteboard] clearContents];
if (selectedNode.details) {
[[NSPasteboard generalPasteboard] setString:[ds fullDetailData:self] forType:NSPasteboardTypeString];
} else {
[[NSPasteboard generalPasteboard] setString:[ds fullBinaryData:self] forType:NSPasteboardTypeString];
}
}

#pragma-mark NSMenuItemValidation

- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
return YES;
}

@end

//============================================================================
Expand Down Expand Up @@ -455,18 +483,22 @@ - (void)handleThreadStateChanged:(NSNotification *)notification
{
if (OSAtomicIncrement32(&threadCount) == 1)
{
[progressIndicator setUsesThreadedAnimation:YES];
[progressIndicator startAnimation:nil];
[stopButton setHidden:NO];
dispatch_async(dispatch_get_main_queue(), ^{
[progressIndicator setUsesThreadedAnimation:YES];
[progressIndicator startAnimation:nil];
[stopButton setHidden:NO];
});
}
}
else if ([threadState isEqualToString:MVStatusTaskTerminated] == YES)
{
if (OSAtomicDecrement32(&threadCount) == 0)
{
[progressIndicator stopAnimation:nil];
[statusText setStringValue:@""];
[stopButton setHidden:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[progressIndicator stopAnimation:nil];
[statusText setStringValue:@""];
[stopButton setHidden:YES];
});
}
}
}
Expand Down
Loading