/* This file is part of GNUnet. Copyright (C) 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.gnunet.construct.parsers; import org.gnunet.construct.Message; import org.gnunet.construct.ReflectUtil; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * Parse an array that takes up all the available space. * * @author Florian Dold */ public class FillParser implements Parser { private final Parser elemParser; private final Field targetField; public FillParser(Parser p, Field field) { targetField = field; elemParser = p; } @Override public int getSize(final Message src) { int size = 0; final Object arr = ReflectUtil.justGet(src, targetField); if (arr == null) { throw new RuntimeException("array not initialized"); } for (int i = 0; i < Array.getLength(arr); ++i) { size += elemParser.getSize((Message) Array.get(arr, i)); } return size; } @Override public int parse(ByteBuffer srcBuf, int frameOffset, Message frameObj, final Message dstObj, List frameSizePath) { if (frameSizePath == null) { throw new AssertionError("FillParser expects a non-null frameSizePath. Does the message have a @FrameSizePath annotation?"); } final int frameSize = ReflectUtil.justGetInt(dstObj, frameSizePath); int remaining = frameOffset + frameSize - srcBuf.position(); int size = 0; Class elemType = targetField.getType().getComponentType(); ArrayList list = new ArrayList(10); while (remaining > 0) { @SuppressWarnings("unchecked") Message next = ReflectUtil.justInstantiate((Class) targetField.getType().getComponentType()); int s = elemParser.parse(srcBuf, frameOffset, frameObj, next, null); size += s; remaining -= s; list.add(next); } Object arr = Array.newInstance(elemType, list.size()); try { targetField.set(dstObj, list.toArray((Object[]) arr)); } catch (IllegalAccessException e) { throw new AssertionError("cannot access field"); } return size; } @Override public int write(final ByteBuffer dstBuf, final Message src) { int size = 0; final Object arr = ReflectUtil.justGet(src, targetField); for (int i = 0; i < Array.getLength(arr); ++i) { size += elemParser.write(dstBuf, (Message) Array.get(arr, i)); } return size; } @Override public void patch(Message m, int frameSize, List frameSizePath, Message frameObj) { if (frameSizePath == null) { throw new AssertionError(); } ReflectUtil.justSetInt(frameObj, frameSizePath, frameSize); // todo: patch nested messages } @Override public int getStaticSize() { // not known return 0; } }