public void exportIntroductionPuzzle(IntroductionPuzzle puzzle, OutputStream os) throws TransformerException, ParserConfigurationException { Document xmlDoc; synchronized ( mDocumentBuilder) { // TODO: Figure out whether the DocumentBuilder is maybe synchronized // anyway xmlDoc = mDOM.createDocument(null, WebOfTrust.WOT_NAME, null); } // 1.0 does not support all Unicode characters which the String class supports. To prevent us // from having to filter all Strings, we use 1.1 xmlDoc.setXmlVersion("1.1"); Element rootElement = xmlDoc.getDocumentElement(); // We include the WoT version to have an easy way of handling bogus XML which might be created // by bugged versions. rootElement.setAttribute("Version", Long.toString(Version.getRealVersion())); Element puzzleElement = xmlDoc.createElement("IntroductionPuzzle"); puzzleElement.setAttribute( "Version", Integer.toString(INTRODUCTION_XML_FORMAT_VERSION)); /* Version of the XML format */ // This lock is actually not necessary because all values which are taken from the puzzle are // final. We leave it here just to make sure that it does // not get lost if it becomes necessary someday. synchronized (puzzle) { puzzleElement.setAttribute("ID", puzzle.getID()); puzzleElement.setAttribute("Type", puzzle.getType().toString()); puzzleElement.setAttribute("MimeType", puzzle.getMimeType()); synchronized (mDateFormat) { puzzleElement.setAttribute("ValidUntil", mDateFormat.format(puzzle.getValidUntilDate())); } Element dataElement = xmlDoc.createElement("Data"); dataElement.setAttribute("Value", Base64.encodeStandard(puzzle.getData())); puzzleElement.appendChild(dataElement); } rootElement.appendChild(puzzleElement); DOMSource domSource = new DOMSource(xmlDoc); StreamResult resultStream = new StreamResult(os); synchronized (mSerializer) { mSerializer.transform(domSource, resultStream); } }
/** * @param xmlInputStream An InputStream which must not return more than {@link * MAX_INTRODUCTIONPUZZLE_BYTE_SIZE} bytes. */ public IntroductionPuzzle importIntroductionPuzzle( FreenetURI puzzleURI, InputStream xmlInputStream) throws SAXException, IOException, InvalidParameterException, UnknownIdentityException, IllegalBase64Exception, ParseException { xmlInputStream = new OneBytePerReadInputStream( xmlInputStream); // Workaround for Java bug, see the stream class for explanation // May not be accurate by definition of available(). So the JavaDoc requires the callers to obey // the size limit, this is a double-check. if (xmlInputStream.available() > MAX_INTRODUCTIONPUZZLE_BYTE_SIZE) throw new IllegalArgumentException( "XML contains too many bytes: " + xmlInputStream.available()); String puzzleID; IntroductionPuzzle.PuzzleType puzzleType; String puzzleMimeType; Date puzzleValidUntilDate; byte[] puzzleData; Document xmlDoc; synchronized ( mDocumentBuilder) { // TODO: Figure out whether the DocumentBuilder is maybe synchronized // anyway xmlDoc = mDocumentBuilder.parse(xmlInputStream); } Element puzzleElement = (Element) xmlDoc.getElementsByTagName("IntroductionPuzzle").item(0); if (Integer.parseInt(puzzleElement.getAttribute("Version")) > INTRODUCTION_XML_FORMAT_VERSION) throw new InvalidParameterException( "Version " + puzzleElement.getAttribute("Version") + " > " + INTRODUCTION_XML_FORMAT_VERSION); puzzleID = puzzleElement.getAttribute("ID"); puzzleType = IntroductionPuzzle.PuzzleType.valueOf(puzzleElement.getAttribute("Type")); puzzleMimeType = puzzleElement.getAttribute("MimeType"); synchronized (mDateFormat) { puzzleValidUntilDate = mDateFormat.parse(puzzleElement.getAttribute("ValidUntil")); } Element dataElement = (Element) puzzleElement.getElementsByTagName("Data").item(0); puzzleData = Base64.decodeStandard(dataElement.getAttribute("Value")); IntroductionPuzzle puzzle; synchronized (mWoT) { Identity puzzleInserter = mWoT.getIdentityByURI(puzzleURI); puzzle = new IntroductionPuzzle( mWoT, puzzleInserter, puzzleID, puzzleType, puzzleMimeType, puzzleData, IntroductionPuzzle.getDateFromRequestURI(puzzleURI), puzzleValidUntilDate, IntroductionPuzzle.getIndexFromRequestURI(puzzleURI)); mWoT.getIntroductionPuzzleStore().storeAndCommit(puzzle); } return puzzle; }