/**
 ******************************************************************************
 * Name: CIccTagStruct::LoadSubTag
 * 
 * Purpose: This will load from the indicated IO object and associate a tag
 *  object to a tag directory entry.  Nothing happens if tag directory entry
 *  is associated with a tag object.
 * 
 * Args: 
 *  pTagEntry - pointer to tag directory entry,
 *  pIO - pointer to IO object to read tag object data from
 * 
 * Return: 
 *  true - tag directory object associated with tag directory entry,
 *  false - failure
 *******************************************************************************
 */
bool CIccTagStruct::LoadElem(IccTagEntry *pTagEntry, CIccIO *pIO)
{
  if (!pTagEntry)
    return false;

  if (pTagEntry->pTag)
    return true;

  icUInt32Number headerSize = sizeof(icTagTypeSignature) + 
    sizeof(icUInt32Number) + 
    sizeof(icUInt32Number);

  if (pTagEntry->TagInfo.offset<headerSize ||
      !pTagEntry->TagInfo.size ||
      pTagEntry->TagInfo.offset+pTagEntry->TagInfo.size > m_tagSize) {
    return false;
  }

  icTagTypeSignature sigType;

  icUInt32Number offset = pTagEntry->TagInfo.offset + m_tagStart;

  //First we need to get the tag type to create the right kind of tag
  if (pIO->Seek(offset, icSeekSet)!=offset)
    return false;

  if (!pIO->Read32(&sigType))
    return false;

  CIccTag *pTag = CIccTag::Create(sigType);

  if (!pTag)
    return false;

  //Now seek back to where the tag starts so the created tag object can read
  //in its data.
  //First we need to get the tag type to create the right kind of tag
  if (pIO->Seek(offset, icSeekSet)!=offset) {
    delete pTag;
    return false;
  }

  if (!pTag->Read(pTagEntry->TagInfo.size, pIO)) {
    delete pTag;
    return false;
  }

  pTagEntry->pTag = pTag;

  IccTagPtr TagPtr;

  TagPtr.ptr = pTag;

  m_ElemVals->push_back(TagPtr);

  TagEntryList::iterator i;

  for (i=m_ElemEntries->begin(); i!= m_ElemEntries->end(); i++) {
    if (i->TagInfo.offset == pTagEntry->TagInfo.offset &&
        i->pTag != pTag)
      i->pTag = pTag; 
  }
  
  return true;
}
/**
******************************************************************************
* Name: CIccTagArray::Read
* 
* Purpose: 
* 
* Args: 
* 
* Return: 
******************************************************************************/
bool CIccTagArray::Read(icUInt32Number size, CIccIO *pIO)
{
  icTagTypeSignature sig;

  icUInt32Number headerSize = sizeof(icTagTypeSignature) + 
    sizeof(icUInt32Number) +
    sizeof(icTagTypeSignature) +
    sizeof(icStructSignature) +
    sizeof(icUInt32Number);

  if (headerSize > size)
    return false;

  if (!pIO) {
    return false;
  }

  Cleanup();

  icUInt32Number nTagStart = pIO->Tell();

  if (!pIO->Read32(&sig))
    return false;

  if (!pIO->Read32(&m_nReserved) ||
      !pIO->Read32(&m_sigArrayType))
    return false;

  icUInt32Number count, i, j;
  IccTagEntry TagEntry;

  TagEntry.pTag = NULL;

  if (!pIO->Read32(&count))
    return false;

  if (headerSize + count*sizeof(icPositionNumber) > size)
    return false;

  if (count) {
    icPositionNumber *tagPos = new icPositionNumber[count];

    if (!SetSize(count)) {
      delete[] tagPos;
      return false;
    }

    for (i=0; i<count; i++) {
      if (!pIO->Read32(&tagPos[i].offset) ||
          !pIO->Read32(&tagPos[i].size)) {
        delete [] tagPos;
        return false;
      }
    }

    for (i=0; i<count; i++) {
      if (!tagPos[i].offset || !tagPos[i].size) {
        m_TagVals[i].ptr = NULL;
        continue;
      }

      for (j=0; j<i; j++) {
        if (tagPos[i].offset == tagPos[j].offset)
          break;
      }

      if (j<i) {
        m_TagVals[i].ptr = m_TagVals[j].ptr;
      }
      else {
        if (tagPos[i].offset + tagPos[i].size > size) {
          delete [] tagPos;
          return false;
        }
        pIO->Seek(nTagStart + tagPos[i].offset, icSeekSet);

        icTagTypeSignature tagSig;
        pIO->Read32(&tagSig);
        pIO->Seek(nTagStart + tagPos[i].offset, icSeekSet);

        CIccTag *pTag = CIccTagCreator::CreateTag(tagSig);
        if (pTag) {
          if (!pTag->Read(tagPos[i].size, pIO)) {
            delete [] tagPos;
            return false;
          }
          m_TagVals[i].ptr = pTag;
        }
        else {
          delete [] tagPos;
          return false;
        }
      }
    }

    delete [] tagPos;
  }  

  return true;
}