/*
 * Copyright (c) 2002, The EROS Group, LLC and Johns Hopkins
 * University. All rights reserved.
 * 
 * This software was developed to support the EROS secure operating
 * system project (http://www.eros-os.org). The latest version of
 * the OpenCM software can be found at http://www.opencm.org.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 * 
 * 3. Neither the name of the The EROS Group, LLC nor the name of
 *    Johns Hopkins University, nor the names of its contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <opencm.h>

void
ebits_show(const void *ob)
{
  const EntityBits *eb = ob;
  
  report(0, "<ebits for %s>\n", ser_getTrueName(eb));
}

void
ebits_serialize(SDR_stream *strm, const void *ob)
{
  const EntityBits *eb = ob;
  
  sdr_w_u64("len", strm, eb->length);
  sdr_w_bytes("bits", strm, eb->length, eb->content);
}

void *
ebits_deserialize(SDR_stream *strm)
{
  EntityBits *eb = (EntityBits *) GC_MALLOC(sizeof(EntityBits));

  eb->serType        = &EntityBits_SerType;
  SER_MODIFIED(eb);

  eb->length  = sdr_r_u64("len", strm);
  eb->content = (char *) sdr_r_bytes("bits", strm, eb->length);
  return eb;
}

EntityBits *
ebits_create(void)
{
  EntityBits *eb = (EntityBits *) GC_MALLOC(sizeof(EntityBits));

  eb->serType = &EntityBits_SerType;
  SER_MODIFIED(eb);
  
  eb->content = 0;
  eb->length = 0;

  return eb;
}

EntityBits *
ebits_FromStream(SDR_stream *s, unsigned char eType)
{
  EntityBits *eb = ebits_create();
  char *buf;
  stream_reread(s);
  eb->length = stream_length(s);

  buf = GC_MALLOC_ATOMIC(eb->length);
  stream_read(s, buf, eb->length);
  eb->content = buf;

  SER_MODIFIED(eb);
  return eb;
}
    
EntityBits *
ebits_ReadFrom(const char *fileName, unsigned char eType)
{
  FILE *f = NULL;
  char *buf;
  EntityBits *eb = (EntityBits *) GC_MALLOC(sizeof(EntityBits));

  /* For the moment, we only handle text or binary content. No
     symlinks or directories yet... */
  assert(eType == 'T' || eType == 'B');
  
  eb->serType = &EntityBits_SerType;
  SER_MODIFIED(eb);
  
  eb->content = 0;

  eb->length = path_file_length(fileName);

  buf = (char *) GC_MALLOC_ATOMIC(sizeof(char) * (eb->length + 1));
  buf[eb->length] = 0;

  TRY {
    f = xfopen(fileName, (eType == 'T') ? "rt" : "rb");
  
    if (eb->length && (fread(buf, 1, eb->length, f) < eb->length))
      THROW(ExTruncated, format("Could not read all of \"%s\"",
				fileName));

    xfclose(f);
  }
  DEFAULT(ex) {
    xfclose(f);
    RETHROW(ex);
  }
  END_CATCH;

  eb->content = buf;

  return eb;
}

void
ebits_WriteTo(const EntityBits *eb, const char *fileName, unsigned char eType)
{
  FILE *f = NULL;
  char *dir;
  char *slash;
  
  /* For the moment, we only handle text or binary content. No
     symlinks or directories yet... */
  assert(eType == 'T' || eType == 'B');
  
  dir = xstrdup(fileName);
  slash = strrchr(dir, '/');
  if (slash) {
    *slash = 0;
    path_smkdir(dir);
  }
			
  TRY {
    f = xfopen(fileName, (eType == 'T') ? "wt" : "wb");

    if (eb->length && (fwrite(eb->content, 1, eb->length, f) < eb->length))
      THROW(ExTruncated, 
	    format("Could not read all of \"%s\".\n",
		   fileName));

    xfclose(f);
  }
  DEFAULT(ex) {
    xfclose(f);
    RETHROW(ex);
  }
  END_CATCH;
}
