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