├── CaptureTool ├── VMBuffer.h └── main.cpp ├── ChunkedBuffer.cpp ├── ChunkedBuffer.h ├── DatabaseLocker.h ├── English.lproj ├── InfoPlist.strings └── MainMenu.xib ├── HexFiend.framework ├── Headers ├── HexFiend ├── Resources └── Versions │ ├── A │ ├── Headers │ │ ├── HFBTreeByteArray.h │ │ ├── HFByteArray.h │ │ ├── HFByteSlice.h │ │ ├── HFCancelButton.h │ │ ├── HFController.h │ │ ├── HFFileByteSlice.h │ │ ├── HFFileReference.h │ │ ├── HFFullMemoryByteArray.h │ │ ├── HFFullMemoryByteSlice.h │ │ ├── HFFunctions.h │ │ ├── HFHexTextRepresenter.h │ │ ├── HFLayoutRepresenter.h │ │ ├── HFLineCountingRepresenter.h │ │ ├── HFProgressTracker.h │ │ ├── HFRepresenter.h │ │ ├── HFSharedMemoryByteSlice.h │ │ ├── HFStatusBarRepresenter.h │ │ ├── HFStringEncodingTextRepresenter.h │ │ ├── HFTextField.h │ │ ├── HFTextRepresenter.h │ │ ├── HFTextView.h │ │ ├── HFTypes.h │ │ ├── HFVerticalScrollerRepresenter.h │ │ └── HexFiend.h │ ├── HexFiend │ └── Resources │ │ ├── HFCancelOff.tiff │ │ ├── HFCancelOn.tiff │ │ ├── HFModalProgress.nib │ │ └── Info.plist │ └── Current ├── LICENSE ├── PrettyCell.h ├── PrettyCell.m ├── README.md ├── Sniffer-Info.plist ├── Sniffer.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── SnifferCapture.h ├── SnifferCapture.mm ├── SnifferDocument.h ├── SnifferDocument.mm ├── SnifferWindowController.h ├── SnifferWindowController.mm ├── SnifferWindowController.xib ├── Sniffer_Prefix.pch ├── SpinLock.h ├── Utils.cpp ├── Utils.h ├── main.m └── schema.sql /CaptureTool/VMBuffer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #include 17 | 18 | /** 19 | * A buffer of memory requested from the kernel. This is guaranteed to be page 20 | * aligned, but cannot be shrunk. 21 | */ 22 | template 23 | class VMBuffer { 24 | public: 25 | VMBuffer(size_t initialSize = PAGE_SIZE) { 26 | Grow(initialSize); 27 | } 28 | 29 | ~VMBuffer() { 30 | vm_deallocate(mach_task_self(), mData, mSize); 31 | } 32 | 33 | /** 34 | * Expands the buffer to contain at least `newSize` bytes. 35 | * 36 | * This function has several side effects and limitations: 37 | * - the existing data pointer will be invalidated 38 | * - the new buffer is not guaranteed to be zeroed 39 | * - data will not be copied from the old buffer 40 | * 41 | * @param newSize The number of bytes the buffer needs to hold. 42 | */ 43 | void Grow(size_t newSize) { 44 | if (mSize >= newSize) return; 45 | 46 | if (mData) 47 | vm_deallocate(mach_task_self(), mData, mSize); 48 | 49 | // Make sure that the requested amount of memory is page aligned. 50 | newSize += newSize % PAGE_SIZE; 51 | 52 | if (vm_allocate(mach_task_self(), &mData, newSize, VM_FLAGS_ANYWHERE) == 0) { 53 | mSize = newSize; 54 | } else { 55 | assert(0); 56 | } 57 | } 58 | 59 | T& operator[] (off_t offset) { 60 | assert(offset * sizeof(T) < mSize); 61 | return reinterpret_cast(mData)[offset]; 62 | } 63 | 64 | /** 65 | * The allocated size of the buffer. This may be larger than the size requested 66 | * by Grow(). 67 | */ 68 | size_t Size() const { 69 | return mSize; 70 | } 71 | 72 | /** 73 | * The underlying data pointer. 74 | */ 75 | T * Data() { 76 | return reinterpret_cast(mData); 77 | } 78 | 79 | private: 80 | vm_size_t mSize; 81 | vm_address_t mData; 82 | }; 83 | 84 | -------------------------------------------------------------------------------- /CaptureTool/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "VMBuffer.h" 23 | #include "Utils.h" 24 | 25 | #define INVALID_PID -1 26 | 27 | static CFMessagePortRef gMessagePort; 28 | 29 | /** 30 | * Determines which process has a socket with the given endpoints. This returns 31 | * the first process found, or INVALID_PID upon failure. 32 | * 33 | * CURRENTLY ONLY HANDLES TCP/IPv4 PACKETS! 34 | */ 35 | pid_t PIDForEndpoints(in_addr_t sourceAddress, int sourcePort, in_addr_t destAddress, int destPort) { 36 | // We need to call proc_listpids once to get the size of the required buffer, 37 | // then again to get the actual list. 38 | static VMBuffer pidBuffer; 39 | pidBuffer.Grow(proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)); 40 | int pidCount = proc_listpids(PROC_ALL_PIDS, 0, pidBuffer.Data(), pidBuffer.Size()) / sizeof(pid_t); 41 | 42 | for(int i = 0; i < pidCount; i++) { 43 | pid_t pid = pidBuffer[i]; 44 | 45 | // We need to call proc_pidinfo once to get the size of the required buffer, 46 | // then again to get the actual list. 47 | static VMBuffer fdBuffer; 48 | fdBuffer.Grow(proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0)); 49 | int fdCount = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdBuffer.Data(), fdBuffer.Size()) / sizeof(struct proc_fdinfo); 50 | 51 | for(int j = 0; j < fdCount; j++) { 52 | // only interested in sockets 53 | if(fdBuffer[j].proc_fdtype != PROX_FDTYPE_SOCKET) continue; 54 | 55 | // get the socket's info 56 | socket_fdinfo finfo; 57 | proc_pidfdinfo(pid, fdBuffer[j].proc_fd, PROC_PIDFDSOCKETINFO, &finfo, sizeof(finfo)); 58 | 59 | // figure out this file's endpoints (holy nesting!) 60 | int fdDestPort = finfo.psi.soi_proto.pri_in.insi_fport; 61 | in_addr_t fdDestAddress = finfo.psi.soi_proto.pri_in.insi_faddr.ina_46.i46a_addr4.s_addr; 62 | int fdSourcePort = finfo.psi.soi_proto.pri_in.insi_lport; 63 | in_addr_t fdSourceAddress = finfo.psi.soi_proto.pri_in.insi_laddr.ina_46.i46a_addr4.s_addr; 64 | 65 | // see if this is our guy 66 | if((sourceAddress == fdSourceAddress && sourcePort == fdSourcePort && destAddress == fdDestAddress && destPort == fdDestPort) || 67 | (sourceAddress == fdDestAddress && sourcePort == fdDestPort && destAddress == fdSourceAddress && destPort == fdSourcePort)) { 68 | return pid; 69 | } 70 | 71 | } 72 | } 73 | 74 | return INVALID_PID; 75 | } 76 | 77 | /** 78 | * Sends information that has been gathered about a packet to the GUI tool on the 79 | * other end of our CFMesssagePort. 80 | * 81 | * The format is: 82 | * - pcap_pkthdr 83 | * - packet data 84 | * - application path 85 | */ 86 | static void SendPacketData(const char *appPath, const struct pcap_pkthdr *packHead, const u_char *packData) 87 | { 88 | static SInt32 msgid; 89 | static VMBuffer messageBuffer; 90 | messageBuffer.Grow(sizeof(pcap_pkthdr) + packHead->caplen + strlen(appPath) + 1); 91 | 92 | UInt8 *pos = messageBuffer.Data(); 93 | memcpy(pos, packHead, sizeof(pcap_pkthdr)); 94 | pos += sizeof(pcap_pkthdr); 95 | 96 | memcpy(pos, packData, packHead->caplen); 97 | pos += packHead->caplen; 98 | 99 | memcpy(pos, appPath, strlen(appPath) + 1); 100 | pos += strlen(appPath) + 1; 101 | 102 | CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, messageBuffer.Data(), pos - messageBuffer.Data(), kCFAllocatorNull); 103 | CFMessagePortSendRequest(gMessagePort, msgid++, data, -1, -1, NULL, NULL); 104 | CFRelease(data); 105 | } 106 | 107 | /** 108 | * The libpcap callback function. Invoked every time a packet is sent/received. 109 | */ 110 | void Handler(u_char *one, const struct pcap_pkthdr *packHead, const u_char *packData) { 111 | const struct ether_header *etherHeader = (const struct ether_header *)packData; 112 | const struct ip *ipHeader = (const struct ip *)(etherHeader + 1); 113 | 114 | // we can only find endpoints for TCP sockets for now 115 | if(IPPROTO_TCP == ipHeader->ip_p) { 116 | const struct tcphdr *tcpHeader = (const struct tcphdr *)(ipHeader + 1); 117 | 118 | // try to find our pid 119 | pid_t owningProcess = PIDForEndpoints(ipHeader->ip_src.s_addr, tcpHeader->th_sport, ipHeader->ip_dst.s_addr, tcpHeader->th_dport); 120 | 121 | // did we find it? 122 | if(INVALID_PID != owningProcess) { 123 | // grab the path 124 | char processPath[MAXPATHLEN] = {}; 125 | proc_pidpath(owningProcess, processPath, sizeof(processPath)); 126 | 127 | SendPacketData(processPath, packHead, packData); 128 | return; 129 | } else { 130 | SendPacketData("(unknown TCP)", packHead, packData); 131 | return; 132 | } 133 | } 134 | 135 | SendPacketData("(unknown other)", packHead, packData); 136 | } 137 | 138 | bool SetupCapture(const char *interface) { 139 | pcap_t *handle = pcap_open_live(interface, BUFSIZ, 1, 2, NULL); 140 | if (handle == NULL) return false; 141 | 142 | // We can't run this on the main thread because it'll block, so we need to 143 | // set it up on a background thread. I tried quite a bit to get this running 144 | // under a CFRunloop using CFFileDescriptorRef, but it just wouldn't work. 145 | // 146 | // If I ran it under libdispach directly, it worked fine (I think), but then 147 | // I couldn't get notifications about the message port being invalidated. 148 | RunBlockThreaded(^(void) { 149 | pcap_loop(handle, -1, Handler, NULL); 150 | pcap_close(handle); 151 | }); 152 | 153 | return true; 154 | } 155 | 156 | void MessagePortClosed(CFMessagePortRef ms, void *info) { 157 | // FIXME: we should think about how this process should gracefully shut down. 158 | // Currently this doesn't kill the capture thread we set up or allow pcap_close 159 | // to run. 160 | // 161 | // I doubt it matters though. 162 | CFRunLoopStop(CFRunLoopGetCurrent()); 163 | } 164 | 165 | int main(int argc, char *argv[]) { 166 | // The name of the message port we're supposed to be connecting to will be the 167 | // first argument passed to the program. If it's invalid or not specified, 168 | // this is a critical error and we must abort the process. 169 | if (argc >= 2) { 170 | CFStringRef portName = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8); 171 | gMessagePort = CFMessagePortCreateRemote(NULL, portName); 172 | CFRelease(portName); 173 | 174 | if (!gMessagePort) return 1; 175 | } 176 | 177 | // FIXME: don't hardcode "en1". Instead we should probably have it passed 178 | // to us in argv. 179 | if (SetupCapture("en1")) { 180 | // We need to get notified when this message port gets invalidated because 181 | // this is our signal by the parent process that capturing needs to stop. 182 | // 183 | // Since we're in CF-land and not using Mach ports directly, we need a 184 | // CFRunLoop and not dispatch_main. 185 | CFMessagePortSetInvalidationCallBack(gMessagePort, MessagePortClosed); 186 | CFRunLoopRun(); 187 | return 0; 188 | } 189 | 190 | return 1; 191 | } 192 | -------------------------------------------------------------------------------- /ChunkedBuffer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | 17 | #include "ChunkedBuffer.h" 18 | #include 19 | 20 | ChunkedBuffer::ChunkedBuffer(size_t chunkSize) : 21 | mChunkSize(chunkSize), 22 | mCurrentOffset(0) 23 | { 24 | mChunks.push_back(CheckedAlloc(chunkSize)); 25 | } 26 | 27 | ChunkedBuffer::~ChunkedBuffer() 28 | { 29 | for (int i = 0; i < mChunks.size(); i++) { 30 | free(mChunks[i]); 31 | } 32 | } 33 | 34 | void ChunkedBuffer::AppendBytes(const void *bytes, size_t length) 35 | { 36 | while (length > mChunkSize - mCurrentOffset) { 37 | // Copy what will fit into the current chunk 38 | size_t available = mChunkSize - mCurrentOffset; 39 | memcpy(mChunks.back(), bytes, available); 40 | 41 | // Advance past the bytes we just wrote 42 | bytes = (char *)bytes + available; 43 | length -= available; 44 | 45 | // And add a new chunk to our buffer to hold what's left of this data 46 | mChunks.push_back(CheckedAlloc(mChunkSize)); 47 | mCurrentOffset = 0; 48 | } 49 | 50 | memcpy(mChunks.back() + mCurrentOffset, bytes, length); 51 | mCurrentOffset += length; 52 | } 53 | 54 | void ChunkedBuffer::CopyBytes(off_t offset, size_t length, void *outBuffer) const 55 | { 56 | char *resultPtr = (char *)outBuffer; 57 | 58 | while (length) { 59 | int chunk = offset / mChunkSize; 60 | int readOffset = offset % mChunkSize; 61 | int readSize = std::min(length, mChunkSize - readOffset); 62 | 63 | memcpy(resultPtr, mChunks[chunk] + readOffset, readSize); 64 | 65 | offset = 0; 66 | resultPtr += readSize; 67 | length -= readSize; 68 | } 69 | } 70 | 71 | size_t ChunkedBuffer::Length() const 72 | { 73 | return (mChunks.size() - 1) * mChunkSize + mCurrentOffset; 74 | } 75 | 76 | char * ChunkedBuffer::CheckedAlloc(size_t size) 77 | { 78 | char *result = (char *)malloc(size); 79 | assert(result); 80 | return result; 81 | } 82 | -------------------------------------------------------------------------------- /ChunkedBuffer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #include 17 | #include 18 | 19 | /** 20 | * A memory buffer that can grow to arbitrary sizes without paying the cost of 21 | * copying all of the data every time the buffer needs to grow. This is achieved 22 | * by spreading the data across various chunks of memory that are allocated on 23 | * demand. 24 | */ 25 | class ChunkedBuffer { 26 | public: 27 | ChunkedBuffer(size_t chunkSize); 28 | ~ChunkedBuffer(); 29 | 30 | /** 31 | * Appends a series of bytes to this memory buffer. 32 | * 33 | * @param bytes - the bytes to append 34 | * @param length - the number of bytes to append 35 | */ 36 | void AppendBytes(const void *bytes, size_t length); 37 | 38 | /** 39 | * The number of bytes that have been added to the buffer. 40 | */ 41 | size_t Length() const; 42 | 43 | /** 44 | * Copies bytes from this buffer into another buffer. 45 | * 46 | * @param offset - the offset into this buffer 47 | * @param length - the number of bytes to copy 48 | * @param outBuffer - the buffer to copy into 49 | */ 50 | void CopyBytes(off_t offset, size_t length, void *outBuffer) const; 51 | 52 | private: 53 | ChunkedBuffer(const ChunkedBuffer &other); 54 | ChunkedBuffer& operator= (const ChunkedBuffer &other); 55 | 56 | static char * CheckedAlloc(size_t size); 57 | 58 | size_t mChunkSize; 59 | off_t mCurrentOffset; 60 | std::vector mChunks; 61 | }; 62 | -------------------------------------------------------------------------------- /DatabaseLocker.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #pragma once 17 | #import "SnifferDocument.h" 18 | 19 | class DatabaseLocker { 20 | public: 21 | DatabaseLocker(SnifferDocument *document) : 22 | mDocument([document retain]) 23 | { 24 | mDatabase = [document acquireDatabase]; 25 | } 26 | 27 | ~DatabaseLocker() 28 | { 29 | [mDocument releaseDatabase]; 30 | [mDocument release]; 31 | } 32 | 33 | sqlite3 * Database() 34 | { 35 | return mDatabase; 36 | } 37 | 38 | private: 39 | SnifferDocument *mDocument; 40 | sqlite3 *mDatabase; 41 | }; 42 | -------------------------------------------------------------------------------- /English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /HexFiend.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /HexFiend.framework/HexFiend: -------------------------------------------------------------------------------- 1 | Versions/Current/HexFiend -------------------------------------------------------------------------------- /HexFiend.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFBTreeByteArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFBTreeByteArray.h 3 | // HexFiend_2 4 | // 5 | // Created by peter on 4/28/09. 6 | // Copyright 2009 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class HFBTree; 12 | 13 | /*! @class HFBTreeByteArray 14 | @brief The principal efficient implementation of HFByteArray. 15 | 16 | HFBTreeByteArray is an efficient subclass of HFByteArray that stores @link HFByteSlice HFByteSlices@endlink, using a 10-way B+ tree. This allows for insertion, deletion, and searching in approximately log-base-10 time. 17 | 18 | Create an HFBTreeByteArray via \c -init. It has no methods other than those on HFByteArray. 19 | */ 20 | 21 | @interface HFBTreeByteArray : HFByteArray { 22 | @private 23 | HFBTree *btree; 24 | } 25 | 26 | /*! Designated initializer for HFBTreeByteArray. 27 | */ 28 | - init; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFByteArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFByteArray.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/4/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class HFByteSlice, HFProgressTracker, HFFileReference; 12 | 13 | /*! @class HFByteArray 14 | @brief The principal Model class for HexFiend's MVC architecture. 15 | 16 | HFByteArray implements the Model portion of HexFiend.framework. It is logically a mutable, resizable array of bytes, with a 64 bit length. It is somewhat analagous to a 64 bit version of NSMutableData, except that it is designed to enable efficient (faster than O(n)) implementations of insertion and deletion. 17 | 18 | HFByteArray, being an abstract class, will raise an exception if you attempt to instantiate it directly. For most uses, instantiate HFBTreeByteArray instead, with the usual [[class alloc] init]. 19 | 20 | HFByteArray also exposes itself as an array of @link HFByteSlice HFByteSlices@endlink, which are logically immutable arrays of bytes. which is useful for operations such as file saving that need to access the underlying byte slices. 21 | 22 | HFByteArray contains a generation count, which is incremented whenever the HFByteArray changes (to allow caches to be implemented on top of it). It also includes the notion of locking: a locked HFByteArray will raise an exception if written to, but it may still be read. 23 | 24 | ByteArrays have the usual threading restrictions for non-concurrent data structures. It is safe to read an HFByteArray concurrently from multiple threads. It is not safe to read an HFByteArray while it is being modified from another thread, nor is it safe to modify one simultaneously from two threads. 25 | 26 | HFByteArray is an abstract class. It will raise an exception if you attempt to instantiate it directly. The principal concrete subclass is HFBTreeByteArray. 27 | */ 28 | 29 | enum 30 | { 31 | HFHexDataStringType, 32 | HFASCIIDataStringType 33 | }; 34 | typedef NSUInteger HFByteArrayDataStringType; 35 | 36 | @interface HFByteArray : NSObject { 37 | @private 38 | NSUInteger changeLockCounter; 39 | NSUInteger changeGenerationCount; 40 | } 41 | 42 | /*! @name Accessing raw data 43 | */ 44 | //@{ 45 | 46 | /*! Returns the length of the HFByteArray as a 64 bit unsigned long long. This is an abstract method that concrete subclasses must override. */ 47 | - (unsigned long long)length; 48 | 49 | /*! Copies a range of bytes into a buffer. This is an abstract method that concrete subclasses must override. */ 50 | - (void)copyBytes:(unsigned char *)dst range:(HFRange)range; 51 | //@} 52 | 53 | /*! @name Accessing byte slices 54 | Methods to access the byte slices underlying the HFByteArray. 55 | */ 56 | //@{ 57 | /*! Returns the contents of the receiver as an array of byte slices. This is an abstract method that concrete subclasses must override. */ 58 | - (NSArray *)byteSlices; 59 | 60 | /*! Returns an NSEnumerator representing the byte slices of the receiver. This is implemented as enumerating over the result of -byteSlices, but subclasses can override this to be more efficient. */ 61 | - (NSEnumerator *)byteSliceEnumerator; 62 | //@} 63 | 64 | /*! @name Modifying the byte array 65 | Methods to modify the given byte array. 66 | */ 67 | //@{ 68 | /*! Insert an HFByteSlice in the given range. The maximum value of the range must not exceed the length of the subarray. The length of the given slice is not required to be equal to length of the range - in other words, this method may change the length of the receiver. This is an abstract method that concrete subclasses must override. */ 69 | - (void)insertByteSlice:(HFByteSlice *)slice inRange:(HFRange)lrange; 70 | 71 | /*! Insert an HFByteArray in the given range. This is implemented via calling insertByteSlice:inRange: with the byte slices from the given byte array. */ 72 | - (void)insertByteArray:(HFByteArray *)array inRange:(HFRange)lrange; 73 | 74 | /*! Delete bytes in the given range. This is implemented on the base class by creating an empty byte array and inserting it in the range to be deleted, via insertByteSlice:inRange:. */ 75 | - (void)deleteBytesInRange:(HFRange)range; 76 | 77 | /*! Returns a new HFByteArray containing the given range. This is an abstract class that concrete subclasses must override. */ 78 | - (HFByteArray *)subarrayWithRange:(HFRange)range; 79 | //@} 80 | 81 | /*! @name Write locking and generation count 82 | Methods to lock and query the lock that prevents writes. 83 | */ 84 | //@{ 85 | 86 | /*! Increment the change lock. Until the change lock reaches 0, all modifications to the receiver will raise an exception. */ 87 | - (void)incrementChangeLockCounter; 88 | 89 | /*! Decrement the change lock. If the change lock reaches 0, modifications will be allowed again. */ 90 | - (void)decrementChangeLockCounter; 91 | 92 | /*! Query if the changes are locked. This method is KVO compliant. */ 93 | - (BOOL)changesAreLocked; 94 | //@} 95 | 96 | /* @name Generation count 97 | Manipulate the generation count */ 98 | // @{ 99 | /*! Increments the generation count, unless the receiver is locked, in which case it raises an exception. All subclasses of HFByteArray should call this method at the beginning of any overridden method that may modify the receiver. 100 | @param sel The selector that would modify the receiver (e.g. deleteBytesInRange:). This is usually _cmd. */ 101 | - (void)incrementGenerationOrRaiseIfLockedForSelector:(SEL)sel; 102 | 103 | /*! Return the change generation count. Every change to the ByteArray increments this by one or more. This can be used for caching layers on top of HFByteArray, to known when to expire their cache. */ 104 | - (NSUInteger)changeGenerationCount; 105 | 106 | //@} 107 | 108 | 109 | 110 | /*! @name Searching 111 | */ 112 | //@{ 113 | /*! Searches the receiver for a byte array matching findBytes within the given range, and returns the index that it was found. This is a concrete method on HFByteArray. 114 | @param findBytes The HFByteArray containing the data to be found (the needle to the receiver's haystack). 115 | @param range The range of the receiver in which to search. The end of the range must not exceed the receiver's length. 116 | @param forwards If this is YES, then the first match within the range is returned. Otherwise the last is returned. 117 | @param progressTracker An HFProgressTracker to allow progress reporting and cancelleation for the search operation. 118 | @return The index in the receiver of bytes equal to findBytes, or ULLONG_MAX if the byte array was not found (or the operation was cancelled) 119 | */ 120 | - (unsigned long long)indexOfBytesEqualToBytes:(HFByteArray *)findBytes inRange:(HFRange)range searchingForwards:(BOOL)forwards trackingProgress:(HFProgressTracker *)progressTracker; 121 | //@} 122 | 123 | @end 124 | 125 | 126 | /*! @category HFByteArray(HFFileWriting) 127 | @brief HFByteArray methods for writing to files, and preparing other HFByteArrays for potentially destructive file writes. 128 | */ 129 | @interface HFByteArray (HFFileWriting) 130 | /* Attempts to write the receiver to a file. This is a concrete method on HFByteArray. 131 | @param targetURL A URL to the file to be written to. It is OK for the receiver to contain one or more instances of HFByteSlice that are sourced from the file. 132 | @param progressTracker An HFProgressTracker to allow progress reporting and cancelleation for the write operation. 133 | @param error An out NSError parameter. 134 | @return YES if the write succeeded, NO if it failed. 135 | */ 136 | - (BOOL)writeToFile:(NSURL *)targetURL trackingProgress:(HFProgressTracker *)progressTracker error:(NSError **)error; 137 | 138 | /*! Returns the ranges of the file that would be modified, if the receiver were written to it. This is useful (for example) in determining if the clipboard can be preserved after a save operation. This is a concrete method on HFByteArray. 139 | @param reference An HFFileReference to the file to be modified 140 | @return An array of @link HFRangeWrapper HFRangeWrappers@endlink, representing the ranges of the file that would be affected. If no range would be affected, the result is an empty array. 141 | */ 142 | - (NSArray *)rangesOfFileModifiedIfSavedToFile:(HFFileReference *)reference; 143 | 144 | /*! Attempts to modify the receiver so that it no longer depends on any of the HFRanges in the array within the given file. It is not necessary to perform this operation on the byte array that is being written to the file. 145 | @param ranges An array of HFRangeWrappers, representing ranges in the given file that the receiver should no longer depend on. 146 | @param reference The HFFileReference that the receiver should no longer depend on. 147 | @return A YES return indicates the operation was successful, and the receiver no longer contains byte slices that source data from any of the ranges of the given file (or never did). A NO return indicates that breaking the dependencies would require too much memory, and so the receiver still depends on some of those ranges. 148 | */ 149 | - (BOOL)clearDependenciesOnRanges:(NSArray *)ranges inFile:(HFFileReference *)reference; 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFByteSlice.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFByteSlice.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/4/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class HFFileReference; 12 | 13 | /*! @class HFByteSlice 14 | @brief A class representing a source of data for an HFByteArray. 15 | 16 | HFByteSlice is an abstract class encapsulating primitive data sources (files, memory buffers, etc.). Each source must support random access reads, and have a well defined length. All HFByteSlices are \b immutable. 17 | 18 | The two principal subclasses of HFByteSlice are HFSharedMemoryByteSlice and HFFileByteSlice, which respectively encapsulate data from memory and from a file. 19 | */ 20 | @interface HFByteSlice : NSObject { 21 | NSUInteger retainCount; 22 | } 23 | 24 | /*! Return the length of the byte slice as a 64 bit value. This is an abstract method that concrete subclasses must override. */ 25 | - (unsigned long long)length; 26 | 27 | /*! Copies a range of data from the byte slice into an in-memory buffer. This is an abstract method that concrete subclasses must override. */ 28 | - (void)copyBytes:(unsigned char *)dst range:(HFRange)range; 29 | 30 | /*! Returns a new slice containing a subrange of the given slice. This is an abstract method that concrete subclasses must override. */ 31 | - (HFByteSlice *)subsliceWithRange:(HFRange)range; 32 | 33 | /*! Attempts to create a new byte slice by appending one byte slice to another. This does not modify the receiver or the slice argument (after all, both are immutable). This is provided as an optimization, and is allowed to return nil if the appending cannot be done efficiently. The default implementation returns nil. 34 | */ 35 | - (id)byteSliceByAppendingSlice:(HFByteSlice *)slice; 36 | 37 | /*! Returns YES if the receiver is sourced from a file. The default implementation returns NO. This is used to estimate cost when writing to a file. 38 | */ 39 | - (BOOL)isSourcedFromFile; 40 | 41 | /*! For a given file reference, returns the range within the file that the receiver is sourced from. If the receiver is not sourced from this file, returns {ULLONG_MAX, ULLONG_MAX}. The default implementation returns {ULLONG_MAX, ULLONG_MAX}. This is used during file saving to to determine how to properly overwrite a given file. 42 | */ 43 | - (HFRange)sourceRangeForFile:(HFFileReference *)reference; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFCancelButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFCancelButton.h 3 | // HexFiend_2 4 | // 5 | // Created by peter on 6/11/08. 6 | // Copyright 2008 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFCancelButton 12 | @brief A simple subclass of NSButton that has the correct appearance for cancelling. This is not a generally useful class. */ 13 | 14 | @interface HFCancelButton : NSButton 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFController.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/3/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | /*! @header HFController 14 | @abstract The HFController.h header contains the HFController class, which is a central class in Hex Fiend. 15 | */ 16 | 17 | @class HFRepresenter, HFByteArray, HFControllerCoalescedUndo; 18 | 19 | /*! @enum HFControllerPropertyBits 20 | The HFControllerPropertyBits bitmask is used to inform the HFRepresenters of a change in the current state that they may need to react to. A bitmask of the changed properties is passed to representerChangedProperties:. It is common for multiple properties to be included in such a bitmask. 21 | */ 22 | enum 23 | { 24 | HFControllerContentValue = 1 << 0, /*!< Indicates that the contents of the ByteArray has changed within the document. There is no indication as to what the change is. If redisplaying everything is expensive, Representers should cache their displayed data and compute any changes manually. */ 25 | HFControllerContentLength = 1 << 1, /*!< Indicates that the length of the ByteArray has changed. */ 26 | HFControllerDisplayedLineRange = 1 << 2, /*!< Indicates that the displayedLineRange property of the document has changed (e.g. the user scrolled). */ 27 | HFControllerSelectedRanges = 1 << 3, /*!< Indicates that the selectedContentsRanges property of the document has changed (e.g. the user selected some other range). */ 28 | HFControllerSelectionPulseAmount = 1 << 4, /*!< Indicates that the amount of "pulse" to show in the Find pulse indicator has changed. */ 29 | HFControllerBytesPerLine = 1 << 5, /*!< Indicates that the number of bytes to show per line has changed. */ 30 | HFControllerBytesPerColumn = 1 << 6, /*!< Indicates that the number of bytes per column (byte grouping) has changed. */ 31 | HFControllerEditable = 1 << 7, /*!< Indicates that the document has become (or is no longer) editable. */ 32 | HFControllerFont = 1 << 8, /*!< Indicates that the font property has changed. */ 33 | HFControllerAntialias = 1 << 9, /*!< Indicates that the shouldAntialias property has changed. */ 34 | HFControllerLineHeight = 1 << 10, /*!< Indicates that the lineHeight property has changed. */ 35 | HFControllerViewSizeRatios = 1 << 11 /*!< Indicates that the optimum size for each view may have changed; used by HFLayoutController after font changes. */ 36 | }; 37 | typedef NSUInteger HFControllerPropertyBits; 38 | 39 | /*! @enum HFControllerMovementDirection 40 | 41 | The HFControllerMovementDirection enum is used to specify a direction (either left or right) in various text editing APIs. HexFiend does not support left-to-right languages. 42 | */ 43 | enum 44 | { 45 | HFControllerDirectionLeft, 46 | HFControllerDirectionRight 47 | }; 48 | typedef NSInteger HFControllerMovementDirection; 49 | 50 | /*! @enum HFControllerSelectionTransformation 51 | 52 | The HFControllerSelectionTransformation enum is used to specify what happens to the selection in various APIs. This is mainly interesting for text-editing style Representers. 53 | */ 54 | enum 55 | { 56 | HFControllerDiscardSelection, /*!< The selection should be discarded. */ 57 | HFControllerShiftSelection, /*!< The selection should be moved, without changing its length. */ 58 | HFControllerExtendSelection /*!< The selection should be extended, changing its length. */ 59 | }; 60 | typedef NSInteger HFControllerSelectionTransformation; 61 | 62 | /*! @enum HFControllerMovementGranularity 63 | 64 | The HFControllerMovementGranularity enum is used to specify the granularity of text movement in various APIs. This is mainly interesting for text-editing style Representers. 65 | */ 66 | enum 67 | { 68 | HFControllerMovementByte, /*!< Move by individual bytes */ 69 | HFControllerMovementLine, /*!< Move by lines */ 70 | HFControllerMovementPage, /*!< Move by pages */ 71 | HFControllerMovementDocument /*!< Move by the whole document */ 72 | }; 73 | typedef NSInteger HFControllerMovementGranularity; 74 | 75 | /*! @class HFController 76 | @brief A central class that acts as the controller layer for HexFiend.framework 77 | 78 | HFController acts as the controller layer in the MVC architecture of HexFiend. The HFController plays several significant central roles, including: 79 | - Mediating between the data itself (in the HFByteArray) and the views of the data (the @link HFRepresenter HFRepresenters@endlink). 80 | - Propagating changes to the views. 81 | - Storing properties common to all Representers, such as the currently diplayed range, the currently selected range(s), the font, etc. 82 | - Handling text editing actions, such as selection changes or insertions/deletions. 83 | 84 | An HFController is the top point of ownership for a HexFiend object graph. It retains both its ByteArray (model) and its array of Representers (views). 85 | 86 | You create an HFController via [[HFController alloc] init]. After that, give it an HFByteArray via setByteArray:, and some Representers via addRepresenter:. Then insert the Representers' views in a window, and you're done. 87 | 88 | */ 89 | @interface HFController : NSObject { 90 | @private 91 | NSMutableArray *representers; 92 | HFByteArray *byteArray; 93 | NSMutableArray *selectedContentsRanges; 94 | HFRange displayedContentsRange; 95 | HFFPRange displayedLineRange; 96 | NSUInteger bytesPerLine; 97 | NSUInteger bytesPerColumn; 98 | NSFont *font; 99 | CGFloat lineHeight; 100 | 101 | NSUInteger currentPropertyChangeToken; 102 | NSMutableArray *additionalPendingTransactions; 103 | HFControllerPropertyBits propertiesToUpdateInCurrentTransaction; 104 | 105 | NSUndoManager *undoManager; 106 | 107 | unsigned long long selectionAnchor; 108 | HFRange selectionAnchorRange; 109 | 110 | HFControllerCoalescedUndo *undoCoalescer; 111 | 112 | CFAbsoluteTime pulseSelectionStartTime, pulseSelectionCurrentTime; 113 | NSTimer *pulseSelectionTimer; 114 | 115 | /* Basic cache support */ 116 | HFRange cachedRange; 117 | NSData *cachedData; 118 | NSUInteger cachedGenerationIndex; 119 | 120 | struct { 121 | unsigned antialias:1; 122 | unsigned overwriteMode:1; 123 | unsigned editable:1; 124 | unsigned selectable:1; 125 | unsigned selectionInProgress:1; 126 | unsigned shiftExtendSelection:1; 127 | unsigned commandExtendSelection:1; 128 | unsigned reserved1:25; 129 | unsigned reserved2:32; 130 | } _hfflags; 131 | } 132 | 133 | /*! @name Representer handling. 134 | Methods for modifying the list of HFRepresenters attached to a controller. Attached representers receive the controllerDidChange: message when various properties of the controller change. A representer may only be attached to one controller at a time. Representers are retained by the controller. 135 | */ 136 | //@{ 137 | /*! Gets the current array of representers attached to this controller. */ 138 | - (NSArray *)representers; 139 | 140 | /*! Adds a new representer to this controller. */ 141 | - (void)addRepresenter:(HFRepresenter *)representer; 142 | 143 | /*! Removes an existing representer from this controller. The representer must be present in the array of representers. */ 144 | - (void)removeRepresenter:(HFRepresenter *)representer; 145 | 146 | //@} 147 | 148 | /*! @name Property transactions 149 | Methods for temporarily delaying notifying representers of property changes. There is a property transaction stack, and all property changes are collected until the last token is popped off the stack, at which point all representers are notified of all collected changes via representerChangedProperties:. To use this, call beginPropertyChangeTransaction, and record the token that is returned. Pass it to endPropertyChangeTransaction: to notify representers of all changed properties in bulk. 150 | 151 | Tokens cannot be popped out of order - they are used only as a correctness check. 152 | */ 153 | //@{ 154 | /*! Begins delaying property change transactions. Returns a token that should be passed to endPropertyChangeTransactions:. */ 155 | - (NSUInteger)beginPropertyChangeTransaction; 156 | 157 | /*! Pass a token returned from beginPropertyChangeTransaction to this method to pop the transaction off the stack and, if the stack is empty, to notify Representers of all collected changes. Tokens cannot be popped out of order - they are used strictly as a correctness check. */ 158 | - (void)endPropertyChangeTransaction:(NSUInteger)token; 159 | //@} 160 | 161 | /*! @name Byte array 162 | Set and get the byte array. */ 163 | //@{ 164 | /*! Sets the byte array for the HFController. The byte array must be non-nil. */ 165 | - (void)setByteArray:(HFByteArray *)val; 166 | 167 | /*! Returns the byte array for the HFController. In general, HFRepresenters should not use this to determine what bytes to display. Instead they should use copyBytes:range: or dataForRange: below. */ 168 | - (HFByteArray *)byteArray; 169 | 170 | /*! Replaces the entire byte array with a new one, preserving as much of the selection as possible. Unlike setByteArray:, this method is undoable, and intended to be used from representers that make a global change (such as Replace All). */ 171 | - (void)replaceByteArray:(HFByteArray *)newArray; 172 | //@} 173 | 174 | /*! @name Properties shared between all representers 175 | The following properties are considered global among all HFRepresenters attached to the receiver. 176 | */ 177 | //@{ 178 | /*! Returns the number of lines on which the cursor may be placed. This is always at least 1, and is equivalent to (unsigned long long)(HFRoundUpToNextMultiple(contentsLength, bytesPerLine) / bytesPerLine) */ 179 | - (unsigned long long)totalLineCount; 180 | 181 | /*! Indicates the number of bytes per line, which is a global property among all the line-oriented representers. */ 182 | - (NSUInteger)bytesPerLine; 183 | 184 | /*! Returns the height of a line, in points. This is generally determined by the font. Representers that wish to align things to lines should use this. */ 185 | - (CGFloat)lineHeight; 186 | 187 | //@} 188 | 189 | /*! @name Selection pulsing 190 | Used to show the current selection after a change, similar to Find in Safari 191 | */ 192 | //{@ 193 | 194 | /*! Begins selection pulsing (e.g. following a successful Find operation). Representers will receive callbacks indicating that HFControllerSelectionPulseAmount has changed. */ 195 | - (void)pulseSelection; 196 | 197 | /*! Return the amount that the "Find pulse indicator" should show. 0 means no pulse, 1 means maximum pulse. This is useful for Representers that support find and replace. */ 198 | - (double)selectionPulseAmount; 199 | //@} 200 | 201 | /*! @name Selection handling 202 | Methods for manipulating the current selected ranges. Hex Fiend supports discontiguous selection. 203 | */ 204 | //{@ 205 | 206 | /*! Returns an array of HFRangeWrappers, representing the selected ranges. This method always contains at least one range. If there is no selection, then the result will contain a single range of length 0, with the location equal to the position of the cursor. */ 207 | - (NSArray *)selectedContentsRanges; 208 | 209 | /*! Explicitly set the selected contents ranges. Pass an array of HFRangeWrappers that meets the following criteria: 210 | The array must not be NULL. 211 | There always must be at least one selected range. 212 | If any range has length 0, there must be exactly one selected range. 213 | No range may extend beyond the contentsLength, with the exception of a single zero-length range, which may be at the end. 214 | */ 215 | - (void)setSelectedContentsRanges:(NSArray *)selectedRanges; 216 | 217 | /*! Selects the entire contents. */ 218 | - (IBAction)selectAll:(id)sender; 219 | 220 | /*! Returns the smallest value in the selected contents ranges, or the insertion location if the selection is empty. */ 221 | - (unsigned long long)minimumSelectionLocation; 222 | 223 | /*! Returns the largest HFMaxRange of the selected contents ranges, or the insertion location if the selection is empty. */ 224 | - (unsigned long long)maximumSelectionLocation; 225 | 226 | /*! Convenience method for creating a byte array containing all of the selected bytes. If the selection has length 0, this returns an empty byte array. */ 227 | - (HFByteArray *)byteArrayForSelectedContentsRanges; 228 | //@} 229 | 230 | /*! @name Bytes per column 231 | Set and get the number of bytes per column. */ 232 | //@{ 233 | /* Sets the number of bytes used in each column for a text-style representer. */ 234 | - (void)setBytesPerColumn:(NSUInteger)val; 235 | 236 | /* Returns the number of bytes used in each column for a text-style representer. */ 237 | - (NSUInteger)bytesPerColumn; 238 | //@} 239 | 240 | /*! @name Overwrite mode 241 | Determines whether text insertion overwrites subsequent text or not. */ 242 | //@{ 243 | 244 | /*! Determines whether this HFController is in overwrite mode or not. */ 245 | - (BOOL)inOverwriteMode; 246 | 247 | /*! Sets whether we this HFController is in overwrite mode or not. */ 248 | - (void)setInOverwriteMode:(BOOL)val; 249 | 250 | /*! Returns YES if we must be in overwrite mode (because our backing data cannot have its size changed) */ 251 | - (BOOL)requiresOverwriteMode; 252 | 253 | //@} 254 | 255 | /*! @name Displayed line range 256 | Methods for setting and getting the current range of displayed lines. 257 | */ 258 | //{@ 259 | /*! Get the current displayed line range. The displayed line range is an HFFPRange (range of long doubles) containing the lines that are currently displayed. 260 | 261 | The values may be fractional. That is, if only the bottom half of line 4 through the top two thirds of line 8 is shown, then the displayedLineRange.location will be 4.5 and the displayedLineRange.length will be 3.17 ( = 7.67 - 4.5). Representers are expected to be able to handle such fractional values. 262 | 263 | */ 264 | - (HFFPRange)displayedLineRange; 265 | 266 | /*! Sets the displayed line range. When setting the displayed line range, the given range must be nonnegative, and the maximum of the range must be no larger than the total line count. See the -displayedLineRange method for more information. */ 267 | - (void)setDisplayedLineRange:(HFFPRange)range; 268 | 269 | /*! Modify the displayedLineRange as little as possible so that as much of the given range as can fit is visible. */ 270 | - (void)maximizeVisibilityOfContentsRange:(HFRange)range; 271 | 272 | //@} 273 | 274 | /*! @name Font 275 | Get and set the current font. 276 | */ 277 | //@{ 278 | /*! Get the current font. */ 279 | - (NSFont *)font; 280 | 281 | /*! Set the current font. */ 282 | - (void)setFont:(NSFont *)font; 283 | 284 | /*! @name Undo management 285 | Get and set the undo manager. If no undo manager is set, then undo is not supported. 286 | */ 287 | //@{ 288 | 289 | /*! Set the undo manager for this HFController. By default the undo manager for an HFController is nil. If one is not set, undo does not occur. This retains the undo manager. */ 290 | - (void)setUndoManager:(NSUndoManager *)manager; 291 | 292 | /*! Gets the undo manager for this HFController. By default the undo manager is nil. Undo will not be supported unless an undo manager is set. */ 293 | - (NSUndoManager *)undoManager; 294 | 295 | //@} 296 | 297 | /*! @name Editability 298 | Set and get whether representers should allow editing the data. 299 | */ 300 | //@{ 301 | /*! Get the editable property, which determines whether the user can edit the document. */ 302 | - (BOOL)editable; 303 | 304 | /*! Set the editable property, which determines whether the user can edit the document. */ 305 | - (void)setEditable:(BOOL)flag; 306 | //@} 307 | 308 | /*! @name Antialiasing 309 | Set and get whether the text should be antialiased. Note that Mac OS X settings may prevent antialiasing text below a certain point size. */ 310 | //@{ 311 | /*! Returns whether text should be antialiased. */ 312 | - (BOOL)shouldAntialias; 313 | 314 | /*! Sets whether text should be antialiased. */ 315 | - (void)setShouldAntialias:(BOOL)antialias; 316 | //@} 317 | 318 | /*! Representer initiated property changes 319 | Called from a representer to indicate when some internal property of the representer has changed which requires that some properties be recalculated. 320 | */ 321 | //@{ 322 | /*! Callback for a representer-initiated change to some property. For example, if some property of a view changes that would cause the number of bytes per line to change, then the representer should call this method which will trigger the HFController to recompute the relevant properties. */ 323 | 324 | - (void)representer:(HFRepresenter *)rep changedProperties:(HFControllerPropertyBits)properties; 325 | //@} 326 | 327 | /*! @name Mouse selection 328 | Methods to handle mouse selection. Representers that allow text selection should call beginSelectionWithEvent:forByteIndex: upon receiving a mouseDown event, and then continueSelectionWithEvent:forByteIndex: for mouseDragged events, terminating with endSelectionWithEvent:forByteIndex: upon receiving the mouse up. HFController will compute the correct selected ranges and propagate any changes via the HFControllerPropertyBits mechanism. */ 329 | //@{ 330 | /*! Begin a selection session, with a mouse down at the given byte index. */ 331 | - (void)beginSelectionWithEvent:(NSEvent *)event forByteIndex:(unsigned long long)byteIndex; 332 | 333 | /*! Continue a selection session, whe the user drags over the given byte index. */ 334 | - (void)continueSelectionWithEvent:(NSEvent *)event forByteIndex:(unsigned long long)byteIndex; 335 | 336 | /*! End a selection session, with a mouse up at the given byte index. */ 337 | - (void)endSelectionWithEvent:(NSEvent *)event forByteIndex:(unsigned long long)byteIndex; 338 | 339 | /*! @name Scrollling 340 | Support for the mouse wheel and scroll bars. */ 341 | //@{ 342 | /*! Trigger scrolling appropriate for the given scroll event. */ 343 | - (void)scrollWithScrollEvent:(NSEvent *)scrollEvent; 344 | 345 | /*! Trigger scrolling by the given number of lines. If lines is positive, then the document is scrolled down; otherwise it is scrolled up. */ 346 | - (void)scrollByLines:(long double)lines; 347 | 348 | //@} 349 | 350 | /*! @name Keyboard navigation 351 | Support for chaging the selection via the keyboard 352 | */ 353 | 354 | /*! General purpose navigation function. Modify the selection in the given direction by the given number of bytes. The selection is modifed according to the given transformation. If useAnchor is set, then anchored selection is used; otherwise any anchor is discarded. 355 | 356 | This has a few limitations: 357 | - Only HFControllerDirectionLeft and HFControllerDirectionRight movement directions are supported. 358 | - Anchored selection is not supported for HFControllerShiftSelection (useAnchor must be NO) 359 | */ 360 | - (void)moveInDirection:(HFControllerMovementDirection)direction byByteCount:(unsigned long long)amountToMove withSelectionTransformation:(HFControllerSelectionTransformation)transformation usingAnchor:(BOOL)useAnchor; 361 | 362 | /*! Navigation designed for key events. */ 363 | - (void)moveInDirection:(HFControllerMovementDirection)direction withGranularity:(HFControllerMovementGranularity)granularity andModifySelection:(BOOL)extendSelection; 364 | - (void)moveToLineBoundaryInDirection:(HFControllerMovementDirection)direction andModifySelection:(BOOL)extendSelection; 365 | 366 | /*! @name Text editing 367 | Methods to support common text editing operations */ 368 | //@{ 369 | 370 | /*! Replaces the selection with the given data. For something like a hex view representer, it takes two keypresses to create a whole byte; the way this is implemented, the first keypress goes into the data as a complete byte, and the second one (if any) replaces it. If previousByteCount > 0, then that many prior bytes are replaced, without breaking undo coalescing. For previousByteCount to be > 0, the following must be true: There is only one selected range, and it is of length 0, and its location >= previousByteCount 371 | 372 | These functions return YES if they succeed, and NO if they fail. Currently they may fail only in overwrite mode, if you attempt to insert data that would require lengthening the byte array. 373 | 374 | These methods are undoable. 375 | */ 376 | - (BOOL)insertByteArray:(HFByteArray *)byteArray replacingPreviousBytes:(unsigned long long)previousByteCount allowUndoCoalescing:(BOOL)allowUndoCoalescing; 377 | - (BOOL)insertData:(NSData *)data replacingPreviousBytes:(unsigned long long)previousByteCount allowUndoCoalescing:(BOOL)allowUndoCoalescing; 378 | 379 | /*! Deletes the selection. This operation is undoable. */ 380 | - (void)deleteSelection; 381 | 382 | /*! If the selection is empty, deletes one byte in a given direction, which must be HFControllerDirectionLeft or HFControllerDirectionRight; if the selection is not empty, deletes the selection. Undoable. */ 383 | - (void)deleteDirection:(HFControllerMovementDirection)direction; 384 | 385 | //@} 386 | 387 | /*! @name Reading data 388 | Methods for reading data */ 389 | 390 | /*! Returns an NSData representing the given HFRange. The length of the HFRange must be of a size that can reasonably be fit in memory. This method may cache the result. */ 391 | - (NSData *)dataForRange:(HFRange)range; 392 | 393 | /*! Copies data within the given HFRange into an in-memory buffer. This is equivalent to [[controller byteArray] copyBytes:bytes range:range]. */ 394 | - (void)copyBytes:(unsigned char *)bytes range:(HFRange)range; 395 | 396 | /*! Returns total number of bytes. This is equivalent to [[controller byteArray] length]. */ 397 | - (unsigned long long)contentsLength; 398 | 399 | /*! @name File writing dependency handling 400 | */ 401 | //@{ 402 | /*! Attempts to clear all dependencies on the given file (clipboard, undo, etc.) that could not be preserved if the file were written. Returns YES if we successfully prepared, NO if someone objected. */ 403 | + (BOOL)prepareForChangeInFile:(NSURL *)targetFile fromWritingByteArray:(HFByteArray *)array; 404 | //@} 405 | 406 | @end 407 | 408 | /*! A notification posted whenever any of the HFController's properties change. The object is the HFController. The userInfo contains one key, HFControllerChangedPropertiesKey, which contains an NSNumber with the changed properties as a HFControllerPropertyBits bitmask. This is useful for external objects to be notified of changes. HFRepresenters added to the HFController are notified via the controllerDidChange: message. 409 | */ 410 | extern NSString * const HFControllerDidChangePropertiesNotification; 411 | 412 | /*! @name HFControllerDidChangePropertiesNotification keys 413 | */ 414 | //@{ 415 | extern NSString * const HFControllerChangedPropertiesKey; //!< A key in the HFControllerDidChangeProperties containing a bitmask of the changed properties, as a HFControllerPropertyBits 416 | //@} 417 | 418 | /*! A notification posted from prepareForChangeInFile:fromWritingByteArray: because we are about to write a ByteArray to a file. The object is the FileReference. 419 | Currently, HFControllers do not listen for this notification. This is because under GC there is no way of knowing whether the controller is live or not. However, pasteboard owners do listen for it, because as long as we own a pasteboard we are guaranteed to be live. 420 | */ 421 | extern NSString * const HFPrepareForChangeInFileNotification; 422 | 423 | /*! @name HFPrepareForChangeInFileNotification keys 424 | */ 425 | //@{ 426 | extern NSString * const HFChangeInFileByteArrayKey; //!< A key in the HFPrepareForChangeInFileNotification specifying the byte array that will be written 427 | extern NSString * const HFChangeInFileModifiedRangesKey; //!< A key in the HFPrepareForChangeInFileNotification specifying the array of HFRangeWrappers indicating which parts of the file will be modified 428 | extern NSString * const HFChangeInFileShouldCancelKey; //!< A key in the HFPrepareForChangeInFileNotification specifying an NSValue containing a pointer to a BOOL. If set to YES, then someone was unable to prepare and the file should not be saved. It's a good idea to check if this value points to YES; if so your notification handler does not have to do anything. 429 | //@} 430 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFFileByteSlice.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFFileByteSlice.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 1/23/08. 6 | // Copyright 2008 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class HFFileReference; 12 | 13 | /*! @class HFFileByteSlice 14 | @brief A subclass of HFByteSlice for working data stored in files. 15 | 16 | HFFileByteSlice is a subclass of HFByteSlice that represents a portion of data from a file. The file is specified as an HFFileReference; since the HFFileReference encapsulates the file descriptor, multiple HFFileByteSlices may all reference the same file without risking overrunning the limit on open files. 17 | */ 18 | @interface HFFileByteSlice : HFByteSlice { 19 | HFFileReference *fileReference; 20 | unsigned long long offset; 21 | unsigned long long length; 22 | } 23 | 24 | /*! Initialize an HFByteSlice from a file. The receiver represents the entire extent of the file. */ 25 | - initWithFile:(HFFileReference *)file; 26 | 27 | /*! Initialize an HFByteSlice from a portion of a file, specified as an offset and length. The sum of the offset and length must not exceed the length of the file. This is the designated initializer. */ 28 | - initWithFile:(HFFileReference *)file offset:(unsigned long long)offset length:(unsigned long long)length; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFFileReference.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFFileReference.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 1/23/08. 6 | // Copyright 2008 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFFileReference 12 | @brief A reference to an open file. 13 | 14 | HFFileReference encapsulates a reference to an open file. Multiple instances of HFFileByteSlice may share an HFFileReference, so that the file only needs to be opened once. 15 | 16 | All HFFileReferences use non-caching IO (F_NOCACHE is set). 17 | */ 18 | @interface HFFileReference : NSObject { 19 | int fileDescriptor; 20 | dev_t device; 21 | unsigned long long fileLength; 22 | unsigned long long inode; 23 | BOOL isWritable; 24 | } 25 | 26 | 27 | /*! Open a file for reading and writing at the given path. The permissions mode of any newly created file is 0744. Returns nil if the file could not be opened, in which case the error parameter (if not nil) will be set. */ 28 | - initWritableWithPath:(NSString *)path error:(NSError **)error; 29 | 30 | /*! Open a file for reading only at the given path. Returns nil if the file could not be opened, in which case the error parameter (if not nil) will be set. */ 31 | - initWithPath:(NSString *)path error:(NSError **)error; 32 | 33 | /*! Closes the file. */ 34 | - (void)close; 35 | 36 | /*! Reads from the file into a local memory buffer. The sum of the length and the offset must not exceed the length of the file. 37 | @param buff The buffer to read into. 38 | @param length The number of bytes to read. 39 | @param offset The offset in the file to read. 40 | */ 41 | - (void)readBytes:(unsigned char *)buff length:(NSUInteger)length from:(unsigned long long)offset; 42 | 43 | /*! Writes data to the file, which must have been opened writable. 44 | @param buff The data to write. 45 | @param length The number of bytes to write. 46 | @param offset The offset in the file to write to. 47 | @return 0 on success, or an errno-style error code on failure 48 | */ 49 | - (int)writeBytes:(const unsigned char *)buff length:(NSUInteger)length to:(unsigned long long)offset; 50 | 51 | /*! Returns the length of the file, as a 64 bit unsigned long long. */ 52 | - (unsigned long long)length; 53 | 54 | /*! Changes the length of the file via \c ftruncate. Returns YES on success, NO on failure; on failure it optionally returns an NSError by reference. */ 55 | - (BOOL)setLength:(unsigned long long)length error:(NSError **)error; 56 | 57 | /*! isEqual: returns whether two file references both reference the same file, as in have the same inode and device. */ 58 | - (BOOL)isEqual:(id)val; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFFullMemoryByteArray.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFFullMemoryByteArray.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/4/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! 12 | @class HFFullMemoryByteArray 13 | @brief A naive subclass of HFByteArray suitable mainly for testing. Use HFBTreeByteArray instead. 14 | 15 | HFFullMemoryByteArray is a simple subclass of HFByteArray that does not store any byte slices. Because it stores all data in an NSMutableData, it is not efficient. It is mainly useful as a naive implementation for testing. Use HFBTreeByteArray instead. 16 | */ 17 | @interface HFFullMemoryByteArray : HFByteArray { 18 | NSMutableData *data; 19 | } 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFFullMemoryByteSlice.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFFullMemoryByteSlice.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/4/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFFullMemoryByteSlice 12 | 13 | @brief A simple subclass of HFByteSlice that wraps an NSData. For most uses, prefer HFSharedMemoryByteSlice. 14 | */ 15 | @interface HFFullMemoryByteSlice : HFByteSlice { 16 | NSData *data; 17 | } 18 | 19 | /*! Init with a given NSData, which is copied via the \c -copy message. */ 20 | - initWithData:(NSData *)val; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFFunctions.h: -------------------------------------------------------------------------------- 1 | /* Functions and convenience methods for working with HFTypes */ 2 | 3 | #import 4 | #import 5 | 6 | #define HFZeroRange (HFRange){0, 0} 7 | 8 | /*! 9 | Makes an HFRange. An HFRange is like an NSRange except it uses unsigned long longs. 10 | */ 11 | static inline HFRange HFRangeMake(unsigned long long loc, unsigned long long len) { 12 | return (HFRange){loc, len}; 13 | } 14 | 15 | /*! 16 | Returns true if a given location is within a given HFRange. 17 | */ 18 | static inline BOOL HFLocationInRange(unsigned long long location, HFRange range) { 19 | return location >= range.location && location - range.location < range.length; 20 | } 21 | 22 | /*! 23 | Like NSRangeToString but for HFRanges 24 | */ 25 | static inline NSString* HFRangeToString(HFRange range) { 26 | return [NSString stringWithFormat:@"{%llu, %llu}", range.location, range.length]; 27 | } 28 | 29 | /*! 30 | Converts a given HFFPRange to a string. 31 | */ 32 | static inline NSString* HFFPRangeToString(HFFPRange range) { 33 | return [NSString stringWithFormat:@"{%Lf, %Lf}", range.location, range.length]; 34 | } 35 | 36 | /*! 37 | Returns true if two HFRanges are equal. 38 | */ 39 | static inline BOOL HFRangeEqualsRange(HFRange a, HFRange b) { 40 | return a.location == b.location && a.length == b.length; 41 | } 42 | 43 | /*! 44 | Returns true if a + b does not overflow an unsigned long long. 45 | */ 46 | static inline BOOL HFSumDoesNotOverflow(unsigned long long a, unsigned long long b) { 47 | return a + b >= a; 48 | } 49 | 50 | /*! 51 | Returns true if a * b does not overflow an unsigned long long. 52 | */ 53 | static inline BOOL HFProductDoesNotOverflow(unsigned long long a, unsigned long long b) { 54 | if (b == 0) return YES; 55 | unsigned long long result = a * b; 56 | return result / b == a; 57 | } 58 | 59 | /*! 60 | Returns a * b as an NSUInteger. This asserts on overflow, unless NDEBUG is defined. 61 | */ 62 | static inline NSUInteger HFProductInt(NSUInteger a, NSUInteger b) { 63 | NSUInteger result = a * b; 64 | assert(a == 0 || result / a == b); //detect overflow 65 | return result; 66 | } 67 | 68 | /*! 69 | Returns a + b as an NSUInteger. This asserts on overflow unless NDEBUG is defined. 70 | */ 71 | static inline NSUInteger HFSumInt(NSUInteger a, NSUInteger b) { 72 | assert(a + b >= a); 73 | return a + b; 74 | } 75 | 76 | /*! 77 | Returns a * b as an unsigned long long. This asserts on overflow, unless NDEBUG is defined. 78 | */ 79 | static inline unsigned long long HFProductULL(unsigned long long a, unsigned long long b) { 80 | unsigned long long result = a * b; 81 | assert(HFProductDoesNotOverflow(a, b)); //detect overflow 82 | return result; 83 | } 84 | 85 | /*! 86 | Returns a + b as an unsigned long long. This asserts on overflow, unless NDEBUG is defined. 87 | */ 88 | static inline unsigned long long HFSum(unsigned long long a, unsigned long long b) { 89 | assert(HFSumDoesNotOverflow(a, b)); 90 | return a + b; 91 | } 92 | 93 | /*! 94 | Returns a - b as an unsigned long long. This asserts on underflow (if b > a), unless NDEBUG is defined. 95 | */ 96 | static inline unsigned long long HFSubtract(unsigned long long a, unsigned long long b) { 97 | assert(a >= b); 98 | return a - b; 99 | } 100 | 101 | /*! 102 | Returns the smallest multiple of B strictly larger than A. 103 | */ 104 | static inline unsigned long long HFRoundUpToNextMultiple(unsigned long long a, unsigned long long b) { 105 | assert(b > 0); 106 | return HFSum(a, b - a % b); 107 | } 108 | 109 | /*! Like NSMaxRange, but for an HFRange. */ 110 | static inline unsigned long long HFMaxRange(HFRange a) { 111 | assert(HFSumDoesNotOverflow(a.location, a.length)); 112 | return a.location + a.length; 113 | } 114 | 115 | /*! Returns YES if needle is fully contained within haystack. Equal ranges are always considered to be subranges of each other (even if they are empty). Furthermore, a zero length needle at the end of haystack is considered a subrange - for example, {6, 0} is a subrange of {3, 3}. */ 116 | static inline BOOL HFRangeIsSubrangeOfRange(HFRange needle, HFRange haystack) { 117 | // handle the case where our needle starts before haystack, or is longer than haystack. These conditions are important to prevent overflow in future checks. 118 | if (needle.location < haystack.location || needle.length > haystack.length) return NO; 119 | 120 | // Equal ranges are considered to be subranges. This is an important check, because two equal ranges of zero length are considered to be subranges. 121 | if (HFRangeEqualsRange(needle, haystack)) return YES; 122 | 123 | // handle the case where needle is a zero-length range at the very end of haystack. We consider this a subrange - that is, (6, 0) is a subrange of (3, 3) 124 | // rearrange the expression needle.location > haystack.location + haystack.length in a way that cannot overflow 125 | if (needle.location - haystack.location > haystack.length) return NO; 126 | 127 | // rearrange expression: (needle.location + needle.length > haystack.location + haystack.length) in a way that cannot produce overflow 128 | if (needle.location - haystack.location > haystack.length - needle.length) return NO; 129 | 130 | return YES; 131 | } 132 | 133 | /*! Returns YES if the given ranges intersect. Two ranges are considered to intersect if they share at least one index in common. Thus, zero-length ranges do not intersect anything. */ 134 | static inline BOOL HFIntersectsRange(HFRange a, HFRange b) { 135 | // Ranges are said to intersect if they share at least one value. Therefore, zero length ranges never intersect anything. 136 | if (a.length == 0 || b.length == 0) return NO; 137 | 138 | // rearrange (a.location < b.location + b.length && b.location < a.location + a.length) to not overflow 139 | // = ! (a.location >= b.location + b.length || b.location >= a.location + a.length) 140 | BOOL clause1 = (a.location >= b.location && a.location - b.location >= b.length); 141 | BOOL clause2 = (b.location >= a.location && b.location - a.location >= a.length); 142 | return ! (clause1 || clause2); 143 | } 144 | 145 | /*! Returns a range containing the union of the given ranges. These ranges must either intersect or be adjacent: there cannot be any "holes" between them. */ 146 | static inline HFRange HFUnionRange(HFRange a, HFRange b) { 147 | assert(HFIntersectsRange(a, b) || HFMaxRange(a) == b.location || HFMaxRange(b) == a.location); 148 | HFRange result; 149 | result.location = MIN(a.location, b.location); 150 | assert(HFSumDoesNotOverflow(a.location, a.length)); 151 | assert(HFSumDoesNotOverflow(b.location, b.length)); 152 | result.length = MAX(a.location + a.length, b.location + b.length) - result.location; 153 | return result; 154 | } 155 | 156 | 157 | /*! Returns whether a+b > c+d, as if there were no overflow (so ULLONG_MAX + 1 > 10 + 20) */ 158 | static inline BOOL HFSumIsLargerThanSum(unsigned long long a, unsigned long long b, unsigned long long c, unsigned long long d) { 159 | //theory: compare a/2 + b/2 to c/2 + d/2, and if they're equal, compare a%2 + b%2 to c%2 + d%2 160 | unsigned long long sum1 = a/2 + b/2; 161 | unsigned long long sum2 = c/2 + d/2; 162 | if (sum1 > sum2) return YES; 163 | else if (sum1 < sum2) return NO; 164 | else { 165 | // sum1 == sum2 166 | unsigned int sum3 = (unsigned int)(a%2) + (unsigned int)(b%2); 167 | unsigned int sum4 = (unsigned int)(c%2) + (unsigned int)(d%2); 168 | if (sum3 > sum4) return YES; 169 | else return NO; 170 | } 171 | } 172 | 173 | /*! Returns the absolute value of a - b. */ 174 | static inline unsigned long long HFAbsoluteDifference(unsigned long long a, unsigned long long b) { 175 | if (a > b) return a - b; 176 | else return b - a; 177 | } 178 | 179 | /*! Returns true if the end of A is larger than the end of B. */ 180 | static inline BOOL HFRangeExtendsPastRange(HFRange a, HFRange b) { 181 | return HFSumIsLargerThanSum(a.location, a.length, b.location, b.length); 182 | } 183 | 184 | /*! Returns a range containing all indexes in common betwen the two ranges. If there are no indexes in common, returns {0, 0}. */ 185 | static inline HFRange HFIntersectionRange(HFRange range1, HFRange range2) { 186 | unsigned long long minend = HFRangeExtendsPastRange(range2, range1) ? range1.location + range1.length : range2.location + range2.length; 187 | if (range2.location <= range1.location && range1.location - range2.location < range2.length) { 188 | return HFRangeMake(range1.location, minend - range1.location); 189 | } 190 | else if (range1.location <= range2.location && range2.location - range1.location < range1.length) { 191 | return HFRangeMake(range2.location, minend - range2.location); 192 | } 193 | return HFRangeMake(0, 0); 194 | } 195 | 196 | /*! ceil() for a CGFloat, for compatibility with OSes that do not have the CG versions. */ 197 | static inline CGFloat HFCeil(CGFloat a) { 198 | if (sizeof(a) == sizeof(float)) return (CGFloat)ceilf((float)a); 199 | else return (CGFloat)ceil((double)a); 200 | } 201 | 202 | /*! floor() for a CGFloat, for compatibility with OSes that do not have the CG versions. */ 203 | static inline CGFloat HFFloor(CGFloat a) { 204 | if (sizeof(a) == sizeof(float)) return (CGFloat)floorf((float)a); 205 | else return (CGFloat)floor((double)a); 206 | } 207 | 208 | /*! round() for a CGFloat, for compatibility with OSes that do not have the CG versions. */ 209 | static inline CGFloat HFRound(CGFloat a) { 210 | if (sizeof(a) == sizeof(float)) return (CGFloat)roundf((float)a); 211 | else return (CGFloat)round((double)a); 212 | } 213 | 214 | /*! fmin() for a CGFloat, for compatibility with OSes that do not have the CG versions. */ 215 | static inline CGFloat HFMin(CGFloat a, CGFloat b) { 216 | if (sizeof(a) == sizeof(float)) return (CGFloat)fminf((float)a, (float)b); 217 | else return (CGFloat)fmin((double)a, (double)b); 218 | } 219 | 220 | /*! fmax() for a CGFloat, for compatibility with OSes that do not have the CG versions. */ 221 | static inline CGFloat HFMax(CGFloat a, CGFloat b) { 222 | if (sizeof(a) == sizeof(float)) return (CGFloat)fmaxf((float)a, (float)b); 223 | else return (CGFloat)fmax((double)a, (double)b); 224 | } 225 | 226 | /*! Returns true if the given HFFPRanges are equal. */ 227 | static inline BOOL HFFPRangeEqualsRange(HFFPRange a, HFFPRange b) { 228 | return a.location == b.location && a.length == b.length; 229 | } 230 | 231 | /*! copysign() for a CGFloat */ 232 | static inline CGFloat HFCopysign(CGFloat a, CGFloat b) { 233 | #if __LP64__ 234 | return copysign(a, b); 235 | #else 236 | return copysignf(a, b); 237 | #endif 238 | } 239 | 240 | /*! Atomically increments an NSUInteger, returning the new value. Optionally invokes a memory barrier. */ 241 | static inline NSUInteger HFAtomicIncrement(NSUInteger *ptr, BOOL barrier) { 242 | #if __LP64__ 243 | return (barrier ? OSAtomicIncrement64Barrier : OSAtomicIncrement64)((volatile int64_t *)ptr); 244 | #else 245 | return (barrier ? OSAtomicIncrement32Barrier : OSAtomicIncrement32)((volatile int32_t *)ptr); 246 | #endif 247 | } 248 | 249 | /*! Atomically decrements an NSUInteger, returning the new value. Optionally invokes a memory barrier. */ 250 | static inline NSUInteger HFAtomicDecrement(NSUInteger *ptr, BOOL barrier) { 251 | #if __LP64__ 252 | return (barrier ? OSAtomicDecrement64Barrier : OSAtomicDecrement64)((volatile int64_t *)ptr); 253 | #else 254 | return (barrier ? OSAtomicDecrement32Barrier : OSAtomicDecrement32)((volatile int32_t *)ptr); 255 | #endif 256 | } 257 | 258 | /*! Converts a long double to unsigned long long. Assumes that val is already an integer - use floorl or ceill */ 259 | static inline unsigned long long HFFPToUL(long double val) { 260 | assert(val >= 0); 261 | assert(val <= ULLONG_MAX); 262 | unsigned long long result = (unsigned long long)val; 263 | assert((long double)result == val); 264 | return result; 265 | } 266 | 267 | /*! Converts an unsigned long long to a long double. */ 268 | static inline long double HFULToFP(unsigned long long val) { 269 | long double result = (long double)val; 270 | assert(HFFPToUL(result) == val); 271 | return result; 272 | } 273 | 274 | /*! Convenience to return information about a CGAffineTransform for logging. */ 275 | static inline NSString *HFDescribeAffineTransform(CGAffineTransform t) { 276 | return [NSString stringWithFormat:@"%f %f 0\n%f %f 0\n%f %f 1", t.a, t.b, t.c, t.d, t.tx, t.ty]; 277 | } 278 | 279 | /*! Returns 1 + floor(log base 10 of val). If val is 0, returns 1. */ 280 | static inline NSUInteger HFCountDigitsBase10(unsigned long long val) { 281 | const unsigned long long kValues[] = {0ULL, 9ULL, 99ULL, 999ULL, 9999ULL, 99999ULL, 999999ULL, 9999999ULL, 99999999ULL, 999999999ULL, 9999999999ULL, 99999999999ULL, 999999999999ULL, 9999999999999ULL, 99999999999999ULL, 999999999999999ULL, 9999999999999999ULL, 99999999999999999ULL, 999999999999999999ULL, 9999999999999999999ULL}; 282 | NSUInteger low = 0, high = sizeof kValues / sizeof *kValues; 283 | while (high > low) { 284 | NSUInteger mid = (low + high)/2; //low + high cannot overflow 285 | if (val > kValues[mid]) { 286 | low = mid + 1; 287 | } 288 | else { 289 | high = mid; 290 | } 291 | } 292 | return MAX(1, low); 293 | } 294 | 295 | /*! Returns 1 + floor(log base 16 of val). If val is 0, returns 1. This works by computing the log base 2 based on the number of leading zeros, and then dividing by 4. */ 296 | static inline NSUInteger HFCountDigitsBase16(unsigned long long val) { 297 | /* __builtin_clzll doesn't like being passed 0 */ 298 | if (val == 0) return 1; 299 | 300 | /* Compute the log base 2 */ 301 | NSUInteger leadingZeros = (NSUInteger)__builtin_clzll(val); 302 | NSUInteger logBase2 = (CHAR_BIT * sizeof val) - leadingZeros - 1; 303 | return 1 + logBase2/4; 304 | } 305 | 306 | /*! Returns YES if the given string encoding is a superset of ASCII. */ 307 | BOOL HFStringEncodingIsSupersetOfASCII(NSStringEncoding encoding); 308 | 309 | /*! Converts an unsigned long long to NSUInteger. The unsigned long long should be no more than ULLONG_MAX. */ 310 | static inline unsigned long ll2l(unsigned long long val) { assert(val <= NSUIntegerMax); return (unsigned long)val; } 311 | 312 | /*! Returns an unsigned long long, which must be no more than ULLONG_MAX, as an unsigned long. */ 313 | static inline CGFloat ld2f(long double val) { 314 | #if ! NDEBUG 315 | if (isfinite(val)) { 316 | assert(val <= CGFLOAT_MAX); 317 | assert(val >= -CGFLOAT_MAX); 318 | if ((val > 0 && val < CGFLOAT_MIN) || (val < 0 && val > -CGFLOAT_MIN)) { 319 | NSLog(@"Warning - conversion of long double %Lf to CGFloat will result in the non-normal CGFloat %f", val, (CGFloat)val); 320 | } 321 | } 322 | #endif 323 | return (CGFloat)val; 324 | } 325 | 326 | /*! Returns the quotient of a divided by b, rounding up, for unsigned long longs. Will not overflow. */ 327 | static inline unsigned long long HFDivideULLRoundingUp(unsigned long long a, unsigned long long b) { 328 | if (a == 0) return 0; 329 | else return ((a - 1) / b) + 1; 330 | } 331 | 332 | /*! Returns the quotient of a divided by b, rounding up, for NSUIntegers. Will not overflow. */ 333 | static inline NSUInteger HFDivideULRoundingUp(NSUInteger a, NSUInteger b) { 334 | if (a == 0) return 0; 335 | else return ((a - 1) / b) + 1; 336 | } 337 | 338 | /*! @brief An object wrapper for the HFRange type. 339 | 340 | A simple class responsible for holding an immutable HFRange as an object. Methods that logically work on multiple HFRanges usually take or return arrays of HFRangeWrappers. */ 341 | @interface HFRangeWrapper : NSObject { 342 | @public 343 | HFRange range; 344 | } 345 | 346 | /*! Returns the HFRange for this HFRangeWrapper. */ 347 | - (HFRange)HFRange; 348 | 349 | /*! Creates an autoreleased HFRangeWrapper for this HFRange. */ 350 | + (HFRangeWrapper *)withRange:(HFRange)range; 351 | 352 | /*! Creates an NSArray of HFRangeWrappers for this HFRange. */ 353 | + (NSArray *)withRanges:(const HFRange *)ranges count:(NSUInteger)count; 354 | 355 | /*! Given an NSArray of HFRangeWrappers, get all of the HFRanges into a C array. */ 356 | + (void)getRanges:(HFRange *)ranges fromArray:(NSArray *)array; 357 | 358 | /*! Given an array of HFRangeWrappers, returns a "cleaned up" array of equivalent ranges. This new array represents the same indexes, but overlapping ranges will have been merged, and the ranges will be sorted in ascending order. */ 359 | + (NSArray *)organizeAndMergeRanges:(NSArray *)inputRanges; 360 | 361 | @end 362 | 363 | #ifndef NDEBUG 364 | void HFStartTiming(const char *name); 365 | void HFStopTiming(void); 366 | #endif 367 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFHexTextRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFHexTextRepresenter.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/3/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFHexTextRepresenter 12 | 13 | @brief HFHexTextRepresenter is an HFRepresenter responsible for showing data in hexadecimal form. 14 | 15 | HFHexTextRepresenter is an HFRepresenter responsible for showing data in hexadecimal form. It has no methods except those inherited from HFTextRepresenter. 16 | */ 17 | @interface HFHexTextRepresenter : HFTextRepresenter { 18 | unsigned long long omittedNybbleLocation; 19 | unsigned char unpartneredLastNybble; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFLayoutRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFLayoutRepresenter.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 12/10/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFLayoutRepresenter 12 | @brief An HFRepresenter responsible for arranging the views of other HFRepresenters attached to the same HFController. 13 | 14 | HFLayoutRepresenter is an HFRepresenter that manages the views of other HFRepresenters. It arranges their views in its own view, mediating between them to determine their position and size, as well as global properties such as bytes per line. 15 | 16 | HFLayoutRepresenter has an array of representers attached to it. When you add an HFRepresenter to this array, HFLayoutRepresenter will add the view of the representer as a subview of its own view. 17 | 18 | \b Layout 19 | 20 | HFLayoutRepresenter is capable of arranging the views of other HFRepresenters to fit within the bounds of its view. The layout process depends on three things: 21 | 22 | -# The \c frame and \c autoresizingMask of the representers' views. 23 | -# The \c minimumViewWidthForBytesPerLine: method, which determines the largest number of bytes per line that the representer can display for a given view width. 24 | -# The representer's \c layoutPosition. This is an NSPoint, but it is not used geometrically. Instead, the relative values of the X and Y coordinates of the \c layoutPosition determine the relative positioning of the views, as described below. 25 | 26 | Thus, to have your subclass of HFRepresenter participate in the HFLayoutRepresenter system, override \c defaultLayoutPosition: to control its positioning, and possibly \\c minimumViewWidthForBytesPerLine: if your representer requires a certain width to display some bytes per line. Then ensure your view has its autoresizing mask set properly, and if its frame is fixed size, ensure that its frame is correct as well. 27 | 28 | The layout process, in detail, is: 29 | 30 | -# The views are sorted vertically by the Y component of their representers' \c layoutPosition into "slices." Smaller values appear towards the bottom of the layout view. There is no space between slices. 31 | -# Views with equal Y components are sorted horizontally by the X component of their representers' \c layoutPosition, with smaller values appearing on the left. 32 | -# The height of each slice is determined by the tallest view within it, excluding views that have \c NSViewHeightSizable set. If there is any leftover vertical space, it is distributed equally among all slices with at least one view with \c NSViewHeightSizable set. 33 | -# If the layout representer is not set to maximize the bytes per line (BPL), then the BPL from the HFController is used. Otherwise: 34 | -# Each representer is queried for its \c minimumViewWidthForBytesPerLine: 35 | -# The largest BPL allowing each row to fit within the layout width is determined via a binary search. 36 | -# The BPL is rounded down to a multiple of the bytes per column (if non-zero). 37 | -# The BPL is then set on the controller. 38 | -# For each row, each view is assigned its minimum view width for the BPL. 39 | -# If there is any horizontal space left over, it is divided evenly between all views in that slice that have \c NSViewWidthSizable set in their autoresizing mask. 40 | 41 | */ 42 | @interface HFLayoutRepresenter : HFRepresenter { 43 | NSMutableArray *representers; 44 | BOOL maximizesBytesPerLine; 45 | 46 | } 47 | 48 | /*! @name Managed representers 49 | Managing the list of representers laid out by the receiver 50 | */ 51 | //@{ 52 | /*! Return the array of representers managed by the receiver. */ 53 | - (NSArray *)representers; 54 | 55 | /*! Adds a new representer to the receiver, triggering relayout. */ 56 | - (void)addRepresenter:(HFRepresenter *)representer; 57 | 58 | /*! Removes a representer to the receiver (which must be present in the receiver's array of representers), triggering relayout. */ 59 | - (void)removeRepresenter:(HFRepresenter *)representer; 60 | //@} 61 | 62 | /*! @name Configuration 63 | */ 64 | //@{ 65 | /*! Sets whether the receiver will attempt to maximize the bytes per line so as to consume as much as possible of the bounds rect. If this is YES, then upon relayout, the receiver will recalculate the maximum number of bytes per line that can fit in its boundsRectForLayout. If this is NO, then the receiver will not change the bytes per line. */ 66 | - (void)setMaximizesBytesPerLine:(BOOL)val; 67 | 68 | /*! Returns whether the receiver maximizes the bytes per line. */ 69 | - (BOOL)maximizesBytesPerLine; 70 | //@} 71 | 72 | /*! @name Layout 73 | Methods to get information about layout, and to explicitly trigger it. 74 | */ 75 | //@{ 76 | /*! Returns the smallest width that produces the same layout (and, if maximizes bytesPerLine, the same bytes per line) as the proposed width. */ 77 | - (CGFloat)minimumViewWidthForLayoutInProposedWidth:(CGFloat)proposedWidth; 78 | 79 | /*! Relayouts are triggered when representers are added and removed, or when the view is resized. You may call this explicitly to trigger a relayout. */ 80 | - (void)performLayout; 81 | //@} 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFLineCountingRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFLineCountingRepresenter.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/26/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @enum HFLineNumberFormat 12 | HFLineNumberFormat is a simple enum used to determine whether line numbers are in decimal or hexadecimal format. 13 | */ 14 | enum 15 | { 16 | HFLineNumberFormatDecimal, //!< Decimal line numbers 17 | HFLineNumberFormatHexadecimal, //!< Hexadecimal line numbers 18 | HFLineNumberFormatMAXIMUM //!< One more than the maximum valid line number format, so that line number formats can be cycled through easily 19 | }; 20 | typedef NSUInteger HFLineNumberFormat; 21 | 22 | /*! @class HFLineCountingRepresenter 23 | @brief The HFRepresenter used to show the "line number gutter." 24 | 25 | HFLineCountingRepresenter is the HFRepresenter used to show the "line number gutter." HFLineCountingRepresenter makes space for a certain number of digits. 26 | */ 27 | @interface HFLineCountingRepresenter : HFRepresenter { 28 | CGFloat lineHeight; 29 | NSUInteger digitsToRepresentContentsLength; 30 | NSUInteger minimumDigitCount; 31 | HFLineNumberFormat lineNumberFormat; 32 | CGFloat preferredWidth; 33 | CGFloat digitAdvance; 34 | } 35 | 36 | /*! Sets the minimum digit count. The receiver will always ensure it is big enough to display at least the minimum digit count. The default is 2. */ 37 | - (void)setMinimumDigitCount:(NSUInteger)count; 38 | 39 | /*! Gets the minimum digit count. */ 40 | - (NSUInteger)minimumDigitCount; 41 | 42 | /*! Returns the number of digits we are making space for. */ 43 | - (NSUInteger)digitCount; 44 | 45 | /*! Returns the current width that the HFRepresenter prefers to be laid out with. */ 46 | - (CGFloat)preferredWidth; 47 | 48 | /*! Returns the current line number format. */ 49 | - (HFLineNumberFormat)lineNumberFormat; 50 | 51 | /*! Sets the current line number format to a new format. */ 52 | - (void)setLineNumberFormat:(HFLineNumberFormat)format; 53 | 54 | /*! Switches to the next line number format. This is called from the view. */ 55 | - (void)cycleLineNumberFormat; 56 | 57 | @end 58 | 59 | /*! Notification posted when the HFLineCountingRepresenter's width has changed because the number of digits it wants to show has increased or decreased. The object is the HFLineCountingRepresenter; there is no user info. 60 | */ 61 | extern NSString *const HFLineCountingRepresenterMinimumViewWidthChanged; 62 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFProgressTracker.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFProgressTracker.h 3 | // HexFiend_2 4 | // 5 | // Created by peter on 2/12/08. 6 | // Copyright 2008 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! 12 | @class HFProgressTracker 13 | @brief A class that helps handle progress indication and cancellation for long running threaded operations. 14 | 15 | HFProgressTracker is a class that helps handle progress indication and cancellation for long running threaded operations, while imposing minimal overhead. Operations such as Find/Replace or Save take an HFProgressTracker to provide cancellation and progress reporting. 16 | 17 | The thread is expected to write directly into the public currentProgress field (with atomic functions) as it makes progress. Once beginTrackingProgress is called, the HFProgressTracker will poll currentProgress until endTrackingProgress is called. 18 | 19 | The thread is also expected to read directly from cancelRequested, which is set by the requestCancel method. If requestCancel is set, it should end the operation. 20 | 21 | Lastly, the thread is expected to call noteFinished: when it is done, either through cancellation or completing normally. 22 | 23 | On the client side, you can set a delegate. progressTracker: didChangeProgressTo: is called on your delegate at regular intervals in the main thread, as the progress changes. Likewise, progressTrackerDidFinish: is called on the main thread after noteFinished: is called. 24 | 25 | There is also a progressIndicator property, which if set to an NSProgressIndicator will cause it to be updated regularly. 26 | 27 | To use HFProgressTracker as a client: 28 | 29 | 30 | */ 31 | 32 | @interface HFProgressTracker : NSObject { 33 | @public 34 | volatile unsigned long long currentProgress; 35 | volatile int cancelRequested; 36 | @private 37 | unsigned long long maxProgress; 38 | NSProgressIndicator *progressIndicator; 39 | NSTimer *progressTimer; 40 | double lastSetValue; 41 | NSDictionary *userInfo; 42 | id delegate; 43 | } 44 | 45 | /*! 46 | HFProgressTracker determines the progress as an unsigned long long, but passes the progress to the delegate as a double, which is computed as the current progress divided by the max progress. 47 | */ 48 | - (void)setMaxProgress:(unsigned long long)max; 49 | - (unsigned long long)maxProgress; 50 | 51 | /*! 52 | The userInfo property is a convenience to allow passing information to the thread. The property is not thread safe - the expectation is that the main thread will set it before the operation starts, and the background thread will read it once after the operation starts. 53 | */ 54 | - (void)setUserInfo:(NSDictionary *)info; 55 | - (NSDictionary *)userInfo; 56 | 57 | /*! 58 | The progressIndicator property allows an NSProgressIndicator to be associated with the HFProgressTracker. The progress indicator should have values in the range 0 to 1, and it will be updated with the fraction currentProgress / maxProgress. 59 | */ 60 | - (void)setProgressIndicator:(NSProgressIndicator *)indicator; 61 | - (NSProgressIndicator *)progressIndicator; 62 | 63 | /*! 64 | Called to indicate you want to begin tracking the progress, which means that the progress indicator will be updated, and the delegate callbacks may fire. 65 | */ 66 | - (void)beginTrackingProgress; 67 | 68 | /*! 69 | Called to indicate you want to end tracking progress. The progress indicator will no longer be updated. 70 | */ 71 | - (void)endTrackingProgress; 72 | 73 | /*! 74 | noteFinished: should be called by the thread when it is done. It is safe to call this from the background thread. 75 | */ 76 | - (void)noteFinished:(id)sender; 77 | 78 | /*! 79 | requestCancel: may be called to mark the cancelRequested variable. The thread should poll this variable to determine if it needs to cancel. 80 | */ 81 | - (void)requestCancel:(id)sender; 82 | 83 | /*! 84 | Set and get the delegate, which may implement the optional methods below. 85 | */ 86 | - (void)setDelegate:(id)delegate; 87 | - (id)delegate; 88 | 89 | @end 90 | 91 | 92 | /*! 93 | @protocol HFProgressTrackerDelegate 94 | @brief The delegate methods for the HFProgressTracker class. 95 | 96 | The HFProgressTrackerDelegate methods are called on the the HFProgressTracker's delegate. These are always called on the main thread. 97 | */ 98 | @protocol HFProgressTrackerDelegate 99 | 100 | /*! 101 | Once beginTrackingProgress is called, this is called on the delegate at regular intervals to report on the new progress. 102 | */ 103 | - (void)progressTracker:(HFProgressTracker *)tracker didChangeProgressTo:(double)fraction; 104 | 105 | /*! 106 | Once the thread has called noteFinished:, this is called on the delegate in the main thread to report that the background thread is done. 107 | */ 108 | - (void)progressTrackerDidFinish:(HFProgressTracker *)tracker; 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFRepresenter.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/3/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | /*! @class HFRepresenter 13 | @brief The principal view class of Hex Fiend's MVC architecture. 14 | 15 | HFRepresenter is a class that visually represents some property of the HFController, such as the data (in various formats), the scroll position, the line number, etc. An HFRepresenter is added to an HFController and then gets notified of changes to various properties, through the controllerDidChange: methods. 16 | 17 | HFRepresenters also have a view, accessible through the -view method. The HFRepresenter is expected to update its view to reflect the relevant properties of its HFController. If the user can interact with the view, then the HFRepresenter should pass any changes down to the HFController, which will subsequently notify all HFRepresenters of the change. 18 | 19 | HFRepresenter is an abstract class, with a different subclass for each possible view type. Because HFController interacts with HFRepresenters, rather than views directly, an HFRepresenter can use standard Cocoa views and controls. 20 | 21 | To add a new view type: 22 | 23 | -# Create a subclass of HFRepresenter 24 | -# Override \c -createView to return a view (note that this method should transfer ownership) 25 | -# Override \c -controllerDidChange:, checking the bitmask to see what properties have changed and updating your view as appropriate 26 | -# If you plan on using this view together with other views, override \c +defaultLayoutPosition to control how your view gets positioned in an HFLayoutRepresenter 27 | -# If your view's width depends on the properties of the controller, override some of the measurement methods, such as \c +maximumBytesPerLineForViewWidth:, so that your view gets sized correctly 28 | 29 | */ 30 | @interface HFRepresenter : NSObject { 31 | @private 32 | id view; 33 | HFController *controller; 34 | NSPoint layoutPosition; 35 | } 36 | 37 | /*! @name View management 38 | Methods related to accessing and initializing the representer's view. 39 | */ 40 | //@{ 41 | /*! Returns the view for the receiver, creating it if necessary. The view for the HFRepresenter is initially nil. When the \c -view method is called, if the view is nil, \c -createView is called and then the result is stored. This method should not be overridden; however you may want to call it to access the view. 42 | */ 43 | - (id)view; 44 | 45 | /*! Override point for creating the view displaying this representation. This is called on your behalf the first time the \c -view method is called, so you would not want to call this explicitly; however this method must be overridden. This follows the "create" rule, and so it should return a retained view. 46 | */ 47 | - (NSView *)createView; 48 | 49 | /*! Override point for initialization of view, after the HFRepresenter has the view set as its -view property. The default implementation does nothing. 50 | */ 51 | - (void)initializeView; 52 | 53 | //@} 54 | 55 | /*! @name Accessing the HFController 56 | */ 57 | //@{ 58 | /*! Returns the HFController for the receiver. This is set by the controller from the call to \c addRepresenter:. A representer can only be in one controller at a time. */ 59 | - (HFController *)controller; 60 | //@} 61 | 62 | /*! @name Property change notifications 63 | */ 64 | //@{ 65 | /*! Indicates that the properties indicated by the given bits did change, and the view should be updated as to reflect the appropriate properties. This is the main mechanism by which representers are notified of changes to the controller. 66 | */ 67 | - (void)controllerDidChange:(HFControllerPropertyBits)bits; 68 | //@} 69 | 70 | /*! @name HFController convenience methods 71 | Convenience covers for certain HFController methods 72 | */ 73 | //@{ 74 | /*! Equivalent to [[self controller] bytesPerLine] */ 75 | - (NSUInteger)bytesPerLine; 76 | 77 | /*! Equivalent to [[self controller] bytesPerColumn] */ 78 | - (NSUInteger)bytesPerColumn; 79 | 80 | /*! Equivalent to [[self controller] representer:self changedProperties:properties] . You may call this when some internal aspect of the receiver's view (such as its frame) has changed in a way that may globally change some property of the controller, and the controller should recalculate those properties. For example, the text representers call this with HFControllerDisplayedLineRange when the view grows vertically, because more data may be displayed. 81 | */ 82 | - (void)representerChangedProperties:(HFControllerPropertyBits)properties; 83 | //@} 84 | 85 | /*! @name Measurement 86 | Methods related to measuring the HFRepresenter, so that it can be laid out properly by an HFLayoutController. All of these methods are candidates for overriding. 87 | */ 88 | //@{ 89 | /*! Returns the maximum number of bytes per line for the given view size. The default value is NSUIntegerMax, which means that the representer can display any number of lines for the given view size. */ 90 | - (NSUInteger)maximumBytesPerLineForViewWidth:(CGFloat)viewWidth; 91 | 92 | /*! Returns the minimum view frame size for the given bytes per line. Default is to return 0, which means that the representer can display the given bytes per line in any view size. Fixed width views should return their fixed width. */ 93 | - (CGFloat)minimumViewWidthForBytesPerLine:(NSUInteger)bytesPerLine; 94 | 95 | /*! Returns the maximum number of lines that could be displayed at once for a given view height. Default is to return DBL_MAX. */ 96 | - (double)maximumAvailableLinesForViewHeight:(CGFloat)viewHeight; 97 | //@} 98 | 99 | /*! @name Auto-layout methods 100 | Methods for simple auto-layout by HFLayoutRepresenter. See the HFLayoutRepresenter class for discussion of how it lays out representer views. 101 | */ 102 | //@{ 103 | 104 | /*! Sets the receiver's layout position to the given value. 105 | */ 106 | - (void)setLayoutPosition:(NSPoint)position; 107 | 108 | /*! Returns the layout position for the receiver. 109 | */ 110 | - (NSPoint)layoutPosition; 111 | 112 | /*! Returns the default layout position for representers of this class. Within the -init method, the view's layout position is set to the default for this class. You may override this to control the default layout position. See HFLayoutRepresenter for a discussion of the significance of the layout postition. 113 | */ 114 | + (NSPoint)defaultLayoutPosition; 115 | 116 | //@} 117 | 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFSharedMemoryByteSlice.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFSharedMemoryByteSlice.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 2/17/08. 6 | // Copyright 2008 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFSharedMemoryByteSlice 12 | @brief A subclass of HFByteSlice for working with data stored in memory. 13 | 14 | HFSharedMemoryByteSlice is a subclass of HFByteSlice that represents a portion of data from memory, e.g. typed or pasted in by the user. The term "shared" refers to the ability for mutiple HFSharedMemoryByteSlices to reference the same NSData; it does not mean that the data is in shared memory or shared between processes. 15 | 16 | Instances of HFSharedMemoryByteSlice are immutable (like all instances of HFByteSlice). However, to support efficient typing, the backing data is an instance of NSMutableData that may be grown. A referenced range of the NSMutableData will never have its contents changed, but it may be allowed to grow larger, so that the data does not have to be copied merely to append a single byte. This is implemented by overriding the -byteSliceByAppendingSlice: method of HFByteSlice. 17 | */ 18 | @interface HFSharedMemoryByteSlice : HFByteSlice { 19 | NSMutableData *data; 20 | NSUInteger offset; 21 | NSUInteger length; 22 | unsigned char inlineTailLength; 23 | unsigned char inlineTail[15]; //size chosen to exhaust padding of 32-byte allocator 24 | } 25 | 26 | // copies the data 27 | - (id)initWithUnsharedData:(NSData *)data; 28 | 29 | // retains, does not copy 30 | - (id)initWithData:(NSMutableData *)data; 31 | - (id)initWithData:(NSMutableData *)data offset:(NSUInteger)offset length:(NSUInteger)length; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFStatusBarRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFStatusBarRepresenter.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 12/16/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @enum HFStatusBarMode 12 | The HFStatusBarMode enum is used to describe the format of the byte counts displayed by the status bar. 13 | */ 14 | enum { 15 | HFStatusModeDecimal, ///< The status bar should display byte counts in decimal 16 | HFStatusModeHexadecimal, ///< The status bar should display byte counts in hexadecimal 17 | HFStatusModeApproximate, ///< The text should display byte counts approximately (e.g. "56.3 KB") 18 | HFSTATUSMODECOUNT ///< The number of modes, to allow easy cycling 19 | }; 20 | typedef NSUInteger HFStatusBarMode; 21 | 22 | /*! @class HFStatusBarRepresenter 23 | @brief The HFRepresenter for the status bar. 24 | 25 | HFStatusBarRepresenter is a subclass of HFRepresenter responsible for showing the status bar, which displays information like the total length of the document, or the number of selected bytes. 26 | */ 27 | @interface HFStatusBarRepresenter : HFRepresenter { 28 | HFStatusBarMode statusMode; 29 | } 30 | 31 | - (HFStatusBarMode)statusMode; 32 | - (void)setStatusMode:(HFStatusBarMode)mode; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFStringEncodingTextRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFASCIITextRepresenter.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/11/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFStringEncodingTextRepresenter 12 | 13 | @brief An HFRepresenter responsible for showing data interpreted via an NSStringEncoding. 14 | 15 | HFHexTextRepresenter is an HFRepresenter responsible for showing and editing data interpreted via an NSStringEncoding. Currently only supersets of ASCII are supported. 16 | */ 17 | @interface HFStringEncodingTextRepresenter : HFTextRepresenter { 18 | NSStringEncoding stringEncoding; 19 | } 20 | 21 | /*! Get the string encoding for this representer. The default encoding is [NSString defaultCStringEncoding]. */ 22 | - (NSStringEncoding)encoding; 23 | 24 | /*! Set the string encoding for this representer. */ 25 | - (void)setEncoding:(NSStringEncoding)encoding; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFTextField.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 2/2/08. 6 | // Copyright 2008 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class HFLayoutRepresenter, HFRepresenter, HFController, HFHexTextRepresenter, HFStringEncodingTextRepresenter; 12 | 13 | /*! @class HFTextField 14 | @brief A high-level view class that is analagous to NSTextField. 15 | 16 | HFTextField encapsulates a HFController and HFRepresenters into a single "do it all" NSControl analagous to NSTextField. Its objectValue is an HFByteArray. It sends its \c action to its \c target when the user hits return. It has no control. 17 | 18 | An HFTextField can be configured to show a hexadecimal view, an ASCII (really the \c defaultCStringEncoding) view, or both. 19 | 20 | This class is currently missing a fair amount of functionality, such as enabled or editable state. 21 | */ 22 | 23 | @interface HFTextField : NSControl { 24 | HFController *dataController; 25 | HFLayoutRepresenter *layoutRepresenter; 26 | HFHexTextRepresenter *hexRepresenter; 27 | HFStringEncodingTextRepresenter *textRepresenter; 28 | IBOutlet id target; 29 | SEL action; 30 | } 31 | 32 | /*! Returns whether the hexadecimal view is shown. */ 33 | - (BOOL)usesHexArea; 34 | 35 | /*! Sets whether the hexadecimal view is shown. */ 36 | - (void)setUsesHexArea:(BOOL)val; 37 | 38 | /*! Returns whether the ASCII view is shown. */ 39 | - (BOOL)usesTextArea; 40 | 41 | /*! Sets whether the ASCII view is shown. */ 42 | - (void)setUsesTextArea:(BOOL)val; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFTextRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFTextRepresenter.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/3/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | /*! @class HFTextRepresenter 13 | @brief An HFRepresenter that draws text (e.g. the hex or ASCII view). 14 | 15 | HFTextRepresenter is an abstract subclass of HFRepresenter that is responsible for displaying text. There are two concrete subclass, HFHexTextRepresenter and HFStringEncodingTextRepresenter. 16 | 17 | Most of the functionality of HFTextRepresenter is private, and there is not yet enough exposed to allow creating new representers based on it. However, there is a small amount of configurability. 18 | */ 19 | @interface HFTextRepresenter : HFRepresenter { 20 | BOOL behavesAsTextField; 21 | NSArray *rowBackgroundColors; 22 | } 23 | 24 | 25 | /*! Returns the per-row background colors. The default is -[NSControl controlAlternatingRowBackgroundColors]. */ 26 | - (NSArray *)rowBackgroundColors; 27 | 28 | /*! Sets the per-row background colors. Each row is drawn with the next color in turn, cycling back to the beginning when the array is exhausted. Any empty space is filled with the first color in the array. If the array is empty, then the background is drawn with \c clearColor. */ 29 | - (void)setRowBackgroundColors:(NSArray *)colors; 30 | 31 | /*! Set whether the text view behaves like a text field (YES) or a text view (NO). Currently this determines whether it draws a focus ring when it is the first responder. 32 | */ 33 | - (void)setBehavesAsTextField:(BOOL)val; 34 | 35 | /*! Returns whether the text view behaves like a text field (YES) or a text view (NO). 36 | */ 37 | - (BOOL)behavesAsTextField; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFTextView.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 6/28/09. 6 | // Copyright 2009 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class HFLayoutRepresenter; 13 | 14 | /*! @class HFTextView 15 | @brief A high-level view class analagous to NSTextView. 16 | 17 | HFTextField encapsulates a HFController and HFRepresenters into a single "do it all" NSControl analagous to NSTextView. 18 | */ 19 | @interface HFTextView : NSControl { 20 | HFController *dataController; 21 | HFLayoutRepresenter *layoutRepresenter; 22 | NSArray *backgroundColors; 23 | BOOL bordered; 24 | IBOutlet id delegate; 25 | NSData *cachedData; 26 | } 27 | 28 | /*! @name Accessing MVC components 29 | */ 30 | //@{ 31 | /*! Returns the HFLayoutRepresenter for the receiver. You may want to access this to add or remove HFRepresenters from the text view at runtime. */ 32 | - (HFLayoutRepresenter *)layoutRepresenter; 33 | 34 | /*! Returns the HFController for the receiver. You may want to access this to add or remove HFRepresenters from the text view at runtime. */ 35 | - (HFController *)controller; 36 | 37 | /*! Returns the HFByteArray for the receiver. This is equivalent to [[self controller] byteArray]. */ 38 | - (HFByteArray *)byteArray; 39 | 40 | //@} 41 | 42 | /*! @name Display configuration 43 | */ 44 | //@{ 45 | /*! Sets the arry of background colors for the receiver. The background colors are used in sequence to draw each row. */ 46 | - (void)setBackgroundColors:(NSArray *)colors; 47 | 48 | /*! Returns the array of background colors for the receiver. */ 49 | - (NSArray *)backgroundColors; 50 | 51 | /*! Sets whether the receiver draws a border. */ 52 | - (void)setBordered:(BOOL)val; 53 | 54 | /*! Returns whether the receiver draws a border. */ 55 | - (BOOL)bordered; 56 | //@} 57 | 58 | /*! @name Delegate handling 59 | */ 60 | //@{ 61 | /*! Sets the delegate, which may implement the methods in HFTextViewDelegate */ 62 | - (void)setDelegate:(id)delegate; 63 | 64 | /*! Returns the delegate, which is initially nil. */ 65 | - (id)delegate; 66 | //@} 67 | 68 | /*! @name Accessing contents as NSData 69 | */ 70 | //@{ 71 | /*! Returns the contents of the HFTextView's HFByteArray as an NSData This NSData proxies an HFByteArray, and therefore it is usually more efficient than naively copying all of the bytes. However, access to the \c -byte method will necessitate copying, a potentially expensive operation. Furthermore, the NSData API is inherently 32 bit in a 32 bit process. Lastly, there is no protection if the backing file for the data disappears. 72 | 73 | For those reasons, this should only be used when its convenience outweighs the downside (e.g. some bindings scenarios). For most use cases, it is better to use the \c -byteArray method above. 74 | */ 75 | - (NSData *)data; 76 | 77 | /*! Sets the contents of the HFTextView's HFByteArray to an \c NSData. Note that the data is copied via the \c -copy message, so prefer to pass an immutable \c NSData when possible. 78 | */ 79 | - (void)setData:(NSData *)data; 80 | //@} 81 | 82 | @end 83 | 84 | /*! @protocol HFTextViewDelegate 85 | @brief Delegate methods for HFTextView 86 | */ 87 | @protocol HFTextViewDelegate 88 | 89 | /*! Called on the delegate when the HFTextView's HFController changed some properties. See the documentation for the #HFControllerPropertyBits enum. */ 90 | - (void)hexTextView:(HFTextView *)view didChangeProperties:(HFControllerPropertyBits)properties; 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFTypes.h: -------------------------------------------------------------------------------- 1 | /* Hide this compatibility junk from Doxygen */ 2 | #ifndef DOXYGEN_ONLY 3 | 4 | #ifndef NSINTEGER_DEFINED 5 | #if __LP64__ || NS_BUILD_32_LIKE_64 6 | typedef long NSInteger; 7 | typedef unsigned long NSUInteger; 8 | #else 9 | typedef int NSInteger; 10 | typedef unsigned int NSUInteger; 11 | #endif 12 | #define NSIntegerMax LONG_MAX 13 | #define NSIntegerMin LONG_MIN 14 | #define NSUIntegerMax ULONG_MAX 15 | #define NSINTEGER_DEFINED 1 16 | #endif 17 | 18 | #ifndef CGFLOAT_DEFINED 19 | #if defined(__LP64__) && __LP64__ 20 | typedef double CGFloat; 21 | #define CGFLOAT_MIN DBL_MIN 22 | #define CGFLOAT_MAX DBL_MAX 23 | #define CGFLOAT_IS_DOUBLE 1 24 | #else /* !defined(__LP64__) || !__LP64__ */ 25 | typedef float CGFloat; 26 | #define CGFLOAT_MIN FLT_MIN 27 | #define CGFLOAT_MAX FLT_MAX 28 | #define CGFLOAT_IS_DOUBLE 0 29 | #endif /* !defined(__LP64__) || !__LP64__ */ 30 | #define CGFLOAT_DEFINED 1 31 | #endif 32 | 33 | #endif 34 | 35 | /*! @brief HFRange is the 64 bit analog of NSRange, containing a 64 bit location and length. */ 36 | typedef struct { 37 | unsigned long long location; 38 | unsigned long long length; 39 | } HFRange; 40 | 41 | /*! @brief HFFPRange is a struct used for representing floating point ranges, similar to NSRange. It contains two long doubles. 42 | 43 | This is useful for (for example) showing the range of visible lines. A double-precision value has 53 significant bits in the mantissa - so we would start to have precision problems at the high end of the range we can represent. Long double has a 64 bit mantissa on Intel, which means that we would start to run into trouble at the very very end of our range - barely acceptable. */ 44 | typedef struct { 45 | long double location; 46 | long double length; 47 | } HFFPRange; 48 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HFVerticalScrollerRepresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // HFRepresenterVerticalScroller.h 3 | // HexFiend_2 4 | // 5 | // Created by Peter Ammon on 11/12/07. 6 | // Copyright 2007 ridiculous_fish. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /*! @class HFVerticalScrollerRepresenter 12 | @brief An HFRepresenter responsible for showing a vertical scroll bar. 13 | 14 | HFVerticalScrollerRepresenter is an HFRepresenter whose view is a vertical NSScroller, that represents the current position within an HFController "document." It has no methods beyond those of HFRepresenter. 15 | 16 | As HFVerticalScrollerRepresenter is an especially simple representer, it makes for good sample code. 17 | */ 18 | @interface HFVerticalScrollerRepresenter : HFRepresenter { 19 | 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Headers/HexFiend.h: -------------------------------------------------------------------------------- 1 | /*! @mainpage HexFiend.framework 2 | * 3 | * @section intro Introduction 4 | * HexFiend.framework (hereafter "Hex Fiend" when there is no risk of confusion with the app by the same name) is a framework designed to enable applications to support viewing and editing of binary data. The emphasis is on editing data in a natural way, following Mac OS X text editing conventions. 5 | * 6 | * Hex Fiend is designed to work efficiently with large amounts (64 bits worth) of data. As such, it can work with arbitrarily large files without reading the entire file into memory. This includes insertions, deletions, and in-place editing. Hex Fiend can also efficiently save such changes back to the file, without requiring any additional temporary disk space. 7 | * 8 | * Hex Fiend has a clean separation between the model, view, and controller layers. The model layer allows for efficient manipulation of raw data of mixed sources, making it useful for tools that need to work with large files. 9 | * 10 | * Both the framework and the app are open source under a BSD-style license. In summary, you may use Hex Fiend in any project as long as you include the copyright notice somewhere in the documentation. 11 | * 12 | * @section requirements Requirements 13 | * Hex Fiend is only available on Mac OS X, and supported on Tiger and later. It is compiled "hybrid" (works with both garbage collection and reference counting) and 4-way fat (64 bit and 32 bit, PowerPC and Intel). Support for 64 bits worth of data is available in both 32 bit and 64 bit - there is no functional difference between the 32 bit and 64 bit versions. 14 | * 15 | * @section getting_started Getting Started 16 | * 17 | * The Hex Fiend source code is available at http://ridiculousfish.com/hexfiend/ 18 | * 19 | * The easiest way to get started is to use the Interface Builder plugin to drag a hex view into your project! Hex Fiend also comes with some sample code ("HexFiendling"), distributed as part of the project. And of course the Hex Fiend application itself is open source, acting as a more sophisticated sample code. 20 | */ 21 | 22 | 23 | #import 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | #import 30 | #import 31 | #import 32 | #import 33 | #import 34 | #import 35 | #import 36 | #import 37 | #import 38 | #import 39 | #import 40 | #import 41 | #import 42 | #import 43 | 44 | 45 | /* The following is all for Doxygen */ 46 | 47 | 48 | /*! @defgroup model Model 49 | * Hex Fiend's model classes 50 | */ 51 | ///@{ 52 | ///@class HFByteArray 53 | ///@class HFBTreeByteArray 54 | ///@class HFFullMemoryByteArray 55 | ///@class HFByteSlice 56 | ///@class HFFileByteSlice 57 | ///@class HFSharedMemoryByteSlice 58 | ///@class HFFullMemoryByteSlice 59 | 60 | ///@} 61 | 62 | 63 | /*! @defgroup view View 64 | * Hex Fiend's view classes 65 | */ 66 | ///@{ 67 | ///@class HFRepresenter 68 | ///@class HFHexTextRepresenter 69 | ///@class HFStringEncodingTextRepresenter 70 | ///@class HFLayoutRepresenter 71 | ///@class HFLineCountingRepresenter 72 | ///@class HFStatusBarRepresenter 73 | ///@class HFVerticalScrollerRepresenter 74 | ///@class HFLineCountingRepresenter 75 | 76 | ///@} 77 | 78 | /*! @defgroup controller Controller 79 | * Hex Fiend's controller classes 80 | */ 81 | ///@{ 82 | ///@class HFController 83 | 84 | ///@} 85 | 86 | /*! @defgroup highlevel High Level 87 | * Hex Fiend's "do it all" classes 88 | */ 89 | ///@{ 90 | ///@class HFTextView 91 | ///@class HFTextField 92 | 93 | ///@} 94 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/HexFiend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sirg3/Sniffer/206ea800427cd250fb13aad8ed5807fe389c4d22/HexFiend.framework/Versions/A/HexFiend -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Resources/HFCancelOff.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sirg3/Sniffer/206ea800427cd250fb13aad8ed5807fe389c4d22/HexFiend.framework/Versions/A/Resources/HFCancelOff.tiff -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Resources/HFCancelOn.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sirg3/Sniffer/206ea800427cd250fb13aad8ed5807fe389c4d22/HexFiend.framework/Versions/A/Resources/HFCancelOn.tiff -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Resources/HFModalProgress.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sirg3/Sniffer/206ea800427cd250fb13aad8ed5807fe389c4d22/HexFiend.framework/Versions/A/Resources/HFModalProgress.nib -------------------------------------------------------------------------------- /HexFiend.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | HexFiend 9 | CFBundleIdentifier 10 | com.ridiculousfish.HexFiend_Framework 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | FMWK 15 | CFBundleShortVersionString 16 | 2.0.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 200 21 | 22 | 23 | -------------------------------------------------------------------------------- /HexFiend.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /PrettyCell.h: -------------------------------------------------------------------------------- 1 | /* 2 | IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in 3 | consideration of your agreement to the following terms, and your use, installation, 4 | modification or redistribution of this Apple software constitutes acceptance of these 5 | terms. If you do not agree with these terms, please do not use, install, modify or 6 | redistribute this Apple software. 7 | 8 | In consideration of your agreement to abide by the following terms, and subject to these 9 | terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in 10 | this original Apple software (the "Apple Software"), to use, reproduce, modify and 11 | redistribute the Apple Software, with or without modifications, in source and/or binary 12 | forms; provided that if you redistribute the Apple Software in its entirety and without 13 | modifications, you must retain this notice and the following text and disclaimers in all 14 | such redistributions of the Apple Software. Neither the name, trademarks, service marks 15 | or logos of Apple Computer, Inc. may be used to endorse or promote products derived from 16 | the Apple Software without specific prior written permission from Apple. Except as expressly 17 | stated in this notice, no other rights or licenses, express or implied, are granted by Apple 18 | herein, including but not limited to any patent rights that may be infringed by your 19 | derivative works or by other works in which the Apple Software may be incorporated. 20 | 21 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, 22 | EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 23 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 24 | USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 25 | 26 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 29 | REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 30 | WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 31 | OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #import 35 | 36 | 37 | @interface PrettyCell : NSTextFieldCell { 38 | @private 39 | NSImage *image; 40 | } 41 | 42 | - (void)setImage:(NSImage *)anImage; 43 | - (NSImage *)image; 44 | 45 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView; 46 | - (NSSize)cellSize; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /PrettyCell.m: -------------------------------------------------------------------------------- 1 | /* 2 | IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in 3 | consideration of your agreement to the following terms, and your use, installation, 4 | modification or redistribution of this Apple software constitutes acceptance of these 5 | terms. If you do not agree with these terms, please do not use, install, modify or 6 | redistribute this Apple software. 7 | 8 | In consideration of your agreement to abide by the following terms, and subject to these 9 | terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in 10 | this original Apple software (the "Apple Software"), to use, reproduce, modify and 11 | redistribute the Apple Software, with or without modifications, in source and/or binary 12 | forms; provided that if you redistribute the Apple Software in its entirety and without 13 | modifications, you must retain this notice and the following text and disclaimers in all 14 | such redistributions of the Apple Software. Neither the name, trademarks, service marks 15 | or logos of Apple Computer, Inc. may be used to endorse or promote products derived from 16 | the Apple Software without specific prior written permission from Apple. Except as expressly 17 | stated in this notice, no other rights or licenses, express or implied, are granted by Apple 18 | herein, including but not limited to any patent rights that may be infringed by your 19 | derivative works or by other works in which the Apple Software may be incorporated. 20 | 21 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, 22 | EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 23 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 24 | USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 25 | 26 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 29 | REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 30 | WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 31 | OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #import "PrettyCell.h" 35 | 36 | 37 | @implementation PrettyCell 38 | - (id)init { 39 | if (self = [super init]) { 40 | [self setLineBreakMode:NSLineBreakByTruncatingTail]; 41 | [self setSelectable:YES]; 42 | } 43 | return self; 44 | } 45 | 46 | - (void)dealloc { 47 | [image release]; 48 | [super dealloc]; 49 | } 50 | 51 | - (id)copyWithZone:(NSZone *)zone { 52 | PrettyCell *cell = (PrettyCell *)[super copyWithZone:zone]; 53 | // The image ivar will be directly copied; we need to retain or copy it. 54 | cell->image = [image retain]; 55 | return cell; 56 | } 57 | 58 | - (void)setImage:(NSImage *)anImage { 59 | if (anImage != image) { 60 | [image release]; 61 | image = [anImage retain]; 62 | } 63 | } 64 | 65 | - (NSImage *)image { 66 | return image; 67 | } 68 | 69 | - (NSRect)imageRectForBounds:(NSRect)cellFrame { 70 | NSRect result; 71 | if (image != nil) { 72 | result.size = [image size]; 73 | result.origin = cellFrame.origin; 74 | result.origin.x += 1; 75 | result.origin.y += ceil((cellFrame.size.height - result.size.height) / 2); 76 | } else { 77 | result = NSZeroRect; 78 | } 79 | return result; 80 | } 81 | 82 | // We could manually implement expansionFrameWithFrame:inView: and drawWithExpansionFrame:inView: or just properly implement titleRectForBounds to get expansion tooltips to automatically work for us 83 | - (NSRect)titleRectForBounds:(NSRect)cellFrame { 84 | NSRect result; 85 | if (image != nil) { 86 | CGFloat imageWidth = [image size].width; 87 | result = cellFrame; 88 | result.origin.x += (7 + imageWidth); 89 | result.size.width -= (7 + imageWidth); 90 | } else { 91 | result = NSZeroRect; 92 | } 93 | return result; 94 | } 95 | 96 | 97 | - (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent { 98 | NSRect textFrame, imageFrame; 99 | NSDivideRect (aRect, &imageFrame, &textFrame, 7 + [image size].width, NSMinXEdge); 100 | [super editWithFrame: textFrame inView: controlView editor:textObj delegate:anObject event: theEvent]; 101 | } 102 | 103 | - (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength { 104 | NSRect textFrame, imageFrame; 105 | NSDivideRect (aRect, &imageFrame, &textFrame, 7 + [image size].width, NSMinXEdge); 106 | [super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength]; 107 | } 108 | 109 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 110 | if (image != nil) { 111 | NSRect imageFrame; 112 | NSSize imageSize = [image size]; 113 | NSDivideRect(cellFrame, &imageFrame, &cellFrame, 5 + imageSize.width, NSMinXEdge); 114 | if ([self drawsBackground]) { 115 | [[self backgroundColor] set]; 116 | NSRectFill(imageFrame); 117 | } 118 | imageFrame.origin.x += 5; 119 | imageFrame.size = imageSize; 120 | 121 | if ([controlView isFlipped]) 122 | imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2); 123 | else 124 | imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2); 125 | 126 | [image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver]; 127 | } 128 | [super drawWithFrame:cellFrame inView:controlView]; 129 | } 130 | 131 | - (NSSize)cellSize { 132 | NSSize cellSize = [super cellSize]; 133 | cellSize.width += (image ? [image size].width : 0) + 1; 134 | return cellSize; 135 | } 136 | 137 | - (NSUInteger)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView { 138 | NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil]; 139 | // If we have an image, we need to see if the user clicked on the image portion. 140 | if (image != nil) { 141 | // This code closely mimics drawWithFrame:inView: 142 | NSSize imageSize = [image size]; 143 | NSRect imageFrame; 144 | NSDivideRect(cellFrame, &imageFrame, &cellFrame, 1 + imageSize.width, NSMinXEdge); 145 | 146 | imageFrame.origin.x += 1; 147 | imageFrame.size = imageSize; 148 | // If the point is in the image rect, then it is a content hit 149 | if (NSMouseInRect(point, imageFrame, [controlView isFlipped])) { 150 | // We consider this just a content area. It is not trackable, nor it it editable text. If it was, we would or in the additional items. 151 | // By returning the correct parts, we allow NSTableView to correctly begin an edit when the text portion is clicked on. 152 | return NSCellHitContentArea; 153 | } 154 | } 155 | // At this point, the cellFrame has been modified to exclude the portion for the image. Let the superclass handle the hit testing at this point. 156 | return [super hitTestForEvent:event inRect:cellFrame ofView:controlView]; 157 | } 158 | @end 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sniffer 2 | ======= 3 | 4 | Sniffer is an unoriginally-named packet sniffer with the unique ability of determining which application a packet is coming from (or going to). At the moment it is little more than a prototype to prove that the idea works. 5 | 6 | Internals 7 | --------- 8 | 9 | Like many packet sniffers, Sniffer is split into two applications: the GUI and the capture tool. The GUI launches the capture tool as root when needed and communicates with it via a CFMessagePort. 10 | 11 | The capture tool uses `libpcap` to do the actual packet capturing. When `libpcap` tells the capture tool about a packet, it uses `libproc` to search through all of the running processes, trying to find a process with a socket that matches. Since multiple processes can have access to the file descriptor for a socket, we simply return the first one found. This may limit the usefulness of the tool for your needs, but works well in most cases. 12 | 13 | To Do 14 | ----- 15 | 16 | * remove hardcoded use of "en1" from the capture tool 17 | * add more endpoint matching (TCP/IPv6, UDP, etc) 18 | * remove Hex Fiend binary from the repository 19 | * provide a decent user interface 20 | * export capture as pcap 21 | 22 | License 23 | ------- 24 | 25 | Sniffer is released under the GPLv2 license. 26 | 27 | Redistribution 28 | -------------- 29 | 30 | Even though it is perfectly legal under the license, I urge you not to distribute binaries of Sniffer. The problem is that `libproc` is not ABI-compatible across Mac OS X releases (or even architectures of the same release). Distributing binaries could result in versions of the application that simply crash when launched on any version of the OS other than the one you built for. -------------------------------------------------------------------------------- /Sniffer-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDocumentTypes 8 | 9 | 10 | CFBundleTypeExtensions 11 | 12 | snifferSession 13 | 14 | CFBundleTypeName 15 | Sniffer 16 | CFBundleTypeRole 17 | Editor 18 | LSItemContentTypes 19 | 20 | com.alacatia.Sniffer.Session 21 | 22 | LSTypeIsPackage 23 | 24 | NSDocumentClass 25 | SnifferDocument 26 | 27 | 28 | CFBundleExecutable 29 | ${EXECUTABLE_NAME} 30 | CFBundleIconFile 31 | 32 | CFBundleIdentifier 33 | com.alacatia.${PRODUCT_NAME:rfc1034identifier} 34 | CFBundleInfoDictionaryVersion 35 | 6.0 36 | CFBundleName 37 | ${PRODUCT_NAME} 38 | CFBundlePackageType 39 | APPL 40 | CFBundleShortVersionString 41 | 1.0 42 | CFBundleSignature 43 | ???? 44 | CFBundleVersion 45 | 1 46 | LSMinimumSystemVersion 47 | ${MACOSX_DEPLOYMENT_TARGET} 48 | NSMainNibFile 49 | MainMenu 50 | NSPrincipalClass 51 | NSApplication 52 | UTExportedTypeDeclarations 53 | 54 | 55 | UTTypeConformsTo 56 | 57 | public.composite-content 58 | com.apple.package 59 | public.data 60 | 61 | UTTypeIdentifier 62 | com.alacatia.Sniffer.Session 63 | UTTypeTagSpecification 64 | 65 | public.filename-extension 66 | snifferSession 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Sniffer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; 11 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 12 | 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 13 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 14 | AC4A678A12D539ED0051B7B1 /* PrettyCell.m in Sources */ = {isa = PBXBuildFile; fileRef = AC4A678912D539ED0051B7B1 /* PrettyCell.m */; }; 15 | ACA31FDA12D2CD9400DF2343 /* HexFiend.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ACA31FD912D2CD9400DF2343 /* HexFiend.framework */; }; 16 | ACA3208312D5340E00DF2343 /* HexFiend.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = ACA31FD912D2CD9400DF2343 /* HexFiend.framework */; }; 17 | D8A2272012C339AF0085FDDE /* Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8A2271F12C339AF0085FDDE /* Utils.cpp */; }; 18 | D8A2275612C3BEA80085FDDE /* ChunkedBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8A2275512C3BEA80085FDDE /* ChunkedBuffer.cpp */; }; 19 | D8A2284212C6D7990085FDDE /* SnifferDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = D8A2284112C6D7990085FDDE /* SnifferDocument.mm */; }; 20 | D8A2285B12C6F0040085FDDE /* SnifferWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = D8A2285A12C6F0040085FDDE /* SnifferWindowController.mm */; }; 21 | D8A2286112C6F23D0085FDDE /* SnifferWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D8A2286012C6F23D0085FDDE /* SnifferWindowController.xib */; }; 22 | D8A2292512C716F40085FDDE /* SnifferCapture.mm in Sources */ = {isa = PBXBuildFile; fileRef = D8A2292412C716F40085FDDE /* SnifferCapture.mm */; }; 23 | D8B4B7EA12C1C018007BE282 /* schema.sql in Resources */ = {isa = PBXBuildFile; fileRef = D8B4B7E912C1C018007BE282 /* schema.sql */; }; 24 | D8B4B7F412C1C21E007BE282 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D8B4B7F312C1C21E007BE282 /* libsqlite3.dylib */; }; 25 | D8E9D0A612BC904000FF3450 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8E9D0A512BC904000FF3450 /* main.cpp */; }; 26 | D8E9D1D512BD59BC00FF3450 /* libpcap.A.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E9D1D412BD59BC00FF3450 /* libpcap.A.dylib */; }; 27 | D8E9D1DE12BD5A1700FF3450 /* CaptureTool in CopyFiles */ = {isa = PBXBuildFile; fileRef = D8E9D09612BC900400FF3450 /* CaptureTool */; }; 28 | D8E9D22912BD5D3200FF3450 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E9D22712BD5D2C00FF3450 /* CoreFoundation.framework */; }; 29 | D8E9D22E12BD5D4100FF3450 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E9D22D12BD5D4100FF3450 /* Security.framework */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | D8E9D1DA12BD59FB00FF3450 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = D8E9D09512BC900400FF3450; 38 | remoteInfo = Sniffer; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXCopyFilesBuildPhase section */ 43 | ACA3200112D2D48200DF2343 /* CopyFiles */ = { 44 | isa = PBXCopyFilesBuildPhase; 45 | buildActionMask = 2147483647; 46 | dstPath = "Users/zfisher/XCode Projects/Sniffer/HexFiend.framework"; 47 | dstSubfolderSpec = 10; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | ACA3202D12D2D4FA00DF2343 /* CopyFiles */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = HexFiend.framework; 56 | dstSubfolderSpec = 7; 57 | files = ( 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | ACA3203812D2D77600DF2343 /* CopyFiles */ = { 62 | isa = PBXCopyFilesBuildPhase; 63 | buildActionMask = 2147483647; 64 | dstPath = ""; 65 | dstSubfolderSpec = 10; 66 | files = ( 67 | ACA3208312D5340E00DF2343 /* HexFiend.framework in CopyFiles */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | ACA3203B12D2DB2100DF2343 /* CopyFiles */ = { 72 | isa = PBXCopyFilesBuildPhase; 73 | buildActionMask = 2147483647; 74 | dstPath = ""; 75 | dstSubfolderSpec = 10; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | ACA3208D12D5342D00DF2343 /* CopyFiles */ = { 81 | isa = PBXCopyFilesBuildPhase; 82 | buildActionMask = 2147483647; 83 | dstPath = "Users/zfisher/XCode Projects/Sniffer/HexFiend.framework"; 84 | dstSubfolderSpec = 10; 85 | files = ( 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | D8E9D1F612BD5A2B00FF3450 /* CopyFiles */ = { 90 | isa = PBXCopyFilesBuildPhase; 91 | buildActionMask = 2147483647; 92 | dstPath = ""; 93 | dstSubfolderSpec = 6; 94 | files = ( 95 | D8E9D1DE12BD5A1700FF3450 /* CaptureTool in CopyFiles */, 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | /* End PBXCopyFilesBuildPhase section */ 100 | 101 | /* Begin PBXFileReference section */ 102 | 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 103 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 104 | 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 105 | 1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 106 | 256AC3F00F4B6AF500CF3369 /* Sniffer_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sniffer_Prefix.pch; sourceTree = ""; }; 107 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 108 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 109 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 110 | 8D1107310486CEB800E47090 /* Sniffer-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Sniffer-Info.plist"; sourceTree = ""; }; 111 | 8D1107320486CEB800E47090 /* Sniffer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sniffer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 112 | AC4A678812D539ED0051B7B1 /* PrettyCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrettyCell.h; sourceTree = ""; }; 113 | AC4A678912D539ED0051B7B1 /* PrettyCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrettyCell.m; sourceTree = ""; }; 114 | ACA31FD912D2CD9400DF2343 /* HexFiend.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = HexFiend.framework; sourceTree = ""; }; 115 | D8A2271E12C339AF0085FDDE /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = ""; }; 116 | D8A2271F12C339AF0085FDDE /* Utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Utils.cpp; sourceTree = ""; }; 117 | D8A2275412C3BEA80085FDDE /* ChunkedBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChunkedBuffer.h; sourceTree = ""; }; 118 | D8A2275512C3BEA80085FDDE /* ChunkedBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChunkedBuffer.cpp; sourceTree = ""; }; 119 | D8A2284012C6D7990085FDDE /* SnifferDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SnifferDocument.h; sourceTree = ""; }; 120 | D8A2284112C6D7990085FDDE /* SnifferDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SnifferDocument.mm; sourceTree = ""; }; 121 | D8A2284412C6DC420085FDDE /* SpinLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpinLock.h; sourceTree = ""; }; 122 | D8A2285912C6F0040085FDDE /* SnifferWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SnifferWindowController.h; sourceTree = ""; }; 123 | D8A2285A12C6F0040085FDDE /* SnifferWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SnifferWindowController.mm; sourceTree = ""; }; 124 | D8A2286012C6F23D0085FDDE /* SnifferWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SnifferWindowController.xib; sourceTree = ""; }; 125 | D8A2290612C715D20085FDDE /* DatabaseLocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseLocker.h; sourceTree = ""; }; 126 | D8A2292312C716F40085FDDE /* SnifferCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SnifferCapture.h; sourceTree = ""; }; 127 | D8A2292412C716F40085FDDE /* SnifferCapture.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SnifferCapture.mm; sourceTree = ""; }; 128 | D8B4B7E912C1C018007BE282 /* schema.sql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = schema.sql; sourceTree = ""; }; 129 | D8B4B7F312C1C21E007BE282 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; 130 | D8E9D09612BC900400FF3450 /* CaptureTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CaptureTool; sourceTree = BUILT_PRODUCTS_DIR; }; 131 | D8E9D0A512BC904000FF3450 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = CaptureTool/main.cpp; sourceTree = ""; }; 132 | D8E9D1D412BD59BC00FF3450 /* libpcap.A.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpcap.A.dylib; path = usr/lib/libpcap.A.dylib; sourceTree = SDKROOT; }; 133 | D8E9D22712BD5D2C00FF3450 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 134 | D8E9D22D12BD5D4100FF3450 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 135 | D8FECD8512BE9A0700AF375F /* VMBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VMBuffer.h; path = CaptureTool/VMBuffer.h; sourceTree = ""; }; 136 | /* End PBXFileReference section */ 137 | 138 | /* Begin PBXFrameworksBuildPhase section */ 139 | 8D11072E0486CEB800E47090 /* Frameworks */ = { 140 | isa = PBXFrameworksBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 144 | D8E9D22E12BD5D4100FF3450 /* Security.framework in Frameworks */, 145 | D8B4B7F412C1C21E007BE282 /* libsqlite3.dylib in Frameworks */, 146 | ACA31FDA12D2CD9400DF2343 /* HexFiend.framework in Frameworks */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | D8E9D09412BC900400FF3450 /* Frameworks */ = { 151 | isa = PBXFrameworksBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | D8E9D1D512BD59BC00FF3450 /* libpcap.A.dylib in Frameworks */, 155 | D8E9D22912BD5D3200FF3450 /* CoreFoundation.framework in Frameworks */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXFrameworksBuildPhase section */ 160 | 161 | /* Begin PBXGroup section */ 162 | 080E96DDFE201D6D7F000001 /* Classes */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | D8A2275412C3BEA80085FDDE /* ChunkedBuffer.h */, 166 | D8A2275512C3BEA80085FDDE /* ChunkedBuffer.cpp */, 167 | D8A2284012C6D7990085FDDE /* SnifferDocument.h */, 168 | D8A2284112C6D7990085FDDE /* SnifferDocument.mm */, 169 | D8A2284412C6DC420085FDDE /* SpinLock.h */, 170 | D8A2285912C6F0040085FDDE /* SnifferWindowController.h */, 171 | D8A2285A12C6F0040085FDDE /* SnifferWindowController.mm */, 172 | D8A2290612C715D20085FDDE /* DatabaseLocker.h */, 173 | D8A2292312C716F40085FDDE /* SnifferCapture.h */, 174 | D8A2292412C716F40085FDDE /* SnifferCapture.mm */, 175 | AC4A678812D539ED0051B7B1 /* PrettyCell.h */, 176 | AC4A678912D539ED0051B7B1 /* PrettyCell.m */, 177 | ); 178 | name = Classes; 179 | sourceTree = ""; 180 | }; 181 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 185 | D8E9D1D412BD59BC00FF3450 /* libpcap.A.dylib */, 186 | D8E9D22712BD5D2C00FF3450 /* CoreFoundation.framework */, 187 | D8E9D22D12BD5D4100FF3450 /* Security.framework */, 188 | D8B4B7F312C1C21E007BE282 /* libsqlite3.dylib */, 189 | ACA31FD912D2CD9400DF2343 /* HexFiend.framework */, 190 | ); 191 | name = "Linked Frameworks"; 192 | sourceTree = ""; 193 | }; 194 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 198 | 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, 199 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 200 | ); 201 | name = "Other Frameworks"; 202 | sourceTree = ""; 203 | }; 204 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 8D1107320486CEB800E47090 /* Sniffer.app */, 208 | D8E9D09612BC900400FF3450 /* CaptureTool */, 209 | ); 210 | name = Products; 211 | sourceTree = ""; 212 | }; 213 | 29B97314FDCFA39411CA2CEA /* PacketMuncher */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | D8E9D0A012BC901600FF3450 /* CaptureTool */, 217 | D8E9D09C12BC900D00FF3450 /* GUI */, 218 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 219 | 19C28FACFE9D520D11CA2CBB /* Products */, 220 | ); 221 | name = PacketMuncher; 222 | sourceTree = ""; 223 | }; 224 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | D8B4B7E912C1C018007BE282 /* schema.sql */, 228 | 256AC3F00F4B6AF500CF3369 /* Sniffer_Prefix.pch */, 229 | 29B97316FDCFA39411CA2CEA /* main.m */, 230 | ); 231 | name = "Other Sources"; 232 | sourceTree = ""; 233 | }; 234 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 235 | isa = PBXGroup; 236 | children = ( 237 | 8D1107310486CEB800E47090 /* Sniffer-Info.plist */, 238 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 239 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, 240 | D8A2286012C6F23D0085FDDE /* SnifferWindowController.xib */, 241 | ); 242 | name = Resources; 243 | sourceTree = ""; 244 | }; 245 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 246 | isa = PBXGroup; 247 | children = ( 248 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 249 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, 250 | ); 251 | name = Frameworks; 252 | sourceTree = ""; 253 | }; 254 | D8E9D09C12BC900D00FF3450 /* GUI */ = { 255 | isa = PBXGroup; 256 | children = ( 257 | 080E96DDFE201D6D7F000001 /* Classes */, 258 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 259 | 29B97317FDCFA39411CA2CEA /* Resources */, 260 | ); 261 | name = GUI; 262 | sourceTree = ""; 263 | }; 264 | D8E9D0A012BC901600FF3450 /* CaptureTool */ = { 265 | isa = PBXGroup; 266 | children = ( 267 | D8E9D0A512BC904000FF3450 /* main.cpp */, 268 | D8FECD8512BE9A0700AF375F /* VMBuffer.h */, 269 | D8A2271E12C339AF0085FDDE /* Utils.h */, 270 | D8A2271F12C339AF0085FDDE /* Utils.cpp */, 271 | ); 272 | name = CaptureTool; 273 | sourceTree = ""; 274 | }; 275 | /* End PBXGroup section */ 276 | 277 | /* Begin PBXNativeTarget section */ 278 | 8D1107260486CEB800E47090 /* Sniffer */ = { 279 | isa = PBXNativeTarget; 280 | buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Sniffer" */; 281 | buildPhases = ( 282 | 8D1107290486CEB800E47090 /* Resources */, 283 | ACA3208D12D5342D00DF2343 /* CopyFiles */, 284 | 8D11072C0486CEB800E47090 /* Sources */, 285 | 8D11072E0486CEB800E47090 /* Frameworks */, 286 | ACA3200112D2D48200DF2343 /* CopyFiles */, 287 | ACA3202D12D2D4FA00DF2343 /* CopyFiles */, 288 | ACA3203812D2D77600DF2343 /* CopyFiles */, 289 | D8E9D1F612BD5A2B00FF3450 /* CopyFiles */, 290 | ACA3203B12D2DB2100DF2343 /* CopyFiles */, 291 | ); 292 | buildRules = ( 293 | ); 294 | dependencies = ( 295 | D8E9D1DB12BD59FB00FF3450 /* PBXTargetDependency */, 296 | ); 297 | name = Sniffer; 298 | productInstallPath = "$(HOME)/Applications"; 299 | productName = PacketMuncher; 300 | productReference = 8D1107320486CEB800E47090 /* Sniffer.app */; 301 | productType = "com.apple.product-type.application"; 302 | }; 303 | D8E9D09512BC900400FF3450 /* CaptureTool */ = { 304 | isa = PBXNativeTarget; 305 | buildConfigurationList = D8E9D09D12BC900D00FF3450 /* Build configuration list for PBXNativeTarget "CaptureTool" */; 306 | buildPhases = ( 307 | D8E9D09312BC900400FF3450 /* Sources */, 308 | D8E9D09412BC900400FF3450 /* Frameworks */, 309 | ); 310 | buildRules = ( 311 | ); 312 | dependencies = ( 313 | ); 314 | name = CaptureTool; 315 | productName = Sniffer; 316 | productReference = D8E9D09612BC900400FF3450 /* CaptureTool */; 317 | productType = "com.apple.product-type.tool"; 318 | }; 319 | /* End PBXNativeTarget section */ 320 | 321 | /* Begin PBXProject section */ 322 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 323 | isa = PBXProject; 324 | attributes = { 325 | LastUpgradeCheck = 0410; 326 | ORGANIZATIONNAME = "Alacatia Labs"; 327 | }; 328 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Sniffer" */; 329 | compatibilityVersion = "Xcode 3.2"; 330 | developmentRegion = English; 331 | hasScannedForEncodings = 1; 332 | knownRegions = ( 333 | English, 334 | Japanese, 335 | French, 336 | German, 337 | ); 338 | mainGroup = 29B97314FDCFA39411CA2CEA /* PacketMuncher */; 339 | projectDirPath = ""; 340 | projectRoot = ""; 341 | targets = ( 342 | 8D1107260486CEB800E47090 /* Sniffer */, 343 | D8E9D09512BC900400FF3450 /* CaptureTool */, 344 | ); 345 | }; 346 | /* End PBXProject section */ 347 | 348 | /* Begin PBXResourcesBuildPhase section */ 349 | 8D1107290486CEB800E47090 /* Resources */ = { 350 | isa = PBXResourcesBuildPhase; 351 | buildActionMask = 2147483647; 352 | files = ( 353 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 354 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, 355 | D8B4B7EA12C1C018007BE282 /* schema.sql in Resources */, 356 | D8A2286112C6F23D0085FDDE /* SnifferWindowController.xib in Resources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | /* End PBXResourcesBuildPhase section */ 361 | 362 | /* Begin PBXSourcesBuildPhase section */ 363 | 8D11072C0486CEB800E47090 /* Sources */ = { 364 | isa = PBXSourcesBuildPhase; 365 | buildActionMask = 2147483647; 366 | files = ( 367 | 8D11072D0486CEB800E47090 /* main.m in Sources */, 368 | D8A2275612C3BEA80085FDDE /* ChunkedBuffer.cpp in Sources */, 369 | D8A2284212C6D7990085FDDE /* SnifferDocument.mm in Sources */, 370 | D8A2285B12C6F0040085FDDE /* SnifferWindowController.mm in Sources */, 371 | D8A2292512C716F40085FDDE /* SnifferCapture.mm in Sources */, 372 | AC4A678A12D539ED0051B7B1 /* PrettyCell.m in Sources */, 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | D8E9D09312BC900400FF3450 /* Sources */ = { 377 | isa = PBXSourcesBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | D8E9D0A612BC904000FF3450 /* main.cpp in Sources */, 381 | D8A2272012C339AF0085FDDE /* Utils.cpp in Sources */, 382 | ); 383 | runOnlyForDeploymentPostprocessing = 0; 384 | }; 385 | /* End PBXSourcesBuildPhase section */ 386 | 387 | /* Begin PBXTargetDependency section */ 388 | D8E9D1DB12BD59FB00FF3450 /* PBXTargetDependency */ = { 389 | isa = PBXTargetDependency; 390 | target = D8E9D09512BC900400FF3450 /* CaptureTool */; 391 | targetProxy = D8E9D1DA12BD59FB00FF3450 /* PBXContainerItemProxy */; 392 | }; 393 | /* End PBXTargetDependency section */ 394 | 395 | /* Begin PBXVariantGroup section */ 396 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { 397 | isa = PBXVariantGroup; 398 | children = ( 399 | 089C165DFE840E0CC02AAC07 /* English */, 400 | ); 401 | name = InfoPlist.strings; 402 | sourceTree = ""; 403 | }; 404 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { 405 | isa = PBXVariantGroup; 406 | children = ( 407 | 1DDD58150DA1D0A300B32029 /* English */, 408 | ); 409 | name = MainMenu.xib; 410 | sourceTree = ""; 411 | }; 412 | /* End PBXVariantGroup section */ 413 | 414 | /* Begin XCBuildConfiguration section */ 415 | C01FCF4B08A954540054247B /* Debug */ = { 416 | isa = XCBuildConfiguration; 417 | buildSettings = { 418 | ALWAYS_SEARCH_USER_PATHS = NO; 419 | COPY_PHASE_STRIP = NO; 420 | FRAMEWORK_SEARCH_PATHS = ( 421 | "$(inherited)", 422 | "\"$(SRCROOT)\"", 423 | ); 424 | GCC_DYNAMIC_NO_PIC = NO; 425 | GCC_MODEL_TUNING = G5; 426 | GCC_OPTIMIZATION_LEVEL = 0; 427 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 428 | GCC_PREFIX_HEADER = Sniffer_Prefix.pch; 429 | INFOPLIST_FILE = "Sniffer-Info.plist"; 430 | INSTALL_PATH = "$(HOME)/Applications"; 431 | PRODUCT_NAME = Sniffer; 432 | }; 433 | name = Debug; 434 | }; 435 | C01FCF4C08A954540054247B /* Release */ = { 436 | isa = XCBuildConfiguration; 437 | buildSettings = { 438 | ALWAYS_SEARCH_USER_PATHS = NO; 439 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 440 | FRAMEWORK_SEARCH_PATHS = ( 441 | "$(inherited)", 442 | "\"$(SRCROOT)\"", 443 | ); 444 | GCC_MODEL_TUNING = G5; 445 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 446 | GCC_PREFIX_HEADER = Sniffer_Prefix.pch; 447 | INFOPLIST_FILE = "Sniffer-Info.plist"; 448 | INSTALL_PATH = "$(HOME)/Applications"; 449 | PRODUCT_NAME = Sniffer; 450 | }; 451 | name = Release; 452 | }; 453 | C01FCF4F08A954540054247B /* Debug */ = { 454 | isa = XCBuildConfiguration; 455 | buildSettings = { 456 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 457 | GCC_C_LANGUAGE_STANDARD = gnu99; 458 | GCC_OPTIMIZATION_LEVEL = 0; 459 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 460 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 461 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 462 | GCC_WARN_UNUSED_VARIABLE = YES; 463 | ONLY_ACTIVE_ARCH = YES; 464 | SDKROOT = macosx; 465 | }; 466 | name = Debug; 467 | }; 468 | C01FCF5008A954540054247B /* Release */ = { 469 | isa = XCBuildConfiguration; 470 | buildSettings = { 471 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 472 | GCC_C_LANGUAGE_STANDARD = gnu99; 473 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 474 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 475 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 476 | GCC_WARN_UNUSED_VARIABLE = YES; 477 | SDKROOT = macosx; 478 | }; 479 | name = Release; 480 | }; 481 | D8E9D09812BC900400FF3450 /* Debug */ = { 482 | isa = XCBuildConfiguration; 483 | buildSettings = { 484 | ALWAYS_SEARCH_USER_PATHS = NO; 485 | COPY_PHASE_STRIP = NO; 486 | GCC_DYNAMIC_NO_PIC = NO; 487 | GCC_MODEL_TUNING = G5; 488 | GCC_OPTIMIZATION_LEVEL = 0; 489 | INSTALL_PATH = /usr/local/bin; 490 | PRODUCT_NAME = CaptureTool; 491 | }; 492 | name = Debug; 493 | }; 494 | D8E9D09912BC900400FF3450 /* Release */ = { 495 | isa = XCBuildConfiguration; 496 | buildSettings = { 497 | ALWAYS_SEARCH_USER_PATHS = NO; 498 | COPY_PHASE_STRIP = YES; 499 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 500 | GCC_MODEL_TUNING = G5; 501 | INSTALL_PATH = /usr/local/bin; 502 | PRODUCT_NAME = Sniffer; 503 | ZERO_LINK = NO; 504 | }; 505 | name = Release; 506 | }; 507 | /* End XCBuildConfiguration section */ 508 | 509 | /* Begin XCConfigurationList section */ 510 | C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Sniffer" */ = { 511 | isa = XCConfigurationList; 512 | buildConfigurations = ( 513 | C01FCF4B08A954540054247B /* Debug */, 514 | C01FCF4C08A954540054247B /* Release */, 515 | ); 516 | defaultConfigurationIsVisible = 0; 517 | defaultConfigurationName = Release; 518 | }; 519 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Sniffer" */ = { 520 | isa = XCConfigurationList; 521 | buildConfigurations = ( 522 | C01FCF4F08A954540054247B /* Debug */, 523 | C01FCF5008A954540054247B /* Release */, 524 | ); 525 | defaultConfigurationIsVisible = 0; 526 | defaultConfigurationName = Release; 527 | }; 528 | D8E9D09D12BC900D00FF3450 /* Build configuration list for PBXNativeTarget "CaptureTool" */ = { 529 | isa = XCConfigurationList; 530 | buildConfigurations = ( 531 | D8E9D09812BC900400FF3450 /* Debug */, 532 | D8E9D09912BC900400FF3450 /* Release */, 533 | ); 534 | defaultConfigurationIsVisible = 0; 535 | defaultConfigurationName = Release; 536 | }; 537 | /* End XCConfigurationList section */ 538 | }; 539 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 540 | } 541 | -------------------------------------------------------------------------------- /Sniffer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SnifferCapture.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #import 17 | #import 18 | @class SnifferDocument; 19 | 20 | @interface SnifferCapture : NSObject { 21 | SnifferDocument *document; 22 | CFMessagePortRef messagePort; 23 | } 24 | 25 | - (id)initWithDocument:(SnifferDocument *)document; 26 | 27 | - (NSString *)captureToolPath; 28 | - (BOOL)beginCaptureWithAuthorization:(AuthorizationRef)authorizationRef; 29 | - (void)stopCapture; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /SnifferCapture.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #import "SnifferCapture.h" 17 | #import 18 | #import "SnifferDocument.h" 19 | 20 | @implementation SnifferCapture 21 | 22 | void DissectPacket(SnifferCapture *delegate, SInt32 msgid, NSData *rawData) { 23 | const char *bytes = (const char *)[rawData bytes]; 24 | pcap_pkthdr *header = (pcap_pkthdr *)bytes; 25 | const char *dataStart = (const char *)(header + 1); 26 | const char *nameStart = dataStart + header->caplen; 27 | 28 | NSData *packetData = [NSData dataWithBytes:dataStart length:header->caplen]; 29 | [delegate->document addPacket:packetData 30 | header:header 31 | identifier:msgid 32 | application:[NSString stringWithUTF8String:nameStart] 33 | metadata:nil]; 34 | } 35 | 36 | CFDataRef PacketCallback(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info) { 37 | SnifferCapture *delegate = (SnifferCapture *)info; 38 | CFDataRef dataCopy = CFDataCreateCopy(NULL, data); 39 | 40 | dispatch_async(dispatch_get_global_queue(0, 0), ^(void) { 41 | DissectPacket(delegate, msgid, (NSData *)dataCopy); 42 | CFRelease(dataCopy); 43 | }); 44 | 45 | return NULL; 46 | } 47 | 48 | - (id)initWithDocument:(SnifferDocument *)theDocument { 49 | if (self = [super init]) { 50 | document = [theDocument retain]; 51 | } 52 | 53 | return self; 54 | } 55 | 56 | - (NSString *)captureToolPath { 57 | return [[NSBundle mainBundle] pathForAuxiliaryExecutable:@"CaptureTool"]; 58 | } 59 | 60 | - (NSString *)makePortName { 61 | CFUUIDRef uuid = CFUUIDCreate(NULL); 62 | CFStringRef uuidString = CFUUIDCreateString(NULL, uuid); 63 | NSString *result = [NSString stringWithFormat:@"com.alacatia.Sniffer.%@", uuidString]; 64 | 65 | CFRelease(uuidString); 66 | CFRelease(uuid); 67 | return result; 68 | } 69 | 70 | - (BOOL)beginCaptureWithAuthorization:(AuthorizationRef)authorizationRef { 71 | NSString *portName = [self makePortName]; 72 | 73 | CFMessagePortContext context; 74 | context.version = 0; 75 | context.info = self; 76 | context.retain = CFRetain; 77 | context.release = CFRelease; 78 | context.copyDescription = CFCopyDescription; 79 | 80 | messagePort = CFMessagePortCreateLocal(NULL, (CFStringRef)portName, PacketCallback, &context, NULL); 81 | CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(NULL, messagePort, 0); 82 | CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode); 83 | CFRelease(source); 84 | 85 | NSString *snifferPathString = [self captureToolPath]; 86 | const char *snifferPath = [snifferPathString fileSystemRepresentation]; 87 | 88 | const char *args[] = { [portName UTF8String], NULL }; 89 | OSStatus err = AuthorizationExecuteWithPrivileges(authorizationRef, snifferPath, kAuthorizationFlagDefaults, (char * const *)args, NULL); 90 | 91 | return err == noErr; 92 | } 93 | 94 | - (void)stopCapture { 95 | CFMessagePortInvalidate(messagePort); 96 | CFRelease(messagePort); 97 | messagePort = NULL; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /SnifferDocument.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import "ChunkedBuffer.h" 21 | @class SnifferWindowController; 22 | 23 | @interface SnifferDocument : NSDocument { 24 | OSSpinLock databaseLock; 25 | sqlite3 *database; 26 | 27 | OSSpinLock bufferLock; 28 | ChunkedBuffer *packetBuffer; 29 | 30 | sqlite3_stmt *appSelectStmt; 31 | sqlite3_stmt *appInsertStmt; 32 | sqlite3_stmt *packetInsertStmt; 33 | sqlite3_stmt *metadataInsertStmt; 34 | sqlite3_stmt *packetDataSelectStmt; 35 | 36 | SnifferWindowController *windowController; 37 | BOOL isNewDocument; 38 | } 39 | 40 | - (BOOL)isNewDocument; 41 | 42 | - (sqlite3 *)acquireDatabase; 43 | - (void)releaseDatabase; 44 | 45 | - (void)addPacket:(NSData *)data header:(pcap_pkthdr *)header identifier:(NSUInteger)packetID application:(NSString *)application metadata:(NSDictionary *)metadata; 46 | 47 | - (NSData *)packetData:(NSUInteger)packetID; 48 | 49 | @end 50 | 51 | 52 | -------------------------------------------------------------------------------- /SnifferDocument.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #import "SnifferDocument.h" 17 | #import "SpinLock.h" 18 | #import "SnifferWindowController.h" 19 | 20 | // See http://wiki.wireshark.org/Development/LibpcapFileFormat 21 | struct pcap_hdr_t { 22 | uint32_t magic_number; /* magic number */ 23 | uint16_t version_major; /* major version number */ 24 | uint16_t version_minor; /* minor version number */ 25 | int32_t thiszone; /* GMT to local correction */ 26 | uint32_t sigfigs; /* accuracy of timestamps */ 27 | uint32_t snaplen; /* max length of captured packets, in octets */ 28 | uint32_t network; /* data link type */ 29 | }; 30 | 31 | struct pcaprec_hdr_t { 32 | uint32_t ts_sec; /* timestamp seconds */ 33 | uint32_t ts_usec; /* timestamp microseconds */ 34 | uint32_t incl_len; /* number of octets of packet saved in file */ 35 | uint32_t orig_len; /* actual length of packet */ 36 | }; 37 | 38 | 39 | @implementation SnifferDocument 40 | 41 | - (id)init { 42 | if (self = [super init]) { 43 | NSURL *initialSQLURL = [[NSBundle mainBundle] URLForResource:@"schema" withExtension:@"sql"]; 44 | NSString *initialSQL = [NSString stringWithContentsOfURL:initialSQLURL encoding:NSUTF8StringEncoding error:NULL]; 45 | 46 | sqlite3_open(":memory:", &database); 47 | sqlite3_exec(database, [initialSQL UTF8String], NULL, NULL, NULL); 48 | sqlite3_prepare_v2(database, "SELECT rowid FROM applications WHERE path = ?", -1, &appSelectStmt, NULL); 49 | sqlite3_prepare_v2(database, "INSERT INTO applications (name, path, bookmark) VALUES (?, ?, ?)", -1, &appInsertStmt, NULL); 50 | sqlite3_prepare_v2(database, "INSERT INTO packets (rowid, application_fk, data_offset, data_size) VALUES (?, ?, ?, ?)", -1, &packetInsertStmt, NULL); 51 | sqlite3_prepare_v2(database, "INSERT INTO metadata (packet_fk, name, data) VALUES (?, ?, ?)", -1, &metadataInsertStmt, NULL); 52 | sqlite3_prepare_v2(database, "SELECT data_offset, data_size FROM packets ORDER BY rowid LIMIT 1 OFFSET ?", -1, &packetDataSelectStmt, NULL); 53 | 54 | databaseLock = OS_SPINLOCK_INIT; 55 | 56 | // Create our packet buffer with an initial size of 64MB 57 | packetBuffer = new ChunkedBuffer(67108864); 58 | 59 | // Our in-memory buffer is just going to be a pcap file. The overhead for 60 | // this is pretty small and makes it pretty easy to export as pcap or load 61 | // from pcap files. 62 | pcap_hdr_t header; 63 | header.magic_number = 0xA1B2C3D4; 64 | header.version_major = 2; 65 | header.version_minor = 4; 66 | header.thiszone = 0; 67 | header.sigfigs = 0; 68 | header.snaplen = 65535; 69 | header.network = 1; 70 | packetBuffer->AppendBytes(&header, sizeof(header)); 71 | 72 | bufferLock = OS_SPINLOCK_INIT; 73 | 74 | isNewDocument = YES; 75 | } 76 | 77 | return self; 78 | } 79 | 80 | - (void)makeWindowControllers { 81 | windowController = [[SnifferWindowController alloc] initWithWindowNibName:@"SnifferWindowController"]; 82 | [self addWindowController:windowController]; 83 | } 84 | 85 | #pragma mark - 86 | 87 | - (void)addPacket:(NSData *)data header:(pcap_pkthdr *)header identifier:(NSUInteger)packetID application:(NSString *)application metadata:(NSDictionary *)metadata { 88 | off_t packetOffset; 89 | 90 | // Only put code in here that needs the file lock 91 | { 92 | SpinLock lock(&bufferLock); 93 | 94 | pcaprec_hdr_t headerRec; 95 | headerRec.ts_sec = header->ts.tv_sec; 96 | headerRec.ts_usec = header->ts.tv_usec; 97 | headerRec.incl_len = header->caplen; 98 | headerRec.orig_len = header->len; 99 | packetBuffer->AppendBytes(&headerRec, sizeof(headerRec)); 100 | 101 | packetOffset = packetBuffer->Length(); 102 | packetBuffer->AppendBytes([data bytes], [data length]); 103 | } 104 | 105 | // Only put code in here that needs the database lock 106 | { 107 | SpinLock dbLock(&databaseLock); 108 | 109 | // First, see if we have already put this application into the applications 110 | // table. If not, insert it. 111 | sqlite3_int64 appRowID = -1; 112 | sqlite3_bind_text(appSelectStmt, 1, [application UTF8String], -1, NULL); 113 | if (SQLITE_ROW == sqlite3_step(appSelectStmt)) { 114 | appRowID = sqlite3_column_int64(appSelectStmt, 0); 115 | } else { 116 | // FIXME: we might want to bookmark icons too, once we have that bit 117 | // of UI working. 118 | NSData *bookmark = [[NSURL fileURLWithPath:application] bookmarkDataWithOptions:0 119 | includingResourceValuesForKeys:nil 120 | relativeToURL:nil 121 | error:NULL]; 122 | 123 | sqlite3_bind_text(appInsertStmt, 1, [[application lastPathComponent] UTF8String], -1, NULL); 124 | sqlite3_bind_text(appInsertStmt, 2, [application UTF8String], -1, NULL); 125 | sqlite3_bind_blob(appInsertStmt, 3, [bookmark bytes], [bookmark length], NULL); 126 | sqlite3_step(appInsertStmt); 127 | sqlite3_reset(appInsertStmt); 128 | 129 | appRowID = sqlite3_last_insert_rowid(database); 130 | } 131 | sqlite3_reset(appSelectStmt); 132 | 133 | // Now that we have our application inserted, we can insert the packet 134 | sqlite3_bind_int64(packetInsertStmt, 1, packetID); 135 | sqlite3_bind_int64(packetInsertStmt, 2, appRowID); 136 | sqlite3_bind_int64(packetInsertStmt, 3, packetOffset); 137 | sqlite3_bind_int64(packetInsertStmt, 4, [data length]); 138 | sqlite3_step(packetInsertStmt); 139 | sqlite3_reset(packetInsertStmt); 140 | 141 | // Now whatever metadata we might have been given 142 | [metadata enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { 143 | // FIXME: support more types 144 | assert([key isKindOfClass:[NSString class]]); 145 | assert([value isKindOfClass:[NSString class]]); 146 | 147 | sqlite3_bind_int64(metadataInsertStmt, 1, packetID); 148 | sqlite3_bind_text(metadataInsertStmt, 2, [key UTF8String], -1, NULL); 149 | sqlite3_bind_text(metadataInsertStmt, 3, [value UTF8String], -1, NULL); 150 | sqlite3_step(metadataInsertStmt); 151 | sqlite3_reset(metadataInsertStmt); 152 | }]; 153 | } 154 | 155 | dispatch_async(dispatch_get_main_queue(), ^(void) { 156 | [windowController dataChanged]; 157 | }); 158 | } 159 | 160 | - (NSData *)packetData:(NSUInteger)packetID { 161 | NSUInteger dataOffset = 0; 162 | NSUInteger dataSize = 0; 163 | { 164 | SpinLock lock(&databaseLock); 165 | sqlite3_reset(packetDataSelectStmt); 166 | sqlite3_bind_int64(packetDataSelectStmt, 1, packetID); 167 | sqlite3_step(packetDataSelectStmt); 168 | dataOffset = sqlite3_column_int(packetDataSelectStmt, 0); 169 | dataSize = sqlite3_column_int(packetDataSelectStmt, 1); 170 | } 171 | 172 | NSMutableData *data = [NSMutableData dataWithLength:dataSize]; 173 | { 174 | SpinLock lock(&bufferLock); 175 | packetBuffer->CopyBytes(dataOffset, dataSize, [data mutableBytes]); 176 | } 177 | 178 | return data; 179 | } 180 | 181 | - (sqlite3 *)acquireDatabase { 182 | OSSpinLockLock(&databaseLock); 183 | return database; 184 | } 185 | 186 | - (void)releaseDatabase { 187 | OSSpinLockUnlock(&databaseLock); 188 | } 189 | 190 | #pragma mark - 191 | 192 | - (NSString *)temporaryFolder { 193 | NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]]; 194 | BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:path 195 | withIntermediateDirectories:YES 196 | attributes:nil 197 | error:NULL]; 198 | if (success) { 199 | return path; 200 | } else { 201 | // Hrm, we failed for some reason. Let's just return the temporary directory 202 | // and hope for the best! 203 | return NSTemporaryDirectory(); 204 | } 205 | } 206 | 207 | - (NSData *)databaseData { 208 | // Unfortunately SQLite has no way to serialize a database to bytes in memory. 209 | // Instead, it requires you to write to a file on disk. 210 | // 211 | // In the future we could optimize this with one of two strategies: 212 | // - use named pipes (mkfifo) 213 | // - implement an SQLite VFS (sqlite3_vfs_register) 214 | NSData *result = nil; 215 | 216 | NSString *backupPath = [[self temporaryFolder] stringByAppendingPathComponent:@"metadata.sqlite"]; 217 | sqlite3 *diskDB; 218 | if (SQLITE_OK == sqlite3_open([backupPath fileSystemRepresentation], &diskDB)) { 219 | SpinLock lock(&databaseLock); 220 | 221 | sqlite3_backup *backup = sqlite3_backup_init(diskDB, "main", database, "main"); 222 | if (backup) { 223 | sqlite3_backup_step(backup, -1); 224 | sqlite3_backup_finish(backup); 225 | } 226 | sqlite3_close(diskDB); 227 | } 228 | 229 | result = [NSData dataWithContentsOfFile:backupPath]; 230 | [[NSFileManager defaultManager] removeFileAtPath:backupPath handler:nil]; 231 | 232 | return result; 233 | } 234 | 235 | - (void)loadDatabaseFromData:(NSData *)data { 236 | // Unfortunately SQLite has no way to read a database from memory. Instead, 237 | // it requires you to read the file from disk. 238 | // 239 | // In the future we could optimize this with one of two strategies: 240 | // - use named pipes (mkfifo) 241 | // - implement an SQLite VFS (sqlite3_vfs_register) 242 | 243 | NSString *backupPath = [[self temporaryFolder] stringByAppendingPathComponent:@"metadata.sqlite"]; 244 | [data writeToFile:backupPath atomically:NO]; 245 | 246 | sqlite3 *diskDB; 247 | if (SQLITE_OK == sqlite3_open([backupPath fileSystemRepresentation], &diskDB)) { 248 | SpinLock lock(&databaseLock); 249 | 250 | sqlite3_backup *backup = sqlite3_backup_init(database, "main", diskDB, "main"); 251 | if (backup) { 252 | sqlite3_backup_step(backup, -1); 253 | sqlite3_backup_finish(backup); 254 | } 255 | sqlite3_close(diskDB); 256 | } 257 | 258 | [[NSFileManager defaultManager] removeFileAtPath:backupPath handler:nil]; 259 | } 260 | 261 | - (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError { 262 | NSFileWrapper *result = [[[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil] autorelease]; 263 | [result addRegularFileWithContents:[self databaseData] preferredFilename:@"metadata.sqlite"]; 264 | 265 | // Copy all the data out of our packet buffer 266 | NSMutableData *data; 267 | { 268 | SpinLock lock(&bufferLock); 269 | data = [NSMutableData dataWithLength:packetBuffer->Length()]; 270 | packetBuffer->CopyBytes(0, packetBuffer->Length(), [data mutableBytes]); 271 | } 272 | [result addRegularFileWithContents:data preferredFilename:@"packets.pcap"]; 273 | 274 | return result; 275 | } 276 | 277 | - (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError { 278 | NSDictionary *wrappers = [fileWrapper fileWrappers]; 279 | NSData *data = [[wrappers objectForKey:@"packets.pcap"] regularFileContents]; 280 | 281 | // FIXME: we should be doing endian swapping 282 | if (*(uint32_t *)[data bytes] != 0xA1B2C3D4) { 283 | return NO; 284 | } 285 | 286 | packetBuffer->AppendBytes([data bytes], [data length]); 287 | 288 | [self loadDatabaseFromData:[[wrappers objectForKey:@"metadata.sqlite"] regularFileContents]]; 289 | isNewDocument = NO; 290 | 291 | return YES; 292 | } 293 | 294 | - (BOOL)isNewDocument { 295 | return isNewDocument; 296 | } 297 | 298 | @end 299 | -------------------------------------------------------------------------------- /SnifferWindowController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri & Zach Fisher. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #import 17 | #import 18 | @class HFTextView; 19 | @class SnifferCapture; 20 | 21 | @interface SnifferWindowController : NSWindowController { 22 | SnifferCapture *capture; 23 | sqlite3_stmt *rowCountStmt; 24 | sqlite3_stmt *packetSelectStmt; 25 | sqlite3_stmt *appSelectStmt; 26 | 27 | IBOutlet HFTextView *dataView; 28 | IBOutlet NSTableView *packetsView; 29 | } 30 | 31 | - (void)dataChanged; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /SnifferWindowController.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri & Zach Fisher. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #import "SnifferWindowController.h" 17 | #import "SnifferDocument.h" 18 | #import "DatabaseLocker.h" 19 | #import "SnifferCapture.h" 20 | #import "PrettyCell.h" 21 | #import 22 | 23 | @interface SnifferWindowController () 24 | - (void)setupDatabase; 25 | - (void)launchCaptureTool; 26 | @end 27 | 28 | 29 | @implementation SnifferWindowController 30 | 31 | - (void)windowDidLoad { 32 | [self setupDatabase]; 33 | [packetsView setDelegate:self]; 34 | [packetsView setDataSource:self]; 35 | [[self window] setDelegate:self]; 36 | 37 | if ([[self document] isNewDocument]) { 38 | [self launchCaptureTool]; 39 | } 40 | } 41 | 42 | - (void)windowWillClose:(NSNotification *)notification { 43 | [capture stopCapture]; 44 | [capture release]; 45 | capture = nil; 46 | 47 | sqlite3_finalize(rowCountStmt); 48 | rowCountStmt = NULL; 49 | 50 | sqlite3_finalize(packetSelectStmt); 51 | packetSelectStmt = NULL; 52 | 53 | sqlite3_finalize(appSelectStmt); 54 | appSelectStmt = NULL; 55 | } 56 | 57 | - (void)setupDatabase { 58 | DatabaseLocker lock([self document]); 59 | sqlite3_prepare_v2(lock.Database(), "SELECT COUNT(*) FROM packets", -1, &rowCountStmt, NULL); 60 | sqlite3_prepare_v2(lock.Database(), "SELECT * FROM packets ORDER BY rowid LIMIT 1 OFFSET ?", -1, &packetSelectStmt, NULL); 61 | sqlite3_prepare_v2(lock.Database(), "SELECT path FROM applications WHERE rowid = ?", -1, &appSelectStmt, NULL); 62 | } 63 | 64 | - (void)launchCaptureTool { 65 | capture = [[SnifferCapture alloc] initWithDocument:[self document]]; 66 | 67 | NSString *snifferPathString = [capture captureToolPath]; 68 | const char *snifferPath = [snifferPathString fileSystemRepresentation]; 69 | 70 | OSStatus status = noErr; 71 | AuthorizationItem item = { 72 | "com.alactia.Sniffer.CaptureTool", 73 | strlen(snifferPath), (void *)snifferPath, 74 | 0 /* flags -- must be zero */ 75 | }; 76 | 77 | AuthorizationItemSet itemSet = { 1, &item }; 78 | AuthorizationRef authorizationRef = NULL; 79 | status = AuthorizationCreate(&itemSet, kAuthorizationEmptyEnvironment, 80 | kAuthorizationFlagDefaults | 81 | kAuthorizationFlagInteractionAllowed | 82 | kAuthorizationFlagExtendRights, 83 | &authorizationRef); 84 | [capture beginCaptureWithAuthorization:authorizationRef]; 85 | AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); 86 | } 87 | 88 | #pragma mark - 89 | 90 | - (void)dataChanged { 91 | [packetsView reloadData]; 92 | [[self document] updateChangeCount:NSChangeDone]; 93 | } 94 | 95 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { 96 | DatabaseLocker lock([self document]); 97 | 98 | sqlite3_reset(rowCountStmt); 99 | sqlite3_step(rowCountStmt); 100 | 101 | return sqlite3_column_int(rowCountStmt, 0); 102 | } 103 | 104 | - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { 105 | DatabaseLocker lock([self document]); 106 | int appRowID; 107 | NSString *result; 108 | 109 | sqlite3_bind_int64(packetSelectStmt, 1, row); 110 | sqlite3_step(packetSelectStmt); 111 | appRowID = sqlite3_column_int64(packetSelectStmt, 0); 112 | sqlite3_reset(packetSelectStmt); 113 | 114 | sqlite3_bind_int64(appSelectStmt, 1, appRowID); 115 | sqlite3_step(appSelectStmt); 116 | result = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(appSelectStmt, 0)]; 117 | sqlite3_reset(appSelectStmt); 118 | 119 | return result; 120 | } 121 | 122 | - (void)tableViewSelectionDidChange:(NSNotification *)notification { 123 | NSInteger row = [[notification object] selectedRow]; 124 | 125 | NSData *data = [[self document] packetData:row]; 126 | //[dataView setString:[data description]]; 127 | [dataView setData: data]; 128 | } 129 | 130 | - (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; 131 | { 132 | NSString *appPath = [cell stringValue]; 133 | 134 | //strip off the XXX.app/Contents/MacOS/XXX part of the appPath. FIXME? 135 | appPath = [appPath stringByDeletingLastPathComponent]; 136 | appPath = [appPath stringByDeletingLastPathComponent]; 137 | appPath = [appPath stringByDeletingLastPathComponent]; 138 | if (![appPath length]) return; 139 | 140 | NSImage *appIcon = [[NSWorkspace sharedWorkspace] iconForFile:appPath]; 141 | NSImage *smallIcon = [[[NSImage alloc] initWithSize:NSMakeSize(16.0f, 16.0f)] autorelease]; 142 | [smallIcon addRepresentation:[appIcon bestRepresentationForRect:NSMakeRect(0, 0, 16.0f, 16.0f) context:nil hints:nil]]; 143 | 144 | PrettyCell *prettyCell = (PrettyCell *)cell; 145 | [prettyCell setImage: smallIcon]; 146 | } 147 | 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /Sniffer_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Sniffer' target in the 'Sniffer' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /SpinLock.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #include 17 | 18 | /** 19 | * A simple RAII wrapper for an OSSpinLock. 20 | */ 21 | class SpinLock { 22 | public: 23 | SpinLock(OSSpinLock *lock) : 24 | mLock(lock) 25 | { 26 | OSSpinLockLock(mLock); 27 | } 28 | 29 | ~SpinLock() 30 | { 31 | OSSpinLockUnlock(mLock); 32 | } 33 | 34 | private: 35 | SpinLock(const SpinLock &other); 36 | SpinLock& operator= (const SpinLock& other); 37 | 38 | OSSpinLock *mLock; 39 | }; 40 | -------------------------------------------------------------------------------- /Utils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #include "Utils.h" 17 | #include 18 | #include 19 | 20 | static void * ThreadEntrypoint(void *info) { 21 | dispatch_block_t block = (dispatch_block_t)info; 22 | block(); 23 | 24 | // We had to create a copy of the block to pass it into pthread_create, so 25 | // be sure to release it here. 26 | Block_release(block); 27 | return NULL; 28 | } 29 | 30 | void RunBlockThreaded(dispatch_block_t block) { 31 | pthread_t result; 32 | pthread_attr_t attr; 33 | pthread_attr_init( &attr ); 34 | pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); 35 | pthread_create( &result, &attr, ThreadEntrypoint, Block_copy(block)); 36 | pthread_attr_destroy( &attr ); 37 | } 38 | -------------------------------------------------------------------------------- /Utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #include 17 | 18 | /** 19 | * Runs a block in its own pthread. 20 | */ 21 | void RunBlockThreaded(dispatch_block_t block); 22 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Joe Ranieri. 2 | // 3 | // Sniffer is free software: you can redistribute it and/or modify it under the 4 | // terms of the GNU General Public License as published by the Free Software 5 | // Foundation, either version 2 of the License, or (at your option) any later 6 | // version. 7 | // 8 | // Sniffer is distributed in the hope that it will be useful, but WITHOUT ANY 9 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10 | // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 11 | // details. 12 | // 13 | // You should have received a copy of the GNU General Public License along with 14 | // Sniffer. If not, see . 15 | 16 | #import 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | return NSApplicationMain(argc, (const char **) argv); 21 | } 22 | -------------------------------------------------------------------------------- /schema.sql: -------------------------------------------------------------------------------- 1 | PRAGMA foreign_keys = ON; 2 | 3 | CREATE TABLE applications ( 4 | name TEXT, 5 | path TEXT, 6 | bookmark BLOB 7 | ); 8 | 9 | CREATE TABLE packets ( 10 | application_fk INTEGER, 11 | data_offset INTEGER, 12 | data_size INTEGER 13 | ); 14 | 15 | CREATE TABLE metadata ( 16 | packet_fk INTEGER, 17 | name TEXT, 18 | data TEXT 19 | ); 20 | --------------------------------------------------------------------------------