1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998,1999 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 /** \file dia_xml.c Helper function to convert Dia's basic to and from XML */
28 #include <libxml/parser.h>
29 #include <libxml/parserInternals.h>
30 #include <libxml/xmlmemory.h>
40 #include "dia_xml_libxml.h"
42 #include "geometry.h" /* For isinf() on Solaris */
46 #include <io.h> /* write, close */
49 #ifdef G_OS_WIN32 /* apparently _MSC_VER and mingw */
52 # define isinf(a) (!_finite(a))
58 /** If all files produced by dia were good XML files, we wouldn't have to do
59 * this little gymnastic. Alas, during the libxml1 days, we were outputting
60 * files with no encoding specification (which means UTF-8 if we're in an
61 * asciish encoding) and strings encoded in local charset (so, we wrote
64 * The following logic finds if we have a broken file, and attempts to fix
65 * it if it's possible. If the file is correct or is unrecognisable, we pass
66 * it untouched to libxml2.
67 * @param filename The name of the file to check.
68 * @param default_enc The default encoding to use if none is given.
69 * @return The filename given if it seems ok, or the name of a new file
70 * with fixed contents, or NULL if we couldn't read the file. The
71 * caller should free this string and unlink the file if it is not
72 * the same as `filename'.
73 * @bug The many gzclose-g_free-return sequences should be refactored into
74 * an "exception handle" (goto+label). At least for people who think goto is
75 * better than this. I dont. --hb
78 xml_file_check_encoding(const gchar
*filename
, const gchar
*default_enc
)
80 gzFile zf
= gzopen(filename
,"rb");
86 gboolean well_formed_utf8
;
88 static char magic_xml
[] =
89 {0x3c,0x3f,0x78,0x6d,0x6c,0x00}; /* "<?xml" in ASCII */
92 /* message_error(_("The file %s can not be opened for reading"),filename); */
93 /* XXX perhaps we can just chicken out to libxml ? -- CC */
96 p
= buf
= g_malloc0(BUFLEN
);
97 len
= gzread(zf
,buf
,BUFLEN
);
100 /* first, we expect the magic <?xml string */
101 if ((0 != strncmp(p
,magic_xml
,5)) || (len
< 5)) {
104 return filename
; /* let libxml figure out what this is. */
106 /* now, we're sure we have some asciish XML file. */
108 while (((*p
== 0x20)||(*p
== 0x09)||(*p
== 0x0d)||(*p
== 0x0a))
110 if (p
>=pmax
) { /* whoops ? */
115 if (0 != strncmp(p
,"version=\"",9)) {
116 gzclose(zf
); /* chicken out. */
121 /* The header is rather well formed. */
122 if (p
>=pmax
) { /* whoops ? */
127 while ((*p
!= '"') && (p
< pmax
)) p
++;
129 while (((*p
== 0x20)||(*p
== 0x09)||(*p
== 0x0d)||(*p
== 0x0a))
131 if (p
>=pmax
) { /* whoops ? */
136 if (0 == strncmp(p
,"encoding=\"",10)) {
137 gzclose(zf
); /* this file has an encoding string. Good. */
141 /* now let's read the whole file, to see if there are offending bits.
142 * We can call it well formed UTF-8 if the highest isn't used
144 well_formed_utf8
= TRUE
;
147 for (i
= 0; i
< len
; i
++)
148 if (buf
[i
] & 0x80 || buf
[i
] == '&')
149 well_formed_utf8
= FALSE
;
150 len
= gzread(zf
,buf
,BUFLEN
);
151 } while (len
> 0 && well_formed_utf8
);
152 if (well_formed_utf8
) {
153 gzclose(zf
); /* this file is utf-8 compatible */
157 gzclose(zf
); /* poor man's fseek */
158 zf
= gzopen(filename
,"rb");
159 len
= gzread(zf
,buf
,BUFLEN
);
162 if (0 != strcmp(default_enc
,"UTF-8")) {
163 message_warning(_("The file %s has no encoding specification;\n"
164 "assuming it is encoded in %s"),
165 dia_message_filename(filename
), default_enc
);
167 gzclose(zf
); /* we apply the standard here. */
173 if (!tmp
) tmp
= getenv("TEMP");
174 if (!tmp
) tmp
= "/tmp";
176 res
= g_strconcat(tmp
,G_DIR_SEPARATOR_S
,"dia-xml-fix-encodingXXXXXX",NULL
);
179 write(uf
," encoding=\"",11);
180 write(uf
,default_enc
,strlen(default_enc
));
182 write(uf
,p
,pmax
- p
);
185 len
= gzread(zf
,buf
,BUFLEN
);
192 return res
; /* caller frees the name and unlinks the file. */
195 /** Parse a given file into XML, handling old broken files correctly.
196 * @param filename The name of the file to read.
197 * @returns An XML document parsed from the file.
198 * @see xmlParseFile() in the XML2 library for details on the return value.
201 xmlDiaParseFile(const char *filename
)
203 G_CONST_RETURN
char *local_charset
= NULL
;
205 if ( !g_get_charset(&local_charset
)
207 /* we're not in an UTF-8 environment. */
208 const gchar
*fname
= xml_file_check_encoding(filename
,local_charset
);
209 if (fname
!= filename
) {
210 /* We've got a corrected file to parse. */
211 xmlDocPtr ret
= xmlDoParseFile(fname
);
213 /* printf("has read %s instead of %s\n",fname,filename); */
214 g_free((void *)fname
);
217 /* the XML file is good. libxml is "old enough" to handle it correctly.
219 return xmlDoParseFile(filename
);
222 return xmlDoParseFile(filename
);
226 /** Relic of earlier, unhappier days.
227 * @param filename A file to parse.
228 * @return An XML document.
229 * @bug Could probably be inlined. So what?
232 xmlDoParseFile(const char *filename
)
234 return xmlParseFile(filename
);
237 /** Find a named attribute node in an XML object node.
238 * Note that Dia has a concept of attribute node that is not the same
239 * as an XML attribute.
240 * @param obj_node The node to look in.
241 * @param attrname The name of the attribute node to find.
242 * @return The node matching the given name, or NULL if none found.
245 object_find_attribute(ObjectNode obj_node
,
246 const char *attrname
)
251 while (obj_node
&& xmlIsBlankNode(obj_node
))
252 obj_node
= obj_node
->next
;
253 if (!obj_node
) return NULL
;
255 attr
= obj_node
->xmlChildrenNode
;
256 while (attr
!= NULL
) {
257 if (xmlIsBlankNode(attr
)) {
262 name
= xmlGetProp(attr
, "name");
263 if ( (name
!=NULL
) && (strcmp(name
, attrname
)==0) ) {
267 if (name
) xmlFree(name
);
274 /** Find an attribute in a composite XML node.
275 * @param composite_node The composite node to search.
276 * @param attrname The name of the attribute node to find.
277 * @return The desired node, or NULL if none exists in `composite_node'.
278 * @bug Describe in more detail how a composite node differs from an
282 composite_find_attribute(DataNode composite_node
,
283 const char *attrname
)
288 while (composite_node
&& xmlIsBlankNode(composite_node
))
289 composite_node
= composite_node
->next
;
290 if (!composite_node
) return NULL
;
292 attr
= composite_node
->xmlChildrenNode
;
293 while (attr
!= NULL
) {
294 if (xmlIsBlankNode(attr
)) {
299 name
= xmlGetProp(attr
, "name");
300 if ( (name
!=NULL
) && (strcmp(name
, attrname
)==0) ) {
304 if (name
) xmlFree(name
);
311 /** The number of non-blank data nodes in an attribute node.
312 * @param attribute The attribute node to read from.
313 * @returns The number of non-blank data nodes in the node.
316 attribute_num_data(AttributeNode attribute
)
321 data
= attribute
? attribute
->xmlChildrenNode
: NULL
;
322 while (data
!= NULL
) {
323 if (xmlIsBlankNode(data
)) {
333 /** Get the first data node in an attribute node.
334 * @param attribute The attribute node to look through.
335 * @return The first non-black data node in the attribute node.
338 attribute_first_data(AttributeNode attribute
)
340 xmlNode
*data
= attribute
? attribute
->xmlChildrenNode
: NULL
;
341 while (data
&& xmlIsBlankNode(data
)) data
= data
->next
;
342 return (DataNode
) data
;
345 /** Get the next data node (sibling).
346 * @param data A data node to start from (e.g. just processed)
347 * @returns The next sibling data node.
350 data_next(DataNode data
)
355 while (data
&& xmlIsBlankNode(data
)) data
= data
->next
;
357 return (DataNode
) data
;
360 /** Get the type of a data node.
361 * @param data The data node.
362 * @return The type that the data node defines, or 0 on error. In case of
363 * error, an error message is displayed.
364 * @note This function does a number of strcmp calls, which may not be the
365 * fastest way to check if a node is of the expected type.
366 * @bug Make functions that check quickly if a node is of a specific type
367 * (but profile first).
370 data_type(DataNode data
)
374 name
= data
? (const char *)data
->name
: (const char *)"";
375 if (strcmp(name
, "composite")==0) {
376 return DATATYPE_COMPOSITE
;
377 } else if (strcmp(name
, "int")==0) {
379 } else if (strcmp(name
, "enum")==0) {
380 return DATATYPE_ENUM
;
381 } else if (strcmp(name
, "real")==0) {
382 return DATATYPE_REAL
;
383 } else if (strcmp(name
, "boolean")==0) {
384 return DATATYPE_BOOLEAN
;
385 } else if (strcmp(name
, "color")==0) {
386 return DATATYPE_COLOR
;
387 } else if (strcmp(name
, "point")==0) {
388 return DATATYPE_POINT
;
389 } else if (strcmp(name
, "rectangle")==0) {
390 return DATATYPE_RECTANGLE
;
391 } else if (strcmp(name
, "string")==0) {
392 return DATATYPE_STRING
;
393 } else if (strcmp(name
, "font")==0) {
394 return DATATYPE_FONT
;
397 message_error("Unknown type of DataNode");
401 /** Return the value of an integer-type data node.
402 * @param data The data node to read from.
403 * @returns The integer value found in the node. If the node is not an
404 * integer node, an error message is displayed and 0 is returned.
407 data_int(DataNode data
)
412 if (data_type(data
)!=DATATYPE_INT
) {
413 message_error("Taking int value of non-int node.");
417 val
= xmlGetProp(data
, "val");
419 if (val
) xmlFree(val
);
424 /** Return the value of an enum-type data node.
425 * @param data The data node to read from.
426 * @returns The enum value found in the node. If the node is not an
427 * enum node, an error message is displayed and 0 is returned.
429 int data_enum(DataNode data
)
434 if (data_type(data
)!=DATATYPE_ENUM
) {
435 message_error("Taking enum value of non-enum node.");
439 val
= xmlGetProp(data
, "val");
441 if (val
) xmlFree(val
);
446 /** Return the value of a real-type data node.
447 * @param data The data node to read from.
448 * @returns The real value found in the node. If the node is not a
449 * real-type node, an error message is displayed and 0.0 is returned.
452 data_real(DataNode data
)
457 if (data_type(data
)!=DATATYPE_REAL
) {
458 message_error("Taking real value of non-real node.");
462 val
= xmlGetProp(data
, "val");
463 res
= g_ascii_strtod(val
, NULL
);
464 if (val
) xmlFree(val
);
469 /** Return the value of a boolean-type data node.
470 * @param data The data node to read from.
471 * @returns The boolean value found in the node. If the node is not a
472 * boolean node, an error message is displayed and FALSE is returned.
475 data_boolean(DataNode data
)
480 if (data_type(data
)!=DATATYPE_BOOLEAN
) {
481 message_error("Taking boolean value of non-boolean node.");
485 val
= xmlGetProp(data
, "val");
487 if ((val
) && (strcmp(val
, "true")==0))
492 if (val
) xmlFree(val
);
497 /** Return the integer value of a hex digit.
498 * @param c A hex digit, one of 0-9, a-f or A-F.
499 * @returns The value of the digit, i.e. 0-15. If a non-gex digit is given
500 * an error message is displayed to the user, and 0 is returned.
505 if ((c
>='0') && (c
<='9'))
507 if ((c
>='a') && (c
<='f'))
509 if ((c
>='A') && (c
<='F'))
511 message_error("wrong hex digit %c", c
);
515 /** Return the value of a color-type data node.
516 * @param data The XML node to read from
517 * @param col A place to store the resulting RGB values. If the node does
518 * not contain a valid color value, an error message is displayed to the
519 * user, and `col' is unchanged.
520 * @note Could be cool to use RGBA data here, even if we can't display it yet.
523 data_color(DataNode data
, Color
*col
)
528 if (data_type(data
)!=DATATYPE_COLOR
) {
529 message_error("Taking color value of non-color node.");
533 val
= xmlGetProp(data
, "val");
538 if ((val
) && (strlen(val
)>=7)) {
539 r
= hex_digit(val
[1])*16 + hex_digit(val
[2]);
540 g
= hex_digit(val
[3])*16 + hex_digit(val
[4]);
541 b
= hex_digit(val
[5])*16 + hex_digit(val
[6]);
544 if (val
) xmlFree(val
);
546 col
->red
= (float)(r
/255.0);
547 col
->green
= (float)(g
/255.0);
548 col
->blue
= (float)(b
/255.0);
551 /** Return the value of a point-type data node.
552 * @param data The XML node to read from
553 * @param point A place to store the resulting x, y values. If the node does
554 * not contain a valid point value, an error message is displayed to the
555 * user, and `point' is unchanged.
558 data_point(DataNode data
, Point
*point
)
564 if (data_type(data
)!=DATATYPE_POINT
) {
565 message_error(_("Taking point value of non-point node."));
569 val
= xmlGetProp(data
, "val");
570 point
->x
= g_ascii_strtod(val
, &str
);
572 if ((ax
> 1e9
) || ((ax
< 1e-9) && (ax
!= 0.0)) || isnan(ax
) || isinf(ax
)) {
573 /* there is no provision to keep values larger when saving,
574 * so do this 'reduction' silent */
576 g_warning(_("Incorrect x Point value \"%s\" %f; discarding it."),val
,point
->x
);
579 while ((*str
!= ',') && (*str
!=0))
583 g_warning(_("Error parsing point."));
587 point
->y
= g_ascii_strtod(str
+1, NULL
);
589 if ((ay
> 1e9
) || ((ay
< 1e-9) && (ay
!= 0.0)) || isnan(ay
) || isinf(ay
)) {
590 if (!(ay
< 1e-9)) /* don't bother with useless warnings (see above) */
591 g_warning(_("Incorrect y Point value \"%s\" %f; discarding it."),str
+1,point
->y
);
597 /** Return the value of a rectangle-type data node.
598 * @param data The data node to read from.
599 * @param rect A place to store the resulting values. If the node does
600 * not contain a valid rectangle value, an error message is displayed to the
601 * user, and `rect' is unchanged.
604 data_rectangle(DataNode data
, Rectangle
*rect
)
609 if (data_type(data
)!=DATATYPE_RECTANGLE
) {
610 message_error("Taking rectangle value of non-rectangle node.");
614 val
= xmlGetProp(data
, "val");
616 rect
->left
= g_ascii_strtod(val
, &str
);
618 while ((*str
!= ',') && (*str
!=0))
622 message_error("Error parsing rectangle.");
627 rect
->top
= g_ascii_strtod(str
+1, &str
);
629 while ((*str
!= ';') && (*str
!=0))
633 message_error("Error parsing rectangle.");
638 rect
->right
= g_ascii_strtod(str
+1, &str
);
640 while ((*str
!= ',') && (*str
!=0))
644 message_error("Error parsing rectangle.");
649 rect
->bottom
= g_ascii_strtod(str
+1, NULL
);
654 /** Return the value of a string-type data node.
655 * @param data The data node to read from.
656 * @returns The string value found in the node. If the node is not a
657 * string node, an error message is displayed and NULL is returned. The
658 * returned valuee should be freed after use.
659 * @note For historical reasons, strings in Dia XML are surrounded by ##.
662 data_string(DataNode data
)
665 gchar
*str
, *p
,*str2
;
668 if (data_type(data
)!=DATATYPE_STRING
) {
669 message_error("Taking string value of non-string node.");
673 val
= xmlGetProp(data
, "val");
674 if (val
!= NULL
) { /* Old kind of string. Left for backwards compatibility */
675 str
= g_malloc(4 * (sizeof(char)*(strlen(val
)+1))); /* extra room
683 /* Just skip this. \0 means nothing */
695 message_error("Error in string tag.");
704 str2
= g_strdup(str
); /* to remove the extra space */
709 if (data
->xmlChildrenNode
!=NULL
) {
710 p
= xmlNodeListGetString(data
->doc
, data
->xmlChildrenNode
, TRUE
);
713 message_error("Error in file, string not starting with #\n");
715 len
= strlen(p
)-1; /* Ignore first '#' */
717 str
= g_malloc(len
+1);
719 strncpy(str
, p
+1, len
);
720 str
[len
]=0; /* For safety */
722 str
[strlen(str
)-1] = 0; /* Remove last '#' */
730 /** Return the value of a filename-type data node.
731 * @param data The data node to read from.
732 * @return The filename value found in the node. If the node is not a
733 * filename node, an error message is displayed and NULL is returned.
734 * The resulting string is in the local filesystem's encoding rather than
735 * UTF-8, and should be freed after use.
736 * @bug data_string() can return NULL, what does g_filename_from_utf8 do then?
739 data_filename(DataNode data
)
741 char *utf8
= data_string(data
);
742 char *filename
= g_filename_from_utf8(utf8
, -1, NULL
, NULL
, NULL
);
747 /** Return the value of a font-type data node. This handles both the current
748 * format (family and style) and the old format (name).
749 * @param data The data node to read from.
750 * @return The font value found in the node. If the node is not a
751 * font node, an error message is displayed and NULL is returned. The
752 * resulting value should be freed after use.
755 data_font(DataNode data
)
760 if (data_type(data
)!=DATATYPE_FONT
) {
761 message_error("Taking font value of non-font node.");
765 family
= xmlGetProp(data
, "family");
766 /* always prefer the new format */
769 xmlChar
* style_name
= xmlGetProp(data
, "style");
770 style
= style_name
? atoi(style_name
) : 0;
772 font
= dia_font_new (family
, style
, 1.0);
773 if (family
) xmlFree(family
);
774 if (style_name
) xmlFree(style_name
);
776 /* Legacy format support */
777 char *name
= xmlGetProp(data
, "name");
778 font
= dia_font_new_from_legacy_name(name
);
784 /* ***** Saving XML **** */
786 /** Create a new attribute node.
787 * @param obj_node The object node to create the attribute node under.
788 * @param attrname The name of the attribute node.
789 * @return A new attribute node.
790 * @bug Should have utility functions that creates the node and sets
791 * the value based on type.
794 new_attribute(ObjectNode obj_node
,
795 const char *attrname
)
798 attr
= xmlNewChild(obj_node
, NULL
, "attribute", NULL
);
799 xmlSetProp(attr
, "name", attrname
);
804 /** Add an attribute node to a composite node.
805 * @param composite_node The composite node.
806 * @param attrname The name of the new attribute node.
807 * @return The attribute node added.
808 * @bug This does exactly the same as new_attribute.
811 composite_add_attribute(DataNode composite_node
,
812 const char *attrname
)
815 attr
= xmlNewChild(composite_node
, NULL
, "attribute", NULL
);
816 xmlSetProp(attr
, "name", attrname
);
821 /** Add integer data to an attribute node.
822 * @param attr The attribute node.
823 * @param data The value to set.
826 data_add_int(AttributeNode attr
, int data
)
829 char buffer
[20+1]; /* Enought for 64bit int + zero */
831 g_snprintf(buffer
, 20, "%d", data
);
833 data_node
= xmlNewChild(attr
, NULL
, "int", NULL
);
834 xmlSetProp(data_node
, "val", buffer
);
837 /** Add enum data to an attribute node.
838 * @param attr The attribute node.
839 * @param data The value to set.
842 data_add_enum(AttributeNode attr
, int data
)
845 char buffer
[20+1]; /* Enought for 64bit int + zero */
847 g_snprintf(buffer
, 20, "%d", data
);
849 data_node
= xmlNewChild(attr
, NULL
, "enum", NULL
);
850 xmlSetProp(data_node
, "val", buffer
);
853 /** Add real-typed data to an attribute node.
854 * @param attr The attribute node.
855 * @param data The value to set.
858 data_add_real(AttributeNode attr
, real data
)
861 char buffer
[G_ASCII_DTOSTR_BUF_SIZE
]; /* Large enought */
863 g_ascii_dtostr(buffer
, G_ASCII_DTOSTR_BUF_SIZE
, data
);
865 data_node
= xmlNewChild(attr
, NULL
, "real", NULL
);
866 xmlSetProp(data_node
, "val", buffer
);
869 /** Add boolean data to an attribute node.
870 * @param attr The attribute node.
871 * @param data The value to set.
874 data_add_boolean(AttributeNode attr
, int data
)
878 data_node
= xmlNewChild(attr
, NULL
, "boolean", NULL
);
880 xmlSetProp(data_node
, "val", "true");
882 xmlSetProp(data_node
, "val", "false");
885 /** Convert a floating-point value to hexadecimal.
886 * @param x The floating point value.
887 * @param str A string to place the result in.
888 * @note Currently only works for 0 <= x <= 255 and will silently cap the value
889 * to those limits. Also expects str to have at least two bytes allocated,
890 * and doesn't null-terminate it. This works well for converting a color
891 * value, but is pretty much useless for other values.
894 convert_to_hex(float x
, char *str
)
896 static const char hex_digit
[] = "0123456789abcdef";
905 str
[0] = hex_digit
[val
/16];
906 str
[1] = hex_digit
[val
%16];
909 /** Add color data to an attribute node.
910 * @param attr The attribute node.
911 * @param col The value to set.
914 data_add_color(AttributeNode attr
, const Color
*col
)
920 convert_to_hex(col
->red
, &buffer
[1]);
921 convert_to_hex(col
->green
, &buffer
[3]);
922 convert_to_hex(col
->blue
, &buffer
[5]);
925 data_node
= xmlNewChild(attr
, NULL
, "color", NULL
);
926 xmlSetProp(data_node
, "val", buffer
);
929 /** Add point data to an attribute node.
930 * @param attr The attribute node.
931 * @param point The value to set.
934 data_add_point(AttributeNode attr
, const Point
*point
)
938 gchar px_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
939 gchar py_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
941 g_ascii_formatd(px_buf
, sizeof(px_buf
), "%g", point
->x
);
942 g_ascii_formatd(py_buf
, sizeof(py_buf
), "%g", point
->y
);
943 buffer
= g_strconcat(px_buf
, ",", py_buf
, NULL
);
945 data_node
= xmlNewChild(attr
, NULL
, "point", NULL
);
946 xmlSetProp(data_node
, "val", buffer
);
950 /** Add rectangle data to an attribute node.
951 * @param attr The attribute node.
952 * @param rect The value to set.
955 data_add_rectangle(AttributeNode attr
, const Rectangle
*rect
)
959 gchar rl_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
960 gchar rr_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
961 gchar rt_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
962 gchar rb_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
964 g_ascii_formatd(rl_buf
, sizeof(rl_buf
), "%g", rect
->left
);
965 g_ascii_formatd(rr_buf
, sizeof(rr_buf
), "%g", rect
->right
);
966 g_ascii_formatd(rt_buf
, sizeof(rt_buf
), "%g", rect
->top
);
967 g_ascii_formatd(rb_buf
, sizeof(rb_buf
), "%g", rect
->bottom
);
969 buffer
= g_strconcat(rl_buf
, ",", rt_buf
, ";", rr_buf
, ",", rb_buf
, NULL
);
971 data_node
= xmlNewChild(attr
, NULL
, "rectangle", NULL
);
972 xmlSetProp(data_node
, "val", buffer
);
977 /** Add string data to an attribute node.
978 * @param attr The attribute node.
979 * @param str The value to set.
982 data_add_string(AttributeNode attr
, const char *str
)
985 xmlChar
*escaped_str
;
986 xmlChar
*sharped_str
;
989 data_node
= xmlNewChild(attr
, NULL
, "string", "##");
993 escaped_str
= xmlEncodeEntitiesReentrant(attr
->doc
,str
);
995 sharped_str
= g_strconcat("#", escaped_str
, "#", NULL
);
997 xmlFree(escaped_str
);
999 data_node
= xmlNewChild(attr
, NULL
, "string", sharped_str
);
1001 g_free(sharped_str
);
1004 /** Add filename data to an attribute node.
1005 * @param attr The attribute node.
1006 * @param filename The value to set. This should be n the local filesystem
1007 * encoding, not utf-8.
1010 data_add_filename(DataNode data
, const char *str
)
1012 char *utf8
= g_filename_to_utf8(str
, -1, NULL
, NULL
, NULL
);
1014 data_add_string(data
, utf8
);
1019 /** Add font data to an attribute node.
1020 * @param attr The attribute node.
1021 * @param font The value to set.
1024 data_add_font(AttributeNode attr
, const DiaFont
*font
)
1028 char buffer
[20+1]; /* Enought for 64bit int + zero */
1030 data_node
= xmlNewChild(attr
, NULL
, "font", NULL
);
1031 style
= dia_font_get_style (font
);
1032 xmlSetProp(data_node
, "family", dia_font_get_family(font
));
1033 g_snprintf(buffer
, 20, "%d", dia_font_get_style(font
));
1035 xmlSetProp(data_node
, "style", buffer
);
1036 /* Legacy support: don't crash older Dia on missing 'name' attribute */
1037 xmlSetProp(data_node
, "name", dia_font_get_legacy_name(font
));
1040 /** Add a new composite node to an attribute node.
1041 * @param attr The attribute node to add to.
1042 * @param type The type of the new node.
1043 * @returns The new child of `attr'.
1046 data_add_composite(AttributeNode attr
, const char *type
)
1048 /* type can be NULL */
1051 data_node
= xmlNewChild(attr
, NULL
, "composite", NULL
);
1053 xmlSetProp(data_node
, "type", type
);
1058 /** Emit a warning to the user that having UTF-8 as local charset doesn't.
1061 warn_about_broken_libxml1(void)
1063 message_warning(_("Your local character set is UTF-8. Because of issues"
1064 " with libxml1 and the support of files generated by"
1065 " previous versions of dia, you will encounter "
1066 " problems. Please report to dia-list@gnome.org if you"
1067 " see this message."));
1070 #define BUFSIZE 2048
1071 #define OVERRUN_SAFETY 16
1074 int pretty_formated_xml
= TRUE
;
1076 /** Save an XML document to a file.
1077 * @param filename The file to save to.
1078 * @param cur The XML document structure.
1079 * @return The return value of xmlSaveFormatFileEnc.
1080 * @bug Get the proper defn of the return value from libxml2.
1083 xmlDiaSaveFile(const char *filename
,
1088 if (pretty_formated_xml
)
1089 old
= xmlKeepBlanksDefault (0);
1090 ret
= xmlSaveFormatFileEnc (filename
,cur
, "UTF-8", pretty_formated_xml
? 1 : 0);
1091 if (pretty_formated_xml
)
1092 xmlKeepBlanksDefault (old
);