blob: 98c8b67757c564fceb2f6809e80d25b60ae523f0 [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* etchexcp.c -- exception objects native and boxed
*/
#include <stdio.h>
#include "etch_encoding.h"
#include "etchexcp.h"
#include "etch_global.h"
#pragma warning (disable:4996)
/**
* etch_throw()
* "throw" specified exception on specified object, meaning create an exception
* and store it in the specified object's return value.
* type: arbitrary exception type, not edited. if a known type and text is not
* supplied, attempt is made to locate and supply default text for that type.
* text: optional text descriptive of the exception.
* bitwise flags:
* ETCHEXCP_COPYTEXT: make a copy of supplied text and free it on destroy
* ETCHEXCP_FREETEXT: at destroy time, free the exception text memory
*/
objmask* etch_throw(objmask* obj, const excptype type, wchar_t* text, unsigned flags)
{
int result = 0;
if (!obj) return NULL;
if(!obj->result)
obj->result = new_etchresult(0, 0);
if (obj->result->exception)
destroy_exception(obj->result->exception);
obj->result->exception = new_exception(type, text, flags);
return obj;
}
/**
* etch_throwex()
* throw specified exception.
* same as etch_throw but with etch_result parameters specified as well.
*/
objmask* etch_throwex(objmask* obj, const excptype type, wchar_t* text,
unsigned flags, const int resultcode, const int reasoncode)
{
if (NULL == etch_throw(obj, type, text, flags)) return NULL;
obj->result->resultcode = resultcode;
obj->result->reasoncode = reasoncode;
return obj;
}
/*
* new_exception()
* instantiate a native exception object.
* this is not an etch object, it is a raw struct, see new_etch_exception()
* bitwise flags:
* ETCHEXCP_COPYTEXT: make a copy of supplied text and free it on destroy
* ETCHEXCP_FREETEXT: at destroy time, free the exception text memory
* ETCHEXCP_UNCHECKED: exception is unchecked
*/
etchexception* new_exception(const excptype type, wchar_t* text, const unsigned flags)
{
size_t numchars = 0;
etchexception* excp = etch_malloc(sizeof(etchexception), ETCHTYPEB_EXCEPTION);
memset(excp, 0, sizeof(etchexception));
excp->excptype = type;
excp->flags = flags;
if (text && !flags) /* if text without flags, default to copy text */
excp->flags = ETCHEXCP_COPYTEXT;
else
if(!text) /* if no text, get default text and clear copy and free flags */
{ text = default_excptext(type);
excp->flags &= ~(ETCHEXCP_FREETEXT | ETCHEXCP_COPYTEXT);
}
if (text) /* calculate byte length of text */
{ numchars = wcslen(text) + 1;
excp->textlen = sizeof(wchar_t) * numchars;
}
if (text && (flags & ETCHEXCP_COPYTEXT))
{ /* if asked to make a copy of the text, do so */
excp->excptext = etch_malloc(excp->textlen, ETCHTYPEB_STRING);
wcscpy_s(excp->excptext, numchars, text);
excp->flags |= ETCHEXCP_FREETEXT; /* indicate free on destroy */
}
else excp->excptext = text; /* ETCHEXCP_FREETEXT may or may not be set */
/* etch_malloc an ansi copy for display */
if (0 == etch_unicode_to_ansi (&excp->ansitext, excp->excptext))
excp->atxtlen = strlen(excp->ansitext);
if (type >= EXCPTYPE_CHECKED_START) /* mark checked excp as such */
excp->flags |= ETCHEXCP_CHECKED;
return excp;
}
/**
* destroy_etch_exception()
*/
int destroy_etch_exception(etch_exception* ee)
{
if (ee->refcount > 0 && --ee->refcount > 0) return -1;
if (!is_etchobj_static_content(ee))
destroy_exception(ee->value);
return destroy_objectex((objmask*) ee);
}
/**
* clone_etch_exception()
*/
etch_exception* clone_etch_exception (etch_exception* ee)
{
etch_exception* newobj = NULL;
etchexception* excp = ee? (etchexception*) ee->value: NULL;
if (!excp) return NULL;
newobj = new_etch_exception (excp->excptype, excp->excptext, ETCHEXCP_COPYTEXT);
return newobj;
}
/**
* new_etch_exception()
* constructor for wrapped exception
*/
etch_exception* new_etch_exception(const excptype type, wchar_t* text,
const unsigned flags)
{
etch_exception* newobj = (etch_exception*) new_object
(sizeof(struct etch_exception), ETCHTYPEB_EXCEPTION, CLASSID_EXCEPTION);
newobj->value = new_exception(type, text, flags);
newobj->destroy = destroy_etch_exception;
newobj->clone = clone_etch_exception;
return newobj;
}
/* builtin exception text */
const wchar_t* excptext_excp = L"etch";
const wchar_t* excptext_io = L"I/O";
const wchar_t* excptext_auth = L"authorization";
const wchar_t* excptext_runtime = L"etch runtime";
const wchar_t* excptext_nullptr = L"null pointer";
const wchar_t* excptext_arg = L"illegal argument";
const wchar_t* excptext_unsupop = L"unsupported operation";
const wchar_t* excptext_internal= L"internal error";
const wchar_t* excptext_notfound= L"not found";
/*
* default_excptext()
* find and return default text for exception type
*/
wchar_t* default_excptext(const excptype type)
{
wchar_t* text = NULL;
switch(type)
{
case EXCPTYPE_GENERIC: text = (wchar_t*) excptext_excp; break;
case EXCPTYPE_ETCHRUNTIME: text = (wchar_t*) excptext_runtime; break;
case EXCPTYPE_ETCHAUTH: text = (wchar_t*) excptext_auth; break;
case EXCPTYPE_IO: text = (wchar_t*) excptext_io; break;
case EXCPTYPE_NULLPTR: text = (wchar_t*) excptext_nullptr; break;
case EXCPTYPE_ILLEGALARG: text = (wchar_t*) excptext_arg; break;
case EXCPTYPE_UNSUPPORTEDOP: text = (wchar_t*) excptext_unsupop; break;
case EXCPTYPE_INTERNALERR: text = (wchar_t*) excptext_internal;break;
case EXCPTYPE_NOTFOUND: text = (wchar_t*) excptext_notfound;break;
}
return text;
}
/*
* destroy_exception()
* free memory for specified native exception object
*/
void destroy_exception (etchexception* excp)
{
if(!excp) return; /* text may be static or freed elsewhere */
if (excp->flags & ETCHEXCP_FREETEXT)
{ ETCHOBJ_FREE(excp->excptext); /* free exception text */
}
/* always allocated in ctor, never passed in */
ETCHOBJ_FREE(excp->ansitext);
etch_free(excp); /* free exception wrapper */
}
/*
* get_excpobj()
* create and return an etchobject for the sole purpose of returning an exception.
* we might use this functionality where our method returns an object which we have
* not yet created, we edit parameters, find them wanting, and wish to throw an
* exception, and need an object in which to return the exception.
*/
objmask* get_excpobj (int objsize, short obj_type, short class_id,
excptype xcptype, wchar_t* xcptext, unsigned flags)
{
objmask* newobj = new_object(objsize, obj_type, class_id);
newobj->is_null = TRUE;
etch_throw(newobj, xcptype, xcptext, flags);
return newobj;
}
/*
* get_excptype()
* return exception type given result code
*/
excptype get_excptype(const results result)
{
excptype xtype;
if (result >= 0) return EXCPTYPE_NONE;
switch(result)
{
case ETCHRESULT_EXCPERR_IO: xtype = EXCPTYPE_IO; break;
case ETCHRESULT_EXCPERR_BADARG: xtype = EXCPTYPE_ILLEGALARG; break;
case ETCHRESULT_EXCPERR_NULLPTR: xtype = EXCPTYPE_NULLPTR; break;
case ETCHRESULT_EXCPERR_BADOP: xtype = EXCPTYPE_UNSUPPORTEDOP; break;
default: xtype = EXCPTYPE_GENERIC;
}
return xtype;
}
/*
* excp_tostring
* returns unicode string representation of exception
* caller owns returned buffer
*/
wchar_t* excp_tostring (etchexception* excp)
{
wchar_t *newbuf = NULL;
const wchar_t *x = L"exception ", charlen = sizeof(wchar_t), *space = L" " ;
const size_t xbytelen = wcslen(x) * charlen;
wchar_t* deftext = default_excptext(excp->excptype);
const size_t deftextbytelen = deftext?
wcslen(deftext) * charlen: 0;
const size_t excptextbytelen = excp->excptext?
wcslen(excp->excptext) * charlen: 0;
wchar_t* excptext
= excptextbytelen? excp->excptext:
deftextbytelen? deftext:
L"generic";
const size_t textbytelen = wcslen(excp->excptext) * charlen;
const size_t buflen = xbytelen + textbytelen + (3 * charlen);
newbuf = etch_malloc(buflen, ETCHTYPEB_BYTES);
memset(newbuf, 0, buflen);
wcscat(newbuf, excptext); /* e.g. "null pointer" */
wcscat(newbuf, space);
wcscat(newbuf, x); /* "exception " */
return newbuf;
}
/*
* excp_tostringx
* returns ascii string representation of exception
* caller owns returned buffer
*/
char* excp_tostringx(etchexception* excp)
{
char* ansibuf = NULL;
wchar_t* unibuf = excp_tostring(excp);
const int result = etch_unicode_to_ansi(&ansibuf, unibuf);
etch_free(unibuf);
return ansibuf;
}
/*
* is_catch_exception()
* "catch" exception defined by result code, returning FALSE if no exception.
* the etchobject wrapping the exception is returned in the out parameter.
* this object is created if no such object is passed.
*/
boolean is_catch_exception(objmask* obj, const int result, objmask** outobj)
{
objmask* excpobj = throw_exception(obj, result);
if (is_exception(excpobj))
{
if (outobj) *outobj = excpobj;
return TRUE;
}
return FALSE;
}
/*
* is_catch()
* "catch" exception defined by result code, returning FALSE if no exception.
* the etchobject wrapping the exception is returned in the out parameter.
* this object is created if no such object is passed.
*/
boolean is_catch(objmask* obj, const int result, const int objtype, objmask** outobj)
{
objmask* excpobj = obj?
throw_exception(obj, result):
throw_exception_from(objtype, result);
if (is_exception(excpobj))
{
if (outobj) *outobj = excpobj;
return TRUE;
}
return FALSE;
}
/*
* catch_exception()
* return an etchobject containing the exception mapping to the specified
* result code. an anonymous object is generated if none is supplied.
*/
objmask* catch_exception(objmask* obj, const int result)
{
return throw_exception(obj, result);
}
/*
* throw_exception()
* return an etchobject of the specified type containing the exception mapping to
* the specified result code. an anonymous object is generated if none is supplied.
*/
objmask* throw_exception(objmask* obj, const int result)
{
excptype xtype = get_excptype(result);
if (obj == NULL)
obj = get_excpobj(sizeof(objmask), ETCHTYPEB_UNDEFINED, 0, xtype, NULL, 0);
if (xtype != EXCPTYPE_NONE)
etch_throw(obj, xtype, NULL, 0);
return obj;
}
/*
* throw_exception_from()
* generate and return an etch object of the specified type containing the exception
* mapping to the specified result code.
*/
objmask* throw_exception_from(const short obj_type, const int result)
{
objmask* obj = NULL;
excptype xtype = get_excptype(result);
obj = get_excpobj(sizeof(objmask), obj_type, 0, xtype, NULL, 0);
return obj;
}
/*
* throw_from()
* generate and return an etchobject of the specified type
* containing the specified exception
*/
objmask* throw_from(excptype xtype, const short obj_type, wchar_t* text, unsigned flags)
{
return get_excpobj(sizeof(objmask), obj_type, 0, xtype, text, flags);
}
/*
* etch_rethrow
* throw an exception from an existing exception
*/
objmask* etch_rethrow(objmask* target, objmask* source)
{
etchexception* excp = NULL;
if (target != NULL)
excp = get_exception(source);
if (excp == NULL) return throw_from(EXCPTYPE_INTERNALERR, target->obj_type, NULL, 0);
return etch_throwex(target, excp->excptype, excp->excptext, excp->flags,
source->result->resultcode, source->result->reasoncode);
}
/*
* get_etch_exception_from()
* returns the etch_exception object if any from the specified etch object.
* @return a non-disposable reference to the etch_exception object, or NULL.
*/
etch_exception* get_etch_exception_from (objmask* obj)
{
if (obj && (obj->obj_type == ETCHTYPEB_EXCEPTION))
return (etch_exception*) obj;
return NULL;
}
/*
* get_exception_from
* returns the unwrapped etchexception if any from the specified etch object.
*/
etchexception* get_exception_from (objmask* obj)
{
if (NULL == obj) return NULL;
if (obj->obj_type == ETCHTYPEB_EXCEPTION)
return (etchexception*) ((etch_exception*) obj)->value;
if (obj->result) return obj->result->exception;
return NULL;
}
/*
* get_exception_from()
* returns a disposable exception object based on the exception contained in
* the specified object.
*/
etch_exception* new_etch_exception_from (objmask* obj)
{
etch_exception* x = NULL;
etchexception* excp = get_exception_from (obj);
if (excp)
x = new_etch_exception (excp->excptype, excp->excptext, ETCHEXCP_COPYTEXT);
return x;
}
/*
* verifyx()
* test specified object for specified type, throw specified exception if not
*/
objmask* verifyx(objmask* obj,
const unsigned short objtype, const unsigned short classid, excptype xtype)
{
if(!obj)
obj = throw_from(xtype, objtype, NULL, 0);
else
if ((objtype != 0 && obj->obj_type != objtype)
|| (classid != 0 && obj->class_id != classid))
etch_throwex(obj, xtype, NULL, 0, -1, 0);
return obj;
}