Thursday, September 15, 2011

Compiling Your Own Version of SQLite for iOS and applying some fixes

Adding your own version of sqlite for iOS is fairly easy task.
  1. Go to http://www.sqlite.org/ and download the latest sqlite amalgamation archive
  2. Extract it somewhere and add it to your Xcode project. You have several options here. You could copy it to your project folder, or link to it. You could also decide, to put it as a static library target and link it to your main target. It's up to you. You will need only sqlite.c and sqlite.h files.
  3. Apply some #defines you might need. For example:
#define SQLITE_ENABLE_FTS3
#define SQLITE_DISABLE_LFS
#define SQLITE_THREADSAFE 0
Then you can compile!

If you need more detail about this part of the process, you can find more detailed description here and here.

And then I hit a problem. I was testing on different simulator versions and found out that for some reason SQLite functions returned strange errors ( SQLITE_CORRUPT with number code 11 ) with some versions of the simulator, while with others, everything worked perfectly fine. After hours of debugging, I've found that the problem is in wrong file size, returned by a function called unixFileSize. Here is how it looks in my sqlite version:
/*
** Determine the current size of a file in bytes
*/
static int unixFileSize(sqlite3_file *id, i64 *pSize){
  int rc;
  struct stat buf;
  assert( id );
  rc = osFstat(((unixFile*)id)->h, &buf);
  SimulateIOError( rc=1 );
  if( rc!=0 ){
    ((unixFile*)id)->lastErrno = errno;
    return SQLITE_IOERR_FSTAT;
  }
  *pSize = buf.st_size;

  /* When opening a zero-size database, the findInodeInfo() procedure
  ** writes a single byte into that file in order to work around a bug
  ** in the OS-X msdos filesystem.  In order to avoid problems with upper
  ** layers, we need to report this file size as zero even though it is
  ** really 1.   Ticket #3260.
  */
  if( *pSize==1 ) *pSize = 0;


  return SQLITE_OK;
}
Here after a successful call to osFstat, buf.st_size contained wrong file size. This is clearly not a bug in SQLite. There might be several reasons for this to happen. Probably struct stat is different in terms of packaging or field sizes from the one compiled with some of the simulators. I don't know and since I cannot fix it in iOS Simulator (the power of closed source in action), I don't really care. What I can fix, is not to use fstat() and struct stat in this function. Here is how I changed the function using other Unix ways and do the job:
/*
** Determine the current size of a file in bytes
*/
static int unixFileSize(sqlite3_file *id, i64 *pSize){
  off_t pos, size;
  pos = lseek(((unixFile*)id)->h, 0L, SEEK_CUR);
  if (-1 == pos){
    ((unixFile*)id)->lastErrno = errno;
    return SQLITE_IOERR_SEEK;
  }
  size = lseek(((unixFile*)id)->h, 0L, SEEK_END);
  if (-1 == size) {
    ((unixFile*)id)->lastErrno = errno;
    return SQLITE_IOERR_SEEK;
  }
  if (-1 == lseek(((unixFile*)id)->h, pos, SEEK_SET)) {
    ((unixFile*)id)->lastErrno = errno;
    return SQLITE_IOERR_SEEK;
  }
  *pSize = size;

  /* When opening a zero-size database, the findInodeInfo() procedure
  ** writes a single byte into that file in order to work around a bug
  ** in the OS-X msdos filesystem.  In order to avoid problems with upper
  ** layers, we need to report this file size as zero even though it is
  ** really 1.   Ticket #3260.
  */
  if( *pSize==1 ) *pSize = 0;


  return SQLITE_OK;
}
As you can see I'm using lseek to get the file size and thus avoid the struct stat and fstat() usage. This fixed the problem for me and I hope this could spare some time to others too. Note that this fix is not portable and will not work in non Unix environment.

Monday, August 29, 2011

How to have great wait cursor animations for free


While searching for a "trivial" wait animation for one of my AJAX projects I've found a great online solution for the problem. It has been around for years now, but it's new for me and I decided to share it.

Introducing http://ajaxload.info/ a free AJAX load animation generator. It's great to have it around.

Here are some images I've created briefly as a showcase ..... well I guess they already have your attention :)







Thursday, August 25, 2011

Linking to Android Market applications on the web

While working on web version of Da Dictionary I've decided to add link to Android version. Web links to Android Market looks like this http://market.android.com/details?id=com.demosten.android.dadict where 'com.demosten.android.dadict' is the package name which is unique for Android Market. This seams to work well when opened from PC browser. However opening this link from Android is a different story. The best way to open it is directly in Android Market application which works with different URI scheme. It looks like market://details?id=com.demosten.android.dadict where again we see the same package name mentioned. While built-in Android browser plays it smart and open the link in directly in Market Application alternative browsers like Firefox does not do so and viewing web version of Android Market on an Android phone is far form what users expected to see.

My solution
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
  updateAndroidMarketLinks();
  // some more core here ... 
 
  function updateAndroidMarketLinks()
  {
    var ua = navigator.userAgent.toLowerCase();
    if (0 <= ua.indexOf("android")) {
      // we have android
      $("a[href^='http://market.android.com/']").each(function() {
        this.href = this.href.replace(/^http:\/\/market\.android\.com\//,
          "market://");
      });
    }
  }
});
</script>
</head>

<body>
<a href="http://market.android.com/details?id=com.demosten.android.dadict" target="_blank">Download for Android</a>
</body>

</html>
As you can see my solution is based on JavaScript and jQuery. The idea is to search for 'android' sub-string inside browser's UserAgent and if that is the case - replace HTTP URI part with Android Market URI part, inside all links.

I believe a JavaScript only version is not hard to do, but I prefer to use jQuery.

Thursday, March 17, 2011

iPad 2 launch event impressions

I've finally found some time to watch Apple's iPad 2 launch event. I liked it. It looks like a great product and as usual, Steve and company presented it very smoothly. Someone should write a book "How to present like Apple" here!

One thing that puzzles me is why did they mentioned the competition so many times? If you are so convinced, you have the greatest product around, why should you bother even mentioning any competition? The history will probably repeat itself. The first phones that caught up with iPhone appeared 2 years later and the first which were (in my opinion) better, after 3. I believe the same will happen with tablets. Saying that, it looks to me like Apple are starting to feel the pressure now, but I don't think they'll be matched this year. Meanwhile I'm adding iPad 2 to my wish list.