void test_commit_parse__header(void) { git_oid oid; parse_test_case *testcase; for (testcase = passing_header_cases; testcase->line != NULL; testcase++) { const char *line = testcase->line; const char *line_end = line + strlen(line); cl_git_pass(git_oid__parse(&oid, &line, line_end, testcase->header)); cl_assert(line == line_end); } for (testcase = failing_header_cases; testcase->line != NULL; testcase++) { const char *line = testcase->line; const char *line_end = line + strlen(line); cl_git_fail(git_oid__parse(&oid, &line, line_end, testcase->header)); } }
int git_commit__parse_raw(void *_commit, const char *data, size_t size) { git_commit *commit = _commit; const char *buffer_start = data, *buffer; const char *buffer_end = buffer_start + size; git_oid parent_id; size_t header_len; git_signature dummy_sig; buffer = buffer_start; /* Allocate for one, which will allow not to realloc 90% of the time */ git_array_init_to_size(commit->parent_ids, 1); GITERR_CHECK_ARRAY(commit->parent_ids); /* The tree is always the first field */ if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) goto bad_buffer; /* * TODO: commit grafts! */ while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { git_oid *new_id = git_array_alloc(commit->parent_ids); GITERR_CHECK_ALLOC(new_id); git_oid_cpy(new_id, &parent_id); } commit->author = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->author); if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0) return -1; /* Some tools create multiple author fields, ignore the extra ones */ while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) { if (git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n') < 0) return -1; git__free(dummy_sig.name); git__free(dummy_sig.email); } /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->committer); if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0) return -1; /* Parse add'l header entries */ while (buffer < buffer_end) { const char *eoln = buffer; if (buffer[-1] == '\n' && buffer[0] == '\n') break; while (eoln < buffer_end && *eoln != '\n') ++eoln; if (git__prefixncmp(buffer, buffer_end - buffer, "encoding ") == 0) { buffer += strlen("encoding "); commit->message_encoding = git__strndup(buffer, eoln - buffer); GITERR_CHECK_ALLOC(commit->message_encoding); } if (eoln < buffer_end && *eoln == '\n') ++eoln; buffer = eoln; } header_len = buffer - buffer_start; commit->raw_header = git__strndup(buffer_start, header_len); GITERR_CHECK_ALLOC(commit->raw_header); /* point "buffer" to data after header, +1 for the final LF */ buffer = buffer_start + header_len + 1; /* extract commit message */ if (buffer <= buffer_end) commit->raw_message = git__strndup(buffer, buffer_end - buffer); else commit->raw_message = git__strdup(""); GITERR_CHECK_ALLOC(commit->raw_message); return 0; bad_buffer: giterr_set(GITERR_OBJECT, "failed to parse bad commit object"); return -1; }
static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" }; unsigned int i; size_t text_len, alloc_len; char *search; if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) return tag_error("Object field invalid"); if (buffer + 5 >= buffer_end) return tag_error("Object too short"); if (memcmp(buffer, "type ", 5) != 0) return tag_error("Type field not found"); buffer += 5; tag->type = GIT_OBJ_BAD; for (i = 1; i < ARRAY_SIZE(tag_types); ++i) { size_t type_length = strlen(tag_types[i]); if (buffer + type_length >= buffer_end) return tag_error("Object too short"); if (memcmp(buffer, tag_types[i], type_length) == 0) { tag->type = i; buffer += type_length; break; } } if (tag->type == GIT_OBJ_BAD) return tag_error("Invalid object type"); if (buffer + 4 >= buffer_end) return tag_error("Object too short"); if (memcmp(buffer, "tag ", 4) != 0) return tag_error("Tag field not found"); buffer += 4; search = memchr(buffer, '\n', buffer_end - buffer); if (search == NULL) return tag_error("Object too short"); text_len = search - buffer; GITERR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1); tag->tag_name = git__malloc(alloc_len); GITERR_CHECK_ALLOC(tag->tag_name); memcpy(tag->tag_name, buffer, text_len); tag->tag_name[text_len] = '\0'; buffer = search + 1; tag->tagger = NULL; if (buffer < buffer_end && *buffer != '\n') { tag->tagger = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(tag->tagger); if (git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') < 0) return -1; } tag->message = NULL; if (buffer < buffer_end) { if( *buffer != '\n' ) return tag_error("No new line before message"); text_len = buffer_end - ++buffer; GITERR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1); tag->message = git__malloc(alloc_len); GITERR_CHECK_ALLOC(tag->message); memcpy(tag->message, buffer, text_len); tag->message[text_len] = '\0'; } return 0; }
int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) { const char *buffer = data; const char *buffer_end = (const char *)data + len; git_oid parent_oid; int error; git_vector_init(&commit->parent_oids, 4, NULL); if ((error = git_oid__parse(&commit->tree_oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) return git__rethrow(error, "Failed to parse buffer"); /* * TODO: commit grafts! */ while (git_oid__parse(&parent_oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { git_oid *new_oid; new_oid = git__malloc(sizeof(git_oid)); git_oid_cpy(new_oid, &parent_oid); if (git_vector_insert(&commit->parent_oids, new_oid) < GIT_SUCCESS) return GIT_ENOMEM; } commit->author = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n')) < GIT_SUCCESS) return git__rethrow(error, "Failed to parse commit"); /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < GIT_SUCCESS) return git__rethrow(error, "Failed to parse commit"); if (git__prefixcmp(buffer, "encoding ") == 0) { const char *encoding_end; buffer += strlen("encoding "); encoding_end = buffer; while (encoding_end < buffer_end && *encoding_end != '\n') encoding_end++; commit->message_encoding = git__strndup(buffer, encoding_end - buffer); if (!commit->message_encoding) return GIT_ENOMEM; buffer = encoding_end; } /* parse commit message */ while (buffer < buffer_end && *buffer == '\n') buffer++; if (buffer < buffer_end) { commit->message = git__strndup(buffer, buffer_end - buffer); if (!commit->message) return GIT_ENOMEM; } return GIT_SUCCESS; }
int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) { const char *buffer = data; const char *buffer_end = (const char *)data + len; git_oid parent_id; if (git_vector_init(&commit->parent_ids, 4, NULL) < 0) return -1; if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) goto bad_buffer; /* * TODO: commit grafts! */ while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { git_oid *new_id = git__malloc(sizeof(git_oid)); GITERR_CHECK_ALLOC(new_id); git_oid_cpy(new_id, &parent_id); if (git_vector_insert(&commit->parent_ids, new_id) < 0) return -1; } commit->author = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->author); if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0) return -1; /* Always parse the committer; we need the commit time */ commit->committer = git__malloc(sizeof(git_signature)); GITERR_CHECK_ALLOC(commit->committer); if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0) return -1; /* Parse add'l header entries until blank line found */ while (buffer < buffer_end && *buffer != '\n') { const char *eoln = buffer; while (eoln < buffer_end && *eoln != '\n') ++eoln; if (git__prefixcmp(buffer, "encoding ") == 0) { buffer += strlen("encoding "); commit->message_encoding = git__strndup(buffer, eoln - buffer); GITERR_CHECK_ALLOC(commit->message_encoding); } if (eoln < buffer_end && *eoln == '\n') ++eoln; buffer = eoln; } /* skip blank lines */ while (buffer < buffer_end - 1 && *buffer == '\n') buffer++; /* parse commit message */ if (buffer <= buffer_end) { commit->message = git__strndup(buffer, buffer_end - buffer); GITERR_CHECK_ALLOC(commit->message); } return 0; bad_buffer: giterr_set(GITERR_OBJECT, "Failed to parse bad commit object"); return -1; }