|
18 | 18 |
|
19 | 19 | static const int OBJECT_BASE_SIZE = 4096; |
20 | 20 |
|
21 | | -static struct { |
| 21 | +typedef struct { |
22 | 22 | const char *str; /* type name string */ |
23 | | - int loose; /* valid loose object type flag */ |
24 | 23 | size_t size; /* size in bytes of the object structure */ |
25 | | -} git_objects_table[] = { |
| 24 | + |
| 25 | + int (*from_odb)(void *self, git_odb_object *obj); |
| 26 | + int (*parse)(void *self, const char *buf, const char *buf_end); |
| 27 | + void (*free)(void *self); |
| 28 | +} git_object_def; |
| 29 | + |
| 30 | +static git_object_def git_objects_table[] = { |
26 | 31 | /* 0 = GIT_OBJ__EXT1 */ |
27 | | - { "", 0, 0}, |
| 32 | + { "", 0, NULL, NULL, NULL }, |
28 | 33 |
|
29 | 34 | /* 1 = GIT_OBJ_COMMIT */ |
30 | | - { "commit", 1, sizeof(struct git_commit)}, |
| 35 | + { "commit", sizeof(git_commit), NULL, git_commit__parse, git_commit__free }, |
31 | 36 |
|
32 | 37 | /* 2 = GIT_OBJ_TREE */ |
33 | | - { "tree", 1, sizeof(struct git_tree) }, |
| 38 | + { "tree", sizeof(git_tree), NULL, git_tree__parse, git_tree__free }, |
34 | 39 |
|
35 | 40 | /* 3 = GIT_OBJ_BLOB */ |
36 | | - { "blob", 1, sizeof(struct git_blob) }, |
| 41 | + { "blob", sizeof(git_blob), git_blob__from_odb_object, NULL, git_blob__free }, |
37 | 42 |
|
38 | 43 | /* 4 = GIT_OBJ_TAG */ |
39 | | - { "tag", 1, sizeof(struct git_tag) }, |
| 44 | + { "tag", sizeof(git_tag), NULL, git_tag__parse, git_tag__free }, |
40 | 45 |
|
41 | 46 | /* 5 = GIT_OBJ__EXT2 */ |
42 | | - { "", 0, 0 }, |
43 | | - |
| 47 | + { "", 0, NULL, NULL, NULL }, |
44 | 48 | /* 6 = GIT_OBJ_OFS_DELTA */ |
45 | | - { "OFS_DELTA", 0, 0 }, |
46 | | - |
| 49 | + { "OFS_DELTA", 0, NULL, NULL, NULL }, |
47 | 50 | /* 7 = GIT_OBJ_REF_DELTA */ |
48 | | - { "REF_DELTA", 0, 0 } |
| 51 | + { "REF_DELTA", 0, NULL, NULL, NULL }, |
49 | 52 | }; |
50 | 53 |
|
51 | | -static int create_object(git_object **object_out, git_otype type) |
52 | | -{ |
53 | | - git_object *object = NULL; |
54 | | - |
55 | | - assert(object_out); |
56 | | - |
57 | | - *object_out = NULL; |
58 | | - |
59 | | - switch (type) { |
60 | | - case GIT_OBJ_COMMIT: |
61 | | - case GIT_OBJ_TAG: |
62 | | - case GIT_OBJ_BLOB: |
63 | | - case GIT_OBJ_TREE: |
64 | | - object = git__malloc(git_object__size(type)); |
65 | | - GITERR_CHECK_ALLOC(object); |
66 | | - memset(object, 0x0, git_object__size(type)); |
67 | | - break; |
68 | | - |
69 | | - default: |
70 | | - giterr_set(GITERR_INVALID, "The given type is invalid"); |
71 | | - return -1; |
72 | | - } |
73 | | - |
74 | | - *object_out = object; |
75 | | - return 0; |
76 | | -} |
77 | | - |
78 | 54 | int git_object__from_odb_object( |
79 | 55 | git_object **object_out, |
80 | 56 | git_repository *repo, |
81 | 57 | git_odb_object *odb_obj, |
82 | 58 | git_otype type) |
83 | 59 | { |
84 | 60 | int error; |
| 61 | + size_t object_size; |
| 62 | + git_object_def *def; |
85 | 63 | git_object *object = NULL; |
86 | 64 |
|
| 65 | + assert(object_out); |
| 66 | + *object_out = NULL; |
| 67 | + |
| 68 | + /* Validate type match */ |
87 | 69 | if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) { |
88 | 70 | giterr_set(GITERR_INVALID, |
89 | 71 | "The requested type does not match the type in the ODB"); |
90 | 72 | return GIT_ENOTFOUND; |
91 | 73 | } |
92 | 74 |
|
93 | | - if ((error = create_object(&object, odb_obj->cached.type)) < 0) |
94 | | - return error; |
| 75 | + if ((object_size = git_object__size(odb_obj->cached.type)) == 0) { |
| 76 | + giterr_set(GITERR_INVALID, "The requested type is invalid"); |
| 77 | + return GIT_ENOTFOUND; |
| 78 | + } |
| 79 | + |
| 80 | + /* Allocate and initialize base object */ |
| 81 | + object = git__calloc(1, object_size); |
| 82 | + GITERR_CHECK_ALLOC(object); |
95 | 83 |
|
96 | | - /* Initialize parent object */ |
97 | 84 | git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); |
98 | | - object->cached.size = odb_obj->cached.size; |
99 | 85 | object->cached.type = odb_obj->cached.type; |
| 86 | + object->cached.size = odb_obj->cached.size; |
100 | 87 | object->repo = repo; |
101 | 88 |
|
102 | | - switch (object->cached.type) { |
103 | | - case GIT_OBJ_COMMIT: |
104 | | - error = git_commit__parse((git_commit *)object, odb_obj); |
105 | | - break; |
106 | | - |
107 | | - case GIT_OBJ_TREE: |
108 | | - error = git_tree__parse((git_tree *)object, odb_obj); |
109 | | - break; |
110 | | - |
111 | | - case GIT_OBJ_TAG: |
112 | | - error = git_tag__parse((git_tag *)object, odb_obj); |
113 | | - break; |
| 89 | + /* Parse raw object data */ |
| 90 | + def = &git_objects_table[odb_obj->cached.type]; |
| 91 | + assert(def->free && (def->from_odb || def->parse)); |
114 | 92 |
|
115 | | - case GIT_OBJ_BLOB: |
116 | | - error = git_blob__parse((git_blob *)object, odb_obj); |
117 | | - break; |
118 | | - |
119 | | - default: |
120 | | - break; |
| 93 | + if (def->from_odb) { |
| 94 | + error = def->from_odb(object, odb_obj); |
| 95 | + } else { |
| 96 | + const char *data = (const char *)git_odb_object_data(odb_obj); |
| 97 | + error = def->parse(object, data, data + git_odb_object_size(odb_obj)); |
121 | 98 | } |
122 | 99 |
|
123 | 100 | if (error < 0) { |
124 | | - git_object__free(object); |
| 101 | + def->free(object); |
125 | 102 | return error; |
126 | 103 | } |
127 | 104 |
|
128 | 105 | *object_out = git_cache_store_parsed(&repo->objects, object); |
129 | 106 | return 0; |
130 | 107 | } |
131 | 108 |
|
| 109 | +void git_object__free(void *obj) |
| 110 | +{ |
| 111 | + git_otype type = ((git_object *)obj)->cached.type; |
| 112 | + |
| 113 | + if (type < 0 || ((size_t)type) >= ARRAY_SIZE(git_objects_table) || |
| 114 | + !git_objects_table[type].free) |
| 115 | + git__free(obj); |
| 116 | + else |
| 117 | + git_objects_table[type].free(obj); |
| 118 | +} |
| 119 | + |
132 | 120 | int git_object_lookup_prefix( |
133 | 121 | git_object **object_out, |
134 | 122 | git_repository *repo, |
@@ -222,35 +210,6 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o |
222 | 210 | return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type); |
223 | 211 | } |
224 | 212 |
|
225 | | -void git_object__free(void *_obj) |
226 | | -{ |
227 | | - git_object *object = (git_object *)_obj; |
228 | | - |
229 | | - assert(object); |
230 | | - |
231 | | - switch (object->cached.type) { |
232 | | - case GIT_OBJ_COMMIT: |
233 | | - git_commit__free((git_commit *)object); |
234 | | - break; |
235 | | - |
236 | | - case GIT_OBJ_TREE: |
237 | | - git_tree__free((git_tree *)object); |
238 | | - break; |
239 | | - |
240 | | - case GIT_OBJ_TAG: |
241 | | - git_tag__free((git_tag *)object); |
242 | | - break; |
243 | | - |
244 | | - case GIT_OBJ_BLOB: |
245 | | - git_blob__free((git_blob *)object); |
246 | | - break; |
247 | | - |
248 | | - default: |
249 | | - git__free(object); |
250 | | - break; |
251 | | - } |
252 | | -} |
253 | | - |
254 | 213 | void git_object_free(git_object *object) |
255 | 214 | { |
256 | 215 | if (object == NULL) |
@@ -304,7 +263,7 @@ int git_object_typeisloose(git_otype type) |
304 | 263 | if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) |
305 | 264 | return 0; |
306 | 265 |
|
307 | | - return git_objects_table[type].loose; |
| 266 | + return (git_objects_table[type].size > 0) ? 1 : 0; |
308 | 267 | } |
309 | 268 |
|
310 | 269 | size_t git_object__size(git_otype type) |
|
0 commit comments