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