EagleFiler 1.9.14
EagleFiler 1.9.14 is a maintenance release for my Mac information organizer app.
Some interesting bugs were:
EagleFiler uses
NSXMLParser
to read Evernote’s ENEX files, which it then converts to standard RTF/RTFD files that any app can read. Some customers had files that were causing it to fail withNSXMLParserUndeclaredEntityError
even though the referenced entities did not appear anywhere in the XML that I was giving the parser. It turns out that sometimes Evernote notes contain images in SVG format (which is based on XML). If Evernote isn’t able to download the image it will in its place save an HTML error page and say that it’simage/svg+xml
. This HTML may contain entities that are not valid in XML. (And, of course, it’s not valid SVG.)But why would this matter when I wasn’t asking it to parse that “XML”? Well, I was putting the bad SVG files into an
NSAttributedString
and saving it as RTFD. I thought it just wrote out the data for the attachments without looking at it. But, apparently, Cocoa creates its ownNSXMLParser
to read the SVG. When it encounters the parse error it doesn’t report it back to via the RTF-generation method that I had called. Instead, it clobbers the internal state of myNSXMLParser
. The documentation says:Unless used in a callback, the
NSXMLParser
is a thread-safe class as long as any given instance is only used in one thread.which led me to think that I would be safe confining my own parser object to a single thread. However, I’m not entirely sure what “Unless used in a callback” means here. Callback for what? I was using
NSAttributedString
in a callback for myNSXMLParser
. It appears thatNSXMLParser
is not re-entrant even across different parser instances. If that’s the problem, I don’t know how you’re supposed to know which APIs might create their ownNSXMLParser
, so you can’t really do anything in a parser callback. The whole reason I’m using a SAX parser is that people want to import multi-GB files without reading them into memory. So I don’t want to just store the data from the callback in memory and process it later, nor do I want to temporarily write chunks of partially processed data to disk for later processing. I ended up working around the problem by forcingNSAttributedString
to create its parser in a different thread.Another
NSXMLParser
issue. I knew that-parser:foundCharacters:
could be called multiple times for a single block of text, but I thought this only occurred for large blocks. It turns out that, if there are non-ASCII characters, it can be called multiple times even for very short strings, and there were a few cases where this wasn’t properly handled. This one is purely my fault.Another
NSAttributedString
issue. Files attached to Evernote notes can have very long names, and I was truncating them to fit the maximum supported filename length.NSAttributedString
can handle multiple attachments with the same name; it will add a numeric prefix to make the names unique. However, if the name is long,NSAttributedString
does not check that the filename is still valid after adding the prefix. So EagleFiler needs to pre-process the filenames so that they are still valid afterNSAttributedString
mucks with them.A recent version of Safari broke the
document
AppleScript object, which I think had been supported for over 20 years. The properties that I wanted to access (to import from Safari) do seem to work on thetab
object, so I rewrote my script to use that. It only does this if the old way fails because it’s not practical for me to test all the old versions of Safari to make sure the new way works with them. It looks like Apple may have fixed thedocument
bug in the macOS 14.5 beta.Text from different fields needed actual token separators so that Search Kit would not find phrase matches across field boundaries.
Previously:
1 Comment RSS · Twitter · Mastodon
I appreciate these bug reports and how you worked through them. Gives me stuff to watch out for.
NSXMLParser is a real piece of work and the edge cases of NSAttributedString continue to bite.