1 #include "csf.h"
2 #include "csfimpl.h"
3 #include <assert.h>
4 #include <string.h>
5
6 /* make block empty
7 */
InitBlock(ATTR_CNTRL_BLOCK * b)8 static void InitBlock(
9 ATTR_CNTRL_BLOCK *b) /* write-only */
10 {
11 int i;
12 for (i = 0 ; i < NR_ATTR_IN_BLOCK; i++)
13 {
14 b->attrs[i].attrId = END_OF_ATTRS;
15 b->attrs[i].attrSize = 0;
16 b->attrs[i].attrOffset = 0;
17 }
18 b->next = 0;
19 }
20
21 /* replace an attribute (LIBRARY_INTERNAL)
22 *
23 */
CsfUpdateAttribute(MAP * m,CSF_ATTR_ID id,size_t itemSize,size_t nitems,void * attr)24 CSF_ATTR_ID CsfUpdateAttribute(
25 MAP *m, /* map handle */
26 CSF_ATTR_ID id, /* attribute identification */
27 size_t itemSize, /* size of each attribute element.
28 * 1 or sizeof(char) in case of a
29 * string
30 */
31 size_t nitems, /* number of attribute elements or
32 * strlen+1 in case of a variable character
33 * string field. Don't forget to pad a
34 * non-variable field with '\0'!
35 */
36 void *attr) /* buffer containing attribute */
37 {
38 PRECOND(CsfValidSize(itemSize));
39 if (CsfAttributeSize(m,id))
40 if (! MdelAttribute(m,id))
41 return 0;
42 return CsfPutAttribute(m,id,itemSize,nitems, attr);
43 }
44
45
46
47 /* write an attribute to a map (LIBRARY_INTERNAL)
48 * MputAttribute writes exactly the number of bytes specified
49 * by the size argument starting at the address of argument
50 * attr. Which means that you can't simply pass a structure or an
51 * array of structures as argument attr, due to the alignment
52 * of fields within a structure and internal swapping. You can
53 * only pass an array of elementary types (UINT1, REAL4, etc.)
54 * or character string.
55 * If one wants to refresh an attribute, one should first
56 * call MdelAttribute to delete the attribute and then use
57 * MputAttribute to write the new value.
58 * returns argument id or 0 in case of error.
59 *
60 * Merrno
61 * ATTRDUPL
62 * NOACCESS
63 * WRITE_ERROR
64 */
CsfPutAttribute(MAP * m,CSF_ATTR_ID id,size_t itemSize,size_t nitems,void * attr)65 CSF_ATTR_ID CsfPutAttribute(
66 MAP *m, /* map handle */
67 CSF_ATTR_ID id, /* attribute identification */
68 size_t itemSize, /* size of each attribute element.
69 * 1 or sizeof(char) in case of a
70 * string
71 */
72 size_t nitems, /* number of attribute elements or
73 * strlen+1 in case of a variable character
74 * string field. Don't forget to pad a
75 * non-variable field with '\0'!
76 */
77 void *attr) /* buffer containing attribute */
78 {
79 size_t size = nitems * itemSize;
80
81 PRECOND(CsfValidSize(itemSize));
82 PRECOND(size > 0);
83
84 if (CsfSeekAttrSpace(m,id,size) == 0)
85 goto error;
86
87 if (m->write(attr, itemSize, nitems, m->fp) != nitems)
88 {
89 M_ERROR(WRITE_ERROR);
90 goto error;
91 }
92 return(id); /* success */
93 error: return(0); /* failure */
94 }
95
96 /* Seek to space for attribute (LIBRARY_INTERNAL)
97 * CsfSeekAttrSpace seeks to the a point in the file where
98 * the attribute must be stored and update the attribute control
99 * blocks accordingly.
100 * Writing can still fail since there is no check if that space is really
101 * available on the device. After this call returns the file is already
102 * sought to the point the functions returns.
103 * returns the file position or 0 in case of error.
104 *
105 * Merrno
106 * ATTRDUPL
107 * NOACCESS
108 * WRITE_ERROR
109 */
CsfSeekAttrSpace(MAP * m,CSF_ATTR_ID id,size_t size)110 CSF_FADDR32 CsfSeekAttrSpace(
111 MAP *m, /* map handle */
112 CSF_ATTR_ID id, /* attribute identification only for check if available */
113 size_t size) /* size to be sought to */
114 {
115 ATTR_CNTRL_BLOCK b;
116 CSF_FADDR32 currBlockPos, prevBlockPos=USED_UNINIT_ZERO, newPos, endBlock, resultPos=0;
117 int noPosFound;
118 int i;
119
120 memset(&b, 0, sizeof(b));
121
122 if (MattributeAvail(m ,id))
123 {
124 M_ERROR(ATTRDUPL);
125 goto error;
126 }
127
128 if (! WRITE_ENABLE(m))
129 {
130 M_ERROR(NOACCESS);
131 goto error;
132 }
133
134 currBlockPos = m->main.attrTable;
135 noPosFound = 1;
136 while (noPosFound)
137 {
138 if (currBlockPos == 0)
139 {
140 if (m->main.attrTable == 0)
141 { /* FIRST BLOCK */
142 newPos =(CSF_FADDR32)(( (CSF_FADDR)(m->raster.nrRows)*
143 (CSF_FADDR)(m->raster.nrCols)*
144 (CSF_FADDR)(CELLSIZE(RgetCellRepr(m))))
145 + ADDR_DATA);
146 m->main.attrTable = newPos;
147 }
148 else
149 { /* NEW/NEXT BLOCK */
150 newPos = b.attrs[LAST_ATTR_IN_BLOCK].attrOffset
151 +
152 b.attrs[LAST_ATTR_IN_BLOCK].attrSize;
153 b.next = newPos;
154 if (CsfWriteAttrBlock(m, prevBlockPos, &b))
155 {
156 M_ERROR(WRITE_ERROR);
157 /*resultPos = 0;*/
158 }
159 }
160 InitBlock(&b);
161 b.attrs[0].attrOffset =
162 newPos + SIZE_OF_ATTR_CNTRL_BLOCK;
163 currBlockPos = newPos;
164 noPosFound = 0;
165 }
166 else
167 CsfReadAttrBlock(m, currBlockPos, &b);
168 i = 0; /* this is also the right index if a new block
169 is added ! */
170 while (noPosFound && i < NR_ATTR_IN_BLOCK)
171 switch (b.attrs[i].attrId)
172 {
173 case END_OF_ATTRS:
174 POSTCOND(i >= 1);
175 /* i >= 1 , no block otherwise */
176 b.attrs[i].attrOffset =
177 b.attrs[i-1].attrOffset +
178 b.attrs[i-1].attrSize;
179 noPosFound = 0;
180 break;
181 case ATTR_NOT_USED:
182 /*
183 KDJ: Commented out because control flow will never
184 reach it. See while condition above.
185 Added assert to document/verify this.
186 if (i == NR_ATTR_IN_BLOCK)
187 endBlock = b.next;
188 else
189 */
190 assert(i+1 < NR_ATTR_IN_BLOCK);
191 endBlock = b.attrs[i+1].attrOffset;
192 if ( (size_t)( endBlock - b.attrs[i].attrOffset) >= size)
193 /* this position can
194 hold the attr */
195 noPosFound = 0;
196 else
197 i++;
198 break;
199 default:
200 i++;
201 } /* switch */
202 /* if (b.next == 0)
203 ? When did I change this CW
204 remember this block position since it may be have
205 to rewritten
206 */
207 prevBlockPos = currBlockPos;
208 if (noPosFound)
209 currBlockPos = b.next;
210 } /* while */
211
212 b.attrs[i].attrSize = (UINT4)size;
213 b.attrs[i].attrId = id;
214 resultPos = b.attrs[i].attrOffset;
215
216 if (CsfWriteAttrBlock(m, currBlockPos, &b))
217 {
218 M_ERROR(WRITE_ERROR);
219 resultPos = 0;
220 }
221 if( csf_fseek(m->fp, resultPos, SEEK_SET) != 0 ) /* fsetpos() is better */
222 {
223 M_ERROR(WRITE_ERROR);
224 resultPos = 0;
225 }
226 error: return resultPos;
227 } /* CsfSeekAttrSpace */
228