/* odmjni100.cpp 0.20                UTF-8                   dh:2007-03-27
 *
 *
 *                 IMPLEMENT THE NATIVE METHODS OF ODMJNI100
 *                 *****************************************
 *
 * This is the C++ Language implementation of the native-method DLL
 * for odmjni100.  It is developed progressively in line with the
 * expansion of info.odma.odmjni100 OdmJniBind class support for
 * different ODMA operations.
 *
 * We have native methods for several OdmJni classes, including OdmJniBind
 * and OdmJniVew, but we will still have a single DLL.  This maximizes
 * on the statically-bound C++ DLL runtime for the native methods and the
 * OdmNative libraries.  We also reduce the amount of DLL loading.
 */



                /* 1. DEPENDENCIES *
                   *************** *
                   */


#include <windows.h>
    /* For native interfaces and COM-related definitions. */

#include <jni.h>
    /* For the standard JNI interface.  This interface will be the
       C++ version when building odmjni100.dll.
       */

#include "jawt.h"
#include "jawt_md.h"
    /* For the access to native substrate of AWT objects */

#include "Odma32types100.h"
    /* For ODMA-specific types and values that we rely on and produce. */

#include "odmjni100x.h"
    /* Rely on the annotated cumulatively-updated header. */

#include "OdmNative100.hpp"
    /* For functions and classes of OdmNative and IodmNative. */

#include "OdmWorking100.hpp"
    /* For the IID and the interface pointer, basically, as well as
       usages adopted from OdmNative100 test\Check05 and Check06 */

#include "OdmPending100.hpp"
    /* For the IID and the interface pointer here too, as well as
       usages adopted from OdmNative 100 test\Check06 */



            /* 2. ODMJNIBIND NATIVE UTILITY METHODS *
               ************************************ *
               */


JNIEXPORT
    jint JNICALL
         Java_info_odma_odmjni100_OdmJniBind_jniVersion
             (  JNIEnv *pIenv,       /* JNI environment interface */
                jclass pThisClass    /* not used */
                )

{   /* Return the JNI Version Number m.n, coded as 0x000m000n.
       pIenv is a ppv. That is, JNIEnv is a pv, and what's passed
       in is a ppv.  In C++, Ienv is a class with interface methods.
       */

    return pIenv->GetVersion();

    } /* jniVersion */



JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniBind_holdNativeInterface
            (   JNIEnv *pIenv,      /* not used */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* A disguised Native pointer */
                )
{   /* This is a standard IUnknown::AddRef() operation.  It could
       also be a QueryInterface as a way of also normalizing the
       interface, but we will go for speed instead. */

    if (rIodmNative == (rIodmNative & 0x1F))
         return 0;
            /* XXX: Simply ignore non-pointer values. */

    ((IUnknown *) rIodmNative) -> AddRef();

    return rIodmNative;

    } /* holdNativeInterface */



JNIEXPORT
    void JNICALL
        Java_info_odma_odmjni100_OdmJniBind_freeNativeInterface
            (   JNIEnv *pIenv,      /* not used */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* a disguised Native pointer */
                )
{   /* Perform a standard IUnknown::Release() using the disguised
       interface reference we are handed.
       */

    if (rIodmNative == (rIodmNative & 0x1F)) return;
            /* XXX: Simply ignore non-pointer values. */

    ((IUnknown *) rIodmNative) -> Release();

    } /* freeNativeInterface */



                /* 3. INTERNAL NATIVE-SUPPORT FUNCTIONS *
                   ************************************ *
                   */


static const IID IID_IodmApplication100 = IID_IodmApplication100_ ;
    /* IodmApplication100 IID of the current header level. */

static const IID IID_IodmWorking100 = IID_IodmWorking100_ ;
    /* IodmWorking100 IID of the current header definition/contract */

static const IID IID_IodmPending100 = IID_IodmPending100_ ;



static jstring OdmCp2jString(JNIEnv *pIenv,
                             LPCSTR pszOdmString)

{   /* CONVERT ODMA CODE-PAGE CHARACTER STRING TO JAVA STRING

       Many strings from ODMA are presumed to be code-page dependent
       single-byte character encodings.  This function takes one of
       those strings and converts it to a Unicode java.lang.String that
       can be used in the Java application.

       The definition of the MultiByteToWideChar native Win32 function
       is found at <http://msdn2.microsoft.com/en-us/ms776413.aspx>.
       It can be found in the VS2005 and Platform SDK Help as well.
       */

    #define SIZE_ALLOWED (301)
        /* Our padded buffer allowance */

    const int
        sizeNeeded
            = MultiByteToWideChar
                (  CP_ACP, 0,
                   pszOdmString, -1,
                   NULL, 0
                   );

            /* Find out how many UTF-16 codes are needed for the
               characters at pszOdmString.  This will include a terminal
               null (L'\u0000') character.
               */

    if (sizeNeeded > SIZE_ALLOWED)
         return NULL;

    WCHAR theUChars[SIZE_ALLOWED+2] = {L'\0'};
            /* Make a little safety provision on the end. */

    int sizeUsed
            = MultiByteToWideChar
                (  CP_ACP, 0,
                   pszOdmString, -1,
                   theUChars, SIZE_ALLOWED+1
                   );
    if (sizeUsed == 0)
         return NULL;
            /* Uh Oh! */

    if (theUChars[sizeUsed-1] == L'\0')
         --sizeUsed;
            /* Don't give the null to Java */

    return pIenv -> NewString( (jchar *) theUChars, sizeUsed);


    } /* OdmCp2jString */



static BOOL OdmJString2Cp(    JNIEnv *pIenv,        /* JNI Environment */
                             jstring theJString,    /* Java Unicode */
                               LPSTR pszOdmString,  /* Buffer for single-
                                                       byte translation */
                                WORD sizeOdmString  /* bytes allowed in
                                                       pszOdmString[] */
                             )

{   /* Convert the Java String to a faithful null-terminated octet string.
       If it is not possible to produce a faithful translation in the
       available space, FALSE is returned.

       XXX: The WideCharToMultibyte Win32 function is documented in the
            Platform SDK and VS2005 Help system.  It is documented on-line
            at <http://msdn2.microsoft.com/en-us/ms776406.aspx>.
       */

    if (theJString == NULL) return FALSE;

    const jchar *pWideChars
                    = pIenv -> GetStringChars(theJString, NULL);

    if (pWideChars == NULL) return FALSE;

    const jsize nWideChars
                    = pIenv -> GetStringLength(theJString);

    BOOL failures = TRUE;

    int nChars = WideCharToMultiByte
                    (   CP_ACP,               /* Use ANSI Code Page only */
                        WC_NO_BEST_FIT_CHARS, /* Must translate perfectly */
                        (LPCWSTR) pWideChars, nWideChars,
                                              /* the actual input */
                        pszOdmString, sizeOdmString,
                                              /* available output buffer */
                        NULL,                 /* Use standard default */
                        &failures             /* Set if untranslatables */
                        );

                    /* XXX: Because we are always using Windows ANSI Code
                            pages, we do not expect to produce any of the
                            ISO 2022, Chinese GB codes, or ISCII codes for
                            which translation-failure detection is not
                            provided.  Those would fail with the above
                            WideCharToMultiple parameters.  They are also
                            out of bounds for ODMA 1.0 functionality.
                            */

    pIenv -> ReleaseStringChars(theJString, pWideChars);

    return (nChars != 0 && !failures);

    } /* OdmJString2Cp */



static HWND findHWND(   JNIEnv *pIenv,  /* The JNI Environment */
                       jobject jWindow  /* A java.awt.Window object */
                       )

{   /* FIND THE JAVA APPLICATION'S NATIVE WINDOWS HANDLE

       Use JNI environment magic to find the Window Handle that goes
       with a supplied java.awt.Window parameter.  This should be the
       main window of the Java application.  We want its Windows handle
       so that it can be communicated to each DMS for naming in modal
       dialogs.  This is a private function within odmjni100.cpp.

       This code relies on the JDK 1.5 include files Jawt.h and, for
       the JAWT_Win32DrawingSurfaceInfo definition, Jawt_md.h of the
       Sun Microsystem JDK 1.5.0_09 include\Win32 directory.  The code
       is based on the example in Jawt.h and on inspection of similar
       programs.

       XXX: This version finds jawt.dll dynamically only when a jWindow
            is supplied.  It depends on jawt.dll and anything it depends on
            being either in the same directory as the java image that was
            loaded or being on the process environment search PATH.  It
            also depends on the DLL's name of the entry point being known
            and stable.
       */

    const char jawtDLL[] = "jawt.dll";
        /* name of the JAWT library */

    const char jawtName[] = "_JAWT_GetAWT@8";
        /* XXX: This is not a defined entry point or part of the defined
                API.  I fished it out of the jawt.dll file by viewing the
                hex to find out how the JAWT_GetAWT entry point is named.
                If there is a change, this code must change too.
           */


    HMODULE jawt = LoadLibraryA(jawtDLL);

    if (jawt == NULL) return NULL;
        /* We're not getting anywhere. */

    typedef jboolean (JNICALL *pfGetAWT)(JNIEnv* env, JAWT* awt);
        /* for jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt)
           as declared in jawt.h of the JDK /include files. */

    pfGetAWT
        getAWT = (pfGetAWT) GetProcAddress(jawt, jawtName);

    BOOL proceedOK = (getAWT != NULL);

    JAWT awt;
        /* Build and initialize an AWT structure for coordination
           with the AWT machinery. */
    awt.version = JAWT_VERSION_1_3;
        /* We do not require any later capabilities. */

    if (proceedOK)
         proceedOK = ((getAWT)(pIenv, &awt) != JNI_FALSE);


    JAWT_DrawingSurface *ds = NULL;

    if (proceedOK)
         {  ds = awt.GetDrawingSurface(pIenv, jWindow);
            proceedOK = (ds != NULL);
            }

    if (!proceedOK)
         {  /* We have failed to obtain the necessary setup.
               There is no drawing surface to free, but the
               DLL should be surrendered. */
            FreeLibrary(jawt);
            return NULL;
            }

    proceedOK = ((ds -> Lock(ds)) & JAWT_LOCK_ERROR) == 0;
        /* If we don't Get the lock, we will not attempt to get the
           other information. */

    HWND hWindow = NULL;

    if (proceedOK)
    {   JAWT_DrawingSurfaceInfo *dsi = ds -> GetDrawingSurfaceInfo(ds);

        hWindow =
            ( (JAWT_Win32DrawingSurfaceInfo *) dsi -> platformInfo) -> hwnd;

        ds -> FreeDrawingSurfaceInfo(dsi);

        ds -> Unlock(ds);
        }

    awt.FreeDrawingSurface(ds);

    FreeLibrary(jawt);

    return hWindow;

    } /* findHWND */



                /* 4. PRIVATE ODMJNIBIND STATIC NATIVE METHODS *
                   ******************************************* *
                   */

JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniBind_getIodmWinNative
            (   JNIEnv *pIenv,      /* JNI environment interface */
                jclass pThisClass,  /* not used */
               jstring jAppId,      /* The Application ID */
               jobject jWindow     /* The application's main Window */
               )

{   /* This procedure binds an IodmApplication100 interface using
       the OdmBindNative100 function.
       */

    HWND hParent = NULL;

    if (jWindow != NULL)
         {  /* Oh goodie, let's get the HWND of jWindow
               if we can. */
            hParent = findHWND(pIenv, jWindow);
            }

    const char *pszAppId
        = pIenv -> GetStringUTFChars(jAppId, NULL);
            /* Get pointer to the UTF (presumably-ASCII string.
               XXX: We let OdmBindNative100 check the string for
               us.  It should have been checked by OdmJniBind before
               we got to here. */

    IUnknown *pIUnk = NULL;
            /* receptacle for the pIodmNative returned from
               OdmBindNative100.  We ask for IodmApplication100
               here so that other code doesn't have to query
               interface and we have a check on the proper version
               by IID match-up.
               */

    HRESULT rc = OdmBindNative100(  pszAppId, hParent,
                                    IID_IodmApplication100,
                                    (void **) &pIUnk
                                    );
            /* If everything is working, we get an interface that is
               reserved for us (and hence our caller). */

    pIenv -> ReleaseStringUTFChars(jAppId, pszAppId);
            /* Let go of the AppID UTF - we don't need it any longer. */

    if (SUCCEEDED(rc)) return (jlong) pIUnk;
            /* Hand out the disguised pIUnk that we succeeded in getting.*/

    return (jlong) ODM_E_FAIL;
            /* Anything else produces a low-numbered value. */

    } /* getIodmWinNative */



JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniBind_getIodmNative
            (   JNIEnv *pIenv,      /* JNI environment interface */
                jclass pThisClass,  /* not used */
               jstring jAppId      /* The Application ID */
               )

{   /* Perform Native100 setup with default for application Window. */

    return
        Java_info_odma_odmjni100_OdmJniBind_getIodmWinNative
            ( pIenv, pThisClass, jAppId, NULL);

    } /* getIodmNative */







                /* 5. PRIVATE ODMJNIAPP STATIC NATIVE METHODS *
                   ****************************************** *
                   */



JNIEXPORT
    jboolean JNICALL
        Java_info_odma_odmjni100_OdmJniApp_checkViewOnly
            (   JNIEnv *pIenv,      /* not used */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* An IodmWorking100 reference */
                )

{   /* Obtain directly in the IodmWorking100 interface.
       */

    return ((IodmWorking100 *) rIodmNative) -> viewOnly();

    } /* checkViewOnly */



JNIEXPORT
    jboolean JNICALL
        Java_info_odma_odmjni100_OdmJniApp_hasConMan
            (   JNIEnv  *pIenv,     /* not used */
                jclass  pThisClass, /* not used */
                 jlong  rIodmNative /* a disguised Native pointer */
                )
{   /* Perform IodmApplication100::hasConMan() and that's all
       we need. */

    /* XXX: Technically, we should do a query interface here, but we
       assert that we have IodmApplication100 every time this
       method is called.
       */

    return ((IodmApplication100 *) rIodmNative) -> hasConMan();


    } /* hasConMan */



JNIEXPORT
    jboolean JNICALL
        Java_info_odma_odmjni100_OdmJniApp_hasDefaultDMS
            (   JNIEnv *pIenv,      /* not used */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* a disguised Native pointer */
                )
{   /* Perform IodmApplication100::hasDefaultDMS() and we're done.
       */

    return ((IodmApplication100 *) rIodmNative) -> hasDefaultDMS();

    } /* hasDefaultDMS */


JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniApp_jniNewDoc
            (   JNIEnv *pIenv,          /* used to convert the string */
                jclass pThisClass,      /* not used */
                 jlong rIodmNative,     /* disguised pIodmApplication100 */
               jstring jDocFormatName   /* validated Document Format Name */
               )

{   /* Perform everything needed to get to an IodmPending for a new
       document or else a result code that provides for alternative
       action by the OdmJniApp acceptNewDocument method.

       This implementation follows the lines of the implementation
       in OdmNative100\test\Check06\CheckNew.cpp.  That provides the
       essential functionality.

       XXX: This implementation is not called if rIodmNative is NULL (0).
            The DocFormatName is expected to be prevalidated and no
            invalid values are delivered to this implementation.
       */

    IodmApplication100 *pIodmApp = (IodmApplication100 *) rIodmNative;

    const char *pszDocFormat
        = pIenv -> GetStringUTFChars(jDocFormatName, NULL);
            /* We must be careful to give this back before any exit
               from this implementation */

    char theDocId[ODM_DOCID_MAX+2] = {'\0'};
            /* Buffer for any returned Document ID, with a little
               extra padding.
               */

    ODMSTATUS odmResult = pIodmApp -> startNewDoc(theDocId, pszDocFormat);

    pIenv -> ReleaseStringUTFChars(jDocFormatName, pszDocFormat);
            /* We have no use below here. */

    if (odmResult != ODM_SUCCESS)
         return (jlong) odmResult;
                /* There's nothing more to do if there's no Document ID */

    char theDocLoc[ODM_FILENAME_MAX+20] = {'\0'};
        /* Where we store our version of the Document Location */


    odmResult = pIodmApp -> openDoc(theDocId, theDocLoc, FALSE);
                /* The ID was from a startNewDoc, so this should work. */

    if (odmResult != ODM_SUCCESS)
         return (jlong) odmResult;

    IodmPending100 *pIodmPend = NULL;

    HRESULT rc = pIodmApp -> makePendingDocument
                                    (  theDocId, theDocLoc,
                                       IID_IodmPending100,
                                       (void**) &pIodmPend
                                       );

    if (SUCCEEDED(rc))
         return (jlong) pIodmPend;

    return (jlong) ODM_E_FAIL;


    } /* jniNewDoc */



JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniApp_selectDoc
            (   JNIEnv *pIenv,      /* not used */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* a disguised Native pointer */
                )
{   /* Use IodmApplication100::selectDocID to connect to the DMS and
       return the selection from the user.

       We return either an ODMSTATUS value or we return an
       IodmWorking100 interface reference.

       This implementation is based on the OdmNative100 test Check05 0.07
       approach.  When OdmNative100 is refactored to to use cohesive
       methods, this function will become much simpler.
       */

    if (rIodmNative == (rIodmNative & 0x1F)) return 0;
            /* XXX: Simply ignore non-pointer values. */

    IodmApplication100 *pIodmApp = (IodmApplication100 *) rIodmNative;
            /* Use the interface pointer we are given.
               XXX: We do not QueryInterface because we trust the caller
                    to provide the correct goodies.
               */

    char theDocId[ODM_DOCID_MAX+2]={'\0'};
            /* FIXME: We need serious buffer over-run
                      protection here, although when we refactor this will
                      all be handled by the IodmAppication100
                      implementation..
               */

    BOOL viewMode = TRUE;
            /* FIXME: We need a better approach to this when we allow
               other cases.  It may be trickier to accomplish this
               when the DMS may push back on what we want.
               */

    ODMSTATUS rc = pIodmApp -> selectDocID(theDocId, &viewMode);

    if (rc != ODM_SUCCESS)
         switch (rc)
         {  /* Stop now with the failure case we have */

            case      ODM_E_FAIL:
            case    ODM_E_CANCEL:
            case ODM_E_APPSELECT:
                        return (jlong) rc;
            default:    return (jlong) ODM_E_FAIL;
            }

    /* We have a good Document ID.  Now we need to see if we can
       open the document.

       FIXME: Below here, everything can be common between selectDoc
              and jniKnownDocument.  This can be dealt with after the
              general refactoring of OdmNative100.
       */

    char theDocLoc[ODM_FILENAME_MAX+20] = {'\0'};

    rc = pIodmApp -> openDoc(theDocId, theDocLoc, viewMode);
            /* The select succeeded, so the open should work */

    if (rc != ODM_SUCCESS)
         return (jlong) ODM_E_FAIL;

    IodmWorking100 *pIodmWrk = NULL;

    HRESULT hr = pIodmApp -> makeWorkingDocument
                                (  theDocId, theDocLoc, viewMode,
                                   IID_IodmWorking100,
                                   (void**) &pIodmWrk
                                   );

    if (SUCCEEDED(hr))
         return (jlong) pIodmWrk;
    else return (jlong) ODM_E_FAIL;


    } /* selectDoc */


JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniApp_jniKnownDocument
            (   JNIEnv *pIEnv,      /* used to get the string content */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative, /* a disguised native pointer */
               jstring jDocId       /* The Java docId string */
               )

{   /* Provide a version of selectDoc that works with a Known Document,
       much like the way openKnownDocument is based on chooseDocument.

       In this case, the verification of jDocId is accomplished by
       verifying that the translation to the default Windows ANSI code
       page succeeds and that the string does not exceed the permitted
       length.

       We return either an ODMSTATUS value or we return an
       IodmWorking100 interface reference.

       XXX: It is assumed that all other filtering of the docId has been
            performed in the calling openKnownDocument implementation.

       This implementation is based on the OdmNative100 test Check05 0.07
       approach.  When OdmNative100 is refactored to to use cohesive
       methods, this function will become much simpler.
       */

    if (rIodmNative == (rIodmNative & 0x1F)) return 0;
            /* XXX: Simply ignore non-pointer values. */

    IodmApplication100 *pIodmApp = (IodmApplication100 *) rIodmNative;
            /* Use the interface pointer we are given.
               XXX: We do not QueryInterface because we trust the caller
                    to provide the correct goodies.
               */

    char theDocId[ODM_DOCID_MAX+2]={'\0'};
            /* FIXME: We need serious buffer over-run
                      protection here, although when we refactor this will
                      all be handled by the IodmAppication100
                      implementation..
               */

    BOOL viewMode = FALSE;
            /* FIXME: We always treat as editable.  We might want to
                      provide a choice of openKnownDocument cases in
                      openKnownDocument, but not now.  This can be
                      completely additive if we go about it properly.
               */

    /* Filter the Document ID and see if it is acceptable.  If it is not,
       we return with ODM_E_FAIL without going any farther.  Otherwise,
       we have the desired Document ID in theDocId.
       */

    BOOL proceedOK = OdmJString2Cp(pIEnv, jDocId, theDocId, ODM_DOCID_MAX);

    if (!proceedOK)
         return (jlong) ODM_E_FAIL;

    /* Now that we are satisfied that the Document ID is well-formed and
       we have its translation, we attempt to open content for that
       document.
       */

    char theDocLoc[ODM_FILENAME_MAX+20] = {'\0'};

    ODMSTATUS rc = pIodmApp -> openDoc(theDocId, theDocLoc, viewMode);
        /* XXX: This code depends on the openDoc implementation failing if
                it cannot establish a working DMS.  It must protect itself
                and fail properly, so we don't have to.
           */

    if (rc != ODM_SUCCESS)
         return (jlong) ODM_E_FAIL;

    IodmWorking100 *pIodmWrk = NULL;

    HRESULT hr = pIodmApp -> makeWorkingDocument
                                (  theDocId, theDocLoc, viewMode,
                                   IID_IodmWorking100,
                                   (void**) &pIodmWrk
                                   );

    if (SUCCEEDED(hr))
         return (jlong) pIodmWrk;
    else return (jlong) ODM_E_FAIL;


    } /* jniKnownDocument */





                /* 6. PRIVATE ODMJNIPEND STATIC NATIVE METHODS *
                   ******************************************* *
                   */


JNIEXPORT
    jstring JNICALL
        Java_info_odma_odmjni100_OdmJniPend_jniPendLoc
            (   JNIEnv *pIenv,      /* Used for string conversion */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* rIodmPending100 */
                )
{   /* Deliver the document location for delivering initial content
       for the pending document.  This is modelled on the OdmJniView
       jniDocLoc method.
       XXX: The OdmJniPend.docSubmissionLocation method will not call
            this implementation when rIodmNative is NULL (0).
       */

     return OdmCp2jString(  pIenv,
                            ((IodmPending100 *) rIodmNative)
                                -> docLocation()
                            );
            /* Returning the translation from the ANSI Code Page
               to Unicode.

               XXX: This is a concern.  It is not clear this is the
                    right thing for operation between Java and the
                    underlying file system, especially if the use of
                    OEM Code Pages is presumed somewhere.
               */

     #if 0
     /* Use this version for must-be-ASCII docLocations. */
     return pIenv -> NewStringUTF
                        (  ((IodmPending100 *) rIodmNative)
                                -> docLocation()
                           );
     #endif


    } /* jniPendLoc */



JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniPend_jniCommitContent
            (   JNIEnv *pIenv,      /* not used */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* rIodmPending100 */
                )

{   /* Implement OdmJniPend.commitContent()'s request of an IodmWorking100
       interface for the committed content.  Any return of a non-reference
       is treated as an ODM_E_FAIL response.
       XXX: The OdmJniPend.commitContent method will not call this
            implementation when rIodmNative is NULL (0).
       */

    IUnknown *pIUnk = NULL;
        /* The provisional pointer */

    IodmWorking100 *pIwork = NULL;

    HRESULT rstatus
                = ((IodmPending100 *) rIodmNative) -> commitContent(&pIUnk);

    if (!SUCCEEDED(rstatus))
         return (jlong) ODM_E_FAIL;

    rstatus = pIUnk -> QueryInterface(  IID_IodmWorking100,
                                        (void **) &pIwork
                                        );

    if (!SUCCEEDED(rstatus))
         return (jlong) ODM_E_FAIL;

    pIUnk -> Release();

    return (jlong) pIwork;


    } /* jniCommitContent */



                /* 6. PRIVATE ODMJNIVIEW STATIC NATIVE METHODS *
                   ******************************************* *
                   */

JNIEXPORT
    jstring JNICALL
        Java_info_odma_odmjni100_OdmJniView_jniDocID
            (   JNIEnv *pIenv,      /* Used to make string */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* an IodmWorking100 reference */
                )

{   /* Take the IodmWorking100::docID() right through to conversion
       to Java Unicode.
       */

    return OdmCp2jString(  pIenv,
                           ((IodmWorking100 *) rIodmNative)
                                  -> docID()
                           );
            /* Translate from the ANSI code-page to Unicode.  This
               may not be ideal, especially if the string is used
               wherever it might be interpreted as the OEM code page.

               XXX: We really do want to force some sort of portability
                    on the Document IDs, hoping that the DMS implementations
                    do not use arbitrary filename type strings.
               */

    #if 0
    return pIenv -> NewStringUTF
                        (  ((IodmWorking100 *) rIodmNative)
                                -> docID()
                           );

    /* XXX: This approach depends on the ODMA Document ID being limited
            to ISO 646/ASCII Character codes that are one-to-one
            equivalent to Unicode code points.
       */
    #endif

    } /* jniDocID */




JNIEXPORT
    jstring JNICALL
        Java_info_odma_odmjni100_OdmJniView_jniDocLoc
            (   JNIEnv *pIenv,      /* Used to make string */
                jclass pThisClass,  /* Not used */
                 jlong rIodmNative  /* an IodmWorking100 reference */
                 )

{   /* Take the IodmWorking100::docLocation() right through to conversion
       to Java Unicode.
       */

     return OdmCp2jString(  pIenv,
                            ((IodmWorking100 *) rIodmNative)
                                -> docLocation()
                            );
            /* Returning the translation from the ANSI Code Page
               to Unicode.

               XXX: This is a concern.  It is not clear this is the
                    right thing for operation between Java and the
                    underlying file system, especially if the use of
                    OEM Code Pages is presumed somewhere.  However this
                    is handled with hardening, it must be the same here
                    and in jniPendLoc.
               */

    #if 0
    return pIenv -> NewStringUTF
                        (  ((IodmWorking100 *) rIodmNative)
                                -> docLocation()
                           );

    /* XXX: This approach depends on the ODMA Document Location being
            limited to ISO 646/ASCII Character codes that are one-to-one
            equivalent to Unicode code points.
       */
    #endif

    } /* jniDocLoc */


JNIEXPORT
    jstring JNICALL
        Java_info_odma_odmjni100_OdmJniView_jniDocProp
            (   JNIEnv *pIenv,      /* Used to make string */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative, /* an IodmWorking100 reference */
                  jint propNum      /* item number of desired property */
                )

{   /* Use OdmWorking100::docProperty to obtain the item, if available. */

    char thePropVal[300] = {'\0'};
            /* Provide generous storage for the string */

    ODMSTATUS rc = ((IodmWorking100 *) rIodmNative)
                    -> docProperty(propNum, thePropVal, sizeof(thePropVal));

    if (rc != ODM_SUCCESS || thePropVal[sizeof(thePropVal)-1] != '\0')
         return (jstring) NULL;
        /* If we fail or if the buffer is not null-terminated, bail out. */

    return OdmCp2jString(pIenv, thePropVal);

    } /* jniDocProp */



JNIEXPORT
    jlong JNICALL
        Java_info_odma_odmjni100_OdmJniView_jniToNewDoc
            (   JNIEnv *pIenv,      /* Used to convert the string */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative, /* an IodmWorking100 reference */
               jstring jDocFormat   /* format desired for the new document
                                       */
               )
{   /* Use the IodmWoring100 methods for deriveNewDoc followed by
       an openPendingDoc to bring forth a ready-for-content Pending
       Document.  This implementation logic follows the implementation
       of acceptNewDocument vary closely, except for choice of methods.
       XXX: This function is not called without a valid rIodmNative
            and a validated jDocFormat string.
       FIXME: We are skating around the second precondition and
              that must be repaired in OdmJniView ASAP.
       */

    IodmWorking100 *pIodmWork = (IodmWorking100 *) rIodmNative;

    const char *pszDocFormat
        = pIenv -> GetStringUTFChars(jDocFormat, NULL);
            /* We must be careful to give this back before any exit
               from this implementation */

    char theDocId[ODM_DOCID_MAX+2] = {'\0'};
            /* Buffer for any returned Document ID, with a little
               extra padding.
               */

    ODMSTATUS odmResult = pIodmWork -> deriveNewDoc(pszDocFormat,
                                                    theDocId );

    pIenv -> ReleaseStringUTFChars(jDocFormat, pszDocFormat);
            /* We have no use below here. */

    if (odmResult != ODM_SUCCESS)
         return (jlong) odmResult;
                /* There's nothing more to do if there's no Document ID */

    IodmPending100 *pIodmPend = NULL;

    HRESULT rc = pIodmWork -> openPendingDoc
                                    (  theDocId,
                                       IID_IodmPending100,
                                       (void**) &pIodmPend
                                       );

    if (SUCCEEDED(rc))
         return (jlong) pIodmPend;

    return (jlong) ODM_E_FAIL;


    } /* jniToNewDoc */



                /* 7. PRIVATE ODMJNIWORK STATIC NATIVE METHODS *
                   ******************************************* *
                   */


JNIEXPORT
    jboolean JNICALL
        Java_info_odma_odmjni100_OdmJniWork_jniCommitChanges
            (   JNIEnv *pIenv,      /* not used */
                jclass pThisClass,  /* not used */
                 jlong rIodmNative  /* for an IodmWorking100 */
                )

{   /* It's available directly in the IodmWorking100 interface.
       */

    return ((IodmWorking100 *) rIodmNative) -> commitChanges();

    } /* commitChanges */



/* 0.20 2007-03-27-21:20 Stop the Madness.  Do not accept a path into
        getIodmWinNative, but do load jawt.dll dynamically only when it
        is of any use.  Other than that, installation conditions must be
        used to ensure that needed libraries can be found.
   0.19 2007-03-27-18:59 Add jBin parameter to getIodmWinNative and
        change to dynamic loading of jawt.dll with the library set as
        indicated.
   0.18 2007-03-07-22:21 Add jniKnownDocument to work well enough for
        0.57beta of odmjni100.  It is cloned from selectDocument.
   0.17 2007-02-12-19:35 Correct jniDocLoc to cast to IodmWorking
        correctly (cut-and-paste error).
   0.16 2007-02-12-17:49 In addition to jniDocProp, the OdmCP2jString
        conversion from the ANSI code page is introduced for jniPendLoc,
        jniDocID, and jniDocLoc.  These are a bit worrisome, but should be
        the safest.  I will have to look again when hardening everything.
   0.15 2007-02-12-13:59 Implement code-page-dependent conversion for the
        OdmWorking document-property retrieval.  if this works well, look
        at using it for DocIds and for DocLocations.
   0.14 2007-02-05-21:06 Create static procedure that explores the
        java.awt.Window for its Windows WHND.
   0.13 2007-02-04-22:16 Rearrange the methods to include additional
        getIodmWinNative as the general case used by GetIodmNative as
        a special case.  Implement null case for regression.
   0.12 2007-01-24-22:16 Correct IID bug in jniCommitContent QueryInterface
   0.11 2007-01-22-22:33 Implement the native method jniToNewDoc and
        obtain clean compile.
   0.10 2007-01-21-20:40 Implement the native methods jniNewDoc, jniPendLoc,
        and jniCommitContent.
   0.09 2007-01-15-16:28 Move hasConMan, hasDefaultDMS, and selectDoc to
        OdmJniApp.
   0.08 2007-01-13-18:27 addition of checkViewOnly() and commitChanges()
        for completion of all methods needed for the 0.40alpha release.
   0.07 2007-01-09-20:52 Introduce the three native methods used by
        OdmJniView 0.04 for the 0.30alpha release.  The DLL is still 68k.
   0.06 2007-01-08-21:44 Update with complete selectDoc implementation.  The
        solutions is a variant on that used in OdmNative100 Check05 0.07.
   0.05 2006-11-30-00:42 Add selectDoc implementation.  This is provisional
        for now because we don't have any OdmNative document objects to
        instantiate yet.  This DLL is 68k.  We don't want multiple DLLs so
        we will have this one be enough.
   0.04 2006-11-29-21:56 Add hadDefaultDMS implementation.
   0.03 2006-11-29-20:58 Add hasConMan implementation.
   0.02 2006-11-29-19:00 Add holdNativeInterface implementation.
   0.01 2006-11-29-13:10 Add getIodmNative and freeNativeInterface.  These
        provide enough to instantiate an OdmConnection implementation.  Now
        there are 69,632 bytes in the DLL.
   0.00 2006-11-28-17:04 Strip down from odmjni100 0.06 to include only
        the jniVersion() method for initial confirmation of DLL location.
        The DLL compiles to the magical 49,152 bytes.

   $Header: /ODMdev/info/odma/odmjni100/odmjni100.cpp 20    07-03-27 23:34 Orcmid $
   */

/*                         *** end of odmjni100.cpp ***                  */
