S57文件存储结构一、DDR结构DDR中定义了文件的总体信息,包括文件名,字段名,字段类型,字段格式和长度,字段间的关系,及子字段.1.文件头区24个字节,内容如下表记录长度是指DDR的总长度.2.记录区记录区从第25个字节开始,直到字节值=30为止.30称为字段终结符(FT=30).每个记录的长度由:文件头区中的,字段长度大小,字段位置大小,字段标识的大小之和决定.每个记录描述一个字段的基本信息(名称、长度、起始位置).每个记录是定长的.3.字段区记录区中的每一条记录对应一个字段,然后在字段描述区进一步给出字段的具体信息。每个字段的描述信息之间由字段终结符(FT30)隔开。每个字段的描述信息内部不同部分由单元终结符(UT=31)隔开。其中每个字段描述信息的第一部分为字段的控制信息,共9个字节组成。DDR的第一个字段为控制字段,字段名为0000(地址为:目录区后的第一个字节(文件头+目录区的长度))控制字段给出了文件名、及全部字段的结构信息。例如:如下控制字段数据可生成对应的字段结构图DDR的其余字段为数据描述字段,(地址为:目录区后的第一个字节+该字段的偏移量)。例如:如下的字段描述字段为4.程序实现S57-文件对应的DDFModule类,在该类中读入DDR信息。其中,DDR文件头存入achLeader中。charachLeader[nLeaderSize];//nLeaderSize=24DDR中完整数据存入:pachRecord中。pachRecord=(char*)CPLMalloc(_recLength);//_recLength在文件头中的第一个域中定义。根据DDR文件头中定义内容和终止符计算DDR中字段的记录个数。for(i=nLeaderSize;i_recLength;i+=nFieldEntryWidth){if(pachRecord[i]==DDF_FIELD_TERMINATOR)break;nFDCount++;}在字段的每一条记录中,得到每一个字段的标识、长度、起始位置(从记录区后面的第一个字节开始计算)。根据记录区中定义的各字段标识、长度、起始位置在字段区中取到该字段对应的描述信息。主要包括字段名称、描述及在后面数据区中占的位置和转换格式。例如SG2D对应的描述为:定义了Y、X坐标为2个实数。程序处理中,将每一个记录定义为一个对象,其基类为:DDFFieldDefnDDFFieldDefn*poFDefn;AddField(poFDefn);voidDDFModule::AddField(DDFFieldDefn*poNewFDefn){nFieldDefnCount++;papoFieldDefns=(DDFFieldDefn**)CPLRealloc(papoFieldDefns,sizeof(void*)*nFieldDefnCount);papoFieldDefns[nFieldDefnCount-1]=poNewFDefn;}其中:DDFFieldDefn**papoFieldDefns;注:*poFDefn本身为DDFFieldDefn指针,而每一个字段对应一个指针,故papoFieldDefns为二级指针。特别注意:switch(pachFieldArea[0])//字段区的第一个字节,即控制字段的第一个字节{case'0':_data_struct_code=dsc_elementary;break;}if(_data_struct_code!=dsc_elementary){if(!BuildSubfields())returnFALSE;if(!ApplyFormats())returnFALSE;}其中,BuildSubfields定义如下:intDDFFieldDefn::BuildSubfields(){char**papszSubfieldNames;constchar*pszSublist=_arrayDescr;//字段描述区字符,在Initialize中定义if(pszSublist[0]=='*'){bRepeatingSubfields=TRUE;pszSublist++;}papszSubfieldNames=CSLTokenizeStringComplex(pszSublist,!,FALSE,FALSE);intnSFCount=CSLCount(papszSubfieldNames);for(intiSF=0;iSFnSFCount;iSF++){DDFSubfieldDefn*poSFDefn=newDDFSubfieldDefn;poSFDefn-SetName(papszSubfieldNames[iSF]);AddSubfield(poSFDefn,TRUE);}CSLDestroy(papszSubfieldNames);returnTRUE;}例如:共定义了12个字段的格式,分别为A(2),I(10),3A,A(3),4R,2A。定义的子字段存入papoSubfields中,而papoSubfields定义为:DDFSubfieldDefn**papoSubfields;注意:每一个字段对应一个对象,存入DDFModule类中的DDFFieldDefn**papoFieldDefns;数组内。而每一个子字段DDFSubfieldDefn**papoSubfields又存入字段类DDFFieldDefn中。ApplyFormats功能为将字段区内的格式域应用于各子字段中。intDDFFieldDefn::ApplyFormats(){char*pszFormatList;char**papszFormatItems;if(strlen(_formatControls)2||_formatControls[0]!='('||_formatControls[strlen(_formatControls)-1]!=')'){CPLError(CE_Failure,CPLE_AppDefined,Formatcontrolsfor`%s'fieldmissingbrackets:%s\n,pszTag,_formatControls);returnFALSE;}pszFormatList=ExpandFormat(_formatControls);//展开格式控制,如3A,展开后为:A,A,ApapszFormatItems=CSLTokenizeStringComplex(pszFormatList,,,FALSE,FALSE);将展开后的格式控制字符串,变成单个格式控制组成的指针.如“(A,A,A,B10,F4)”则指针分别指向:A,A,A,B10,F4各单项CPLFree(pszFormatList);intiFormatItem;for(iFormatItem=0;papszFormatItems[iFormatItem]!=NULL;iFormatItem++){constchar*pszPastPrefix;pszPastPrefix=papszFormatItems[iFormatItem];while(*pszPastPrefix='0'&&*pszPastPrefix='9')pszPastPrefix++;if(iFormatItem=nSubfieldCount){CPLError(CE_Warning,CPLE_AppDefined,格式项与子字段项不等`%s'.\n,pszTag);break;}if(!papoSubfields[iFormatItem]-SetFormat(pszPastPrefix))returnFALSE;}CSLDestroy(papszFormatItems);if(iFormatItemnSubfieldCount){CPLError(CE_Failure,CPLE_AppDefined,Gotlessformatsthansubfieldsforfield`%s',\n,pszTag);returnFALSE;}判断该字段是否为定长,nFixedWidth=0;for(inti=0;inSubfieldCount;i++){if(papoSubfields[i]-GetWidth()==0){nFixedWidth=0;只要有一个子字段不定长时,则该字段不定长,即nFixedWidth=0;break;}elsenFixedWidth+=papoSubfields[i]-GetWidth();}returnTRUE;}二、DR结构1.文件头区24个字节,内容如下表记录长度是指DR的总长度.3.记录区与DDR相同3.字段区与DDR相同DR程序分析:在DR区内每次读入一条记录,存入DDFModule类内的poRecord。而poRecord类型为:DDFRecord*poRecord;注意:每一个DR读入后,即开始处理,并未保存poRecord;在每次DR的读入过程中,首先判断上一次读入的DR文件头是否要重要使用,若否,则先读入该DR的文件头。if(!nReuseHeader){return(ReadHeader());}其中,nReuseHeader在上一个DR的文件头中定义。if(_leaderIden=='R')nReuseHeader=TRUE;DR中的数据存入DDFRecord类的pachData中。本DR的字段个数存入DDFRecord类中的nFieldCount。DR中的字段存入paoFields=newDDFField[nFieldCount]中;初始化paoFields后得到各字段的数据、长度,并在DDFModule类中定义的DDFFieldDefn**papoFieldDefns;找到对应项,取到相应的格式。然后,调用CParseS57_VC6Doc中的函数:ViewRecordField来解析本DR中的全部字段。得到物标的特征属性数据和空间属性数据。DDFFieldDefn*poFieldDefn=poModule-FindFieldDefn(szTag);读DR时,调用oModule.ReadRecord().每个DR对应一个oModule.ReadRecord().在oModule.ReadRecord()中,先读出文件头区,然后读出记录区,每条记录对应一个字段.然后调用ViewRecordField来解析该字段对应的数据.while((poRecord=oModule.ReadRecord())!=NULL){//debuginfo(@@@@@@@@@@@@@@@@@@@@@@@DDFRecordstart@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n);for(intiField=0;iFieldpoRecord-GetFieldCount();iField++){DDFField*poField=poRecord-GetField(iField);ViewRecordField(poField);nFieldCount++;}nRecordCount++;}字段数据解析函数voidCParseS57Doc::ViewRecordField(DDFField*poField){intnBytesRemaining;constchar*pachFieldData;DDFFieldDefn*poFieldDefn=poField-GetFieldDefn();charstr[300];if((strncmp(poFieldDefn-GetName(),VRID,4)==0)||(strncmp(poFieldDefn-GetName(),FRID,4)==0)){//为空间数据就打印,并赋m_datatype值m_datatype=NEED_TYPE;}elseif(strncmp(poFieldDef