title: Calculating TIFF image size in memory [C/C++]
body: <p>If I have a pointer to TIFF data, but no indication of the size, is there any way to accurately calculate it?</p>
  
  <p>I've gone through several different ideas, all of which work most of the time, but not always, since there's just so many different ways to format a TIFF, and I figured there has to be an easier way to do this.  Right now, the closest I've gotten is:</p>
  
  <pre><code>ULONG readImageHeader(char* image)
  {
  TIF_HDR       *xTIFHdr;
  TIF_IFD       *xTIFIFD;
  TIF_IFD_ENTRY *pxTIFIFDEntry;
  UCHAR         *pHdrPtr;
  USHORT         i;
  ULONG length  = 0;
  ULONG imgLength = 0;
  ULONG count = 0;
  
  // check to see if it is a TIFF header
  xTIFHdr = (TIF_HDR *)image;
  
  // Little Endian
  if (xTIFHdr-&gt;usTIFID == TIF_HEAD_LITTLE)
  {
      pHdrPtr = (UCHAR*)image;
      pHdrPtr += xTIFHdr-&gt;ulFirstIFDOffset;
  
      // read TIF IFD
      xTIFIFD = (TIF_IFD *)pHdrPtr;
  
      // Look at all the IFD entries and set internal image hdr
      pHdrPtr += TIF_IFD_LEN;
      pxTIFIFDEntry = (TIF_IFD_ENTRY *)pHdrPtr;
  
      // iterate through each IFD entry
      for (i=0; i&lt;xTIFIFD-&gt;usNumIFDEntries; i++)
      {
          if(length &lt;= (ULONG)pxTIFIFDEntry-&gt;ulTIFValueOffset)
          {
              length = (ULONG)pxTIFIFDEntry-&gt;ulTIFValueOffset;
  
              // the TIF length is in units of the TIF type
              switch(pxTIFIFDEntry-&gt;usTIFType)
              {
              case TIF_BYTE:
                  length += (ULONG)pxTIFIFDEntry-&gt;ulTIFLength * TIF_BYTE_SIZE;
                  break;
              case TIF_ASCII:
                  length += (ULONG)pxTIFIFDEntry-&gt;ulTIFLength * TIF_ASCII_SIZE;
                  break;
              case TIF_SHORT:
                  length += (ULONG)pxTIFIFDEntry-&gt;ulTIFLength * TIF_SHORT_SIZE;
                  break;
              case TIF_LONG:
                  length += (ULONG)pxTIFIFDEntry-&gt;ulTIFLength * TIF_LONG_SIZE;
                  break;
              case TIF_RATIONAL:
                  length += (ULONG)pxTIFIFDEntry-&gt;ulTIFLength * TIF_RATIONAL_SIZE;
                  break;
              default:
                  length += (ULONG)pxTIFIFDEntry-&gt;ulTIFLength;
                  break;
              }
          }
          switch (pxTIFIFDEntry-&gt;usTIFTag)
          {
          case TIF_STRIP_BYTE_COUNTS:
          case TIF_STRIP_OFFSETS:
          {
              ULONG valueOffset = (ULONG)pxTIFIFDEntry-&gt;ulTIFValueOffset;
              count = (ULONG)pxTIFIFDEntry-&gt;ulTIFLength;
  
              // if the count &gt; 1, then the valueOffset actually represents an offset
              if(count &gt; 1)
              {
                  ULONG countsize = (count - 1) * sizeof(ULONG);
                  imgLength += *(ULONG*) ((UCHAR*)image + valueOffset + countsize);
              }
              else
              {
                  // if count is 1, then the valueOffset is really just the value of that item
                  imgLength += valueOffset;
              }
              break;
          }
          default:
              break;
          }
      pxTIFIFDEntry++;
      }
  
      // the length is the largest offset, plus the length of that item
      // the imgLength is the offset of the image, plus the size of the image, which is stored as two separate tags
      // return the largest of them
      return(length &gt; imgLength ? length : imgLength);
  }
  // Big Endian
  else if(xTIFHdr-&gt;usTIFID == TIF_HEAD_BIG)
  {
      // I don't care about this
      printf("Big Endian TIFF image\n");
  }
  
  printf("Invalid TIFF image\n");
  return(0);
  }
  </code></pre>
  
  <p>Essentially what I'm doing here is I'm iterating through the TIFF header, and calculating two running sums: (largest offset + data length) and (strip offset + strip byte count).  Then I just use the larger of the two values.</p>
  
  <p>This mostly works, except that sometimes the ulTIFValueOffset is not an offset at all, but the actual value.  In (some of) those cases, I'm getting a file size that is too big.  So far, all my failed examples have been when it's grabbing the Width or Length tag, although I can't rule out the possibility that other tags could have the same problem.</p>
  
  <p>Is there either</p>
  
  <ol>
  <li>A way to calculate the file size given the headers? or </li>
  <li>A way to know if the headers are a value or an offset?</li>
  </ol>
  
  <p>Thanks!</p>