/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;

public abstract class WrappedOutput {
 public static final int HDRSIZE     = Proto.HEADER_SIZE;
 public static final int BUFSIZE     = Proto.BUFFER_SIZE-HDRSIZE;

 private byte buf[];
 private int pos;

 private int type;
 private boolean nosize;

 public WrappedOutput() {
  buf=new byte[BUFSIZE];
  type=-1;
  nosize=false;
  reset();
 }

 public void reset() {
  pos=0;

  if (type>=0) buf[pos++]=(byte)type;
 }

 public int size() {
  return pos;
 }

 public void set_data_type(int t) {
  type=t;
  reset();
 }

 public void no_size() {
  nosize=true;
 }

 public void with_size() {
  nosize=false;
 }

 public abstract void put_byte(int val) throws Throwable;

 public void write_byte(int val) throws Throwable {
  if (pos==BUFSIZE) {
   flush();
  }

  buf[pos++]=(byte)val;
 }

 public void write_boolean(boolean val) throws Throwable {
  if (val) write_byte(1);
   else write_byte(0);
 }

 public void write_short(int val) throws Throwable {
  write_byte((val>>>8)&0xFF);
  write_byte((val>>>0)&0xFF);
 }

 public void write_int(int val) throws Throwable {
  write_byte((val>>>24)&0xFF);
  write_byte((val>>>16)&0xFF);
  write_byte((val>>>8)&0xFF);
  write_byte((val>>>0)&0xFF);
 }

 public void write_string(String str) throws Throwable {
  if (str==null) {
   write_int(-1);
   return;  
  }

  int len=str.length();
  int i;

  write_int(len);

  for(i=0;i<len;i++) {
   write_byte((int)str.charAt(i));
  }
 }

 public void write_buf(byte[] b) throws Throwable {
  write_int(b.length);
  for(int i=0;i<b.length;i++) {
   write_byte((int)b[i]);
  }
 }

 public void write_buf(byte[] b,int size) throws Throwable {
  write_int(size);
  for(int i=0;i<size;i++) {
   write_byte((int)b[i]);
  }
 }

 public synchronized void flush() throws Throwable {
  int size=size();

  if (size>0) {
   if (!nosize) {
    size=(size-1)*Mangle.CHAR_SIZE;

    put_byte((size>>8)&0xff);
    put_byte(size&0xff);
   }

   for(int i=0;i<size();i++) {
    put_byte(buf[i]);
   }

   reset();
  }
 }

}
