Solipsism Gradient

Rainer Brockerhoff’s blog

Browsing Posts tagged XRay

What, already?

No comments

Heh. Seems the year’s over already and I almost didn’t notice.

Looking back, it’s been a busy and surprising year. I traveled more than I’d planned and wrote less. XRay II saw a lot of progress in fits and starts, but my plans to release a public beta this year didn’t work out – mostly because I had underestimated the back-end work necessary to actually save data.

On the Apple front, the year has been busy. No iPhone from Apple. Zune out, Vista out (sort of), AAPL options scandal, Leopard, Mac Pro, the Intel migration has been completed, lots of security flaps, new laptops… it’s a long list, so long I don’t feel like finding all those old links. Looking back, what surprises me most is that Apple doesn’t seem to be as interested in virtualization as I felt they should be.

And of course MacWorld is just a little over a week away. Rumors are already flying fast and furious, of course. Here are some things I believe to be more likely (not that I have any inside knowledge, I hasten to add):

  • New Apple displays, with built-in iSights and microphones.
  • New Mac Pro with 8 cores, probably with a new case design.
  • The transition is over, and people are now sure the Intel Macs are “really Macs”, so new case designs are overdue across the whole line, although in the case of the laptops I’d say that’ll be really hard. Thinner and better/larger screens of course, but there’s only so much you can do with minimalism.
  • Leopard? Perhaps we’ll finally see some UI changes. My tip for the release date is March/April.
  • iTV, no idea in which direction they’ll take that; I watch very little TV. Regarding the name(s), it would make sense to go away from the whole iThing.
  • whateverPhone: I don’t use a cellphone, so the basic idea leaves me cold. Unless Apple breaks the entire paradigm with some sort of VoIP breakthrough, it’s bound to be some sort of weak US-only experiment. Let’s hope they don’t do that. I also see no sense in having music capabilities built-in as a default. Opening it up to developers in a big way would be excellent, and the recent rumors of a stripped-down, embedded Mac OS X dovetail with that.
  • .mac is dead. It’s never worked well (or at all) outside the US, as far as I know. It’s an expensive embarrassment. Apple could close it outright, sell it to Google, or allow people to operate their own sync servers.

Re: Update: XRay

No comments

Rainer Brockerhoff wrote:

…Imagine my surprise when I learned that Peter had just published the complete Hex Fiend source code, and also started up a Wiki to explain details…

That said, I haven’t had time to look at details of his data backend yet, but that too looks like it will save me at least a month of tinkering.

Well, I’ve now had a little time to look at the Hex Fiend code.

As I expected, it builds a tree of referenced/changed byte ranges for an edited file. There’s a generic “ByteSlice” class with concrete subclasses that represent either a range of bytes inside a file or a range of bytes in memory – the latter would be the result of an editing operation like typing or pasting in stuff. That much I’m already doing myself, albeit with different names.

The interesting part comes when an edited file is saved. Hex Fiend goes to great lengths in optimizing writing time, allocated RAM, and disk space; it uses threaded AVL trees and lots of neuron grease, and while I understood very generally what’s supposed to be going on, the details are extremely daunting. My hat’s off to the wizard. And he spent similar care on optimized searching, too.

Now, just lifting all that code and plopping it into XRay II just wouldn’t be cost-effective. Yes, the result is that you can open a 240GB file on a 250GB disk, swap huge chunks of it around, and insert random bytes in the middle, and save it with no problem. Do I see this situation arising frequently for XRay II users? Frankly, no. Remember, the idea is to do structured editing of file contents, not necessarily pure hex editing… and Hex Fiend is already terrific at this (not to mention, free). I see the hex editing panels in XRay II more suited to editing small amounts of data and as a convenience to view raw file contents without necessarily changing them.

So, falling back on the old method of saving an edited file to a temporary file, then swapping it with the original if creation succeeded, means that complexity will go way down at the expense of speed (noticeable only for really huge files) and of the necessity of extra free space (same).

A second problem is that, for Hex Fiend, a file is just a sequence of bytes – no structure. For me, on the contrary, changing a byte in one place – meaning editing a representation of (say) an ID3 tag in a music file, or a QuickTime atom in a movie file – will usually mean that elsewhere in the file one (or even several) count or length fields will also have to change, preserving the file’s integrity. So my data representation tree also needs to reflect a particular file’s format as decoded by a plugin – and there may be several plugins seeing the file in different ways – and the nodes need to be more intelligent, notifying each other when necessary.

Still, seeing the Hex Fiend code has given me assurance that I can do it myself, so that’s good… icon_biggrin.gif

Update: XRay

No comments

As expected, I’ve worked a lot on XRay II during the trip. I’d hoped to get the raw data updating backend working, but unfortunately debugging the plugin interface took much more time than I had anticipated. In particular, I ran into edge cases on my automatic view resizing algorithms and had to refactor them completely; it turned out that I had 3 different cases – for NSTextFields, for my outline views, and for plugin views – which were fighting each other and thus had to be folded into a single model. Anyway, the new scheme seems conceptually sound and the only thing missing are some optimizations.

To test all this out I started work on a QuickTime plugin. Currently this has a movie preview pane and a QuickTime atoms pane. The preview pane was actually working well when we started out on the trip but it turned out to be surprisingly hard to adapt to the view resizing scheme, so I’ll have to redo it. I’m using Tiger’s new QTMovie view which does a lot of work for you, but at some point it’s unavoidable to dip into the old Carbon QuickTime API which is, to put it mildly, a confusing patchwork.

No doubt there are sound historical reasons for this, but it’s a huge pain to get it all working in a modern Cocoa environment. For instance, the movie inside a QTMovie view doesn’t necessarily obey Cocoa’s clipping rules while it is playing – especially if it’s a QTVR panorama. QTVRs also seem to override Cocoa’s cursors even if the view itself is hidden or clipped out.

The second pane does a hierarchical display of QuickTime atoms. There’s a huge and confusingly documented roster of possible QuickTime atoms and they may be nested in often unintuitive ways. So far, I’ve been just using them to debug my nested container views and the autoresizing scheme, but it’s clear that this will probably be an extreme test case for both; other plugins won’t stress these aspects so much.

With all this, the data updating scheme took a back seat. Briefly, XRay II plugins will interact with the file system over an abstraction class called XRayItem. An item can represent an actual file system item, the entire contents of one such an item’s data or resource forks, or specific subparts of those. The idea is to have plugins chop XRayItems up into smaller pieces and pass them to other plugins to format and display them. Ultimately, once a data portion is changed by some editing action by the user the changed data are cached and the changes are passed upward the chain so other plugins can update their own representations accordingly. Then, when the changes are saved, they have to be collected and written out into a reasonably efficient manner.

Turns out this is not as easy as it sounds. Starting with just the default plugins that show the hex view of a file’s data fork, the user might want to open a 20GB file, select half of it, cut it to the clipboard, past it back at the end of the file (or even another file), go back to the middle and change a single byte, then do a search/replace loop over the result. Since, on Tiger, a typical Cocoa program can allocate just a little over 2GB of RAM (and not necessarily in a single chunk), this becomes a non-trivial memory management problem.

Of course, for the vast majority of files up to a certain limit – let’s say up to 128MB or so – keeping all that in RAM and changing it there would be the simplest and not-to-slow solution, and I’ll certainly have a fallback implementation for that. And if this were a Leopard-only app with a 64-bit version, this limit could be pushed a lot higher – but it has to run on Tiger and on 32-bit systems too.

So I was putting this off while tinkering with the other parts of the app, and seriously considering asking Peter Ammon for more hints, as I knew he’d solved the problem in his excellent HexFiend hex editor. Imagine my surprise when I learned that Peter had just published the complete HexFiend source code, and also started up a Wiki to explain details. Thanks a lot, Peter. Every Cocoa developer should download this gem, there’s lots of cool stuff inside from a Cocoa team insider; I’ve already learned how to filter out all fixed-width fonts, for instance.

That said, I haven’t had time to look at details of his data backend yet, but that too looks like it will save me at least a month of tinkering.

And, packing…

No comments

We’re also packing for yet another trip. If all goes well, we’ll be in Milano (Italy) early on Sunday, catch a train to Venezia, and from there start the first of two Mediterranean cruises. In between we’ll visit friends in Verona. Back around the end of November…

Of course, I’ll take my trusty laptop and plan to make excellent progress on the XRay II project. icon_wink.gif So stay tuned for developments.

Re: Text editing…

No comments

Yet Another interim progress report on XRay II.

Turns out some of my problems with the hex editor were due to overuse of the idea to have my scrollview’s delegate do everything (including standing in for the First Responder). So I changed back to a simpler model. I now have a single view inside my scroll view as the delegate, and it stays in place – it just checks the scrollbar’s status to decide what to draw.

As this subview is declared as NSView<NSTextInput> – meaning it’s a plain subclass of NSView that obeys the NSTextInput protocol – it’s also a descendant of NSResponder, and now stuff started “just working”. Seems obvious in retrospect, of course. There’s lots of details about implementing that protocol, but it’s mostly working now; I’m still not doing any actual editing, but that’s the top item on my list of things to do next.

Several other issues are being worked on in the meantime. Many things are more complex than I anticipated, but I believe the final result will be worthwhile. The actual plugin interface is still mutating from day to day, mostly because the actual usage patterns are hard to anticipate. I have two plugins partially working: File Metadata and File Forks (which use the basic hex editor to do its work).

I’m now making a separate version of the main XRay II application to be used as the plugin developer base. This will be a stripped-down version of the application: it’ll run only the two basic plugins and a third one, the one being developed. It will also have some debugging infrastructure in place.

Next, I’ll use this to start up projects for at least two more, perhaps more, plugins of different types, both reusing basic UI elements from the main application. Hopefully this will give me enough variations to publish a rich but robust plugin interface. I envision stopping development on the main application as soon as possible – perhaps even this year, if all goes well – and doing all the rest inside plugins.

Text editing…

No comments

Autoresizing NSTextFields are now working quite well, except in one instance – when there are several of them stacked and the window is resized several times very rapidly. I’ve left this alone for now while tackling another problem: text editing. Let me explain this a little.

One of my basic UI elements is a fast hex editor view. Here’s what it looks like at present:

Three columns, hex displacement at the left, hex characters in the center, MacOSRoman (or any other encoding) to the right. All in a scrolling view. That’s where things began to get strange. For normal Cocoa use, you’d normally define an NSTextView inside an NSScrollView. The three columns might be done by NSTextBlocks, as this will be Tiger-only. Or three different NSTextContainers, each one referencing an aspect of the same NSTextStorage…

The main stumbling point here is, I want to be able to edit very large files with no performance penalty. Files tens of gigabytes in size or even larger. All the standard Cocoa text objects above are out; they use 32-bit offsets and ranges for text sizes and selections, meaning things are limited to 4GB (or even 2GB in some cases). Also, NSTextView becomes slow as molasses well before text sizes reach those magnitudes, as the entire text needs to be laid out first to determine line breaks. Also, RAM requirements to generate the hex interpretation go up – remember a standard Mac OS X app can allocate just a little over 2GB of RAM. Finally, NSScrollView uses floats to track the scroll thumb position, meaning that scroll tracking becomes imprecise when you’re trying to track millions of lines.

Well, my fate apparently is to recode most of the NeXT-era UI widgets anyway – see RBSplitView. I tackled the scroller problem first, as I needed it for the file browser anyway, and soon had a special scroll view that tracked scrolling positions with unsigned 64-bit displacements – large enough for the largest file supported by Mac OS X – and faster and simpler than the standard one. It basically consists of the vertical NSScroller and the empty (document) space to its left; no intervening NSClipView. Any subviews are relocated by the offset when the scroller changes and drawing is optimized to the visible portion.

I also put in the option to have the view’s delegate redraw the visible portion directly – this was the idea I had to optimize the hex editor. Indeed, drawing is very fast; I have my own cached CoreGraphics bitmaps of the characters, and blit them to the visible portion of the sscroll view. And only the necessary part of the displayed file needs to be accessed, thanks to mapping only that part to memory with mmap(). And putting in editing later would be easy once the display portion is finished…

Famous last words. Turns out that the Cocoa text system is rather more complex than I expected – the standard NSTextView/NSTextField objects hide that very successfully from the “normal” developer. After several days of reading the very terse docs, and trying to find out which methods are called where, I’m finally at a point where the normal text input methods are working. However, I still can’t figure out how the standard copy/cut/paste menu items are enabled, and the whole process is still too clunky for wider use.

Stay tuned for developments…

So, I needed to autoresize NSTextFields in XRay II (vertically only). Sort of a poor man’s WebView. This had to “just work” on certain NSTextFields used by third-party plugins, though, without any extra code or subclassing by the plugin writer.

There are two problems there. One is finding out the actual optimum vertical size, while editing and while not, for any type of border or bezel. Here’s the code I finally worked out, with the kind help of Daniel Jalkut:

- (NSSize)minSizeForContent {
   NSRect frame = [self frame];
   NSRect newf = frame;
   NSTextView* editor = nil;
   if ((editor = (NSTextView*)[self currentEditor])) {
      newf = [[editor layoutManager] usedRectForTextContainer:[editor textContainer]];
      newf.size.height += frame.size.height-[[self cell] drawingRectForBounds:frame].size.height;
   } else {
      newf.size.height = HUGE_VALF;
      newf.size = [[self cell] cellSizeForBounds:newf];
   }
   frame.size.height = newf.size.height;
   return frame.size;
}

So I put this into a category of NSTextField and did some runtime diddling with implementation pointers, but for other uses it could well be in a subclass.

The second problem is properly pushing down the views below the field when it is resized. The solution I ended up coding is a little too gnarly to post here, and it depends on the field and its sibling views being inside a custom NSView subclass with flipped coordinates… still, it seems to work well enough now, so I’ll leave it there and work on other stuff.

WWDC thoughts

No comments

WWDC 2006 had two main topics: the new Mac Pros and Leopard. Regarding the Mac Pros, they seem quite competitive and well-built. I’m very content with my current iMac G5 (which I bought at last year’s WWDC), so I haven’t looked at them closely; desk space is important to me. By the way, it seems that Apple Brazil has just released the local price of the standard configuration, and it comes out to US$5400. Ouch.

Regarding Leopard, there’s a nice write-up at Wikipedia, so I won’t try to enumerate everything here.

All in all, I can say this was one of my best WWDCs yet. As I’ve said before, the timing was excellent. Apple has obviously made the most of the (unusual) June-to-August delay and from the developer standpoint all important stuff was in place. Most of the Leopard APIs seem to be well-defined, reasonably stable, and of course the tools are all in place. Xcode 3.0 and the new developer tools “just work”. In one Q&A session Chris Espinosa, was asked about the stability of the tools – whether developers should rely on them for new products, or should wait for the GM release – answered “we all use them daily for building Leopard, so they have to work well!”

So, this is important news for developers. Before, existing tools were used to build a new system and the next generation of tools came out with (or after) the GM release. Now, Apple has obviously been working on the new stuff iteratively; first versions of the new frameworks were used to build first versions of the new tools, then those were in turn re-used to work on the new frameworks. Certainly this has always happened to some extent, but I believe that this synergy between tools and frameworks has now hit an important inflection point.

Apple has clearly been working towards this for years. Mac OS X ‘s frameworks are now 4-way universal, containing binaries for PowerPC 32, PowerPC 64, Intel 32 and Intel 64 bits. Therefore, applications can now be built for all 4 environments, and all are fully supported by the new developer tools. This is a well-known capability of the Mach-O executable format by the way, not a new thing; NeXT applications were also distributed for several architectures, and the Virtual PC 7 executable has binaries optimized for 5 (!) different PowerPC variants.

Framework synergy is a marvelous thing. Apple has just released a short movie showing off CoreAnimation. The “city towers” effect in the second half can be now rendered in realtime on a MacPro – something that even two years ago would have been impossible. Looking very closely you can see that some of those squares are actually playing movies! But only a developer can fully appreciate the other important aspect: the code to generate this movie has shrunk down to less than 10% of what would have been necessary in Tiger.

Let’s talk somewhat vaguely (NDA mumble mumble) about how synergy might have made this happen in the CoreAnimation case. The MacPro has a faster, 64-bit CPU architecture, as well as faster video cards. 64-bit processes can use extra CPU registers and the new vector operations which seem to, finally, have equivalent power to the PowerPC G5’s AltiVec. The LLVM compiler is now used in the OpenGL stack to add a significant speedup (and this even for low-end machines!). Add in Quartz optimizations. Add in easy Cocoa support for all of these. Add in runtime efficiences introduced by Objective C 2.0. Add in new debugging and optimization made possible by implementing DTrace. Add in the ease of programming all this with less and more reliable code. Add in some extra stuff I can’t talk about… it adds up! And comparable gains are visible all through the new system.

At the risk of repeating myself, all this ho-hum talk about Leopard just being Spaces, Time Machine and some UI tweaks to iChat and Mail is so wrong. Granted that Steve Jobs had to show some non-developer news at the keynote, given the wildly unrealistic expectations. But, it really was a Developer Preview. It was released at the right time and to the right people in order to make sure that, whenever the Leopard GM comes out (my guess would be in January at MacWorld Expo), some hundred cool new applications will be available on the same day. And they’ll necessarily be Leopard-only; expect Leopard to be adopted by a significant portion of the user base in a very short timeframe.

Now to my own projects. I’d really love to have the upcoming XRay II to be Leopard-only, but that would delay release too much, and it doesn’t really need 64-bit capabilities. However, I’ll really need some fixes introduced in the last Tiger updates, so 10.4.7 will be the minimum supported version, which should be no hardship, as I can’t imagine anyone voluntarily staying with older Tiger versions. However, some of the stuff I’ve seen at WWDC has completely changed my plans regarding certain features and capabilities, so I’ll opt for implementing things in a way that might be a little constrained under Tiger but will really be much better under Leopard.

RBSplitView has been a marvelous experience for me. It’s been very widely adopted and even the Cocoa team has promised to take a look at it (no promises, of course). And it was very gratifying to be instantly recognized by many famous developers – of course my XRay II/RBSplitView t-shirt was intended to make this very easy! I’ve received lots of positive feedback and I’m working hard on implementing my own fixes and all suggestions. Hopefully I’ll have version 1.1.4 out in a very short time. This should be universal and fully compatible with Xcode 2.4. A 64-bit version compatible with the new Interface Builder will, unfortunately, have to wait until a more widely available Leopard beta comes out – I’m waiting for word from Apple about when it’ll be kosher, as I’ll necessarily have to include some new Leopard headers and APIs.

I have updated Nudge to be universal, and it seems to still be useful on Tiger for mounted network volumes. Expect the update to be available in a few days – I’m still doing some last-minute checking. Zingg! is, unfortunately, much harder to update at the moment. I haven’t touched it since 1.4.1 came out over 2 years ago, and the source code has been pushed out to some CDR backups – and the two I’ve found are, sadly, unreadable. I still have some hope of finding a copy someday (there’s a ton of stuff stashed away from my move), but don’t count on it. Recoding it from the ground up will have to wait for Leopard, where it’ll be much easier to do – there were some awful undocumented things I had to do at the time. Sorry about that. The USInternational keyboard layout will soon be repackaged in a way that (hopefully) will work around the “custom keyboard layout is randomly deselected” bug in Tiger. I’ll need to wait for a Leopard beta to come out to check if it’ll be upwardly compatible, though. I’m trying (again) to go through Apple channels to have it included with the standard system, perhaps this time it’ll work out?

Photos licensed by Creative Commons license. Unless otherwise noted, content © 2002-2022 by Rainer Brockerhoff. Iravan child theme by Rainer Brockerhoff, based on Arjuna-X, a WordPress Theme by SRS Solutions. jQuery UI based on Aristo.