1 /******************************************************************************
2  *   Copyright (C) 2009-2015, International Business Machines
3  *   Corporation and others.  All Rights Reserved.
4  *******************************************************************************
5  */
6 
7 #include "flagparser.h"
8 #include "filestrm.h"
9 #include "cstring.h"
10 #include "cmemory.h"
11 
12 #define DEFAULT_BUFFER_SIZE 512
13 
14 static int32_t currentBufferSize = DEFAULT_BUFFER_SIZE;
15 
16 static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status);
17 static int32_t getFlagOffset(const char *buffer, int32_t bufferSize);
18 
19 /*
20  * Opens the given fileName and reads in the information storing the data in flagBuffer.
21  */
22 U_CAPI int32_t U_EXPORT2
parseFlagsFile(const char * fileName,char ** flagBuffer,int32_t flagBufferSize,const char ** flagNames,int32_t numOfFlags,UErrorCode * status)23 parseFlagsFile(const char *fileName, char **flagBuffer, int32_t flagBufferSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status) {
24     char* buffer = NULL;
25     char* tmpFlagBuffer = NULL;
26     UBool allocateMoreSpace = FALSE;
27     int32_t idx, i;
28     int32_t result = 0;
29 
30     FileStream *f = T_FileStream_open(fileName, "r");
31     if (f == NULL) {
32         *status = U_FILE_ACCESS_ERROR;
33         goto parseFlagsFile_cleanup;
34     }
35 
36     buffer = uprv_malloc(sizeof(char) * currentBufferSize);
37     tmpFlagBuffer = uprv_malloc(sizeof(char) * flagBufferSize);
38 
39     if (buffer == NULL || tmpFlagBuffer == NULL) {
40         *status = U_MEMORY_ALLOCATION_ERROR;
41         goto parseFlagsFile_cleanup;
42     }
43 
44     do {
45         if (allocateMoreSpace) {
46             allocateMoreSpace = FALSE;
47             currentBufferSize *= 2;
48             uprv_free(buffer);
49             buffer = uprv_malloc(sizeof(char) * currentBufferSize);
50             if (buffer == NULL) {
51                 *status = U_MEMORY_ALLOCATION_ERROR;
52                 goto parseFlagsFile_cleanup;
53             }
54         }
55         for (i = 0; i < numOfFlags;) {
56             if (T_FileStream_readLine(f, buffer, currentBufferSize) == NULL) {
57                 /* End of file reached. */
58                 break;
59             }
60             if (buffer[0] == '#') {
61                 continue;
62             }
63 
64             if (uprv_strlen(buffer) == (currentBufferSize - 1) && buffer[currentBufferSize-2] != '\n') {
65                 /* Allocate more space for buffer if it didnot read the entrire line */
66                 allocateMoreSpace = TRUE;
67                 T_FileStream_rewind(f);
68                 break;
69             } else {
70                 idx = extractFlag(buffer, currentBufferSize, tmpFlagBuffer, flagBufferSize, flagNames, numOfFlags, status);
71                 if (U_FAILURE(*status)) {
72                     if (*status == U_BUFFER_OVERFLOW_ERROR) {
73                         result = currentBufferSize;
74                     } else {
75                         result = -1;
76                     }
77                     break;
78                 } else {
79                     if (flagNames != NULL) {
80                         if (idx >= 0) {
81                             uprv_strcpy(flagBuffer[idx], tmpFlagBuffer);
82                         } else {
83                             /* No match found.  Skip it. */
84                             continue;
85                         }
86                     } else {
87                         uprv_strcpy(flagBuffer[i++], tmpFlagBuffer);
88                     }
89                 }
90             }
91         }
92     } while (allocateMoreSpace && U_SUCCESS(*status));
93 
94 parseFlagsFile_cleanup:
95     uprv_free(tmpFlagBuffer);
96     uprv_free(buffer);
97 
98     T_FileStream_close(f);
99 
100     if (U_FAILURE(*status)) {
101         return -1;
102     }
103 
104     if (U_SUCCESS(*status) && result == 0) {
105         currentBufferSize = DEFAULT_BUFFER_SIZE;
106     }
107 
108     return result;
109 }
110 
111 
112 /*
113  * Extract the setting after the '=' and store it in flag excluding the newline character.
114  */
extractFlag(char * buffer,int32_t bufferSize,char * flag,int32_t flagSize,const char ** flagNames,int32_t numOfFlags,UErrorCode * status)115 static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char **flagNames, int32_t numOfFlags, UErrorCode *status) {
116     int32_t i, idx = -1;
117     char *pBuffer;
118     int32_t offset=0;
119     UBool bufferWritten = FALSE;
120 
121     if (buffer[0] != 0) {
122         /* Get the offset (i.e. position after the '=') */
123         offset = getFlagOffset(buffer, bufferSize);
124         pBuffer = buffer+offset;
125         for(i = 0;;i++) {
126             if (i >= flagSize) {
127                 *status = U_BUFFER_OVERFLOW_ERROR;
128                 return -1;
129             }
130             if (pBuffer[i+1] == 0) {
131                 /* Indicates a new line character. End here. */
132                 flag[i] = 0;
133                 break;
134             }
135 
136             flag[i] = pBuffer[i];
137             if (i == 0) {
138                 bufferWritten = TRUE;
139             }
140         }
141     }
142 
143     if (!bufferWritten) {
144         flag[0] = 0;
145     }
146 
147     if (flagNames != NULL && offset>0) {
148         offset--;  /* Move offset back 1 because of '='*/
149         for (i = 0; i < numOfFlags; i++) {
150             if (uprv_strncmp(buffer, flagNames[i], offset) == 0) {
151                 idx = i;
152                 break;
153             }
154         }
155     }
156 
157     return idx;
158 }
159 
160 /*
161  * Get the position after the '=' character.
162  */
getFlagOffset(const char * buffer,int32_t bufferSize)163 static int32_t getFlagOffset(const char *buffer, int32_t bufferSize) {
164     int32_t offset = 0;
165 
166     for (offset = 0; offset < bufferSize;offset++) {
167         if (buffer[offset] == '=') {
168             offset++;
169             break;
170         }
171     }
172 
173     if (offset == bufferSize || (offset - 1) == bufferSize) {
174         offset = 0;
175     }
176 
177     return offset;
178 }
179