String Utf8Codec::decode(const char* data, unsigned size) { Utf8Codec codec; Char to[64]; MBState state; String ret; const char* from = data; result r; do { Char* to_next = to; const char* from_next = from; r = codec.in(state, from, from + size, from_next, to, to + sizeof(to), to_next); if (r == error) throw ConversionError("character conversion failed"); if (r == partial && from_next == from) throw ConversionError("character conversion failed - unexpected end of utf8 sequence"); ret.append(to, to_next); size -= (from_next - from); from = from_next; } while (r == partial); return ret; }
void _allow_value_only(const std::string& type_name) const { if (m_type == Type::SECTION) { throw ConversionError("Can't convert section to " + type_name + "."); } if (m_type == Type::LIST) { throw ConversionError("Can't convert list to " + type_name + "."); } }
std::string Utf8Codec::encode(const Char* data, unsigned size) { Utf8Codec codec; char to[64]; MBState state; result r; const Char* from = data; std::string ret; do{ const Char* from_next; char* to_next = to; r = codec.out(state, from, from + size, from_next, to, to + sizeof(to), to_next); if (r == error) throw ConversionError("character conversion failed"); ret.append(to, to_next); size -= (from_next - from); from = from_next; } while (r == partial); return ret; }
void convert(Date& date, const std::string& s) { if (s.size() < 10 || s.at(4) != '-' || s.at(7) != '-') { throw ConversionError("Illegal date format"); } const char* d = s.data(); date = Date(getNumber4(d), getNumber2(d + 5), getNumber2(d + 8)); }
static wxPoint StringToPoint(const wxString & str) { wxArrayString tokens = wxStringTokenize(str, _T(", "), wxTOKEN_STRTOK); long x, y; if (tokens.size() != 2 || ! (tokens[0].ToLong(&x) && tokens[1].ToLong(&y)) ) { throw ConversionError(); } return wxPoint(x, y); }
String::operator bool() const throw(X::ConversionErrorBase) { if (*this == u"true") return true; else if (*this == u"false") return false; else if (*this == u"1") return true; else if (*this == u"0") return false; else throw ConversionError(typeOf<String>::type, typeOf<bool>::type); }
UniChar::UniChar(const char * utf8) : priv(NULL) { UChar32 cp = 0; /* If it happen to find a zero, terminating character, non of the if branches * will apply, because each requires some non-null value. */ /* http://en.wikipedia.ptrrg/wiki/UTF-8#Description */ if(0x00 == (utf8[0] & 0x80)){ /* 7 bit -> 1 byte to use (ascii code) */ cp = utf8[0]; } else if(0xc0 == (utf8[0] & 0xe0)){ /* 11 bit -> 2 byte to use */ if(!(0x80 == (utf8[1] & 0xc0))) throw ConversionError("Invalid second byte in utf8 sequence: " "%", utf8[1]); cp = utf8[0] & 0x1f; cp <<= 6; cp |= utf8[1] & 0x3f; } else if(0xe0 == (utf8[0] & 0xf0)) { /* 16 bit -> 3 byte to use */ if(!(0x80 == (utf8[1] & 0xc0))) throw ConversionError("Invalid second byte in utf8 sequence: " "%", utf8[1]); if(!(0x80 == (utf8[2] & 0xc0))) throw ConversionError("Invalid third byte in utf8 sequence: " "%", utf8[2]); cp = utf8[0] & 0x0f; cp <<= 6; cp |= utf8[1] & 0x3f; cp <<= 6; cp |= utf8[2] & 0x3f; } else if(0xf0 == (utf8[0] & 0xf8)) { /* 21 bit -> 4 byte to use */ if(!(0x80 == (utf8[1] & 0xc0))) throw ConversionError("Invalid second byte in utf8 sequence: " "%", utf8[1]); if(!(0x80 == (utf8[2] & 0xc0))) throw ConversionError("Invalid third byte in utf8 sequence: " "%", utf8[2]); if(!(0x80 == (utf8[3] & 0xc0))) throw ConversionError("Invalid fourth byte in utf8 sequence: " "%", utf8[3]); cp = utf8[0] & 0x07; cp <<= 6; cp |= utf8[1] & 0x3f; cp <<= 6; cp |= utf8[2] & 0x3f; cp <<= 6; cp |= utf8[3] & 0x3f; } else throw ConversionError("Invalid first byte in utf8 sequence: %", utf8[0]); if(!unicodePointValidity(cp)) throw InvalidArgument("The value '%' (converted from utf8 sequence " "'%%%%'), is not a valid unicode point.", (long unsigned int)cp, utf8[0], utf8[1], utf8[2], utf8[3]); priv = new UniCharPrivate(); priv->val = cp; priv->dirtyUtf8 = true; }
/** Converts this node to true/false, only if it has a single value of 'true' or 'false'. */ bool to_boolean() const { _allow_value_only("boolean"); std::string value = m_content.front(); if (value == "true") { return true; } else if (value == "false") { return false; } else { throw ConversionError("Can't convert this string to boolean, it's neither 'true' nor 'false'."); } }
/** * Converts this node to string if it's not a section. * List values are converted to multi-line text. */ std::string to_string() const { if (m_type == Type::SECTION) { throw ConversionError("Can't convert section to string."); } if (m_type == Type::VALUE) { return m_content.front(); } else { std::stringstream buffer; for (const std::string& line : m_content) { buffer << line << " \n"; } return buffer.str(); } }
void ConversionError::doThrow(const std::string& argname, unsigned argnum, const char* typeto, const std::string& value) { std::ostringstream msg; msg << "Cannot convert \"'" << value << '"'; if (typeto) msg << " to <" << typeto << '>'; if (!argname.empty()) { msg << " for argument \"" << argname; if (argnum > 0) msg << '[' << argnum << ']'; msg << '"'; } else if (argnum > 0) { msg << " for argument " << argnum; } throw ConversionError(msg.str()); }
//----------------------------------------------------------------------------- // SaveXPF //----------------------------------------------------------------------------- void SaveXPF(Puzzle * puz, const std::string & filename, void * /* dummy */) { const Grid & grid = puz->GetGrid(); if (grid.IsScrambled()) throw ConversionError("XPF does not support scrambled puzzles"); if (! grid.HasSolution()) throw ConversionError("XPF does not support puzzles without a solution"); for (const Square * square = puz->GetGrid().First(); square != NULL; square = square->Next()) { if (square->HasImage()) throw ConversionError("XPF does not support puzzles with background images."); } xml::document doc; xml::node puzzles = doc.append_child("Puzzles"); puzzles.append_attribute("Version") = "1.0"; xml::node puzzle = puzzles.append_child("Puzzle"); // Metadata puz::Puzzle::metamap_t & meta = puz->GetMetadata(); puz::Puzzle::metamap_t::iterator it; for (it = meta.begin(); it != meta.end(); ++it) { if (it->first == puzT("notes")) // "notes" -> "Notepad" xml::Append(puzzle, "Notepad", it->second); else xml::Append(puzzle, xml::CamelCase(it->first).c_str(), it->second); } // Grid if (grid.GetType() == TYPE_DIAGRAMLESS) xml::Append(puzzle, "Type", "diagramless"); // Grid Size xml::node size = puzzle.append_child("Size"); xml::Append(size, "Rows", puz::ToString(grid.GetHeight())); xml::Append(size, "Cols", puz::ToString(grid.GetWidth())); // Answers { xml::node grid_node = puzzle.append_child("Grid"); xml::node row; std::string row_text; row_text.reserve(grid.GetWidth()); const Square * square; for (square = grid.First(); square; square = square->Next()) { if (square->IsFirst(ACROSS)) row = grid_node.append_child("Row"); if (square->IsMissing()) row_text.append(1, '~'); else if (square->IsBlack()) row_text.append(1, char(Square::Black[0])); else if (square->IsSolutionBlank()) row_text.append(1, ' '); else row_text.append(1, square->GetPlainSolution()); if (square->IsLast(ACROSS)) { xml::SetText(row, row_text.c_str()); row_text.clear(); } } } // Circles { xml::node circles = puzzle.append_child("Circles"); const Square * square; for (square = grid.First(); square; square = square->Next()) { if (square->HasCircle()) { xml::node circle = circles.append_child("Circle"); circle.append_attribute("Row") = square->GetRow() + 1; circle.append_attribute("Col") = square->GetCol() + 1; } } if (circles.empty()) puzzle.remove_child(circles); } // Rebus { xml::node rebus = puzzle.append_child("RebusEntries"); const Square * square; for (square = grid.First(); square; square = square->Next()) { if (square->HasSolutionRebus()) { xml::node entry = rebus.append_child("Rebus"); entry.append_attribute("Row") = square->GetRow() + 1; entry.append_attribute("Col") = square->GetCol() + 1; entry.append_attribute("Short") = std::string(1, square->GetPlainSolution()).c_str(); xml::SetText(entry, square->GetSolution()); } } if (rebus.empty()) puzzle.remove_child(rebus); } // Shades { xml::node shades = puzzle.append_child("Shades"); const Square * square; for (square = grid.First(); square; square = square->Next()) { if (square->HasColor()) { xml::node shade = shades.append_child("Shade"); shade.append_attribute("Row") = square->GetRow() + 1; shade.append_attribute("Col") = square->GetCol() + 1; if (square->HasHighlight()) xml::SetText(shade, "gray"); else xml::SetText(shade, square->GetHtmlColor()); } } if (shades.empty()) puzzle.remove_child(shades); } // Clues { xml::node clues_node = puzzle.append_child("Clues"); Clues & clues = puz->GetClues(); Clues::iterator clues_it; for (clues_it = clues.begin(); clues_it != clues.end(); ++clues_it) { ClueList & cluelist = clues_it->second; ClueList::iterator it; for (it = cluelist.begin(); it != cluelist.end(); ++it) { xml::node clue = clues_node.append_child("Clue"); // Find the clue direction if (! puz->IsDiagramless()) { const Word & word = it->GetWord(); switch (word.GetDirection()) { case ACROSS: clue.append_attribute("Dir") = "Across"; break; case DOWN: clue.append_attribute("Dir") = "Down"; break; case DIAGONAL_SW: clue.append_attribute("Dir") = "Diagonal"; break; default: throw ConversionError("XPF clues must be Across, Down, or Diagonal"); break; } clue.append_attribute("Row") = word.front()->GetRow() + 1; clue.append_attribute("Col") = word.front()->GetCol() + 1; } else // diagramless { puz::string_t title = cluelist.GetTitle(); if (title == puzT("Across")) clue.append_attribute("Dir") = "Across"; else if (title == puzT("Down")) clue.append_attribute("Dir") = "Down"; else if (title == puzT("Diagonal")) clue.append_attribute("Dir") = "Diagonal"; else throw ConversionError("XPF clues must be Across, Down, or Diagonal"); } clue.append_attribute("Num") = encode_utf8(it->GetNumber()).c_str(); // Clue formatting needs to be escaped if it is XHTML. // xml::SetInnerXML(clue, it->GetText()); xml::SetText(clue, it->GetText()); } } } // User Grid { xml::node usergrid = puzzle.append_child("UserGrid"); xml::node row; std::string row_text; row_text.reserve(grid.GetWidth()); const Square * square; for (square = grid.First(); square; square = square->Next()) { if (square->IsFirst(ACROSS)) row = usergrid.append_child("Row"); if (square->IsMissing()) row_text.append(1, '~'); else if (square->IsBlack()) row_text.append(1, char(Square::Black[0])); else if (square->IsBlank()) row_text.append(1, ' '); else row_text.append(1, square->GetPlainText()); if (square->IsLast(ACROSS)) { xml::SetText(row, row_text.c_str()); row_text.clear(); } } if (usergrid.empty()) puzzle.remove_child(usergrid); } // User Rebus { xml::node rebus = puzzle.append_child("UserRebusEntries"); const Square * square; for (square = grid.First(); square; square = square->Next()) { if (square->HasTextRebus()) { xml::node entry = rebus.append_child("Rebus"); entry.append_attribute("Row") = square->GetRow() + 1; entry.append_attribute("Col") = square->GetCol() + 1; entry.append_attribute("Short") = std::string(1, square->GetPlainText()).c_str(); xml::SetText(entry, square->GetText()); } } if (rebus.empty()) puzzle.remove_child(rebus); } // Square Flags { xml::node flags = puzzle.append_child("SquareFlags"); const Square * square; for (square = grid.First(); square; square = square->Next()) { if (square->GetFlag() != 0) { xml::node entry = flags.append_child("Flag"); entry.append_attribute("Row") = square->GetRow() + 1; entry.append_attribute("Col") = square->GetCol() + 1; if (square->HasFlag(FLAG_PENCIL)) entry.append_attribute("Pencil") = "true"; if (square->HasFlag(FLAG_BLACK)) entry.append_attribute("Checked") = "true"; if (square->HasFlag(FLAG_REVEALED)) entry.append_attribute("Revealed") = "true"; if (square->HasFlag(FLAG_X)) entry.append_attribute("Incorrect") = "true"; if (square->HasFlag(FLAG_CORRECT)) entry.append_attribute("Correct") = "true"; } } if (flags.empty()) puzzle.remove_child(flags); } // Timer { if (puz->GetTime() != 0) { xml::node timer = puzzle.append_child("Timer"); timer.append_attribute("Seconds") = puz->GetTime(); if (puz->IsTimerRunning()) timer.append_attribute("Running") = "true"; } } doc.save_file(filename.c_str()); }