2013-09-18 08:05:24 +00:00
# include <errno.h>
# include <gio/gio.h>
# include <libxml/parser.h>
# include <libxml/xpath.h>
2013-09-17 22:29:13 +00:00
# include <libxml/tree.h>
2013-09-20 07:58:31 +00:00
# include <libxml/xinclude.h>
2013-09-19 17:56:25 +00:00
# include <libxslt/xsltInternals.h>
# include <libxslt/transform.h>
2013-09-17 08:00:12 +00:00
# include <swe-glib.h>
2013-09-19 21:14:37 +00:00
# include <locale.h>
2013-09-17 08:00:12 +00:00
2013-09-13 23:25:46 +00:00
# include "ag-chart.h"
struct _AgChartPrivate {
2013-09-17 20:18:24 +00:00
gchar * name ;
gchar * country ;
gchar * city ;
2013-09-13 23:25:46 +00:00
gchar * save_buffer ;
} ;
2013-09-17 20:18:24 +00:00
enum {
PROP_0 ,
PROP_NAME ,
PROP_COUNTRY ,
PROP_CITY
} ;
2013-09-18 08:05:24 +00:00
typedef enum {
XML_CONVERT_STRING ,
XML_CONVERT_DOUBLE ,
XML_CONVERT_INT
} XmlConvertType ;
2013-09-18 08:02:23 +00:00
G_DEFINE_QUARK ( ag - chart - error - quark , ag_chart_error ) ;
2013-09-13 23:25:46 +00:00
G_DEFINE_TYPE ( AgChart , ag_chart , GSWE_TYPE_MOMENT ) ;
# define GET_PRIVATE(instance) (G_TYPE_INSTANCE_GET_PRIVATE((instance), AG_TYPE_CHART, AgChartPrivate))
2013-09-21 13:47:48 +00:00
# define ag_g_variant_unref(v) if ((v) != NULL) { \
g_variant_unref ( ( v ) ) ; \
}
2013-09-13 23:25:46 +00:00
2013-09-17 20:18:24 +00:00
static void ag_chart_set_property ( GObject * gobject , guint prop_id , const GValue * value , GParamSpec * param_spec ) ;
static void ag_chart_get_property ( GObject * gobject , guint prop_id , GValue * value , GParamSpec * param_spec ) ;
static void ag_chart_finalize ( GObject * gobject ) ;
2013-09-13 23:25:46 +00:00
static void
ag_chart_class_init ( AgChartClass * klass )
{
2013-09-17 20:18:24 +00:00
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
2013-09-13 23:25:46 +00:00
g_type_class_add_private ( klass , sizeof ( AgChartPrivate ) ) ;
2013-09-17 20:18:24 +00:00
gobject_class - > set_property = ag_chart_set_property ;
gobject_class - > get_property = ag_chart_get_property ;
gobject_class - > finalize = ag_chart_finalize ;
g_object_class_install_property ( gobject_class , PROP_NAME , g_param_spec_string ( " name " , " Chart name " , " Name of the person on this chart " , NULL , G_PARAM_READWRITE ) ) ;
g_object_class_install_property ( gobject_class , PROP_COUNTRY , g_param_spec_string ( " country " , " Country name " , " Name of the country of birth " , NULL , G_PARAM_READWRITE ) ) ;
g_object_class_install_property ( gobject_class , PROP_CITY , g_param_spec_string ( " city " , " City name " , " Name of the city of birth " , NULL , G_PARAM_READWRITE ) ) ;
2013-09-13 23:25:46 +00:00
}
static void
ag_chart_init ( AgChart * chart )
{
chart - > priv = GET_PRIVATE ( chart ) ;
2013-09-17 20:18:24 +00:00
chart - > priv - > name = NULL ;
chart - > priv - > country = NULL ;
chart - > priv - > city = NULL ;
chart - > priv - > save_buffer = NULL ;
}
static void
ag_chart_set_property ( GObject * gobject , guint prop_id , const GValue * value , GParamSpec * param_spec )
{
switch ( prop_id ) {
case PROP_NAME :
ag_chart_set_name ( AG_CHART ( gobject ) , g_value_get_string ( value ) ) ;
break ;
case PROP_COUNTRY :
ag_chart_set_country ( AG_CHART ( gobject ) , g_value_get_string ( value ) ) ;
break ;
case PROP_CITY :
ag_chart_set_city ( AG_CHART ( gobject ) , g_value_get_string ( value ) ) ;
break ;
}
}
static void
ag_chart_get_property ( GObject * gobject , guint prop_id , GValue * value , GParamSpec * param_spec )
{
switch ( prop_id ) {
case PROP_NAME :
g_value_set_string ( value , AG_CHART ( gobject ) - > priv - > name ) ;
break ;
case PROP_COUNTRY :
g_value_set_string ( value , AG_CHART ( gobject ) - > priv - > country ) ;
break ;
case PROP_CITY :
g_value_set_string ( value , AG_CHART ( gobject ) - > priv - > city ) ;
break ;
}
}
static void
ag_chart_finalize ( GObject * gobject )
{
AgChart * chart = AG_CHART ( gobject ) ;
if ( chart - > priv - > name ! = NULL ) {
g_free ( chart - > priv - > name ) ;
}
if ( chart - > priv - > country ! = NULL ) {
g_free ( chart - > priv - > country ) ;
}
if ( chart - > priv - > city ! = NULL ) {
g_free ( chart - > priv - > city ) ;
}
if ( chart - > priv - > save_buffer ! = NULL ) {
g_free ( chart - > priv - > save_buffer ) ;
}
2013-09-13 23:25:46 +00:00
}
AgChart *
2013-09-14 15:37:33 +00:00
ag_chart_new_full ( GsweTimestamp * timestamp , gdouble longitude , gdouble latitude , gdouble altitude , GsweHouseSystem house_system )
2013-09-13 23:25:46 +00:00
{
2013-09-17 07:31:37 +00:00
AgChart * chart ;
2013-09-14 15:37:33 +00:00
GsweCoordinates * coords = g_new0 ( GsweCoordinates , 1 ) ;
coords - > longitude = longitude ;
coords - > latitude = latitude ;
coords - > altitude = altitude ;
2013-09-17 07:31:37 +00:00
chart = AG_CHART ( g_object_new ( AG_TYPE_CHART ,
2013-09-14 15:37:33 +00:00
" timestamp " , timestamp ,
" coordinates " , coords ,
" house-system " , house_system ,
NULL ) ) ;
g_free ( coords ) ;
2013-09-17 08:00:12 +00:00
gswe_moment_add_all_planets ( GSWE_MOMENT ( chart ) ) ;
2013-09-17 07:31:37 +00:00
return chart ;
2013-09-13 23:25:46 +00:00
}
2013-09-17 20:18:24 +00:00
void
ag_chart_set_name ( AgChart * chart , const gchar * name )
{
if ( chart - > priv - > name ! = NULL ) {
g_free ( chart - > priv - > name ) ;
}
chart - > priv - > name = g_strdup ( name ) ;
}
gchar *
ag_chart_get_name ( AgChart * chart )
{
return g_strdup ( chart - > priv - > name ) ;
}
void
ag_chart_set_country ( AgChart * chart , const gchar * country )
{
if ( chart - > priv - > country ! = NULL ) {
g_free ( chart - > priv - > country ) ;
}
chart - > priv - > country = g_strdup ( country ) ;
}
gchar *
ag_chart_get_country ( AgChart * chart )
{
return g_strdup ( chart - > priv - > country ) ;
}
void
ag_chart_set_city ( AgChart * chart , const gchar * city )
{
if ( chart - > priv - > city ! = NULL ) {
g_free ( chart - > priv - > city ) ;
}
chart - > priv - > city = g_strdup ( city ) ;
}
gchar *
ag_chart_get_city ( AgChart * chart )
{
return g_strdup ( chart - > priv - > city ) ;
}
2013-09-21 13:49:13 +00:00
/**
* get_by_xpath :
* @ xpath_context : an XPath context
* @ uri : the name of the file currently being processed . Used in error messages only
* @ xpath : an XPath expression
* @ value_required : marks the value as required . Although the XML tags must be present , some values ( like country or city name ) may be omitted
* @ type : the type of the variable to return
* @ err : a GError
*
* Get the value of an XML tag via XPath .
*
* Returns : ( transfer container ) : a GVariant with the requested value
*/
2013-09-18 08:05:24 +00:00
static GVariant *
2013-09-21 13:49:13 +00:00
get_by_xpath ( xmlXPathContextPtr xpath_context , const gchar * uri , const gchar * xpath , gboolean value_required , XmlConvertType type , GError * * err )
2013-09-18 08:05:24 +00:00
{
xmlXPathObjectPtr xpathObj ;
const gchar * text ;
char * endptr ;
GVariant * ret = NULL ;
gdouble d ;
gint i ;
if ( ( xpathObj = xmlXPathEvalExpression ( ( const xmlChar * ) xpath , xpath_context ) ) = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_LIBXML , " File '%s' could not be parsed due to internal XML error. " , uri ) ;
return NULL ;
}
if ( xpathObj - > nodesetval = = NULL ) {
2013-09-18 09:20:02 +00:00
g_debug ( " No such node '%s' " , xpath ) ;
2013-09-18 08:05:24 +00:00
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
xmlXPathFreeObject ( xpathObj ) ;
return NULL ;
}
if ( xpathObj - > nodesetval - > nodeNr > 1 ) {
2013-09-18 09:20:02 +00:00
g_debug ( " Too many '%s' nodes " , xpath ) ;
2013-09-18 08:05:24 +00:00
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
xmlXPathFreeObject ( xpathObj ) ;
return NULL ;
}
2013-09-21 13:49:13 +00:00
if ( xpathObj - > nodesetval - > nodeNr = = 0 ) {
if ( value_required ) {
g_debug ( " Too many '%s' nodes " , xpath ) ;
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
xmlXPathFreeObject ( xpathObj ) ;
return NULL ;
} else {
GVariant * ret = NULL ;
switch ( type ) {
case XML_CONVERT_STRING :
ret = g_variant_new ( " ms " , NULL ) ;
break ;
case XML_CONVERT_DOUBLE :
ret = g_variant_new ( " md " , FALSE , 0 ) ;
break ;
case XML_CONVERT_INT :
ret = g_variant_new ( " mi " , FALSE , 0 ) ;
break ;
}
return ret ;
}
}
2013-09-18 08:05:24 +00:00
text = ( const gchar * ) xpathObj - > nodesetval - > nodeTab [ 0 ] - > content ;
switch ( type ) {
case XML_CONVERT_STRING :
ret = g_variant_new_string ( text ) ;
break ;
case XML_CONVERT_DOUBLE :
d = g_ascii_strtod ( text , & endptr ) ;
if ( ( * endptr ! = 0 ) | | ( errno ! = 0 ) ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
ret = NULL ;
} else {
ret = g_variant_new_double ( d ) ;
}
break ;
case XML_CONVERT_INT :
i = strtol ( text , & endptr , 10 ) ;
if ( ( * endptr ! = 0 ) | | ( errno ! = 0 ) ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
ret = NULL ;
} else {
ret = g_variant_new_int32 ( i ) ;
}
break ;
}
xmlXPathFreeObject ( xpathObj ) ;
return ret ;
}
AgChart *
ag_chart_load_from_file ( GFile * file , GError * * err )
{
AgChart * chart = NULL ;
gchar * uri ,
2013-09-21 13:50:16 +00:00
* xml = NULL ,
* country_name ,
* city_name ;
2013-09-18 08:05:24 +00:00
guint length ;
xmlDocPtr doc ;
xmlXPathContextPtr xpath_context ;
GVariant * chart_name ,
* country ,
* city ,
* longitude ,
* latitude ,
* altitude ,
* year ,
* month ,
* day ,
* hour ,
* minute ,
* second ,
* timezone ;
GsweTimestamp * timestamp ;
2013-09-21 13:47:48 +00:00
gboolean found_error = FALSE ;
2013-09-18 08:05:24 +00:00
uri = g_file_get_uri ( file ) ;
if ( ! g_file_load_contents ( file , NULL , & xml , & length , NULL , err ) ) {
g_free ( uri ) ;
return NULL ;
}
if ( ( doc = xmlReadMemory ( xml , length , " chart.xml " , NULL , 0 ) ) = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' can not be read. Maybe it is corrupt, or not a save file at all " , uri ) ;
g_free ( xml ) ;
g_free ( uri ) ;
return NULL ;
}
if ( ( xpath_context = xmlXPathNewContext ( doc ) ) = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_LIBXML , " File '%s' could not be loaded due to internal LibXML error " , uri ) ;
xmlFreeDoc ( doc ) ;
g_free ( xml ) ;
g_free ( uri ) ;
return NULL ;
}
2013-09-21 13:49:13 +00:00
if ( ( chart_name = get_by_xpath ( xpath_context , uri , " /chartinfo/data/name/text() " , TRUE , XML_CONVERT_STRING , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( country = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/country/text() " , FALSE , XML_CONVERT_STRING , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( city = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/city/text() " , FALSE , XML_CONVERT_STRING , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( longitude = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/longitude/text() " , TRUE , XML_CONVERT_DOUBLE , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( latitude = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/latitude/text() " , TRUE , XML_CONVERT_DOUBLE , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( altitude = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/altitude/text() " , TRUE , XML_CONVERT_DOUBLE , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( year = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/year/text() " , TRUE , XML_CONVERT_INT , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( month = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/month/text() " , TRUE , XML_CONVERT_INT , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( day = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/day/text() " , TRUE , XML_CONVERT_INT , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( hour = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/hour/text() " , TRUE , XML_CONVERT_INT , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( minute = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/minute/text() " , TRUE , XML_CONVERT_INT , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( second = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/second/text() " , TRUE , XML_CONVERT_INT , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
2013-09-18 09:20:02 +00:00
}
2013-09-21 13:49:13 +00:00
if ( ( timezone = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/timezone/text() " , TRUE , XML_CONVERT_DOUBLE , err ) ) = = NULL ) {
2013-09-21 13:47:48 +00:00
found_error = TRUE ;
}
if ( found_error ) {
ag_g_variant_unref ( chart_name ) ;
ag_g_variant_unref ( country ) ;
ag_g_variant_unref ( city ) ;
ag_g_variant_unref ( longitude ) ;
ag_g_variant_unref ( latitude ) ;
ag_g_variant_unref ( altitude ) ;
ag_g_variant_unref ( year ) ;
ag_g_variant_unref ( month ) ;
ag_g_variant_unref ( day ) ;
ag_g_variant_unref ( hour ) ;
ag_g_variant_unref ( minute ) ;
ag_g_variant_unref ( second ) ;
ag_g_variant_unref ( timezone ) ;
2013-09-18 09:20:02 +00:00
xmlFreeDoc ( doc ) ;
g_free ( xml ) ;
g_free ( uri ) ;
return NULL ;
}
2013-09-18 08:05:24 +00:00
timestamp = gswe_timestamp_new_from_gregorian_full (
g_variant_get_int32 ( year ) ,
g_variant_get_int32 ( month ) ,
g_variant_get_int32 ( day ) ,
g_variant_get_int32 ( hour ) ,
g_variant_get_int32 ( minute ) ,
g_variant_get_int32 ( second ) ,
0 ,
g_variant_get_double ( timezone )
) ;
g_variant_unref ( year ) ;
g_variant_unref ( month ) ;
g_variant_unref ( day ) ;
g_variant_unref ( hour ) ;
g_variant_unref ( minute ) ;
g_variant_unref ( second ) ;
g_variant_unref ( timezone ) ;
// TODO: Make house system configurable (and saveable)
chart = ag_chart_new_full ( timestamp , g_variant_get_double ( longitude ) , g_variant_get_double ( latitude ) , g_variant_get_double ( altitude ) , GSWE_HOUSE_SYSTEM_PLACIDUS ) ;
g_variant_unref ( longitude ) ;
g_variant_unref ( latitude ) ;
g_variant_unref ( altitude ) ;
ag_chart_set_name ( chart , g_variant_get_string ( chart_name , NULL ) ) ;
g_variant_unref ( chart_name ) ;
2013-09-21 13:50:16 +00:00
g_variant_get ( country , " ms " , & country_name ) ;
2013-09-18 08:05:24 +00:00
g_variant_unref ( country ) ;
2013-09-21 13:50:16 +00:00
ag_chart_set_country ( chart , country_name ) ;
g_free ( country_name ) ;
2013-09-18 08:05:24 +00:00
2013-09-21 13:50:16 +00:00
g_variant_get ( city , " ms " , & city_name ) ;
2013-09-18 08:05:24 +00:00
g_variant_unref ( city ) ;
2013-09-21 13:50:16 +00:00
ag_chart_set_city ( chart , city_name ) ;
g_free ( city_name ) ;
2013-09-18 08:05:24 +00:00
g_free ( xml ) ;
g_free ( uri ) ;
xmlXPathFreeContext ( xpath_context ) ;
xmlFreeDoc ( doc ) ;
return chart ;
}
2013-09-18 09:22:07 +00:00
static xmlDocPtr
create_save_doc ( AgChart * chart )
{
xmlDocPtr doc = NULL ;
xmlNodePtr root_node = NULL ,
data_node = NULL ,
place_node = NULL ,
time_node = NULL ;
gchar * value ;
GsweCoordinates * coordinates ;
GsweTimestamp * timestamp ;
doc = xmlNewDoc ( BAD_CAST " 1.0 " ) ;
root_node = xmlNewNode ( NULL , BAD_CAST " chartinfo " ) ;
xmlDocSetRootElement ( doc , root_node ) ;
// Begin <data> node
data_node = xmlNewChild ( root_node , NULL , BAD_CAST " data " , NULL ) ;
value = ag_chart_get_name ( chart ) ;
xmlNewChild ( data_node , NULL , BAD_CAST " name " , BAD_CAST value ) ;
g_free ( value ) ;
// Begin <place> node
place_node = xmlNewChild ( data_node , NULL , BAD_CAST " place " , NULL ) ;
value = ag_chart_get_country ( chart ) ;
xmlNewChild ( place_node , NULL , BAD_CAST " country " , BAD_CAST value ) ;
g_free ( value ) ;
value = ag_chart_get_city ( chart ) ;
xmlNewChild ( place_node , NULL , BAD_CAST " city " , BAD_CAST value ) ;
g_free ( value ) ;
coordinates = gswe_moment_get_coordinates ( GSWE_MOMENT ( chart ) ) ;
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , coordinates - > longitude ) ;
xmlNewChild ( place_node , NULL , BAD_CAST " longitude " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , coordinates - > latitude ) ;
xmlNewChild ( place_node , NULL , BAD_CAST " latitude " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , coordinates - > altitude ) ;
xmlNewChild ( place_node , NULL , BAD_CAST " altitude " , BAD_CAST value ) ;
g_free ( value ) ;
g_free ( coordinates ) ;
// Begin <time> node
time_node = xmlNewChild ( data_node , NULL , BAD_CAST " time " , NULL ) ;
timestamp = gswe_moment_get_timestamp ( GSWE_MOMENT ( chart ) ) ;
value = g_malloc0 ( 10 ) ;
g_ascii_dtostr ( value , 10 , gswe_timestamp_get_gregorian_year ( timestamp , NULL ) ) ;
xmlNewChild ( time_node , NULL , BAD_CAST " year " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 3 ) ;
g_ascii_dtostr ( value , 3 , gswe_timestamp_get_gregorian_month ( timestamp , NULL ) ) ;
xmlNewChild ( time_node , NULL , BAD_CAST " month " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 3 ) ;
g_ascii_dtostr ( value , 3 , gswe_timestamp_get_gregorian_day ( timestamp , NULL ) ) ;
xmlNewChild ( time_node , NULL , BAD_CAST " day " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 3 ) ;
g_ascii_dtostr ( value , 3 , gswe_timestamp_get_gregorian_hour ( timestamp , NULL ) ) ;
xmlNewChild ( time_node , NULL , BAD_CAST " hour " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 3 ) ;
g_ascii_dtostr ( value , 3 , gswe_timestamp_get_gregorian_minute ( timestamp , NULL ) ) ;
xmlNewChild ( time_node , NULL , BAD_CAST " minute " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 3 ) ;
g_ascii_dtostr ( value , 3 , gswe_timestamp_get_gregorian_second ( timestamp , NULL ) ) ;
xmlNewChild ( time_node , NULL , BAD_CAST " second " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 7 ) ;
g_ascii_dtostr ( value , 7 , gswe_timestamp_get_gregorian_timezone ( timestamp ) ) ;
xmlNewChild ( time_node , NULL , BAD_CAST " timezone " , BAD_CAST value ) ;
g_free ( value ) ;
return doc ;
}
2013-09-18 08:06:12 +00:00
void
ag_chart_save_to_file ( AgChart * chart , GFile * file , GError * * err )
{
2013-09-18 09:22:23 +00:00
xmlChar * content = NULL ;
int length ;
xmlDocPtr save_doc = create_save_doc ( chart ) ;
xmlDocDumpFormatMemoryEnc ( save_doc , & content , & length , " UTF-8 " , 1 ) ;
g_file_replace_contents ( file , ( const gchar * ) content , length , NULL , FALSE , G_FILE_CREATE_NONE , NULL , NULL , err ) ;
xmlFreeDoc ( save_doc ) ;
2013-09-18 08:06:12 +00:00
}
2013-09-19 17:56:25 +00:00
gchar *
ag_chart_create_svg ( AgChart * chart , GError * * err )
2013-09-17 22:29:13 +00:00
{
2013-09-19 17:56:25 +00:00
xmlDocPtr doc = create_save_doc ( chart ) ,
xslt_doc ,
svg_doc ;
2013-09-17 22:29:13 +00:00
xmlNodePtr root_node = NULL ,
ascmcs_node = NULL ,
houses_node = NULL ,
bodies_node = NULL ,
2013-09-18 20:31:14 +00:00
aspects_node = NULL ,
antiscia_node = NULL ,
2013-09-17 22:29:13 +00:00
node = NULL ;
2013-09-19 17:56:25 +00:00
gchar * value ,
* stylesheet_path ,
2013-09-19 21:16:52 +00:00
* css_path ,
* save_content = NULL ,
* css_uri ,
* css_final_uri ,
* * params ;
2013-09-17 22:29:13 +00:00
GList * houses ,
* house ,
2013-09-18 20:31:14 +00:00
* planet ,
* aspect ,
* antiscion ;
2013-09-17 22:29:13 +00:00
const GswePlanetData * planet_data ;
2013-09-18 20:31:14 +00:00
const GsweAspectData * aspect_data ;
GEnumClass * planets_class ,
* aspects_class ,
* antiscia_class ;
2013-09-19 17:56:25 +00:00
gint save_length ;
2013-09-20 08:03:08 +00:00
GFile * css_file ;
2013-09-19 17:56:25 +00:00
xsltStylesheetPtr xslt_proc ;
2013-09-19 21:14:37 +00:00
locale_t current_locale ;
2013-09-17 22:29:13 +00:00
root_node = xmlDocGetRootElement ( doc ) ;
// gswe_moment_get_house_cusps() also calculates ascmcs data, so call it this early
houses = gswe_moment_get_house_cusps ( GSWE_MOMENT ( chart ) , NULL ) ;
// Begin <ascmcs> node
2013-09-19 17:56:25 +00:00
g_debug ( " Generating theoretical points table " ) ;
2013-09-17 22:29:13 +00:00
ascmcs_node = xmlNewChild ( root_node , NULL , BAD_CAST " ascmcs " , NULL ) ;
node = xmlNewChild ( ascmcs_node , NULL , BAD_CAST " ascendant " , NULL ) ;
planet_data = gswe_moment_get_planet ( GSWE_MOMENT ( chart ) , GSWE_PLANET_ASCENDENT , NULL ) ;
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , planet_data - > position ) ;
xmlNewProp ( node , BAD_CAST " degree_ut " , BAD_CAST value ) ;
g_free ( value ) ;
node = xmlNewChild ( ascmcs_node , NULL , BAD_CAST " mc " , NULL ) ;
planet_data = gswe_moment_get_planet ( GSWE_MOMENT ( chart ) , GSWE_PLANET_MC , NULL ) ;
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , planet_data - > position ) ;
xmlNewProp ( node , BAD_CAST " degree_ut " , BAD_CAST value ) ;
g_free ( value ) ;
node = xmlNewChild ( ascmcs_node , NULL , BAD_CAST " vertex " , NULL ) ;
planet_data = gswe_moment_get_planet ( GSWE_MOMENT ( chart ) , GSWE_PLANET_VERTEX , NULL ) ;
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , planet_data - > position ) ;
xmlNewProp ( node , BAD_CAST " degree_ut " , BAD_CAST value ) ;
g_free ( value ) ;
// Begin <houses> node
2013-09-19 17:56:25 +00:00
g_debug ( " Generating houses table " ) ;
2013-09-17 22:29:13 +00:00
houses_node = xmlNewChild ( root_node , NULL , BAD_CAST " houses " , NULL ) ;
for ( house = houses ; house ; house = g_list_next ( house ) ) {
GsweHouseData * house_data = house - > data ;
node = xmlNewChild ( houses_node , NULL , BAD_CAST " house " , NULL ) ;
value = g_malloc0 ( 3 ) ;
g_ascii_dtostr ( value , 3 , house_data - > house ) ;
xmlNewProp ( node , BAD_CAST " number " , BAD_CAST value ) ;
g_free ( value ) ;
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , house_data - > cusp_position ) ;
xmlNewProp ( node , BAD_CAST " degree " , BAD_CAST value ) ;
g_free ( value ) ;
}
// Begin <bodies> node
2013-09-19 17:56:25 +00:00
g_debug ( " Generating bodies table " ) ;
2013-09-17 22:29:13 +00:00
bodies_node = xmlNewChild ( root_node , NULL , BAD_CAST " bodies " , NULL ) ;
2013-09-18 20:31:14 +00:00
planets_class = g_type_class_ref ( GSWE_TYPE_PLANET ) ;
2013-09-17 22:29:13 +00:00
2013-09-18 20:31:14 +00:00
for ( planet = gswe_moment_get_all_planets ( GSWE_MOMENT ( chart ) ) ; planet ; planet = g_list_next ( planet ) ) {
2013-09-17 22:29:13 +00:00
planet_data = planet - > data ;
2013-09-18 20:31:14 +00:00
GEnumValue * enum_value ;
2013-09-17 22:29:13 +00:00
if (
( planet_data - > planet_id = = GSWE_PLANET_ASCENDENT )
| | ( planet_data - > planet_id = = GSWE_PLANET_MC )
| | ( planet_data - > planet_id = = GSWE_PLANET_VERTEX )
) {
continue ;
}
node = xmlNewChild ( bodies_node , NULL , BAD_CAST " body " , NULL ) ;
2013-09-18 20:31:14 +00:00
enum_value = g_enum_get_value ( G_ENUM_CLASS ( planets_class ) , planet_data - > planet_id ) ;
xmlNewProp ( node , BAD_CAST " name " , BAD_CAST enum_value - > value_name ) ;
2013-09-17 22:29:13 +00:00
value = g_malloc0 ( 12 ) ;
g_ascii_dtostr ( value , 12 , planet_data - > position ) ;
xmlNewProp ( node , BAD_CAST " degree " , BAD_CAST value ) ;
g_free ( value ) ;
}
2013-09-18 20:31:14 +00:00
// Begin <aspects> node
2013-09-19 17:56:25 +00:00
g_debug ( " Generating aspects table " ) ;
2013-09-18 20:31:14 +00:00
aspects_node = xmlNewChild ( root_node , NULL , BAD_CAST " aspects " , NULL ) ;
aspects_class = g_type_class_ref ( GSWE_TYPE_ASPECT ) ;
for ( aspect = gswe_moment_get_all_aspects ( GSWE_MOMENT ( chart ) ) ; aspect ; aspect = g_list_next ( aspect ) ) {
GEnumValue * enum_value ;
aspect_data = aspect - > data ;
if ( aspect_data - > aspect = = GSWE_ASPECT_NONE ) {
continue ;
}
node = xmlNewChild ( aspects_node , NULL , BAD_CAST " aspect " , NULL ) ;
enum_value = g_enum_get_value ( G_ENUM_CLASS ( planets_class ) , aspect_data - > planet1 - > planet_id ) ;
xmlNewProp ( node , BAD_CAST " body1 " , BAD_CAST enum_value - > value_name ) ;
enum_value = g_enum_get_value ( G_ENUM_CLASS ( planets_class ) , aspect_data - > planet2 - > planet_id ) ;
xmlNewProp ( node , BAD_CAST " body2 " , BAD_CAST enum_value - > value_name ) ;
enum_value = g_enum_get_value ( G_ENUM_CLASS ( aspects_class ) , aspect_data - > aspect ) ;
xmlNewProp ( node , BAD_CAST " type " , BAD_CAST enum_value - > value_name ) ;
}
g_type_class_unref ( aspects_class ) ;
// Begin <antiscia> node
2013-09-19 17:56:25 +00:00
g_debug ( " Generating antiscia table " ) ;
2013-09-18 20:31:14 +00:00
antiscia_node = xmlNewChild ( root_node , NULL , BAD_CAST " antiscia " , NULL ) ;
antiscia_class = g_type_class_ref ( GSWE_TYPE_ANTISCION_AXIS ) ;
for ( antiscion = gswe_moment_get_all_antiscia ( GSWE_MOMENT ( chart ) ) ; antiscion ; antiscion = g_list_next ( antiscion ) ) {
GsweAntiscionData * antiscion_data = antiscion - > data ;
GEnumValue * enum_value ;
if ( antiscion_data - > axis = = GSWE_ANTISCION_AXIS_NONE ) {
continue ;
}
node = xmlNewChild ( antiscia_node , NULL , BAD_CAST " antiscia " , NULL ) ;
enum_value = g_enum_get_value ( G_ENUM_CLASS ( planets_class ) , antiscion_data - > planet1 - > planet_id ) ;
xmlNewProp ( node , BAD_CAST " body1 " , BAD_CAST enum_value - > value_name ) ;
enum_value = g_enum_get_value ( G_ENUM_CLASS ( planets_class ) , antiscion_data - > planet2 - > planet_id ) ;
xmlNewProp ( node , BAD_CAST " body2 " , BAD_CAST enum_value - > value_name ) ;
enum_value = g_enum_get_value ( G_ENUM_CLASS ( antiscia_class ) , antiscion_data - > axis ) ;
xmlNewProp ( node , BAD_CAST " axis " , BAD_CAST enum_value - > value_name ) ;
}
g_type_class_unref ( planets_class ) ;
2013-09-19 17:56:25 +00:00
// Now, doc contains the generated XML tree
2013-09-19 21:16:52 +00:00
css_path = g_strdup_printf ( " %s/%s " , PKGDATADIR , " chart.css " ) ;
g_debug ( " Using %s as a CSS stylesheet " , css_path ) ;
css_file = g_file_new_for_path ( css_path ) ;
css_uri = g_file_get_uri ( css_file ) ;
2013-09-20 08:03:08 +00:00
stylesheet_path = g_strdup_printf ( " %s/%s " , PKGDATADIR , " chart.xsl " ) ;
g_debug ( " Opening %s as a stylesheet " , stylesheet_path ) ;
if ( ( xslt_doc = xmlReadFile ( stylesheet_path , " UTF-8 " , 0 ) ) = = NULL ) {
2013-09-19 17:56:25 +00:00
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' can not be parsed as a stylesheet file. " , stylesheet_path ) ;
g_free ( stylesheet_path ) ;
2013-09-19 21:16:52 +00:00
g_free ( css_path ) ;
g_free ( css_uri ) ;
g_object_unref ( css_file ) ;
2013-09-19 17:56:25 +00:00
xmlFreeDoc ( doc ) ;
return NULL ;
}
2013-09-20 07:58:31 +00:00
# if LIBXML_VERSION >= 20603
xmlXIncludeProcessFlags ( xslt_doc , XSLT_PARSE_OPTIONS ) ;
# else
xmlXIncludeProcess ( xslt_doc ) ;
# endif
2013-09-19 17:56:25 +00:00
if ( ( xslt_proc = xsltParseStylesheetDoc ( xslt_doc ) ) = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' can not be parsed as a stylesheet file. " , stylesheet_path ) ;
g_free ( stylesheet_path ) ;
2013-09-19 21:16:52 +00:00
g_free ( css_path ) ;
g_free ( css_uri ) ;
g_object_unref ( css_file ) ;
2013-09-19 17:56:25 +00:00
xmlFreeDoc ( xslt_doc ) ;
xmlFreeDoc ( doc ) ;
return NULL ;
}
2013-09-19 21:16:52 +00:00
css_final_uri = g_strdup_printf ( " '%s' " , css_uri ) ;
g_free ( css_uri ) ;
params = g_new0 ( gchar * , 3 ) ;
params [ 0 ] = " css_file " ;
params [ 1 ] = css_final_uri ;
2013-09-19 21:14:37 +00:00
// libxml2 messes up the output, as it prints decimal floating point
// numbers in a localized format. It is not good in locales that use a
// character for decimal separator other than a dot. So let's just use the
// C locale until the SVG is generated.
current_locale = uselocale ( newlocale ( LC_ALL , " C " , 0 ) ) ;
2013-09-19 21:16:52 +00:00
svg_doc = xsltApplyStylesheet ( xslt_proc , doc , ( const char * * ) params ) ;
2013-09-19 21:14:37 +00:00
uselocale ( current_locale ) ;
2013-09-19 17:56:25 +00:00
g_free ( stylesheet_path ) ;
2013-09-19 21:16:52 +00:00
g_free ( css_path ) ;
g_object_unref ( css_file ) ;
g_free ( params ) ;
2013-09-19 17:56:25 +00:00
xsltFreeStylesheet ( xslt_proc ) ;
2013-09-17 22:29:13 +00:00
xmlFreeDoc ( doc ) ;
2013-09-19 17:56:25 +00:00
// Now, svg_doc contains the generated SVG file
xmlDocDumpFormatMemoryEnc ( svg_doc , ( xmlChar * * ) & save_content , & save_length , " UTF-8 " , 1 ) ;
xmlFreeDoc ( svg_doc ) ;
return save_content ;
2013-09-17 22:29:13 +00:00
}