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