/******************************************************************************* * Copyright (c) 2015 IBH SYSTEMS GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBH SYSTEMS GmbH - initial API and implementation *******************************************************************************/ package org.eclipse.packagedrone.utils.rpm; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.function.Function; public class RpmEntry { private static final class Unknown { @Override public String toString () { return "UNKNOWN"; } } public static final Unknown UNKNOWN = new Unknown (); private final int tag; private Object value; private final int type; private final int index; private final int count; public RpmEntry ( final int tag, final int type, final int index, final int count ) { this.tag = tag; this.type = type; this.index = index; this.count = count; } public int getTag () { return this.tag; } public Object getValue () { return this.value; } void fillFromStore ( final ByteBuffer storeData ) throws IOException { switch ( this.type ) { case 0: // null value break; case 1: // character this.value = getFromStore ( storeData, buf -> (char)storeData.get (), size -> new Character[size] ); break; case 2: // byte this.value = getFromStore ( storeData, buf -> buf.get (), size -> new Byte[size] ); break; case 3: // unsigned 16bit integer this.value = getFromStore ( storeData, buf -> buf.getShort () & 0xFFFF, size -> new Integer[size] ); break; case 4: // unsigned 32bit integer this.value = getFromStore ( storeData, buf -> (long) ( buf.getInt () & 0xFFFFFFFFL ), size -> new Long[size] ); break; case 5: // unsigned 64bit integer this.value = getFromStore ( storeData, buf -> buf.getLong (), size -> new Long[size] ); break; case 6: // one string { // only one allowed storeData.position ( this.index ); this.value = makeString ( storeData ); } break; case 7: // blob { final byte[] data = new byte[this.count]; storeData.get ( data ); this.value = data; } break; case 8: // string array this.value = getFromStore ( storeData, buf -> makeString ( buf ), size -> new String[size] ); break; case 9: // i18n string array this.value = getFromStore ( storeData, buf -> makeString ( buf ), size -> new String[size] ); break; default: this.value = UNKNOWN; break; } } @FunctionalInterface public static interface IOFunction<T, R> { public R apply ( T t ) throws IOException; } private <R> Object getFromStore ( final ByteBuffer data, final IOFunction<ByteBuffer, R> func, final Function<Integer, R[]> creator ) throws IOException { data.position ( this.index ); if ( this.count == 1 ) { return func.apply ( data ); } final R[] result = creator.apply ( this.count ); for ( int i = 0; i < this.count; i++ ) { result[i] = func.apply ( data ); } return result; } private static String makeString ( final ByteBuffer buf ) throws IOException { final byte[] data = buf.array (); final int start = buf.position (); for ( int i = 0; i < buf.remaining (); i++ ) // check if there is at least one more byte, null byte { if ( data[start + i] == 0 ) { buf.position ( start + i + 1 ); // skip content plus null byte return new String ( data, start, i, StandardCharsets.UTF_8 ); } } throw new IOException ( "Corrupt tag entry. Null byte missing!" ); } @Override public String toString () { final StringBuilder sb = new StringBuilder (); sb.append ( '[' ); sb.append ( this.tag ); sb.append ( " = " ); Rpms.dumpValue ( sb, this.value ); if ( this.value != null ) { if ( this.value != UNKNOWN ) { sb.append ( " - " ).append ( this.value.getClass ().getName () ); } else { sb.append ( " - " ).append ( this.type ); } } else { sb.append ( "NULL" ); } sb.append ( " | " ); sb.append ( this.count ); sb.append ( ']' ); return sb.toString (); } }