From 25c111061b9ace2620582d11ee4577aaa18f3868 Mon Sep 17 00:00:00 2001 From: Chris Piker Date: Wed, 24 Jul 2024 23:24:59 -0500 Subject: [PATCH] Draft v2 to v3 autoconvert --- das2/builder.c | 223 ++++++++++++++++++++++++++++++++++-------------- das2/dataset.c | 15 ++++ das2/dataset.h | 18 ++++ das2/io.c | 21 ++++- das2/property.c | 159 +++++++++++++++++++++++++++------- das2/serial.c | 10 +-- das2/serial.h | 21 +---- das2/stream.c | 25 ++++-- 8 files changed, 355 insertions(+), 137 deletions(-) diff --git a/das2/builder.c b/das2/builder.c index bb45e5e..bbdf23b 100644 --- a/das2/builder.c +++ b/das2/builder.c @@ -412,6 +412,34 @@ DasDim* _DasDsBldr_getDim( return pDim; } + +/* ************************************************************************* */ +/* Add a das3 codec to a dataset that's equavalent to a das2 encoder */ +DasErrCode _DasDsBldr_addCodec( + DasDs* pDs, const char* sAryId, int nItems, DasEncoding* pEncoder +){ + + int nHash = DasEnc_hash(pEncoder); + const char* sEncType = NULL; + int nItemBytes = 0; + const char* sSemantic = "real"; + switch(nHash){ + case DAS2DT_BE_REAL_8: sEncType = "BEreal"; nItemBytes = 8; break; + case DAS2DT_LE_REAL_8: sEncType = "LEreal"; nItemBytes = 8; break; + case DAS2DT_BE_REAL_4: sEncType = "BEreal"; nItemBytes = 4; break; + case DAS2DT_LE_REAL_4: sEncType = "LEreal"; nItemBytes = 4; break; + } + if(sEncType == NULL){ + nItemBytes = pEncoder->nWidth; + sEncType = "utf8"; + if(pEncoder->nCat == DAS2DT_TIME) + sSemantic = "datetime"; + } + + return DasDs_addFixedCodec(pDs, sAryId, sSemantic, sEncType, nItemBytes, nItems); +} + + /* ************************************************************************* */ /* Initialize X-Y pattern * Make one dimension for X and one each for the Y's. Could do some deeper @@ -429,11 +457,13 @@ void _strrep(char* pId, char c, char r) } -DasDs* _DasDsBldr_initXY(DasStream* pSd, PktDesc* pPd, const char* pGroup) -{ +DasDs* _DasDsBldr_initXY( + DasStream* pSd, PktDesc* pPd, const char* pGroup, bool bCodecs +){ /* If my group name is null, make up a new one appropriate to XY data */ const char* pId = NULL; PlaneDesc* pPlane = NULL; + DasEncoding* pEncoder = NULL; const char* sRole = NULL; /* The reason this plane is present */ int nY = 0; char sBuf[64] = {'\0'}; @@ -466,8 +496,12 @@ DasDs* _DasDsBldr_initXY(DasStream* pSd, PktDesc* pPd, const char* pGroup) size_t uDims = 0; /* Copy any properties that don't start with one of the axis prefixes */ + + /* ... actually, we output stream headers now, so this isn't needed, it + was always a bit of a hack and doesn't play well with CDF generation. DasDs_copyInProps(pDs, (DasDesc*)pSd); DasDs_copyInProps(pDs, (DasDesc*)pPd); + */ char sAryId[64] = {'\0'}; double fill; @@ -475,6 +509,8 @@ DasDs* _DasDsBldr_initXY(DasStream* pSd, PktDesc* pPd, const char* pGroup) for(size_t u = 0; u < pPd->uPlanes; ++u){ pPlane = pPd->planes[u]; + pEncoder = PlaneDesc_getValEncoder(pPlane); + pId = pPlane->sName; if(pPlane->planeType == X){ cAxis = 'x'; @@ -527,6 +563,10 @@ DasDs* _DasDsBldr_initXY(DasStream* pSd, PktDesc* pPd, const char* pGroup) if( pVar == NULL) return NULL; sRole = _DasDsBldr_role(pPlane); if(! DasDim_addVar(pDim, sRole, pVar)) return NULL; + + if(bCodecs) + if(_DasDsBldr_addCodec(pDs, sAryId, 1, pEncoder) != DAS_OKAY) + return NULL; } return pDs; } @@ -534,11 +574,13 @@ DasDs* _DasDsBldr_initXY(DasStream* pSd, PktDesc* pPd, const char* pGroup) /* ************************************************************************* */ /* Initialize X-Y-Z pattern */ -DasDs* _DasDsBldr_initXYZ(DasStream* pSd, PktDesc* pPd, const char* pGroup) -{ +DasDs* _DasDsBldr_initXYZ( + DasStream* pSd, PktDesc* pPd, const char* pGroup, bool bCodecs +){ /* If my group name is null, make up a new one appropriate to XYZ data */ const char* pId = NULL; PlaneDesc* pPlane = NULL; + DasEncoding* pEncoder = NULL; const char* sRole = NULL; /* The reason this plane is present */ int nZ = 0; char sBuf[64] = {'\0'}; @@ -571,8 +613,9 @@ DasDs* _DasDsBldr_initXYZ(DasStream* pSd, PktDesc* pPd, const char* pGroup) size_t uDims = 0; /* Copy any properties that don't start with one of the axis prefixes */ + /* ... or don't. Messes up CDF output DasDs_copyInProps(pDs, (DasDesc*)pSd); - DasDs_copyInProps(pDs, (DasDesc*)pPd); + DasDs_copyInProps(pDs, (DasDesc*)pPd); */ char sAryId[64] = {'\0'}; double fill; @@ -580,8 +623,8 @@ DasDs* _DasDsBldr_initXYZ(DasStream* pSd, PktDesc* pPd, const char* pGroup) for(size_t u = 0; u < pPd->uPlanes; ++u){ pPlane = pPd->planes[u]; - pId = pPlane->sName; - + pId = pPlane->sName; + pEncoder = PlaneDesc_getValEncoder(pPlane); switch(pPlane->planeType){ case X: @@ -653,6 +696,10 @@ DasDs* _DasDsBldr_initXYZ(DasStream* pSd, PktDesc* pPd, const char* pGroup) * otherwise */ sRole = _DasDsBldr_role(pPlane); if(! DasDim_addVar(pDim, sRole, pVar)) return NULL; + + if(bCodecs) + if(_DasDsBldr_addCodec(pDs, sAryId, 1, pEncoder) != DAS_OKAY) + return NULL; } return pDs; @@ -755,8 +802,9 @@ bool _DasDsBldr_isWaveform(PlaneDesc* pPlane){ return true; } -DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) -{ +DasDs* _DasDsBldr_initYScan( + DasStream* pSd, PktDesc* pPd, const char* pGroup, bool bCodecs +){ /* Make sure all the yscans have the same yTags. The assumption here is * that a single packet only has data correlated in it's coordinates. If * two yscans have different yTag sets then they are not correlated. */ @@ -786,14 +834,16 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) DasDs* pDs = new_DasDs(sDsId, pGroup, 2); DasDim* pDim = NULL; DasDim* pXDim = NULL; + DasDim* pYDim = NULL; DasVar* pVar = NULL; DasVar* pOffset = NULL; DasVar* pReference = NULL; - + /* Dito, see above searching for string CDF DasDs_copyInProps(pDs, (DasDesc*)pSd); - DasDs_copyInProps(pDs, (DasDesc*)pPd); /*These never have props in das 2.2 */ + DasDs_copyInProps(pDs, (DasDesc*)pPd); */ /*These never have props in das 2.2 */ const char* pPlaneId = NULL; + DasEncoding* pEncoder = NULL; const char* sRole = NULL; das_units Yunits; das_units Zunits; @@ -823,6 +873,8 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) /* Assume this is a center value unless told otherwise */ sRole = _DasDsBldr_role(pPlane); + + pEncoder = PlaneDesc_getValEncoder(pPlane); /* If we're lucky the plane will tell us the purpose for it's * values, i.e. min, center, max, err-bar */ @@ -830,8 +882,9 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) switch(pPlane->planeType){ case X: if(pPlaneId == NULL){ - if(Units_haveCalRep(pPlane->units)) pPlaneId = "time"; - else pPlaneId = "X"; + if(Units_haveCalRep(pPlane->units)) pPlaneId = "time"; + else pPlaneId = "X"; + } pAry = new_DasAry(pPlaneId, vtDouble, 0, NULL, RANK_1(0), pPlane->units); if(pAry == NULL) return NULL; @@ -849,6 +902,10 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) pVar = new_DasVarArray(pAry, SCALAR_2(0, DASIDX_UNUSED)); if(pVar == NULL) return NULL; if(! DasDim_addVar(pXDim, sRole, pVar)) return NULL; + + if(bCodecs) + if(_DasDsBldr_addCodec(pDs, pPlaneId, 1, pEncoder) != DAS_OKAY) + return NULL; break; case Y: @@ -869,17 +926,20 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) /* Assume that extra Y values are more coordinates unless told * otherwise by a setting of some sort that I don't yet know */ - pDim = _DasDsBldr_getDim( + pYDim = _DasDsBldr_getDim( pPlane, pPd, pSd, 'y', pDs, DASDIM_COORD, pPlaneId, aDims, aDimSrc, &uDims ); - if(pDim == NULL) return NULL; + if(pYDim == NULL) return NULL; /* Map index 0 to this array, ignore index 1 */ pVar = new_DasVarArray(pAry, SCALAR_2(0, DASIDX_UNUSED)); if(pVar == NULL) return NULL; - if(! DasDim_addVar(pDim, sRole, pVar)) return NULL; - + if(! DasDim_addVar(pYDim, sRole, pVar)) return NULL; + + if(bCodecs) + if(_DasDsBldr_addCodec(pDs, pPlaneId, 1, pEncoder) != DAS_OKAY) + return NULL; break; case YScan: @@ -926,20 +986,39 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) /* Make new center variable that is rank 2 since reference and * offset are orthogonal */ pVar = new_DasVarBinary("center", pReference, "+", pOffset); - DasDim_addVar(pXDim, DASVAR_CENTER, pVar); + if(! DasDim_addVar(pXDim, DASVAR_CENTER, pVar) ) return NULL; } else{ - pDim = DasDs_makeDim(pDs, DASDIM_COORD, pYTagId, ""); - if(pDim == NULL) return NULL; - DasDim_copyInProps(pDim, 'y', (DasDesc*)pSd); - DasDim_copyInProps(pDim, 'y', (DasDesc*)pPd); - DasDim_copyInProps(pDim, 'y', (DasDesc*)pPlane); + /* If we have and then the Y's are our reference values + Convert the old CENTER variable to a Reference variable and + add the Ytags as offsets */ + if(pYDim != NULL){ + pOffset = new_DasVarArray(pAry, SCALAR_2(DASIDX_UNUSED, 0)); + DasDim_addVar(pYDim, DASVAR_OFFSET, pOffset); + + /* Convert the old CENTER variable to a Reference variable */ + pReference = DasDim_popVar(pYDim, DASVAR_CENTER); + DasDim_addVar(pYDim, DASVAR_REF, pReference); + + /* Make new center variable that is rank 2 since reference and + * offset are orthogonal */ + pVar = new_DasVarBinary("center", pReference, "+", pOffset); + if(! DasDim_addVar(pYDim, DASVAR_CENTER, pVar) ) return NULL; + } + else{ + /* Nope no offsets in freq or time, just a new center variable */ + pDim = DasDs_makeDim(pDs, DASDIM_COORD, pYTagId, ""); + if(pDim == NULL) return NULL; + + DasDim_copyInProps(pDim, 'y', (DasDesc*)pSd); + DasDim_copyInProps(pDim, 'y', (DasDesc*)pPd); + DasDim_copyInProps(pDim, 'y', (DasDesc*)pPlane); - /* Map index 1 to this array's index 0, ignore 0, always assume */ - /* center values */ - pVar = new_DasVarArray(pAry, SCALAR_2(DASIDX_UNUSED, 0)); - if(pVar == NULL) return NULL; - if(! DasDim_addVar(pDim, DASVAR_CENTER, pVar)) return NULL; + /* Map index 1 to this array's index 0, ignore 0, assume */ + /* center values */ + pVar = new_DasVarArray(pAry, SCALAR_2(DASIDX_UNUSED, 0)); + if(! DasDim_addVar(pDim, DASVAR_CENTER, pVar)) return NULL; + } } bAddedYTags = true; @@ -948,15 +1027,12 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) /* Now for the actual data values array, try for a good array name */ Zunits = PlaneDesc_getUnits(pPlane); if(pPlaneId == NULL){ - if(Units_canConvert(Zunits, UNIT_E_SPECDENS)){ + if(Units_canConvert(Zunits, UNIT_E_SPECDENS)) strncpy(sAryId, "e_spec_dens", 63); - } - else{ - if(Units_canConvert(Zunits, UNIT_B_SPECDENS)) - strncpy(sAryId, "b_spec_dens", 63); - else - snprintf(sAryId, 63, "YScan_%d", nYScan); - } + else if(Units_canConvert(Zunits, UNIT_B_SPECDENS)) + strncpy(sAryId, "b_spec_dens", 63); + else + snprintf(sAryId, 63, "YScan_%d", nYScan); } else{ strncpy(sAryId, pPlaneId, 63); @@ -982,6 +1058,11 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) pVar = new_DasVarArray(pAry, SCALAR_2(0, 1)); if(pVar == NULL) return NULL; if(! DasDim_addVar(pDim, sRole, pVar)) return NULL; + + if(bCodecs) + if(_DasDsBldr_addCodec(pDs, sAryId, (int)uItems, pEncoder) != DAS_OKAY) + return NULL; + break; default: @@ -993,6 +1074,47 @@ DasDs* _DasDsBldr_initYScan(DasStream* pSd, PktDesc* pPd, const char* pGroup) return pDs; } +/* Generate an potentiall active dataset object from a packet descriptor + * + * This is an internal function and thus is not present in builder.h. To use it + * define the function prototype in the relavent module. + * + * @param bCodecs If true, define codecs for the generated dataset object so that + * it can be used to parse data packet payloads + */ +DasDs* dasds_from_packet(DasStream* pSd, PktDesc* pPd, const char* sGroup, bool bCodecs) +{ + /* Initialize based on the observed pattern. Das2 streams have traditionally + * followed certian layout patterns, you can't have arbitrary collections of + * and planes. */ + size_t u, uPlanes = PktDesc_getNPlanes(pPd); + PlaneDesc* pPlane = NULL; + int nXs = 0, nYs = 0, nYScans = 0, nZs = 0; + for(u = 0; u < uPlanes; ++u){ + pPlane = PktDesc_getPlane(pPd, u); + switch(PlaneDesc_getType(pPlane)){ + case X: ++nXs; break; + case Y: ++nYs; break; + case YScan: ++nYScans; break; + case Z: ++nZs; break; + case Invalid: das_error(DASERR_DS, "logic error"); return NULL; + } + } + + DasDs* pCd = NULL; + if(nYScans == 0){ + if(nZs != 0) pCd = _DasDsBldr_initXYZ(pSd, pPd, sGroup, bCodecs); + else{ + if(nXs == 2) pCd = _DasDsBldr_initEvents(pSd, pPd, sGroup); + else pCd = _DasDsBldr_initXY(pSd, pPd, sGroup, bCodecs); + } + } + else{ + pCd = _DasDsBldr_initYScan(pSd, pPd, sGroup, bCodecs); + } + return pCd; +} + /* Get the correlated dataset container that corresponds to the given packet * descriptor. This uses duck typing. If a packet descriptor has the same * number and type of planes, and each plane has the same name (and ytags if @@ -1019,34 +1141,7 @@ DasErrCode DasDsBldr_onPktDesc(DasStream* pSd, PktDesc* pPd, void* vpUd) char sGroupId[64] = {'\0'}; const char* pGroup = _DasDsBldr_getExistingGroup(pThis, pPd, sGroupId, 64); - /* Initialize based on the observed pattern. Das2 streams have traditionally - * followed certian layout patterns, you can't have arbitrary collections of - * and planes. */ - size_t u, uPlanes = PktDesc_getNPlanes(pPd); - PlaneDesc* pPlane = NULL; - int nXs = 0, nYs = 0, nYScans = 0, nZs = 0; - for(u = 0; u < uPlanes; ++u){ - pPlane = PktDesc_getPlane(pPd, u); - switch(PlaneDesc_getType(pPlane)){ - case X: ++nXs; break; - case Y: ++nYs; break; - case YScan: ++nYScans; break; - case Z: ++nZs; break; - case Invalid: das_error(DASERR_DS, "logic error"); return DASERR_DS; - } - } - - DasDs* pCd = NULL; - if(nYScans == 0){ - if(nZs != 0) pCd = _DasDsBldr_initXYZ(pSd, pPd, pGroup); - else{ - if(nXs == 2) pCd = _DasDsBldr_initEvents(pSd, pPd, pGroup); - else pCd = _DasDsBldr_initXY(pSd, pPd, pGroup); - } - } - else{ - pCd = _DasDsBldr_initYScan(pSd, pPd, pGroup); - } + DasDs* pCd = dasds_from_packet(pSd, pPd, pGroup, false); if(!pCd) return DASERR_BLDR; DasStream_addPktDesc(pThis->pStream, (DasDesc*)pCd, iPktId); diff --git a/das2/dataset.c b/das2/dataset.c index c4bcd69..023cf48 100644 --- a/das2/dataset.c +++ b/das2/dataset.c @@ -414,6 +414,21 @@ DasErrCode DasDs_addFixedCodec( return DAS_OKAY; } +int DasDs_recBytes(const DasDs* pThis) +{ + int nBytesPerPkt = 0; + for(size_t u = 0; u < pThis->uCodecs; ++u){ + int nValsExpect = DasDs_pktItems(pThis, u); + + if(nValsExpect < 1) /* Return -1 to indicate variable length packets */ + return -1; + + int16_t nValSz = DasDs_getCodec(pThis, u)->nBufValSz; + nBytesPerPkt += nValSz*nValsExpect; + } + return nBytesPerPkt; +} + /* ************************************************************************* */ char* DasDs_toStr(const DasDs* pThis, char* sBuf, int nLen) diff --git a/das2/dataset.h b/das2/dataset.h index 81929c0..0adba13 100644 --- a/das2/dataset.h +++ b/das2/dataset.h @@ -591,6 +591,24 @@ DAS_API DasErrCode DasDs_addRaggedCodec( int nItemBytes, int nSeps, ubyte uSepLen, const ubyte* pSepByIdx ); +/** Get the number of bytes in each record of this dataset when serialized + * + * Given the current codec set, determine how many bytes must be read + * for each packet in a stream. Works for the fixed encodings typical + * in *.d3b and *.d3t files but not for serializing to and from pure + * XML documents. + * + * @param pThis a Dataset structure pointer + * + * @returns The number of bytes expected in each packet payload for this + * dataset. It may be 0 if no codecs are defined. A values of + * -1 or less indicates variable length packets + * + * @memberof DasDs + */ +DAS_API int DasDs_recBytes(const DasDs* pThis); + + /** Clear any arrays that are ragged in index l * * This function is handy when reading data to insure that memory usage diff --git a/das2/io.c b/das2/io.c index 19fff5e..4a320cc 100644 --- a/das2/io.c +++ b/das2/io.c @@ -1127,10 +1127,23 @@ int _DasIO_sizeOrErr( return -1 * das_error(DASERR_IO, "Packet type %02d data received before packet " "type %02d header", nPktId, nPktId); - if(pDesc->type != PACKET) - return -1 * das_error(DASERR_IO, "Logic error in id.c"); - - nPktSz = PktDesc_recBytes((PktDesc*)pDesc); + if(pDesc->type == DATASET){ + nPktSz = DasDs_recBytes((DasDs*)pDesc); + if(nPktSz == 0){ + if(DasDs_numCodecs((DasDs*)pDesc) == 0) + return -1 * das_error(DASERR_IO, "No codecs are defined for the dataset"); + else + return -1 * das_error(DASERR_IO, "Logic error in io.c"); + } + if(nPktSz < 0) + return -1 * das_error(DASERR_IO, "Das2 streams do not support variable length packets"); + } + else{ + if(pDesc->type == PACKET) + nPktSz = PktDesc_recBytes((PktDesc*)pDesc); + else + return -1 * das_error(DASERR_IO, "Logic error in io.c"); + } } return nPktSz; } diff --git a/das2/property.c b/das2/property.c index 837482b..e4518aa 100644 --- a/das2/property.c +++ b/das2/property.c @@ -420,20 +420,98 @@ char DasProp_sep(const DasProp* pProp) int DasProp_items(const DasProp* pProp) { - /* Just count seperators */ - char cSep = DasProp_sep(pProp); - const char* sValue = DasProp_value(pProp); - int nItems = 1; - while(*sValue != '\0'){ - if(*sValue == cSep){ - ++nItems; + if((DASPROP_MULTI_MASK & pProp->flags) == DASPROP_SINGLE) + return 1; + + if((DASPROP_MULTI_MASK & pProp->flags) == DASPROP_RANGE) + return 2; + + /* For sets, count separators */ + if((DASPROP_MULTI_MASK & pProp->flags) == DASPROP_SET){ + char cSep = DasProp_sep(pProp); + const char* sValue = DasProp_value(pProp); + int nItems = 1; + while(*sValue != '\0'){ + if(*sValue == cSep){ + ++nItems; + } + ++sValue; } - ++sValue; + return nItems; } - return nItems; + + return 0; } -/* Converting values here. Note this is repeated in Descriptor and shouldn't be */ +/* The output functions here *********************************************** */ +/* TODO: Functionality is repeated in Descriptor and shouldn't be. */ + +/** Copy out the next value into a seperate buffer */ +bool _DasProp_next(const DasProp* pProp, const char** ppRead, char* sBuf, size_t uLen) +{ + if((*ppRead == NULL)||(*(*ppRead) == '\0')) /* Read pointing to '\0' indicates done too? */ + return false; + + if(uLen < 2){ + das_error(DASERR_PROP, "Output buffer too short, less then 2 bytes"); + return false; + } + + const char* sValue = DasProp_value(pProp); + const char* sTo = NULL; + ptrdiff_t uWrite = 0; + + switch(pProp->flags & 0x00000003){ + case DASPROP_SINGLE: + if(*ppRead == sValue){ // 1st item + *ppRead = NULL; + strncpy(sBuf, sValue, uLen-1); + return true; + } + break; + + case DASPROP_RANGE: + sTo = strstr(sValue, " to "); + if(*ppRead == sValue){ // 1st item + uWrite = sTo - sValue; + if(uWrite > uLen) uWrite = uLen; + strncpy(sBuf, sValue, uWrite); + *ppRead = sTo + 4; + return true; + } + else{ + uWrite = strlen(sValue) - (sTo - sValue) - 4; + if(uWrite > uLen) uWrite = uLen; + strncpy(sBuf, *ppRead, uWrite); + *ppRead = NULL; + return true; + } + break; + + case DASPROP_SET: + /* Find next sep*/ + sTo = strchr(*ppRead, DasProp_sep(pProp)); + if(sTo != NULL){ + uWrite = sTo - *ppRead; + if(uWrite > uLen) uWrite = uLen; + strncpy(sBuf, *ppRead, uWrite); + *ppRead = sTo + 1; + } + else{ + uWrite = strlen(*ppRead); + if(uWrite > uLen) uWrite = uLen; + strncpy(sBuf, *ppRead, uWrite); + *ppRead = NULL; + } + return true; + + default: + break; + } + + *ppRead = NULL; + return false; +} /** Convert integer property values to 64-bit ints * @@ -441,15 +519,22 @@ int DasProp_items(const DasProp* pProp) */ int DasProp_convertInt(const DasProp* pProp, int64_t* pBuf, size_t uBufLen) { + char sConv[32] = {'\0'}; + const char* pRead = DasProp_value(pProp); + size_t uRead = 0; + + while( _DasProp_next(pProp, &pRead, sConv, 31) && (uRead < uBufLen)){ #ifdef _WIN32 - if(sscanf(DasProp_value(pProp), "%lld", pBuf) != 1) + if(sscanf(sConv, "%lld", pBuf) != 1) #else - if(sscanf(DasProp_value(pProp), "%ld", pBuf) != 1) + if(sscanf(sConv, "%ld", pBuf) != 1) #endif - return -1 * das_error(DASERR_PROP, "Error converting '%s' to a double", - DasProp_value(pProp) - ); - return 1; + return -1 * das_error(DASERR_PROP, "Error converting '%s' to an integer", DasProp_value(pProp)); + ++pBuf; + ++uRead; + memset(sConv, 0, 32); + } + return (int)uRead; } /** Convert real-value properties to double @@ -458,13 +543,18 @@ int DasProp_convertInt(const DasProp* pProp, int64_t* pBuf, size_t uBufLen) */ int DasProp_convertReal(const DasProp* pProp, double* pBuf, size_t uBufLen) { - if(sscanf(DasProp_value(pProp), "%lf", pBuf) != 1) - return -1 * das_error(DASERR_PROP, "Error converting '%s' to a double", - DasProp_value(pProp) - ); - if(DasProp_items(pProp) > 1) - return -1 * das_error(DASERR_NOTIMP, "Add array property handling before v3.0 release"); - return 1; + char sConv[32] = {'\0'}; + const char* pRead = DasProp_value(pProp); + size_t uRead = 0; + + while( _DasProp_next(pProp, &pRead, sConv, 31) && (uRead < uBufLen)){ + if(sscanf(sConv, "%lf", pBuf) != 1) + return -1 * das_error(DASERR_PROP, "Error converting '%s' to a double", DasProp_value(pProp)); + ++pBuf; + ++uRead; + memset(sConv, 0, 32); + } + return (int)uRead; } /** Convert boolean property values to bytes @@ -479,20 +569,23 @@ int DasProp_convertBool(const DasProp* pProp, uint8_t* pBuf, size_t uBufLen) /** Convert datatime properties TT2K long integers */ int DasProp_convertTt2k(const DasProp* pProp, int64_t* pBuf, size_t uBufLen) { - const char* sValue = DasProp_value(pProp); + char sConv[32] = {'\0'}; + const char* pRead = DasProp_value(pProp); + size_t uRead = 0; das_time dt; - if(!dt_parsetime(sValue, &dt)) - return -1 * das_error(DASERR_TIME, "Could not convert %s to a datetime", sValue); - - *pBuf = dt_to_tt2k(&dt); - if(DasProp_items(pProp) > 1) - return -1 * das_error(DASERR_NOTIMP, "Add array property handling before v3.0 release"); - - return 1; + while( _DasProp_next(pProp, &pRead, sConv, 31) && (uRead < uBufLen)){ + if(!dt_parsetime(sConv, &dt)) + return -1 * das_error(DASERR_TIME, "Could not convert %s to a datetime", DasProp_value(pProp)); + *pBuf = dt_to_tt2k(&dt); + ++pBuf; + ++uRead; + memset(sConv, 0, 32); + } + return (int)uRead; } -/** Convert datatime properties to a double based value of units */ +/** Convert datetime properties to a double based value of units */ int DasProp_convertTime(const DasProp* pProp, uint64_t* pBuf, size_t uBufLen){ return -1 * das_error(DASERR_NOTIMP, "Time property conversion not yet implemented"); } diff --git a/das2/serial.c b/das2/serial.c index 0a80981..dbf457b 100644 --- a/das2/serial.c +++ b/das2/serial.c @@ -1405,7 +1405,7 @@ static void _serial_xmlElementEnd(void* pUserData, const char* sElement) /* ************************************************************************** */ -DasDs* dasds_from_xmlheader3(DasBuf* pBuf, StreamDesc* pParent, int nPktId) +DasDs* dasds_from_xmlheader(DasBuf* pBuf, StreamDesc* pParent, int nPktId) { context_t context = {0}; // All object's initially null context.pSd = pParent; @@ -1457,14 +1457,6 @@ DasDs* dasds_from_xmlheader3(DasBuf* pBuf, StreamDesc* pParent, int nPktId) return NULL; } -/* ************************************************************************** */ - -DasDs* dasds_from_xmlheader2(DasBuf* pBuf, StreamDesc* pParent, int nPktId) -{ - das_error(DASERR_NOTIMP, "Building datasets from das2 headers is not yet implemented"); - return NULL; -} - /* ************************************************************************** */ /* Decoding a data packet, using a dataset created above */ diff --git a/das2/serial.h b/das2/serial.h index 8ffd02a..df12b7b 100644 --- a/das2/serial.h +++ b/das2/serial.h @@ -28,7 +28,7 @@ extern "C" { #endif -/** Define a das dataset and all it's constiutant parts from a das3 XML header +/** Define a das dataset and all it's constiutant parts from an XML header * * @param pBuf The buffer to read. Reading will start with the read point * and will run until DasBuf_remaining() is 0 or the end tag @@ -43,24 +43,7 @@ extern "C" { * @returns A pointer to a new DasDs and all if it's children allocated * on the heap, or NULL on an error. */ -DAS_API DasDs* dasds_from_xmlheader3(DasBuf* pBuf, StreamDesc* pParent, int nPktId); - -/** Define a das dataset and all it's constiutant parts from a legacy das2 XML header - * - * @param pBuf The buffer to read. Reading will start with the read point - * and will run until DasBuf_remaining() is 0 or the end tag - * is found, which ever comes first. - * - * @param pParent The parent descriptor for this data set. This is assumed - * to be an object which can hold vector frame definitions. - * - * @param nPktId The packet's ID within it's parent's array. My be 0 if - * and only if pParent is NULL - * - * @returns A pointer to a new DasDs and all if it's children allocated - * on the heap, or NULL on an error. - */ -DAS_API DasDs* dasds_from_xmlheader2(DasBuf* pBuf, StreamDesc* pParent, int nPktId); +DAS_API DasDs* dasds_from_xmlheader(DasBuf* pBuf, StreamDesc* pParent, int nPktId); /** Given a das dataset decode it's packets diff --git a/das2/stream.c b/das2/stream.c index ceba279..c147513 100644 --- a/das2/stream.c +++ b/das2/stream.c @@ -40,6 +40,13 @@ #include "serial.h" #include "stream.h" +/* ************************************************************************** */ +/* Private defs from other modules */ + +DasDs* dasds_from_packet( + DasStream* pSd, PktDesc* pPd, const char* sGroup, bool bCodecs +); + /* ************************************************************************** */ /* Construction */ @@ -989,13 +996,15 @@ DasDesc* DasDesc_decode( } if(strcmp(sName, "packet") == 0){ - if((nModel == STREAM_MODEL_MIXED)||(nModel == STREAM_MODEL_V2)){ - return (DasDesc*) new_PktDesc_xml(pBuf, (DasDesc*)pSd, nPktId); - } - else{ - /* Upgrade to v3 internals for this type */ - return (DasDesc*) dasds_from_xmlheader2(pBuf, pSd, nPktId); - } + PktDesc* pPkt = new_PktDesc_xml(pBuf, (DasDesc*)pSd, nPktId); + + /* Up convert to a dataset if this is supposed to be a das3 stream. + Note: The stream descriptor is needed to check for a "waveform" renderer. + One of the spur-of-the-moment bad ideas in the v2 format. */ + if(nModel == STREAM_MODEL_V3) + return (DasDesc*) dasds_from_packet(pSd, pPkt, NULL, true /* = add codecs */); + else + return (DasDesc*) pPkt; } if(strcmp(sName, "dataset") == 0){ @@ -1003,7 +1012,7 @@ DasDesc* DasDesc_decode( das_error(DASERR_STREAM, "das3 element found, expected das2 headers"); return NULL; } - return (DasDesc*) dasds_from_xmlheader3(pBuf, pSd, nPktId); + return (DasDesc*) dasds_from_xmlheader(pBuf, pSd, nPktId); } das_error(DASERR_STREAM, "Unknown top-level descriptor object: %s", sName);