SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
HexFiend/HFHexTextRepresenter.m
1 //
2 // HFHexTextRepresenter.m
3 // HexFiend_2
4 //
5 // Copyright 2007 ridiculous_fish. All rights reserved.
6 //
7
8 #import <HexFiend/HFHexTextRepresenter.h>
9 #import <HexFiend/HFRepresenterHexTextView.h>
10 #import <HexFiend/HFPasteboardOwner.h>
11
12 @interface HFHexPasteboardOwner : HFPasteboardOwner {
13 NSUInteger _bytesPerColumn;
14 }
15 @property (nonatomic) NSUInteger bytesPerColumn;
16 @end
17
18 static inline unsigned char hex2char(NSUInteger c) {
19 HFASSERT(c < 16);
20 return "0123456789ABCDEF"[c];
21 }
22
23 @implementation HFHexPasteboardOwner
24
25 @synthesize bytesPerColumn = _bytesPerColumn;
26
27 - (unsigned long long)stringLengthForDataLength:(unsigned long long)dataLength {
28 if(!dataLength) return 0;
29 // -1 because no trailing space for an exact multiple.
30 unsigned long long spaces = _bytesPerColumn ? (dataLength-1)/_bytesPerColumn : 0;
31 if ((ULLONG_MAX - spaces)/2 <= dataLength) return ULLONG_MAX;
32 else return dataLength*2 + spaces;
33 }
34
35 - (void)writeDataInBackgroundToPasteboard:(NSPasteboard *)pboard ofLength:(unsigned long long)length forType:(NSString *)type trackingProgress:(id)tracker {
36 HFASSERT([type isEqual:NSStringPboardType]);
37 if(length == 0) {
38 [pboard setString:@"" forType:type];
39 return;
40 }
41 HFByteArray *byteArray = [self byteArray];
42 HFASSERT(length <= NSUIntegerMax);
43 NSUInteger dataLength = ll2l(length);
44 NSUInteger stringLength = ll2l([self stringLengthForDataLength:length]);
45 HFASSERT(stringLength < ULLONG_MAX);
46 NSUInteger offset = 0, stringOffset = 0, remaining = dataLength;
47 unsigned char * restrict const stringBuffer = check_malloc(stringLength);
48 while (remaining > 0) {
49 unsigned char dataBuffer[64 * 1024];
50 NSUInteger amountToCopy = MIN(sizeof dataBuffer, remaining);
51 NSUInteger bound = offset + amountToCopy - 1;
52 [byteArray copyBytes:dataBuffer range:HFRangeMake(offset, amountToCopy)];
53
54 if(_bytesPerColumn > 0 && offset > 0) { // ensure offset > 0 to skip adding a leading space
55 NSUInteger left = _bytesPerColumn - (offset % _bytesPerColumn);
56 if(left != _bytesPerColumn) {
57 while(left-- > 0 && offset <= bound) {
58 unsigned char c = dataBuffer[offset++];
59 stringBuffer[stringOffset] = hex2char(c >> 4);
60 stringBuffer[stringOffset + 1] = hex2char(c & 0xF);
61 stringOffset += 2;
62 }
63 }
64 if(offset <= bound)
65 stringBuffer[stringOffset++] = ' ';
66 }
67
68 if(_bytesPerColumn > 0) while(offset+_bytesPerColumn <= bound) {
69 for(NSUInteger j = 0; j < _bytesPerColumn; j++) {
70 unsigned char c = dataBuffer[offset++];
71 stringBuffer[stringOffset] = hex2char(c >> 4);
72 stringBuffer[stringOffset + 1] = hex2char(c & 0xF);
73 stringOffset += 2;
74 }
75 stringBuffer[stringOffset++] = ' ';
76 }
77
78 while (offset <= bound) {
79 unsigned char c = dataBuffer[offset++];
80 stringBuffer[stringOffset] = hex2char(c >> 4);
81 stringBuffer[stringOffset + 1] = hex2char(c & 0xF);
82 stringOffset += 2;
83 }
84
85 remaining -= amountToCopy;
86 }
87
88 NSString *string = [[NSString alloc] initWithBytesNoCopy:stringBuffer length:stringLength encoding:NSASCIIStringEncoding freeWhenDone:YES];
89 [pboard setString:string forType:type];
90 [string release];
91 }
92
93 @end
94
95 @implementation HFHexTextRepresenter
96
97 /* No extra NSCoder support needed */
98
99 - (Class)_textViewClass {
100 return [HFRepresenterHexTextView class];
101 }
102
103 - (void)initializeView {
104 [super initializeView];
105 [[self view] setBytesBetweenVerticalGuides:4];
106 unpartneredLastNybble = UCHAR_MAX;
107 omittedNybbleLocation = ULLONG_MAX;
108 }
109
110 + (NSPoint)defaultLayoutPosition {
111 return NSMakePoint(0, 0);
112 }
113
114 - (void)_clearOmittedNybble {
115 unpartneredLastNybble = UCHAR_MAX;
116 omittedNybbleLocation = ULLONG_MAX;
117 }
118
119 - (BOOL)_insertionShouldDeleteLastNybble {
120 /* Either both the omittedNybbleLocation and unpartneredLastNybble are invalid (set to their respective maxima), or neither are */
121 HFASSERT((omittedNybbleLocation == ULLONG_MAX) == (unpartneredLastNybble == UCHAR_MAX));
122 /* We should delete the last nybble if our omittedNybbleLocation is the point where we would insert */
123 BOOL result = NO;
124 if (omittedNybbleLocation != ULLONG_MAX) {
125 HFController *controller = [self controller];
126 NSArray *selectedRanges = [controller selectedContentsRanges];
127 if ([selectedRanges count] == 1) {
128 HFRange selectedRange = [selectedRanges[0] HFRange];
129 result = (selectedRange.length == 0 && selectedRange.location > 0 && selectedRange.location - 1 == omittedNybbleLocation);
130 }
131 }
132 return result;
133 }
134
135 - (BOOL)_canInsertText:(NSString *)text {
136 REQUIRE_NOT_NULL(text);
137 NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"];
138 return [text rangeOfCharacterFromSet:characterSet].location != NSNotFound;
139 }
140
141 - (void)insertText:(NSString *)text {
142 REQUIRE_NOT_NULL(text);
143 if (! [self _canInsertText:text]) {
144 /* The user typed invalid data, and we can ignore it */
145 return;
146 }
147
148 BOOL shouldReplacePriorByte = [self _insertionShouldDeleteLastNybble];
149 if (shouldReplacePriorByte) {
150 HFASSERT(unpartneredLastNybble < 16);
151 /* Prepend unpartneredLastNybble as a nybble */
152 text = [NSString stringWithFormat:@"%1X%@", unpartneredLastNybble, text];
153 }
154 BOOL isMissingLastNybble;
155 NSData *data = HFDataFromHexString(text, &isMissingLastNybble);
156 HFASSERT([data length] > 0);
157 HFASSERT(shouldReplacePriorByte != isMissingLastNybble);
158 HFController *controller = [self controller];
159 BOOL success = [controller insertData:data replacingPreviousBytes: (shouldReplacePriorByte ? 1 : 0) allowUndoCoalescing:YES];
160 if (isMissingLastNybble && success) {
161 HFASSERT([data length] > 0);
162 HFASSERT(unpartneredLastNybble == UCHAR_MAX);
163 [data getBytes:&unpartneredLastNybble range:NSMakeRange([data length] - 1, 1)];
164 NSArray *selectedRanges = [controller selectedContentsRanges];
165 HFASSERT([selectedRanges count] >= 1);
166 HFRange selectedRange = [selectedRanges[0] HFRange];
167 HFASSERT(selectedRange.location > 0);
168 omittedNybbleLocation = HFSubtract(selectedRange.location, 1);
169 }
170 else {
171 [self _clearOmittedNybble];
172 }
173 }
174
175 - (NSData *)dataFromPasteboardString:(NSString *)string {
176 REQUIRE_NOT_NULL(string);
177 return HFDataFromHexString(string, NULL);
178 }
179
180 - (void)controllerDidChange:(HFControllerPropertyBits)bits {
181 if (bits & HFControllerHideNullBytes) {
182 [[self view] setHidesNullBytes:[[self controller] shouldHideNullBytes]];
183 }
184 [super controllerDidChange:bits];
185 if (bits & (HFControllerSelectedRanges)) {
186 [self _clearOmittedNybble];
187 }
188 }
189
190 - (void)copySelectedBytesToPasteboard:(NSPasteboard *)pb {
191 REQUIRE_NOT_NULL(pb);
192 HFByteArray *selection = [[self controller] byteArrayForSelectedContentsRanges];
193 HFASSERT(selection != NULL);
194 if ([selection length] == 0) {
195 NSBeep();
196 } else {
197 HFHexPasteboardOwner *owner = [HFHexPasteboardOwner ownPasteboard:pb forByteArray:selection withTypes:@[HFPrivateByteArrayPboardType, NSStringPboardType]];
198 [owner setBytesPerLine:[self bytesPerLine]];
199 owner.bytesPerColumn = self.bytesPerColumn;
200 }
201 }
202
203 @end
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.