os/graphics/m3g/m3gcore11/src/m3g_loader.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: Native implementation of the Loader class
    15 *
    16 */
    17 
    18 
    19 /*!
    20  * \internal
    21  * \file
    22  * \brief Native implementation of the Loader class
    23  *
    24 */
    25 
    26 #include "m3g_object.h"
    27 #include "m3g_array.h"
    28 
    29 /*----------------------------------------------------------------------
    30  * Internal data types
    31  *--------------------------------------------------------------------*/
    32 
    33 /*!
    34  * \internal
    35  * \brief Possible global states for the loader
    36  */
    37 typedef enum {
    38     /*! \internal \brief Loading not supported yet */
    39     LOADSTATE_NOT_SUPPORTED = -2,
    40     /*! \internal \brief Loading has terminated with an error */
    41     LOADSTATE_ERROR         = -1,
    42     /*! \internal \brief Loading has not started yet */
    43     LOADSTATE_INITIAL       =  0,
    44     /*! \internal \brief The identifier of the file is being read */
    45     LOADSTATE_IDENTIFIER,
    46     /*! \internal \brief The header of the section is being read */
    47     LOADSTATE_SECTION,
    48     /*! \internal \brief The header field of an object is being read */
    49     LOADSTATE_OBJECT,
    50     /*! \internal \brief Loading is finished */
    51     LOADSTATE_DONE
    52 } LoaderState;
    53 
    54 /*!
    55  * \internal
    56  * \brief Possible local states for the loader
    57  */
    58 typedef enum {
    59     /*! \internal \brief Local state is entered */
    60     LOADSTATE_ENTER,
    61     /*! \internal \brief Local state is exited */
    62     LOADSTATE_EXIT,
    63     /*! \internal \brief Local state is section checksum */
    64     LOADSTATE_CHECKSUM
    65 } LoaderLocalState;
    66 
    67 /*!
    68  * \internal
    69  * \brief Buffered byte stream class
    70  */
    71 typedef struct
    72 {
    73     M3Gubyte *allocatedData;
    74     M3Gubyte *data;
    75     M3Gsizei capacity, bytesAvailable, totalBytes;
    76 } BufferedStream;
    77 
    78 /*!
    79  * \internal
    80  * \brief User data for a loaded object
    81  */
    82 typedef struct
    83 {
    84     M3GObject object;
    85     M3Gint numParams;
    86     M3Gbyte **params;
    87     M3Gsizei *paramLengths;
    88     M3Gint *paramId;
    89 } UserData;
    90 
    91 /*!
    92  * \internal
    93  * \brief Loader instance data
    94  */
    95 typedef struct M3GLoaderImpl
    96 {
    97     Object object;
    98 
    99     BufferedStream stream;
   100     M3Gsizei bytesRequired;
   101     M3Gsizei sectionBytesRequired;
   102 
   103     PointerArray refArray;
   104     PointerArray userDataArray;
   105 
   106     /*!
   107      * \internal
   108      * \brief The global state the loader is in
   109      *
   110      * This is a rather ordinary state machine thing; basically the
   111      * type of object being loaded, or one of the possible error
   112      * conditions. In here, it also amounts to a particular coroutine
   113      * execution context.
   114      */
   115     LoaderState state;
   116 
   117     /*!
   118      * \internal
   119      * \brief The local state of the loader
   120      *
   121      * This is basically the line number within a particular coroutine
   122      * function.
   123      */
   124     M3Gint localState;
   125 
   126     /*!
   127      * \internal
   128      * \brief Object being loaded
   129      */
   130     M3Gint objectType;
   131 
   132     /*!
   133      * \internal
   134      * \brief Loaded object
   135      */
   136     M3GObject loadedObject;
   137 
   138     /*!
   139      * \internal
   140      * \brief Pointer to the beginning of an object
   141      */
   142     M3Gubyte *objectData;
   143 
   144     /*!
   145      * \internal
   146      * \brief Pointer to the end of an object
   147      */
   148     M3Gubyte *objectDataEnd;
   149 
   150     /*!
   151      * \internal
   152      * \brief Pointer to the context data for the current coroutine
   153      * context
   154      */
   155     M3Gubyte *localData;
   156 
   157     /*!
   158      * \internal
   159      * \brief Size of the current coroutine data
   160      *
   161      * This is grown dynamically as necessary, rather than trying to
   162      * maintain a single size that fits all coroutines.
   163      */
   164     size_t localDataSize;
   165 
   166     /* File information */
   167     M3Gbool hasReferences;
   168     M3Gsizei fileSize;
   169     M3Gsizei contentSize;
   170     M3Gint triCount;
   171     M3Gint triConstraint;
   172 
   173     /* Section information */
   174     M3Gbool compressed;
   175     M3Gint sectionLength;
   176     M3Gint sectionNum;
   177     M3Gint inflatedLength;
   178     M3Gubyte *sectionData;
   179     M3Gubyte *allocatedSectionData;
   180     
   181     /* Adler data */
   182     M3Gint S12[2];
   183 } Loader;
   184 
   185 typedef struct {
   186     const unsigned char *data;
   187     int read;
   188     int length;
   189 } compressedData;
   190 
   191 /* Type ID used for classifying objects derived from Node */
   192 #define ANY_NODE_CLASS ((M3GClass)(-1))
   193 
   194 #include <string.h>
   195 #define m3gCmp(s1, s2, len)  memcmp(s1, s2, len)
   196 
   197 /*----------------------------------------------------------------------
   198  * Private constants
   199  *--------------------------------------------------------------------*/
   200 
   201 #define M3G_MIN_OBJECT_SIZE     (1 + 4)
   202 #define M3G_MIN_SECTION_SIZE    (1 + 4 + 4)
   203 #define M3G_CHECKSUM_SIZE       4
   204 
   205 #define M3G_ADLER_CONST         65521;
   206 
   207 static const M3Gubyte M3G_FILE_IDENTIFIER[] = {
   208     0xAB, 0x4A, 0x53, 0x52, 0x31, 0x38, 0x34, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
   209 };
   210 
   211 static const M3Gubyte PNG_FILE_IDENTIFIER[] = {
   212     0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a
   213 };
   214 
   215 static void m3gCleanupLoader(M3GLoader loader);
   216 
   217 /*----------------------------------------------------------------------
   218  * Platform-specific "inflate" decompression code
   219  *--------------------------------------------------------------------*/
   220 
   221 /*!
   222  * \internal
   223  * \brief Decompresses a block of data into an output buffer
   224  *
   225  * \param srcLength number of bytes in the input (compressed) buffer
   226  * \param src       pointer to the input buffer
   227  * \param dstLength number of bytes allocated in the output buffer
   228  * \param dst       pointer to the output buffer
   229  * \return the number of bytes written to \c dst
   230  */
   231 static M3Gsizei m3gInflateBlock(M3Gsizei srcLength, const M3Gubyte *src,
   232                                 M3Gsizei dstLength, M3Gubyte *dst);
   233                            
   234 /* Include the platform-dependent implementation */
   235 #if !defined(M3G_TARGET_GENERIC)
   236 #   include "m3g_loader_inflate.inl"
   237 #endif
   238 
   239 /*----------------------------------------------------------------------
   240  * Private functions
   241  *--------------------------------------------------------------------*/
   242 
   243 /*!
   244  * \internal
   245  * \brief Destructor
   246  */
   247 static void m3gDestroyLoader(Object *obj)
   248 {
   249     Loader* loader = (Loader *) obj;
   250     M3G_VALIDATE_OBJECT(loader);
   251     {
   252         Interface *m3g = M3G_INTERFACE(loader);
   253         M3Gint n, i;
   254 
   255         m3gCleanupLoader(loader);
   256         m3gDestroyArray(&loader->refArray, m3g);
   257         n = m3gArraySize(&loader->userDataArray);
   258         for (i = 0; i < n; ++i)
   259         {
   260             UserData *data = (UserData *)m3gGetArrayElement(&loader->userDataArray, i);
   261             m3gFree(m3g, data->params);
   262             m3gFree(m3g, data->paramLengths);
   263             m3gFree(m3g, data->paramId);
   264             m3gFree(m3g, data);
   265         }
   266         m3gDestroyArray(&loader->userDataArray, m3g);
   267         m3gFree(m3g, loader->stream.allocatedData);
   268         m3gFree(m3g, loader->allocatedSectionData);
   269     }
   270     m3gDestroyObject(obj);
   271 }
   272 
   273 /*!
   274  * \internal
   275  * \brief Stores new data in the stream buffer of this loader
   276  */
   277 static M3Gbool m3gBufferData( M3GInterface m3g,
   278                            BufferedStream *stream,
   279                            M3Gsizei bytes,
   280                            const M3Gubyte *data)
   281 {
   282     M3Gsizei used;
   283 
   284     /* Allocate initial buffer */
   285     if (stream->allocatedData == NULL) {
   286         stream->capacity = bytes + 512;
   287         stream->allocatedData = m3gAllocZ(m3g, stream->capacity);
   288         if (!stream->allocatedData) {
   289             return M3G_FALSE;
   290         }
   291         stream->data = stream->allocatedData;
   292         stream->bytesAvailable = 0;
   293         stream->totalBytes = 0;
   294     }
   295 
   296     /* First skip used bytes */
   297     used = stream->data - stream->allocatedData;
   298     if (used > 0) {
   299         m3gMove(stream->allocatedData, stream->data, stream->bytesAvailable);
   300         stream->data = stream->allocatedData;
   301     }
   302 
   303     /* Check if new data fits in current buffer */
   304     if ((stream->capacity - stream->bytesAvailable) < bytes) {
   305         M3Gubyte *newData;
   306         stream->capacity = stream->capacity + bytes + 512;
   307         newData = m3gAllocZ(m3g, stream->capacity);
   308         if (!newData) {
   309             m3gFree(m3g, stream->allocatedData);
   310             stream->allocatedData = NULL;
   311             return M3G_FALSE;
   312         }
   313         m3gCopy(newData, stream->data, stream->bytesAvailable);
   314         m3gFree(m3g, stream->allocatedData);
   315         stream->allocatedData = newData;
   316         stream->data = stream->allocatedData;
   317     }
   318 
   319     m3gCopy(stream->data + stream->bytesAvailable, data, bytes);
   320     stream->bytesAvailable += bytes;
   321 
   322     return M3G_TRUE;
   323 }
   324 
   325 /*!
   326  * \internal
   327  * \brief Resets buffered data
   328  */
   329 static void m3gResetBufferedData(BufferedStream *stream)
   330 {
   331     stream->bytesAvailable = 0;
   332     stream->data = stream->allocatedData;
   333     stream->totalBytes = 0;
   334 }
   335 
   336 /*!
   337  * \internal
   338  * \brief Gets buffered data pointer
   339  */
   340 static M3Gubyte *m3gGetBufferedDataPtr(BufferedStream *stream, M3Gint length)
   341 {
   342     if (stream->bytesAvailable >= length) {
   343         return stream->data;
   344     }
   345     else {
   346         return NULL;
   347     }
   348 }
   349 
   350 /*!
   351  * \internal
   352  * \brief Advances buffered data pointer
   353  */
   354 static void m3gAdvanceBufferedData(BufferedStream *stream, M3Gint length)
   355 {
   356     stream->data += length;
   357     stream->bytesAvailable -= length;
   358     stream->totalBytes += length;
   359 }
   360 
   361 /*!
   362  * \internal
   363  * \brief Verify a boolean
   364  */
   365 static M3Gbool m3gVerifyBool(M3Gubyte *data)
   366 {
   367     return (*data == 0 || *data == 1);
   368 }
   369 
   370 /*!
   371  * \internal
   372  * \brief Loads ARGB color from data array
   373  */
   374 static M3Guint m3gLoadARGB(M3Gubyte *data)
   375 {
   376     M3Guint v = data[3];
   377     v <<= 8;
   378     v |=  data[0];
   379     v <<= 8;
   380     v |=  data[1];
   381     v <<= 8;
   382     v |=  data[2];
   383 
   384     return v;
   385 }
   386 
   387 /*!
   388  * \internal
   389  * \brief Loads RGB color from data array
   390  */
   391 static M3Guint m3gLoadRGB(M3Gubyte *data)
   392 {
   393     M3Guint v = data[0];
   394     v <<= 8;
   395     v |=  data[1];
   396     v <<= 8;
   397     v |=  data[2];
   398 
   399     return v;
   400 }
   401 
   402 /*!
   403  * \internal
   404  * \brief Loads short from data array
   405  */
   406 static M3Gshort m3gLoadShort(M3Gubyte *data)
   407 {
   408     M3Gshort v = data[1];
   409     v <<= 8;
   410     v |=  data[0];
   411 
   412     return v;
   413 }
   414 
   415 /*!
   416  * \internal
   417  * \brief Loads integer from data array
   418  */
   419 static M3Gint m3gLoadInt(M3Gubyte *data)
   420 {
   421     M3Gint v = data[3];
   422     v <<= 8;
   423     v |=  data[2];
   424     v <<= 8;
   425     v |=  data[1];
   426     v <<= 8;
   427     v |=  data[0];
   428 
   429     return v;
   430 }
   431 
   432 /*!
   433  * \internal
   434  * \brief Loads integer from data array
   435  */
   436 static M3Gbool m3gLoadFloat(M3Gubyte *data, M3Gfloat *res)
   437 {
   438     M3Guint v = data[3];
   439     v <<= 8;
   440     v |=  data[2];
   441     v <<= 8;
   442     v |=  data[1];
   443     v <<= 8;
   444     v |=  data[0];
   445 
   446     *res = (*(M3Gfloat*)&(v));
   447     if ((v & 0x7f800000) ==  0x7f800000 ||
   448         v == 0x80000000 || // negative zero
   449         ((v & 0x007FFFFF ) != 0 && ( v & 0x7F800000 ) == 0))
   450         return M3G_FALSE;
   451     return M3G_TRUE;
   452 }
   453 
   454 /*!
   455  * \internal
   456  * \brief Loads 4 * 4 matrix from data array
   457  */
   458 static M3Gbool m3gLoadMatrix(Matrix *m, M3Gubyte *data)
   459 {
   460     M3Gint i;
   461     M3Gfloat array[16];
   462 
   463     for (i = 0; i < 16; i++) {
   464         if (!m3gLoadFloat(data + 4 * i, &array[i]))
   465             return M3G_FALSE;
   466     }
   467 
   468     m3gSetMatrixRows(m, array);
   469     return M3G_TRUE;
   470 }
   471 
   472 /*!
   473  * \internal
   474  * \brief Inflates a section
   475  */
   476 static M3Gubyte *m3gInflateSection(Loader *loader,
   477                                    M3Gubyte *compressed,
   478                                    M3Gint cLength, M3Gint iLength)
   479 {
   480     M3Gubyte *inflated = m3gAllocZ(M3G_INTERFACE(loader), iLength);
   481     if (inflated && !m3gInflateBlock(cLength, compressed, iLength, inflated)) {
   482         m3gFree(M3G_INTERFACE(loader), inflated);
   483         return NULL;
   484     }
   485 
   486     return inflated;
   487 }
   488 
   489 /*!
   490  * \internal
   491  * \brief Loads file identifier
   492  */
   493 static LoaderState m3gLoadIdentifier(Loader *loader)
   494 {
   495     M3Gubyte *data = m3gGetBufferedDataPtr(&loader->stream, loader->bytesRequired);
   496 
   497     if (loader->localState == LOADSTATE_ENTER) {
   498         if (m3gCmp(data, PNG_FILE_IDENTIFIER, sizeof(PNG_FILE_IDENTIFIER)) == 0) {
   499             m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
   500             return LOADSTATE_NOT_SUPPORTED;
   501         }
   502         else {
   503             loader->localState = LOADSTATE_EXIT;
   504             loader->bytesRequired = sizeof(M3G_FILE_IDENTIFIER);
   505             return LOADSTATE_IDENTIFIER;
   506         }
   507     }
   508     else {
   509         if (m3gCmp(data, M3G_FILE_IDENTIFIER, sizeof(M3G_FILE_IDENTIFIER)) == 0) {
   510             m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
   511             loader->localState = LOADSTATE_ENTER;
   512             loader->bytesRequired = M3G_MIN_SECTION_SIZE;
   513             return LOADSTATE_SECTION;
   514         }
   515 
   516         loader->bytesRequired = 0;
   517         return LOADSTATE_ERROR;
   518     }
   519 }
   520 
   521 /*!
   522  * \internal
   523  * \brief Adler helper functions
   524  */
   525 
   526 static void m3gInitAdler(M3Gint *S12)
   527 {
   528     S12[0] = 1; S12[1] = 0;
   529 }
   530 
   531 static void m3gUpdateAdler(M3Gint *S12, M3Gubyte *data, M3Gint length)
   532 {
   533     int i;
   534     for (i = 0; i < length; i++) {
   535         S12[0] = (S12[0] + data[i]) % M3G_ADLER_CONST;
   536         S12[1] = (S12[1] + S12[0])  % M3G_ADLER_CONST;
   537     }
   538 }
   539 
   540 static M3Gint m3gGetAdler(M3Gint *S12)
   541 {
   542     return (S12[1] << 16) | S12[0];
   543 }
   544 
   545 /*!
   546  * \internal
   547  * \brief Loads a section
   548  */
   549 static LoaderState m3gLoadSection(Loader *loader)
   550 {
   551     M3Gubyte *data = m3gGetBufferedDataPtr(&loader->stream, loader->bytesRequired);
   552 
   553     if (data == NULL) {
   554         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
   555         return LOADSTATE_ERROR;
   556     }
   557 
   558     switch(loader->localState) {
   559     case LOADSTATE_ENTER:
   560         m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
   561         m3gInitAdler(loader->S12);
   562         m3gUpdateAdler(loader->S12, data, loader->bytesRequired);
   563 
   564         if (*data > 1)
   565         {
   566             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
   567             return LOADSTATE_ERROR;
   568         }
   569         loader->compressed = data[0];
   570         loader->sectionLength = m3gLoadInt(data + 1);
   571         loader->inflatedLength = m3gLoadInt(data + 5);
   572 
   573         loader->localState = LOADSTATE_EXIT;
   574         loader->bytesRequired = loader->sectionLength - loader->bytesRequired;
   575         if (!loader->compressed && loader->inflatedLength != (loader->bytesRequired - M3G_CHECKSUM_SIZE))
   576         {
   577             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
   578             return LOADSTATE_ERROR;
   579         }
   580 
   581         loader->sectionNum++;
   582 
   583         /* Special case for empty sections */
   584         if (loader->bytesRequired == M3G_CHECKSUM_SIZE) {
   585             loader->localData = data + loader->sectionLength - M3G_CHECKSUM_SIZE;
   586             loader->sectionData = loader->localData;
   587             loader->compressed = M3G_FALSE;
   588             loader->localState = LOADSTATE_CHECKSUM;
   589         }
   590         return LOADSTATE_SECTION;
   591 
   592     case LOADSTATE_EXIT:
   593     default:
   594         m3gUpdateAdler(loader->S12, data, loader->bytesRequired - M3G_CHECKSUM_SIZE);
   595 
   596         if (loader->compressed) {
   597             if (loader->inflatedLength > 0) {
   598                 m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
   599                 loader->sectionData = m3gInflateSection(loader, data, loader->bytesRequired, loader->inflatedLength);
   600                 loader->allocatedSectionData = loader->sectionData;
   601 
   602                 if (!loader->sectionData) {
   603                     if (m3gErrorRaised(M3G_INTERFACE(loader)) == M3G_NO_ERROR)
   604                         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
   605                     return LOADSTATE_ERROR;
   606                 }
   607             }
   608             else {
   609                 loader->sectionData = NULL;
   610             }
   611         }
   612         else {
   613             loader->sectionData = data;
   614         }
   615 
   616         loader->localData = loader->sectionData;
   617         loader->sectionBytesRequired = M3G_MIN_OBJECT_SIZE;
   618         loader->localState = LOADSTATE_ENTER;
   619         return LOADSTATE_OBJECT;
   620 
   621     case LOADSTATE_CHECKSUM:
   622         if (loader->localData != loader->sectionData + loader->inflatedLength || /* Length */
   623             m3gLoadInt(data + loader->bytesRequired - M3G_CHECKSUM_SIZE) != m3gGetAdler(loader->S12))
   624         {
   625             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
   626             m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
   627             loader->allocatedSectionData = NULL;
   628             return LOADSTATE_ERROR;
   629         }
   630         m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
   631 
   632         m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
   633         loader->allocatedSectionData = NULL;
   634 
   635         loader->localState = LOADSTATE_ENTER;
   636         loader->bytesRequired = M3G_MIN_SECTION_SIZE;
   637         return LOADSTATE_SECTION;
   638     }
   639 }
   640 
   641 /*!
   642  * \internal
   643  * \brief Resets section data pointer to the beginning of an object
   644  */
   645 static void m3gRewindObject(Loader *loader)
   646 {
   647     loader->localData = loader->objectData;
   648 }
   649 
   650 /*!
   651  * \internal
   652  * \brief Resets section data pointer to the end of an object
   653  */
   654 static void m3gSkipObject(Loader *loader)
   655 {
   656     loader->localData = loader->objectDataEnd;
   657 }
   658 
   659 /*!
   660  * \internal
   661  * \brief Marks object to begin
   662  */
   663 static void m3gBeginObject(Loader *loader)
   664 {
   665     loader->objectData = loader->localData;
   666 }
   667 
   668 /*!
   669  * \internal
   670  * \brief Marks object to end
   671  */
   672 static void m3gEndObject(Loader *loader)
   673 {
   674     loader->objectDataEnd = loader->localData;
   675 }
   676 
   677 /*!
   678  * \internal
   679  * \brief Gets section data pointer
   680  */
   681 static M3Gubyte *m3gGetSectionDataPtr(Loader *loader, M3Gint length)
   682 {
   683     if ((loader->localData + length) <= (loader->sectionData + loader->inflatedLength)) {
   684         return loader->localData;
   685     }
   686     else {
   687         return NULL;
   688     }
   689 }
   690 
   691 /*!
   692  * \internal
   693  * \brief Advances section data pointer
   694  */
   695 static void m3gAdvanceSectionData(Loader *loader, M3Gint length)
   696 {
   697     loader->localData += length;
   698 }
   699 
   700 /*!
   701  * \internal
   702  * \brief Check length of the available section data
   703  */
   704 static M3Gbool m3gCheckSectionDataLength(Loader *loader, const M3Gubyte *data, M3Gsizei length)
   705 {
   706     if (data + length < data) return M3G_FALSE; /* Check for overflow */
   707     return ((data + length) <= (loader->sectionData + loader->inflatedLength));
   708 }
   709 
   710 /*!
   711  * \internal
   712  * \brief References an object in the object array
   713  *
   714  * \note Uses lowest bit of the pointer to mark a reference
   715  */
   716 static void m3gReferenceLoaded(PointerArray *array, M3Gint idx)
   717 {
   718     M3Guint ptr = (M3Guint)m3gGetArrayElement(array, idx);
   719     ptr |= 1;
   720     m3gSetArrayElement(array, idx, (void *)ptr);
   721 }
   722 
   723 /*!
   724  * \internal
   725  * \brief Gets an object in the object array and
   726  * returns reference status
   727  */
   728 static M3GObject m3gGetLoadedPtr(PointerArray *array, M3Gint idx, M3Gbool *referenced)
   729 {
   730     M3Guint ptr = (M3Guint)m3gGetArrayElement(array, idx);
   731     if (referenced != NULL) {
   732         *referenced = ptr & 1;
   733     }
   734     return (M3GObject)(ptr & (~1));
   735 }
   736 
   737 /*!
   738  * \internal
   739  * \brief Gets a loaded object and marks it referenced
   740  */
   741 static M3GObject m3gGetLoaded(Loader *loader, M3Gint idx, M3GClass classID)
   742 {
   743     M3GObject obj;
   744     M3GClass objClassID;
   745     M3Gbool isCompatible;
   746 
   747     if (idx == 0) return NULL;
   748     idx -= 2;
   749 
   750     if (idx < 0 || idx >= m3gArraySize(&loader->refArray)) {
   751         /* Error, not loaded */
   752         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
   753         return NULL;
   754     }
   755 
   756     obj = m3gGetLoadedPtr(&loader->refArray, idx, NULL);
   757     objClassID = M3G_CLASS(obj);
   758 
   759     /* Class type check; handle nodes as a special case */
   760     
   761     if (classID == ANY_NODE_CLASS) {
   762         switch (objClassID) {
   763         case M3G_CLASS_CAMERA:
   764         case M3G_CLASS_GROUP:
   765         case M3G_CLASS_LIGHT:
   766         case M3G_CLASS_MESH:
   767         case M3G_CLASS_MORPHING_MESH:
   768         case M3G_CLASS_SKINNED_MESH:
   769         case M3G_CLASS_SPRITE:
   770         case M3G_CLASS_WORLD:
   771             isCompatible = M3G_TRUE;
   772             break;
   773         default:
   774             isCompatible = M3G_FALSE;
   775         }
   776     }
   777     else {
   778         switch (classID) {
   779         case M3G_ABSTRACT_CLASS:
   780             M3G_ASSERT(M3G_FALSE);
   781             isCompatible = M3G_FALSE;
   782             break;
   783         case M3G_CLASS_MESH:
   784             isCompatible = (objClassID == M3G_CLASS_MESH)
   785                 || (objClassID == M3G_CLASS_MORPHING_MESH)
   786                 || (objClassID == M3G_CLASS_SKINNED_MESH);
   787             break;
   788         default:
   789             isCompatible = (classID == objClassID);
   790         }
   791     }
   792 
   793     if (!isCompatible) {
   794         /* Error, class mismatch */
   795         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
   796         return NULL;
   797     }
   798 
   799     /* Mark object as referenced */
   800     m3gReferenceLoaded(&loader->refArray, idx);
   801     return obj;
   802 }
   803 
   804 /*!
   805  * \internal
   806  * \brief Loads Object3D data
   807  */
   808 static M3Gbool m3gLoadObject3DData(Loader *loader, M3GObject obj)
   809 {
   810     M3Guint animTracks, i, userParams, paramId, paramLength;
   811     UserData *userData = NULL;
   812     M3Gubyte *data = m3gGetSectionDataPtr(loader, 8);
   813     if (data == NULL) return M3G_FALSE;
   814 
   815     m3gSetUserID(obj, m3gLoadInt(data));
   816     data += 4;
   817 
   818     animTracks = m3gLoadInt(data);
   819     data += 4;
   820 
   821     /* Overflow? */
   822     if (animTracks >= 0x1fffffff) {
   823         return M3G_FALSE;
   824     }
   825 
   826     if (m3gCheckSectionDataLength(loader, data, animTracks * 4 + 4) == M3G_FALSE) return M3G_FALSE;
   827     for (i = 0; i < animTracks; i++) {
   828         M3GAnimationTrack at = (M3GAnimationTrack)m3gGetLoaded(loader, m3gLoadInt(data),M3G_CLASS_ANIMATION_TRACK);
   829         if (at == NULL || m3gAddAnimationTrack(obj, at) == -1) {
   830             return M3G_FALSE;
   831         }
   832         data += 4;
   833     }
   834 
   835     userParams = m3gLoadInt(data);
   836     data += 4;
   837 
   838     if (userParams != 0) {
   839         /* Overflow? */
   840         if (userParams >= 0x10000000) {
   841             return M3G_FALSE;
   842         }
   843 
   844         if (m3gCheckSectionDataLength(loader, data, userParams * 8) == M3G_FALSE)
   845             return M3G_FALSE; /* Check the minimum size to avoid useless allocation */
   846         userData = (UserData *)m3gAllocZ(M3G_INTERFACE(loader), sizeof(UserData));
   847         if (userData == NULL)
   848             return M3G_FALSE;
   849         userData->object = obj;
   850         userData->numParams = userParams;
   851         userData->params = (M3Gbyte **)m3gAllocZ(M3G_INTERFACE(loader), userParams*sizeof(M3Gbyte *));
   852         userData->paramLengths = (M3Gsizei *)m3gAlloc(M3G_INTERFACE(loader), userParams*sizeof(M3Gsizei));
   853         userData->paramId = (M3Gint *)m3gAlloc(M3G_INTERFACE(loader), userParams*sizeof(M3Gint));
   854         if (userData->params == NULL ||
   855             userData->paramLengths == NULL ||
   856             userData->paramId == NULL ||
   857             m3gArrayAppend(&loader->userDataArray, userData, M3G_INTERFACE(loader)) == -1) {
   858             m3gFree(M3G_INTERFACE(loader), userData->params);
   859             m3gFree(M3G_INTERFACE(loader), userData->paramLengths);
   860             m3gFree(M3G_INTERFACE(loader), userData->paramId);
   861             m3gFree(M3G_INTERFACE(loader), userData);
   862             return M3G_FALSE;
   863         }
   864 
   865         for (i = 0; i < userParams; i++) {
   866             if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
   867             paramId = m3gLoadInt(data);
   868             data += 4;
   869             paramLength = m3gLoadInt(data);
   870             data += 4;
   871             userData->paramId[i] = paramId;
   872             userData->paramLengths[i] = paramLength;
   873             if (m3gCheckSectionDataLength(loader, data, paramLength) == M3G_FALSE) return M3G_FALSE;
   874             userData->params[i] = (M3Gbyte *)m3gAlloc(M3G_INTERFACE(loader), paramLength*sizeof(M3Gbyte));
   875             if (userData->params[i] == NULL)
   876                 return M3G_FALSE;
   877             m3gCopy(userData->params[i], data, paramLength);
   878             data += paramLength;
   879         }
   880     }
   881 
   882     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
   883     return M3G_TRUE;
   884 }
   885 
   886 /*!
   887  * \internal
   888  * \brief Skips Object3D data
   889  */
   890 static M3Gbool m3gSkipObject3DData(Loader *loader)
   891 {
   892     M3Guint animTracks, i, userParams, paramLength;
   893     M3Gubyte *data = m3gGetSectionDataPtr(loader, 8);
   894     if (data == NULL) return M3G_FALSE;
   895 
   896     data += 4;
   897     animTracks = m3gLoadInt(data);
   898     data += 4;
   899 
   900     /* Overflow? */
   901     if (animTracks >= 0x1fffffff) {
   902         return M3G_FALSE;
   903     }
   904 
   905     if (m3gCheckSectionDataLength(loader, data, animTracks * 4 + 4) == M3G_FALSE) return M3G_FALSE;
   906     for (i = 0; i < animTracks; i++) {
   907         data += 4;
   908     }
   909 
   910     userParams = m3gLoadInt(data);
   911     data += 4;
   912 
   913     for (i = 0; i < userParams; i++) {
   914         if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
   915         data += 4;
   916         paramLength = m3gLoadInt(data);
   917         if (m3gCheckSectionDataLength(loader, data, paramLength) == M3G_FALSE) return M3G_FALSE;
   918         data += 4 + paramLength;
   919     }
   920 
   921     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
   922     return M3G_TRUE;
   923 }
   924 
   925 /*!
   926  * \internal
   927  * \brief Loads transformable data
   928  */
   929 static M3Gbool m3gLoadTransformableData(Loader *loader, M3GTransformable obj)
   930 {
   931     M3Gfloat f1, f2, f3, f4;
   932     M3Gubyte *data;
   933     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
   934         return M3G_FALSE;
   935     }
   936 
   937     data = m3gGetSectionDataPtr(loader, 1);
   938     if (data == NULL) return M3G_FALSE;
   939 
   940     if (!m3gVerifyBool(data)) return M3G_FALSE;
   941     /* Component transform ? */
   942     if (*data++) {
   943         if (m3gCheckSectionDataLength(loader, data, 40) == M3G_FALSE) return M3G_FALSE;
   944         if (!m3gLoadFloat(data + 0, &f1) ||
   945             !m3gLoadFloat(data + 4, &f2) ||
   946             !m3gLoadFloat(data + 8, &f3))
   947             return M3G_FALSE;
   948         m3gSetTranslation(obj, f1, f2, f3);
   949         if (!m3gLoadFloat(data + 12, &f1) ||
   950             !m3gLoadFloat(data + 16, &f2) ||
   951             !m3gLoadFloat(data + 20, &f3))
   952             return M3G_FALSE;
   953         m3gSetScale(obj, f1, f2, f3);
   954         if (!m3gLoadFloat(data + 24, &f1) ||
   955             !m3gLoadFloat(data + 28, &f2) ||
   956             !m3gLoadFloat(data + 32, &f3) ||
   957             !m3gLoadFloat(data + 36, &f4))
   958             return M3G_FALSE;
   959         m3gSetOrientation(obj, f1, f2, f3, f4);
   960         data += 40;
   961     }
   962 
   963     if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
   964     if (!m3gVerifyBool(data)) return M3G_FALSE;
   965     /* Generic transform */
   966     if (*data++) {
   967         Matrix m;
   968         if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
   969         if (!m3gLoadMatrix(&m, data)) return M3G_FALSE;
   970         m3gSetTransform(obj, &m);
   971         data += 64;
   972     }
   973 
   974     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
   975     return M3G_TRUE;
   976 }
   977 
   978 /*!
   979  * \internal
   980  * \brief Skips transformable data
   981  */
   982 static M3Gbool m3gSkipTransformableData(Loader *loader)
   983 {
   984     M3Gubyte *data;
   985     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
   986 
   987     data = m3gGetSectionDataPtr(loader, 1);
   988     if (data == NULL) return M3G_FALSE;
   989 
   990     /* Component transform ? */
   991     if (*data++) {
   992         if (m3gCheckSectionDataLength(loader, data, 40) == M3G_FALSE) return M3G_FALSE;
   993         data += 40;
   994     }
   995 
   996     if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
   997     /* Generic transform */
   998     if (*data++) {
   999         if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
  1000         data += 64;
  1001     }
  1002 
  1003     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1004     return M3G_TRUE;
  1005 }
  1006 
  1007 /*!
  1008  * \internal
  1009  * \brief Loads node data
  1010  */
  1011 static M3Gbool m3gLoadNodeData(Loader *loader, M3GNode obj)
  1012 {
  1013     M3Gubyte *data;
  1014     if (!m3gLoadTransformableData(loader, (M3GTransformable)obj)) {
  1015         return M3G_FALSE;
  1016     }
  1017 
  1018     data = m3gGetSectionDataPtr(loader, 8);
  1019     if (data == NULL) return M3G_FALSE;
  1020 
  1021     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1022     m3gEnable(obj, 0, *data++);
  1023     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1024     m3gEnable(obj, 1, *data++);
  1025     {
  1026         unsigned a = *data++; 
  1027         m3gSetAlphaFactor(obj, m3gDivif(a, 255));
  1028     }
  1029     m3gSetScope(obj, m3gLoadInt(data));
  1030     data += 4;
  1031 
  1032     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1033     if (*data++) {
  1034         M3Gubyte zt, yt;
  1035         M3Gint zr, yr;
  1036         if (m3gCheckSectionDataLength(loader, data, 10) == M3G_FALSE) return M3G_FALSE;
  1037         zt = *data++;
  1038         yt = *data++;
  1039         zr = m3gLoadInt(data);
  1040         yr = m3gLoadInt(data + 4);
  1041         m3gSetAlignment(obj,    (M3GNode)m3gGetLoaded(loader, zr, ANY_NODE_CLASS),
  1042                                 zt,
  1043                                 (M3GNode)m3gGetLoaded(loader, yr, ANY_NODE_CLASS),
  1044                                 yt);
  1045         data += 8;
  1046     }
  1047 
  1048     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1049     return M3G_TRUE;
  1050 }
  1051 
  1052 /*!
  1053  * \internal
  1054  * \brief Skips node data
  1055  */
  1056 static M3Gbool m3gSkipNodeData(Loader *loader)
  1057 {
  1058     M3Gubyte *data;
  1059     if (!m3gSkipTransformableData(loader)) return M3G_FALSE;
  1060 
  1061     data = m3gGetSectionDataPtr(loader, 8);
  1062     if (data == NULL) return M3G_FALSE;
  1063     data += 7;
  1064 
  1065     /* Alignment? */
  1066     if (*data++) {
  1067         if (m3gCheckSectionDataLength(loader, data, 10) == M3G_FALSE) return M3G_FALSE;
  1068         data += 10;
  1069     }
  1070 
  1071     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1072     return M3G_TRUE;
  1073 }
  1074 
  1075 /*!
  1076  * \internal
  1077  * \brief Loads a camera
  1078  */
  1079 static M3Gbool m3gLoadCamera(Loader *loader)
  1080 {
  1081     M3Gfloat f1, f2, f3, f4;
  1082     M3Gubyte *data;
  1083     M3GCamera obj = m3gCreateCamera(M3G_INTERFACE(loader));
  1084     loader->loadedObject = (M3GObject)obj;
  1085     if (!obj) return M3G_FALSE;
  1086 
  1087     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
  1088         return M3G_FALSE;
  1089     }
  1090 
  1091     data = m3gGetSectionDataPtr(loader, 1);
  1092     if (data == NULL) return M3G_FALSE;
  1093 
  1094     switch(*data++) {
  1095     case M3G_GENERIC:
  1096         {
  1097             Matrix m;
  1098             if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
  1099             if (!m3gLoadMatrix(&m, data)) return M3G_FALSE;
  1100             m3gSetProjectionMatrix(obj, &m);
  1101             data += 64;
  1102         }
  1103         break;
  1104     case M3G_PERSPECTIVE:
  1105         if (m3gCheckSectionDataLength(loader, data, 16) == M3G_FALSE) return M3G_FALSE;
  1106         if (!m3gLoadFloat(data + 0, &f1) ||
  1107             !m3gLoadFloat(data + 4, &f2) ||
  1108             !m3gLoadFloat(data + 8, &f3) ||
  1109             !m3gLoadFloat(data + 12, &f4))
  1110             return M3G_FALSE;
  1111         m3gSetPerspective(obj, f1, f2, f3, f4);
  1112         data += 16;
  1113         break;
  1114     case M3G_PARALLEL:
  1115         if (m3gCheckSectionDataLength(loader, data, 16) == M3G_FALSE) return M3G_FALSE;
  1116         if (!m3gLoadFloat(data + 0, &f1) ||
  1117             !m3gLoadFloat(data + 4, &f2) ||
  1118             !m3gLoadFloat(data + 8, &f3) ||
  1119             !m3gLoadFloat(data + 12, &f4))
  1120             return M3G_FALSE;
  1121         m3gSetParallel(obj, f1, f2, f3, f4);
  1122         data += 16;
  1123         break;
  1124     default:
  1125         /* Error */
  1126         break;
  1127     }
  1128 
  1129     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1130 
  1131     return M3G_TRUE;
  1132 }
  1133 
  1134 /*!
  1135  * \internal
  1136  * \brief Loads a background
  1137  */
  1138 static M3Gbool m3gLoadBackground(Loader *loader)
  1139 {
  1140     M3Gubyte *data;
  1141     M3GBackground obj = m3gCreateBackground(M3G_INTERFACE(loader));
  1142     loader->loadedObject = (M3GObject)obj;
  1143     if (!obj) return M3G_FALSE;
  1144 
  1145     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1146         return M3G_FALSE;
  1147     }
  1148 
  1149     data = m3gGetSectionDataPtr(loader, 28);
  1150     if (data == NULL) return M3G_FALSE;
  1151 
  1152     m3gSetBgColor(obj, m3gLoadARGB(data));
  1153     data += 4;
  1154     m3gSetBgImage(obj, (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE));
  1155     data += 4;
  1156     m3gSetBgMode(obj, data[0], data[1]);
  1157     data += 2;
  1158     m3gSetBgCrop(obj,   m3gLoadInt(data),
  1159                         m3gLoadInt(data + 4),
  1160                         m3gLoadInt(data + 8),
  1161                         m3gLoadInt(data + 12) );
  1162     data += 16;
  1163 
  1164     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1165     m3gSetBgEnable(obj, 0, *data++);
  1166     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1167     m3gSetBgEnable(obj, 1, *data++);
  1168 
  1169     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1170 
  1171     return M3G_TRUE;
  1172 }
  1173 
  1174 /*!
  1175  * \internal
  1176  * \brief Loads a vertex array
  1177  */
  1178 static M3Gbool m3gLoadVertexArray(Loader *loader)
  1179 {
  1180     M3Gint i, j;
  1181     M3Guint size;
  1182     M3Gushort vertices;
  1183     M3Gubyte *data, components, encoding;
  1184     M3Gdatatype componentSize;
  1185     M3GVertexArray obj;
  1186 
  1187     m3gBeginObject(loader);
  1188     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
  1189 
  1190     data = m3gGetSectionDataPtr(loader, 5);
  1191     if (data == NULL) return M3G_FALSE;
  1192 
  1193     if (*data != 1 && *data != 2) return M3G_FALSE;
  1194     componentSize = (*data++ == 1) ? M3G_BYTE : M3G_SHORT;
  1195     components    = *data++;
  1196     encoding      = *data++;
  1197     vertices      = m3gLoadShort(data);
  1198     data += 2;
  1199 
  1200     size = vertices * components * (componentSize == M3G_BYTE ? 1 : 2);
  1201 
  1202     /* Overflow? */
  1203     if (size < vertices) {
  1204         return M3G_FALSE;
  1205     }
  1206 
  1207     if (m3gCheckSectionDataLength(loader, data, size) == M3G_FALSE) return M3G_FALSE;
  1208     obj = m3gCreateVertexArray(M3G_INTERFACE(loader), vertices, components, componentSize);
  1209     loader->loadedObject = (M3GObject)obj;
  1210     if (!obj) return M3G_FALSE;
  1211 
  1212     if (componentSize == M3G_BYTE) {
  1213         M3Gbyte previousValues[4];
  1214         m3gZero(previousValues, sizeof(previousValues));
  1215 
  1216         for (i = 0; i < vertices; i++) {
  1217             for (j = 0; j < components; j++) {
  1218                 if (encoding == 0) {
  1219                     previousValues[j] = *data++;
  1220                 }
  1221                 else {
  1222                     previousValues[j] = (M3Gbyte) (previousValues[j] + *data++);
  1223                 }
  1224             }
  1225             m3gSetVertexArrayElements(obj, i, 1, sizeof(previousValues), componentSize, previousValues);
  1226         }
  1227     }
  1228     else {
  1229         M3Gshort previousValues[4];
  1230         m3gZero(previousValues, sizeof(previousValues));
  1231 
  1232         for (i = 0; i < vertices; i++) {
  1233             for (j = 0; j < components; j++) {
  1234                 if (encoding == 0) {
  1235                     previousValues[j] = m3gLoadShort(data);
  1236                 }
  1237                 else {
  1238                     previousValues[j] = (M3Gshort) (previousValues[j] + m3gLoadShort(data));
  1239                 }
  1240                 data += 2;
  1241             }
  1242             m3gSetVertexArrayElements(obj, i, 1, sizeof(previousValues), componentSize, previousValues);
  1243         }
  1244     }
  1245 
  1246     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1247 
  1248     m3gEndObject(loader);
  1249     m3gRewindObject(loader);
  1250     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1251         return M3G_FALSE;
  1252     }
  1253     m3gSkipObject(loader);
  1254 
  1255     return M3G_TRUE;
  1256 }
  1257 
  1258 /*!
  1259  * \internal
  1260  * \brief Loads a vertex buffer
  1261  */
  1262 static M3Gbool m3gLoadVertexBuffer(Loader *loader)
  1263 {
  1264     M3Gubyte *data;
  1265     M3GVertexArray va;
  1266     M3Gfloat bias[3], scale;
  1267     M3Guint i, taCount;
  1268     M3GVertexBuffer obj = m3gCreateVertexBuffer(M3G_INTERFACE(loader));
  1269     loader->loadedObject = (M3GObject)obj;
  1270     if (!obj) return M3G_FALSE;
  1271 
  1272     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1273         return M3G_FALSE;
  1274     }
  1275 
  1276     data = m3gGetSectionDataPtr(loader, 36);
  1277     if (data == NULL) return M3G_FALSE;
  1278 
  1279     m3gSetVertexDefaultColor(obj, m3gLoadARGB(data));
  1280     data += 4;
  1281 
  1282     /* Positions */
  1283     va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
  1284     data += 4;
  1285     if (!m3gLoadFloat(data + 0, &bias[0])) return M3G_FALSE;
  1286     if (!m3gLoadFloat(data + 4, &bias[1])) return M3G_FALSE;
  1287     if (!m3gLoadFloat(data + 8, &bias[2])) return M3G_FALSE;
  1288     if (!m3gLoadFloat(data + 12, &scale)) return M3G_FALSE;
  1289     if (va != NULL) {
  1290         m3gSetVertexArray(obj, va, scale, bias, 3);
  1291     }
  1292     data += 16;
  1293 
  1294     /* Normals */
  1295     va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
  1296     data += 4;
  1297     if (va != NULL) {
  1298         m3gSetNormalArray(obj, va);
  1299     }
  1300 
  1301     /* Colors */
  1302     va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
  1303     data += 4;
  1304     if (va != NULL) {
  1305         m3gSetColorArray(obj, va);
  1306     }
  1307 
  1308     /* Texture coordinates */
  1309     taCount = m3gLoadInt(data);
  1310     data += 4;
  1311 
  1312     /* Overflow? */
  1313     if (taCount >= 0x0ccccccc) {
  1314         return M3G_FALSE;
  1315     }
  1316 
  1317     if (m3gCheckSectionDataLength(loader, data, taCount * 20) == M3G_FALSE) return M3G_FALSE;
  1318     for (i = 0; i < taCount; i++) {
  1319         va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
  1320         data += 4;
  1321         if (!m3gLoadFloat(data + 0, &bias[0])) return M3G_FALSE;
  1322         if (!m3gLoadFloat(data + 4, &bias[1])) return M3G_FALSE;
  1323         if (!m3gLoadFloat(data + 8, &bias[2])) return M3G_FALSE;
  1324         if (!m3gLoadFloat(data + 12, &scale)) return M3G_FALSE;
  1325         if (va != NULL) {
  1326             m3gSetTexCoordArray(obj, i, va, scale, bias, 3);
  1327         }
  1328         else {
  1329             return M3G_FALSE;
  1330         }
  1331         data += 16;
  1332     }
  1333 
  1334     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1335 
  1336     return M3G_TRUE;
  1337 }
  1338 
  1339 
  1340 /*!
  1341  * \internal
  1342  * \brief Loads a triangle strip array
  1343  */
  1344 static M3Gbool m3gLoadTsa(Loader *loader)
  1345 {
  1346     M3Gubyte *data;
  1347     M3GIndexBuffer obj = 0;
  1348     M3Gubyte encoding;
  1349     M3Guint startIndex = 0, indicesCount = 0, *indices = NULL;
  1350     M3Guint lengthCount;
  1351     M3Gint *lengths = NULL;
  1352     M3Guint i;
  1353 
  1354     m3gBeginObject(loader);
  1355     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
  1356 
  1357     data = m3gGetSectionDataPtr(loader, 1);
  1358     if (data == NULL) return M3G_FALSE;
  1359 
  1360     encoding = *data++;
  1361 
  1362     switch(encoding) {
  1363     case 0:
  1364         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
  1365         startIndex = m3gLoadInt(data);
  1366         data += 4;
  1367         break;
  1368 
  1369     case 1:
  1370         if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
  1371         startIndex = *data++;
  1372         break;
  1373 
  1374     case 2:
  1375         if (m3gCheckSectionDataLength(loader, data, 2) == M3G_FALSE) return M3G_FALSE;
  1376         startIndex = (M3Gushort) m3gLoadShort(data);
  1377         data += 2;
  1378         break;
  1379 
  1380     case 128:
  1381         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
  1382         indicesCount = m3gLoadInt(data);
  1383         data += 4;
  1384 
  1385         /* Overflow? */
  1386         if (indicesCount >= 0x20000000) {
  1387             return M3G_FALSE;
  1388         }
  1389 
  1390         if (m3gCheckSectionDataLength(loader, data, indicesCount * 4) == M3G_FALSE) return M3G_FALSE;
  1391         indices = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * indicesCount);
  1392         if (!indices) return M3G_FALSE;
  1393         for (i = 0; i < indicesCount; i++ ) {
  1394             indices[i] = m3gLoadInt(data);
  1395             data += 4;
  1396         }
  1397         break;
  1398 
  1399     case 129:
  1400         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
  1401         indicesCount = m3gLoadInt(data);
  1402         data += 4;
  1403         if (m3gCheckSectionDataLength(loader, data, indicesCount) == M3G_FALSE) return M3G_FALSE;
  1404         indices = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * indicesCount);
  1405         if (!indices) return M3G_FALSE;
  1406         for (i = 0; i < indicesCount; i++ ) {
  1407             indices[i] = *data++;
  1408         }
  1409         break;
  1410 
  1411     case 130:
  1412         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
  1413         indicesCount = m3gLoadInt(data);
  1414         data += 4;
  1415 
  1416         /* Overflow? */
  1417         if (indicesCount >= 0x40000000) {
  1418             return M3G_FALSE;
  1419         }
  1420 
  1421         if (m3gCheckSectionDataLength(loader, data, indicesCount * 2) == M3G_FALSE) return M3G_FALSE;
  1422         indices = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * indicesCount);
  1423         if (!indices) return M3G_FALSE;
  1424         for (i = 0; i < indicesCount; i++) {
  1425             indices[i] = (M3Gushort)m3gLoadShort(data);
  1426             data += 2;
  1427         }
  1428         break;
  1429 
  1430     default:
  1431         return M3G_FALSE;
  1432     }
  1433 
  1434     if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) goto cleanup;
  1435     lengthCount = m3gLoadInt(data);
  1436     data += 4;
  1437 
  1438     /* Overflow? */
  1439     if (lengthCount >= 0x20000000) {
  1440         goto cleanup;
  1441     }
  1442 
  1443     if (m3gCheckSectionDataLength(loader, data, lengthCount * 4) == M3G_FALSE) goto cleanup;
  1444     lengths = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * lengthCount);
  1445     if (!lengths) goto cleanup;
  1446 
  1447     for (i = 0; i < lengthCount; i++) {
  1448         lengths[i] = m3gLoadInt(data);
  1449         data += 4;
  1450     }
  1451 
  1452     if (encoding == 0 || encoding == 1 || encoding == 2) {
  1453         obj = m3gCreateImplicitStripBuffer( M3G_INTERFACE(loader),
  1454                                             lengthCount,
  1455                                             lengths,
  1456                                             startIndex);
  1457     }
  1458     else {
  1459         obj = m3gCreateStripBuffer( M3G_INTERFACE(loader),
  1460                                     M3G_TRIANGLE_STRIPS,
  1461                                     lengthCount,
  1462                                     lengths,
  1463                                     M3G_INT,
  1464                                     indicesCount,
  1465                                     indices);
  1466     }
  1467 
  1468 cleanup:
  1469     m3gFree(M3G_INTERFACE(loader), indices);
  1470     m3gFree(M3G_INTERFACE(loader), lengths);
  1471 
  1472     loader->loadedObject = (M3GObject)obj;
  1473     if (!obj) return M3G_FALSE;
  1474 
  1475     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1476 
  1477     m3gEndObject(loader);
  1478     m3gRewindObject(loader);
  1479     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1480         return M3G_FALSE;
  1481     }
  1482     m3gSkipObject(loader);
  1483 
  1484     return M3G_TRUE;
  1485 }
  1486 
  1487 /*!
  1488  * \internal
  1489  * \brief Loads a compositing mode
  1490  */
  1491 static M3Gbool m3gLoadCompositingMode(Loader *loader)
  1492 {
  1493     M3Gfloat f1, f2;
  1494     M3Gubyte *data;
  1495     M3GCompositingMode obj = m3gCreateCompositingMode(M3G_INTERFACE(loader));
  1496     loader->loadedObject = (M3GObject)obj;
  1497     if (!obj) return M3G_FALSE;
  1498 
  1499     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1500         return M3G_FALSE;
  1501     }
  1502 
  1503     data = m3gGetSectionDataPtr(loader, 14);
  1504     if (data == NULL) return M3G_FALSE;
  1505 
  1506     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1507     m3gEnableDepthTest      (obj, *data++);
  1508     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1509     m3gEnableDepthWrite     (obj, *data++);
  1510     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1511     m3gEnableColorWrite     (obj, *data++);
  1512     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1513     m3gSetAlphaWriteEnable  (obj, *data++);
  1514     m3gSetBlending          (obj, *data++);
  1515     {
  1516         unsigned a = *data++; 
  1517         m3gSetAlphaThreshold(obj, m3gDivif(a, 255));
  1518     }
  1519     if (!m3gLoadFloat(data, &f1) || !m3gLoadFloat(data + 4, &f2)) return M3G_FALSE;
  1520     m3gSetDepthOffset       (obj, f1, f2);
  1521     data += 8;
  1522 
  1523     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1524 
  1525     return M3G_TRUE;
  1526 }
  1527 
  1528 /*!
  1529  * \internal
  1530  * \brief Loads a polygon mode
  1531  */
  1532 static M3Gbool m3gLoadPolygonMode(Loader *loader)
  1533 {
  1534     M3Gubyte *data;
  1535     M3GPolygonMode obj = m3gCreatePolygonMode(M3G_INTERFACE(loader));
  1536     loader->loadedObject = (M3GObject)obj;
  1537     if (!obj) return M3G_FALSE;
  1538 
  1539     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1540         return M3G_FALSE;
  1541     }
  1542 
  1543     data = m3gGetSectionDataPtr(loader, 6);
  1544     if (data == NULL) return M3G_FALSE;
  1545 
  1546     m3gSetCulling                       (obj, *data++);
  1547     m3gSetShading                       (obj, *data++);
  1548     m3gSetWinding                       (obj, *data++);
  1549     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1550     m3gSetTwoSidedLightingEnable        (obj, *data++);
  1551     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1552     m3gSetLocalCameraLightingEnable     (obj, *data++);
  1553     if (!m3gVerifyBool(data)) return M3G_FALSE;
  1554     m3gSetPerspectiveCorrectionEnable   (obj, *data++);
  1555 
  1556     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1557 
  1558     return M3G_TRUE;
  1559 }
  1560 
  1561 /*!
  1562  * \internal
  1563  * \brief Loads an appearance
  1564  */
  1565 static M3Gbool m3gLoadAppearance(Loader *loader)
  1566 {
  1567     M3Guint textures, i;
  1568     M3Gubyte *data;
  1569     M3GAppearance obj = m3gCreateAppearance(M3G_INTERFACE(loader));
  1570     loader->loadedObject = (M3GObject)obj;
  1571     if (!obj) return M3G_FALSE;
  1572 
  1573     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1574         return M3G_FALSE;
  1575     }
  1576 
  1577     data = m3gGetSectionDataPtr(loader, 21);
  1578     if (data == NULL) return M3G_FALSE;
  1579 
  1580     m3gSetLayer(obj, (M3Gbyte)*data++);
  1581     m3gSetCompositingMode(obj, (M3GCompositingMode)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_COMPOSITING_MODE));
  1582     data += 4;
  1583     m3gSetFog(obj, (M3GFog)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_FOG));
  1584     data += 4;
  1585     m3gSetPolygonMode(obj, (M3GPolygonMode)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_POLYGON_MODE));
  1586     data += 4;
  1587     m3gSetMaterial(obj, (M3GMaterial)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_MATERIAL));
  1588     data += 4;
  1589 
  1590     textures = m3gLoadInt(data);
  1591     data += 4;
  1592 
  1593     /* Overflow? */
  1594     if (textures >= 0x20000000) {
  1595         return M3G_FALSE;
  1596     }
  1597 
  1598     if (m3gCheckSectionDataLength(loader, data, textures * 4) == M3G_FALSE) return M3G_FALSE;
  1599     for (i = 0; i < textures; i++) {
  1600         M3GTexture tex = (M3GTexture)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_TEXTURE);
  1601         if (!tex) {
  1602             return M3G_FALSE;
  1603         }
  1604         m3gSetTexture(obj, i, tex);
  1605         data += 4;
  1606     }
  1607 
  1608     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1609 
  1610     return M3G_TRUE;
  1611 }
  1612 
  1613 /*!
  1614  * \internal
  1615  * \brief Loads a mesh
  1616  */
  1617 static M3Gbool m3gLoadMesh(Loader *loader)
  1618 {
  1619     M3Guint subMeshCount, i;
  1620     M3GVertexBuffer vb;
  1621     M3GIndexBuffer *ib = NULL;
  1622     M3GAppearance *ap = NULL;
  1623     M3Gubyte *data;
  1624     M3GMesh obj = NULL;
  1625 
  1626     m3gBeginObject(loader);
  1627     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
  1628 
  1629     data = m3gGetSectionDataPtr(loader, 8);
  1630     if (data == NULL) return M3G_FALSE;
  1631 
  1632     vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
  1633     if (vb == NULL) return M3G_FALSE;
  1634     data += 4;
  1635     subMeshCount = m3gLoadInt(data);
  1636     data += 4;
  1637 
  1638     /* Overflow? */
  1639     if (subMeshCount >= 0x10000000) {
  1640         return M3G_FALSE;
  1641     }
  1642 
  1643     if (m3gCheckSectionDataLength(loader, data, subMeshCount * 8) == M3G_FALSE) return M3G_FALSE;
  1644     ib = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ib) * subMeshCount);
  1645     ap = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ap) * subMeshCount);
  1646     if (!ib || !ap) goto cleanup;
  1647 
  1648     for (i = 0; i < subMeshCount; i++) {
  1649         M3GIndexBuffer indexBuffer;
  1650         indexBuffer = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
  1651         if (indexBuffer != NULL && loader->triConstraint != 0) {
  1652             loader->triCount += indexBuffer->indexCount;
  1653             if (loader->triCount > loader->triConstraint) goto cleanup;
  1654         }
  1655         ib[i] = indexBuffer;
  1656         data += 4;
  1657         ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
  1658         data += 4;
  1659     }
  1660 
  1661     obj = m3gCreateMesh(    M3G_INTERFACE(loader),
  1662                             vb,
  1663                             ib,
  1664                             ap,
  1665                             subMeshCount);
  1666 
  1667 cleanup:
  1668     m3gFree(M3G_INTERFACE(loader), ib);
  1669     m3gFree(M3G_INTERFACE(loader), ap);
  1670     loader->loadedObject = (M3GObject)obj;
  1671     if (!obj) return M3G_FALSE;
  1672 
  1673     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1674 
  1675     m3gEndObject(loader);
  1676     m3gRewindObject(loader);
  1677     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
  1678         return M3G_FALSE;
  1679     }
  1680     m3gSkipObject(loader);
  1681 
  1682     return M3G_TRUE;
  1683 }
  1684 
  1685 /*!
  1686  * \internal
  1687  * \brief Loads group data
  1688  */
  1689 static M3Gbool m3gLoadGroupData(Loader *loader, M3GGroup obj)
  1690 {
  1691     M3Guint childCount, i;
  1692     M3Gubyte *data;
  1693 
  1694     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
  1695         return M3G_FALSE;
  1696     }
  1697 
  1698     data = m3gGetSectionDataPtr(loader, 4);
  1699     if (data == NULL) return M3G_FALSE;
  1700 
  1701     childCount = m3gLoadInt(data);
  1702     data += 4;
  1703 
  1704     /* Overflow? */
  1705     if (childCount >= 0x20000000) {
  1706         return M3G_FALSE;
  1707     }
  1708 
  1709     if (m3gCheckSectionDataLength(loader, data, childCount * 4) == M3G_FALSE) return M3G_FALSE;
  1710     for (i = 0; i < childCount; i++) {
  1711         m3gAddChild(obj, (M3GNode)m3gGetLoaded(loader, m3gLoadInt(data), ANY_NODE_CLASS));
  1712         data += 4;
  1713     }
  1714 
  1715     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1716 
  1717     return M3G_TRUE;
  1718 }
  1719 
  1720 /*!
  1721  * \internal
  1722  * \brief Loads a group
  1723  */
  1724 static M3Gbool m3gLoadGroup(Loader *loader)
  1725 {
  1726     M3GGroup obj = m3gCreateGroup(M3G_INTERFACE(loader));
  1727     loader->loadedObject = (M3GObject)obj;
  1728     if (!obj) return M3G_FALSE;
  1729 
  1730     if (!m3gLoadGroupData(loader, obj)) {
  1731         return M3G_FALSE;
  1732     }
  1733 
  1734     return M3G_TRUE;
  1735 }
  1736 
  1737 /*!
  1738  * \internal
  1739  * \brief Loads a world
  1740  */
  1741 static M3Gbool m3gLoadWorld(Loader *loader)
  1742 {
  1743     M3GCamera cam;
  1744     M3Gubyte *data;
  1745     M3GWorld obj = m3gCreateWorld(M3G_INTERFACE(loader));
  1746     loader->loadedObject = (M3GObject)obj;
  1747     if (!obj) return M3G_FALSE;
  1748 
  1749     if (!m3gLoadGroupData(loader, (M3GGroup)obj)) {
  1750         return M3G_FALSE;
  1751     }
  1752 
  1753     data = m3gGetSectionDataPtr(loader, 8);
  1754     if (data == NULL) return M3G_FALSE;
  1755 
  1756     cam = (M3GCamera)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_CAMERA);
  1757     data += 4;
  1758     if (cam != NULL) {
  1759         m3gSetActiveCamera(obj, cam);
  1760     }
  1761     m3gSetBackground(obj, (M3GBackground)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_BACKGROUND));
  1762     data += 4;
  1763 
  1764     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1765 
  1766     return M3G_TRUE;
  1767 }
  1768 
  1769 /*!
  1770  * \internal
  1771  * \brief Loads a light
  1772  */
  1773 static M3Gbool m3gLoadLight(Loader *loader)
  1774 {
  1775     M3Gfloat f1, f2, f3;
  1776     M3Gubyte *data;
  1777     M3GLight obj = m3gCreateLight(M3G_INTERFACE(loader));
  1778     loader->loadedObject = (M3GObject)obj;
  1779     if (!obj) return M3G_FALSE;
  1780 
  1781     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
  1782         return M3G_FALSE;
  1783     }
  1784 
  1785     data = m3gGetSectionDataPtr(loader, 28);
  1786     if (data == NULL) return M3G_FALSE;
  1787 
  1788     if (!m3gLoadFloat(data, &f1) ||
  1789         !m3gLoadFloat(data + 4, &f2) ||
  1790         !m3gLoadFloat(data + 8, &f3)) return M3G_FALSE;
  1791     m3gSetAttenuation   (obj, f1, f2, f3);
  1792     data += 12;
  1793     m3gSetLightColor    (obj, m3gLoadRGB(data));
  1794     data += 3;
  1795     m3gSetLightMode     (obj, *data++);
  1796     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
  1797     m3gSetIntensity     (obj, f1);
  1798     data += 4;
  1799     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
  1800     m3gSetSpotAngle     (obj, f1);
  1801     data += 4;
  1802     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
  1803     m3gSetSpotExponent  (obj, f1);
  1804     data += 4;
  1805 
  1806     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1807 
  1808     return M3G_TRUE;
  1809 }
  1810 
  1811 /*!
  1812  * \internal
  1813  * \brief Loads a keyframe sequence
  1814  */
  1815 static M3Gbool m3gLoadKeyframeSequence(Loader *loader)
  1816 {
  1817     M3Guint i, j, interpolation, repeatMode, encoding, duration,
  1818             rangeFirst, rangeLast, components, keyFrames, size;
  1819     M3Gfloat *values;
  1820     M3Gubyte *data;
  1821     M3GKeyframeSequence obj;
  1822 
  1823     m3gBeginObject(loader);
  1824     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
  1825 
  1826     data = m3gGetSectionDataPtr(loader, 23);
  1827     if (data == NULL) return M3G_FALSE;
  1828 
  1829     interpolation = *data++;
  1830     repeatMode    = *data++;
  1831     encoding      = *data++;
  1832     duration      = m3gLoadInt(data);
  1833     data += 4;
  1834     rangeFirst    = m3gLoadInt(data);
  1835     data += 4;
  1836     rangeLast     = m3gLoadInt(data);
  1837     data += 4;
  1838     components    = m3gLoadInt(data);
  1839     data += 4;
  1840     keyFrames     = m3gLoadInt(data);
  1841     data += 4;
  1842 
  1843     if (encoding == 0) {
  1844         size = keyFrames * (4 + components * 4);
  1845     }
  1846     else {
  1847         size = components * 8 + keyFrames * (4 + components * (encoding == 1 ? 1 : 2));
  1848     }
  1849 
  1850     /* Overflow? */
  1851     if (size < keyFrames) {
  1852         return M3G_FALSE;
  1853     }
  1854 
  1855     if (m3gCheckSectionDataLength(loader, data, size) == M3G_FALSE) return M3G_FALSE;
  1856 
  1857     obj = m3gCreateKeyframeSequence(M3G_INTERFACE(loader), keyFrames, components, interpolation);
  1858     loader->loadedObject = (M3GObject)obj;
  1859     if (!obj) return M3G_FALSE;
  1860 
  1861     m3gSetRepeatMode(obj, repeatMode);
  1862     m3gSetDuration(obj, duration);
  1863     m3gSetValidRange(obj, rangeFirst, rangeLast);
  1864 
  1865     values = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * components);
  1866     if (!values) return M3G_FALSE;
  1867 
  1868     if (encoding == 0) {
  1869         for (i = 0; i < keyFrames; i++ ) {
  1870             M3Gint time = m3gLoadInt(data);
  1871             data += 4;
  1872 
  1873             for (j = 0; j < components; j++ ) {
  1874                 if (!m3gLoadFloat(data, &values[j])) {
  1875                     m3gFree(M3G_INTERFACE(loader), values);
  1876                     return M3G_FALSE;
  1877                 }
  1878                 data += 4;
  1879             }
  1880 
  1881             m3gSetKeyframe(obj, i, time, components, values);
  1882         }
  1883     }
  1884     else {
  1885         M3Gfloat *vectorBiasScale = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * components * 2);
  1886         if (!vectorBiasScale) {
  1887             m3gFree(M3G_INTERFACE(loader), values);
  1888             return M3G_FALSE;
  1889         }
  1890 
  1891         for (i = 0; i < components; i++ ) {
  1892             if (!m3gLoadFloat(data, &vectorBiasScale[i])) {
  1893                 m3gFree(M3G_INTERFACE(loader), vectorBiasScale);
  1894                 m3gFree(M3G_INTERFACE(loader), values);
  1895                 return M3G_FALSE;
  1896             }
  1897             data += 4;
  1898         }
  1899         for (i = 0; i < components; i++ ) {
  1900             if (!m3gLoadFloat(data, &vectorBiasScale[i + components])) {
  1901                 m3gFree(M3G_INTERFACE(loader), vectorBiasScale);
  1902                 m3gFree(M3G_INTERFACE(loader), values);
  1903                 return M3G_FALSE;
  1904             }
  1905             data += 4;
  1906         }
  1907 
  1908         for (i = 0; i < keyFrames; i++ ) {
  1909             M3Gint time;
  1910             time = m3gLoadInt(data);
  1911             data += 4;
  1912 
  1913             if (encoding == 1) {
  1914                 for (j = 0; j < components; j++ ) {
  1915                     M3Gubyte v = *data++;
  1916                     values[j] = vectorBiasScale[j] + ((vectorBiasScale[j + components] * v ) / 255.0f);
  1917                 }
  1918             }
  1919             else {
  1920                 for (j = 0; j < components; j++ ) {
  1921                     M3Gushort v = m3gLoadShort(data);
  1922                     data += 2;
  1923                     values[j] = vectorBiasScale[j] + ((vectorBiasScale[j + components] * v) / 65535.0f);
  1924                 }
  1925             }
  1926 
  1927             m3gSetKeyframe(obj, i, time, components, values);
  1928         }
  1929 
  1930         m3gFree(M3G_INTERFACE(loader), vectorBiasScale);
  1931     }
  1932 
  1933     m3gFree(M3G_INTERFACE(loader), values);
  1934 
  1935     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1936 
  1937     m3gEndObject(loader);
  1938     m3gRewindObject(loader);
  1939     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1940         return M3G_FALSE;
  1941     }
  1942     m3gSkipObject(loader);
  1943 
  1944     return M3G_TRUE;
  1945 }
  1946 
  1947 /*!
  1948  * \internal
  1949  * \brief Loads an animation controller
  1950  */
  1951 static M3Gbool m3gLoadAnimationController(Loader *loader)
  1952 {
  1953     M3Gfloat speed, weight, referenceSeqTime;
  1954     M3Gint referenceWorldTime;
  1955     M3Gubyte *data;
  1956     M3GAnimationController obj = m3gCreateAnimationController(M3G_INTERFACE(loader));
  1957     loader->loadedObject = (M3GObject)obj;
  1958     if (!obj) return M3G_FALSE;
  1959 
  1960     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  1961         return M3G_FALSE;
  1962     }
  1963 
  1964     data = m3gGetSectionDataPtr(loader, 24);
  1965     if (data == NULL) return M3G_FALSE;
  1966 
  1967     if (!m3gLoadFloat(data, &speed)) return M3G_FALSE;
  1968     data += 4;
  1969     if (!m3gLoadFloat(data, &weight)) return M3G_FALSE;
  1970     data += 4;
  1971     m3gSetActiveInterval(obj, m3gLoadInt(data), m3gLoadInt(data + 4));
  1972     data += 8;
  1973     if (!m3gLoadFloat(data, &referenceSeqTime)) return M3G_FALSE;
  1974     data += 4;
  1975     referenceWorldTime = m3gLoadInt(data);
  1976     data += 4;
  1977 
  1978     m3gSetPosition(obj, referenceSeqTime, referenceWorldTime);
  1979     m3gSetSpeed(obj, speed, referenceWorldTime);
  1980     m3gSetWeight(obj, weight);
  1981 
  1982     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  1983 
  1984     return M3G_TRUE;
  1985 }
  1986 
  1987 /*!
  1988  * \internal
  1989  * \brief Loads an animation track
  1990  */
  1991 static M3Gbool m3gLoadAnimationTrack(Loader *loader)
  1992 {
  1993     M3Gint property;
  1994     M3GKeyframeSequence ks;
  1995     M3GAnimationController ac;
  1996     M3Gubyte *data;
  1997     M3GAnimationTrack obj;
  1998 
  1999     m3gBeginObject(loader);
  2000     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
  2001 
  2002     data = m3gGetSectionDataPtr(loader, 12);
  2003     if (data == NULL) return M3G_FALSE;
  2004 
  2005     ks = (M3GKeyframeSequence)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_KEYFRAME_SEQUENCE);
  2006     data += 4;
  2007     ac = (M3GAnimationController)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_ANIMATION_CONTROLLER);
  2008     data += 4;
  2009     property = m3gLoadInt(data);
  2010     data += 4;
  2011 
  2012     obj = m3gCreateAnimationTrack(M3G_INTERFACE(loader), ks, property);
  2013     loader->loadedObject = (M3GObject)obj;
  2014     if (!obj) return M3G_FALSE;
  2015 
  2016     m3gSetController(obj, ac);
  2017 
  2018     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2019 
  2020     m3gEndObject(loader);
  2021     m3gRewindObject(loader);
  2022     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  2023         return M3G_FALSE;
  2024     }
  2025     m3gSkipObject(loader);
  2026 
  2027     return M3G_TRUE;
  2028 }
  2029 
  2030 /*!
  2031  * \internal
  2032  * \brief Loads a material
  2033  */
  2034 static M3Gbool m3gLoadMaterial(Loader *loader)
  2035 {
  2036     M3Gfloat f1;
  2037     M3Gubyte *data;
  2038     M3GMaterial obj = m3gCreateMaterial(M3G_INTERFACE(loader));
  2039     loader->loadedObject = (M3GObject)obj;
  2040     if (!obj) return M3G_FALSE;
  2041 
  2042     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  2043         return M3G_FALSE;
  2044     }
  2045 
  2046     data = m3gGetSectionDataPtr(loader, 18);
  2047     if (data == NULL) return M3G_FALSE;
  2048 
  2049     m3gSetColor(obj, M3G_AMBIENT_BIT, m3gLoadRGB(data));
  2050     data += 3;
  2051     m3gSetColor(obj, M3G_DIFFUSE_BIT, m3gLoadARGB(data));
  2052     data += 4;
  2053     m3gSetColor(obj, M3G_EMISSIVE_BIT, m3gLoadRGB(data));
  2054     data += 3;
  2055     m3gSetColor(obj, M3G_SPECULAR_BIT, m3gLoadRGB(data));
  2056     data += 3;
  2057     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
  2058     m3gSetShininess(obj, f1);
  2059     data += 4;
  2060     if (!m3gVerifyBool(data)) return M3G_FALSE;
  2061     m3gSetVertexColorTrackingEnable(obj, *data++);
  2062 
  2063     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2064 
  2065     return M3G_TRUE;
  2066 }
  2067 
  2068 /*!
  2069  * \internal
  2070  * \brief Loads a fog
  2071  */
  2072 static M3Gbool m3gLoadFog(Loader *loader)
  2073 {
  2074     M3Gfloat f1, f2;
  2075     M3Gubyte *data;
  2076     M3GFog obj = m3gCreateFog(M3G_INTERFACE(loader));
  2077     loader->loadedObject = (M3GObject)obj;
  2078     if (!obj) return M3G_FALSE;
  2079 
  2080     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  2081         return M3G_FALSE;
  2082     }
  2083 
  2084     data = m3gGetSectionDataPtr(loader, 4);
  2085     if (data == NULL) return M3G_FALSE;
  2086 
  2087     m3gSetFogColor(obj, m3gLoadRGB(data));
  2088     data += 3;
  2089     m3gSetFogMode(obj, *data);
  2090 
  2091     if (*data++ == M3G_EXPONENTIAL_FOG) {
  2092         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
  2093         if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
  2094         m3gSetFogDensity(obj, f1);
  2095         data += 4;
  2096     }
  2097     else {
  2098         if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
  2099         if (!m3gLoadFloat(data, &f1) || !m3gLoadFloat(data + 4, &f2)) return M3G_FALSE;
  2100         m3gSetFogLinear(obj, f1, f2);
  2101         data += 8;
  2102     }
  2103 
  2104     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2105 
  2106     return M3G_TRUE;
  2107 }
  2108 
  2109 /*!
  2110  * \internal
  2111  * \brief Loads an image
  2112  */
  2113 static M3Gbool m3gLoadImage(Loader *loader)
  2114 {
  2115     M3GImageFormat format;
  2116     M3Guint width, height;
  2117     M3Gbyte isMutable;
  2118     M3Gubyte *data;
  2119     M3GImage obj;
  2120 
  2121     m3gBeginObject(loader);
  2122     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
  2123 
  2124     data = m3gGetSectionDataPtr(loader, 10);
  2125     if (data == NULL) return M3G_FALSE;
  2126 
  2127     format = (M3GImageFormat)*data++;
  2128     if (!m3gVerifyBool(data)) return M3G_FALSE;
  2129     isMutable = *data++;
  2130     width = m3gLoadInt(data);
  2131     data += 4;
  2132     height = m3gLoadInt(data);
  2133     data += 4;
  2134 
  2135     if (isMutable) {
  2136         obj = m3gCreateImage(M3G_INTERFACE(loader), format,
  2137                                                     width, height,
  2138                                                     M3G_RENDERING_TARGET);
  2139     }
  2140     else {
  2141         M3Gubyte *palette = NULL, *pixels = NULL;
  2142         M3Gint paletteLength, pixelsLength, bpp;
  2143 
  2144         switch(format) {
  2145         case M3G_ALPHA:             bpp = 1; break;
  2146         case M3G_LUMINANCE:         bpp = 1; break;
  2147         case M3G_LUMINANCE_ALPHA:   bpp = 2; break;
  2148         case M3G_RGB:               bpp = 3; break;
  2149         case M3G_RGBA:              bpp = 4; break;
  2150         default:                    return M3G_FALSE;
  2151         }
  2152 
  2153         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
  2154         paletteLength = m3gLoadInt(data);
  2155         data += 4;
  2156 
  2157         if (paletteLength > 0) {
  2158             if (m3gCheckSectionDataLength(loader, data, paletteLength) == M3G_FALSE) return M3G_FALSE;
  2159             palette = data;
  2160             data += paletteLength;
  2161         }
  2162 
  2163         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
  2164         pixelsLength = m3gLoadInt(data);
  2165         data += 4;
  2166         if (m3gCheckSectionDataLength(loader, data, pixelsLength) == M3G_FALSE) return M3G_FALSE;
  2167         pixels = data;
  2168         data += pixelsLength;
  2169 
  2170         if (palette != NULL) {
  2171             obj = m3gCreateImage(M3G_INTERFACE(loader), format,
  2172                                                         width, height,
  2173                                                         M3G_PALETTED);
  2174             if (obj != NULL) {
  2175                 M3Gint numEntries = paletteLength / bpp;
  2176                 if (numEntries > 256) {
  2177                     numEntries = 256;
  2178                 }
  2179                 m3gSetImage(obj, pixels);
  2180                 m3gSetImagePalette(obj, numEntries, palette);
  2181                 m3gCommitImage(obj);
  2182             }
  2183         }
  2184         else {
  2185             obj = m3gCreateImage(M3G_INTERFACE(loader), format,
  2186                                                         width, height,
  2187                                                         0);
  2188             if (obj != NULL) {
  2189                 m3gSetImage(obj, pixels);
  2190                 m3gCommitImage(obj);
  2191             }
  2192         }
  2193     }
  2194 
  2195     loader->loadedObject = (M3GObject)obj;
  2196     if (!obj) return M3G_FALSE;
  2197 
  2198     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2199 
  2200     m3gEndObject(loader);
  2201     m3gRewindObject(loader);
  2202     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
  2203         return M3G_FALSE;
  2204     }
  2205     m3gSkipObject(loader);
  2206 
  2207     return M3G_TRUE;
  2208 }
  2209 
  2210 /*!
  2211  * \internal
  2212  * \brief Loads a texture
  2213  */
  2214 static M3Gbool m3gLoadTexture(Loader *loader)
  2215 {
  2216     M3GImage image;
  2217     M3Gubyte *data;
  2218     M3GTexture obj;
  2219 
  2220     m3gBeginObject(loader);
  2221     if (!m3gSkipTransformableData(loader)) return M3G_FALSE;
  2222 
  2223     data = m3gGetSectionDataPtr(loader, 12);
  2224     if (data == NULL) return M3G_FALSE;
  2225 
  2226     image = (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE);
  2227     data += 4;
  2228 
  2229     obj = m3gCreateTexture(M3G_INTERFACE(loader), image);
  2230     loader->loadedObject = (M3GObject)obj;
  2231     if (!obj) return M3G_FALSE;
  2232 
  2233     m3gSetBlendColor(obj, m3gLoadRGB(data));
  2234     data += 3;
  2235     m3gTextureSetBlending(obj, *data++);
  2236     m3gSetWrapping(obj, data[0], data[1]);
  2237     data += 2;
  2238     m3gSetFiltering(obj, data[0], data[1]);
  2239     data += 2;
  2240 
  2241     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2242 
  2243     m3gEndObject(loader);
  2244     m3gRewindObject(loader);
  2245     if (!m3gLoadTransformableData(loader, (M3GTransformable)obj)) {
  2246         return M3G_FALSE;
  2247     }
  2248     m3gSkipObject(loader);
  2249 
  2250     return M3G_TRUE;
  2251 }
  2252 
  2253 /*!
  2254  * \internal
  2255  * \brief Loads a skinned mesh
  2256  */
  2257 static M3Gbool m3gLoadSkinnedMesh(Loader *loader)
  2258 {
  2259     M3GVertexBuffer vb;
  2260     M3Guint i, subMeshCount, transformReferenceCount, firstVertex, vertexCount;
  2261     M3Gint weight;
  2262     M3GIndexBuffer *ib = NULL;
  2263     M3GAppearance *ap = NULL;
  2264     M3GGroup skeleton;
  2265     M3GNode bone;
  2266     M3Gubyte *data;
  2267     M3GSkinnedMesh obj = NULL;
  2268 
  2269     m3gBeginObject(loader);
  2270     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
  2271 
  2272     data = m3gGetSectionDataPtr(loader, 8);
  2273     if (data == NULL) return M3G_FALSE;
  2274 
  2275     vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
  2276     if (vb == NULL) return M3G_FALSE;
  2277     data += 4;
  2278     subMeshCount = m3gLoadInt(data);
  2279     data += 4;
  2280 
  2281     /* Overflow? */
  2282     if (subMeshCount >= 0x10000000) {
  2283         return M3G_FALSE;
  2284     }
  2285 
  2286     if (m3gCheckSectionDataLength(loader, data, subMeshCount * 8) == M3G_FALSE) return M3G_FALSE;
  2287     ib = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ib) * subMeshCount);
  2288     ap = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ap) * subMeshCount);
  2289     if (!ib || !ap) goto cleanup;
  2290 
  2291     for (i = 0; i < subMeshCount; i++) {
  2292         ib[i] = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
  2293         data += 4;
  2294         ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
  2295         data += 4;
  2296     }
  2297 
  2298     if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) goto cleanup;
  2299     skeleton = (M3GGroup)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_GROUP);
  2300     data += 4;
  2301 
  2302     obj = m3gCreateSkinnedMesh( M3G_INTERFACE(loader),
  2303                                 vb,
  2304                                 ib,
  2305                                 ap,
  2306                                 subMeshCount,
  2307                                 skeleton);
  2308 
  2309 cleanup:
  2310     m3gFree(M3G_INTERFACE(loader), ib);
  2311     m3gFree(M3G_INTERFACE(loader), ap);
  2312     loader->loadedObject = (M3GObject)obj;
  2313     if (!obj) return M3G_FALSE;
  2314 
  2315     transformReferenceCount = m3gLoadInt(data);
  2316     data += 4;
  2317 
  2318     /* Overflow? */
  2319     if (transformReferenceCount >= 0x08000000) {
  2320         return M3G_FALSE;
  2321     }
  2322 
  2323     if (m3gCheckSectionDataLength(loader, data, transformReferenceCount * 16) == M3G_FALSE) return M3G_FALSE;
  2324     for (i = 0; i < transformReferenceCount; i++) {
  2325         bone        = (M3GNode)m3gGetLoaded(loader, m3gLoadInt(data), ANY_NODE_CLASS);
  2326         data += 4;
  2327         firstVertex = m3gLoadInt(data);
  2328         data += 4;
  2329         vertexCount = m3gLoadInt(data);
  2330         data += 4;
  2331         weight      = m3gLoadInt(data);
  2332         data += 4;
  2333         m3gAddTransform(obj, bone, weight, firstVertex, vertexCount);
  2334     }
  2335 
  2336     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2337 
  2338     m3gEndObject(loader);
  2339     m3gRewindObject(loader);
  2340     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
  2341         return M3G_FALSE;
  2342     }
  2343     m3gSkipObject(loader);
  2344 
  2345     return M3G_TRUE;
  2346 }
  2347 
  2348 /*!
  2349  * \internal
  2350  * \brief Loads a morphing mesh
  2351  */
  2352 static M3Gbool m3gLoadMorphingMesh(Loader *loader)
  2353 {
  2354     M3GVertexBuffer vb, *targets = NULL;
  2355     M3Guint i, subMeshCount, targetCount;
  2356     M3Gfloat *weights = NULL;
  2357     M3GIndexBuffer *ib = NULL;
  2358     M3GAppearance *ap = NULL;
  2359     M3Gubyte *data;
  2360     M3GMorphingMesh obj = NULL;
  2361 
  2362     m3gBeginObject(loader);
  2363     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
  2364 
  2365     data = m3gGetSectionDataPtr(loader, 8);
  2366     if (data == NULL) return M3G_FALSE;
  2367 
  2368     vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
  2369     if (vb == NULL) return M3G_FALSE;
  2370     data += 4;
  2371     subMeshCount = m3gLoadInt(data);
  2372     data += 4;
  2373 
  2374     /* Overflow? */
  2375     if (subMeshCount >= 0x10000000) {
  2376         return M3G_FALSE;
  2377     }
  2378 
  2379     if (m3gCheckSectionDataLength(loader, data, subMeshCount * 8) == M3G_FALSE) return M3G_FALSE;
  2380     ib = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ib) * subMeshCount);
  2381     ap = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ap) * subMeshCount);
  2382     if (!ib || !ap) goto cleanup;
  2383 
  2384     for (i = 0; i < subMeshCount; i++) {
  2385         ib[i] = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
  2386         data += 4;
  2387         ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
  2388         data += 4;
  2389     }
  2390 
  2391     if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) goto cleanup;
  2392     targetCount = m3gLoadInt(data);
  2393     data += 4;
  2394 
  2395     /* Overflow? */
  2396     if (targetCount >= 0x10000000) {
  2397         goto cleanup;
  2398     }
  2399 
  2400     if (m3gCheckSectionDataLength(loader, data, targetCount * 8) == M3G_FALSE) goto cleanup;
  2401     weights = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * targetCount);
  2402     targets = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*targets) * targetCount);
  2403     if (!weights || !targets) goto cleanup;
  2404 
  2405     for (i = 0; i < targetCount; i++) {
  2406         targets[i] = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
  2407         data += 4;
  2408         if (!m3gLoadFloat(data, &weights[i])) goto cleanup;
  2409         data += 4;
  2410     }
  2411 
  2412     obj = m3gCreateMorphingMesh(    M3G_INTERFACE(loader),
  2413                                     vb,
  2414                                     targets,
  2415                                     ib,
  2416                                     ap,
  2417                                     subMeshCount,
  2418                                     targetCount);
  2419 
  2420 cleanup:
  2421     m3gFree(M3G_INTERFACE(loader), ib);
  2422     m3gFree(M3G_INTERFACE(loader), ap);
  2423     m3gFree(M3G_INTERFACE(loader), targets);
  2424     m3gFree(M3G_INTERFACE(loader), weights);
  2425     loader->loadedObject = (M3GObject)obj;
  2426     if (!obj) return M3G_FALSE;
  2427 
  2428     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2429 
  2430     m3gEndObject(loader);
  2431     m3gRewindObject(loader);
  2432     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
  2433         return M3G_FALSE;
  2434     }
  2435     m3gSkipObject(loader);
  2436 
  2437     return M3G_TRUE;
  2438 }
  2439 
  2440 /*!
  2441  * \internal
  2442  * \brief Loads a sprite
  2443  */
  2444 static M3Gbool m3gLoadSprite(Loader *loader)
  2445 {
  2446     M3GImage image;
  2447     M3GAppearance appearance;
  2448     M3Gubyte *data;
  2449     M3GSprite obj;
  2450 
  2451     m3gBeginObject(loader);
  2452     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
  2453 
  2454     data = m3gGetSectionDataPtr(loader, 25);
  2455     if (data == NULL) return M3G_FALSE;
  2456 
  2457     image = (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE);
  2458     data += 4;
  2459     appearance = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
  2460     data += 4;
  2461 
  2462     if (!m3gVerifyBool(data)) return M3G_FALSE;
  2463     obj = m3gCreateSprite(  M3G_INTERFACE(loader),
  2464                             *data++,
  2465                             image,
  2466                             appearance);
  2467     loader->loadedObject = (M3GObject)obj;
  2468     if (!obj) return M3G_FALSE;
  2469 
  2470     m3gSetCrop(obj, m3gLoadInt(data),
  2471                     m3gLoadInt(data + 4),
  2472                     m3gLoadInt(data + 8),
  2473                     m3gLoadInt(data + 12));
  2474     data += 16;
  2475 
  2476     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2477 
  2478     m3gEndObject(loader);
  2479     m3gRewindObject(loader);
  2480     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
  2481         return M3G_FALSE;
  2482     }
  2483     m3gSkipObject(loader);
  2484 
  2485     return M3G_TRUE;
  2486 }
  2487 
  2488 /*!
  2489  * \internal
  2490  * \brief Loads a M3G file header
  2491  */
  2492 static M3Gbool m3gLoadHeader(Loader *loader)
  2493 {
  2494     M3Gubyte *data;
  2495     data = m3gGetSectionDataPtr(loader, 12);
  2496     if (data == NULL) return M3G_FALSE;
  2497 
  2498     /* Check version */
  2499     if (data[0] != 1 || data[1] != 0 || loader->sectionNum != 0) {
  2500         return M3G_FALSE;
  2501     }
  2502     data += 2;
  2503 
  2504     if (!m3gVerifyBool(data)) return M3G_FALSE;
  2505     loader->hasReferences = *data++;
  2506     loader->fileSize = m3gLoadInt(data);
  2507     data += 4;
  2508     loader->contentSize = m3gLoadInt(data);
  2509     data += 4;
  2510 
  2511     /* Skip authoring field */
  2512     while(*data++)
  2513         if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
  2514 
  2515     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2516 
  2517     return M3G_TRUE;
  2518 }
  2519 
  2520 /*!
  2521  * \internal
  2522  * \brief Skips external reference
  2523  */
  2524 static M3Gbool m3gLoadExternalReference(Loader *loader)
  2525 {
  2526     M3Gubyte *data;
  2527     if (loader->sectionNum != 1 || !loader->hasReferences)
  2528         return M3G_FALSE;
  2529     data = m3gGetSectionDataPtr(loader, 1);
  2530     while(*data++) { /* Skip string */
  2531         if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE)
  2532             return M3G_FALSE;
  2533     }
  2534     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
  2535     return M3G_TRUE;
  2536 }
  2537 
  2538 /*!
  2539  * \internal
  2540  * \brief Loads an object
  2541  */
  2542 static LoaderState m3gLoadObject(Loader *loader)
  2543 {
  2544     M3Gubyte *data = m3gGetSectionDataPtr(loader, loader->sectionBytesRequired);
  2545 
  2546     if (data == NULL) {
  2547         loader->localState = LOADSTATE_CHECKSUM;
  2548         return LOADSTATE_SECTION;
  2549     }
  2550 
  2551     m3gAdvanceSectionData(loader, loader->sectionBytesRequired);
  2552 
  2553     if (loader->localState == LOADSTATE_ENTER) {
  2554         M3Gbool status = M3G_TRUE;
  2555 
  2556         loader->objectType = *data++;
  2557         loader->loadedObject = NULL;
  2558         loader->localState = LOADSTATE_EXIT;
  2559         loader->sectionBytesRequired = m3gLoadInt(data);
  2560         data += 4;
  2561         if (loader->sectionNum == 0 && loader->objectType != 0) {
  2562             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
  2563             return LOADSTATE_ERROR;
  2564         }
  2565 
  2566         switch(loader->objectType) {
  2567         case 0: /* Header Object */
  2568             status = m3gLoadHeader(loader);
  2569             break;
  2570         case 1: /* AnimationController */
  2571             status = m3gLoadAnimationController(loader);
  2572             break;
  2573         case 2: /* AnimationTrack */
  2574             status = m3gLoadAnimationTrack(loader);
  2575             break;
  2576         case 3: /* Appearance */
  2577             status = m3gLoadAppearance(loader);
  2578             break;
  2579         case 4: /* Background */
  2580             status = m3gLoadBackground(loader);
  2581             break;
  2582         case 5: /* Camera */
  2583             status = m3gLoadCamera(loader);
  2584             break;
  2585         case 6: /* CompositingMode */
  2586             status = m3gLoadCompositingMode(loader);
  2587             break;
  2588         case 7: /* Fog */
  2589             status = m3gLoadFog(loader);
  2590             break;
  2591         case 8: /* PolygonMode */
  2592             status = m3gLoadPolygonMode(loader);
  2593             break;
  2594         case 9: /* Group */
  2595             status = m3gLoadGroup(loader);
  2596             break;
  2597         case 10: /* Image2D */
  2598             status = m3gLoadImage(loader);
  2599             break;
  2600         case 11: /* TriangleStripArray */
  2601             status = m3gLoadTsa(loader);
  2602             break;
  2603         case 12: /* Light */
  2604             status = m3gLoadLight(loader);
  2605             break;
  2606         case 13: /* Material */
  2607             status = m3gLoadMaterial(loader);
  2608             break;
  2609         case 14: /* Mesh */
  2610             status = m3gLoadMesh(loader);
  2611             break;
  2612         case 15: /* MorphingMesh */
  2613             status = m3gLoadMorphingMesh(loader);
  2614             break;
  2615         case 16: /* SkinnedMesh */
  2616             status = m3gLoadSkinnedMesh(loader);
  2617             break;
  2618         case 17: /* Texture2D */
  2619             status = m3gLoadTexture(loader);
  2620             break;
  2621         case 18: /* Sprite */
  2622             status = m3gLoadSprite(loader);
  2623             break;
  2624         case 19: /* KeyframeSequence */
  2625             status = m3gLoadKeyframeSequence(loader);
  2626             break;
  2627         case 20: /* VertexArray */
  2628             status = m3gLoadVertexArray(loader);
  2629             break;
  2630         case 21: /* VertexBuffer */
  2631             status = m3gLoadVertexBuffer(loader);
  2632             break;
  2633         case 22: /* World */
  2634             status = m3gLoadWorld(loader);
  2635             break;
  2636         case 255: /* External Reference */
  2637             status = m3gLoadExternalReference(loader);
  2638             break;
  2639         default:  /* 23 ... 254 Reserved for use in future versions of the file format */
  2640             status = M3G_FALSE;
  2641             break;
  2642         }
  2643 
  2644         /* Check if object loading caused an error */
  2645         if (m3gErrorRaised(M3G_INTERFACE(loader))) {
  2646             m3gDeleteObject(loader->loadedObject);
  2647             return LOADSTATE_ERROR;
  2648         }
  2649         if (!status || 
  2650             m3gGetSectionDataPtr(loader, 0) != data + loader->sectionBytesRequired) {
  2651             m3gDeleteObject(loader->loadedObject);
  2652             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
  2653             return LOADSTATE_ERROR;
  2654         }
  2655         loader->sectionBytesRequired = 0;
  2656         
  2657         /* Add object to loaded objects array */
  2658         if (loader->loadedObject != NULL) {
  2659             if (m3gArrayAppend(&loader->refArray, loader->loadedObject, M3G_INTERFACE(loader)) == -1) {
  2660                 /* OOM */
  2661                 m3gDeleteObject(loader->loadedObject);
  2662                 return LOADSTATE_ERROR;
  2663             }
  2664             m3gAddRef(loader->loadedObject);
  2665         }
  2666     }
  2667     else {
  2668         loader->sectionBytesRequired = M3G_MIN_OBJECT_SIZE;
  2669         loader->localState = LOADSTATE_ENTER;
  2670     }
  2671 
  2672     return LOADSTATE_OBJECT;
  2673 }
  2674 
  2675 /*!
  2676  * \internal
  2677  * \brief Handles branching to different subroutines upon re-entry
  2678  *
  2679  * When sufficient data is available in internal buffers, this
  2680  * function gets called and directs execution into the coroutine
  2681  * matching the current global state.
  2682  */
  2683 static LoaderState m3gLoaderMain(Loader *loader)
  2684 {
  2685     M3G_VALIDATE_OBJECT(loader);
  2686     M3G_ASSERT(loader->bytesRequired > 0);
  2687     M3G_ASSERT(loader->bytesRequired <= loader->stream.bytesAvailable);
  2688 
  2689     switch (loader->state) {
  2690     case LOADSTATE_INITIAL:
  2691         loader->stream.totalBytes = 0;
  2692         loader->localState = LOADSTATE_ENTER;
  2693         loader->fileSize = 0x00ffffff;
  2694         loader->bytesRequired = sizeof(PNG_FILE_IDENTIFIER);
  2695         return LOADSTATE_IDENTIFIER;
  2696     case LOADSTATE_IDENTIFIER:
  2697         return m3gLoadIdentifier(loader);
  2698     case LOADSTATE_SECTION:
  2699         return m3gLoadSection(loader);
  2700     case LOADSTATE_OBJECT:
  2701         return m3gLoadObject(loader);
  2702     default:
  2703         loader->bytesRequired = 0;
  2704         return LOADSTATE_ERROR;
  2705     }
  2706 }
  2707 
  2708 /*!
  2709  * \brief Deletes all unreferenced objects
  2710  */
  2711 static void m3gCleanupLoader(M3GLoader loader)
  2712 {
  2713     M3Gint i, j, n;
  2714     PointerArray *refs;
  2715     M3Gbool referenced;
  2716     M3GObject obj;    
  2717 
  2718     refs = &loader->refArray;
  2719     n = m3gArraySize(refs);
  2720 
  2721     /* All unreferenced objects will be deleted, as their ref count becomes 0 */
  2722     for (i = 0; i < n; ++i) {
  2723         obj = m3gGetLoadedPtr(refs, i, &referenced);
  2724         m3gDeleteRef(obj);
  2725     }
  2726     m3gClearArray(&loader->refArray);
  2727 
  2728     n = m3gArraySize(&loader->userDataArray);
  2729     for (i = 0; i < n; ++i)
  2730     {
  2731         UserData *data = (UserData *)m3gGetArrayElement(&loader->userDataArray, i);
  2732         for (j = 0; j < data->numParams; ++j)
  2733             m3gFree(M3G_INTERFACE(loader), data->params[j]);
  2734         m3gFree(M3G_INTERFACE(loader), data->params);
  2735         m3gFree(M3G_INTERFACE(loader), data->paramLengths);
  2736         m3gFree(M3G_INTERFACE(loader), data->paramId);
  2737         m3gFree(M3G_INTERFACE(loader), data);
  2738     }
  2739     m3gClearArray(&loader->userDataArray);
  2740 
  2741     m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
  2742     loader->allocatedSectionData = NULL;
  2743 }
  2744 
  2745 /*!
  2746  * \internal
  2747  * \brief Resets the loader
  2748  */
  2749 static void m3gResetLoader(Loader *loader)
  2750 {
  2751     /* Reset loader state */
  2752     loader->state = LOADSTATE_INITIAL;
  2753     loader->bytesRequired = sizeof(PNG_FILE_IDENTIFIER);
  2754 
  2755     m3gCleanupLoader(loader);
  2756     m3gResetBufferedData(&loader->stream);
  2757 }
  2758 
  2759 /*----------------------------------------------------------------------
  2760  * Virtual function table
  2761  *--------------------------------------------------------------------*/
  2762 
  2763 static const ObjectVFTable m3gvf_Loader = {
  2764     NULL, /* ApplyAnimation */
  2765     NULL, /* IsCompatible */
  2766     NULL, /* UpdateProperty */
  2767     NULL, /* DoGetReferences */
  2768     NULL, /* FindID */
  2769     NULL, /* Duplicate */
  2770     m3gDestroyLoader
  2771 };
  2772     
  2773 
  2774 /*----------------------------------------------------------------------
  2775  * Public interface
  2776  *--------------------------------------------------------------------*/
  2777 
  2778 /*!
  2779  * \brief Creates a new loader instance
  2780  */
  2781 M3G_API M3GLoader m3gCreateLoader(M3GInterface m3g)
  2782 {
  2783     Loader *loader;
  2784     M3G_VALIDATE_INTERFACE(m3g);
  2785 
  2786     loader = m3gAllocZ(m3g, sizeof(*loader));
  2787     if (loader != NULL) {
  2788         m3gInitObject(&loader->object, m3g, M3G_CLASS_LOADER);
  2789         m3gInitArray(&loader->refArray);
  2790         m3gInitArray(&loader->userDataArray);
  2791         loader->bytesRequired = sizeof(PNG_FILE_IDENTIFIER);
  2792         loader->state = LOADSTATE_INITIAL;
  2793         loader->sectionNum = -1;
  2794     }
  2795     return loader;
  2796 }
  2797 
  2798 /*!
  2799  * \brief Import a set of objects into the reference table of a loader
  2800  *
  2801  * This is intended for passing in external references, decoded in
  2802  * Java
  2803  */
  2804 M3G_API void m3gImportObjects(M3GLoader loader, M3Gint n, M3GObject *refs)
  2805 {
  2806     int i;
  2807     M3G_VALIDATE_OBJECT(loader);
  2808 
  2809     if (loader->state == LOADSTATE_DONE)
  2810         m3gResetLoader(loader);
  2811     for (i = 0; i < n; ++i) {
  2812         /* For loop is interrupted in case of OOM */
  2813         if (m3gArrayAppend(&loader->refArray,
  2814                            refs[i],
  2815                            M3G_INTERFACE(loader)) == -1) {
  2816             break;
  2817         }
  2818         m3gAddRef(refs[i]);
  2819     }
  2820 }
  2821 
  2822 /*!
  2823  * \brief Return the complete reference table for this loader instance
  2824  *
  2825  * The reference table will contain the handle of each object that has
  2826  * been loaded so far.
  2827  *
  2828  * \param loader loader instance
  2829  * \param buffer destination buffer, or NULL to just get
  2830  *               the number of unreferenced objects
  2831  * \return number of unreferenced objects
  2832  */
  2833 M3G_API M3Gint m3gGetLoadedObjects(M3GLoader loader, M3GObject *buffer)
  2834 {
  2835     PointerArray *refs;
  2836     int i, n, unref = 0;
  2837     M3Gbool referenced;
  2838     M3GObject obj, *dst = buffer;
  2839     M3G_VALIDATE_OBJECT(loader);
  2840 
  2841     /* If error in decoding, reset and return 0 objects */
  2842     if (loader->state < LOADSTATE_INITIAL) {
  2843         return 0;
  2844     }
  2845 
  2846     refs = &loader->refArray;
  2847     n = m3gArraySize(refs);
  2848 
  2849     /* Scan unreferenced objects */
  2850     for (i = 0; i < n; ++i) {
  2851         obj = m3gGetLoadedPtr(refs, i, &referenced);
  2852         if (!referenced) {
  2853             unref++;
  2854             if (dst != NULL) {
  2855                 *dst++ = obj;
  2856             }
  2857         }
  2858     }
  2859 
  2860     return unref;
  2861 }
  2862 
  2863 /*!
  2864  * \brief Submits data to the loader for processing
  2865  *
  2866  * Upon data input, the loader will either read more objects from the
  2867  * stream or buffer the data for processing later on. The return value
  2868  * will indicate how many bytes of data are required before the next
  2869  * data element can be loaded, but that data can still be submitted in
  2870  * smaller blocks.
  2871  *
  2872  * \param loader the loader instance
  2873  * \param bytes  the number of bytes in the data
  2874  * \param data   pointer to the data
  2875  *
  2876  * \return the number of bytes required to load the next data element,
  2877  * or zero to indicate that loading has finished
  2878  */
  2879 
  2880 #ifdef M3G_ENABLE_PROFILING
  2881 static M3Gsizei m3gDecodeDataInternal(M3GLoader loader,
  2882                                M3Gsizei bytes,
  2883                                const M3Gubyte *data);
  2884 
  2885 M3G_API M3Gsizei m3gDecodeData(M3GLoader loader,
  2886                                M3Gsizei bytes,
  2887                                const M3Gubyte *data)
  2888 {
  2889     M3Gsizei bytesReq;
  2890     M3G_BEGIN_PROFILE(M3G_INTERFACE(loader), M3G_PROFILE_LOADER_DECODE);
  2891     bytesReq = m3gDecodeDataInternal(loader, bytes, data);
  2892     M3G_END_PROFILE(M3G_INTERFACE(loader), M3G_PROFILE_LOADER_DECODE);
  2893     return bytesReq;
  2894 }
  2895 
  2896 static M3Gsizei m3gDecodeDataInternal(M3GLoader loader,
  2897                                M3Gsizei bytes,
  2898                                const M3Gubyte *data)
  2899 
  2900 #else
  2901 M3G_API M3Gsizei m3gDecodeData(M3GLoader loader,
  2902                                M3Gsizei bytes,
  2903                                const M3Gubyte *data)
  2904 
  2905 #endif
  2906 {
  2907     m3gErrorHandler *errorHandler;
  2908     Interface *m3g = M3G_INTERFACE(loader);
  2909 
  2910     M3G_VALIDATE_OBJECT(loader);
  2911     M3G_VALIDATE_INTERFACE(m3g);
  2912 
  2913     /* Check for errors */
  2914     if (bytes <= 0 || data == NULL) {
  2915         m3gRaiseError(m3g, M3G_INVALID_VALUE);
  2916         return 0;
  2917     }
  2918 
  2919     if (loader->state == LOADSTATE_DONE)
  2920         m3gResetLoader(loader);
  2921 
  2922     /* Submit data, then load until we run out of data again or are
  2923      * finished */
  2924 
  2925     if (!m3gBufferData(m3g, &loader->stream, bytes, data)) {
  2926         return 0;
  2927     }
  2928 
  2929     /* Disable error handler */
  2930     errorHandler = m3gSetErrorHandler(m3g, NULL);
  2931 
  2932     /* Continue loading if sufficient data has arrived */
  2933     while (loader->bytesRequired > 0
  2934            && loader->bytesRequired <= loader->stream.bytesAvailable) {
  2935         loader->state = m3gLoaderMain(loader);
  2936     }
  2937 
  2938     /* Restore error handler */
  2939     m3gSetErrorHandler(m3g, errorHandler); 
  2940 
  2941     /* Check if error was raised */
  2942     if (m3gErrorRaised(m3g) != M3G_NO_ERROR) {
  2943         /* Need to free all loaded objects */
  2944         m3gResetLoader(loader);
  2945 
  2946         /* Raise again with original error handler in place */
  2947         if (m3gErrorRaised(m3g) == M3G_OUT_OF_MEMORY)
  2948             m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
  2949         else
  2950             m3gRaiseError(m3g, M3G_IO_ERROR);
  2951         return 0;
  2952     }
  2953 
  2954     /* Return the number of bytes we need for loading to proceed
  2955      * further; clamp to zero in case we're exiting due to an error,
  2956      * or just have been fed excess data */
  2957     {
  2958         M3Gsizei bytesReq =
  2959             loader->bytesRequired - loader->stream.bytesAvailable;
  2960 
  2961         /* Check if whole file is done */
  2962         if (loader->stream.totalBytes >= loader->fileSize) {
  2963             loader->state = LOADSTATE_DONE;
  2964             bytesReq = 0;
  2965         }
  2966 
  2967         return (bytesReq >= 0) ? bytesReq : 0;
  2968     }
  2969 }
  2970 
  2971 /*!
  2972  * \brief Return all loaded objects with user parameters
  2973  *
  2974  * \param loader  the loader instance
  2975  * \param objects an array for objects with user parameters,
  2976  *                or null to return the number of objects
  2977  *
  2978  * \return Number of objects with user parameters
  2979  */
  2980 M3G_API M3Gint m3gGetObjectsWithUserParameters(M3GLoader loader, M3GObject *objects) {
  2981     const Loader *ldr = (const Loader *) loader;
  2982     M3G_VALIDATE_OBJECT(ldr);
  2983     {
  2984         M3Gint i, n;
  2985         n = m3gArraySize(&ldr->userDataArray);
  2986     
  2987         if (objects != NULL)
  2988             for (i = 0; i < n; ++i)
  2989             {
  2990                 const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, i);
  2991                 objects[i] = data->object;
  2992             }
  2993         return n;
  2994     }
  2995 }
  2996 
  2997 /*!
  2998  * \brief Return the number of user parameters loaded for an object
  2999  */
  3000 M3G_API M3Gint m3gGetNumUserParameters(M3GLoader loader, M3Gint object)
  3001 {
  3002     const Loader *ldr = (const Loader *) loader;
  3003     M3G_VALIDATE_OBJECT(ldr);
  3004     {
  3005         const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, object);
  3006         return (data != NULL) ? data->numParams : 0;
  3007     }
  3008 }
  3009 
  3010 /*!
  3011  * \brief Set constraints for loading.
  3012  * \param triConstraint maximum triangle count
  3013  */
  3014 M3G_API void m3gSetConstraints(M3GLoader loader, M3Gint triConstraint)
  3015 {
  3016     M3G_VALIDATE_OBJECT(loader);
  3017     loader->triConstraint = triConstraint;
  3018 }
  3019 
  3020 /*!
  3021  * \brief Return the given user parameter for an object
  3022  *
  3023  * \param loader the loader instance
  3024  * \param object the object to query
  3025  * \param index  index of the string to query
  3026  * \param buffer buffer to copy the data into,
  3027  *               or NULL to just query the length
  3028  *
  3029  * \return id of the parameter, or the length of the string if data was NULL
  3030  */
  3031 M3G_API M3Gsizei m3gGetUserParameter(M3GLoader loader,
  3032                                      M3Gint object,
  3033                                      M3Gint index,
  3034                                      M3Gbyte *buffer)
  3035 {
  3036     const Loader *ldr = (const Loader *) loader;
  3037     M3G_VALIDATE_OBJECT(ldr);
  3038     {
  3039         const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, object);
  3040         if (data != NULL && m3gInRange(index, 0, data->numParams - 1)) {
  3041             const char *src = (const char *)data->params[index];
  3042             M3Gsizei len = data->paramLengths[index];
  3043             if (buffer != NULL) {
  3044                 m3gCopy(buffer, src, len);
  3045                 return data->paramId[index];
  3046             }
  3047             else
  3048                 return len;
  3049         }
  3050         else
  3051             return 0;
  3052     }
  3053 }
  3054 
  3055 #undef ANY_NODE_CLASS
  3056