1 /**
2 * Copyright 1981-2016 ECMWF.
3 *
4 * This software is licensed under the terms of the Apache Licence
5 * Version 2.0 which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6 *
7 * In applying this licence, ECMWF does not waive the privileges and immunities
8 * granted to it by virtue of its status as an intergovernmental organisation
9 * nor does it submit to any jurisdiction.
10 */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
16 
17 #include "bitmap.h"
18 #include "common/fortint.h"
19 
20 #define BUFFLEN 50000
21 #define NOTSET -1
22 
MAKEMAP(char * filename,fortint * n,fortint * m,char ** mybitmap,fortint filenameLength)23 fortint MAKEMAP(
24   char * filename,
25   fortint *n,
26   fortint *m,
27   char ** mybitmap,
28   fortint filenameLength) {
29 /*
30 // Builds a bitmap in memory from the definition in a file.
31 //
32 // Called from FORTRAN:
33 //
34 // STATUS = MAKEMAP(FILENAME,N,M,BITMAP)
35 //
36 // where:
37 //
38 // FILENAME is a FORTRAN CHARACTER variable containing the file name.
39 //
40 // Returns:
41 //
42 // N is the number of rows in the bitmap.
43 // M is the number of columns in the bitmap.
44 // BITMAP is the binary map expanded in memory.
45 //
46 // STATUS = 0 if the processing is successful.
47 //
48 */
49 FILE * in;
50 char * bitmap;
51 char buffer[BUFFLEN];
52 int rowCount, columnCount;
53 int start, finish, defaultValue, size, i;
54 int firstColumn, lastColumn, rowNumber, columnNumber;
55 char defaultValueSetting, delimiter = '\1', previousDelimiter = '\0';
56 static int oldRow = NOTSET;
57 char * fileName, *p;
58 
59 /*
60 // Open and read the file containing the bitmap definition.
61 */
62   fileName = (char *) malloc(filenameLength+1);
63   if( fileName == NULL ) {
64     perror("MAKEMAP: malloc error (fileName)");
65     exit(1);
66   }
67   strncpy(fileName,filename,filenameLength);
68   fileName[filenameLength] = '\0';
69   p = fileName + filenameLength - 1;
70   while ( *p == ' ' ) *(p--) = '\0';
71 
72   in = fopen(fileName,"r");
73   if( in == NULL ) {
74     printf("MAKEMAP: Problem opening bitmap file: %s\n",fileName);
75     perror("MAKEMAP: File open error");
76     return 1;
77   }
78   free(fileName);
79 
80   fread(buffer, 1, BUFFLEN, in);
81   if( ! feof(in) ) {
82     printf("MAKEMAP: Internal buffer size too small = %d bytes\n", BUFFLEN);
83     return 2;
84   }
85 
86 /*
87 // Check for "SPEC,SIZE="
88 */
89   if( strncmp(buffer,"SPEC",4) != 0 ) {
90     printf("MAKEMAP: Specification does not start with SPEC\n");
91     return 3;
92   }
93 
94   start = 5;
95 
96   if( strncmp((buffer+start),"SIZE=",5) != 0 ) {
97     printf("MAKEMAP: In specification, SPEC not followed by SIZE=\n");
98     return 4;
99   }
100 
101 /*
102 // Get count of rows and columns
103 */
104   start = 1 + findCharacter(buffer,BUFFLEN,start,'=');
105   if( start == 0 ) {
106     printf("MAKEMAP: '=' missing in SIZE specification\n");
107     return 5;
108   }
109 
110   finish = findCharacter(buffer,BUFFLEN,start,':');
111   if( finish == 0 ) {
112     printf("MAKEMAP: ':' missing in SIZE specification\n");
113     return 6;
114   }
115   rowCount = findNumber(buffer,BUFFLEN,start,&finish,':');
116   *n = rowCount;
117 
118   start = 1 + finish;
119   finish = findCharacter(buffer,BUFFLEN,start,',');
120   if( finish == 0 ) {
121     printf("MAKEMAP: ',' missing after SIZE specification\n");
122     return 7;
123   }
124   columnCount = findNumber(buffer,BUFFLEN,start,&finish,',');
125   *m = columnCount;
126 
127 /*
128 // Find default VALUE (OFF/ON)
129 */
130   start = 1 + finish;
131   if( strncmp((buffer+start),"VALUES=",7) != 0 ) {
132     printf("MAKEMAP: In specification, SIZE not followed by VALUES=\n");
133     return 8;
134   }
135   start += 7;
136   if( strncmp((buffer+start),"ON",2) == 0 ) {
137     defaultValueSetting = 0xff;
138     defaultValue = 1;
139   }
140   else {
141     defaultValueSetting = 0;
142     defaultValue = 0;
143   }
144 
145 /*
146 // Claim memory for bitmap and fill it with default setting
147 */
148    size = (rowCount*columnCount+7)/8;
149    bitmap = (char *) malloc(size);
150    if( bitmap == NULL ) {
151      perror("MAKEMAP: malloc error (bitmap)");
152      exit(1);
153    }
154    *mybitmap = bitmap;
155    for( i = 0; i < size; i++ )
156      bitmap[i] = defaultValueSetting;
157 
158 /*
159 // Fill in the bits
160 */
161   start = findCharacter(buffer,BUFFLEN,start,'P');
162   if( start == 0 ) {
163     printf("MAKEMAP: '=' POINTS missing in specification\n");
164     return 9;
165   }
166   if( strncmp((buffer+start),"POINTS=",7) != 0 ) {
167     printf("MAKEMAP: In specification, VALUES= not followed by POINTS=\n");
168     return 10;
169   }
170 
171   finish = start + 6;
172 
173 /*
174 // Work through POINTS specification
175 */
176 
177   do {
178     previousDelimiter = delimiter;
179     start = 1 + finish;
180     delimiter = findDelimiter(buffer,BUFFLEN,start);
181     if( delimiter == 0 ) {
182       fclose(in);
183       return 0;
184     }
185 
186     switch( delimiter ) {
187 
188       case '-':                              /* eg 03-08 */
189         firstColumn = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
190         start = 1 + finish;
191         delimiter = findDelimiter(buffer,BUFFLEN,start);
192         lastColumn = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
193         for(columnNumber=firstColumn; columnNumber<=lastColumn; columnNumber++)
194           setBit(bitmap,defaultValue,columnCount,rowNumber,columnNumber);
195         break;
196 
197       case '/':                              /* eg 03/04 */
198         columnNumber = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
199         setBit(bitmap,defaultValue,columnCount,rowNumber,columnNumber);
200         break;
201 
202       case '\n':                             /* eg 03\n */
203         if( previousDelimiter == ',' ) {
204           finish++;
205           break;
206         }
207         if( previousDelimiter == '\n' ) {
208           if( (oldRow < rowCount) && (oldRow != NOTSET) ) {
209             int loop;
210 
211             for( loop = (oldRow+1); loop <= rowCount; loop++ )
212               copyRow(bitmap, columnCount, oldRow, loop, defaultValue);
213           }
214           oldRow = rowCount;
215           fclose(in);
216           return 0;
217         }
218 
219       case ',':                              /* eg 03,  */
220         columnNumber = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
221         if( columnNumber != 0 )
222           setBit(bitmap,defaultValue,columnCount,rowNumber,columnNumber);
223         break;
224 
225       case ':':                              /* eg 01:  */
226         rowNumber = findNumber(buffer,BUFFLEN,start,&finish,delimiter);
227         if( (oldRow < rowNumber) && (oldRow != NOTSET) ) {
228           int loop;
229 
230           for( loop = (oldRow+1); loop < rowNumber; loop++ )
231             copyRow(bitmap, columnCount, oldRow, loop, defaultValue);
232         }
233         oldRow = rowNumber;
234         break;
235 
236       default:
237         break;
238 
239     }
240 
241   } while( 1 );
242 
243 }
244 
findNumber(char * buffer,int length,int start,int * finish,char delimiter)245 int findNumber(char * buffer,int length,int start,int * finish,char delimiter) {
246 char number[20];
247 int end;
248 
249   end = findCharacter(buffer,length,start,delimiter);
250   *finish = end;
251   strncpy(number,(buffer+start),(end-start));
252   number[(end-start)] = '\0';
253   return atoi(number);
254 
255 }
256 
findDelimiter(char * buffer,int length,int point)257 char findDelimiter(char * buffer, int length, int point) {
258 int i, j;
259 char delimiter[5] = {'-','/',',','\n',':'};
260 
261   for( i = point; i < length; i++ )
262     for( j = 0; j < 5; j++ )
263       if( buffer[i] == delimiter[j] ) return buffer[i];
264 
265   return (char) 0;
266 }
267 
findCharacter(char * buffer,int length,int point,char character)268 int findCharacter(char * buffer, int length, int point, char character) {
269 int i;
270 
271   for( i = point; i < length; i++ )
272     if( buffer[i] == character ) return i;
273 
274   return 0;
275 }
276 
setBit(char * buffer,int value,int columnCount,int row,int column)277 void setBit(char * buffer, int value, int columnCount, int row, int column) {
278 int bitNumber, byte, bit;
279 char mask[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
280 
281   bitNumber = (row - 1)*columnCount + (column - 1);
282   byte = bitNumber / 8;
283   bit  = bitNumber % 8;
284 
285   if( value == 1 )
286     buffer[byte] &= (char) ~mask[bit];
287   else
288     buffer[byte] |= (char) mask[bit];
289 
290   return;
291 }
292 
copyRow(char * buffer,int columnCount,int oldRow,int newRow,int value)293 void copyRow(char * buffer, int columnCount, int oldRow, int newRow, int value) {
294 int oldByte, oldBit, newByte, newBit, bitNumber;
295 char oldValue, newValue, mask;
296 int loop;
297 
298   for( loop = 0; loop < columnCount; loop++ ) {
299     bitNumber = (oldRow - 1)*columnCount + loop;
300     oldByte = bitNumber / 8;
301     oldBit  = bitNumber % 8;
302     oldValue = (char) ((buffer[oldByte] >> (7-oldBit)) & 0x01);
303 
304     bitNumber = (newRow - 1)*columnCount + loop;
305     newByte = bitNumber / 8;
306     newBit  = bitNumber % 8;
307 
308     newValue = oldValue << (7-newBit);
309     if( value == 1 ) {
310       mask = 1 << (7-newBit);
311       buffer[newByte] &= (char) ~mask;
312       buffer[newByte] |= (char) newValue;
313     }
314     else
315       buffer[newByte] |= newValue;
316   }
317 
318 }
319 
320