1 #include "csf.h"
2 #include "csfimpl.h"
3 
4 /* get the number of entries with a negative
5  * number for a type 1 legend
6  */
NrLegendEntries(MAP * m)7 static int NrLegendEntries(MAP *m)
8 {
9 	int size = (int)CsfAttributeSize(m, ATTR_ID_LEGEND_V2);
10 	if (size == 0)
11 	{
12 		if ( (size = -(int)CsfAttributeSize(m, ATTR_ID_LEGEND_V1)) != 0 )
13 			size -= CSF_LEGEND_ENTRY_SIZE;
14 	}
15 	return size/CSF_LEGEND_ENTRY_SIZE;
16 }
CmpEntries(CSF_LEGEND * e1,CSF_LEGEND * e2)17 static int CmpEntries(
18 	CSF_LEGEND *e1,
19 	CSF_LEGEND *e2)
20 {
21 	return (int) ((e1->nr) - (e2->nr));
22 }
23 
SortEntries(CSF_LEGEND * l,size_t nr)24 static void SortEntries(
25 	CSF_LEGEND *l, /* version 2 legend */
26 	size_t        nr) /* nr entries + name */
27 {
28 #ifndef USE_IN_PCR
29 	typedef int (*QSORT_CMP)(const void *e1, const void *e2);
30 #endif
31 	PRECOND(nr >= 1);
32 	qsort(l+1, (size_t)nr-1, sizeof(CSF_LEGEND), (QSORT_CMP)CmpEntries);
33 }
34 
35 /* get the number of legend entries
36  * MgetNrLegendEntries tries to find a version 2 or version 1
37  * legend. The return number can be used to allocate the appropriate
38  * array for legend.
39  * returns the number of entries in a legend plus 1 (for the name of the legend)
40  * or 0 if there is no legend
41  */
MgetNrLegendEntries(MAP * m)42 size_t MgetNrLegendEntries(
43 	MAP *m) /* the map pointer */
44 {
45 	return (size_t)ABS(NrLegendEntries(m));
46 }
47 
48 /* read a legend
49  * MgetLegend reads a version 2 and 1 legend.
50  * Version 1 legend are converted to version 2: the first
51  * array entry holds an empty string in the description field.
52  * returns
53  * 0 if no legend is available or in case of an error,
54  * nonzero otherwise
55  */
MgetLegend(MAP * m,CSF_LEGEND * l)56 int MgetLegend(
57 	MAP *m,        /* Map handle */
58 	CSF_LEGEND *l) /* array large enough to hold name and all entries,
59 	                * the entries are sorted
60 	                * struct CSF_LEGEND is typedef'ed in csfattr.h
61 	                */
62 {
63 	CSF_ATTR_ID id = NrLegendEntries(m) < 0 ? ATTR_ID_LEGEND_V1 : ATTR_ID_LEGEND_V2;
64 	size_t size;
65 	CSF_FADDR pos = CsfGetAttrPosSize(m, id, &size);
66 	size_t i,nr,start = 0;
67         if (pos == 0)
68         	return 0;
69         if( csf_fseek(m->fp, pos, SEEK_SET) != 0 )
70                 return 0;
71         if (id == ATTR_ID_LEGEND_V1)
72         {
73         	/* empty name */
74         	l[0].nr       = 0;
75         	l[0].descr[0] = '\0';
76         	start = 1; /* don't read in name */
77         }
78 	nr = size/CSF_LEGEND_ENTRY_SIZE;
79 	for(i = start; i < nr+start; i++)
80 	{
81 		m->read(&(l[i].nr), sizeof(INT4), (size_t)1, m->fp);
82 		m->read(l[i].descr, sizeof(char), (size_t)CSF_LEGEND_DESCR_SIZE, m->fp);
83 	}
84 	SortEntries(l, nr+start);
85 	return 1;
86 }
87 
88 /* write a legend
89  * MputLegend writes a (version 2) legend to a map replacing
90  * the old one if existent.
91  * See  csfattr.h for the legend structure.
92  *
93  * returns
94  * 0 in case of an error,
95  * nonzero otherwise
96  *
97  * Merrno
98  * NOACCESS
99  * WRITE_ERROR
100  */
MputLegend(MAP * m,CSF_LEGEND * l,size_t nrEntries)101 int MputLegend(
102 	MAP *m,        /* Map handle */
103 	CSF_LEGEND *l, /* read-write, array with name and entries, the entries
104 	                * are sorted before writing to the file.
105 	                * Strings are padded with zeros.
106 	                */
107 	size_t nrEntries) /* number of array elements. That is name plus real legend entries */
108 {
109 	int i = NrLegendEntries(m);
110 	CSF_ATTR_ID id = i < 0 ? ATTR_ID_LEGEND_V1 : ATTR_ID_LEGEND_V2;
111 	if (i)
112 		if (! MdelAttribute(m, id))
113 			return 0;
114 	SortEntries(l, nrEntries);
115 	if (CsfSeekAttrSpace(m, ATTR_ID_LEGEND_V2, (size_t)(nrEntries*CSF_LEGEND_ENTRY_SIZE)) == 0)
116 			return 0;
117 	for(i = 0; i < (int)nrEntries; i++)
118 	{
119 	     if(
120 		m->write(&(l[i].nr), sizeof(INT4), (size_t)1, m->fp) != 1 ||
121 		m->write(
122 		 CsfStringPad(l[i].descr,(size_t)CSF_LEGEND_DESCR_SIZE),
123 		 sizeof(char), (size_t)CSF_LEGEND_DESCR_SIZE, m->fp)
124 		 != CSF_LEGEND_DESCR_SIZE )
125 		 {
126 		 	M_ERROR(WRITE_ERROR);
127 		 	return 0;
128 		 }
129 	}
130 	return 1;
131 }
132