void test_commit_parse__signature(void) { passing_signature_test_case *passcase; failing_signature_test_case *failcase; for (passcase = passing_signature_cases; passcase->string != NULL; passcase++) { const char *str = passcase->string; size_t len = strlen(passcase->string); struct git_signature person = {0}; cl_git_pass(git_signature__parse(&person, &str, str + len, passcase->header, '\n')); cl_assert_equal_s(passcase->name, person.name); cl_assert_equal_s(passcase->email, person.email); cl_assert_equal_i(passcase->time, person.when.time); cl_assert_equal_i(passcase->offset, person.when.offset); git__free(person.name); git__free(person.email); } for (failcase = failing_signature_cases; failcase->string != NULL; failcase++) { const char *str = failcase->string; size_t len = strlen(failcase->string); git_signature person = {0}; cl_git_fail(git_signature__parse(&person, &str, str + len, failcase->header, '\n')); git__free(person.name); git__free(person.email); } }
int git_signature_from_buffer(git_signature **out, const char *buf) { git_signature *sig; const char *buf_end; int error; assert(out && buf); *out = NULL; sig = git__calloc(1, sizeof(git_signature)); GITERR_CHECK_ALLOC(sig); buf_end = buf + strlen(buf); error = git_signature__parse(sig, &buf, buf_end, NULL, '\0'); if (error) git__free(sig); else *out = sig; return error; }
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; }
int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags) { char *buffer = (char *)data; const char *buffer_end = (char *)data + len; git_oid oid; int error; /* first parse; the vector hasn't been initialized yet */ if (commit->parents.contents == NULL) { git_vector_init(&commit->parents, 4, NULL, NULL); } clear_parents(commit); if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) return error; if ((error = git_repository_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS) return error; /* * TODO: commit grafts! */ while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { git_commit *parent; if ((error = git_repository_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS) return error; if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS) return GIT_ENOMEM; } if (parse_flags & COMMIT_FULL_PARSE) { if (commit->author) git_signature_free(commit->author); commit->author = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ")) < GIT_SUCCESS) return error; } else { if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) return GIT_EOBJCORRUPTED; buffer++; } /* Always parse the committer; we need the commit time */ if (commit->committer) git_signature_free(commit->committer); commit->committer = git__malloc(sizeof(git_signature)); if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ")) < GIT_SUCCESS) return error; /* parse commit message */ while (buffer <= buffer_end && *buffer == '\n') buffer++; if (parse_flags & COMMIT_FULL_PARSE && buffer < buffer_end) { const char *line_end; size_t message_len = buffer_end - buffer; /* Long message */ message_len = buffer_end - buffer; commit->message = git__malloc(message_len + 1); memcpy(commit->message, buffer, message_len); commit->message[message_len] = 0; /* Short message */ if((line_end = memchr(buffer, '\n', buffer_end - buffer)) == NULL) line_end = buffer_end; message_len = line_end - buffer; commit->message_short = git__malloc(message_len + 1); memcpy(commit->message_short, buffer, message_len); commit->message_short[message_len] = 0; } return GIT_SUCCESS; }
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; }