bool DOS_Shell::CheckConfig(char* cmd_in,char*line) { Section* test = control->GetSectionFromProperty(cmd_in); if(!test) return false; if(line && !line[0]) { std::string val = test->GetPropValue(cmd_in); if(val != NO_SUCH_PROPERTY) WriteOut("%s\n",val.c_str()); return true; } char newcom[1024]; newcom[0] = 0; strcpy(newcom,"z:\\config -set "); strcat(newcom,test->GetName()); strcat(newcom," "); strcat(newcom,cmd_in);strcat(newcom,line); DoCommand(newcom); return true; }
void CONFIG::Run(void) { FILE * f; if (cmd->FindString("-writeconf",temp_line,true) || cmd->FindString("-wc",temp_line,true)) { /* In secure mode don't allow a new configfile to be created */ if(control->SecureMode()) { WriteOut(MSG_Get("PROGRAM_CONFIG_SECURE_DISALLOW")); return; } f=fopen(temp_line.c_str(),"wb+"); if (!f) { WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),temp_line.c_str()); return; } fclose(f); control->PrintConfig(temp_line.c_str()); return; } if (cmd->FindString("-writelang",temp_line,true) ||cmd->FindString("-wl",temp_line,true)) { /* In secure mode don't allow a new languagefile to be created * Who knows which kind of file we would overwriting. */ if(control->SecureMode()) { WriteOut(MSG_Get("PROGRAM_CONFIG_SECURE_DISALLOW")); return; } f=fopen(temp_line.c_str(),"wb+"); if (!f) { WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),temp_line.c_str()); return; } fclose(f); MSG_Write(temp_line.c_str()); return; } /* Code for switching to secure mode */ if(cmd->FindExist("-securemode",true)) { control->SwitchToSecureMode(); WriteOut(MSG_Get("PROGRAM_CONFIG_SECURE_ON")); return; } /* Code for getting the current configuration. * * Official format: config -get "section property" * * As a bonus it will set %CONFIG% to this value as well */ if(cmd->FindString("-get",temp_line,true)) { std::string temp2 = ""; cmd->GetStringRemain(temp2);//So -get n1 n2= can be used without quotes if(temp2 != "") temp_line = temp_line + " " + temp2; std::string::size_type space = temp_line.find(" "); if(space == std::string::npos) { WriteOut(MSG_Get("PROGRAM_CONFIG_GET_SYNTAX")); return; } //Copy the found property to a new string and erase from templine (mind the space) std::string prop = temp_line.substr(space+1); temp_line.erase(space); Section* sec = control->GetSection(temp_line.c_str()); if(!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_SECTION_ERROR"),temp_line.c_str()); return; } std::string val = sec->GetPropValue(prop.c_str()); if(val == NO_SUCH_PROPERTY) { WriteOut(MSG_Get("PROGRAM_CONFIG_NO_PROPERTY"),prop.c_str(),temp_line.c_str()); return; } WriteOut("%s",val.c_str()); first_shell->SetEnv("CONFIG",val.c_str()); return; } /* Code for the configuration changes * * Official format: config -set "section property=value" * * Accepted: without quotes and/or without -set and/or without section * * and/or the "=" replaced by a " " */ if (cmd->FindString("-set",temp_line,true)) { //get all arguments std::string temp2 = ""; cmd->GetStringRemain(temp2);//So -set n1 n2=n3 can be used without quotes if(temp2!="") temp_line = temp_line + " " + temp2; } else if(!cmd->GetStringRemain(temp_line)) {//no set WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); //and no arguments specified return; }; //Wanted input: n1 n2=n3 char copy[1024]; strcpy(copy,temp_line.c_str()); //seperate section from property const char* temp = strchr(copy,' '); if((temp && *temp) || (temp=strchr(copy,'=')) ) copy[temp++ - copy]= 0; else { WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); return; } //if n1 n2 n3 then replace last space with = const char* sign = strchr(temp,'='); if(!sign) { sign = strchr(temp,' '); if(sign) { copy[sign - copy] = '='; } else { //2 items specified (no space nor = between n2 and n3 //assume that they posted: property value //Try to determine the section. Section* sec=control->GetSectionFromProperty(copy); if(!sec){ if(control->GetSectionFromProperty(temp)) return; //Weird situation:ignore WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR"),copy); return; } //Hack to allow config ems true char buffer[1024];strcpy(buffer,copy);strcat(buffer,"=");strcat(buffer,temp); sign = strchr(buffer,' '); if(sign) buffer[sign - buffer] = '='; strcpy(copy,sec->GetName()); temp = buffer; } } /* Input processed. Now the real job starts * copy contains the likely "sectionname" * temp contains "property=value" * the section is destroyed and a new input line is given to * the configuration parser. Then the section is restarted. */ char* inputline = const_cast<char*>(temp); Section* sec = 0; sec = control->GetSection(copy); if(!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_SECTION_ERROR"),copy);return;} sec->ExecuteDestroy(false); sec->HandleInputline(inputline); sec->ExecuteInit(false); return; }
void CONFIG::Run(void) { static const char* const params[] = { "-r", "-wcp", "-wcd", "-wc", "-writeconf", "-l", "-rmconf", "-h", "-help", "-?", "-axclear", "-axadd", "-axtype", "-get", "-set", "-writelang", "-wl", "-securemode", "" }; enum prs { P_NOMATCH, P_NOPARAMS, // fixed return values for GetParameterFromList P_RESTART, P_WRITECONF_PORTABLE, P_WRITECONF_DEFAULT, P_WRITECONF, P_WRITECONF2, P_LISTCONF, P_KILLCONF, P_HELP, P_HELP2, P_HELP3, P_AUTOEXEC_CLEAR, P_AUTOEXEC_ADD, P_AUTOEXEC_TYPE, P_GETPROP, P_SETPROP, P_WRITELANG, P_WRITELANG2, P_SECURE } presult = P_NOMATCH; bool first = true; std::vector<std::string> pvars; // Loop through the passed parameters while(presult != P_NOPARAMS) { presult = (enum prs)cmd->GetParameterFromList(params, pvars); switch(presult) { case P_RESTART: if (securemode_check()) return; if (pvars.size() == 0) restart_program(control->startup_params); else { std::vector<std::string> restart_params; restart_params.push_back(control->cmdline->GetFileName()); for(size_t i = 0; i < pvars.size(); i++) { restart_params.push_back(pvars[i]); if (pvars[i].find(' ') != std::string::npos) { pvars[i] = "\""+pvars[i]+"\""; // add back spaces } } // the rest on the commandline, too cmd->FillVector(restart_params); restart_program(restart_params); } return; case P_LISTCONF: { Bitu size = control->configfiles.size(); std::string config_path; Cross::GetPlatformConfigDir(config_path); WriteOut(MSG_Get("PROGRAM_CONFIG_CONFDIR"), VERSION,config_path.c_str()); if (size==0) WriteOut(MSG_Get("PROGRAM_CONFIG_NOCONFIGFILE")); else { WriteOut(MSG_Get("PROGRAM_CONFIG_PRIMARY_CONF"),control->configfiles.front().c_str()); if (size > 1) { WriteOut(MSG_Get("PROGRAM_CONFIG_ADDITIONAL_CONF")); for(Bitu i = 1; i < size; i++) WriteOut("%s\n",control->configfiles[i].c_str()); } } if (control->startup_params.size() > 0) { std::string test; for(size_t k = 0; k < control->startup_params.size(); k++) test += control->startup_params[k] + " "; WriteOut(MSG_Get("PROGRAM_CONFIG_PRINT_STARTUP"), test.c_str()); } break; } case P_WRITECONF: case P_WRITECONF2: if (securemode_check()) return; if (pvars.size() > 1) return; else if (pvars.size() == 1) { // write config to specific file, except if it is an absolute path writeconf(pvars[0], !Cross::IsPathAbsolute(pvars[0])); } else { // -wc without parameter: write primary config file if (control->configfiles.size()) writeconf(control->configfiles[0], false); else WriteOut(MSG_Get("PROGRAM_CONFIG_NOCONFIGFILE")); } break; case P_WRITECONF_DEFAULT: { // write to /userdir/dosbox0.xx.conf if (securemode_check()) return; if (pvars.size() > 0) return; std::string confname; Cross::GetPlatformConfigName(confname); writeconf(confname, true); break; } case P_WRITECONF_PORTABLE: if (securemode_check()) return; if (pvars.size() > 1) return; else if (pvars.size() == 1) { // write config to startup directory writeconf(pvars[0], false); } else { // -wcp without parameter: write dosbox.conf to startup directory if (control->configfiles.size()) writeconf(std::string("dosbox.conf"), false); else WriteOut(MSG_Get("PROGRAM_CONFIG_NOCONFIGFILE")); } break; case P_NOPARAMS: if (!first) break; case P_NOMATCH: WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); return; case P_HELP: case P_HELP2: case P_HELP3: { switch(pvars.size()) { case 0: WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); return; case 1: { if (!strcasecmp("sections",pvars[0].c_str())) { // list the sections WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_SECTLIST")); Bitu i = 0; while(true) { Section* sec = control->GetSection(i++); if (!sec) break; WriteOut("%s\n",sec->GetName()); } return; } // if it's a section, leave it as one-param Section* sec = control->GetSection(pvars[0].c_str()); if (!sec) { // could be a property sec = control->GetSectionFromProperty(pvars[0].c_str()); if (!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } pvars.insert(pvars.begin(),std::string(sec->GetName())); } break; } case 2: { // sanity check Section* sec = control->GetSection(pvars[0].c_str()); Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); if (sec != sec2) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); } break; } default: WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); return; } // if we have one value in pvars, it's a section // two values are section + property Section* sec = control->GetSection(pvars[0].c_str()); if (sec==NULL) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } Section_prop* psec = dynamic_cast <Section_prop*>(sec); if (psec==NULL) { // failed; maybe it's the autoexec section? Section_line* pline = dynamic_cast <Section_line*>(sec); if (pline==NULL) E_Exit("Section dynamic cast failed."); WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_LINEHLP"), pline->GetName(), // this is 'unclean' but the autoexec section has no help associated MSG_Get("AUTOEXEC_CONFIGFILE_HELP"), pline->data.c_str() ); return; } if (pvars.size()==1) { size_t i = 0; WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_SECTHLP"),pvars[0].c_str()); while(true) { // list the properties Property* p = psec->Get_prop(i++); if (p==NULL) break; WriteOut("%s\n", p->propname.c_str()); } } else { // find the property by it's name size_t i = 0; while (true) { Property *p = psec->Get_prop(i++); if (p==NULL) break; if (!strcasecmp(p->propname.c_str(),pvars[1].c_str())) { // found it; make the list of possible values std::string propvalues; std::vector<Value> pv = p->GetValues(); if (p->Get_type()==Value::V_BOOL) { // possible values for boolean are true, false propvalues += "true, false"; } else if (p->Get_type()==Value::V_INT) { // print min, max for integer values if used Prop_int* pint = dynamic_cast <Prop_int*>(p); if (pint==NULL) E_Exit("Int property dynamic cast failed."); if (pint->getMin() != pint->getMax()) { std::ostringstream oss; oss << pint->getMin(); oss << ".."; oss << pint->getMax(); propvalues += oss.str(); } } for(Bitu k = 0; k < pv.size(); k++) { if (pv[k].ToString() =="%u") propvalues += MSG_Get("PROGRAM_CONFIG_HLP_POSINT"); else propvalues += pv[k].ToString(); if ((k+1) < pv.size()) propvalues += ", "; } WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_PROPHLP"), p->propname.c_str(), sec->GetName(), p->Get_help(),propvalues.c_str(), p->Get_Default_Value().ToString().c_str(), p->GetValue().ToString().c_str()); // print 'changability' if (p->getChange()==Property::Changeable::OnlyAtStart) { WriteOut(MSG_Get("PROGRAM_CONFIG_HLP_NOCHANGE")); } return; } } break; } return; } case P_AUTOEXEC_CLEAR: { Section_line* sec = dynamic_cast <Section_line*> (control->GetSection(std::string("autoexec"))); sec->data.clear(); break; } case P_AUTOEXEC_ADD: { if (pvars.size() == 0) { WriteOut(MSG_Get("PROGRAM_CONFIG_MISSINGPARAM")); return; } Section_line* sec = dynamic_cast <Section_line*> (control->GetSection(std::string("autoexec"))); for(Bitu i = 0; i < pvars.size(); i++) sec->HandleInputline(pvars[i]); break; } case P_AUTOEXEC_TYPE: { Section_line* sec = dynamic_cast <Section_line*> (control->GetSection(std::string("autoexec"))); WriteOut("\n%s",sec->data.c_str()); break; } case P_GETPROP: { // "section property" // "property" // "section" // "section" "property" if (pvars.size()==0) { WriteOut(MSG_Get("PROGRAM_CONFIG_GET_SYNTAX")); return; } std::string::size_type spcpos = pvars[0].find_first_of(' '); // split on the ' ' if (spcpos != std::string::npos) { pvars.insert(++pvars.begin(),pvars[0].substr(spcpos+1)); pvars[0].erase(spcpos); } switch(pvars.size()) { case 1: { // property/section only // is it a section? Section* sec = control->GetSection(pvars[0].c_str()); if (sec) { // list properties in section Bitu i = 0; Section_prop* psec = dynamic_cast <Section_prop*>(sec); if (psec==NULL) { // autoexec section Section_line* pline = dynamic_cast <Section_line*>(sec); if (pline==NULL) E_Exit("Section dynamic cast failed."); WriteOut("%s",pline->data.c_str()); break; } while(true) { // list the properties Property* p = psec->Get_prop(i++); if (p==NULL) break; WriteOut("%s=%s\n", p->propname.c_str(), p->GetValue().ToString().c_str()); } } else { // no: maybe it's a property? sec = control->GetSectionFromProperty(pvars[0].c_str()); if (!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } // it's a property name std::string val = sec->GetPropValue(pvars[0].c_str()); WriteOut("%s",val.c_str()); } break; } case 2: { // section + property Section* sec = control->GetSection(pvars[0].c_str()); if (!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_SECTION_ERROR")); return; } std::string val = sec->GetPropValue(pvars[1].c_str()); if (val == NO_SUCH_PROPERTY) { WriteOut(MSG_Get("PROGRAM_CONFIG_NO_PROPERTY"), pvars[1].c_str(),pvars[0].c_str()); return; } WriteOut("%s",val.c_str()); break; } default: WriteOut(MSG_Get("PROGRAM_CONFIG_GET_SYNTAX")); return; } return; } case P_SETPROP: { // Code for the configuration changes // Official format: config -set "section property=value" // Accepted: with or without -set, // "section property value" // "section property=value" // "property" "value" // "section" "property=value" // "section" "property=value" "value" "value" ... // "section" "property" "value" "value" ... // "section property" "value" "value" ... // "property" "value" "value" ... // "property=value" "value" "value" ... if (pvars.size()==0) { WriteOut(MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); return; } // add rest of command std::string rest; if (cmd->GetStringRemain(rest)) pvars.push_back(rest); // attempt to split off the first word std::string::size_type spcpos = pvars[0].find_first_of(' '); std::string::size_type equpos = pvars[0].find_first_of('='); if ((equpos != std::string::npos) && ((spcpos == std::string::npos) || (equpos < spcpos))) { // If we have a '=' possibly before a ' ' split on the = pvars.insert(++pvars.begin(),pvars[0].substr(equpos+1)); pvars[0].erase(equpos); // As we had a = the first thing must be a property now Section* sec=control->GetSectionFromProperty(pvars[0].c_str()); if (sec) pvars.insert(pvars.begin(),std::string(sec->GetName())); else { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } // order in the vector should be ok now } else { if ((spcpos != std::string::npos) && ((equpos == std::string::npos) || (spcpos < equpos))) { // ' ' before a possible '=', split on the ' ' pvars.insert(++pvars.begin(),pvars[0].substr(spcpos+1)); pvars[0].erase(spcpos); } // check if the first parameter is a section or property Section* sec = control->GetSection(pvars[0].c_str()); if (!sec) { // not a section: little duplicate from above Section* sec=control->GetSectionFromProperty(pvars[0].c_str()); if (sec) pvars.insert(pvars.begin(),std::string(sec->GetName())); else { WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); return; } } else { // first of pvars is most likely a section, but could still be gus // have a look at the second parameter if (pvars.size() < 2) { WriteOut(MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); return; } std::string::size_type spcpos2 = pvars[1].find_first_of(' '); std::string::size_type equpos2 = pvars[1].find_first_of('='); if ((equpos2 != std::string::npos) && ((spcpos2 == std::string::npos) || (equpos2 < spcpos2))) { // split on the = pvars.insert(pvars.begin()+2,pvars[1].substr(equpos2+1)); pvars[1].erase(equpos2); } else if ((spcpos2 != std::string::npos) && ((equpos2 == std::string::npos) || (spcpos2 < equpos2))) { // split on the ' ' pvars.insert(pvars.begin()+2,pvars[1].substr(spcpos2+1)); pvars[1].erase(spcpos2); } // is this a property? Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); if (!sec2) { // not a property, Section* sec3 = control->GetSectionFromProperty(pvars[0].c_str()); if (sec3) { // section and property name are identical pvars.insert(pvars.begin(),pvars[0]); } // else has been checked above already } } } if(pvars.size() < 3) { WriteOut(MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); return; } // check if the property actually exists in the section Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); if (!sec2) { WriteOut(MSG_Get("PROGRAM_CONFIG_NO_PROPERTY"), pvars[1].c_str(),pvars[0].c_str()); return; } // Input has been parsed (pvar[0]=section, [1]=property, [2]=value) // now execute Section* tsec = control->GetSection(pvars[0]); std::string value; value += pvars[2]; for(Bitu i = 3; i < pvars.size(); i++) value += (std::string(" ") + pvars[i]); std::string inputline = pvars[1] + "=" + value; tsec->ExecuteDestroy(false); bool change_success = tsec->HandleInputline(inputline.c_str()); if (!change_success) WriteOut(MSG_Get("PROGRAM_CONFIG_VALUE_ERROR"), value.c_str(),pvars[1].c_str()); tsec->ExecuteInit(false); return; } case P_WRITELANG: case P_WRITELANG2: // In secure mode don't allow a new languagefile to be created // Who knows which kind of file we would overwrite. if (securemode_check()) return; if (pvars.size() < 1) { WriteOut(MSG_Get("PROGRAM_CONFIG_MISSINGPARAM")); return; } if (!MSG_Write(pvars[0].c_str())) { WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),pvars[0].c_str()); return; } break; case P_SECURE: // Code for switching to secure mode control->SwitchToSecureMode(); WriteOut(MSG_Get("PROGRAM_CONFIG_SECURE_ON")); return; default: E_Exit("bug"); break; } first = false; } return; }
Section* BinaryWriter<ElemType>::CreateSection(const ConfigParameters& config, Section* parentSection, size_t p_records, size_t p_windowSize) { // first check if we need to open a new section file std::vector<std::wstring> sections; // determine the element size, default to ElemType size size_t elementSize = sizeof(ElemType); if (config.ExistsCurrent(L"elementSize")) { elementSize = config(L"elementSize"); } // get the number of records we should expect (max) // if defined in previous levels same number will be used size_t records = p_records; if (config.ExistsCurrent(L"wrecords")) { records = config(L"wrecords"); } if (records == 0) { InvalidArgument("Required config variable 'wrecords' missing from BinaryWriter configuration."); } size_t dim = 1; // default dimension (single item) if (config.ExistsCurrent(L"dim")) { dim = config(L"dim"); } // get the section type (used for caching) SectionType sectionType = sectionTypeNull; if (config.ExistsCurrent(L"sectionType")) { SectionType foundType = sectionTypeNull; wstring type = config(L"sectionType"); for (int i = 0; i < sectionTypeMax; i++) { if (EqualCI(type, SectionTypeStrings[i])) { foundType = SectionType(i); break; } } // check to make sure it matched something if (foundType == sectionTypeNull) { InvalidArgument("Invalid value for 'sectionType' in BinaryWriter configuration: %ls", type.c_str()); } sectionType = foundType; } // calculate number of bytes = dim*elementSize*records size_t dataOnlySize = records * elementSize * dim; size_t dataSize = dataOnlySize + sectionHeaderMin; // filename to use the one defined at this level, if there is none use the parent file SectionFile* file = NULL; if (config.ExistsCurrent(L"wfile")) { std::wstring wfile = config(L"wfile"); auto secFile = m_secFiles.find(wfile); if (secFile != m_secFiles.end()) { file = secFile->second; } else { // TODO: sanity check and use records as a clue of how big to make it size_t initialSize = config(L"wsize", (size_t) 256); // default to 256MB if not provided initialSize *= 1024 * 1024; // convert MB to bytes if (initialSize < dataSize) initialSize = dataSize * 5 / 4; // make the initalSize slightly larger than needed for data file = new SectionFile(wfile, fileOptionsReadWrite, initialSize); m_secFiles[wfile] = file; parentSection = file->FileSection(); parentSection->SetElementCount(records); parentSection->SetFileUniqueId(this->m_uniqueID); } } else { // no file defined at this config level, use parent file if (parentSection != NULL && parentSection->GetSectionFile() != NULL) { file = parentSection->GetSectionFile(); } else if (sectionType != sectionTypeNull) { InvalidArgument("No filename (wfile) defined in BinaryWriter configuration."); } } // determine file position if needed size_t filePositionLast = 0; size_t filePositionNext = 0; if (file != NULL) { // get the next available position in the file (always on the end) filePositionLast = file->GetFilePositionMax(); filePositionNext = file->RoundUp(filePositionLast); // we have a gap, zero it out to keep the file clean if (filePositionLast != filePositionNext) { size_t size = filePositionNext - filePositionLast; size_t roundDown = file->RoundUp(filePositionLast - file->GetViewAlignment() - 1); // need to get a veiw to zero out non-used bytes void* view = file->GetView(roundDown, file->GetViewAlignment()); char* ptr = (char*) view + filePositionLast % file->GetViewAlignment(); memset(ptr, 0, size); file->ReleaseView(view); } } // get the new section name std::string sectionName = config.ConfigName(); // get the window size, to see if we want to do separate element mapping size_t windowSize = p_windowSize; if (config.ExistsCurrent(L"windowSize")) { windowSize = config(L"windowSize"); } MappingType mappingMain = windowSize ? mappingElementWindow : mappingParent; MappingType mappingAux = windowSize ? mappingSection : mappingParent; // now create the new section Section* section = NULL; switch (sectionType) { case sectionTypeNull: // this happens for the original file header, nothing to do // also used when multiple files are defined, but none at the base level break; case sectionTypeFile: // file header // shouldn't occur, but same case as above break; case sectionTypeData: // data section section = new Section(file, parentSection, filePositionNext, mappingMain, dataSize); section->InitHeader(sectionTypeData, sectionName + ":Data Section", sectionDataFloat, sizeof(ElemType)); break; case sectionTypeLabel: // label data { size_t elementSize2 = sizeof(LabelIdType); dataSize = records * elementSize2 + sectionHeaderMin; auto sectionLabel = new SectionLabel(file, parentSection, filePositionNext, mappingMain, dataSize); SectionData dataType = sectionDataInt; LabelKind labelKind = labelCategory; // default if (config.Match(L"labelType", L"Regression")) { labelKind = labelRegression; dataType = sectionDataFloat; elementSize2 = sizeof(ElemType); } else if (config.Match(L"labelType", L"Category")) { // everything set already, default value } else { RuntimeError("Invalid type 'labelType' or missing in BinaryWriter configuration."); } // initialize the section header sectionLabel->InitHeader(sectionTypeLabel, sectionName + ":Labels", dataType, (WORD) elementSize2); // initialize the special label header items sectionLabel->SetLabelKind(labelKind); sectionLabel->SetLabelDim(config(L"labelDim")); section = sectionLabel; break; } case sectionTypeLabelMapping: // label mapping table (array of strings) section = new SectionString(file, parentSection, filePositionNext, mappingAux, dataSize); section->InitHeader(sectionTypeLabelMapping, sectionName + ":Label Map", sectionDataStrings, 0); // declare variable length strings section->SetFlags(flagAuxilarySection); section->SetFlags(flagVariableSized); break; case sectionTypeStats: // data statistics { ConfigArray calcStats = config(L"compute"); records = calcStats.size(); elementSize = sizeof(NumericStatistics); dataOnlySize = records * elementSize; dataSize = dataOnlySize + sectionHeaderMin; auto sectionStats = new SectionStats(file, parentSection, filePositionNext, mappingAux, dataSize); sectionStats->InitHeader(sectionTypeStats, sectionName + ":Data Statistics", sectionDataStruct, sizeof(NumericStatistics)); // declare variable length strings sectionStats->SetFlags(flagAuxilarySection); section = sectionStats; break; } case sectionTypeCategoryLabel: section = new Section(file, parentSection, filePositionNext, mappingMain, dataSize); section->InitHeader(sectionTypeCategoryLabel, sectionName + ":Category Labels", sectionDataFloat, sizeof(ElemType)); // declare variable length strings break; } // set the rest of the header variables necessary if (section == NULL) { // NULL or file section/already created section = parentSection; } else { section->SetElementSize(elementSize); section->SetElementsPerRecord(dim); section->SetElementCount(records * dim); section->SetSize(dataSize); section->SetSizeAll(dataSize); // windowSize is in records, convert to bytes size_t dataWindowSize = windowSize ? windowSize * elementSize * dim : dataOnlySize; // clamp it down to actual data size dataWindowSize = min(dataOnlySize, dataWindowSize); // now get the data pointer setup and allocate the view as necessary bool auxSection = !!(section->GetFlags() & flagAuxilarySection); section->EnsureElements(0, auxSection ? dataOnlySize : dataWindowSize); // update the max file position for the next section file->SetFilePositionMax(section->GetFilePosition() + dataSize); // Add new section to parent parentSection->AddSection(section); } // From here on down we have a fully usable section object // now find the subsections and repeat vector<std::wstring> subsections; FindConfigNames(config, "sectionType", subsections); // look for any children and create them as well for (std::wstring subsection : subsections) { CreateSection(config(subsection), section, records, windowSize); } // wait until here so everything is mapped and valid in the object if (sectionType == sectionTypeStats) { ConfigArray calcStats = config(L"compute"); ((SectionStats*) section)->InitCompute(calcStats); } // add to section map if (sectionType != sectionTypeFile && sectionType != sectionTypeNull) { std::wstring wsectionName = msra::strfun::utf16(sectionName); // can't have identical names in a write configuration if (m_sections.find(wsectionName) != m_sections.end()) { RuntimeError("Identical section name appears twice:%s", sectionName.c_str()); } m_sections[wsectionName] = section; } // validate the header (make sure it's sane) if (section && file && !section->ValidateHeader(file->Writing())) { RuntimeError("Invalid header in file %ls, in header %ls\n", file->GetName().c_str(), section->GetName().c_str()); } // return the now complete section return section; }