[jpegio] clarify and comment the reading code and handle the case of an expanding...
authorJonathan Marshall <jmarshall@never.you.mind>
Wed, 9 Jan 2013 19:55:40 +0000 (08:55 +1300)
committerJonathan Marshall <jmarshall@never.you.mind>
Wed, 9 Jan 2013 19:55:40 +0000 (08:55 +1300)
xbmc/guilib/JpegIO.cpp

index 05ac821..f6f2c44 100644 (file)
@@ -259,17 +259,30 @@ bool CJpegIO::Open(const CStdString &texturePath, unsigned int minx, unsigned in
   XFILE::CFile file;
   if (file.Open(m_texturePath.c_str(), READ_TRUNCATED))
   {
+    /*
+     GetLength() will typically return values that fall into three cases:
+       1. The real filesize. This is the typical case.
+       2. Zero. This is the case for some http:// streams for example.
+       3. Some value smaller than the real filesize. This is the case for an expanding file.
+
+     In order to handle all three cases, we read the file in chunks, relying on Read()
+     returning 0 at EOF.  To minimize (re)allocation of the buffer, the chunksize in
+     cases 1 and 3 is set to one byte larger** than the value returned by GetLength().
+     The chunksize in case 2 is set to the larger of 64k and GetChunkSize().
+
+     We fill the buffer entirely before reallocation.  Thus, reallocation never occurs in case 1
+     as the buffer is larger than the file, so we hit EOF before we hit the end of buffer.
+
+     To minimize reallocation, we double the chunksize each time up to a maxchunksize of 2MB.
+     */
     unsigned int filesize = (unsigned int)file.GetLength();
-    unsigned int chunksize = filesize, maxchunksize = filesize;
-    if (!chunksize)
-    { // no size information, so try reading chunked
-      chunksize = std::max(65536U, (unsigned int)file.GetChunkSize());
-      maxchunksize = std::max(chunksize, 2048*1024U); // max 2MB
-    }
-    unsigned int total = 0, amount = 0;
+    unsigned int chunksize = filesize ? (filesize + 1) : std::max(65536U, (unsigned int)file.GetChunkSize());
+    unsigned int maxchunksize = 2048*1024U; /* max 2MB chunksize */
+
+    unsigned int total_read = 0, free_space = 0;
     while (true)
     {
-      if (!amount)
+      if (!free_space)
       { // (re)alloc
         m_inputBuffSize += chunksize;
         m_inputBuff = (unsigned char *)realloc(m_inputBuff, m_inputBuffSize);
@@ -278,16 +291,16 @@ bool CJpegIO::Open(const CStdString &texturePath, unsigned int minx, unsigned in
           CLog::Log(LOGERROR, "%s unable to allocate buffer of size %u", __FUNCTION__, m_inputBuffSize);
           return false;
         }
-        amount = chunksize;
+        free_space = chunksize;
         chunksize = std::min(chunksize*2, maxchunksize);
       }
-      unsigned int read = file.Read(m_inputBuff + total, amount);
-      amount -= read;
-      total  += read;
-      if (!read || total == filesize)
+      unsigned int read = file.Read(m_inputBuff + total_read, free_space);
+      free_space -= read;
+      total_read += read;
+      if (!read)
         break;
     }
-    m_inputBuffSize = total;
+    m_inputBuffSize = total_read;
     file.Close();
 
     if (m_inputBuffSize == 0)