EStatusCode IndirectObjectsReferenceRegistry::ReadState(PDFParser* inStateReader,ObjectIDType inObjectID)
{
	PDFObjectCastPtr<PDFDictionary> indirectObjectsDictionary(inStateReader->ParseNewObject(inObjectID));

	PDFObjectCastPtr<PDFArray> objectsWritesRegistry(indirectObjectsDictionary->QueryDirectObject("mObjectsWritesRegistry"));

	SingleValueContainerIterator<PDFObjectVector> it = objectsWritesRegistry->GetIterator();

	mObjectsWritesRegistry.clear();
	while(it.MoveNext())
	{
		ObjectWriteInformation newObjectInformation;
		PDFObjectCastPtr<PDFDictionary> objectWriteInformationDictionary(inStateReader->ParseNewObject(
																				((PDFIndirectObjectReference*)it.GetItem())->mObjectID));
		
		PDFObjectCastPtr<PDFBoolean> objectWritten(objectWriteInformationDictionary->QueryDirectObject("mObjectWritten"));

		newObjectInformation.mObjectWritten = objectWritten->GetValue();

		if(newObjectInformation.mObjectWritten)
		{
			PDFObjectCastPtr<PDFInteger> writePosition(objectWriteInformationDictionary->QueryDirectObject("mWritePosition"));
			newObjectInformation.mWritePosition = writePosition->GetValue();
		}

		PDFObjectCastPtr<PDFInteger> objectReferenceType(objectWriteInformationDictionary->QueryDirectObject("mObjectReferenceType"));
		newObjectInformation.mObjectReferenceType = (ObjectWriteInformation::EObjectReferenceType)objectReferenceType->GetValue();

		mObjectsWritesRegistry.push_back(newObjectInformation);
	}

	return PDFHummus::eSuccess;
}
EStatusCode WrittenFontCFF::ReadState(PDFParser* inStateReader,ObjectIDType inObjectID)
{
	PDFObjectCastPtr<PDFDictionary> writtenFontState(inStateReader->ParseNewObject(inObjectID));


	PDFObjectCastPtr<PDFInteger> availablePositionsCount(writtenFontState->QueryDirectObject("mAvailablePositionsCount"));

	mAvailablePositionsCount = (unsigned char)availablePositionsCount->GetValue();

	mFreeList.clear();
	PDFObjectCastPtr<PDFArray> freeListState(writtenFontState->QueryDirectObject("mFreeList"));

	SingleValueContainerIterator<PDFObjectVector> it =  freeListState->GetIterator();
	PDFObjectCastPtr<PDFInteger> item;
	UCharAndUChar aPair;
	while(it.MoveNext())
	{
		item = it.GetItem();
		aPair.first = (unsigned char)item->GetValue();
		it.MoveNext();
		item = it.GetItem();
		aPair.second = (unsigned char)item->GetValue();
		mFreeList.push_back(aPair);
	}

	PDFObjectCastPtr<PDFArray> assignedPositionsState(writtenFontState->QueryDirectObject("mAssignedPositions"));
	it =  assignedPositionsState->GetIterator();
	int i=0;
	
	PDFObjectCastPtr<PDFInteger> assignedPositionItem;
	while(it.MoveNext())
	{
		assignedPositionItem = it.GetItem();
		mAssignedPositions[i] = (unsigned int)assignedPositionItem->GetValue();
		++i;
	}

	PDFObjectCastPtr<PDFArray> assignedPositionsAvailableState(writtenFontState->QueryDirectObject("mAssignedPositionsAvailable"));
	it =  assignedPositionsAvailableState->GetIterator();
	i=0;
	
	PDFObjectCastPtr<PDFBoolean> assignedPositionAvailableItem;
	while(it.MoveNext())
	{
		assignedPositionAvailableItem = it.GetItem();
		mAssignedPositionsAvailable[i] = assignedPositionAvailableItem->GetValue();
		++i;
	}


	PDFObjectCastPtr<PDFBoolean> isCIDState(writtenFontState->QueryDirectObject("mIsCID"));

	mIsCID = isCIDState->GetValue();

	return AbstractWrittenFont::ReadStateFromObject(inStateReader,writtenFontState.GetPtr());
}
void showPageContent(PDFParser& parser, RefCountPtr<PDFObject> contents, InputFile& pdfFile) 
{
    if(contents->GetType() == ePDFObjectArray) 
	{
        PDFObjectCastPtr<PDFIndirectObjectReference> streamReferences;
		SingleValueContainerIterator<PDFObjectVector> itContents = ((PDFArray*)contents.GetPtr())->GetIterator();
		// array of streams
		while(itContents.MoveNext())
		{
            streamReferences = itContents.GetItem();
            PDFObjectCastPtr<PDFStreamInput> stream = parser.ParseNewObject(streamReferences->mObjectID);
            showContentStream(stream.GetPtr(),pdfFile.GetInputStream(),parser);
        }
    } 
	else 
	{
        // stream
        showContentStream((PDFStreamInput*)contents.GetPtr(),pdfFile.GetInputStream(),parser);
    }
}
EStatusCode UsedFontsRepository::ReadState(PDFParser* inStateReader,ObjectIDType inObjectID)
{
	EStatusCode status = PDFHummus::eSuccess;

	// clear current state
	StringAndLongToPDFUsedFontMap::iterator itUsedFonts = mUsedFonts.begin();
	for(; itUsedFonts != mUsedFonts.end();++itUsedFonts)
		delete (itUsedFonts->second);
	mUsedFonts.clear(); 


	PDFObjectCastPtr<PDFDictionary> usedFontsRepositoryState(inStateReader->ParseNewObject(inObjectID));

	mOptionaMetricsFiles.clear();
	PDFObjectCastPtr<PDFArray> optionalMetricsState(usedFontsRepositoryState->QueryDirectObject("mOptionaMetricsFiles"));
	SingleValueContainerIterator<PDFObjectVector> it = optionalMetricsState->GetIterator();
	PDFObjectCastPtr<PDFLiteralString> aStringValue;

	while(it.MoveNext())
	{
		PDFTextString aKey;

		aStringValue = it.GetItem();
		aKey = aStringValue->GetValue();

		PDFTextString aValue;

		it.MoveNext();
		aStringValue = it.GetItem();
		aValue = aStringValue->GetValue();

		mOptionaMetricsFiles.insert(StringToStringMap::value_type(aKey.ToUTF8String(),aValue.ToUTF8String()));
	}

	PDFObjectCastPtr<PDFArray> usedFontsState(usedFontsRepositoryState->QueryDirectObject("mUsedFonts"));

	it = usedFontsState->GetIterator();
	PDFObjectCastPtr<PDFLiteralString> keyStringItem;
    PDFObjectCastPtr<PDFInteger> keyIndexItem;
	PDFObjectCastPtr<PDFIndirectObjectReference> valueItem;

	if(!mInputFontsInformation)
		mInputFontsInformation = new FreeTypeWrapper();

	while(it.MoveNext() && PDFHummus::eSuccess == status)
	{
		keyStringItem = it.GetItem();
		it.MoveNext();
        keyIndexItem = it.GetItem();
        it.MoveNext();
		valueItem = it.GetItem();

		PDFTextString aTextString(keyStringItem->GetValue());
		std::string filePath = aTextString.ToUTF8String();
        long fontIndex = (long)keyIndexItem->GetValue();

		FT_Face face;
		face = mInputFontsInformation->NewFace(filePath,fontIndex);
		
		if(!face)
		{
			TRACE_LOG2("UsedFontsRepository::ReadState, Failed to load font from %s at index %ld",filePath.c_str(),fontIndex);
			status = PDFHummus::eFailure;
			break;
		}


		PDFUsedFont* usedFont;
		
		StringToStringMap::iterator itOptionlMetricsFile = mOptionaMetricsFiles.find(filePath);
		if(itOptionlMetricsFile != mOptionaMetricsFiles.end())
			usedFont = new PDFUsedFont(face,filePath,itOptionlMetricsFile->second,fontIndex,mObjectsContext);
		else
			usedFont = new PDFUsedFont(face,filePath,"",fontIndex,mObjectsContext);
		if(!usedFont->IsValid())
		{
			TRACE_LOG2("UsedFontsRepository::ReadState, Unreckognized font format for font in %s at index %ld",filePath.c_str(),fontIndex);
			delete usedFont;
			usedFont = NULL;
			status = PDFHummus::eFailure;
			break;
		}

		usedFont->ReadState(inStateReader,valueItem->mObjectID);
		mUsedFonts.insert(StringAndLongToPDFUsedFontMap::value_type(StringAndLong(filePath,fontIndex),usedFont));

	}
	return status;
	
}
PDFHummus::EStatusCode PDFModifiedPage::WritePage()
{
	EStatusCode status = EndContentContext(); // just in case someone forgot to close the latest content context

	do {
		if (status != eSuccess || !mIsDirty) {
			break;
		}

		// allocate an object ID for the new contents stream (for placing the form)
		// we first create the modified page object, so that we can define a name for the new form xobject
		// that is unique
		ObjectsContext& objectContext = mWriter->GetObjectsContext();
		ObjectIDType newContentObjectID = objectContext.GetInDirectObjectsRegistry().AllocateNewObjectID();
		ObjectIDType newEncapsulatingObjectID = 0;


		// create a copying context, so we can copy the page dictionary, and modify its contents + resources dict
		PDFDocumentCopyingContext* copyingContext = mWriter->CreatePDFCopyingContextForModifiedFile();

		// get the page object
		ObjectIDType pageObjectID = copyingContext->GetSourceDocumentParser()->GetPageObjectID(mPageIndex);
		PDFObjectCastPtr<PDFDictionary> pageDictionaryObject = copyingContext->GetSourceDocumentParser()->ParsePage(mPageIndex);
		MapIterator<PDFNameToPDFObjectMap>  pageDictionaryObjectIt = pageDictionaryObject->GetIterator();

		// create modified page object
		objectContext.StartModifiedIndirectObject(pageObjectID);
		DictionaryContext* modifiedPageObject = mWriter->GetObjectsContext().StartDictionary();

		// copy all elements of the page to the new page object, but the "Contents", "Resources" and "Annots" elements
		while (pageDictionaryObjectIt.MoveNext())
		{
			if (pageDictionaryObjectIt.GetKey()->GetValue() != "Resources" &&
				pageDictionaryObjectIt.GetKey()->GetValue() != "Contents" &&
				pageDictionaryObjectIt.GetKey()->GetValue() != "Annots")
			{
				modifiedPageObject->WriteKey(pageDictionaryObjectIt.GetKey()->GetValue());
				copyingContext->CopyDirectObjectAsIs(pageDictionaryObjectIt.GetValue());
			}
		}

		// Write new annotations entry, joining existing annotations, and new ones (from links attaching or what not)
		if (pageDictionaryObject->Exists("Annots") || mWriter->GetDocumentContext().GetAnnotations().size() > 0)
		{
			modifiedPageObject->WriteKey("Annots");
			objectContext.StartArray();

			// write old annots, if any exist
			if(pageDictionaryObject->Exists("Annots")) {
				PDFObjectCastPtr<PDFArray> anArray(copyingContext->GetSourceDocumentParser()->QueryDictionaryObject(pageDictionaryObject.GetPtr(), "Annots"));
				SingleValueContainerIterator<PDFObjectVector> refs = anArray->GetIterator();
				while (refs.MoveNext())
					copyingContext->CopyDirectObjectAsIs(refs.GetItem());

			}

			// write new annots from links
			ObjectIDTypeSet& annotations = mWriter->GetDocumentContext().GetAnnotations();
			if (annotations.size() > 0)
			{
				ObjectIDTypeSet::iterator it = annotations.begin();
				for (; it != annotations.end(); ++it)
					objectContext.WriteNewIndirectObjectReference(*it);
			}
			annotations.clear();
			objectContext.EndArray(eTokenSeparatorEndLine);

		}

		// Write new contents entry, joining the existing contents with the new one. take care of various scenarios of the existing Contents
		modifiedPageObject->WriteKey("Contents");
		if (!pageDictionaryObject->Exists("Contents"))
		{	// no contents
			objectContext.WriteIndirectObjectReference(newContentObjectID);
		}
		else
		{
			objectContext.StartArray();
			if (mEnsureContentEncapsulation)
			{
				newEncapsulatingObjectID = objectContext.GetInDirectObjectsRegistry().AllocateNewObjectID();
				objectContext.WriteNewIndirectObjectReference(newEncapsulatingObjectID);
			}

			RefCountPtr<PDFObject> pageContent(copyingContext->GetSourceDocumentParser()->QueryDictionaryObject(pageDictionaryObject.GetPtr(), "Contents"));
			if (pageContent->GetType() == PDFObject::ePDFObjectStream)
			{
				// single content stream. must be a refrence which points to it
				PDFObjectCastPtr<PDFIndirectObjectReference> ref(pageDictionaryObject->QueryDirectObject("Contents"));
				objectContext.WriteIndirectObjectReference(ref->mObjectID, ref->mVersion);
			}
			else if (pageContent->GetType() == PDFObject::ePDFObjectArray)
			{
				PDFArray* anArray = (PDFArray*)pageContent.GetPtr();

				// multiple content streams
				SingleValueContainerIterator<PDFObjectVector> refs = anArray->GetIterator();
				PDFObjectCastPtr<PDFIndirectObjectReference> ref;
				while (refs.MoveNext())
				{
					ref = refs.GetItem();
					objectContext.WriteIndirectObjectReference(ref->mObjectID, ref->mVersion);
				}

			}
			else {
				// this basically means no content...or whatever. just ignore.
			}

			objectContext.WriteNewIndirectObjectReference(newContentObjectID);
			objectContext.EndArray();
			objectContext.EndLine();
		}

		// Write a new resource entry. copy all but the "XObject" entry, which needs to be modified. Just for kicks i'm keeping the original 
		// form (either direct dictionary, or indirect object)
		ObjectIDType resourcesIndirect = 0;
		ObjectIDType newResourcesIndirect = 0;
		vector<string> formResourcesNames;

		modifiedPageObject->WriteKey("Resources");
		if (!pageDictionaryObject->Exists("Resources"))
		{
			// check if there's inherited dict. if so - write directly as a modified version
			PDFObjectCastPtr<PDFDictionary> parentDict(
				pageDictionaryObject->Exists("Parent") ? 
					copyingContext->GetSourceDocumentParser()->QueryDictionaryObject(pageDictionaryObject.GetPtr(), "Parent"): 
					NULL);
			if(!parentDict) {
				formResourcesNames = WriteNewResourcesDictionary(objectContext);
			}
			else {
				PDFObjectCastPtr<PDFDictionary> inheritedResources = findInheritedResources(copyingContext->GetSourceDocumentParser(),parentDict.GetPtr());
				if(!inheritedResources) {
					formResourcesNames = WriteNewResourcesDictionary(objectContext);
				} else {
					formResourcesNames = WriteModifiedResourcesDict(copyingContext->GetSourceDocumentParser(), inheritedResources.GetPtr(), objectContext, copyingContext);
				}
			}
		}
		else
		{
			// resources may be direct, or indirect. if direct, write as is, adding the new form xobject, otherwise wait till page object ends and write then
			PDFObjectCastPtr<PDFIndirectObjectReference> resourceDictRef(pageDictionaryObject->QueryDirectObject("Resources"));
			if (!resourceDictRef)
			{
				PDFObjectCastPtr<PDFDictionary> resourceDict(pageDictionaryObject->QueryDirectObject("Resources"));
				formResourcesNames = WriteModifiedResourcesDict(copyingContext->GetSourceDocumentParser(), resourceDict.GetPtr(), objectContext, copyingContext);
			}
			else
			{
				resourcesIndirect = resourceDictRef->mObjectID;
				// later will write a modified version of the resources dictionary, with the new form.
				// only modify the resources dict object if wasn't already modified (can happen when sharing resources dict between multiple pages).
				// in the case where it was alrady modified, create a new resources dictionary that's a copy, and use it instead, to avoid overwriting
				// the previous modification
				GetObjectWriteInformationResult res = objectContext.GetInDirectObjectsRegistry().GetObjectWriteInformation(resourcesIndirect);
				if (res.first && res.second.mIsDirty)
				{
					newResourcesIndirect = objectContext.GetInDirectObjectsRegistry().AllocateNewObjectID();
					modifiedPageObject->WriteObjectReferenceValue(newResourcesIndirect);
				}
				else
					modifiedPageObject->WriteObjectReferenceValue(resourcesIndirect);
			}
		}

		objectContext.EndDictionary(modifiedPageObject);
		objectContext.EndIndirectObject();

		if (resourcesIndirect != 0)
		{
			if (newResourcesIndirect != 0)
				objectContext.StartNewIndirectObject(newResourcesIndirect);
			else
				objectContext.StartModifiedIndirectObject(resourcesIndirect);
			PDFObjectCastPtr<PDFDictionary> resourceDict(copyingContext->GetSourceDocumentParser()->ParseNewObject(resourcesIndirect));
			formResourcesNames = WriteModifiedResourcesDict(copyingContext->GetSourceDocumentParser(), resourceDict.GetPtr(), objectContext, copyingContext);
			objectContext.EndIndirectObject();
		}

		// if required write encapsulation code, so that new stream is independent of graphic context of original
		PDFStream* newStream;
		PrimitiveObjectsWriter primitivesWriter;
		if (newEncapsulatingObjectID != 0)
		{
			objectContext.StartNewIndirectObject(newEncapsulatingObjectID);
			newStream = objectContext.StartPDFStream();
			primitivesWriter.SetStreamForWriting(newStream->GetWriteStream());
			primitivesWriter.WriteKeyword("q");
			objectContext.EndPDFStream(newStream);

		}

		// last but not least, create the actual content stream object, placing the form
		objectContext.StartNewIndirectObject(newContentObjectID);
		newStream = objectContext.StartPDFStream();
		primitivesWriter.SetStreamForWriting(newStream->GetWriteStream());

		if (newEncapsulatingObjectID != 0) {
			primitivesWriter.WriteKeyword("Q");
		}

		vector<string>::iterator it = formResourcesNames.begin();
		for (; it != formResourcesNames.end(); ++it)
		{
			primitivesWriter.WriteKeyword("q");
			primitivesWriter.WriteInteger(1);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteInteger(1);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteInteger(0);
			primitivesWriter.WriteKeyword("cm");
			primitivesWriter.WriteName(*it);
			primitivesWriter.WriteKeyword("Do");
			primitivesWriter.WriteKeyword("Q");
		}

		objectContext.EndPDFStream(newStream);
	} while (false);

	return status;
}