record.c

00001 /****************************************************************************
00002 
00003  \file      record.c
00004  \ingroup   Patterns
00005  \brief     Binary record support functions
00006  \author    David Mace
00007 
00008 Binary Record Handling
00009 
00010 This writes something a lot like XML, except it all doesn't have to be mapped
00011 into memory at once, and we don't need to recursively parse text.  Everything
00012 is an offset to an offset.  
00013 
00014 This is every bit as robust as the XML that DataGen uses, except it's binary.
00015 
00016 We store labels and enumerations and types as text, so that validation and
00017 conversion can be done on data.  Generally the system still expects certain
00018 things to be present at certain places, but the data types can change somewhat
00019 without breaking.  Enumerations can have new members added.  Scalar types may
00020 be translated.  Arrays may be grown.  Enum or structure members may be re-
00021 arranged without breaking the stored data.  Most kinds of containers (i.e.
00022 arrays, vectors, sets, etc.) are interchangeable, as long as they expect the
00023 same members.  You can not change one type of structure to another.  You 
00024 can not change a scalar to a structure or to a container.
00025 
00026 Generally, this is the serialization meant for files, databases and archives
00027 that last across versions of the application.  Where ctl_serial will melt 
00028 down for minor changes to the application which affect its protocol (i.e. if
00029 you add or change a member and send a packet to a previous version, that
00030 older version will not be able to decode it), this is far more forgiving, 
00031 assuming you follow the rules.
00032 
00033 *****************************************************************************/
00034 
00035 #include <stdio.h>
00036 #include "ctl/dg/datagen.h"
00037 #include "ctl/algorithm.temp.h"
00038 
00046 size_t ctl_record_head_size( const char* label, const char* type )
00047 {
00048     assertconst(label,1);
00049     assertconst(type,1);
00050     return 
00051         sizeof(uint32) +                /* Record size */
00052         sizeof(uint16) +                /* Header size */
00053         cstrlen(char)( label ) + 1 +    /* NUL terminated record label string */
00054         cstrlen(char)( type ) + 1;      /* NUL terminated record type string */
00055 }
00056 
00065 size_t ctl_record_objarray_head_size( const char* label, const char* type, const char* mbrtype )
00066 {
00067     assertconst(label,1);
00068     assertconst(type,1);
00069     assertconst(mbrtype,1);
00070     return 
00071         sizeof(uint32) +                /* Record size */
00072         sizeof(uint16) +                /* Header size */
00073         cstrlen(char)( label ) + 1 +    /* NUL terminated record label string */
00074         cstrlen(char)( type ) + 1 +     /* NUL terminated record type string */
00075         cstrlen(char)( mbrtype ) + 1 +  /* NUL terminated record member type string */
00076         sizeof(uint32);                 /* Record count */
00077 }
00078 
00085 bool ctl_record_valid( const ctl_serial* serial )
00086 {
00087     uint32 size;
00088     uint16 headersize;
00089     size_t labellen;
00090     size_t typelen;
00091     ctl_serial parse;
00092     assertobjconst(serial);
00093     parse = *serial;
00094     /* We should have AT LEAST a header with one-byte label/type */
00095     if( serial->end - serial->curr < 10 )
00096         return false;
00097     uint32_serial_read(&size, &parse );
00098     /* Size should be within bounds */
00099     if( serial->curr + size > serial->end )
00100         return false;
00101     uint16_serial_read(&headersize, &parse );
00102     /* Data offset should be within bounds */
00103     if( serial->curr + headersize > serial->end )
00104         return false;
00105     /* Data offset should be smaller than size */
00106     if( headersize > size )
00107         return false;
00108     labellen = cstrnlen(char)((char*)parse.curr,headersize-6);
00109     /* Label length isn't NUL terminated, or it consumes type string space */
00110     if( labellen >= (size_t)(headersize-6) )
00111         return false;
00112     parse.curr += labellen;
00113     /* Needed to be NUL terminated */
00114     if( *parse.curr )
00115         return false;
00116     parse.curr++;
00117     typelen = cstrnlen(char)((char*)parse.curr,headersize-(6+labellen));
00118     parse.curr += labellen;
00119     /* Needed to be NUL terminated */
00120     if( *parse.curr )
00121         return false;
00122     parse.curr++;
00123     /* Should add up to the header size */
00124     if( 6 + labellen + 1 + typelen + 1 != headersize )
00125         return false;
00126 
00127     /* Didn't find any problem */
00128     return true;
00129 }
00130 
00137 bool ctl_record_next( ctl_serial* serial )
00138 {
00139     uint8* curr;
00140     uint32 offset;
00141     assertobjptr(serial);
00142     curr = serial->curr;
00143     uint32_serial_read(&offset, serial );
00144     if( curr + offset > serial->end )
00145         ctl_serial_except( serial, "ctl_record_next: Bad offset" );
00146     serial->curr = curr + offset;
00147     return serial->curr < serial->end;
00148 }
00149 
00157 bool ctl_record_find( ctl_serial* serial, const char* label )
00158 {
00159     ctl_serial search;
00160     assertobjptr(serial);
00161     search = *serial;
00162     do
00163     {
00164         const char *szcurr = ctl_record_label( &search );
00165         if( !cstrcmp(char)( label, szcurr ) )
00166         {
00167             serial->curr = search.curr;
00168             return true;
00169         }
00170     }
00171     while( ctl_record_next( &search ) );
00172     return false;
00173 }
00174 
00182 bool ctl_record_find_next( ctl_serial* serial, const char* label )
00183 {
00184     ctl_serial search;
00185     assertobjptr(serial);
00186     search = *serial;
00187     while( ctl_record_next( &search ) )
00188     {
00189         if( !cstrcmp(char)( label, ctl_record_label( &search ) ) )
00190         {
00191             serial->curr = search.curr;
00192             return true;
00193         }
00194     }
00195     return false;
00196 }
00197 
00204 size_t ctl_record_getdata( ctl_serial* serial )
00205 {
00206     uint8* curr;
00207     uint32 offset;
00208     uint16 dataoffset;
00209     assertobjptr(serial);
00210     curr = serial->curr;
00211     uint32_serial_read(&offset, serial );
00212     uint16_serial_read(&dataoffset, serial );
00213     if( dataoffset > offset )
00214         ctl_serial_except( serial, "ctl_record_getdata: Bad offset" );
00215     if( curr + offset > serial->end )
00216         ctl_serial_except( serial, "ctl_record_getdata: Offset exceeds serial data" );
00217     serial->end = curr + offset;
00218     serial->curr = curr + dataoffset;
00219     return offset - dataoffset;
00220 }
00221 
00230 size_t ctl_record_container_validatedata( ctl_serial* serial, const char* type, const char* mbrtype )
00231 {
00232     assertobjptr(serial);
00233     assertconst(type,1);
00234     assertconst(mbrtype,1);
00235     if( type && !ctl_record_type_is( type, serial ) )
00236         ctl_serial_except( serial, "ctl_record_container_validatedata: Mismatched container type" );
00237     if( mbrtype && !ctl_record_contained_type_is( mbrtype, serial ) )
00238         ctl_serial_except( serial, "ctl_record_container_validatedata: Mismatched content type" );
00239     {
00240         uint8* curr = serial->curr;
00241         uint32 offset;
00242         uint16 dataoffset;
00243         uint32 count;
00244         uint32_serial_read(&offset, serial );
00245         uint16_serial_read(&dataoffset, serial );
00246         if( dataoffset > offset )
00247             ctl_serial_except( serial, "ctl_record_container_validatedata: Bad offset" );
00248         if( curr + offset > serial->end )
00249             ctl_serial_except( serial, "ctl_record_container_validatedata: Offset exceeds serial data" );
00250         serial->end = curr + offset;
00251         serial->curr = curr + dataoffset - 4;
00252         uint32_serial_read(&count, serial );
00253         return count;
00254     }
00255 }
00256 
00257 
00264 const uint8* ctl_record_end( const ctl_serial* serial )
00265 {
00266     uint32 offset;
00267     ctl_serial tmp;
00268     assertobjconst(serial);
00269     tmp = *serial;
00270     uint32_serial_read(&offset, &tmp );
00271     if( serial->curr + offset > serial->end )
00272         ctl_serial_except( serial, "ctl_record_next: Bad offset" );
00273     return serial->curr + offset;;
00274 }
00275 
00283 bool ctl_record_is( const char* label, const ctl_serial* serial )
00284 {
00285     assertconst(label,1);
00286     assertobjconst(serial);
00287     return !cstrcmp(char)( label, ctl_record_label( serial ) );
00288 }
00289 
00290 
00297 const char* ctl_record_label( const ctl_serial* serial )
00298 {
00299     assertobjconst(serial);
00300     if( serial->curr + 7 > serial->end )
00301         ctl_serial_except( serial, "ctl_record_label: Truncated" );
00302     return (const char*)(serial->curr + 6);
00303 }
00304 
00311 const char* ctl_record_type( const ctl_serial* serial )
00312 {
00313     const char* label;
00314     assertobjconst(serial);
00315     label = ctl_record_label( serial );
00316     label += cstrnlen(char)(label,ctl_serial_remain(serial))+1;
00317     if( (uint8*)label >= serial->end )
00318         ctl_serial_except( serial, "ctl_record_type: Truncated" );
00319     return label;
00320 }
00321 
00329 bool ctl_record_type_is( const char* label, const ctl_serial* serial )
00330 {
00331     assertconst(label,1);
00332     assertobjconst(serial);
00333     return !cstrcmp(char)( label, ctl_record_type( serial ) );
00334 }
00335 
00342 const char* ctl_record_contained_type( const ctl_serial* serial )
00343 {
00344     const char* type;
00345     assertobjconst(serial);
00346     type = ctl_record_type( serial );
00347     type += cstrnlen(char)(type,ctl_serial_remain(serial))+1;
00348     if( (uint8*)type >= serial->end )
00349         ctl_serial_except( serial, "ctl_record_contained_type: Truncated" );
00350     return type;
00351 }
00352 
00360 bool ctl_record_contained_type_is( const char* label, const ctl_serial* serial )
00361 {
00362     assertconst(label,1);
00363     assertobjconst(serial);
00364     return !cstrcmp(char)(label,ctl_record_contained_type( serial ) );
00365 }
00366 
00373 size_t ctl_record_count( const ctl_serial* serial )
00374 {
00375     ctl_serial pserial;
00376     uint16 dataoffset;
00377     uint32 count;
00378     assertobjconst(serial);
00379     pserial = *serial;
00380     pserial.curr += 4;
00381     uint16_serial_read(&dataoffset, &pserial );
00382     pserial.curr = serial->curr + dataoffset - 4;
00383     uint32_serial_read(&count, &pserial );
00384     return count;
00385 }
00386 
00396 uint8* ctl_record_write_begin( const char* type, size_t size, ctl_serial* serial, const char* label )
00397 {
00398     assertobjptr(serial);
00399     assertconst(type,1);
00400     assertconst(label,1);
00401     {
00402         uint8* ret = serial->curr;
00403         size_t lenLabel = cstrlen(char)(label)+1;
00404         size_t lenType = cstrlen(char)(type)+1;
00405         uint16 offData = (uint16)(lenLabel + lenType + 6);
00406         uint32 reserve = (uint32)size + offData;
00407         /* This should fit into the reported space */
00408         assert( serial->curr + offData + size <= serial->end );
00409         uint32_serial_write(&reserve, serial );
00410         uint16_serial_write(&offData, serial );
00411         memcpy(serial->curr, label, lenLabel);
00412         serial->curr += lenLabel;
00413         memcpy(serial->curr, type, lenType);
00414         serial->curr += lenType;
00415         return ret;
00416     }
00417 }
00418 
00419 
00431 uint8* ctl_record_write_container_begin( const char* containertype, const char* contenttype, size_t size, size_t count, ctl_serial* serial, const char* label )
00432 {
00433     assertobjptr(serial);
00434     assertconst(containertype,1);
00435     assertconst(contenttype,1);
00436     assertconst(label,1);
00437     {
00438         uint8* ret = serial->curr;
00439         size_t lenLabel = cstrlen(char)(label)+1;
00440         size_t lenType = cstrlen(char)(containertype)+1;
00441         size_t lenContent = cstrlen(char)(contenttype)+1;
00442         uint16 offData = (uint16)(lenLabel + lenType + lenContent + 10);
00443         uint32 reserve = (uint32)size + offData;
00444         uint32 mbrcount = (uint32)count;
00445         /* This should fit into the reported space */
00446         assert( serial->curr + offData + size <= serial->end );
00447         uint32_serial_write(&reserve, serial );
00448         uint16_serial_write(&offData, serial );
00449         memcpy(serial->curr, label, lenLabel);
00450         serial->curr += lenLabel;
00451         memcpy(serial->curr, containertype, lenType);
00452         serial->curr += lenType;
00453         memcpy(serial->curr, contenttype, lenContent);
00454         serial->curr += lenContent;
00455         uint32_serial_write(&mbrcount, serial );
00456         return ret;
00457     }
00458 }
00459 
00466 void ctl_record_write_end( uint8* begret, ctl_serial* serial )
00467 {
00468     assertobjptr(serial);
00469     assertptr(begret,1);
00470     {
00471         uint8* tmp = serial->curr;
00472         uint32 size = (uint32)(serial->curr - begret);
00473         serial->curr = begret;
00474         uint32_serial_write( &size, serial );
00475         serial->curr = tmp;
00476     }
00477 }
00478 
00485 size_t ctl_serial_record_size( const ctl_serial* serial, const char* label )
00486 {
00487     size_t size;
00488     assertconst(label,1);
00489     assertobjconst(serial);
00490     size = ctl_serial_total( serial );
00491     if( 0 == size )
00492         return 0;
00493     size += ctl_record_head_size( label, "raw" );
00494     return size;
00495 }
00503 void ctl_serial_record_write( const ctl_serial* from, ctl_serial* to, const char* label )
00504 {
00505     size_t total;
00506     assertobjconst(from);
00507     assertobjptr(to);
00508     assertconst(label,1);
00509     total = ctl_serial_total( from );
00510     if( 0 != total )
00511     {
00512         size_t total = ctl_serial_total( from );
00513         ctl_record_write_begin( "raw", total, to, label );
00514         memcpy( to->curr, from->begin, total );
00515         to->curr += total;
00516     }
00517 }
00525 bool ctl_serial_record_read( ctl_serial* to, ctl_serial* from, const char* label )
00526 {
00527     ctl_serial tmp;
00528     assertobjptr(from);
00529     assertobjptr(to);
00530     assertconst(label,1);
00531     tmp = *from;
00532     if( ctl_record_find( &tmp, label ) )
00533     {
00534         const char* szcontainer = ctl_record_type( &tmp );
00535         if( cstrcmp(char)(szcontainer,"raw") )
00536             ctl_serial_except( from, "ctl_serial_record_read: Not raw data" );
00537         ctl_record_getdata( &tmp );
00538         ctl_serial_init( to, tmp.curr, tmp.end );
00539         return true;
00540     }
00541     return false;
00542 }
00543 
00544 
00552 size_t char_record_size_string( const char* str, size_t maxsize, const char* label )
00553 {
00554     assertconst(label,1);
00555     assertconst(str,1);
00556     return ctl_record_objarray_head_size( label,"string","char" ) + chssize(char,cstrnlen(char)(str,maxsize));
00557 }
00565 size_t wchar_t_record_size_string( const wchar_t* str, size_t maxsize, const char* label )
00566 {
00567     assertconst(label,1);
00568     assertconst(str,1);
00569     return ctl_record_objarray_head_size( label,"string","wchar_t" ) + chssize(wchar_t,cstrnlen(wchar_t)(str,maxsize));
00570 }
00577 size_t char_record_size_gstring( const ctl_gstring(char)* str, const char* label )
00578 {
00579     assertconst(label,1);
00580     assertobjconst(str);
00581     return ctl_record_objarray_head_size( label,"string","char" ) + chssize(char,ctl_gstring_size(char,str));
00582 }
00589 size_t wchar_t_record_size_gstring( const ctl_gstring(wchar_t)* str, const char* label )
00590 {
00591     assertconst(label,1);
00592     assertobjconst(str);
00593     return ctl_record_objarray_head_size( label,"string","wchar_t" ) + chssize(wchar_t,ctl_gstring_size(wchar_t,str));
00594 }
00595 
00596 
00605 void char_record_write_string( const char* sz, size_t size, ctl_serial* serial, const char* label )
00606 {
00607     size_t storesize;
00608     assertconst(sz,1);
00609     assertconst(label,1);
00610     assertobjptr(serial);
00611     storesize = cstrnlen(char)(sz,size);
00612     assert( serial->curr + storesize <= serial->end );
00613     ctl_record_write_container_begin( "string", "char", storesize,storesize, serial, label );
00614     memcpy( serial->curr, sz, storesize );
00615     serial->curr += storesize;
00616 }
00625 void wchar_t_record_write_string( const wchar_t* sz, size_t size, ctl_serial* serial, const char* label )
00626 {
00627     size_t storesize;
00628     assertconst(sz,1);
00629     assertconst(label,1);
00630     assertobjptr(serial);
00631     storesize = cstrnlen(wchar_t)(sz,size);
00632     ctl_record_write_container_begin( "string", "wchar_t", chssize(wchar_t,storesize),storesize, serial, label );
00633     {
00634         pointer_foreach_const( wchar_t, sz, storesize, curr )
00635         {
00636             uint16 ch = (uint16)*curr;
00637             uint16_serial_write( &ch, serial );
00638         }
00639     }
00640 }
00641 
00650 bool char_record_read_string( char* sz, size_t size, const ctl_serial* serial, const char* label )
00651 {
00652     ctl_serial tmp;
00653     assertptr(sz,size);
00654     assertconst(label,1);
00655     assertobjconst(serial);
00656     tmp = *serial;
00657     if( ctl_record_find( &tmp, label ) )
00658     {
00659         const char* szcontainer = ctl_record_type( &tmp );
00660         if( cstrcmp(char)(szcontainer,"string") )
00661             ctl_serial_except( serial, "char_record_read_string: Not a string" );
00662         {
00663             const char* szt = ctl_record_contained_type( &tmp );
00664             size_t rsize = ctl_record_getdata( &tmp );
00665             if( !cstrcmp(char)(szt,"char") )
00666             {
00667                 memcpy( sz, tmp.curr, min(size,rsize) );
00668                 if( size > rsize )
00669                     sz[rsize] = 0;
00670             }
00671             else if( !cstrcmp(char)(szt,"type") )
00672             {
00673                 while( size-- && tmp.curr < tmp.end )
00674                 {
00675                     uint16 ch;
00676                     uint16_serial_read( &ch, &tmp );
00677                     *sz++ = (char)ch;
00678                 }
00679                 if( size > 0 )
00680                     *sz++ = 0;
00681             }
00682             else
00683             {
00684                 ctl_serial_except( serial, "char_record_read_string: Unknown character type" );
00685             }
00686         }
00687         return true;
00688     }
00689     return false;
00690 }
00691 
00700 bool wchar_t_record_read_string( wchar_t* sz, size_t size, const ctl_serial* serial, const char* label )
00701 {
00702     ctl_serial tmp;
00703     assertconst(sz,1);
00704     assertconst(label,1);
00705     assertobjconst(serial);
00706     tmp = *serial;
00707     if( ctl_record_find( &tmp, label ) )
00708     {
00709         const char* szcontainer = ctl_record_type( &tmp );
00710         if( cstrcmp(char)(szcontainer,"string") )
00711             ctl_serial_except( serial, "wchar_t_record_read_string: Not a string" );
00712         {
00713             const char* szwchar_t = ctl_record_contained_type( &tmp );
00714             ctl_record_getdata( &tmp );
00715             if( !cstrcmp(char)(szwchar_t,"char") )
00716             {
00717                 const char* psz = (const char*)tmp.curr;
00718                 while( size-- && tmp.curr < tmp.end )
00719                     *sz++ = (wchar_t)*psz++;
00720                 if( size > 0 )
00721                     *sz++ = 0;
00722             }
00723             else if( !cstrcmp(char)(szwchar_t,"wchar_t") )
00724             {
00725                 while( size-- && tmp.curr < tmp.end )
00726                 {
00727                     uint16 ch;
00728                     uint16_serial_read( &ch, &tmp );
00729                     *sz++ = (wchar_t)ch;
00730                 }
00731                 if( size > 0 )
00732                     *sz++ = 0;
00733             }
00734             else
00735             {
00736                 ctl_serial_except( serial, "wchar_t_record_read_string: Unknown character wchar_t" );
00737             }
00738         }
00739         return true;
00740     }
00741     return false;
00742 }
00743 
00751 bool char_record_read_gstring( ctl_gstring(char)* str, const ctl_serial* serial, const char* label )
00752 {
00753     ctl_serial tmp;
00754     assertobjptr(str);
00755     assertconst(label,1);
00756     assertobjconst(serial);
00757     tmp = *serial;
00758     if( ctl_record_find( &tmp, label ) )
00759     {
00760         const char* szcontainer = ctl_record_type( &tmp );
00761         if( cstrcmp(char)(szcontainer,"string") )
00762             ctl_serial_except( serial, "char_record_read_string: Not a string" );
00763         {
00764             const char* sz = ctl_record_contained_type( &tmp );
00765             size_t rsize = ctl_record_getdata( &tmp );
00766             if( !cstrcmp(char)(sz,"char") )
00767             {
00768                 ctl_gstring_resize(char, str, ctl_chlength(char,rsize) );
00769                 memcpy( str->begin, tmp.curr, rsize );
00770             }
00771             else if( !cstrcmp(char)(sz,"wchar_t") )
00772             {
00773                 char* sz;
00774                 if( rsize & 1 )
00775                     ctl_serial_except( serial, "char_record_read_string: Odd string length" );
00776                 ctl_gstring_resize(char, str, chslength(wchar_t,rsize) );
00777                 sz = str->begin;
00778                 while( tmp.curr < tmp.end )
00779                 {
00780                     uint16 ch;
00781                     uint16_serial_read( &ch, &tmp );
00782                     *sz++ = (char)ch;
00783                 }
00784             }
00785             else
00786             {
00787                 ctl_serial_except( serial, "char_record_read_string: Unknown character type" );
00788             }
00789         }
00790         return true;
00791     }
00792     return false;
00793 }
00794 
00802 bool wchar_t_record_read_gstring( ctl_gstring(wchar_t)* str, const ctl_serial* serial, const char* label )
00803 {
00804     ctl_serial tmp;
00805     assertobjptr(str);
00806     assertconst(label,1);
00807     assertobjconst(serial);
00808     tmp = *serial;
00809     if( ctl_record_find( &tmp, label ) )
00810     {
00811         const char* szcontainer = ctl_record_type( &tmp );
00812         if( cstrcmp(char)(szcontainer,"string") )
00813             ctl_serial_except( serial, "wchar_t_record_read_string: Not a string" );
00814         {
00815             const char* szwchar_t = ctl_record_contained_type( &tmp );
00816             size_t rsize = ctl_record_getdata( &tmp );
00817             if( !cstrcmp(char)(szwchar_t,"char") )
00818             {
00819                 wchar_t* sz;
00820                 const char* psz = (const char*)tmp.curr;
00821                 ctl_gstring_resize(wchar_t, str, rsize );
00822                 sz = str->begin;
00823                 while( tmp.curr < tmp.end )
00824                     *sz++ = (wchar_t)*psz++;
00825             }
00826             else if( !cstrcmp(char)(szwchar_t,"wchar_t") )
00827             {
00828                 wchar_t* sz;
00829                 if( rsize & 1 )
00830                     ctl_serial_except( serial, "wchar_t_record_read_string: Odd string length" );
00831                 rsize = chslength(wchar_t,rsize);
00832                 ctl_gstring_resize(wchar_t, str, rsize );
00833                 sz = str->begin;
00834                 while( tmp.curr < tmp.end )
00835                 {
00836                     uint16 ch;
00837                     uint16_serial_read( &ch, &tmp );
00838                     *sz++ = (wchar_t)ch;
00839                 }
00840             }
00841             else
00842             {
00843                 ctl_serial_except( serial, "wchar_t_record_read_string: Unknown character wchar_t" );
00844             }
00845         }
00846         return true;
00847     }
00848     return false;
00849 }
00850 
00851 #if 1
00852 
00853 void spew1();
00854 
00855 #define X_RECORD_READ(type,unused)\
00856 \
00864 bool ppConcat(type,_record_read)( type* pdata, const ctl_serial* serial, const char* label ) \
00865 {\
00866     ctl_serial tmp;\
00867     assertconst(label,1);\
00868     assertobjconst(serial);\
00869     assertptr(pdata,sizeof(type));\
00870     tmp = *serial;\
00871     if( ctl_record_find( &tmp, label ) )\
00872     {\
00873         const char* sz = ctl_record_type( &tmp );\
00874         ctl_record_getdata( &tmp );\
00875         DEF_ENUMTYPES_INNER(X_SCALAR_TYPES,type)\
00876         {\
00877             ctl_serial_except( serial, #type "_record_read: Invalid scalar type" );\
00878         }\
00879     }\
00880     return false;\
00881 }
00882 #define X_SCALAR_TYPES(type,outertype)\
00883         if( !strcmp(sz,#type) )\
00884         {\
00885             type ppConcat(get_,type);\
00886             ppConcat(type,_serial_read)( &ppConcat(get_,type), &tmp );\
00887             ppConcat(outertype,_copy_t)(*pdata,type,ppConcat(get_,type));\
00888             return true;\
00889         }\
00890         else 
00891 
00892 DEF_ENUMTYPES(X_RECORD_READ,unused)
00893 #undef X_RECORD_READ
00894 #undef X_SCALAR_TYPES
00895 
00896 
00897 
00898 /* Write & write array of various scalar types */
00899 #define X_RECORD_WRITE(type,unused) \
00900 void ppConcat(type,_record_write)( const type* pdata, ctl_serial* serial, const char* label )\
00901 {\
00902     assertconst(label,1);\
00903     assertobjptr(serial);\
00904     assertconst(pdata,sizeof(type));\
00905     ctl_record_write_begin( #type, ppConcat(type,_serial_size)( p ), serial, label );\
00906     ppConcat(type,_serial_write)( pdata, serial );\
00907 }
00908 DEF_ENUMTYPES(X_RECORD_WRITE,unused)
00909 #undef X_RECORD_WRITE
00910 
00911 #define X_RECORD_ARRAY_WRITE(type,unused) \
00912 void ppConcat(type,_record_writearray)( const type* pdata, size_t count, ctl_serial* serial, const char* label )\
00913 {\
00914     assertconst(label,1);\
00915     assertobjptr(serial);\
00916     assertconst(pdata,sizeof(type));\
00917     ctl_record_write_container_begin( "array", #type, ppConcat(type,_serial_size)( p )*count, count, serial, label );\
00918     {\
00919         pointer_foreach_const( type, pdata, count, curr )\
00920             ppConcat(type,_serial_write)( curr, serial );\
00921     }\
00922 }
00923 DEF_ENUMTYPES(X_RECORD_ARRAY_WRITE,unused)
00924 #undef X_RECORD_ARRAY_WRITE
00925 
00926 #define X_RECORD_ARRAY_READ(type,unused) \
00927 \
00936 bool ppConcat(type,_record_readarray)( type* pdata, size_t count, const ctl_serial* serial, const char* label )\
00937 {\
00938     ctl_serial tmp;\
00939     assertconst(label,1);\
00940     assertobjconst(serial);\
00941     assertptr(pdata,count*sizeof(type));\
00942     tmp = *serial;\
00943     if( ctl_record_find( &tmp, label ) )\
00944     {\
00945         /*const char* szcontainer = ctl_record_type( &pserial, end );*/\
00946         const char* sz = ctl_record_contained_type( &tmp );\
00947         size_t rsize = ctl_record_getdata( &tmp );\
00948         DEF_ENUMTYPES_INNER(X_SCALAR_TYPES,type)\
00949         {\
00950             ctl_serial_except( serial, #type "_record_readarray: Invalid scalar type" );\
00951         }\
00952     }\
00953     return false;\
00954 }
00955 #define X_SCALAR_TYPES(type,outertype)\
00956         if( !strcmp(sz,#type) )\
00957         {\
00958             if( rsize % ppConcat(type,_serial_size)( 0 ) )\
00959                 ctl_serial_except( serial, #outertype "_record_readarray: Odd length array" );\
00960             {\
00961                 size_t scount = rsize / ppConcat(type,_serial_size)( 0 );\
00962                 if( scount > count )\
00963                     scount = count;\
00964                 {\
00965                     pointer_foreach( outertype, pdata, scount, curr )\
00966                     {\
00967                         type ppConcat(get_,type);\
00968                         ppConcat(type,_serial_read)( &ppConcat(get_,type), &tmp );\
00969                         ppConcat(outertype,_copy_t)(*pdata,type,ppConcat(get_,type));\
00970                         pdata++;\
00971                     }\
00972                     return true;\
00973                 }\
00974             }\
00975         }\
00976         else 
00977 
00978 DEF_ENUMTYPES(X_RECORD_ARRAY_READ,unused)
00979 #undef X_RECORD_ARRAY_READ
00980 #undef X_SCALAR_TYPES
00981 
00982 #else 
00983 
00984 void spew0();
00985 
00986 #endif

Generated on Fri Jan 2 15:28:34 2009 for Squat by  doxygen 1.5.6