CPDF_Object* CPDF_Object::CloneInternal(FX_BOOL bDirect, CFX_MapPtrToPtr* visited) const
{
    switch (m_Type) {
        case PDFOBJ_BOOLEAN:
            return new CPDF_Boolean(((CPDF_Boolean*)this)->m_bValue);
        case PDFOBJ_NUMBER:
            return new CPDF_Number(((CPDF_Number*)this)->m_bInteger, &((CPDF_Number*)this)->m_Integer);
        case PDFOBJ_STRING:
            return new CPDF_String(((CPDF_String*)this)->m_String, ((CPDF_String*)this)->IsHex());
        case PDFOBJ_NAME:
            return new CPDF_Name(((CPDF_Name*)this)->m_Name);
        case PDFOBJ_ARRAY: {
                CPDF_Array* pCopy = new CPDF_Array();
                CPDF_Array* pThis = (CPDF_Array*)this;
                int n = pThis->GetCount();
                for (int i = 0; i < n; i ++) {
                    CPDF_Object* value = (CPDF_Object*)pThis->m_Objects.GetAt(i);
                    pCopy->m_Objects.Add(value->CloneInternal(bDirect, visited));
                }
                return pCopy;
            }
        case PDFOBJ_DICTIONARY: {
                CPDF_Dictionary* pCopy = new CPDF_Dictionary();
                CPDF_Dictionary* pThis = (CPDF_Dictionary*)this;
                FX_POSITION pos = pThis->m_Map.GetStartPosition();
                while (pos) {
                    CFX_ByteString key;
                    CPDF_Object* value;
                    pThis->m_Map.GetNextAssoc(pos, key, (void*&)value);
                    pCopy->m_Map.SetAt(key, value->CloneInternal(bDirect, visited));
                }
                return pCopy;
            }
        case PDFOBJ_NULL: {
                return new CPDF_Null;
            }
        case PDFOBJ_STREAM: {
                CPDF_Stream* pThis = (CPDF_Stream*)this;
                CPDF_StreamAcc acc;
                acc.LoadAllData(pThis, TRUE);
                FX_DWORD streamSize = acc.GetSize();
                CPDF_Stream* pObj;
                if (pThis->GetDict())
                    pObj = new CPDF_Stream(acc.DetachData(), streamSize, (CPDF_Dictionary*)((CPDF_Object*)pThis->GetDict())->CloneInternal(bDirect, visited));
                else
                    pObj = new CPDF_Stream(acc.DetachData(), streamSize, NULL);
                return pObj;
            }
        case PDFOBJ_REFERENCE: {
                CPDF_Reference* pRef = (CPDF_Reference*)this;
                FX_DWORD obj_num = pRef->m_RefObjNum;
                if (bDirect && !visited->GetValueAt((void*)(FX_UINTPTR)obj_num)) {
                    visited->SetAt((void*)(FX_UINTPTR)obj_num, (void*)1);
                    CPDF_Object* ret;
                    if (pRef->GetDirect())
                        ret = pRef->GetDirect()->CloneInternal(TRUE, visited);
                    else
                        ret = NULL;
                    return ret;
                } else {
                    return new CPDF_Reference(pRef->m_pObjList, obj_num);
                }
            }
    }
    return NULL;
}
CPDF_Object* CPDF_Object::CloneInternal(FX_BOOL bDirect,
                                        std::set<FX_DWORD>* visited) const {
  switch (m_Type) {
    case PDFOBJ_BOOLEAN:
      return new CPDF_Boolean(AsBoolean()->m_bValue);
    case PDFOBJ_NUMBER: {
      const CPDF_Number* pThis = AsNumber();
      return new CPDF_Number(pThis->m_bInteger ? pThis->m_Integer
                                               : pThis->m_Float);
    }
    case PDFOBJ_STRING: {
      const CPDF_String* pString = AsString();
      return new CPDF_String(pString->m_String, pString->IsHex());
    }
    case PDFOBJ_NAME:
      return new CPDF_Name(AsName()->m_Name);
    case PDFOBJ_ARRAY: {
      CPDF_Array* pCopy = new CPDF_Array();
      const CPDF_Array* pThis = AsArray();
      int n = pThis->GetCount();
      for (int i = 0; i < n; i++) {
        CPDF_Object* value = pThis->m_Objects.GetAt(i);
        pCopy->m_Objects.Add(value->CloneInternal(bDirect, visited));
      }
      return pCopy;
    }
    case PDFOBJ_DICTIONARY: {
      CPDF_Dictionary* pCopy = new CPDF_Dictionary();
      const CPDF_Dictionary* pThis = AsDictionary();
      for (const auto& it : *pThis) {
        pCopy->m_Map.insert(std::make_pair(
            it.first, it.second->CloneInternal(bDirect, visited)));
      }
      return pCopy;
    }
    case PDFOBJ_NULL: {
      return new CPDF_Null;
    }
    case PDFOBJ_STREAM: {
      const CPDF_Stream* pThis = AsStream();
      CPDF_StreamAcc acc;
      acc.LoadAllData(pThis, TRUE);
      FX_DWORD streamSize = acc.GetSize();
      CPDF_Dictionary* pDict = pThis->GetDict();
      if (pDict) {
        pDict = ToDictionary(pDict->CloneInternal(bDirect, visited));
      }
      return new CPDF_Stream(acc.DetachData(), streamSize, pDict);
    }
    case PDFOBJ_REFERENCE: {
      const CPDF_Reference* pRef = AsReference();
      FX_DWORD obj_num = pRef->GetRefObjNum();
      if (bDirect && !pdfium::ContainsKey(*visited, obj_num)) {
        visited->insert(obj_num);
        auto* pDirect = pRef->GetDirect();
        return pDirect ? pDirect->CloneInternal(TRUE, visited) : nullptr;
      }
      return new CPDF_Reference(pRef->m_pObjList, obj_num);
    }
  }
  return NULL;
}