{"id":900,"date":"2012-07-04T20:12:08","date_gmt":"2012-07-04T08:12:08","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=900"},"modified":"2012-07-04T20:12:08","modified_gmt":"2012-07-04T08:12:08","slug":"porting-the-objective-c-cfftpsample-to-xe2-part-1","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/900\/","title":{"rendered":"Porting the Objective-C CFFTPSample to XE2: Part 1"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>On the NZ DUG email list (yes, we still have those here) a question was recently posted asking for help with getting some FTP code working on OSX, using XE2.  This coincided nicely with my reaching a point in my Objective-C learning where this sort of exercise was of interest to me also, so I decided to try porting the <a href=\"http:\/\/developer.apple.com\/library\/mac\/#samplecode\/CFFTPSample\/Introduction\/Intro.html\">CFFTPSample from the Apple Developer reference materials<\/a> as a learning exercise.<br \/>\n<!--more--><br \/>\nWhilst I am intent on using Objective-C for any actual OSX\/iOS work, I was also curious to see just how difficult (or easy) XE2 made this task (on the off-chance that initial impressions might have been overly pessimistic) but also as an exercise in testing my level of knowledge with Objective-C gleaned so far.<\/p>\n<p>Could I take some arbitrary Objective-C code and translate it to Pascal ?<\/p>\n<p>Obviously syntax isn&#8217;t the biggest challenge here, rather understanding how the Objective-C language is &#8220;plumbed in&#8221; to the OSX\/iOS environment, which isn&#8217;t something that the language teaching materials guides (that I have been using to this point) actually deal with.<\/p>\n<p>This post is the first in a series of currently undetermined length (or frequency) in which I shall share this experience.<\/p>\n<p>For those who can&#8217;t wait for the denoument and want to know whether the exercise confirmed or dispelled my concerns w.r.t using Delphi (in it&#8217;s current form) for OSX\/iOS development, suffice to say I am continuing with my Objective-C learning.<\/p>\n<p>If you are still interested in how and why I reaffirmed this decision, read on&#8230;<\/p>\n<h3>First Things First<\/h3>\n<p>So, the first thing obviously is to download the CFFTPSample code itself.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSampleRef-xcode.png?ssl=1\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSampleRef-xcode.png?resize=150%2C150&#038;ssl=1\" alt=\"\" title=\"CFFTPSample - xcode\" width=\"150\" height=\"150\" class=\"alignleft size-thumbnail wp-image-903\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSampleRef-xcode.png?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSampleRef-xcode.png?zoom=2&amp;resize=150%2C150&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSampleRef-xcode.png?zoom=3&amp;resize=150%2C150&amp;ssl=1 450w\" sizes=\"(max-width: 150px) 100vw, 150px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>When viewing the developer reference materials from the XCode Documentation viewer application, the sample entry has an &#8220;Open Project&#8221; link.  This prompts you for the location where you wish to place the sample code and then opens the project in XCode itself.  Very slick.<\/p>\n<p>Embarcadero &#8211; take some notes here will you ?<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSample-Ref-web.png?ssl=1\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSample-Ref-web.png?resize=150%2C150&#038;ssl=1\" alt=\"\" title=\"CFFTPSample - web\" width=\"150\" height=\"150\" class=\"alignright size-thumbnail wp-image-902\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSample-Ref-web.png?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSample-Ref-web.png?zoom=2&amp;resize=150%2C150&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/CFFTPSample-Ref-web.png?zoom=3&amp;resize=150%2C150&amp;ssl=1 450w\" sizes=\"(max-width: 150px) 100vw, 150px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>If you are viewing the sample page in a browser over the web then this XCode integration is replaced by a &#8220;Download Sample Code&#8221; facility which downloads a zip &#8211; not as slick, obviously, but just goes to show that just because you have documentation on a web site that doesn&#8217;t mean you can&#8217;t also offer the same thing in a way that takes advantage of tighter integration where\/when available.<\/p>\n<h3>What it Does and Doesn&#8217;t Do<\/h3>\n<p>The CFFTPSample is a simple command line utility that supports a basic download\/upload or directory listing facility to a URL.  It respects system configured proxy settings where required and exercises the key aspects of an FTP client, so in that respects it is a useful, non-trivial example.<\/p>\n<p>At the time of writing, I have so far only translated the directory listing functionality of the sample code, but that has already thrown up enough challenges, with attendant cranial bruising and wall damage, to make these posts worth writing before the exercise is strictly complete.<\/p>\n<h3>In the main()<\/h3>\n<p>First of all, I am not &#8211; at this stage &#8211; going to show the line-by-line translation of the code as it happened.  Most of it is pretty mundane and straightforward stuff.  I shall instead focus on those things that caused headaches or are non-obvious.<\/p>\n<p>So things like the decoding of command line parameters passed to the utility I shall skip over.  Obviously there was no literal translation from the Objective-C code using <strong>argc<\/strong> and <strong>argv<\/strong> etc, rather a re-write to use <strong>ParamCount<\/strong> and <strong>ParamStr()<\/strong>.<\/p>\n<p>However, one aspect of the parameter handling did cause some unexpected trouble.<\/p>\n<h3>String Theory<\/h3>\n<p>As Delphi developers I think it can be easy to forget the pain that users of other lower level languages have to deal with when it comes to strings.  The Delphi String type is &#8211; by and large &#8211; a hugely powerful and yet deceptively simple beast (things got a bit more complicated for some of us, thanks to the way that Unicode was approached, but even then this complication results primarily in pitfalls for the unwary who venture into perhaps rarer territory than most when it comes to string handling).<\/p>\n<p>In particular we take for granted the fact that this power comes packaged in a neat little box which we can use directly with the runtime of the operating system for which it was, after-all, designed (i.e Windows) simply by the appropriate use of a type-cast.  A <strong>String<\/strong>, with all it&#8217;s power, is also a simple <strong>PChar<\/strong> when required.<\/p>\n<p>That&#8217;s fine and dandy for Windows, but things are not so straightforward when working with OS X or iOS.<\/p>\n<p>In OS X\/iOS (from now on just OS X, for brevity unless\/except where the distinction is important and thus will be mentioned) we have to deal with strings in a multitude of forms.  The most common (in the CFFTPSample at least) is the <strong>CFStringRef<\/strong> form.<\/p>\n<p>This is actually a reference to a <strong>CFString<\/strong> object, the reference\/value distinction being explicit in this case.  <strong>CFString<\/strong> is the string, to which a <strong>CFStringRef<\/strong> is a reference.  In our code (so far it seems) we always deal with a <strong>CFString<\/strong> through a <strong>CFStringRef<\/strong> reference (<strong>CFString<\/strong> isn&#8217;t even declared for us in the MacAPI.* units with XE2.  More on what is, and what is NOT in those MacAPI.* units later).<\/p>\n<p>Being a command-line sample, one of the first things I had to do in my port was to convert the various command-line parameters to the application into <strong>CFStringRef<\/strong> references.  The <strong>CoreFoundation<\/strong> library provides a number of factory functions to facilitate precisely this.<\/p>\n<p>Notice I said &#8220;functions&#8221;, not &#8220;constructors&#8221;.<\/p>\n<p>Although <strong>CFString<\/strong> is referred to as an &#8220;object&#8221;, everything we do with it is via function calls, not methods (or messages if you are already adapted to the Objective-C way of thinking).<\/p>\n<p><center><\/p>\n<h2>!! HERE BE DRAGONS !!<\/h2>\n<p><\/center><\/p>\n<p>For the unwary Delphite these factory functions include a couple of traps.<\/p>\n<p>First, there is the temptingly named <strong>CFStringCreateWithPascalString()<\/strong> function, which even allows us to specify the encoding using by that string!  Brilliant!  We can just pass in our Delphi Strings, telling OS X that they use UTF-16 and all will be well, right ?<\/p>\n<p>Wrong.<\/p>\n<p>This will compile but will not work:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  var\r\n    url: CFStringRef;\r\n  begin\r\n    :\r\n    url  := CFStringCreateWithPascalString(NIL, @ParamStr(2)[1], kCFStringEncodingUTF16);\r\n    :\r\n  end.\r\n<\/pre>\n<p>Delphi being <strong><em>Pascal<\/em><\/strong>, this is a honey trap of the first order!  A &#8220;String&#8221; in Delphi Pascal is <strong>NOT<\/strong> a &#8220;PascalString&#8221; as far as OS X thinks of them.  At least not necessarily.<\/p>\n<p>If you are still using <em>SHORTSTRINGS<\/em> in your Delphi code then yes, this is what is meant by &#8220;PascalString&#8221; in this context.  i.e. a string with a leading length byte.  Otherwise the <strong>String<\/strong> type in Delphi is actually a C string.  That is, null terminated.<\/p>\n<p>So, clearly the <strong>CFStringCreateWithCString()<\/strong> factory function is the most appropriate.  Yes ?  As we know from the convenience of being able to simply type-cast a String as a <strong>PChar<\/strong> on <em>Windows<\/em>, whenever we need to pass a <em>Delphi String<\/em> to a function expecting a <em>C string<\/em>, we just have to type-cast it, right?<\/p>\n<p>Normally, yes.  But in this case, no.<\/p>\n<p>The documentation for <strong>CFStringCreateWithCString()<\/strong> tells us that the C string supplied to the function must use an 8-bit encoding.  There is no option to specify the encoding with this function, and in XE2 a Delphi &#8220;String&#8221; is a UnicodeString, which uses UTF-16 &#8211; a 16-bit encoding.<\/p>\n<p>So, before we can use <strong>CFStringCreateWithCString()<\/strong> to create a <strong>CFStringRef<\/strong> for our command line parameters we must first re-encode those parameter strings in an 8-bit encoding.  UTF-8 would be the most obvious candidate:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  var\r\n    url: CFStringRef;\r\n    url8: RawByteString;\r\n  begin\r\n    :\r\n    url8 := UTF8Encode(ParamStr(2));\r\n    url  := CFStringCreateWithCString(NIL, PANSIChar(url8), kCFStringEncodingUTF8);\r\n    :\r\n  end.\r\n<\/pre>\n<p>This is a bit laborious however, and fortunately there is yet another factory function which is slightly more convenient: <strong>CFStringCreateWithCharacters()<\/strong><\/p>\n<p>This takes a pointer to a WideChar buffer, although slightly less conveniently it also requires that we specify the length of that buffer &#8211; null termination is no help here.<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  var\r\n    url: CFStringRef;\r\n  begin\r\n    :\r\n    url  := CFStringCreateWithCString(NIL, PWideChar(ParamStr(2)), Length(ParamStr(2)));\r\n    :\r\n  end.\r\n<\/pre>\n<h3>Conclusions of the First Part, and Next Steps<\/h3>\n<p>So, even the simple process of getting our command-line parameters into a form usable by the real &#8220;meat&#8221; of our simple sample presented some unexpected hurdles and gave us (i.e. me) our first introduction to some of the differences to expect when coming from a language that has been extended specifically to support the underlying OS and runtime in the way that Delphi originally was for Windows, versus being cajoled into spitting out the right code at the back-end without being updated on the front-end.<\/p>\n<p>Not that I think the &#8220;String&#8221; type necessarily would have been easily implemented as an OS X &#8220;native&#8221; type or in a type-compatible fashion as was possible with Delphi String and Windows *CHAR.  Just that this provides a first brush with the level of &#8220;disconnect&#8221; experienced when trying to use Delphi for OS X development.<\/p>\n<p>In the next installment in this series I shall look at another disconnect, in the form of gaping omissions in the XE2 exposures of CoreFoundation libraries available in OS X.  Even basic OS facilities are not accessible using the provided MacAPI.* units in XE2.<\/p>\n<p>Fortunately adding the required exposures is relatively straightforward, if cumbersome.  And that is what we shall look at next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> On the NZ DUG email list (yes, we still have those here) a question was recently posted asking for help with getting some FTP code working on OSX, using XE2. This coincided nicely with my reaching a point in my Objective-C learning where this sort of exercise was of interest to me also, so I [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4,143],"tags":[159,158,137,151,138,160,136],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-ew","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":791,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/791\/","url_meta":{"origin":900,"position":0},"title":"Why Does My OSX FireMonkey App Think It Is a Console App ?","date":"15 Sep 2011","format":false,"excerpt":"Because System.IsConsole is hardwired to TRUE on MAC OS: This is actually also the case for $ifdef LINUX, but nobody is likely to notice that, at least not just yet. :) But it caused me no end of confusion when my FireMonkey app behaved one way on Windows and a\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":924,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/924\/","url_meta":{"origin":900,"position":1},"title":"CFStringRef and TCFString(s)","date":"05 Jul 2012","format":false,"excerpt":"In the comments on yesterdays initial post in a series following the experiences of porting an Objective-C sample to XE2, a number of people have asked why I didn't use the TCFString record type in System.Mac.CFUtils to get the CFStringRef references that I required. The reason is embarrassingly simple. I\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":936,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/936\/","url_meta":{"origin":900,"position":2},"title":"A Pain In The Butt","date":"31 Jul 2012","format":false,"excerpt":"This post is one of those classic double-entendres for which us Brits are (in)famous, involving as it does both an actual Pain In The Butt and a euphemistic one. I have been incapacitated recently by a sudden onset of sciatica caused - so my physio seems to think - by\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":760,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/760\/","url_meta":{"origin":900,"position":3},"title":"Platform Independence Version Dependencies in the XE2 RTL","date":"14 Sep 2011","format":false,"excerpt":"So I have spent about a week now with XE2 and FireMonkey and thought I would share some of the experience so far. After an initial peek and poke around, the first order of business for me was to migrate some of my existing code to the new RTL. First\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":735,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/735\/","url_meta":{"origin":900,"position":4},"title":"RAD STUDIO XE2: Launch Event Report","date":"04 Aug 2011","format":false,"excerpt":"Today I was fortunate to be present in Auckland at the World Premier of the launch event for RAD Studio XE2. \u00a0There is so much good to report that I really don't know where to begin, so apologies if this post is a bit of a disorganised ramble. \u00a0But here\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":843,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/843\/","url_meta":{"origin":900,"position":5},"title":"XE2 Update #4 On The Horizon","date":"19 Jan 2012","format":false,"excerpt":"The release notes for Update #4 have appeared online, signalling the imminent arrival no doubt of the update itself. The good news if you are using FireMonkey is that this is a significant update, including functionality for printing. The bad news is that like update #1, this update is not\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/900"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=900"}],"version-history":[{"count":20,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/900\/revisions"}],"predecessor-version":[{"id":923,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/900\/revisions\/923"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=900"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=900"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}