void PropertyMapReader::Read (InputStream& stream)
{
  try
  {
    const PropertyMapHeader& header = stream.Read<PropertyMapHeader> ();

      //синхронизация лэйаута

    Impl::LayoutDescPtr layout_desc;

    object_id_t layout_id = 0;

    if (header.has_layout)
    {      
      layout_desc = impl->ReadLayout (stream);
      layout_id   = layout_desc->source_id;
    }
    else if (header.has_layout_id)
    {
      layout_id = read (stream, xtl::type<object_id_t> ());
    }

      //синхронизация карты свойств

    Impl::MapDescMap::iterator map_iter = impl->property_maps.find (header.id);

    Impl::MapDescPtr map_desc;

    if (map_iter != impl->property_maps.end ())
    {
      map_desc = map_iter->second;

      if (!(header.has_layout_id || header.has_layout) || (!layout_desc && map_desc->layout->source_id == layout_id && map_desc->layout_hash == map_desc->layout->layout.Hash ()))
      {
        layout_desc = map_desc->layout;
      }
      else
      {
        Impl::LayoutMap::iterator iter = impl->layouts.find (layout_id);

        if (iter == impl->layouts.end ())
          throw xtl::format_operation_exception ("", "Internal error: can't find layout %llu to update property map %llu", layout_id, header.id);

        layout_desc = iter->second;

          //обновление лэйаута существующей карты

        const common::PropertyLayout& layout = layout_desc->layout;

        map_desc->properties.Reset (layout);

        map_desc->layout      = layout_desc;
        map_desc->layout_hash = layout.Hash ();          
      }
    }
    else
    {
        //поиск лэйаута

      Impl::LayoutMap::iterator iter = impl->layouts.find (layout_id);

      if (iter == impl->layouts.end ())
        throw xtl::format_operation_exception ("", "Internal error: no layout %llu for new property map %llu", layout_id, header.id);

      layout_desc = iter->second;

        //новая карта свойств

      map_desc = Impl::MapDescPtr (new Impl::MapDesc (layout_desc), false);
    }

      //синхронизация карты свойств

    common::PropertyMap& properties = map_desc->properties;

    try
    {
        //синхронизация буфера карты свойств

      size_t      src_buffer_size = stream.Read<uint32> ();
      const void* src_buffer      = stream.ReadData (src_buffer_size);

      if (src_buffer_size != properties.BufferSize ())
        throw xtl::format_operation_exception ("", "Internal error: can't sync property map %llu. Incoming buffer data size is %u but actual is %u", header.id, src_buffer_size, properties.BufferSize ());

      properties.SetBufferData (src_buffer);

        //синхронизация строк

      for (IndexArray::iterator iter=layout_desc->string_indices.begin (), end=layout_desc->string_indices.end (); iter!=end; ++iter)
      {
        const char* string = read (stream, xtl::type<const char*> ());

        properties.SetProperty (*iter, string);
      }
    }
    catch (...)
    {
        //reset strings, because SetBufferData is atomic operation

      const common::PropertyDesc* property = properties.Layout ().Properties ();
      
      for (size_t i=0, count=properties.Layout ().Size (); i<count; i++, property++)
      {
        if (property->type == common::PropertyType_String)
          properties.SetProperty (i, "");
      }

      throw;
    }

      //обновление структур данных

    if (map_iter == impl->property_maps.end ())
      impl->property_maps.insert_pair (header.id, map_desc);
  }
  catch (xtl::exception& e)
  {
    e.touch ("render::scene::interchange::PropertyMapReader::Read");
    throw;
  }
}