src/RecfileHandler.h
branchv_0
changeset 17 f67047a1e19e
parent 16 1731e8dff446
child 18 002077ecb17a
equal deleted inserted replaced
16:1731e8dff446 17:f67047a1e19e
    41 private:
    41 private:
    42 	std::ostream& output;
    42 	std::ostream& output;
    43 	wstring_convert<codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8
    43 	wstring_convert<codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8
    44 	std::vector<TypeId> attributeTypes;
    44 	std::vector<TypeId> attributeTypes;
    45 	std::vector<string_t> attributeTypeCodes;
    45 	std::vector<string_t> attributeTypeCodes;
    46 	std::vector<string_t> attributeNames;
    46 	std::vector<string_t> attributeNamesIn;
       
    47 	std::vector<string_t> attributeNamesOut;
    47 	integer_t valueCount = 0;
    48 	integer_t valueCount = 0;
    48 	integer_t attributeCount = 0;
    49 	integer_t attributeCount = 0;
    49 	integer_t relationCount = 0;
    50 	integer_t relationCount = 0;
    50 
    51 
    51 	void writeRelationName(const string_t& name) {
    52 	void writeRelationName(const string_t& name) {
    60 			case TypeId::STRING: return "";
    61 			case TypeId::STRING: return "";
    61 			default: throw RelpipeReaderException(L"Unsupported type – unable to convert to a Recfile type");
    62 			default: throw RelpipeReaderException(L"Unsupported type – unable to convert to a Recfile type");
    62 		}
    63 		}
    63 	}
    64 	}
    64 
    65 
    65 	void writeAttributeMetadata(const handlers::AttributeMetadata& attribute) {
    66 	void writeAttributeMetadata(size_t i) {
    66 		// FIXME: escaping/filtering
    67 		std::string recfileType = toRecfileType(attributeTypes[i]);
    67 		std::string recfileType = toRecfileType(attribute.getTypeId());
    68 		if (recfileType.size()) output << "%type: " << convertor.to_bytes(attributeNamesOut[i]) << " " << recfileType << std::endl;
    68 		if (recfileType.size()) output << "%type: " << convertor.to_bytes(attribute.getAttributeName()) << " " << recfileType << std::endl;
       
    69 	}
    69 	}
    70 
    70 
    71 	void writeSeparator() {
    71 	void writeSeparator() {
    72 		output << std::endl;
    72 		output << std::endl;
    73 	}
    73 	}
    88 					|| between(ch, L'A', L'Z')
    88 					|| between(ch, L'A', L'Z')
    89 					|| between(ch, L'0', L'9');
    89 					|| between(ch, L'0', L'9');
    90 		}
    90 		}
    91 	}
    91 	}
    92 
    92 
    93 	void writeAttribute(const string_t& name, const TypeId& type, const string_t& value) {
    93 	const string_t escapeAttributeName(const string_t& name) {
       
    94 		std::wstringstream escaped;
       
    95 
    94 		// TODO: multiple escapting mode - including one that is not lossless
    96 		// TODO: multiple escapting mode - including one that is not lossless
    95 		// but allows writing a single '_' inside the name
    97 		// but allows writing a single '_' inside the name
    96 		for (size_t i = 0, limit = name.size(); i < limit; i++) {
    98 		for (size_t i = 0, limit = name.size(); i < limit; i++) {
    97 			wchar_t ch = name[i];
    99 			wchar_t ch = name[i];
    98 			bool valid = isValidNameCharacter(ch, i == 0);
   100 			bool valid = isValidNameCharacter(ch, i == 0);
    99 
   101 
   100 			// Not a lossless round-trip
   102 			// Not a lossless round-trip
   101 			// (maybe we could sacrifice some reserved prefix):
   103 			// (maybe we could sacrifice some reserved prefix):
   102 			if (i == 0 && !valid) output << 'x';
   104 			if (i == 0 && !valid) escaped << 'x';
   103 
   105 
   104 			if (ch == '_') output << "__";
   106 			if (ch == '_') escaped << "__";
   105 			else if (valid) output << convertor.to_bytes(ch);
   107 			else if (valid) escaped << ch;
   106 			else output << '_' << ((uint32_t) ch) << '_';
   108 			else escaped << '_' << ((uint32_t) ch) << '_';
   107 		}
   109 		}
   108 		output << ": ";
   110 
       
   111 		return escaped.str();
       
   112 	}
       
   113 
       
   114 	void writeAttribute(const string_t& escapedName, const TypeId& type, const string_t& value) {
       
   115 		output << convertor.to_bytes(escapedName) << ": ";
   109 
   116 
   110 		for (char ch : convertor.to_bytes(value)) {
   117 		for (char ch : convertor.to_bytes(value)) {
   111 			output << ch;
   118 			output << ch;
   112 			if (ch == '\n') output << "+ ";
   119 			if (ch == '\n') output << "+ ";
   113 		}
   120 		}
   138 		writeRelationName(name);
   145 		writeRelationName(name);
   139 
   146 
   140 		attributeCount = attributes.size();
   147 		attributeCount = attributes.size();
   141 		attributeTypes.resize(attributeCount);
   148 		attributeTypes.resize(attributeCount);
   142 		attributeTypeCodes.resize(attributeCount);
   149 		attributeTypeCodes.resize(attributeCount);
   143 		attributeNames.resize(attributeCount);
   150 		attributeNamesIn.resize(attributeCount);
       
   151 		attributeNamesOut.resize(attributeCount);
   144 		for (int i = 0; i < attributes.size(); i++) {
   152 		for (int i = 0; i < attributes.size(); i++) {
   145 			attributeNames[i] = attributes[i].getAttributeName();
   153 			attributeNamesIn[i] = attributes[i].getAttributeName();
       
   154 			attributeNamesOut[i] = escapeAttributeName(attributeNamesIn[i]);
   146 			attributeTypes[i] = attributes[i].getTypeId();
   155 			attributeTypes[i] = attributes[i].getTypeId();
   147 			attributeTypeCodes[i] = attributes[i].getTypeName();
   156 			attributeTypeCodes[i] = attributes[i].getTypeName();
   148 			writeAttributeMetadata(attributes[i]);
   157 			writeAttributeMetadata(i);
   149 		}
   158 		}
   150 	}
   159 	}
   151 
   160 
   152 	void attribute(const string_t& value) override {
   161 	void attribute(const string_t& value) override {
   153 		integer_t i = valueCount % attributeCount;
   162 		integer_t i = valueCount % attributeCount;
   154 		if (i == 0) writeSeparator();
   163 		if (i == 0) writeSeparator();
   155 		valueCount++;
   164 		valueCount++;
   156 		writeAttribute(attributeNames[i], attributeTypes[i], value);
   165 		writeAttribute(attributeNamesOut[i], attributeTypes[i], value);
   157 	}
   166 	}
   158 
   167 
   159 	void endOfPipe() {
   168 	void endOfPipe() {
   160 		writeRecordCount();
   169 		writeRecordCount();
   161 		if (valueCount) writeSeparator();
   170 		if (valueCount) writeSeparator();