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.