How to commit to a git repository using libgit2? - c++

Since there is no copy-paste example for creating a commit without using files on disk with libgit2 as far as I can tell I thought I should add one.
Don't forget that libgit2 is in full development at this time (March 2013) so have a look at official documentation and source code, as new features are added daily:
libgit2 API
headers are very well commented - here's an example
extensive tests may be a source of inspiration
there are some official examples, general.c is a good place to start
inspiration may be found in LibGit2Sharp - here are some tests

bool addGitCommit (
git_repository * repo, git_signature * sign,
const char * content, int content_sz,
const char * message )
{
int rc; /* return code for git_ functions */
git_oid oid_blob; /* the SHA1 for our blob in the tree */
git_oid oid_tree; /* the SHA1 for our tree in the commit */
git_oid oid_commit; /* the SHA1 for our initial commit */
git_blob * blob; /* our blob in the tree */
git_tree * tree_cmt; /* our tree in the commit */
git_treebuilder * tree_bld; /* tree builder */
bool b = false;
/* create a blob from our buffer */
rc = git_blob_create_frombuffer(
&oid_blob,
repo,
content,
content_sz );
if ( rc == 0 ) { /* blob created */
rc = git_blob_lookup( &blob, repo, &oid_blob );
if ( rc == 0 ) { /* blob created and found */
rc = git_treebuilder_create( &tree_bld, NULL );
if ( rc == 0 ) { /* a new tree builder created */
rc = git_treebuilder_insert(
NULL,
tree_bld,
"name-of-the-file.txt",
&oid_blob,
GIT_FILEMODE_BLOB );
if ( rc == 0 ) { /* blob inserted in tree */
rc = git_treebuilder_write(
&oid_tree,
repo,
tree_bld );
if ( rc == 0 ) { /* the tree was written to the database */
rc = git_tree_lookup(
&tree_cmt, repo, &oid_tree );
if ( rc == 0 ) { /*we've got the tree pointer */
rc = git_commit_create(
&oid_commit, repo, "HEAD",
sign, sign, /* same author and commiter */
NULL, /* default UTF-8 encoding */
message,
tree_cmt, 0, NULL );
if ( rc == 0 ) {
b = true;
}
git_tree_free( tree_cmt );
}
}
}
git_treebuilder_free( tree_bld );
}
git_blob_free( blob );
}
}
return b;
}
The repository comes from git_repository_init() or git_repository_open().
The signature comes from git_signature_now() or git_signature_new().
The function updates the HEAD for current branch.
If you do a git status after the function executes you will notice that the file name-of-the-file.txt appears as being deleted. That is because the function does not create an actual file, only an entry in the git database.
Also, note the last arguments of git_commit_create(). 0 and NULL means that this is the first (root) commit. For all other there should be at least a parent commit specified, maybe obtained using git_commit_lookup().
I'm just learning these things. Please improve this answer if you know better.

Related

Getting digital signature from mmc.exe at windows 8

I have an application that tries to verify the mmc.exe (services) signature. (the context of the application I think is irrelevant) I am trying with winapi function which both fails with
WinVerifyTrust. I get TRUST_E_BAD_DIGEST when I am trying with verification from catalog, and
TRUST_E_NOSIGNATURE when trying from file info. it is very important to mention that my function succeeds on win7, XP but fails on win8.
this is the code snippet for the function
CATALOG_INFO InfoStruct = {0};
InfoStruct.cbStruct = sizeof(CATALOG_INFO);
WINTRUST_CATALOG_INFO WintrustCatalogStructure = {0};
WintrustCatalogStructure.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
WINTRUST_FILE_INFO WintrustFileStructure = {0};
WintrustFileStructure.cbStruct = sizeof(WINTRUST_FILE_INFO);
GUID ActionGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
//Get a context for signature verification.
HCATADMIN Context = NULL;
if(!::CryptCATAdminAcquireContext(&Context, NULL, 0) ){
return false;
}
//Open file.
cx_handle hFile(::CreateFileW(filename_.c_str(), GENERIC_READ, 7, NULL, OPEN_EXISTING, 0, NULL));
if( INVALID_HANDLE_VALUE == (HANDLE)hFile )
{
CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Get the size we need for our hash.
DWORD HashSize = 0;
::CryptCATAdminCalcHashFromFileHandle(hFile, &HashSize, NULL, 0);
if( HashSize == 0 )
{
//0-sized has means error!
::CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Allocate memory.
buffer hashbuf(HashSize);
//Actually calculate the hash
if( !CryptCATAdminCalcHashFromFileHandle(hFile, &HashSize, hashbuf.data, 0) )
{
CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Convert the hash to a string.
buffer MemberTag(((HashSize * 2) + 1) * sizeof(wchar_t));
for( unsigned int i = 0; i < HashSize; i++ ){
swprintf(&((PWCHAR)MemberTag.data)[i * 2], L"%02X", hashbuf.data[i ]);
}
//Get catalog for our context.
HCATINFO CatalogContext = CryptCATAdminEnumCatalogFromHash(Context, hashbuf, HashSize, 0, NULL);
if ( CatalogContext )
{
//If we couldn't get information
if ( !CryptCATCatalogInfoFromContext(CatalogContext, &InfoStruct, 0) )
{
//Release the context and set the context to null so it gets picked up below.
CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);
CatalogContext = NULL;
}
}
//If we have a valid context, we got our info.
//Otherwise, we attempt to verify the internal signature.
WINTRUST_DATA WintrustStructure = {0};
WintrustStructure.cbStruct = sizeof(WINTRUST_DATA);
if( !CatalogContext )
{
load_signature_verification_from_file_info(WintrustFileStructure, WintrustStructure);
}
else
{
load_signature_verification_from_catalog(WintrustStructure, WintrustCatalogStructure, InfoStruct, MemberTag);
}
//Call our verification function.
long verification_res = ::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
//Check return.
bool is_success = SUCCEEDED(verification_res) ? true : false;
// if failed with CatalogContext, try with FILE_INFO
if(!is_success && CatalogContext && verification_res != TRUST_E_NOSIGNATURE)
{
//warning2(L"Failed verification with Catalog Context: 0x%x %s ; Retrying with FILE_INFO.", verification_res, (const wchar_t*)format_last_error(verification_res));
load_signature_verification_from_file_info(WintrustFileStructure, WintrustStructure);
verification_res = ::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
is_success = SUCCEEDED(verification_res) ? true : false;
}
if(perr && !is_success && verification_res != TRUST_E_NOSIGNATURE)
{
perr->code = verification_res;
perr->description = format_last_error(verification_res);
}
//Free context.
if( CatalogContext ){
::CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);
}
//If we successfully verified, we need to free.
if( is_success )
{
WintrustStructure.dwStateAction = WTD_STATEACTION_CLOSE;
::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
}
::CryptCATAdminReleaseContext(Context, 0);
return is_success;
I don't think any thing had changed in this function from win7 to win 8 so what could possibly go wrong?
UPDATE
I did notice that my function does work for task manager at win 8.
but again for the mmc it does not work.
It appears that your general approach is correct and the functions themselves haven't changed. However there are subtle changes; namely the data on which they operate has changed. The hashes stored for files on Windows 8, according to comments on CryptCATAdminCalcHashFromFileHandle, are calculated using SHA-256 hashes.
The SHA-256 hashing algorithm is not supported by CryptCATAdminCalcHashFromFileHandle, so you must update the code to use CryptCATAdminAcquireContext2 and CryptCATAdminCalcHashFromFileHandle2 on Windows 8; the former allows you to acquire a HCATADMIN with a specified hash algorithm, and the latter allows using that HCATADMIN.
(Interestingly, WINTRUST_CATALOG_INFO also points this direction with its HCATADMIN hCatAdmin member, documented as "Windows 8 and Windows Server 2012: Support for this member begins.")

Deleting a file from git repository using libgit2

Say you have a file in a git repository:
a.txt
What APIs should be used to create a commit that removes that file?
For example in this question the file is committed without creating it on disk. Is it now possible to remove that file without using the index (stage area)?
I was expecting a similar flow, maybe creating a git_tree_entry for the tree builder, but that does not seem to be the case. git_reference_list() does not list files, so there's a dead end. Also searching the sources for delete and remove got me no success.
Removing a file is similar to adding a file - you remove the index entry to stage the delete, then you can create a commit from the index.
You probably want to use git_index_remove_bypath, which will remove the file from the index and resolve any conflicts that file had.
Here is a copy-paste example; for getLastCommit() see this question.
bool commitStage (
git_repository * repo, git_signature * sign,
const char * message )
{
bool b = false;
int rc;
git_index * repo_idx; /* the stage area for our repository */
git_oid oid_idx_tree; /* the SHA1 for the tree generated from index */
git_oid oid_commit; /* the SHA1 for our commit */
git_tree * tree_cmt; /* tree generated from index */
git_commit * parent_commit;/* most recent commit in the head */
parent_commit = getLastCommit( repo );
if ( parent_commit != NULL )
{ /* we have the parent commit */
rc = git_repository_index( &repo_idx, repo );
if ( rc == 0 )
{ /* we now have the index (stage area) structure in repo_idx */
git_index_read(repo_idx);
/* the stage area may be altered here with functions like
git_index_add_bypath();
git_index_remove_bypath();
*/
/* by writing the index we get the SHA1 of the tree */
rc = git_index_write_tree( &oid_idx_tree, repo_idx );
if ( rc == 0 )
{
rc = git_tree_lookup(
&tree_cmt, repo, &oid_idx_tree );
if ( rc == 0 )
{ /* the actual tree structure; create a commit from it */
rc = git_commit_create(
&oid_commit, repo, "HEAD",
sign, sign, NULL,
message,
tree_cmt, 1, (const git_commit**)&parent_commit );
if ( rc == 0 )
{
b = true;
}
}
}
git_index_free( repo_idx );
}
git_commit_free( parent_commit );
}
return b;
}

HDF5 :Create a Dataset with string

I am using HDF5 API and I am trying to create a dataset with variable-length string.
The struct is
struct dataX
{
std::string data;
};
I was using char[256] with a static hard coded size.
But I want it to be dynamic so after reading the HDF5 Doc, I found H5T_VARIABLE and used it as follows but it still fails.
H5Dcreate returns a negative value (means error).
hid_t mem_type;
mem_type = H5Tcopy( H5T_C_S1 );
H5Tset_size(mem_type,H5T_VARIABLE);
/* Create the memory data type. */
if ((mem_type_id = H5Tcreate (H5T_COMPOUND, mem_type )) < 0 ) {
return -1;
}
/* Insert fields. */
if ( H5Tinsert(mem_type_id, "field", 0, mem_type_id ) < 0 ) {
return -1;
}
/* Create a simple data space with unlimited size */
// hsize_t dims[1]={0};
// hsize_t maxdimsk[1]={ H5S_UNLIMITED };
if ( (sid = H5Screate_simple( 1, dims, maxdims )) < 0 ){
return -1;
}
/* Modify dataset creation properties, i.e. enable chunking */
plist_id = H5Pcreate (H5P_DATASET_CREATE);
//chunk==1
if ( H5Pset_chunk ( plist_id, 1, chunk ) < 0 ){
return -1;
}
H5Pset_alloc_time( plist_id, H5D_ALLOC_TIME_EARLY )
/* Set the fill value using a struct as the data type. */
// fill_data=0
if ( fill_data )
{
if ( H5Pset_fill_value( plist_id, mem_type_id, fill_data ) < 0 ){
LOG_ERROR << "cannot fill value " << LOG_ENDL;
return -1;
}
}
else {
if ( H5Pset_fill_time( plist_id, H5D_FILL_TIME_NEVER ) < 0 ) {
LOG_ERROR << "error" << LOG_ENDL;
}
}
/* Create the dataset. */
did = H5Dcreate( loc_id, dset_name, mem_type_id, sid, plist_id )
I tried H5D_ALLOC_TIME_LATE, thinking that maybe if it allocated the memory just before writing it would work but ... it didn't.
Now I'm stuck and I don't know what to do.
Did I miss something ?
Your mem_type_id doubly invalid:
the second argument of H5Tcreate should be the size of the compound datatype
in H5Tinsert, the last argument should be the datatype of the inserted field. Here I guess you meant mem_type instead of mem_type_id.
I don't know anything about what you are doing in particular, but to write variable length string, you do not need to create a compound type nor to set any special property lists. Basically your 3 first line are enough to create a valid variable-length string datatype (mem_type). Then you create the simple dataspace, then the dataset.
Have a look at this example, you will see it's pretty simple.

How to use OpenSSL to extend {D,E,N} RSA key to {D,E,N,p,q,etc.}?

I have an RSA key consisting of the public & private factors and the modulus D. (I'm currently generating and using the key with a JavaScript library.) I would like to use the same key to perform encryptions & decryptions with OpenSSL. I can plug my factors into an OpenSSL RSA key and everything works, but I'd like to have OpenSSL calculate the auxiliary factors it uses (if available) to speed up operations.
I'm not sure whether it's even mathematically possible to work back from {D,E,N} to those factors, but if it is, I'd like to know how to ask libopenssl to do it.
Thanks!
The algorithm for deriving p and q from the secret d is very easy and fast, though probabilistic. It is explained very briefly in Chapter 8 of "Handbook of applied cryptography", section 8.2.2, or in Boneh's article "Twenty Years of Attacks on the RSA Cryptosystem", page 205.
You could find first an implementation of the algorithm in a high level language (for instance in Python, check the function rsa_construct in PyCrypto). From there, you can implement it via OpenSSL using its multiprecision API.
/* crypto/rsa/rsa_aug_key.c -*- Mode: C; c-file-style: "eay" -*- */
/* ====================================================================
* Copyright (c) 1999 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core#OpenSSL.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
/*
* If key has d, e and n, but not p, q, dmp1, dmq1 and iqmp, try
* to calculate these extra factors. Return 1 on success or 0
* on failure. (The key may still be useable even if this fails.)
*/
int RSA_augment_key(RSA *key)
{
int spotted;
BN_CTX *ctx;
BIGNUM *ktot;
BIGNUM *t;
BIGNUM *tmp;
BIGNUM *a;
BIGNUM *two;
BIGNUM *l00;
BIGNUM *cand;
BIGNUM *k;
BIGNUM *n_1;
if (!key || !key->d || !key->e || !key->n) return 0;
spotted = 0;
ctx = BN_CTX_new( );
ktot = BN_new( );
t = BN_new( );
tmp = BN_new( );
a = 0; BN_dec2bn( &a, "2" );
two = 0; BN_dec2bn( &two, "2" );
l00 = 0; BN_dec2bn( &l00, "100" );
cand = BN_new( );
k = BN_new( );
n_1 = BN_new( ); if (!BN_sub( n_1, key->n, BN_value_one( ) )) goto fail;
/* Python-code comments from PyCrypto
// ------------------------------------------------------------------
// # Compute factors p and q from the private exponent d.
// # We assume that n has no more than two factors.
// # See 8.2.2(i) in Handbook of Applied Cryptography.
// ktot = d*e-1*/
if (!BN_mul( tmp, key->d, key->e, ctx )) goto fail;
if (!BN_sub( ktot, tmp, BN_value_one( ) )) goto fail;
/* # The quantity d*e-1 is a multiple of phi(n), even,
// # and can be represented as t*2^s.
// t = ktot */
if (!BN_copy( t, ktot )) goto fail;
/* while t%2==0:
// t=divmod(t,2)[0] */
while (!BN_is_odd( t ))
if (!BN_rshift1( t, t )) goto fail;
/* # Cycle through all multiplicative inverses in Zn.
// # The algorithm is non-deterministic, but there is a 50% chance
// # any candidate a leads to successful factoring.
// # See "Digitalized Signatures and Public Key Functions as Intractable
// # as Factorization", M. Rabin, 1979
// spotted = 0
// a = 2
// while not spotted and a<100: */
while (!spotted && BN_cmp( a, l00 ) < 0) {
/* k = t */
if (!BN_copy( k, t )) goto fail;
/* # Cycle through all values a^{t*2^i}=a^k
// while k<ktot: */
while (BN_cmp( k, ktot ) < 0) {
/* cand = pow(a,k,n) */
if (!BN_mod_exp( cand, a, k, key->n, ctx )) goto fail;
/* # Check if a^k is a non-trivial root of unity (mod n)
// if cand!=1 and cand!=(n-1) and pow(cand,2,n)==1: */
if (BN_cmp( cand, BN_value_one( ) ) && BN_cmp( cand, n_1 )) {
if (!BN_mod_exp( tmp, cand, two, key->n, ctx )) goto fail;
if (BN_cmp( tmp, BN_value_one( )) == 0) {
/* # We have found a number such that (cand-1)(cand+1)=0 (mod n).
// # Either of the terms divides n.
// obj.p = GCD(cand+1,n)
// spotted = 1
// break */
key->p = BN_new( );
if (!BN_add( tmp, cand, BN_value_one( ) )) goto fail;
if (!BN_gcd( key->p, tmp, key->n, ctx )) goto fail;
spotted = 1;
break;
}
}
// k = k*2
if (!BN_lshift1( k, k )) goto fail;
}
/* # This value was not any good... let's try another!
// a = a+2 */
if (!BN_add( a, a, two )) goto fail;
}
if (!spotted) {
/* Unable to compute factors P and Q from exponent D */
goto fail;
}
key->q = BN_new( );
if (!BN_div( key->q, tmp, key->n, key->p, ctx )) goto fail;
if (!BN_is_zero( tmp )) {
/* Curses! Tricked with a bogus P! */
goto fail;
}
key->dmp1 = BN_new( );
key->dmq1 = BN_new( );
key->iqmp = BN_new( );
if (!BN_sub( tmp, key->p, BN_value_one( ) )) goto fail;
if (!BN_mod( key->dmp1, key->d, tmp, ctx )) goto fail;
if (!BN_sub( tmp, key->q, BN_value_one( ) )) goto fail;
if (!BN_mod( key->dmq1, key->d, tmp, ctx )) goto fail;
if (!BN_mod_inverse( key->iqmp, key->q, key->p, ctx )) goto fail;
if (RSA_check_key( key ) == 1) goto cleanup;
fail:
BN_free( key->p ); key->p = 0;
BN_free( key->q ); key->q = 0;
BN_free( key->dmp1 ); key->dmp1 = 0;
BN_free( key->dmq1 ); key->dmq1 = 0;
BN_free( key->iqmp ); key->iqmp = 0;
spotted = 0;
cleanup:
BN_free( k );
BN_free( cand );
BN_free( n_1 );
BN_free( l00 );
BN_free( two );
BN_free( a );
BN_free( tmp );
BN_free( t );
BN_free( ktot );
BN_CTX_free( ctx );
return spotted;
}
Hard problem. To find p and q from n, you need to factor n, which is hard. Given that you know both d and e, you could instead look for a large factor of de-1, which would be phi(n). Once you have that you can take advantage of the fact that, n - phi(n) = p + q - 1 for RSA keys, and thus find p and q
So the process is roughly:
Try to guess x in de-1 = x phi(n). Sine e = 65537 for RSA, this shouldn't be too bad -- x has to be somewhere in the range 50000..200000 or so, so it should only require 100K or so trial divisions.
Now find y = (p + q)/2 = (n + phi(n) + 1)/2 and z = sqrt(yy - n), which gives you p = y+z and q = y-z
Relatively straight-forward, but there's no built-in way of doing this with openssl or any other library I'm aware of.

Why would GLU crash at this spot?

I have found that my application crashes with a null reference exception right here in sweep.c in GLU source code:
static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
/*
* Purpose: connect a "left" vertex (one where both edges go right)
* to the processed portion of the mesh. Let R be the active region
* containing vEvent, and let U and L be the upper and lower edge
* chains of R. There are two possibilities:
*
* - the normal case: split R into two regions, by connecting vEvent to
* the rightmost vertex of U or L lying to the left of the sweep line
*
* - the degenerate case: if vEvent is close enough to U or L, we
* merge vEvent into that edge chain. The subcases are:
* - merging with the rightmost vertex of U or L
* - merging with the active edge of U or L
* - merging with an already-processed portion of U or L
*/
{
ActiveRegion *regUp, *regLo, *reg;
GLUhalfEdge *eUp, *eLo, *eNew;
ActiveRegion tmp;
/* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
/* Get a pointer to the active region containing vEvent */
tmp.eUp = vEvent->anEdge->Sym;
/* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
regLo = RegionBelow( regUp );
eUp = regUp->eUp;
eLo = regLo->eUp; //CRASHES RIGHT HERE SINCE RegLo is = 0x000000 FOR SOME REASON
/* Try merging with U or L first */
if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
ConnectLeftDegenerate( tess, regUp, vEvent );
return;
}
/* Connect vEvent to rightmost processed vertex of either chain.
* e->Dst is the vertex that we will connect to vEvent.
*/
reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
if( regUp->inside || reg->fixUpperEdge) {
if( reg == regUp ) {
eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
if (eNew == NULL) longjmp(tess->env,1);
} else {
GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
if (tempHalfEdge == NULL) longjmp(tess->env,1);
eNew = tempHalfEdge->Sym;
}
if( reg->fixUpperEdge ) {
if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
} else {
ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
}
SweepEvent( tess, vEvent );
} else {
/* The new vertex is in a region which does not belong to the polygon.
* We don''t need to connect this vertex to the rest of the mesh.
*/
AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
}
}
It seems as though eRegLo is a NULL pointer sometimes which causes my application to crash. How could I modify the source to prevent it from crashing my application?
Thanks
You will have to look into the source for RegionBelow and see if and when it can return a NULL pointer. Between your call to RegionBelow and your de-reference of regLo, perform a regLo == NULL check. You can do this with an assert or by throwing an exception (in C++). Most likely, if RegionBelow can return NULL on error, there will be some other method that you can use to determine what the error was and how to handle it. You will have to consult the source code or documentation for RegionBelow to find that information.