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 */
51 #define isinf(a) (!_finite(a))
56 /** If all files produced by dia were good XML files, we wouldn't have to do
57 * this little gymnastic. Alas, during the libxml1 days, we were outputting
58 * files with no encoding specification (which means UTF-8 if we're in an
59 * asciish encoding) and strings encoded in local charset (so, we wrote
62 * The following logic finds if we have a broken file, and attempts to fix
63 * it if it's possible. If the file is correct or is unrecognisable, we pass
64 * it untouched to libxml2.
65 * @param filename The name of the file to check.
66 * @param default_enc The default encoding to use if none is given.
67 * @return The filename given if it seems ok, or the name of a new file
68 * with fixed contents, or NULL if we couldn't read the file. The
69 * caller should free this string and unlink the file if it is not
70 * the same as `filename'.
71 * @bug The many gzclose-g_free-return sequences should be refactored into
72 * an "exception handle" (goto+label). At least for people who think goto is
73 * better than this. I dont. --hb
76 xml_file_check_encoding(const gchar
*filename
, const gchar
*default_enc
)
78 gzFile zf
= gzopen(filename
,"rb");
84 gboolean well_formed_utf8
;
86 static char magic_xml
[] =
87 {0x3c,0x3f,0x78,0x6d,0x6c,0x00}; /* "<?xml" in ASCII */
90 /* message_error(_("The file %s can not be opened for reading"),filename); */
91 /* XXX perhaps we can just chicken out to libxml ? -- CC */
94 p
= buf
= g_malloc0(BUFLEN
);
95 len
= gzread(zf
,buf
,BUFLEN
);
98 /* first, we expect the magic <?xml string */
99 if ((0 != strncmp(p
,magic_xml
,5)) || (len
< 5)) {
102 return filename
; /* let libxml figure out what this is. */
104 /* now, we're sure we have some asciish XML file. */
106 while (((*p
== 0x20)||(*p
== 0x09)||(*p
== 0x0d)||(*p
== 0x0a))
108 if (p
>=pmax
) { /* whoops ? */
113 if (0 != strncmp(p
,"version=\"",9)) {
114 gzclose(zf
); /* chicken out. */
119 /* The header is rather well formed. */
120 if (p
>=pmax
) { /* whoops ? */
125 while ((*p
!= '"') && (p
< pmax
)) p
++;
127 while (((*p
== 0x20)||(*p
== 0x09)||(*p
== 0x0d)||(*p
== 0x0a))
129 if (p
>=pmax
) { /* whoops ? */
134 if (0 == strncmp(p
,"encoding=\"",10)) {
135 gzclose(zf
); /* this file has an encoding string. Good. */
139 /* now let's read the whole file, to see if there are offending bits.
140 * We can call it well formed UTF-8 if the highest isn't used
142 well_formed_utf8
= TRUE
;
145 for (i
= 0; i
< len
; i
++)
146 if (buf
[i
] & 0x80 || buf
[i
] == '&')
147 well_formed_utf8
= FALSE
;
148 len
= gzread(zf
,buf
,BUFLEN
);
149 } while (len
> 0 && well_formed_utf8
);
150 if (well_formed_utf8
) {
151 gzclose(zf
); /* this file is utf-8 compatible */
155 gzclose(zf
); /* poor man's fseek */
156 zf
= gzopen(filename
,"rb");
157 len
= gzread(zf
,buf
,BUFLEN
);
160 if (0 != strcmp(default_enc
,"UTF-8")) {
161 message_warning(_("The file %s has no encoding specification;\n"
162 "assuming it is encoded in %s"),
163 dia_message_filename(filename
), default_enc
);
165 gzclose(zf
); /* we apply the standard here. */
171 if (!tmp
) tmp
= getenv("TEMP");
172 if (!tmp
) tmp
= "/tmp";
174 res
= g_strconcat(tmp
,G_DIR_SEPARATOR_S
,"dia-xml-fix-encodingXXXXXX",NULL
);
177 write(uf
," encoding=\"",11);
178 write(uf
,default_enc
,strlen(default_enc
));
180 write(uf
,p
,pmax
- p
);
183 len
= gzread(zf
,buf
,BUFLEN
);
190 return res
; /* caller frees the name and unlinks the file. */
193 /** Parse a given file into XML, handling old broken files correctly.
194 * @param filename The name of the file to read.
195 * @returns An XML document parsed from the file.
196 * @see xmlParseFile() in the XML2 library for details on the return value.
199 xmlDiaParseFile(const char *filename
)
201 G_CONST_RETURN
char *local_charset
= NULL
;
203 if ( !g_get_charset(&local_charset
)
205 /* we're not in an UTF-8 environment. */
206 const gchar
*fname
= xml_file_check_encoding(filename
,local_charset
);
207 if (fname
!= filename
) {
208 /* We've got a corrected file to parse. */
209 xmlDocPtr ret
= xmlDoParseFile(fname
);
211 /* printf("has read %s instead of %s\n",fname,filename); */
212 g_free((void *)fname
);
215 /* the XML file is good. libxml is "old enough" to handle it correctly.
217 return xmlDoParseFile(filename
);
220 return xmlDoParseFile(filename
);
224 /** Relic of earlier, unhappier days.
225 * @param filename A file to parse.
226 * @return An XML document.
227 * @bug Could probably be inlined. So what?
230 xmlDoParseFile(const char *filename
)
232 return xmlParseFile(filename
);
235 /** Find a named attribute node in an XML object node.
236 * Note that Dia has a concept of attribute node that is not the same
237 * as an XML attribute.
238 * @param obj_node The node to look in.
239 * @param attrname The name of the attribute node to find.
240 * @return The node matching the given name, or NULL if none found.
243 object_find_attribute(ObjectNode obj_node
,
244 const char *attrname
)
249 while (obj_node
&& xmlIsBlankNode(obj_node
))
250 obj_node
= obj_node
->next
;
251 if (!obj_node
) return NULL
;
253 attr
= obj_node
->xmlChildrenNode
;
254 while (attr
!= NULL
) {
255 if (xmlIsBlankNode(attr
)) {
260 name
= xmlGetProp(attr
, "name");
261 if ( (name
!=NULL
) && (strcmp(name
, attrname
)==0) ) {
265 if (name
) xmlFree(name
);
272 /** Find an attribute in a composite XML node.
273 * @param composite_node The composite node to search.
274 * @param attrname The name of the attribute node to find.
275 * @return The desired node, or NULL if none exists in `composite_node'.
276 * @bug Describe in more detail how a composite node differs from an
280 composite_find_attribute(DataNode composite_node
,
281 const char *attrname
)
286 while (composite_node
&& xmlIsBlankNode(composite_node
))
287 composite_node
= composite_node
->next
;
288 if (!composite_node
) return NULL
;
290 attr
= composite_node
->xmlChildrenNode
;
291 while (attr
!= NULL
) {
292 if (xmlIsBlankNode(attr
)) {
297 name
= xmlGetProp(attr
, "name");
298 if ( (name
!=NULL
) && (strcmp(name
, attrname
)==0) ) {
302 if (name
) xmlFree(name
);
309 /** The number of non-blank data nodes in an attribute node.
310 * @param attribute The attribute node to read from.
311 * @returns The number of non-blank data nodes in the node.
314 attribute_num_data(AttributeNode attribute
)
319 data
= attribute
? attribute
->xmlChildrenNode
: NULL
;
320 while (data
!= NULL
) {
321 if (xmlIsBlankNode(data
)) {
331 /** Get the first data node in an attribute node.
332 * @param attribute The attribute node to look through.
333 * @return The first non-black data node in the attribute node.
336 attribute_first_data(AttributeNode attribute
)
338 xmlNode
*data
= attribute
? attribute
->xmlChildrenNode
: NULL
;
339 while (data
&& xmlIsBlankNode(data
)) data
= data
->next
;
340 return (DataNode
) data
;
343 /** Get the next data node (sibling).
344 * @param data A data node to start from (e.g. just processed)
345 * @returns The next sibling data node.
348 data_next(DataNode data
)
353 while (data
&& xmlIsBlankNode(data
)) data
= data
->next
;
355 return (DataNode
) data
;
358 /** Get the type of a data node.
359 * @param data The data node.
360 * @return The type that the data node defines, or 0 on error. In case of
361 * error, an error message is displayed.
362 * @note This function does a number of strcmp calls, which may not be the
363 * fastest way to check if a node is of the expected type.
364 * @bug Make functions that check quickly if a node is of a specific type
365 * (but profile first).
368 data_type(DataNode data
)
372 name
= data
? (const char *)data
->name
: (const char *)"";
373 if (strcmp(name
, "composite")==0) {
374 return DATATYPE_COMPOSITE
;
375 } else if (strcmp(name
, "int")==0) {
377 } else if (strcmp(name
, "enum")==0) {
378 return DATATYPE_ENUM
;
379 } else if (strcmp(name
, "real")==0) {
380 return DATATYPE_REAL
;
381 } else if (strcmp(name
, "boolean")==0) {
382 return DATATYPE_BOOLEAN
;
383 } else if (strcmp(name
, "color")==0) {
384 return DATATYPE_COLOR
;
385 } else if (strcmp(name
, "point")==0) {
386 return DATATYPE_POINT
;
387 } else if (strcmp(name
, "rectangle")==0) {
388 return DATATYPE_RECTANGLE
;
389 } else if (strcmp(name
, "string")==0) {
390 return DATATYPE_STRING
;
391 } else if (strcmp(name
, "font")==0) {
392 return DATATYPE_FONT
;
395 message_error("Unknown type of DataNode");
399 /** Return the value of an integer-type data node.
400 * @param data The data node to read from.
401 * @returns The integer value found in the node. If the node is not an
402 * integer node, an error message is displayed and 0 is returned.
405 data_int(DataNode data
)
410 if (data_type(data
)!=DATATYPE_INT
) {
411 message_error("Taking int value of non-int node.");
415 val
= xmlGetProp(data
, "val");
417 if (val
) xmlFree(val
);
422 /** Return the value of an enum-type data node.
423 * @param data The data node to read from.
424 * @returns The enum value found in the node. If the node is not an
425 * enum node, an error message is displayed and 0 is returned.
427 int data_enum(DataNode data
)
432 if (data_type(data
)!=DATATYPE_ENUM
) {
433 message_error("Taking enum value of non-enum node.");
437 val
= xmlGetProp(data
, "val");
439 if (val
) xmlFree(val
);
444 /** Return the value of a real-type data node.
445 * @param data The data node to read from.
446 * @returns The real value found in the node. If the node is not a
447 * real-type node, an error message is displayed and 0.0 is returned.
450 data_real(DataNode data
)
455 if (data_type(data
)!=DATATYPE_REAL
) {
456 message_error("Taking real value of non-real node.");
460 val
= xmlGetProp(data
, "val");
461 res
= g_ascii_strtod(val
, NULL
);
462 if (val
) xmlFree(val
);
467 /** Return the value of a boolean-type data node.
468 * @param data The data node to read from.
469 * @returns The boolean value found in the node. If the node is not a
470 * boolean node, an error message is displayed and FALSE is returned.
473 data_boolean(DataNode data
)
478 if (data_type(data
)!=DATATYPE_BOOLEAN
) {
479 message_error("Taking boolean value of non-boolean node.");
483 val
= xmlGetProp(data
, "val");
485 if ((val
) && (strcmp(val
, "true")==0))
490 if (val
) xmlFree(val
);
495 /** Return the integer value of a hex digit.
496 * @param c A hex digit, one of 0-9, a-f or A-F.
497 * @returns The value of the digit, i.e. 0-15. If a non-gex digit is given
498 * an error message is displayed to the user, and 0 is returned.
503 if ((c
>='0') && (c
<='9'))
505 if ((c
>='a') && (c
<='f'))
507 if ((c
>='A') && (c
<='F'))
509 message_error("wrong hex digit %c", c
);
513 /** Return the value of a color-type data node.
514 * @param data The XML node to read from
515 * @param col A place to store the resulting RGB values. If the node does
516 * not contain a valid color value, an error message is displayed to the
517 * user, and `col' is unchanged.
518 * @note Could be cool to use RGBA data here, even if we can't display it yet.
521 data_color(DataNode data
, Color
*col
)
526 if (data_type(data
)!=DATATYPE_COLOR
) {
527 message_error("Taking color value of non-color node.");
531 val
= xmlGetProp(data
, "val");
536 if ((val
) && (strlen(val
)>=7)) {
537 r
= hex_digit(val
[1])*16 + hex_digit(val
[2]);
538 g
= hex_digit(val
[3])*16 + hex_digit(val
[4]);
539 b
= hex_digit(val
[5])*16 + hex_digit(val
[6]);
542 if (val
) xmlFree(val
);
544 col
->red
= ((float)r
)/255.0;
545 col
->green
= ((float)g
)/255.0;
546 col
->blue
= ((float)b
)/255.0;
549 /** Return the value of a point-type data node.
550 * @param data The XML node to read from
551 * @param point A place to store the resulting x, y values. If the node does
552 * not contain a valid point value, an error message is displayed to the
553 * user, and `point' is unchanged.
556 data_point(DataNode data
, Point
*point
)
562 if (data_type(data
)!=DATATYPE_POINT
) {
563 message_error(_("Taking point value of non-point node."));
567 val
= xmlGetProp(data
, "val");
568 point
->x
= g_ascii_strtod(val
, &str
);
570 if ((ax
> 1e9
) || ((ax
< 1e-9) && (ax
!= 0.0)) || isnan(ax
) || isinf(ax
)) {
571 /* there is no provision to keep values larger when saving,
572 * so do this 'reduction' silent */
574 g_warning(_("Incorrect x Point value \"%s\" %f; discarding it."),val
,point
->x
);
577 while ((*str
!= ',') && (*str
!=0))
581 g_warning(_("Error parsing point."));
585 point
->y
= g_ascii_strtod(str
+1, NULL
);
587 if ((ay
> 1e9
) || ((ay
< 1e-9) && (ay
!= 0.0)) || isnan(ay
) || isinf(ay
)) {
588 if (!(ay
< 1e-9)) /* don't bother with useless warnings (see above) */
589 g_warning(_("Incorrect y Point value \"%s\" %f; discarding it."),str
+1,point
->y
);
595 /** Return the value of a rectangle-type data node.
596 * @param data The data node to read from.
597 * @param rect A place to store the resulting values. If the node does
598 * not contain a valid rectangle value, an error message is displayed to the
599 * user, and `rect' is unchanged.
602 data_rectangle(DataNode data
, Rectangle
*rect
)
607 if (data_type(data
)!=DATATYPE_RECTANGLE
) {
608 message_error("Taking rectangle value of non-rectangle node.");
612 val
= xmlGetProp(data
, "val");
614 rect
->left
= g_ascii_strtod(val
, &str
);
616 while ((*str
!= ',') && (*str
!=0))
620 message_error("Error parsing rectangle.");
625 rect
->top
= g_ascii_strtod(str
+1, &str
);
627 while ((*str
!= ';') && (*str
!=0))
631 message_error("Error parsing rectangle.");
636 rect
->right
= g_ascii_strtod(str
+1, &str
);
638 while ((*str
!= ',') && (*str
!=0))
642 message_error("Error parsing rectangle.");
647 rect
->bottom
= g_ascii_strtod(str
+1, NULL
);
652 /** Return the value of a string-type data node.
653 * @param data The data node to read from.
654 * @returns The string value found in the node. If the node is not a
655 * string node, an error message is displayed and NULL is returned. The
656 * returned valuee should be freed after use.
657 * @note For historical reasons, strings in Dia XML are surrounded by ##.
660 data_string(DataNode data
)
663 gchar
*str
, *p
,*str2
;
666 if (data_type(data
)!=DATATYPE_STRING
) {
667 message_error("Taking string value of non-string node.");
671 val
= xmlGetProp(data
, "val");
672 if (val
!= NULL
) { /* Old kind of string. Left for backwards compatibility */
673 str
= g_malloc(4 * (sizeof(char)*(strlen(val
)+1))); /* extra room
681 /* Just skip this. \0 means nothing */
693 message_error("Error in string tag.");
702 str2
= g_strdup(str
); /* to remove the extra space */
707 if (data
->xmlChildrenNode
!=NULL
) {
708 p
= xmlNodeListGetString(data
->doc
, data
->xmlChildrenNode
, TRUE
);
711 message_error("Error in file, string not starting with #\n");
713 len
= strlen(p
)-1; /* Ignore first '#' */
715 str
= g_malloc(len
+1);
717 strncpy(str
, p
+1, len
);
718 str
[len
]=0; /* For safety */
720 str
[strlen(str
)-1] = 0; /* Remove last '#' */
728 /** Return the value of a filename-type data node.
729 * @param data The data node to read from.
730 * @return The filename value found in the node. If the node is not a
731 * filename node, an error message is displayed and NULL is returned.
732 * The resulting string is in the local filesystem's encoding rather than
733 * UTF-8, and should be freed after use.
734 * @bug data_string() can return NULL, what does g_filename_from_utf8 do then?
737 data_filename(DataNode data
)
739 char *utf8
= data_string(data
);
740 char *filename
= g_filename_from_utf8(utf8
, -1, NULL
, NULL
, NULL
);
745 /** Return the value of a font-type data node. This handles both the current
746 * format (family and style) and the old format (name).
747 * @param data The data node to read from.
748 * @return The font value found in the node. If the node is not a
749 * font node, an error message is displayed and NULL is returned. The
750 * resulting value should be freed after use.
753 data_font(DataNode data
)
758 if (data_type(data
)!=DATATYPE_FONT
) {
759 message_error("Taking font value of non-font node.");
763 family
= xmlGetProp(data
, "family");
764 /* always prefer the new format */
767 xmlChar
* style_name
= xmlGetProp(data
, "style");
768 style
= style_name
? atoi(style_name
) : 0;
770 font
= dia_font_new (family
, style
, 1.0);
771 if (family
) xmlFree(family
);
772 if (style_name
) xmlFree(style_name
);
774 /* Legacy format support */
775 char *name
= xmlGetProp(data
, "name");
776 font
= dia_font_new_from_legacy_name(name
);
782 /* ***** Saving XML **** */
784 /** Create a new attribute node.
785 * @param obj_node The object node to create the attribute node under.
786 * @param attrname The name of the attribute node.
787 * @return A new attribute node.
788 * @bug Should have utility functions that creates the node and sets
789 * the value based on type.
792 new_attribute(ObjectNode obj_node
,
793 const char *attrname
)
796 attr
= xmlNewChild(obj_node
, NULL
, "attribute", NULL
);
797 xmlSetProp(attr
, "name", attrname
);
802 /** Add an attribute node to a composite node.
803 * @param composite_node The composite node.
804 * @param attrname The name of the new attribute node.
805 * @return The attribute node added.
806 * @bug This does exactly the same as new_attribute.
809 composite_add_attribute(DataNode composite_node
,
810 const char *attrname
)
813 attr
= xmlNewChild(composite_node
, NULL
, "attribute", NULL
);
814 xmlSetProp(attr
, "name", attrname
);
819 /** Add integer data to an attribute node.
820 * @param attr The attribute node.
821 * @param data The value to set.
824 data_add_int(AttributeNode attr
, int data
)
827 char buffer
[20+1]; /* Enought for 64bit int + zero */
829 g_snprintf(buffer
, 20, "%d", data
);
831 data_node
= xmlNewChild(attr
, NULL
, "int", NULL
);
832 xmlSetProp(data_node
, "val", buffer
);
835 /** Add enum data to an attribute node.
836 * @param attr The attribute node.
837 * @param data The value to set.
840 data_add_enum(AttributeNode attr
, int data
)
843 char buffer
[20+1]; /* Enought for 64bit int + zero */
845 g_snprintf(buffer
, 20, "%d", data
);
847 data_node
= xmlNewChild(attr
, NULL
, "enum", NULL
);
848 xmlSetProp(data_node
, "val", buffer
);
851 /** Add real-typed data to an attribute node.
852 * @param attr The attribute node.
853 * @param data The value to set.
856 data_add_real(AttributeNode attr
, real data
)
859 char buffer
[G_ASCII_DTOSTR_BUF_SIZE
]; /* Large enought */
861 g_ascii_dtostr(buffer
, G_ASCII_DTOSTR_BUF_SIZE
, data
);
863 data_node
= xmlNewChild(attr
, NULL
, "real", NULL
);
864 xmlSetProp(data_node
, "val", buffer
);
867 /** Add boolean data to an attribute node.
868 * @param attr The attribute node.
869 * @param data The value to set.
872 data_add_boolean(AttributeNode attr
, int data
)
876 data_node
= xmlNewChild(attr
, NULL
, "boolean", NULL
);
878 xmlSetProp(data_node
, "val", "true");
880 xmlSetProp(data_node
, "val", "false");
883 /** Convert a floating-point value to hexadecimal.
884 * @param x The floating point value.
885 * @param str A string to place the result in.
886 * @note Currently only works for 0 <= x <= 255 and will silently cap the value
887 * to those limits. Also expects str to have at least two bytes allocated,
888 * and doesn't null-terminate it. This works well for converting a color
889 * value, but is pretty much useless for other values.
892 convert_to_hex(float x
, char *str
)
894 static const char hex_digit
[] = "0123456789abcdef";
903 str
[0] = hex_digit
[val
/16];
904 str
[1] = hex_digit
[val
%16];
907 /** Add color data to an attribute node.
908 * @param attr The attribute node.
909 * @param col The value to set.
912 data_add_color(AttributeNode attr
, const Color
*col
)
918 convert_to_hex(col
->red
, &buffer
[1]);
919 convert_to_hex(col
->green
, &buffer
[3]);
920 convert_to_hex(col
->blue
, &buffer
[5]);
923 data_node
= xmlNewChild(attr
, NULL
, "color", NULL
);
924 xmlSetProp(data_node
, "val", buffer
);
927 /** Add point data to an attribute node.
928 * @param attr The attribute node.
929 * @param point The value to set.
932 data_add_point(AttributeNode attr
, const Point
*point
)
936 gchar px_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
937 gchar py_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
939 g_ascii_formatd(px_buf
, sizeof(px_buf
), "%g", point
->x
);
940 g_ascii_formatd(py_buf
, sizeof(py_buf
), "%g", point
->y
);
941 buffer
= g_strconcat(px_buf
, ",", py_buf
, NULL
);
943 data_node
= xmlNewChild(attr
, NULL
, "point", NULL
);
944 xmlSetProp(data_node
, "val", buffer
);
948 /** Add rectangle data to an attribute node.
949 * @param attr The attribute node.
950 * @param rect The value to set.
953 data_add_rectangle(AttributeNode attr
, const Rectangle
*rect
)
957 gchar rl_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
958 gchar rr_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
959 gchar rt_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
960 gchar rb_buf
[G_ASCII_DTOSTR_BUF_SIZE
];
962 g_ascii_formatd(rl_buf
, sizeof(rl_buf
), "%g", rect
->left
);
963 g_ascii_formatd(rr_buf
, sizeof(rr_buf
), "%g", rect
->right
);
964 g_ascii_formatd(rt_buf
, sizeof(rt_buf
), "%g", rect
->top
);
965 g_ascii_formatd(rb_buf
, sizeof(rb_buf
), "%g", rect
->bottom
);
967 buffer
= g_strconcat(rl_buf
, ",", rt_buf
, ";", rr_buf
, ",", rb_buf
, NULL
);
969 data_node
= xmlNewChild(attr
, NULL
, "rectangle", NULL
);
970 xmlSetProp(data_node
, "val", buffer
);
975 /** Add string data to an attribute node.
976 * @param attr The attribute node.
977 * @param str The value to set.
980 data_add_string(AttributeNode attr
, const char *str
)
983 xmlChar
*escaped_str
;
984 xmlChar
*sharped_str
;
987 data_node
= xmlNewChild(attr
, NULL
, "string", "##");
991 escaped_str
= xmlEncodeEntitiesReentrant(attr
->doc
,str
);
993 sharped_str
= g_strconcat("#", escaped_str
, "#", NULL
);
995 xmlFree(escaped_str
);
997 data_node
= xmlNewChild(attr
, NULL
, "string", sharped_str
);
1002 /** Add filename data to an attribute node.
1003 * @param attr The attribute node.
1004 * @param filename The value to set. This should be n the local filesystem
1005 * encoding, not utf-8.
1008 data_add_filename(DataNode data
, const char *str
)
1010 char *utf8
= g_filename_to_utf8(str
, -1, NULL
, NULL
, NULL
);
1012 data_add_string(data
, utf8
);
1017 /** Add font data to an attribute node.
1018 * @param attr The attribute node.
1019 * @param font The value to set.
1022 data_add_font(AttributeNode attr
, const DiaFont
*font
)
1026 char buffer
[20+1]; /* Enought for 64bit int + zero */
1028 data_node
= xmlNewChild(attr
, NULL
, "font", NULL
);
1029 style
= dia_font_get_style (font
);
1030 xmlSetProp(data_node
, "family", dia_font_get_family(font
));
1031 g_snprintf(buffer
, 20, "%d", dia_font_get_style(font
));
1033 xmlSetProp(data_node
, "style", buffer
);
1034 /* Legacy support: don't crash older Dia on missing 'name' attribute */
1035 xmlSetProp(data_node
, "name", dia_font_get_legacy_name(font
));
1038 /** Add a new composite node to an attribute node.
1039 * @param attr The attribute node to add to.
1040 * @param type The type of the new node.
1041 * @returns The new child of `attr'.
1044 data_add_composite(AttributeNode attr
, const char *type
)
1046 /* type can be NULL */
1049 data_node
= xmlNewChild(attr
, NULL
, "composite", NULL
);
1051 xmlSetProp(data_node
, "type", type
);
1056 /** Emit a warning to the user that having UTF-8 as local charset doesn't.
1059 warn_about_broken_libxml1(void)
1061 message_warning(_("Your local character set is UTF-8. Because of issues"
1062 " with libxml1 and the support of files generated by"
1063 " previous versions of dia, you will encounter "
1064 " problems. Please report to dia-list@gnome.org if you"
1065 " see this message."));
1068 #define BUFSIZE 2048
1069 #define OVERRUN_SAFETY 16
1072 int pretty_formated_xml
= TRUE
;
1074 /** Save an XML document to a file.
1075 * @param filename The file to save to.
1076 * @param cur The XML document structure.
1077 * @return The return value of xmlSaveFormatFileEnc.
1078 * @bug Get the proper defn of the return value from libxml2.
1081 xmlDiaSaveFile(const char *filename
,
1086 if (pretty_formated_xml
)
1087 old
= xmlKeepBlanksDefault (0);
1088 ret
= xmlSaveFormatFileEnc (filename
,cur
, "UTF-8", pretty_formated_xml
? 1 : 0);
1089 if (pretty_formated_xml
)
1090 xmlKeepBlanksDefault (old
);