On the first point, I’ve inserted a read only DVD into my machine and am shown a “Files Ready to be Written to Disc” section. How is this helpful and not confusing to regular users? Why do I care that Windows really wanted to write a file to the DVD but can’t because it’s read only?
The second point is more subtle. The column headers don’t even apply to this icon mode. You can’t resize them in this view. They are there in case you decide to switch to a view mode that might need them. Again, how is this helpful and not confusing to regular users?
If you are working on Objective-C kode in VI the following functions and key mapping will allow you to quickly switch between the header and implementation file.
" Switch editing between" *.c and *.h files (C)" or" *.m and *.h files (ObjC)function! Flip_Extension()ifmatch(expand("%"),'\.m')>0let s:flipname = substitute(expand("%"),'\.m\(.*\)','.h\1',"")call LoadFile(s:flipname)elseifmatch(expand("%"),"\\.h")>0let s:flipname = substitute(expand("%"),'\.h\(.*\)','.m\1',"")if(filereadable(s:flipname))>0call LoadFile(s:flipname)elselet s:flipname = substitute(expand("%"),'\.h\(.*\)','.c\1',"")call LoadFile(s:flipname)endifelseifmatch(expand("%"),"\\.c")>0let s:flipname = substitute(expand("%"),'\.c\(.*\)','.h\1',"")call LoadFile(s:flipname)endif
endfun
" Find the filename in an existing buffer" if it exists open that buffer so you don't" lose your file position.function! LoadFile(filename)let s:bufname = bufname(a:filename)if(strlen(s:bufname))>0exe":buffer" s:bufnameelseexe":find " a:filename
endif
endfun
map<F4>:call Flip_Extension()<CR>
I have a habit of dragging addresses from the Safari address bar to my desktop on my Mac. Eventually these web link files pile up and things become unmanageable. Since I use dropbox, I decided to do a reboot by copying all of these files to a dropbox folder. Then when I had free time and was sitting in front of a Windows machine that was also using dropbox I could do some reading.
“Safari is on Windows, it must read .webloc files”, I naively thought. When I got to my Windows machine and had some free time I discovered that Windows Safari does not read .webloc files. The .webloc file was in a binary format. Opening the webloc file in vi showed some goobly-gook (binary data) and the URL string floating in binary data. I could have easily copied the URL in vi and pasted it into the address bar, but I’d gone this far and a program was demanding to be written.
So a .webloc file is stored as a binary plist, and reading a plist file is simple in Cocoa. This was the perfect excuse for writing an Objective-C program in Windows.
Be warned. Unlike my regular posts which I try to keep focused and to the point this one does go off on a tangent.
If you want to just skip ahead and read the kode then take a look at the following two gitHub repositories:
In a previous posting I explained how to write a simple Objective-C program in Windows. The main benefits of using Objective-C on the Macintosh are:
It’s object oriented
The frameworks/libraries provided
It’s not as ugly as C++
The frameworks and libraries are particularly important. Learning new frameworks takes time, and being able to leverage a familiar framework can save time. Frameworks can also be designed poorly making them hard to use. Lots of methods with too many parameters for example.
Even if a framework is designed well, if the documentation for that framework is poor then learning how to use that framework will still be tedious. Without proper documentation, you will need to experiment with method calls more which will take more time.
The framework that we’re talking about here is obviously Cocoa. All those classes that make Objective-C programming fun like NSString and NSData. So what options do we have for using Cocoa on Windows?
I decided to first start with Cocotron so I downloaded the latest source code. However, Cocotron can only be built through XCode on Mac OS X. Since I’m trying to do the build directly from Windows this was a non-starter but I figured having the source code handy would be a good idea.
Initially I stayed away from GNUStep because I was unsure of the licensing. I also already have a highly customized Cygwin environment so was hesitant in using GNUStep because it uses minGW and that would be another environment to customize and maintain. Later I did look into GNUStep and ported my implementation to GNUStep easily.
As far as GNUStep licensing is concerned it uses GPL and LGPL so it should be safe to link to and distribute a binary. However, I am not a lawyer and have yet to find a good explanation of the licensing terms. There is no clear document that I could find in the GNUStep installation or website that states that GNUStep uses LGPL. I determined that GNUStep is LGPL by the description on wikipedia and by looking at the license inside the header files (/GNUstep/System/Library/Headers). Documentation is not fun work, but the organization of the GNUStep documentation is particularly scatterbrained.
So with the constraint of doing the build purely in Windows, Cocotron was not an option. I decided to stay away from GNUStep temporarily so what option did that leave me with? Surely I wasn’t going to build my own Cocoa framework. That would be pure folly.
Core Foundation
Well there was another option I didn’t mention, Core Foundation. Like the Objective-C runtime, Apple has been releasing their Core Foundation library as open source for some time now. Core Foundation is not Objective-C kode, it is pure C, however the names of the C structures are eerily similar to some Objective-C foundation classes. Core Foundation has a CFStringRef (NSString), CFArrayRef(NSArray), etc. So it didn’t seem far fetched to write Objective-C wrappers for these C data structures.
I downloaded and compiled Core Foundation, which was a little bit more difficult than I expected. Like the Objective-C runtime the build is not always verified to see if it works in Windows so some massaging is required. If you are interested in doing this then check out the links below this paragraph. Building Core Foundation is a good exercise, because it will help familiarize you with the library if you read some of the kode. Now that I’ve built it however, I will just grab a copy out of a Safari installation because it’s just plain easier.
Once I decided to write Objective-C wrappers for Core Foundation I wondered if that was what Cocotron did. So I looked at the CocoTron kode and discovered that CocoTron does not rely on Core Foundation. This surprised me because it went completely against my lazy programmer instincts. Why reinvent the wheel? You have this highly tested kode base that you can use but you’re going to rewrite it?
Eventually Christopher Lloyd did explain that CocoTron does not use Core Foundation because of some philosophical issues with regard to the APSL (Apple Software License Agreement).
If you modify any APSL kode you must clearly mark what you modified.
Apple has the right to terminate the APSL.
Christopher believes that issue #1 would be a long term hassle. Personally I just wouldn’t modify any APSL kode unless there were no other options. Fix any issues with the kode in the wrapper layer, or provide an alternative implementation if the APSL kode doesn’t work properly.
Issue #2 is nothing to get your feathers ruffled about. Sure it sounds pretty nasty but this is a corporate cover your ass clause. Apple has been releasing stuff under APSL for 10 years now and I have not heard of them terminating the license on anything. I can see this clause only being used in exceptional circumstances because the PR backlash it would generate in the programmer world (general consumers couldn’t care less) could be big.
Here are some interesting links. If you’re smart enough to read then you’re smart enough to think. Make up your own mind about the APSL.
So the stage has been set and now you know the actors. I decided to call the program lilac for lack of a better name. I first wrote lilac in pure C with Core Foundation to read the .webloc file as a plist and print out the URL value to the console. This was very easy as Apple has the kode to read a plist file with Core Foundation here. Then I figured out how to read the default web browser from the registry (fun) and open a link in the default browser (see mondoWin32/WinHelper.m).
After the core logic was built I started implementing it in Objective-C. I created only the Cocoa objects that I needed, with the methods that I needed and put these source files in a directory called cocoaLite. I copied what code I could from CocoTron but some of the logic is obviously different since I was plugging into Core Foundation.
In the end I really only created NSString and NSArray, but this was enough for me to prove that it could be done. Since the application I was creating is very short-lived (it reads a file and passes an URL to a browser and then dies), there was no need to support memory management (retain, release, pools).
How NSString Works
The trickiest part of the implementation was getting NSString working, and the Cocotron kode was very helpful in this regard. Actually the trickiest part was sitting down and learning how to write a makefile but that was more patience and reading than anything else; I had been avoiding that for years anyway.
To get @”" string constants to work you need to do the following:
@implementationNSString// NSString is a stub class that creates another class// that extends NSString. We need to do this// so that the variable signature does not interfere// with NSConstantString which allows us to use @"blah"// to construct strings.+(id)alloc {return(id)class_create_instance([NSStringCF class]);
}
Create an NSStringCF class that extends NSString and works as a wrapper for a Core Foundation CFStringRef.Because you’re going to need a non-constant implementation of NSString.
So I defined NSString, and NSArray, and I could have implemented NSData but I didn’t. I felt I had gotten a good feeling as to how much work was required to create Objective-C wrappers for all the Core Foundation objects (alot).
Later I followed a tutorial on how to install GNUStep and create a HelloWorld application. The installation for GNUStep strikes me as odd. You have to run three installers to use GNUStep, and it is this type of disorganization that makes people shy away from things. However, once you go through all those hoops, like an obedient show dog, you get the benefit of an Objective-C API (OpenStep/Cocoa) that you can program against.
Converting lilac to use GNUStep (lilacStep) was quick and easy. The biggest stumbling block that I had was accidently typing “make” from a Cygwin window instead of the minGW. Because I had access to a framework almost identical to Cocoa I could delete the files from src/CocoaLite and simplify the makefile. I could also greatly simplify the implementation of getURLFromWeblocFilename since I had access to NSData and NSDictionary.
So for some reason or another you need to get something from a DMG file and there isn’t a Mac in the vicinity. It is possible, and you don’t need to pay $50 for something like MacDrive.
For the super lazy and non-koder types you can use dmg2iso to create an ISO from the DMG file. Then mount the ISO with some windows ISO mounting software.
I didn’t do this. I downloaded the source to dmg2img and read the README. Yes, I actually read README files, why do you think they’re named so? This pointed me in the direction of libdmg-hfsplus.
People looking for a more professional tool should take a look to the libdmg library and related utilities at
libdmg-hfsplus uses CMake so make sure you have cmake installed. You can either install the cygwin package or get the latest Windows version. I recommend the cygwin version since that’s what I used.
Execute these commands in the root libdmg-hfsplus directory:
cmake ./
make
Now you’ve built the tools you need to cut through DMG files like butter.
dmg.exe
hdutil.exe
hfsplus.exe
Copy the exe files somewhere that is in your path (~/bin for example).
Use the Tools
To test this out you’re gonna need a DMG file. You can download the DMG file I used here. It’s zipped up so you should probably unzip it.
Of the three executable files you built the only one you really need to use is hdutil. Here is the command to list the contents of a DMG file.
hdutil SunFlowerPublic-0.7.dmg ls
The ls command will also take a parameter which will let you explore the contents of the DMG file system.
hdutil SunFlowerPublic-0.7.dmg ls /SunFlower.app/Contents
The extract command wants two arguments. The first is the location of the file in the DMG file. The second is where to put the file on your machine.
Perplexingly, nowhere on the Bluebird page does it state what Bluebird is. I had to download it and run it to find out. Quite forgivable though since they are in beta.
Matthieu Cormier has been developing and releasing Macintosh software since 2003. He is pursuing a full-time career as a Macintosh developer but keeps getting roped into bland web-based enterprise projects.