1 /* libjclass - Library for reading java class files
2  * Copyright (C) 2003  Nicos Panayides
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  * $Id: manifest.c,v 1.4 2004/03/21 05:04:10 anarxia Exp $
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <jclass/manifest.h>
29 
30 /**
31 * jclass_manifest_new_from_buffer
32 * @buf: A memory buffer containing a manifest file.
33 * @length: The length of the buffer in bytes.
34 * If the buffer is NULL terminated set to 0.
35 *
36 * Creates a Manifest struct representing the given memory buffer. If the length
37 * given is 0 it is assumed that the buffer is NULL terminated.
38 *
39 * Returns: A Manifest struct or NULL if something went wrong.
40 */
jclass_manifest_new_from_buffer(const char * orig_buf,uint32_t buf_len)41 Manifest *jclass_manifest_new_from_buffer(const char* orig_buf, uint32_t buf_len) {
42 	Manifest *manifest;
43 	ManifestEntry *entry;
44 	const char *p, *p1;
45 	char *buf;
46 	int entry_count;
47 	int section_count;
48 	int token_length;
49 	int i;
50 
51 	if (!orig_buf)
52 		return NULL;
53 
54 	/* Copy the buffer and add a terminating null */
55 	if (buf_len > 0) {
56 		buf = (char*) malloc(buf_len + 1);
57 		buf = memcpy(buf, orig_buf, buf_len);
58 		buf[buf_len] = '\0';
59 	} else {
60 		buf = (char*)orig_buf;
61 	}
62 
63 	manifest = (Manifest*) malloc(sizeof(Manifest));
64 	manifest->section_count = 1;
65 
66 	/* count sections */
67 	for(p = buf; *p ; p++) {
68 		while (*p && *p == ' ')
69 			p++;
70 
71 		if (*p == '\0')
72 			break;
73 
74 		if (!strncmp("Name:", p, 5)) {
75 			manifest->section_count++;
76 		}
77 		while (*p && *p != '\n')
78 			p++;
79 	}
80 
81 	manifest->sections = (ManifestSection*) malloc(sizeof(ManifestSection) * manifest->section_count);
82 	manifest->sections[0].name = NULL;
83 	manifest->sections[0].entry_count = 0;
84 	section_count = 0;
85 
86 	/* count entries per section and get section names */
87 	for(p = buf; *p; p++) {
88 		while(*p && (*p == '\r' || *p == '\n' || *p == ' '))
89 			p++;
90 
91 		if (*p == '\0')
92 			break;
93 
94 		if (!strncmp("Name:", p, 5)) {
95 			section_count++;
96 			manifest->sections[section_count].entry_count = 0;
97 			p += 5;
98 			while (*p == ' ')
99 				p++;
100 			if (*p == ' ')
101 				p++;
102 
103 			p1 = p;
104 			token_length = 0;
105 			while (*p1 && *p1 != '\n' && *p1 != '\r') {
106 				p1++;
107 				token_length++;
108 			}
109 			manifest->sections[section_count].entry_count = 0;
110 			manifest->sections[section_count].name = (char*) malloc(token_length + 1);
111 			manifest->sections[section_count].name =
112 				strncpy(manifest->sections[section_count].name, p, token_length);
113 			manifest->sections[section_count].name[token_length] = '\0';
114 			p = p1;
115 		}
116 
117 		while (*p && *p != '\n' && *p != ':')
118 			p++;
119 
120 		if (*p == ':')
121 			manifest->sections[section_count].entry_count++;
122 
123 		while (*p && *p != '\n')
124 			p++;
125 	}
126 
127 	/* Allocate memory for entries */
128 	for (i = 0; i < manifest->section_count; i++) {
129 		entry_count = manifest->sections[i].entry_count;
130 		if (!(entry_count))
131 			manifest->sections[i].entries = NULL;
132 		else {
133 			manifest->sections[i].entries = (ManifestEntry*) malloc(sizeof(ManifestEntry) * entry_count);
134 		}
135 	}
136 
137 	section_count = 0;
138 	entry_count = 0;
139 
140 	/* Read entries */
141 	for(p = buf; *p; p++) {
142 		while(*p && (*p == '\r' || *p == '\n' || *p == ' '))
143 			p++;
144 
145 		if (*p == '\0')
146 			break;
147 
148 		if (!strncmp("Name:", p, 5)) {
149 			section_count++;
150 			entry_count = 0;
151 
152 			while (*p && *p != '\n')
153 				p++;
154 
155 			if (*p == '\0')
156 				break;
157 
158 			if (*p == '\n')
159 				p++;
160 		}
161 
162 		/* Key */
163 		token_length = 0;
164 		for (p1 = p; *p1 && *p != '\n' && *p1 != ':'; p1++) {
165 			token_length++;
166 		}
167 		if (token_length && *p1 == ':') {
168 			/* Check if we have more entries than we counted before.
169 			* This happens on manifests with multi-line entries.
170 			*/
171 			if (entry_count >= manifest->sections[section_count].entry_count) {
172 				continue;
173 			}
174 			entry = &manifest->sections[section_count].entries[entry_count];
175 			entry->key = (char*) malloc(token_length + 1);
176 			entry->key = strncpy(entry->key, p, token_length);
177 			entry->key[token_length] = '\0';
178 
179 			/* Skip leading spaces */
180 			for (p = p1 + 1; *p == ' '; p++);
181 
182 			/* Value */
183 			token_length = 0;
184 			for (p1 = p; *p1 && *p1 != '\r' && *p1 != '\n'; p1++) {
185 				token_length++;
186 			}
187 			if (token_length) {
188 				entry->value = (char*) malloc(token_length + 1);
189 				entry->value = strncpy(entry->value, p, token_length);
190 				entry->value[token_length] = '\0';
191 			} else {
192 				entry->value = NULL;
193 			}
194 			p = p1;
195 
196 			entry_count++;
197 			while (*p && *p != '\n')
198 				p++;
199 		}
200 	}
201 
202 	if (buf_len > 0)
203 		free(buf);
204 
205 	return manifest;
206 }
207 
get_section(Manifest * manifest,const char * section)208 static const ManifestSection *get_section(Manifest *manifest, const char *section) {
209 	int i;
210 	if (!manifest)
211 		return NULL;
212 
213 	for (i = 0; i < manifest->section_count; i++) {
214 		if (!section && !manifest->sections[i].name)
215 			return &manifest->sections[i];
216 		if (manifest->sections[i].name && strcmp(manifest->sections[i].name, section))
217 			return &manifest->sections[i];
218 	}
219 	return NULL;
220 }
221 
222 /**
223 * jclass_manifest_get_entry
224 * @manifest: The manifest to get the entry from.
225 * @section_name: The name of the section containing the entry or NULL for the main section.
226 * @key: The name of the entry.
227 *
228 * Gets the value of the given entry from a manifest.
229 *
230 * Returns: A NULL terminated string you should not modify.
231 */
jclass_manifest_get_entry(Manifest * manifest,const char * section_name,const char * key)232 const char *jclass_manifest_get_entry(Manifest *manifest, const char *section_name, const char *key) {
233 	const ManifestSection *section;
234 	int i;
235 
236 	section = get_section(manifest, section_name);
237 	if (!section)
238 		return NULL;
239 
240 	for (i = 0; i < section->entry_count; i++) {
241 		if (!strcmp(section->entries[i].key, key))
242 			return section->entries[i].value;
243 	}
244 	return NULL;
245 }
246 
247 /**
248 * jclass_manifest_free
249 * @manifest: The manifest to free.
250 *
251 * Frees the given manifest structure.
252 */
jclass_manifest_free(Manifest * manifest)253 void jclass_manifest_free(Manifest *manifest) {
254 	int i, j;
255 	ManifestEntry *entry;
256 
257 	if (!manifest)
258 		return;
259 
260 	for (i = 0; i < manifest->section_count; i++) {
261 		if (manifest->sections[i].name)
262 			free(manifest->sections[i].name);
263 
264 		if (manifest->sections[i].entries) {
265 			for (j = 0; j < manifest->sections[i].entry_count; j++) {
266 				entry = &manifest->sections[i].entries[j];
267 				free(entry->key);
268 				if (entry->value)
269 					free(entry->value);
270 			}
271 			free(manifest->sections[i].entries);
272 		}
273 	}
274 	free(manifest->sections);
275 	free(manifest);
276 }
277