Fix data block length when uncompressing TNG data.
[alexxy/gromacs.git] / src / external / tng_io / src / lib / tng_io.c
1 /* This code is part of the tng binary trajectory format.
2  *
3  * Written by Magnus Lundborg
4  * Copyright (c) 2012-2014, The GROMACS development team.
5  * Check out http://www.gromacs.org for more information.
6  *
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the Revised BSD License.
10  */
11
12 #define _FILE_OFFSET_BITS 64
13 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
14 #define _LARGEFILE_SOURCE
15 /* Define for large files, on AIX-style hosts. */
16 #define _LARGE_FILES
17
18 #include "tng/tng_io.h"
19
20 #ifdef USE_STD_INTTYPES_H
21 #include <inttypes.h>
22 #endif
23
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <math.h>
29 #ifdef USE_ZLIB
30 #include <zlib.h>
31 #endif
32
33 #include "tng/md5.h"
34 #include "compression/tng_compress.h"
35 #include "tng/version.h"
36
37 #ifdef _MSC_VER
38 #define fseeko _fseeki64
39 #define ftello _ftelli64
40 #endif
41
42 struct tng_bond {
43     /** One of the atoms of the bond */
44     int64_t from_atom_id;
45     /** The other atom of the bond */
46     int64_t to_atom_id;
47 };
48
49 struct tng_atom {
50     /** The residue containing this atom */
51     tng_residue_t residue;
52     /** A unique (per molecule) ID number of the atom */
53     int64_t id;
54     /** The atom_type (depending on the forcefield) */
55     char *atom_type;
56     /** The name of the atom */
57     char *name;
58 };
59
60 struct tng_residue {
61     /** The chain containing this residue */
62     tng_chain_t chain;
63     /** A unique (per chain) ID number of the residue */
64     int64_t id;
65     /** The name of the residue */
66     char *name;
67     /** The number of atoms in the residue */
68     int64_t n_atoms;
69     /** A list of atoms in the residue */
70     int64_t atoms_offset;
71 };
72
73 struct tng_chain {
74     /** The molecule containing this chain */
75     tng_molecule_t molecule;
76     /** A unique (per molecule) ID number of the chain */
77     int64_t id;
78     /** The name of the chain */
79     char *name;
80     /** The number of residues in the chain */
81     int64_t n_residues;
82     /** A list of residues in the chain */
83     tng_residue_t residues;
84 };
85
86 struct tng_molecule {
87     /** A unique ID number of the molecule */
88     int64_t id;
89     /** Quaternary structure of the molecule.
90      *  1 => monomeric
91      *  2 => dimeric
92      *  3 => trimeric
93      *  etc */
94     int64_t quaternary_str;
95     /** The number of chains in the molecule */
96     int64_t n_chains;
97     /** The number of residues in the molecule */
98     int64_t n_residues;
99     /** The number of atoms in the molecule */
100     int64_t n_atoms;
101     /** The number of bonds in the molecule. If the bonds are not specified this
102      * value can be 0. */
103     int64_t n_bonds;
104     /** The name of the molecule */
105     char *name;
106     /** A list of chains in the molecule */
107     tng_chain_t chains;
108     /** A list of residues in the molecule */
109     tng_residue_t residues;
110     /** A list of the atoms in the molecule */
111     tng_atom_t atoms;
112     /** A list of the bonds in the molecule */
113     tng_bond_t bonds;
114 };
115
116 struct tng_gen_block {
117     /** The size of the block header in bytes */
118     int64_t header_contents_size;
119     /** The size of the block contents in bytes */
120     int64_t block_contents_size;
121     /** The ID of the block to determine its type */
122     int64_t id;
123     /** The MD5 hash of the block to verify integrity */
124     char md5_hash[TNG_MD5_HASH_LEN];
125     /** The name of the block */
126     char *name;
127     /** The library version used to write the block */
128     int64_t block_version;
129     int64_t alt_hash_type;
130     int64_t alt_hash_len;
131     char *alt_hash;
132     int64_t signature_type;
133     int64_t signature_len;
134     char *signature;
135     /** The full block header contents */
136     char *header_contents;
137     /** The full block contents */
138     char *block_contents;
139 };
140
141 struct tng_particle_mapping {
142     /** The index number of the first particle in this mapping block */
143     int64_t num_first_particle;
144     /** The number of particles list in this mapping block */
145     int64_t n_particles;
146     /** the mapping of index numbers to the real particle numbers in the
147      * trajectory. real_particle_numbers[0] is the real particle number
148      * (as it is numbered in the molecular system) of the first particle
149      * in the data blocks covered by this particle mapping block */
150     int64_t *real_particle_numbers;
151 };
152
153 struct tng_trajectory_frame_set {
154     /** The number of different particle mapping blocks present. */
155     int64_t n_mapping_blocks;
156     /** The atom mappings of this frame set */
157     struct tng_particle_mapping *mappings;
158     /** The first frame of this frame set */
159     int64_t first_frame;
160     /** The number of frames in this frame set */
161     int64_t n_frames;
162     /** The number of written frames in this frame set (used when writing one
163      * frame at a time). */
164     int64_t n_written_frames;
165     /** The number of frames not yet written to file in this frame set
166      * (used from the utility functions to finish the writing properly. */
167     int64_t n_unwritten_frames;
168
169
170     /** A list of the number of each molecule type - only used when using
171      * variable number of atoms */
172     int64_t *molecule_cnt_list;
173     /** The number of particles/atoms - only used when using variable number
174      * of atoms */
175     int64_t n_particles;
176     /** The file position of the next frame set */
177     int64_t next_frame_set_file_pos;
178     /** The file position of the previous frame set */
179     int64_t prev_frame_set_file_pos;
180     /** The file position of the frame set one long stride step ahead */
181     int64_t medium_stride_next_frame_set_file_pos;
182     /** The file position of the frame set one long stride step behind */
183     int64_t medium_stride_prev_frame_set_file_pos;
184     /** The file position of the frame set one long stride step ahead */
185     int64_t long_stride_next_frame_set_file_pos;
186     /** The file position of the frame set one long stride step behind */
187     int64_t long_stride_prev_frame_set_file_pos;
188     /** Time stamp (in seconds) of first frame in frame set */
189     double first_frame_time;
190
191     /* The data blocks in a frame set are trajectory data blocks */
192     /** The number of trajectory data blocks of particle dependent data */
193     int n_particle_data_blocks;
194     /** A list of data blocks containing particle dependent data */
195     struct tng_particle_data *tr_particle_data;
196     /** The number of trajectory data blocks independent of particles */
197     int n_data_blocks;
198     /** A list of data blocks containing particle indepdendent data */
199     struct tng_non_particle_data *tr_data;
200 };
201
202 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
203 /* FIXME: Make only one data block struct */
204 struct tng_particle_data {
205     /** The block ID of the data block containing this particle data.
206      *  This is used to determine the kind of data that is stored */
207     int64_t block_id;
208     /** The name of the data block. This is used to determine the kind of
209      *  data that is stored */
210     char *block_name;
211     /** The type of data stored. */
212     char datatype;
213     /** The frame number of the first data value */
214     int64_t first_frame_with_data;
215     /** The number of frames in this frame set */
216     int64_t n_frames;
217     /** The number of values stored per frame */
218     int64_t n_values_per_frame;
219     /** The number of frames between each data point - e.g. when
220      *  storing sparse data. */
221     int64_t stride_length;
222     /** ID of the CODEC used for compression 0 == no compression. */
223     int64_t codec_id;
224     /** If reading one frame at a time this is the last read frame */
225     int64_t last_retrieved_frame;
226     /** The multiplier used for getting integer values for compression */
227     double compression_multiplier;
228     /** A 1-dimensional array of values of length
229      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
230     void *values;
231     /** If storing character data store it in a 3-dimensional array */
232     char ****strings;
233 };
234
235 struct tng_non_particle_data {
236     /** The ID of the data block */
237     int64_t block_id;
238     /** The name of the data block. This is used to determine the kind of
239      *  data that is stored */
240     char *block_name;
241     /** The type of data stored. */
242     char datatype;
243     /** The first frame number of the first data value */
244     int64_t first_frame_with_data;
245     /** The number of frames in this data block */
246     int64_t n_frames;
247     /** The number of values stored per frame */
248     int64_t n_values_per_frame;
249     /** The number of frames between each data value, e.g. if storing data
250      *  that is not saved every frame. */
251     int64_t stride_length;
252     /** ID of the CODEC used for compression. 0 == no compression. */
253     int64_t codec_id;
254     /** If reading one frame at a time this is the last read frame */
255     int64_t last_retrieved_frame;
256     /** Compressed data is stored as integers. This compression multiplier is
257      *  the multiplication factor to convert from integer to float/double */
258     double compression_multiplier;
259     /** A 1-dimensional array of values of length
260      *  [sizeof (datatype)] * n_frames * n_values_per_frame */
261     void *values;
262     /** If storing character data store it in a 2-dimensional array */
263     char ***strings;
264 };
265
266
267
268 struct tng_trajectory {
269     /** The path of the input trajectory file */
270     char *input_file_path;
271     /** A handle to the input file */
272     FILE *input_file;
273     /** The length of the input file */
274     int64_t input_file_len;
275     /** The path of the output trajectory file */
276     char *output_file_path;
277     /** A handle to the output file */
278     FILE *output_file;
279     /** Function to swap 32 bit values to and from the endianness of the
280      * input file */
281     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
282     /** Function to swap 64 bit values to and from the endianness of the
283      * input file */
284     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
285     /** Function to swap 32 bit values to and from the endianness of the
286      * input file */
287     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
288     /** Function to swap 64 bit values to and from the endianness of the
289      * input file */
290     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
291     /** The endianness of 32 bit values of the current computer */
292     char endianness_32;
293     /** The endianness of 64 bit values of the current computer */
294     char endianness_64;
295
296     /** The name of the program producing this trajectory */
297     char *first_program_name;
298     /** The forcefield used in the simulations */
299     char *forcefield_name;
300     /** The name of the user running the simulations */
301     char *first_user_name;
302     /** The name of the computer on which the simulations were performed */
303     char *first_computer_name;
304     /** The PGP signature of the user creating the file. */
305     char *first_pgp_signature;
306     /** The name of the program used when making last modifications to the
307      *  file */
308     char *last_program_name;
309     /** The name of the user making the last modifications to the file */
310     char *last_user_name;
311     /** The name of the computer on which the last modifications were made */
312     char *last_computer_name;
313     /** The PGP signature of the user making the last modifications to the
314      *  file. */
315     char *last_pgp_signature;
316     /** The time (n seconds since 1970) when the file was created */
317     int64_t time;
318     /** The exponential of the value of the distance unit used. The default
319      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
320      * the measurements are in Ã… the distance_unit_exponential = -10. */
321     int64_t distance_unit_exponential;
322
323     /** A flag indicating if the number of atoms can vary throughout the
324      *  simulation, e.g. using a grand canonical ensemble */
325     char var_num_atoms_flag;
326     /** The number of frames in a frame set. It is allowed to have frame sets
327      *  with fewer frames, but this will help searching for specific frames */
328     int64_t frame_set_n_frames;
329     /** The number of frame sets in a medium stride step */
330     int64_t medium_stride_length;
331     /** The number of frame sets in a long stride step */
332     int64_t long_stride_length;
333     /** The current (can change from one frame set to another) time length
334      *  (in seconds) of one frame */
335     double time_per_frame;
336
337     /** The number of different kinds of molecules in the trajectory */
338     int64_t n_molecules;
339     /** A list of molecules in the trajectory */
340     tng_molecule_t molecules;
341     /** A list of the count of each molecule - if using variable number of
342      *  particles this will be specified in each frame set */
343     int64_t *molecule_cnt_list;
344     /** The total number of particles/atoms. If using variable number of
345      *  particles this will be specified in each frame set */
346     int64_t n_particles;
347
348      /** The pos in the src file of the first frame set */
349     int64_t first_trajectory_frame_set_input_file_pos;
350     /** The pos in the dest file of the first frame set */
351     int64_t first_trajectory_frame_set_output_file_pos;
352     /** The pos in the src file of the last frame set */
353     int64_t last_trajectory_frame_set_input_file_pos;
354     /** The pos in the dest file of the last frame set */
355     int64_t last_trajectory_frame_set_output_file_pos;
356     /** The currently active frame set */
357     struct tng_trajectory_frame_set current_trajectory_frame_set;
358     /** The pos in the src file of the current frame set */
359     int64_t current_trajectory_frame_set_input_file_pos;
360     /** The pos in the dest file of the current frame set */
361     int64_t current_trajectory_frame_set_output_file_pos;
362     /** The number of frame sets in the trajectory N.B. Not saved in file and
363      *  cannot be trusted to be up-to-date */
364     int64_t n_trajectory_frame_sets;
365
366     /* These data blocks are non-trajectory data blocks */
367     /** The number of non-frame dependent particle dependent data blocks */
368     int n_particle_data_blocks;
369     /** A list of data blocks containing particle dependent data */
370     struct tng_particle_data *non_tr_particle_data;
371
372     /** The number of frame and particle independent data blocks */
373     int n_data_blocks;
374     /** A list of frame and particle indepdendent data blocks */
375     struct tng_non_particle_data *non_tr_data;
376
377     /** TNG compression algorithm for compressing positions */
378     int *compress_algo_pos;
379     /** TNG compression algorithm for compressing velocities */
380     int *compress_algo_vel;
381     /** The precision used for lossy compression */
382     double compression_precision;
383 };
384
385 #ifndef USE_WINDOWS
386 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
387 #define USE_WINDOWS
388 #endif /* win32... */
389 #endif /* not defined USE_WINDOWS */
390
391 #ifdef USE_WINDOWS
392 #define TNG_INLINE __inline
393 #define TNG_SNPRINTF _snprintf
394 #else
395 #define TNG_INLINE inline
396 #define TNG_SNPRINTF snprintf
397 #endif
398
399 static TNG_INLINE int tng_min_i(int a, int b)
400 {
401     return (a < b ? a : b);
402 }
403
404 /*
405 static TNG_INLINE int tng_max_i(int a, int b)
406 {
407     return (a > b ? a : b);
408 }
409 */
410 static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
411 {
412     return (a < b ? a : b);
413 }
414
415 static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
416 {
417     return (a > b ? a : b);
418 }
419
420 /*
421 static TNG_INLINE float tng_min_f(float a, float b)
422 {
423     return (a < b ? a : b);
424 }
425
426 static TNG_INLINE float tng_max_f(float a, float b)
427 {
428     return (a > b ? a : b);
429 }
430
431 static TNG_INLINE double tng_min_d(double a, double b)
432 {
433     return (a < b ? a : b);
434 }
435
436 static TNG_INLINE double tng_max_d(double a, double b)
437 {
438     return (a > b ? a : b);
439 }
440 */
441
442 /** This function swaps the byte order of a 32 bit numerical variable
443  * to big endian.
444  * It does not only work with integer, but e.g. floats need casting.
445  * If the byte order is already big endian no change is needed.
446  * @param tng_data is a trajectory data container.
447  * @param v is a pointer to a 32 bit numerical value (float or integer).
448  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
449  * byte order is not recognised.
450  */
451 static tng_function_status tng_swap_byte_order_big_endian_32
452                 (const tng_trajectory_t tng_data, int32_t *v)
453 {
454     switch(tng_data->endianness_32)
455     {
456     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
457         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
458              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
459              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
460              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
461
462         return(TNG_SUCCESS);
463
464     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
465         *v = ((*v & 0xFFFF0000) >> 16) |
466              ((*v & 0x0000FFFF) << 16);
467
468         return(TNG_SUCCESS);
469
470     case TNG_BIG_ENDIAN_32: /* Already correct */
471         return(TNG_SUCCESS);
472
473     default:
474         return(TNG_FAILURE);
475     }
476 }
477
478 /** This function swaps the byte order of a 64 bit numerical variable
479  * to big endian.
480  * It does not only work with integer, but e.g. floats need casting.
481  * The byte order swapping routine can convert four different byte
482  * orders to big endian.
483  * If the byte order is already big endian no change is needed.
484  * @param tng_data is a trajectory data container.
485  * @param v is a pointer to a 64 bit numerical value (double or integer).
486  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
487  * byte order is not recognised.
488  */
489 static tng_function_status tng_swap_byte_order_big_endian_64
490                 (const tng_trajectory_t tng_data, int64_t *v)
491 {
492     switch(tng_data->endianness_64)
493     {
494     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
495         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
496              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
497              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
498              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
499              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
500              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
501              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
502              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
503
504         return(TNG_SUCCESS);
505
506     case TNG_QUAD_SWAP_64: /* Byte quad swap */
507         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
508              ((*v & 0x00000000FFFFFFFFLL) << 32);
509
510         return(TNG_SUCCESS);
511
512     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
513         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
514              ((*v & 0x0000FFFF0000FFFFLL) << 16);
515
516         return(TNG_SUCCESS);
517
518     case TNG_BYTE_SWAP_64: /* Byte swap */
519         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
520              ((*v & 0x00FF00FF00FF00FFLL) << 8);
521
522         return(TNG_SUCCESS);
523
524     case TNG_BIG_ENDIAN_64: /* Already correct */
525         return(TNG_SUCCESS);
526
527     default:
528         return(TNG_FAILURE);
529     }
530 }
531
532 /** This function swaps the byte order of a 32 bit numerical variable
533  * to little endian.
534  * It does not only work with integer, but e.g. floats need casting.
535  * If the byte order is already little endian no change is needed.
536  * @param tng_data is a trajectory data container.
537  * @param v is a pointer to a 32 bit numerical value (float or integer).
538  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
539  * byte order is not recognised.
540  */
541 static tng_function_status tng_swap_byte_order_little_endian_32
542                 (const tng_trajectory_t tng_data, int32_t *v)
543 {
544     switch(tng_data->endianness_32)
545     {
546     case TNG_LITTLE_ENDIAN_32: /* Already correct */
547         return(TNG_SUCCESS);
548
549     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
550         *v = ((*v & 0xFF00FF00) >> 8) |
551              ((*v & 0x00FF00FF) << 8);
552
553         return(TNG_SUCCESS);
554
555     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
556         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
557              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
558              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
559              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
560
561         return(TNG_SUCCESS);
562
563     default:
564         return(TNG_FAILURE);
565     }
566 }
567
568 /** This function swaps the byte order of a 64 bit numerical variable
569  * to little endian.
570  * It does not only work with integer, but e.g. floats need casting.
571  * The byte order swapping routine can convert four different byte
572  * orders to little endian.
573  * If the byte order is already little endian no change is needed.
574  * @param tng_data is a trajectory data container.
575  * @param v is a pointer to a 64 bit numerical value (double or integer).
576  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
577  * byte order is not recognised.
578  */
579 static tng_function_status tng_swap_byte_order_little_endian_64
580                 (const tng_trajectory_t tng_data, int64_t *v)
581 {
582     switch(tng_data->endianness_64)
583     {
584     case TNG_LITTLE_ENDIAN_64: /* Already correct */
585         return(TNG_SUCCESS);
586
587     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
588         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
589              ((*v & 0x00FF000000FF0000LL) >> 8) |
590              ((*v & 0x0000FF000000FF00LL) << 8) |
591              ((*v & 0x000000FF000000FFLL) << 24);
592
593         return(TNG_SUCCESS);
594
595     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
596         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
597              ((*v & 0x00FF00FF00000000LL) >> 24) |
598              ((*v & 0x00000000FF00FF00LL) << 24) |
599              ((*v & 0x0000000000FF00FFLL) << 40);
600
601         return(TNG_SUCCESS);
602
603     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
604         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
605              ((*v & 0x0000FFFF00000000LL) >> 16) |
606              ((*v & 0x00000000FFFF0000LL) << 16) |
607              ((*v & 0x000000000000FFFFLL) << 48);
608
609         return(TNG_SUCCESS);
610
611     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
612         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
613              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
614              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
615              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
616              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
617              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
618              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
619              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
620
621         return(TNG_SUCCESS);
622
623     default:
624         return(TNG_FAILURE);
625     }
626 }
627 /** Generate the md5 hash of a block.
628  * The hash is created based on the actual block contents.
629  * @param block is a general block container.
630  * @return TNG_SUCCESS (0) if successful.
631  */
632 static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
633 {
634     md5_state_t md5_state;
635
636     md5_init(&md5_state);
637     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
638                (int)block->block_contents_size);
639     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
640
641     return(TNG_SUCCESS);
642 }
643
644 /** Compare the current block md5 hash (e.g. read from file) with the md5 hash
645  * calculated from the current contents.
646  * If the current md5 hash is not set skip the comparison.
647  * @param block is a general block container.
648  * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
649  * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
650  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
651  * set.
652  */
653 static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
654                                                      tng_bool *results)
655 {
656     md5_state_t md5_state;
657     char hash[TNG_MD5_HASH_LEN];
658
659     TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
660
661     *results = TNG_TRUE;
662     if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
663     {
664         return(TNG_FAILURE);
665     }
666     md5_init(&md5_state);
667     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
668                (int)block->block_contents_size);
669     md5_finish(&md5_state, (md5_byte_t *)hash);
670
671     if(strncmp(block->md5_hash, hash, 16) != 0)
672     {
673         *results = TNG_FALSE;
674     }
675
676     return(TNG_SUCCESS);
677 }
678
679 /** Open the input file if it is not already opened.
680  * @param tng_data is a trajectory data container.
681  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
682  * error has occured.
683  */
684 static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
685 {
686     if(!tng_data->input_file)
687     {
688         if(!tng_data->input_file_path)
689         {
690             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
691                    __FILE__, __LINE__);
692             return(TNG_CRITICAL);
693         }
694         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
695         if(!tng_data->input_file)
696         {
697             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
698                    tng_data->input_file_path, __FILE__, __LINE__);
699             return(TNG_CRITICAL);
700         }
701     }
702     return(TNG_SUCCESS);
703 }
704
705 /** Open the output file if it is not already opened
706  * @param tng_data is a trajectory data container.
707  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
708  * error has occured.
709  */
710 static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
711 {
712     if(!tng_data->output_file)
713     {
714         if(!tng_data->output_file_path)
715         {
716             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
717                    __FILE__, __LINE__);
718             return(TNG_CRITICAL);
719         }
720
721         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
722
723         if(!tng_data->output_file)
724         {
725             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
726                    tng_data->output_file_path, __FILE__, __LINE__);
727             return(TNG_CRITICAL);
728         }
729     }
730     return(TNG_SUCCESS);
731 }
732
733 /** Setup a file block container.
734  * @param block_p a pointer to memory to initialise as a file block container.
735  * @details Memory is allocated during initialisation.
736  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
737  * error has occured.
738  */
739 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
740 {
741     tng_gen_block_t block;
742
743     *block_p = malloc(sizeof(struct tng_gen_block));
744     if(!*block_p)
745     {
746         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
747                sizeof(struct tng_gen_block), __FILE__, __LINE__);
748         return(TNG_CRITICAL);
749     }
750
751     block = *block_p;
752
753     block->id = -1;
754     /* Reset the md5_hash */
755     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
756     block->name = 0;
757     block->block_version = TNG_API_VERSION;
758     block->header_contents = 0;
759     block->header_contents_size = 0;
760     block->block_contents = 0;
761     block->block_contents_size = 0;
762
763     return(TNG_SUCCESS);
764 }
765
766 /**
767  * @brief Clean up a file block container.
768  * @param block_p a pointer to the file block container to destroy.
769  * @details All allocated memory in the data structure is freed, as well as
770  * block_p itself.
771  * @return TNG_SUCCESS (0) if successful.
772  */
773 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
774 {
775     tng_gen_block_t block = *block_p;
776
777     if(!*block_p)
778     {
779         return(TNG_SUCCESS);
780     }
781
782 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
783     if(block->name)
784     {
785         free(block->name);
786         block->name = 0;
787     }
788     if(block->header_contents)
789     {
790         free(block->header_contents);
791         block->header_contents = 0;
792     }
793     if(block->block_contents)
794     {
795         free(block->block_contents);
796         block->block_contents = 0;
797     }
798
799     free(*block_p);
800     *block_p = 0;
801
802     return(TNG_SUCCESS);
803 }
804
805 /** Read the header of a data block, regardless of its type
806  * @param tng_data is a trajectory data container.
807  * @param block is a general block container.
808  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
809  * error has occured (not able to read the header size, thus skipping
810  * the block) or TNG_CRITICAL (2) if a major error has occured.
811  */
812 static tng_function_status tng_block_header_read
813                 (tng_trajectory_t tng_data, tng_gen_block_t block)
814 {
815     int len;
816     int64_t offset = 0;
817
818     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
819
820     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
821     {
822         return(TNG_CRITICAL);
823     }
824
825     /* First read the header size to be able to read the whole header. */
826     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
827         1, tng_data->input_file) == 0)
828     {
829         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
830                __FILE__, __LINE__);
831         return(TNG_CRITICAL);
832     }
833
834     if(block->header_contents_size == 0)
835     {
836         block->id = -1;
837         return(TNG_FAILURE);
838     }
839
840     /* If this was the size of the general info block check the endianness */
841     if(ftello(tng_data->input_file) < 9)
842     {
843         /* File is little endian */
844         if ( *((const char*)&block->header_contents_size) != 0x00 &&
845              *((const char*)(&block->header_contents_size) + 7) == 0x00)
846         {
847             /* If the architecture endianness is little endian no byte swap
848              * will be needed. Otherwise use the functions to swap to little
849              * endian */
850             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
851             {
852                 tng_data->input_endianness_swap_func_32 = 0;
853             }
854             else
855             {
856                 tng_data->input_endianness_swap_func_32 =
857                 &tng_swap_byte_order_little_endian_32;
858             }
859             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
860             {
861                 tng_data->input_endianness_swap_func_64 = 0;
862             }
863             else
864             {
865                 tng_data->input_endianness_swap_func_64 =
866                 &tng_swap_byte_order_little_endian_64;
867             }
868         }
869         /* File is big endian */
870         else
871         {
872             /* If the architecture endianness is big endian no byte swap
873              * will be needed. Otherwise use the functions to swap to big
874              * endian */
875             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
876             {
877                 tng_data->input_endianness_swap_func_32 = 0;
878             }
879             else
880             {
881                 tng_data->input_endianness_swap_func_32 =
882                 &tng_swap_byte_order_big_endian_32;
883             }
884             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
885             {
886                 tng_data->input_endianness_swap_func_64 = 0;
887             }
888             else
889             {
890                 tng_data->input_endianness_swap_func_64 =
891                 &tng_swap_byte_order_big_endian_64;
892             }
893         }
894     }
895
896     if(tng_data->input_endianness_swap_func_64)
897     {
898         if(tng_data->input_endianness_swap_func_64(tng_data,
899                                                    &block->header_contents_size)
900             != TNG_SUCCESS)
901         {
902             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
903                     __FILE__, __LINE__);
904         }
905     }
906
907     /* Move the reading position to the beginning of the header. */
908     fseeko(tng_data->input_file, -(int64_t)sizeof(block->header_contents_size),
909            SEEK_CUR);
910
911     /* If there is already memory allocated for the contents free it (we do not
912      * know if the size is correct). */
913     if(block->header_contents)
914     {
915         free(block->header_contents);
916     }
917
918     block->header_contents = malloc(block->header_contents_size);
919     if(!block->header_contents)
920     {
921         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
922                block->header_contents_size, __FILE__, __LINE__);
923         return(TNG_CRITICAL);
924     }
925
926     /* Read the whole header into header_contents. This way it can be saved
927      * even if it cannot be interpreted
928      * for one reason or another. */
929     if(fread(block->header_contents, block->header_contents_size, 1,
930         tng_data->input_file) == 0)
931     {
932         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
933         return(TNG_CRITICAL);
934     }
935
936     /* The header contents size has already been read. Skip ahead. */
937     offset = sizeof(block->header_contents_size);
938
939
940     /* Copy the respective parameters from the header contents block */
941     memcpy(&block->block_contents_size, block->header_contents+offset,
942            sizeof(block->block_contents_size));
943     if(tng_data->input_endianness_swap_func_64)
944     {
945         if(tng_data->input_endianness_swap_func_64(tng_data,
946                                                    &block->block_contents_size)
947             != TNG_SUCCESS)
948         {
949             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
950                     __FILE__, __LINE__);
951         }
952     }
953
954     offset += sizeof(block->block_contents_size);
955
956     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
957     if(tng_data->input_endianness_swap_func_64)
958     {
959         if(tng_data->input_endianness_swap_func_64(tng_data,
960                                                    &block->id)
961             != TNG_SUCCESS)
962         {
963             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
964                     __FILE__, __LINE__);
965         }
966     }
967
968     offset += sizeof(block->id);
969
970     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
971     offset += TNG_MD5_HASH_LEN;
972
973     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
974     {
975         free(block->name);
976         block->name = 0;
977     }
978     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
979     if(!block->name)
980     {
981         block->name = malloc(len);
982         if(!block->name)
983         {
984             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
985                     __FILE__, __LINE__);
986             return(TNG_CRITICAL);
987         }
988         strncpy(block->name, block->header_contents+offset, len);
989     }
990     offset += len;
991
992     memcpy(&block->block_version, block->header_contents+offset,
993            sizeof(block->block_version));
994     if(tng_data->input_endianness_swap_func_64)
995     {
996         if(tng_data->input_endianness_swap_func_64(tng_data,
997                                                    &block->block_version)
998             != TNG_SUCCESS)
999         {
1000             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1001                     __FILE__, __LINE__);
1002         }
1003     }
1004
1005     return(TNG_SUCCESS);
1006 }
1007
1008 /** Write a whole block, both header and contents, regardless of it type
1009  * @param tng_data is a trajectory data container.
1010  * @param block is a general block container.
1011  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1012  * has occurred or TNG_CRITICAL (2) if a major error has occured.
1013  */
1014 /* Disabled until it is used.*/
1015 /*
1016 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1017 //                                                     tng_gen_block_t block)
1018 // {
1019 //     if(!block->header_contents)
1020 //     {
1021 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1022 //         return(TNG_FAILURE);
1023 //     }
1024 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1025 //                 tng_data->output_file) != 1)
1026 //     {
1027 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1028 //                 __FILE__, __LINE__);
1029 //         return(TNG_CRITICAL);
1030 //     }
1031 //
1032 //     if(!block->block_contents)
1033 //     {
1034 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1035 //                 __FILE__, __LINE__);
1036 //         return(TNG_FAILURE);
1037 //     }
1038 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1039 //                 tng_data->output_file) != 1)
1040 //     {
1041 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1042 //                 __FILE__, __LINE__);
1043 //         return(TNG_CRITICAL);
1044 //     }
1045 //     return(TNG_SUCCESS);
1046 // }
1047 */
1048
1049 /** Update the md5 hash of a block already written to the file
1050  * @param tng_data is a trajectory data container.
1051  * @param block is the block, of which to update the md5 hash.
1052  * @param header_start_pos is the file position where the block header starts.
1053  * @param contents_start_pos is the file position where the block contents
1054  * start.
1055  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1056  * error has occured.
1057  */
1058 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
1059                                                tng_gen_block_t block,
1060                                                const int64_t header_start_pos,
1061                                                const int64_t contents_start_pos)
1062 {
1063     if(block->block_contents)
1064     {
1065         free(block->block_contents);
1066     }
1067
1068     block->block_contents = malloc(block->block_contents_size);
1069     if(!block->block_contents)
1070     {
1071         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1072                block->block_contents_size, __FILE__, __LINE__);
1073         return(TNG_CRITICAL);
1074     }
1075
1076     fseeko(tng_data->output_file, contents_start_pos, SEEK_SET);
1077     if(fread(block->block_contents, block->block_contents_size, 1,
1078             tng_data->output_file) == 0)
1079     {
1080         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1081         return(TNG_CRITICAL);
1082     }
1083
1084     tng_block_md5_hash_generate(block);
1085
1086     fseeko(tng_data->output_file, header_start_pos + 3 * sizeof(int64_t),
1087           SEEK_SET);
1088     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1089
1090     return(TNG_SUCCESS);
1091 }
1092
1093 /** Update the frame set pointers in the file header (general info block),
1094  * already written to disk
1095  * @param tng_data is a trajectory data container.
1096  * @param hash_mode specifies whether to update the block md5 hash when
1097  * updating the pointers.
1098  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1099  * error has occured.
1100  */
1101 static tng_function_status tng_header_pointers_update
1102                 (tng_trajectory_t tng_data, const char hash_mode)
1103 {
1104     tng_gen_block_t block;
1105     FILE *temp = tng_data->input_file;
1106     int64_t output_file_pos, pos, contents_start_pos;
1107
1108     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1109     {
1110         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1111                __FILE__, __LINE__);
1112         return(TNG_CRITICAL);
1113     }
1114
1115     tng_data->input_file = tng_data->output_file;
1116
1117     tng_block_init(&block);
1118
1119     output_file_pos = ftello(tng_data->output_file);
1120     fseeko(tng_data->output_file, 0, SEEK_SET);
1121
1122     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1123     {
1124         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1125                __FILE__, __LINE__);
1126         tng_data->input_file = temp;
1127         tng_block_destroy(&block);
1128         return(TNG_CRITICAL);
1129     }
1130
1131     contents_start_pos = ftello(tng_data->output_file);
1132
1133     fseeko(tng_data->output_file, block->block_contents_size - 5 *
1134           sizeof(int64_t), SEEK_CUR);
1135
1136     tng_data->input_file = temp;
1137
1138     pos = tng_data->first_trajectory_frame_set_output_file_pos;
1139
1140     if(tng_data->input_endianness_swap_func_64)
1141     {
1142         if(tng_data->input_endianness_swap_func_64(tng_data,
1143                                                     &pos)
1144             != TNG_SUCCESS)
1145         {
1146             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1147                     __FILE__, __LINE__);
1148         }
1149     }
1150
1151     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1152     {
1153         tng_block_destroy(&block);
1154         return(TNG_CRITICAL);
1155     }
1156
1157     pos = tng_data->last_trajectory_frame_set_output_file_pos;
1158
1159     if(tng_data->input_endianness_swap_func_64)
1160     {
1161         if(tng_data->input_endianness_swap_func_64(tng_data,
1162                                                     &pos)
1163             != TNG_SUCCESS)
1164         {
1165             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1166                     __FILE__, __LINE__);
1167         }
1168     }
1169
1170     if(fwrite(&pos,
1171         sizeof(int64_t), 1, tng_data->output_file) != 1)
1172     {
1173         tng_block_destroy(&block);
1174         return(TNG_CRITICAL);
1175     }
1176
1177     if(hash_mode == TNG_USE_HASH)
1178     {
1179         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1180     }
1181
1182     tng_block_destroy(&block);
1183
1184     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1185
1186     return(TNG_SUCCESS);
1187 }
1188
1189 /** Update the frame set pointers in the current frame set block, already
1190  * written to disk. It also updates the pointers of the blocks pointing to
1191  * the current frame set block.
1192  * @param tng_data is a trajectory data container.
1193  * @param hash_mode specifies whether to update the block md5 hash when
1194  * updating the pointers.
1195  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1196  * error has occured.
1197  */
1198 static tng_function_status tng_frame_set_pointers_update
1199                 (tng_trajectory_t tng_data, const char hash_mode)
1200 {
1201     tng_gen_block_t block;
1202     tng_trajectory_frame_set_t frame_set;
1203     FILE *temp = tng_data->input_file;
1204     int64_t pos, output_file_pos, contents_start_pos;
1205
1206     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1207     {
1208         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1209                __FILE__, __LINE__);
1210         return(TNG_CRITICAL);
1211     }
1212
1213     tng_block_init(&block);
1214     output_file_pos = ftello(tng_data->output_file);
1215
1216     tng_data->input_file = tng_data->output_file;
1217
1218     frame_set = &tng_data->current_trajectory_frame_set;
1219
1220     pos = tng_data->current_trajectory_frame_set_output_file_pos;
1221
1222     /* Update next frame set */
1223     if(frame_set->next_frame_set_file_pos > 0)
1224     {
1225         fseeko(tng_data->output_file, frame_set->next_frame_set_file_pos,
1226               SEEK_SET);
1227
1228         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1229         {
1230             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1231                 __FILE__, __LINE__);
1232             tng_data->input_file = temp;
1233             tng_block_destroy(&block);
1234             return(TNG_CRITICAL);
1235         }
1236
1237         contents_start_pos = ftello(tng_data->output_file);
1238
1239         fseeko(tng_data->output_file, block->block_contents_size - (5 *
1240             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1241
1242         if(tng_data->input_endianness_swap_func_64)
1243         {
1244             if(tng_data->input_endianness_swap_func_64(tng_data,
1245                                                         &pos)
1246                 != TNG_SUCCESS)
1247             {
1248                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1249                         __FILE__, __LINE__);
1250             }
1251         }
1252
1253         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1254         {
1255             tng_data->input_file = temp;
1256             tng_block_destroy(&block);
1257             return(TNG_CRITICAL);
1258         }
1259
1260         if(hash_mode == TNG_USE_HASH)
1261         {
1262             tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1263                                 contents_start_pos);
1264         }
1265         fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1266     }
1267     /* Update previous frame set */
1268     if(frame_set->prev_frame_set_file_pos > 0)
1269     {
1270         fseeko(tng_data->output_file, frame_set->prev_frame_set_file_pos,
1271               SEEK_SET);
1272
1273         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1274         {
1275             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1276                 __FILE__, __LINE__);
1277             tng_data->input_file = temp;
1278             tng_block_destroy(&block);
1279             return(TNG_CRITICAL);
1280         }
1281
1282         contents_start_pos = ftello(tng_data->output_file);
1283
1284         fseeko(tng_data->output_file, block->block_contents_size - (6 *
1285             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1286
1287         if(tng_data->input_endianness_swap_func_64)
1288         {
1289             if(tng_data->input_endianness_swap_func_64(tng_data,
1290                                                         &pos)
1291                 != TNG_SUCCESS)
1292             {
1293                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1294                         __FILE__, __LINE__);
1295             }
1296         }
1297
1298         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1299         {
1300             tng_data->input_file = temp;
1301             tng_block_destroy(&block);
1302             return(TNG_CRITICAL);
1303         }
1304
1305         if(hash_mode == TNG_USE_HASH)
1306         {
1307             tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1308                                 contents_start_pos);
1309         }
1310         fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1311     }
1312
1313     /* Update the frame set one medium stride step after */
1314     if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1315     {
1316         fseeko(tng_data->output_file,
1317                frame_set->medium_stride_next_frame_set_file_pos,
1318                SEEK_SET);
1319
1320         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1321         {
1322             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1323                 __FILE__, __LINE__);
1324             tng_data->input_file = temp;
1325             tng_block_destroy(&block);
1326             return(TNG_CRITICAL);
1327         }
1328
1329         contents_start_pos = ftello(tng_data->output_file);
1330
1331         fseeko(tng_data->output_file, block->block_contents_size - (3 *
1332             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1333
1334         if(tng_data->input_endianness_swap_func_64)
1335         {
1336             if(tng_data->input_endianness_swap_func_64(tng_data,
1337                                                         &pos)
1338                 != TNG_SUCCESS)
1339             {
1340                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1341                         __FILE__, __LINE__);
1342             }
1343         }
1344
1345         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1346         {
1347             tng_data->input_file = temp;
1348             tng_block_destroy(&block);
1349             return(TNG_CRITICAL);
1350         }
1351
1352         if(hash_mode == TNG_USE_HASH)
1353         {
1354             tng_md5_hash_update(tng_data, block,
1355                                 frame_set->medium_stride_next_frame_set_file_pos,
1356                                 contents_start_pos);
1357         }
1358     }
1359     /* Update the frame set one medium stride step before */
1360     if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1361     {
1362         fseeko(tng_data->output_file,
1363                frame_set->medium_stride_prev_frame_set_file_pos,
1364                SEEK_SET);
1365
1366         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1367         {
1368             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1369                 __FILE__, __LINE__);
1370             tng_data->input_file = temp;
1371             tng_block_destroy(&block);
1372             return(TNG_CRITICAL);
1373         }
1374
1375         contents_start_pos = ftello(tng_data->output_file);
1376
1377         fseeko(tng_data->output_file, block->block_contents_size - (4 *
1378             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1379
1380         if(tng_data->input_endianness_swap_func_64)
1381         {
1382             if(tng_data->input_endianness_swap_func_64(tng_data,
1383                                                         &pos)
1384                 != TNG_SUCCESS)
1385             {
1386                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1387                         __FILE__, __LINE__);
1388             }
1389         }
1390
1391         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1392         {
1393             tng_data->input_file = temp;
1394             tng_block_destroy(&block);
1395             return(TNG_CRITICAL);
1396         }
1397
1398         if(hash_mode == TNG_USE_HASH)
1399         {
1400             tng_md5_hash_update(tng_data, block,
1401                                 frame_set->medium_stride_prev_frame_set_file_pos,
1402                                 contents_start_pos);
1403         }
1404     }
1405
1406     /* Update the frame set one long stride step after */
1407     if(frame_set->long_stride_next_frame_set_file_pos > 0)
1408     {
1409         fseeko(tng_data->output_file,
1410                frame_set->long_stride_next_frame_set_file_pos,
1411                SEEK_SET);
1412
1413         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1414         {
1415             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1416                 __FILE__, __LINE__);
1417             tng_data->input_file = temp;
1418             tng_block_destroy(&block);
1419             return(TNG_CRITICAL);
1420         }
1421
1422         contents_start_pos = ftello(tng_data->output_file);
1423
1424         fseeko(tng_data->output_file, block->block_contents_size - (1 *
1425                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1426
1427         if(tng_data->input_endianness_swap_func_64)
1428         {
1429             if(tng_data->input_endianness_swap_func_64(tng_data,
1430                                                         &pos)
1431                 != TNG_SUCCESS)
1432             {
1433                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1434                         __FILE__, __LINE__);
1435             }
1436         }
1437
1438         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1439         {
1440             tng_data->input_file = temp;
1441             tng_block_destroy(&block);
1442             return(TNG_CRITICAL);
1443         }
1444
1445         if(hash_mode == TNG_USE_HASH)
1446         {
1447             tng_md5_hash_update(tng_data, block,
1448                                 frame_set->long_stride_next_frame_set_file_pos,
1449                                 contents_start_pos);
1450         }
1451     }
1452     /* Update the frame set one long stride step before */
1453     if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1454     {
1455         fseeko(tng_data->output_file,
1456                frame_set->long_stride_prev_frame_set_file_pos,
1457                SEEK_SET);
1458
1459         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1460         {
1461             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1462                 __FILE__, __LINE__);
1463             tng_data->input_file = temp;
1464             tng_block_destroy(&block);
1465             return(TNG_CRITICAL);
1466         }
1467
1468         contents_start_pos = ftello(tng_data->output_file);
1469
1470         fseeko(tng_data->output_file, block->block_contents_size - (2 *
1471             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1472
1473         if(tng_data->input_endianness_swap_func_64)
1474         {
1475             if(tng_data->input_endianness_swap_func_64(tng_data,
1476                                                         &pos)
1477                 != TNG_SUCCESS)
1478             {
1479                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1480                         __FILE__, __LINE__);
1481             }
1482         }
1483
1484         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1485         {
1486             tng_data->input_file = temp;
1487             tng_block_destroy(&block);
1488             return(TNG_CRITICAL);
1489         }
1490
1491         if(hash_mode == TNG_USE_HASH)
1492         {
1493             tng_md5_hash_update(tng_data, block,
1494                                 frame_set->long_stride_prev_frame_set_file_pos,
1495                                 contents_start_pos);
1496         }
1497     }
1498
1499     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1500
1501     tng_data->input_file = temp;
1502
1503     tng_block_destroy(&block);
1504
1505     return(TNG_SUCCESS);
1506 }
1507
1508 static tng_function_status tng_reread_frame_set_at_file_pos
1509                 (tng_trajectory_t tng_data,
1510                  const int64_t pos)
1511 {
1512     tng_gen_block_t block;
1513     tng_function_status stat;
1514
1515     tng_block_init(&block);
1516
1517     fseeko(tng_data->input_file, pos, SEEK_SET);
1518     if(pos > 0)
1519     {
1520         stat = tng_block_header_read(tng_data, block);
1521         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1522         {
1523             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
1524                     __FILE__, __LINE__);
1525             tng_block_destroy(&block);
1526             return(TNG_FAILURE);
1527         }
1528
1529         if(tng_block_read_next(tng_data, block,
1530                                TNG_SKIP_HASH) != TNG_SUCCESS)
1531         {
1532             tng_block_destroy(&block);
1533             return(TNG_CRITICAL);
1534         }
1535     }
1536
1537     tng_block_destroy(&block);
1538
1539     return(TNG_SUCCESS);
1540 }
1541
1542 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1543                 (tng_trajectory_t tng_data,
1544                  int64_t *pos)
1545 {
1546     int64_t orig_pos, curr_frame_set_pos;
1547     tng_gen_block_t block;
1548     tng_function_status stat;
1549     tng_trajectory_frame_set_t frame_set =
1550     &tng_data->current_trajectory_frame_set;
1551
1552     orig_pos = ftello(tng_data->input_file);
1553     curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1554
1555     *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1556
1557     if(*pos <= 0)
1558     {
1559         return(TNG_SUCCESS);
1560     }
1561
1562     fseeko(tng_data->input_file, *pos, SEEK_SET);
1563
1564     tng_block_init(&block);
1565     /* Read block headers first to see that a frame set block is found. */
1566     stat = tng_block_header_read(tng_data, block);
1567     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1568     {
1569         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1570                 __FILE__, __LINE__);
1571         tng_block_destroy(&block);
1572         return(TNG_FAILURE);
1573     }
1574
1575     if(tng_block_read_next(tng_data, block,
1576                            TNG_SKIP_HASH) != TNG_SUCCESS)
1577     {
1578         tng_block_destroy(&block);
1579         return(TNG_CRITICAL);
1580     }
1581
1582     /* Read all frame set blocks (not the blocks between them) */
1583     while(frame_set->next_frame_set_file_pos > 0)
1584     {
1585         fseeko(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1586         stat = tng_block_header_read(tng_data, block);
1587         if(stat == TNG_CRITICAL)
1588         {
1589             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1590                     __FILE__, __LINE__);
1591             tng_block_destroy(&block);
1592             return(TNG_CRITICAL);
1593         }
1594         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1595         {
1596             return(TNG_FAILURE);
1597         }
1598
1599         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1600         if(stat != TNG_SUCCESS)
1601         {
1602             tng_block_destroy(&block);
1603             return(stat);
1604         }
1605         /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1606         if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1607            tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1608         {
1609             *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1610         }
1611     }
1612
1613     /* Re-read the frame set that used to be the current one */
1614     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1615
1616     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1617
1618     tng_block_destroy(&block);
1619
1620     return(TNG_SUCCESS);
1621 }
1622
1623 static tng_function_status tng_frame_set_complete_migrate
1624                 (tng_trajectory_t tng_data,
1625                  int64_t block_start_pos,
1626                  int64_t block_len,
1627                  int64_t new_pos)
1628 {
1629     int64_t i;
1630     tng_bool updated = TNG_FALSE;
1631
1632     char *contents;
1633
1634     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1635     {
1636         return(TNG_CRITICAL);
1637     }
1638
1639     fseeko(tng_data->input_file, block_start_pos, SEEK_SET);
1640
1641     contents = malloc(block_len);
1642     if(!contents)
1643     {
1644         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1645                 block_len, __FILE__, __LINE__);
1646         return(TNG_CRITICAL);
1647     }
1648
1649     if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1650     {
1651         fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1652                __FILE__, __LINE__);
1653         free(contents);
1654         return(TNG_CRITICAL);
1655     }
1656     fseeko(tng_data->output_file, new_pos, SEEK_SET);
1657
1658     if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1659     {
1660         fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1661                 __FILE__, __LINE__);
1662         free(contents);
1663         return(TNG_CRITICAL);
1664     }
1665
1666     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1667
1668     tng_frame_set_pointers_update(tng_data, TNG_USE_HASH);
1669
1670     /* Update the general info block if needed */
1671     if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1672     {
1673         tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1674         updated = TNG_TRUE;
1675     }
1676     if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1677     {
1678         tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1679         updated = TNG_TRUE;
1680     }
1681     if(updated)
1682     {
1683         tng_header_pointers_update(tng_data, TNG_USE_HASH);
1684     }
1685
1686     /* Fill the block with NULL to avoid confusion. */
1687     for(i = 0; i < block_len; i++)
1688     {
1689         contents[i] = '\0';
1690     }
1691     fseeko(tng_data->output_file, block_start_pos, SEEK_SET);
1692
1693     /* FIXME: casting block_len to size_t is dangerous */
1694     fwrite(contents, 1, block_len, tng_data->output_file);
1695
1696     free(contents);
1697
1698     return(TNG_SUCCESS);
1699 }
1700
1701 static tng_function_status tng_length_of_current_frame_set_contents_get
1702                 (tng_trajectory_t tng_data,
1703                  int64_t *len)
1704 {
1705     int64_t orig_pos, pos, curr_frame_set_pos;
1706     tng_gen_block_t block;
1707     tng_function_status stat;
1708
1709     orig_pos = ftello(tng_data->input_file);
1710     curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1711
1712     *len = 0;
1713
1714     fseeko(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1715
1716     tng_block_init(&block);
1717     /* Read block headers first to see that a frame set block is found. */
1718     stat = tng_block_header_read(tng_data, block);
1719     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1720     {
1721         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
1722                 curr_frame_set_pos, __FILE__, __LINE__);
1723         tng_block_destroy(&block);
1724         return(TNG_FAILURE);
1725     }
1726
1727     /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1728     while(stat == TNG_SUCCESS)
1729     {
1730         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1731         *len += block->header_contents_size + block->block_contents_size;
1732         pos += block->header_contents_size + block->block_contents_size;
1733         if(pos >= tng_data->input_file_len)
1734         {
1735             break;
1736         }
1737         stat = tng_block_header_read(tng_data, block);
1738         if(block->id == TNG_TRAJECTORY_FRAME_SET)
1739         {
1740             break;
1741         }
1742     }
1743
1744     /* Re-read the frame set that used to be the current one */
1745     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1746
1747     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1748
1749     tng_block_destroy(&block);
1750
1751     return(TNG_SUCCESS);
1752 }
1753
1754 /** Migrate blocks in the file to make room for new data in a block. This
1755  * is required e.g. when adding data to a block or extending strings in a
1756  * block.
1757  * @param tng_data is a trajectory data container.
1758  * @param start_pos is the position from which to start moving data, usually
1759  * the byte after the end of the block to which data was added.
1760  * @param offset is the number of bytes that were inserted.
1761  * @details Trajectory blocks (frame sets and their related blocks) are moved
1762  * to the end of the file (if needed) in order to make room for non-trajectory
1763  * data.
1764  */
1765 static tng_function_status tng_migrate_data_in_file
1766                 (tng_trajectory_t tng_data,
1767                  int64_t start_pos,
1768                  int64_t offset)
1769 {
1770     int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1771     tng_gen_block_t block;
1772     tng_function_status stat;
1773     FILE *temp;
1774
1775     if(offset <= 0)
1776     {
1777         return(TNG_SUCCESS);
1778     }
1779
1780     temp = tng_data->input_file;
1781
1782     stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1783     if(stat != TNG_SUCCESS)
1784     {
1785         tng_data->input_file = temp;
1786         return(stat);
1787     }
1788
1789     tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1790
1791     empty_space = traj_start_pos - (start_pos - 1);
1792
1793     if(empty_space >= offset)
1794     {
1795         return(TNG_SUCCESS);
1796     }
1797
1798     orig_file_pos = ftello(tng_data->input_file);
1799     tng_block_init(&block);
1800
1801     while(empty_space < offset)
1802     {
1803         fseeko(tng_data->input_file, traj_start_pos, SEEK_SET);
1804         stat = tng_block_header_read(tng_data, block);
1805         if(stat == TNG_CRITICAL)
1806         {
1807             fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1808                     __FILE__, __LINE__);
1809             tng_block_destroy(&block);
1810             tng_data->input_file = temp;
1811             return(TNG_CRITICAL);
1812         }
1813         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1814         {
1815             tng_data->input_file = temp;
1816             tng_block_destroy(&block);
1817             return(TNG_FAILURE);
1818         }
1819         stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1820         if(stat != TNG_SUCCESS)
1821         {
1822             tng_data->input_file = temp;
1823             tng_block_destroy(&block);
1824             return(stat);
1825         }
1826         stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1827                                               frame_set_length, tng_data->input_file_len);
1828         if(stat != TNG_SUCCESS)
1829         {
1830             tng_data->input_file = temp;
1831             tng_block_destroy(&block);
1832             return(stat);
1833         }
1834
1835         empty_space += frame_set_length;
1836     }
1837     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
1838     tng_block_destroy(&block);
1839
1840     return(TNG_SUCCESS);
1841 }
1842
1843 static tng_function_status tng_block_header_len_calculate
1844                 (const tng_trajectory_t tng_data,
1845                  tng_gen_block_t block,
1846                  int64_t *len)
1847 {
1848     int name_len;
1849     (void)tng_data;
1850
1851     /* If the string is unallocated allocate memory for just string
1852      * termination */
1853     if(!block->name)
1854     {
1855         block->name = malloc(1);
1856         if(!block->name)
1857         {
1858             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1859                    __FILE__, __LINE__);
1860             return(TNG_CRITICAL);
1861         }
1862         block->name[0] = 0;
1863     }
1864
1865     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1866
1867     /* Calculate the size of the header to write */
1868     *len = sizeof(block->header_contents_size) +
1869                   sizeof(block->block_contents_size) +
1870                   sizeof(block->id) +
1871                   sizeof(block->block_version) +
1872                   TNG_MD5_HASH_LEN +
1873                   name_len;
1874
1875     return (TNG_SUCCESS);
1876 }
1877
1878 /** Write the header of a data block, regardless of its type
1879  * @param tng_data is a trajectory data container.
1880  * @param block is a general block container.
1881  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1882  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1883  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1884  * error has occured.
1885  */
1886 static tng_function_status tng_block_header_write
1887                 (tng_trajectory_t tng_data,
1888                  tng_gen_block_t block,
1889                  const char hash_mode)
1890 {
1891     int name_len, offset = 0;
1892
1893     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1894
1895     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1896     {
1897         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1898                __FILE__, __LINE__);
1899         return(TNG_CRITICAL);
1900     }
1901
1902     if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
1903         TNG_SUCCESS)
1904     {
1905         fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
1906                 __FILE__, __LINE__);
1907         return(TNG_CRITICAL);
1908     }
1909
1910     if(hash_mode == TNG_USE_HASH)
1911     {
1912         tng_block_md5_hash_generate(block);
1913     }
1914
1915     if(block->header_contents)
1916     {
1917         free(block->header_contents);
1918     }
1919
1920     block->header_contents = malloc(block->header_contents_size);
1921     if(!block->header_contents)
1922     {
1923         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1924                block->header_contents_size, __FILE__, __LINE__);
1925         return(TNG_CRITICAL);
1926     }
1927
1928     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1929
1930     /* First copy all data into the header_contents block and finally write
1931      * the whole block at once. */
1932     memcpy(block->header_contents, &block->header_contents_size,
1933            sizeof(block->header_contents_size));
1934     if(tng_data->output_endianness_swap_func_64)
1935     {
1936         if(tng_data->output_endianness_swap_func_64(tng_data,
1937                                       (int64_t *)block->header_contents+offset)
1938             != TNG_SUCCESS)
1939         {
1940             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1941                     __FILE__, __LINE__);
1942         }
1943     }
1944     offset += sizeof(block->header_contents_size);
1945
1946     memcpy(block->header_contents+offset, &block->block_contents_size,
1947            sizeof(block->block_contents_size));
1948     if(tng_data->output_endianness_swap_func_64)
1949     {
1950         if(tng_data->output_endianness_swap_func_64(tng_data,
1951                                       (int64_t *)block->header_contents+offset)
1952             != TNG_SUCCESS)
1953         {
1954             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1955                     __FILE__, __LINE__);
1956         }
1957     }
1958     offset += sizeof(block->block_contents_size);
1959
1960     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1961     if(tng_data->output_endianness_swap_func_64)
1962     {
1963         if(tng_data->output_endianness_swap_func_64(tng_data,
1964                                       (int64_t *)block->header_contents+offset)
1965             != TNG_SUCCESS)
1966         {
1967             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1968                     __FILE__, __LINE__);
1969         }
1970     }
1971     offset += sizeof(block->id);
1972
1973     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1974     offset += TNG_MD5_HASH_LEN;
1975
1976     strncpy(block->header_contents+offset, block->name, name_len);
1977     offset += name_len;
1978
1979     memcpy(block->header_contents+offset, &block->block_version,
1980            sizeof(block->block_version));
1981     if(tng_data->output_endianness_swap_func_64)
1982     {
1983         if(tng_data->output_endianness_swap_func_64(tng_data,
1984                                       (int64_t *)block->header_contents+offset)
1985             != TNG_SUCCESS)
1986         {
1987             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1988                     __FILE__, __LINE__);
1989         }
1990     }
1991
1992     if(fwrite(block->header_contents, block->header_contents_size,
1993        1, tng_data->output_file) != 1)
1994     {
1995         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
1996         return(TNG_CRITICAL);
1997     }
1998     return(TNG_SUCCESS);
1999 }
2000
2001 static tng_function_status tng_general_info_block_len_calculate
2002                 (tng_trajectory_t tng_data,
2003                  int64_t *len)
2004 {
2005     int first_program_name_len, first_user_name_len;
2006     int first_computer_name_len, first_pgp_signature_len;
2007     int last_program_name_len, last_user_name_len;
2008     int last_computer_name_len, last_pgp_signature_len;
2009     int forcefield_name_len;
2010
2011     /* If the strings are unallocated allocate memory for just string
2012      * termination */
2013     if(!tng_data->first_program_name)
2014     {
2015         tng_data->first_program_name = malloc(1);
2016         if(!tng_data->first_program_name)
2017         {
2018             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2019                    __FILE__, __LINE__);
2020             return(TNG_CRITICAL);
2021         }
2022         tng_data->first_program_name[0] = 0;
2023     }
2024     if(!tng_data->last_program_name)
2025     {
2026         tng_data->last_program_name = malloc(1);
2027         if(!tng_data->last_program_name)
2028         {
2029             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2030                    __FILE__, __LINE__);
2031             return(TNG_CRITICAL);
2032         }
2033         tng_data->last_program_name[0] = 0;
2034     }
2035     if(!tng_data->first_user_name)
2036     {
2037         tng_data->first_user_name = malloc(1);
2038         if(!tng_data->first_user_name)
2039         {
2040             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2041                    __FILE__, __LINE__);
2042             return(TNG_CRITICAL);
2043         }
2044         tng_data->first_user_name[0] = 0;
2045     }
2046     if(!tng_data->last_user_name)
2047     {
2048         tng_data->last_user_name = malloc(1);
2049         if(!tng_data->last_user_name)
2050         {
2051             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2052                    __FILE__, __LINE__);
2053             return(TNG_CRITICAL);
2054         }
2055         tng_data->last_user_name[0] = 0;
2056     }
2057     if(!tng_data->first_computer_name)
2058     {
2059         tng_data->first_computer_name = malloc(1);
2060         if(!tng_data->first_computer_name)
2061         {
2062             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2063                    __FILE__, __LINE__);
2064             return(TNG_CRITICAL);
2065         }
2066         tng_data->first_computer_name[0] = 0;
2067     }
2068     if(!tng_data->last_computer_name)
2069     {
2070         tng_data->last_computer_name = malloc(1);
2071         if(!tng_data->last_computer_name)
2072         {
2073             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2074                    __FILE__, __LINE__);
2075             return(TNG_CRITICAL);
2076         }
2077         tng_data->last_computer_name[0] = 0;
2078     }
2079     if(!tng_data->first_pgp_signature)
2080     {
2081         tng_data->first_pgp_signature = malloc(1);
2082         if(!tng_data->first_pgp_signature)
2083         {
2084             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2085                    __FILE__, __LINE__);
2086             return(TNG_CRITICAL);
2087         }
2088         tng_data->first_pgp_signature[0] = 0;
2089     }
2090     if(!tng_data->last_pgp_signature)
2091     {
2092         tng_data->last_pgp_signature = malloc(1);
2093         if(!tng_data->last_pgp_signature)
2094         {
2095             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2096                    __FILE__, __LINE__);
2097             return(TNG_CRITICAL);
2098         }
2099         tng_data->last_pgp_signature[0] = 0;
2100     }
2101     if(!tng_data->forcefield_name)
2102     {
2103         tng_data->forcefield_name = malloc(1);
2104         if(!tng_data->forcefield_name)
2105         {
2106             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2107                    __FILE__, __LINE__);
2108             return(TNG_CRITICAL);
2109         }
2110         tng_data->forcefield_name[0] = 0;
2111     }
2112
2113     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2114                            TNG_MAX_STR_LEN);
2115     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2116                            TNG_MAX_STR_LEN);
2117     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2118                         TNG_MAX_STR_LEN);
2119     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2120                         TNG_MAX_STR_LEN);
2121     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2122                             TNG_MAX_STR_LEN);
2123     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2124                             TNG_MAX_STR_LEN);
2125     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2126                             TNG_MAX_STR_LEN);
2127     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2128                             TNG_MAX_STR_LEN);
2129     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2130                               TNG_MAX_STR_LEN);
2131
2132     *len = sizeof(tng_data->time) +
2133                   sizeof(tng_data->var_num_atoms_flag) +
2134                   sizeof(tng_data->frame_set_n_frames) +
2135                   sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2136                   sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2137                   sizeof(tng_data->medium_stride_length) +
2138                   sizeof(tng_data->long_stride_length) +
2139                   sizeof(tng_data->distance_unit_exponential) +
2140                   first_program_name_len +
2141                   last_program_name_len +
2142                   first_user_name_len +
2143                   last_user_name_len +
2144                   first_computer_name_len +
2145                   last_computer_name_len +
2146                   first_pgp_signature_len +
2147                   last_pgp_signature_len +
2148                   forcefield_name_len;
2149
2150     return(TNG_SUCCESS);
2151 }
2152
2153 /** Read a general info block. This is the first block of a TNG file.
2154  *  Populate the fields in tng_data.
2155  * @param tng_data is a trajectory data container.
2156  * @param block is a general block container.
2157  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2158  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2159  * compared to the md5 hash of the read contents to ensure valid data.
2160  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2161  * error has occured.
2162  */
2163 static tng_function_status tng_general_info_block_read
2164                 (tng_trajectory_t tng_data, tng_gen_block_t block,
2165                  const char hash_mode)
2166 {
2167     int len, offset = 0;
2168     tng_bool same_hash;
2169
2170     void *temp;
2171
2172     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2173
2174     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2175     {
2176         return(TNG_CRITICAL);
2177     }
2178
2179     temp = realloc(block->block_contents, block->block_contents_size);
2180     if(!temp)
2181     {
2182         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2183                block->block_contents_size, __FILE__, __LINE__);
2184         free(block->block_contents);
2185         block->block_contents = 0;
2186         return(TNG_CRITICAL);
2187     }
2188     block->block_contents = temp;
2189
2190     /* Read the whole block into block_contents to be able to write it to disk
2191      * even if it cannot be interpreted. */
2192     if(fread(block->block_contents, block->block_contents_size, 1,
2193              tng_data->input_file) == 0)
2194     {
2195         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2196         return(TNG_CRITICAL);
2197     }
2198
2199     /* FIXME: Does not check if the size of the contents matches the expected
2200      * size or if the contents can be read. */
2201
2202     if(hash_mode == TNG_USE_HASH)
2203     {
2204         tng_md5_hash_match_verify(block, &same_hash);
2205         if(same_hash != TNG_TRUE)
2206         {
2207             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2208                 "%s: %d\n",
2209                 __FILE__, __LINE__);
2210     /*         return(TNG_FAILURE); */
2211         }
2212     }
2213
2214     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
2215     temp = realloc(tng_data->first_program_name, len);
2216     if(!temp)
2217     {
2218         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2219                __FILE__, __LINE__);
2220         free(tng_data->first_program_name);
2221         tng_data->first_program_name = 0;
2222         return(TNG_CRITICAL);
2223     }
2224     tng_data->first_program_name = temp;
2225     strncpy(tng_data->first_program_name, block->block_contents, len);
2226     offset += len;
2227
2228     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
2229     temp = realloc(tng_data->last_program_name, len);
2230     if(!temp)
2231     {
2232         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2233                __FILE__, __LINE__);
2234         free(tng_data->last_program_name);
2235         tng_data->last_program_name = 0;
2236         return(TNG_CRITICAL);
2237     }
2238     tng_data->last_program_name = temp;
2239     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
2240     offset += len;
2241
2242     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2243     temp = realloc(tng_data->first_user_name, len);
2244     if(!temp)
2245     {
2246         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2247                __FILE__, __LINE__);
2248         free(tng_data->first_user_name);
2249         tng_data->first_user_name = 0;
2250         return(TNG_CRITICAL);
2251     }
2252     tng_data->first_user_name = temp;
2253     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
2254     offset += len;
2255
2256     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2257     temp = realloc(tng_data->last_user_name, len);
2258     if(!temp)
2259     {
2260         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2261                __FILE__, __LINE__);
2262         free(tng_data->last_user_name);
2263         tng_data->last_user_name = 0;
2264         return(TNG_CRITICAL);
2265     }
2266     tng_data->last_user_name = temp;
2267     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
2268     offset += len;
2269
2270     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2271     temp = realloc(tng_data->first_computer_name, len);
2272     if(!temp)
2273     {
2274         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2275                __FILE__, __LINE__);
2276         free(tng_data->first_computer_name);
2277         tng_data->first_computer_name = 0;
2278         return(TNG_CRITICAL);
2279     }
2280     tng_data->first_computer_name = temp;
2281     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
2282     offset += len;
2283
2284     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2285     temp = realloc(tng_data->last_computer_name, len);
2286     if(!temp)
2287     {
2288         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2289                __FILE__, __LINE__);
2290         free(tng_data->last_computer_name);
2291         tng_data->last_computer_name = 0;
2292         return(TNG_CRITICAL);
2293     }
2294     tng_data->last_computer_name = temp;
2295     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
2296     offset += len;
2297
2298     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2299     temp = realloc(tng_data->first_pgp_signature, len);
2300     if(!temp)
2301     {
2302         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2303                __FILE__, __LINE__);
2304         free(tng_data->first_pgp_signature);
2305         tng_data->first_pgp_signature = 0;
2306         return(TNG_CRITICAL);
2307     }
2308     tng_data->first_pgp_signature = temp;
2309     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
2310     offset += len;
2311
2312     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2313     temp = realloc(tng_data->last_pgp_signature, len);
2314     if(!temp)
2315     {
2316         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2317                __FILE__, __LINE__);
2318         free(tng_data->last_pgp_signature);
2319         tng_data->last_pgp_signature = 0;
2320         return(TNG_CRITICAL);
2321     }
2322     tng_data->last_pgp_signature = temp;
2323     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
2324     offset += len;
2325
2326     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2327     temp = realloc(tng_data->forcefield_name, len);
2328     if(!temp)
2329     {
2330         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2331                __FILE__, __LINE__);
2332         free(tng_data->forcefield_name);
2333         tng_data->forcefield_name = 0;
2334         return(TNG_CRITICAL);
2335     }
2336     tng_data->forcefield_name = temp;
2337     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
2338     offset += len;
2339
2340     memcpy(&tng_data->time, block->block_contents+offset,
2341            sizeof(tng_data->time));
2342     if(tng_data->input_endianness_swap_func_64)
2343     {
2344         if(tng_data->input_endianness_swap_func_64(tng_data,
2345                                                    &tng_data->time)
2346             != TNG_SUCCESS)
2347         {
2348             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2349                     __FILE__, __LINE__);
2350         }
2351     }
2352     offset += sizeof(tng_data->time);
2353
2354     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
2355            sizeof(tng_data->var_num_atoms_flag));
2356     offset += sizeof(tng_data->var_num_atoms_flag);
2357
2358     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
2359            sizeof(tng_data->frame_set_n_frames));
2360     if(tng_data->input_endianness_swap_func_64)
2361     {
2362         if(tng_data->input_endianness_swap_func_64(tng_data,
2363                                                  &tng_data->frame_set_n_frames)
2364             != TNG_SUCCESS)
2365         {
2366             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2367                     __FILE__, __LINE__);
2368         }
2369     }
2370     offset += sizeof(tng_data->frame_set_n_frames);
2371
2372     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
2373            block->block_contents+offset,
2374            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
2375     if(tng_data->input_endianness_swap_func_64)
2376     {
2377         if(tng_data->input_endianness_swap_func_64(tng_data,
2378                           &tng_data->first_trajectory_frame_set_input_file_pos)
2379             != TNG_SUCCESS)
2380         {
2381             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2382                     __FILE__, __LINE__);
2383         }
2384     }
2385     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
2386
2387     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2388     tng_data->first_trajectory_frame_set_input_file_pos;
2389
2390
2391     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
2392            block->block_contents+offset,
2393            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
2394     if(tng_data->input_endianness_swap_func_64)
2395     {
2396         if(tng_data->input_endianness_swap_func_64(tng_data,
2397                           &tng_data->last_trajectory_frame_set_input_file_pos)
2398             != TNG_SUCCESS)
2399         {
2400             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2401                     __FILE__, __LINE__);
2402         }
2403     }
2404     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
2405
2406     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
2407            sizeof(tng_data->medium_stride_length));
2408     if(tng_data->input_endianness_swap_func_64)
2409     {
2410         if(tng_data->input_endianness_swap_func_64(tng_data,
2411                                                &tng_data->medium_stride_length)
2412             != TNG_SUCCESS)
2413         {
2414             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2415                     __FILE__, __LINE__);
2416         }
2417     }
2418     offset += sizeof(tng_data->medium_stride_length);
2419
2420     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
2421            sizeof(tng_data->long_stride_length));
2422     if(tng_data->input_endianness_swap_func_64)
2423     {
2424         if(tng_data->input_endianness_swap_func_64(tng_data,
2425                                                    &tng_data->long_stride_length)
2426             != TNG_SUCCESS)
2427         {
2428             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2429                     __FILE__, __LINE__);
2430         }
2431     }
2432     offset += sizeof(tng_data->long_stride_length);
2433
2434     if(block->block_version >= 3)
2435     {
2436         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
2437             sizeof(tng_data->distance_unit_exponential));
2438         if(tng_data->input_endianness_swap_func_64)
2439         {
2440             if(tng_data->input_endianness_swap_func_64(tng_data,
2441                                           &tng_data->distance_unit_exponential)
2442                 != TNG_SUCCESS)
2443             {
2444                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2445                         __FILE__, __LINE__);
2446             }
2447         }
2448     }
2449
2450     return(TNG_SUCCESS);
2451 }
2452
2453 /** Write a general info block. This is the first block of a TNG file.
2454  * @param tng_data is a trajectory data container.
2455  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2456  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2457  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2458  * error has occured.
2459  */
2460 static tng_function_status tng_general_info_block_write
2461                 (tng_trajectory_t tng_data,
2462                  const char hash_mode)
2463 {
2464     int first_program_name_len, first_user_name_len;
2465     int first_computer_name_len, first_pgp_signature_len;
2466     int last_program_name_len, last_user_name_len;
2467     int last_computer_name_len, last_pgp_signature_len;
2468     int forcefield_name_len, name_len;
2469     int offset = 0;
2470     tng_gen_block_t block;
2471
2472     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2473     {
2474         return(TNG_CRITICAL);
2475     }
2476
2477     fseeko(tng_data->output_file, 0, SEEK_SET);
2478
2479     tng_block_init(&block);
2480
2481     name_len = (int)strlen("GENERAL INFO");
2482
2483     block->name = malloc(name_len + 1);
2484     if(!block->name)
2485     {
2486         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2487                 name_len+1, __FILE__, __LINE__);
2488         tng_block_destroy(&block);
2489         return(TNG_CRITICAL);
2490     }
2491
2492     strcpy(block->name, "GENERAL INFO");
2493     block->id = TNG_GENERAL_INFO;
2494
2495     if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2496         TNG_SUCCESS)
2497     {
2498         fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2499                 __FILE__, __LINE__);
2500         tng_block_destroy(&block);
2501         return(TNG_CRITICAL);
2502     }
2503
2504     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2505                            TNG_MAX_STR_LEN);
2506     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2507                            TNG_MAX_STR_LEN);
2508     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2509                         TNG_MAX_STR_LEN);
2510     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2511                         TNG_MAX_STR_LEN);
2512     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2513                             TNG_MAX_STR_LEN);
2514     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2515                             TNG_MAX_STR_LEN);
2516     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2517                             TNG_MAX_STR_LEN);
2518     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2519                             TNG_MAX_STR_LEN);
2520     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2521                               TNG_MAX_STR_LEN);
2522
2523     if(block->block_contents)
2524     {
2525         free(block->block_contents);
2526     }
2527     block->block_contents = malloc(block->block_contents_size);
2528     if(!block->block_contents)
2529     {
2530         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2531                block->block_contents_size, __FILE__, __LINE__);
2532         tng_block_destroy(&block);
2533         return(TNG_CRITICAL);
2534     }
2535
2536     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
2537     offset += first_program_name_len;
2538
2539     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
2540     offset += last_program_name_len;
2541
2542     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
2543     offset += first_user_name_len;
2544
2545     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
2546     offset += last_user_name_len;
2547
2548     strncpy(block->block_contents+offset, tng_data->first_computer_name,
2549             first_computer_name_len);
2550     offset += first_computer_name_len;
2551
2552     strncpy(block->block_contents+offset, tng_data->last_computer_name,
2553             last_computer_name_len);
2554     offset += last_computer_name_len;
2555
2556     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
2557             first_pgp_signature_len);
2558     offset += first_pgp_signature_len;
2559
2560     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
2561             last_pgp_signature_len);
2562     offset += last_pgp_signature_len;
2563
2564     strncpy(block->block_contents+offset, tng_data->forcefield_name,
2565             forcefield_name_len);
2566     offset += forcefield_name_len;
2567
2568     memcpy(block->block_contents+offset, &tng_data->time,
2569            sizeof(tng_data->time));
2570     if(tng_data->output_endianness_swap_func_64)
2571     {
2572         if(tng_data->output_endianness_swap_func_64(tng_data,
2573                                       (int64_t *)block->header_contents+offset)
2574             != TNG_SUCCESS)
2575         {
2576             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2577                     __FILE__, __LINE__);
2578         }
2579     }
2580     offset += sizeof(tng_data->time);
2581
2582     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
2583            sizeof(tng_data->var_num_atoms_flag));
2584     offset += sizeof(tng_data->var_num_atoms_flag);
2585
2586     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
2587            sizeof(tng_data->frame_set_n_frames));
2588     if(tng_data->output_endianness_swap_func_64)
2589     {
2590         if(tng_data->output_endianness_swap_func_64(tng_data,
2591                                       (int64_t *)block->header_contents+offset)
2592             != TNG_SUCCESS)
2593         {
2594             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2595                     __FILE__, __LINE__);
2596         }
2597     }
2598     offset += sizeof(tng_data->frame_set_n_frames);
2599
2600     memcpy(block->block_contents+offset,
2601            &tng_data->first_trajectory_frame_set_output_file_pos,
2602            sizeof(tng_data->first_trajectory_frame_set_output_file_pos));
2603     if(tng_data->output_endianness_swap_func_64)
2604     {
2605         if(tng_data->output_endianness_swap_func_64(tng_data,
2606                                       (int64_t *)block->header_contents+offset)
2607             != TNG_SUCCESS)
2608         {
2609             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2610                     __FILE__, __LINE__);
2611         }
2612     }
2613     offset += sizeof(tng_data->first_trajectory_frame_set_output_file_pos);
2614
2615     memcpy(block->block_contents+offset,
2616            &tng_data->last_trajectory_frame_set_output_file_pos,
2617            sizeof(tng_data->last_trajectory_frame_set_output_file_pos));
2618     if(tng_data->output_endianness_swap_func_64)
2619     {
2620         if(tng_data->output_endianness_swap_func_64(tng_data,
2621                                       (int64_t *)block->header_contents+offset)
2622             != TNG_SUCCESS)
2623         {
2624             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2625                     __FILE__, __LINE__);
2626         }
2627     }
2628     offset += sizeof(tng_data->last_trajectory_frame_set_output_file_pos);
2629
2630     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
2631            sizeof(tng_data->medium_stride_length));
2632     if(tng_data->output_endianness_swap_func_64)
2633     {
2634         if(tng_data->output_endianness_swap_func_64(tng_data,
2635                                       (int64_t *)block->header_contents+offset)
2636             != TNG_SUCCESS)
2637         {
2638             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2639                     __FILE__, __LINE__);
2640         }
2641     }
2642     offset += sizeof(tng_data->medium_stride_length);
2643
2644     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
2645            sizeof(tng_data->long_stride_length));
2646     if(tng_data->output_endianness_swap_func_64)
2647     {
2648         if(tng_data->output_endianness_swap_func_64(tng_data,
2649                                       (int64_t *)block->header_contents+offset)
2650             != TNG_SUCCESS)
2651         {
2652             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2653                     __FILE__, __LINE__);
2654         }
2655     }
2656     offset += sizeof(tng_data->long_stride_length);
2657
2658     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
2659            sizeof(tng_data->distance_unit_exponential));
2660     if(tng_data->output_endianness_swap_func_64)
2661     {
2662         if(tng_data->output_endianness_swap_func_64(tng_data,
2663                                       (int64_t *)block->header_contents+offset)
2664             != TNG_SUCCESS)
2665         {
2666             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2667                     __FILE__, __LINE__);
2668         }
2669     }
2670
2671     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2672     {
2673         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2674                tng_data->output_file_path, __FILE__, __LINE__);
2675         tng_block_destroy(&block);
2676         return(TNG_CRITICAL);
2677     }
2678
2679     if(fwrite(block->block_contents, block->block_contents_size, 1,
2680         tng_data->output_file) != 1)
2681     {
2682         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
2683         tng_block_destroy(&block);
2684         return(TNG_CRITICAL);
2685     }
2686
2687     tng_block_destroy(&block);
2688
2689     return(TNG_SUCCESS);
2690 }
2691
2692 /** Read the chain data of a molecules block.
2693  * @param tng_data is a trajectory data container.
2694  * @param block is a general block container.
2695  * @param chain is the chain data container.
2696  * @param offset is the offset of the block input and is updated when reading.
2697  * @return TNG_SUCCESS(0) is successful.
2698  */
2699 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
2700                                                tng_gen_block_t block,
2701                                                tng_chain_t chain,
2702                                                int *offset)
2703 {
2704     int len;
2705
2706     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2707
2708     memcpy(&chain->id, block->block_contents+*offset,
2709             sizeof(chain->id));
2710     if(tng_data->input_endianness_swap_func_64)
2711     {
2712         if(tng_data->input_endianness_swap_func_64(tng_data,
2713                                                    &chain->id)
2714             != TNG_SUCCESS)
2715         {
2716             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2717                     __FILE__, __LINE__);
2718         }
2719     }
2720     *offset += sizeof(chain->id);
2721
2722     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2723             TNG_MAX_STR_LEN);
2724     chain->name = malloc(len);
2725     strncpy(chain->name,
2726             block->block_contents+*offset, len);
2727     *offset += len;
2728
2729     memcpy(&chain->n_residues, block->block_contents+*offset,
2730         sizeof(chain->n_residues));
2731     if(tng_data->input_endianness_swap_func_64)
2732     {
2733         if(tng_data->input_endianness_swap_func_64(tng_data,
2734                                                    &chain->n_residues)
2735             != TNG_SUCCESS)
2736         {
2737             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2738                     __FILE__, __LINE__);
2739         }
2740     }
2741     *offset += sizeof(chain->n_residues);
2742
2743     return(TNG_SUCCESS);
2744 }
2745
2746 /** Write the chain data of a molecules block.
2747  * @param tng_data is a trajectory data container.
2748  * @param block is a general block container.
2749  * @param chain is the chain data container.
2750  * @param offset is the offset of the block output and is updated when writing.
2751  * @return TNG_SUCCESS(0) is successful.
2752  */
2753 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
2754                                                 tng_gen_block_t block,
2755                                                 tng_chain_t chain,
2756                                                 int *offset)
2757 {
2758     int len;
2759
2760     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2761
2762     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
2763     if(tng_data->output_endianness_swap_func_64)
2764     {
2765         if(tng_data->output_endianness_swap_func_64(tng_data,
2766                                     (int64_t *)block->header_contents+*offset)
2767             != TNG_SUCCESS)
2768         {
2769             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2770                     __FILE__, __LINE__);
2771         }
2772     }
2773     *offset += sizeof(chain->id);
2774
2775     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2776     strncpy(block->block_contents + *offset, chain->name, len);
2777     *offset += len;
2778
2779     memcpy(block->block_contents+*offset, &chain->n_residues,
2780         sizeof(chain->n_residues));
2781     if(tng_data->output_endianness_swap_func_64)
2782     {
2783         if(tng_data->output_endianness_swap_func_64(tng_data,
2784                                     (int64_t *)block->header_contents+*offset)
2785             != TNG_SUCCESS)
2786         {
2787             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2788                     __FILE__, __LINE__);
2789         }
2790     }
2791     *offset += sizeof(chain->n_residues);
2792
2793     return(TNG_SUCCESS);
2794 }
2795
2796 /** Read the residue data of a molecules block.
2797  * @param tng_data is a trajectory data container.
2798  * @param block is a general block container.
2799  * @param residue is the residue data container.
2800  * @param offset is the offset of the block input and is updated when reading.
2801  * @return TNG_SUCCESS(0) is successful.
2802  */
2803 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
2804                                                  tng_gen_block_t block,
2805                                                  tng_residue_t residue,
2806                                                  int *offset)
2807 {
2808     int len;
2809
2810     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2811
2812     memcpy(&residue->id, block->block_contents+*offset,
2813         sizeof(residue->id));
2814     if(tng_data->input_endianness_swap_func_64)
2815     {
2816         if(tng_data->input_endianness_swap_func_64(tng_data,
2817                                                    &residue->id)
2818             != TNG_SUCCESS)
2819         {
2820             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2821                     __FILE__, __LINE__);
2822         }
2823     }
2824     *offset += sizeof(residue->id);
2825
2826     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2827             TNG_MAX_STR_LEN);
2828     residue->name = malloc(len);
2829     strncpy(residue->name,
2830             block->block_contents+*offset, len);
2831     *offset += len;
2832
2833     memcpy(&residue->n_atoms, block->block_contents+*offset,
2834             sizeof(residue->n_atoms));
2835     if(tng_data->input_endianness_swap_func_64)
2836     {
2837         if(tng_data->input_endianness_swap_func_64(tng_data,
2838                                                    &residue->n_atoms)
2839             != TNG_SUCCESS)
2840         {
2841             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2842                     __FILE__, __LINE__);
2843         }
2844     }
2845     *offset += sizeof(residue->n_atoms);
2846
2847     return(TNG_SUCCESS);
2848 }
2849
2850 /** Write the residue data of a molecules block.
2851  * @param tng_data is a trajectory data container.
2852  * @param block is a general block container.
2853  * @param residue is the residue data container.
2854  * @param offset is the offset of the block output and is updated when writing.
2855  * @return TNG_SUCCESS(0) is successful.
2856  */
2857 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
2858                                                   tng_gen_block_t block,
2859                                                   tng_residue_t residue,
2860                                                   int *offset)
2861 {
2862     int len;
2863
2864     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2865
2866     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
2867     if(tng_data->output_endianness_swap_func_64)
2868     {
2869         if(tng_data->output_endianness_swap_func_64(tng_data,
2870                                     (int64_t *)block->header_contents+*offset)
2871             != TNG_SUCCESS)
2872         {
2873             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2874                     __FILE__, __LINE__);
2875         }
2876     }
2877     *offset += sizeof(residue->id);
2878
2879     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2880     strncpy(block->block_contents + *offset, residue->name, len);
2881     *offset += len;
2882
2883     memcpy(block->block_contents+*offset, &residue->n_atoms,
2884         sizeof(residue->n_atoms));
2885     if(tng_data->output_endianness_swap_func_64)
2886     {
2887         if(tng_data->output_endianness_swap_func_64(tng_data,
2888                                     (int64_t *)block->header_contents+*offset)
2889             != TNG_SUCCESS)
2890         {
2891             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2892                     __FILE__, __LINE__);
2893         }
2894     }
2895     *offset += sizeof(residue->n_atoms);
2896
2897     return(TNG_SUCCESS);
2898 }
2899
2900 /** Read the atom data of a molecules block.
2901  * @param tng_data is a trajectory data container.
2902  * @param block is a general block container.
2903  * @param atom is the atom data container.
2904  * @param offset is the offset of the block input and is updated when reading.
2905  * @return TNG_SUCCESS(0) is successful.
2906  */
2907 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2908                                               tng_gen_block_t block,
2909                                               tng_atom_t atom,
2910                                               int *offset)
2911 {
2912     int len;
2913
2914     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2915
2916     memcpy(&atom->id, block->block_contents+*offset,
2917         sizeof(atom->id));
2918     if(tng_data->input_endianness_swap_func_64)
2919     {
2920         if(tng_data->input_endianness_swap_func_64(tng_data,
2921                                                     &atom->id)
2922             != TNG_SUCCESS)
2923         {
2924             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2925                     __FILE__, __LINE__);
2926         }
2927     }
2928     *offset += sizeof(atom->id);
2929
2930     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2931             TNG_MAX_STR_LEN);
2932     atom->name = malloc(len);
2933     strncpy(atom->name,
2934             block->block_contents+*offset, len);
2935     *offset += len;
2936
2937     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2938             TNG_MAX_STR_LEN);
2939     atom->atom_type = malloc(len);
2940     strncpy(atom->atom_type,
2941             block->block_contents+*offset, len);
2942     *offset += len;
2943
2944     return(TNG_SUCCESS);
2945 }
2946
2947 /** Write the atom data of a molecules block.
2948  * @param tng_data is a trajectory data container.
2949  * @param block is a general block container.
2950  * @param atom is the atom data container.
2951  * @param offset is the offset of the block output and is updated when writing.
2952  * @return TNG_SUCCESS(0) is successful.
2953  */
2954 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2955                                                tng_gen_block_t block,
2956                                                tng_atom_t atom,
2957                                                int *offset)
2958 {
2959     int len;
2960
2961     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2962
2963     memcpy(block->block_contents+*offset, &atom->id,
2964             sizeof(atom->id));
2965     if(tng_data->output_endianness_swap_func_64)
2966     {
2967         if(tng_data->output_endianness_swap_func_64(tng_data,
2968                                     (int64_t *)block->header_contents+*offset)
2969             != TNG_SUCCESS)
2970         {
2971             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2972                     __FILE__, __LINE__);
2973         }
2974     }
2975     *offset += sizeof(atom->id);
2976
2977     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2978     strncpy(block->block_contents + *offset, atom->name, len);
2979     *offset += len;
2980
2981     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2982     strncpy(block->block_contents + *offset, atom->atom_type, len);
2983     *offset += len;
2984
2985     return(TNG_SUCCESS);
2986 }
2987
2988 static tng_function_status tng_molecules_block_len_calculate
2989                 (const tng_trajectory_t tng_data,
2990                  int64_t *len)
2991 {
2992     int64_t i, j;
2993     tng_molecule_t molecule;
2994     tng_chain_t chain;
2995     tng_residue_t residue;
2996     tng_atom_t atom;
2997     tng_bond_t bond;
2998
2999     *len = 0;
3000
3001     for(i = 0; i < tng_data->n_molecules; i++)
3002     {
3003         molecule = &tng_data->molecules[i];
3004         if(!molecule->name)
3005         {
3006             molecule->name = malloc(1);
3007             if(!molecule->name)
3008             {
3009                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3010                        __FILE__, __LINE__);
3011                 return(TNG_CRITICAL);
3012             }
3013             molecule->name[0] = 0;
3014         }
3015         *len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3016
3017         chain = molecule->chains;
3018         for(j = 0; j < molecule->n_chains; j++)
3019         {
3020             *len += sizeof(chain->id);
3021
3022             if(!chain->name)
3023             {
3024                 chain->name = malloc(1);
3025                 if(!chain->name)
3026                 {
3027                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3028                            __FILE__, __LINE__);
3029                     return(TNG_CRITICAL);
3030                 }
3031                 chain->name[0] = 0;
3032             }
3033             *len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
3034
3035             *len += sizeof(chain->n_residues);
3036
3037             chain++;
3038         }
3039
3040         residue = molecule->residues;
3041         for(j = 0; j < molecule->n_residues; j++)
3042         {
3043             *len += sizeof(residue->id);
3044
3045             if(!residue->name)
3046             {
3047                 residue->name = malloc(1);
3048                 if(!residue->name)
3049                 {
3050                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3051                            __FILE__, __LINE__);
3052                     return(TNG_CRITICAL);
3053                 }
3054                 residue->name[0] = 0;
3055             }
3056             *len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
3057
3058             *len += sizeof(residue->n_atoms);
3059
3060             residue++;
3061         }
3062
3063         atom = molecule->atoms;
3064         for(j = 0; j < molecule->n_atoms; j++)
3065         {
3066             *len += sizeof(atom->id);
3067             if(!atom->name)
3068             {
3069                 atom->name = malloc(1);
3070                 if(!atom->name)
3071                 {
3072                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3073                            __FILE__, __LINE__);
3074                     return(TNG_CRITICAL);
3075                 }
3076                 atom->name[0] = 0;
3077             }
3078             *len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
3079
3080             if(!atom->atom_type)
3081             {
3082                 atom->atom_type = malloc(1);
3083                 if(!atom->atom_type)
3084                 {
3085                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3086                            __FILE__, __LINE__);
3087                     return(TNG_CRITICAL);
3088                 }
3089                 atom->atom_type[0] = 0;
3090             }
3091             *len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
3092
3093             atom++;
3094         }
3095
3096         for(j = 0; j < molecule->n_bonds; j++)
3097         {
3098             *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
3099         }
3100     }
3101     *len += sizeof(tng_data->n_molecules) +
3102             (sizeof(molecule->id) +
3103             sizeof(molecule->quaternary_str) +
3104             sizeof(molecule->n_chains) +
3105             sizeof(molecule->n_residues) +
3106             sizeof(molecule->n_atoms) +
3107             sizeof(molecule->n_bonds)) *
3108             tng_data->n_molecules;
3109
3110     if(!tng_data->var_num_atoms_flag)
3111     {
3112         *len += tng_data->n_molecules * sizeof(int64_t);
3113     }
3114
3115     return(TNG_SUCCESS);
3116 }
3117
3118 /** Read a molecules block. Contains chain, residue and atom data
3119  * @param tng_data is a trajectory data container.
3120  * @param block is a general block container.
3121  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3122  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3123  * compared to the md5 hash of the read contents to ensure valid data.
3124  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3125  * error has occured.
3126  */
3127 static tng_function_status tng_molecules_block_read
3128                 (tng_trajectory_t tng_data,
3129                  tng_gen_block_t block,
3130                  const char hash_mode)
3131 {
3132     int64_t i, j, k, l;
3133     int len, offset = 0;
3134     tng_molecule_t molecule;
3135     tng_chain_t chain;
3136     tng_residue_t residue;
3137     tng_atom_t atom;
3138     tng_bond_t bond;
3139     tng_bool same_hash;
3140
3141     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3142     {
3143         return(TNG_CRITICAL);
3144     }
3145
3146     if(block->block_contents)
3147     {
3148         free(block->block_contents);
3149     }
3150
3151     block->block_contents = malloc(block->block_contents_size);
3152     if(!block->block_contents)
3153     {
3154         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3155                block->block_contents_size, __FILE__, __LINE__);
3156         return(TNG_CRITICAL);
3157     }
3158
3159     /* Read the whole block into block_contents to be able to write it to disk
3160      * even if it cannot be interpreted. */
3161     if(fread(block->block_contents, block->block_contents_size, 1,
3162              tng_data->input_file) == 0)
3163     {
3164         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3165     }
3166
3167     /* FIXME: Does not check if the size of the contents matches the expected
3168      * size or if the contents can be read. */
3169
3170     if(hash_mode == TNG_USE_HASH)
3171     {
3172         tng_md5_hash_match_verify(block, &same_hash);
3173         if(same_hash != TNG_TRUE)
3174         {
3175             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3176                 "%s: %d\n",
3177                 __FILE__, __LINE__);
3178         }
3179     }
3180
3181     if(tng_data->molecules)
3182     {
3183         for(i=0; i<tng_data->n_molecules; i++)
3184         {
3185             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
3186         }
3187         free(tng_data->molecules);
3188         tng_data->molecules = 0;
3189         tng_data->n_molecules = 0;
3190     }
3191
3192     memcpy(&tng_data->n_molecules, block->block_contents,
3193            sizeof(tng_data->n_molecules));
3194     if(tng_data->input_endianness_swap_func_64)
3195     {
3196         if(tng_data->input_endianness_swap_func_64(tng_data,
3197                                                    &tng_data->n_molecules)
3198             != TNG_SUCCESS)
3199         {
3200             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3201                     __FILE__, __LINE__);
3202         }
3203     }
3204     offset += sizeof(tng_data->n_molecules);
3205
3206     if(tng_data->molecules)
3207     {
3208         free(tng_data->molecules);
3209     }
3210
3211     tng_data->n_particles = 0;
3212
3213     tng_data->molecules = malloc(tng_data->n_molecules *
3214                           sizeof(struct tng_molecule));
3215     if(!tng_data->molecules)
3216     {
3217         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3218                tng_data->n_molecules * sizeof(struct tng_molecule),
3219                __FILE__, __LINE__);
3220         return(TNG_CRITICAL);
3221     }
3222
3223     if(!tng_data->var_num_atoms_flag)
3224     {
3225         if(tng_data->molecule_cnt_list)
3226         {
3227             free(tng_data->molecule_cnt_list);
3228         }
3229         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
3230                                       tng_data->n_molecules);
3231         if(!tng_data->molecule_cnt_list)
3232         {
3233             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3234                    tng_data->n_molecules * sizeof(struct tng_molecule),
3235                    __FILE__, __LINE__);
3236             return(TNG_CRITICAL);
3237         }
3238     }
3239
3240     /* Read each molecule from file */
3241     for(i=0; i < tng_data->n_molecules; i++)
3242     {
3243         molecule = &tng_data->molecules[i];
3244
3245         memcpy(&molecule->id, block->block_contents+offset,
3246                sizeof(molecule->id));
3247         if(tng_data->input_endianness_swap_func_64)
3248         {
3249             if(tng_data->input_endianness_swap_func_64(tng_data,
3250                                                        &molecule->id)
3251                 != TNG_SUCCESS)
3252             {
3253                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3254                         __FILE__, __LINE__);
3255             }
3256         }
3257         offset += sizeof(molecule->id);
3258
3259 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
3260         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
3261         molecule->name = malloc(len);
3262         strncpy(molecule->name, block->block_contents+offset, len);
3263         offset += len;
3264
3265         memcpy(&molecule->quaternary_str, block->block_contents+offset,
3266                sizeof(molecule->quaternary_str));
3267         if(tng_data->input_endianness_swap_func_64)
3268         {
3269             if(tng_data->input_endianness_swap_func_64(tng_data,
3270                                                      &molecule->quaternary_str)
3271                 != TNG_SUCCESS)
3272             {
3273                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3274                         __FILE__, __LINE__);
3275             }
3276         }
3277         offset += sizeof(molecule->quaternary_str);
3278
3279         if(!tng_data->var_num_atoms_flag)
3280         {
3281             memcpy(&tng_data->molecule_cnt_list[i],
3282                    block->block_contents+offset,
3283                    sizeof(int64_t));
3284             if(tng_data->input_endianness_swap_func_64)
3285             {
3286                 if(tng_data->input_endianness_swap_func_64(tng_data,
3287                                                &tng_data->molecule_cnt_list[i])
3288                     != TNG_SUCCESS)
3289                 {
3290                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3291                             __FILE__, __LINE__);
3292                 }
3293             }
3294             offset += sizeof(int64_t);
3295         }
3296
3297
3298         memcpy(&molecule->n_chains, block->block_contents+offset,
3299                sizeof(molecule->n_chains));
3300         if(tng_data->input_endianness_swap_func_64)
3301         {
3302             if(tng_data->input_endianness_swap_func_64(tng_data,
3303                                                        &molecule->n_chains)
3304                 != TNG_SUCCESS)
3305             {
3306                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3307                         __FILE__, __LINE__);
3308             }
3309         }
3310         offset += sizeof(molecule->n_chains);
3311
3312         memcpy(&molecule->n_residues, block->block_contents+offset,
3313                sizeof(molecule->n_residues));
3314         if(tng_data->input_endianness_swap_func_64)
3315         {
3316             if(tng_data->input_endianness_swap_func_64(tng_data,
3317                                                        &molecule->n_residues)
3318                 != TNG_SUCCESS)
3319             {
3320                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3321                         __FILE__, __LINE__);
3322             }
3323         }
3324         offset += sizeof(molecule->n_residues);
3325
3326         memcpy(&molecule->n_atoms, block->block_contents+offset,
3327                sizeof(molecule->n_atoms));
3328         if(tng_data->input_endianness_swap_func_64)
3329         {
3330             if(tng_data->input_endianness_swap_func_64(tng_data,
3331                                                        &molecule->n_atoms)
3332                 != TNG_SUCCESS)
3333             {
3334                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3335                         __FILE__, __LINE__);
3336             }
3337         }
3338         offset += sizeof(molecule->n_atoms);
3339
3340         tng_data->n_particles += molecule->n_atoms *
3341                                  tng_data->molecule_cnt_list[i];
3342
3343         if(molecule->n_chains > 0)
3344         {
3345             molecule->chains = malloc(molecule->n_chains *
3346                                     sizeof(struct tng_chain));
3347             if(!molecule->chains)
3348             {
3349                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3350                     molecule->n_chains * sizeof(struct tng_chain),
3351                     __FILE__, __LINE__);
3352                 return(TNG_CRITICAL);
3353             }
3354
3355             chain = molecule->chains;
3356         }
3357         else
3358         {
3359             chain = 0;
3360         }
3361
3362         if(molecule->n_residues > 0)
3363         {
3364             molecule->residues = malloc(molecule->n_residues *
3365                                 sizeof(struct tng_residue));
3366             if(!molecule->residues)
3367             {
3368                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3369                     molecule->n_residues * sizeof(struct tng_residue),
3370                     __FILE__, __LINE__);
3371                 if(molecule->chains)
3372                 {
3373                     free(molecule->chains);
3374                     molecule->chains = 0;
3375                 }
3376                 return(TNG_CRITICAL);
3377             }
3378
3379             residue = molecule->residues;
3380         }
3381         else
3382         {
3383             residue = 0;
3384         }
3385
3386         molecule->atoms = malloc(molecule->n_atoms *
3387                                  sizeof(struct tng_atom));
3388         if(!molecule->atoms)
3389         {
3390             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3391                    molecule->n_atoms * sizeof(struct tng_atom),
3392                    __FILE__, __LINE__);
3393             if(molecule->chains)
3394             {
3395                 free(molecule->chains);
3396                 molecule->chains = 0;
3397             }
3398             if(molecule->residues)
3399             {
3400                 free(molecule->residues);
3401                 molecule->residues = 0;
3402             }
3403             return(TNG_CRITICAL);
3404         }
3405
3406         atom = molecule->atoms;
3407
3408         if(molecule->n_chains > 0)
3409         {
3410             /* Read the chains of the molecule */
3411             for(j=0; j<molecule->n_chains; j++)
3412             {
3413                 chain->molecule = molecule;
3414
3415                 tng_chain_data_read(tng_data, block, chain, &offset);
3416
3417                 chain->residues = molecule->residues;
3418                 residue = chain->residues;
3419
3420                 /* Read the residues of the chain */
3421                 for(k=0; k<chain->n_residues; k++)
3422                 {
3423                     residue->chain = chain;
3424
3425                     tng_residue_data_read(tng_data, block, residue, &offset);
3426
3427                     residue->atoms_offset = atom - molecule->atoms;
3428                     /* Read the atoms of the residue */
3429                     for(l=0; l<residue->n_atoms; l++)
3430                     {
3431                         atom->residue = residue;
3432
3433                         tng_atom_data_read(tng_data, block, atom, &offset);
3434
3435                         atom++;
3436                     }
3437                     residue++;
3438                 }
3439                 chain++;
3440             }
3441         }
3442         else
3443         {
3444             if(molecule->n_residues > 0)
3445             {
3446                 for(k=0; k<molecule->n_residues; k++)
3447                 {
3448                     residue->chain = 0;
3449
3450                     tng_residue_data_read(tng_data, block, residue, &offset);
3451
3452                     residue->atoms_offset = atom - molecule->atoms;
3453                     /* Read the atoms of the residue */
3454                     for(l=0; l<residue->n_atoms; l++)
3455                     {
3456                         atom->residue = residue;
3457
3458                         tng_atom_data_read(tng_data, block, atom, &offset);
3459
3460                         atom++;
3461                     }
3462                     residue++;
3463                 }
3464             }
3465             else
3466             {
3467                 for(l=0; l<molecule->n_atoms; l++)
3468                 {
3469                     atom->residue = 0;
3470
3471                     tng_atom_data_read(tng_data, block, atom, &offset);
3472
3473                     atom++;
3474                 }
3475             }
3476         }
3477
3478         memcpy(&molecule->n_bonds, block->block_contents+offset,
3479                sizeof(molecule->n_bonds));
3480         if(tng_data->input_endianness_swap_func_64)
3481         {
3482             if(tng_data->input_endianness_swap_func_64(tng_data,
3483                                                        &molecule->n_bonds)
3484                 != TNG_SUCCESS)
3485             {
3486                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3487                         __FILE__, __LINE__);
3488             }
3489         }
3490         offset += sizeof(molecule->n_bonds);
3491
3492         if(molecule->n_bonds > 0)
3493         {
3494             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
3495                                            sizeof(struct tng_bond));
3496             if(!molecule->bonds)
3497             {
3498                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3499                        molecule->n_bonds * sizeof(struct tng_bond),
3500                        __FILE__, __LINE__);
3501                 if(molecule->chains)
3502                 {
3503                     free(molecule->chains);
3504                     molecule->chains = 0;
3505                 }
3506                 if(molecule->residues)
3507                 {
3508                     free(molecule->residues);
3509                     molecule->residues = 0;
3510                 }
3511                 if(molecule->atoms)
3512                 {
3513                     free(molecule->atoms);
3514                     molecule->atoms = 0;
3515                 }
3516                 return(TNG_CRITICAL);
3517             }
3518
3519             bond = molecule->bonds;
3520
3521             for(j=0; j<molecule->n_bonds; j++)
3522             {
3523                 memcpy(&bond->from_atom_id, block->block_contents+offset,
3524                     sizeof(bond->from_atom_id));
3525                 if(tng_data->input_endianness_swap_func_64)
3526                 {
3527                     if(tng_data->input_endianness_swap_func_64(tng_data,
3528                                                                &bond->from_atom_id)
3529                         != TNG_SUCCESS)
3530                     {
3531                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3532                                 __FILE__, __LINE__);
3533                     }
3534                 }
3535                 offset += sizeof(bond->from_atom_id);
3536
3537                 memcpy(&bond->to_atom_id, block->block_contents+offset,
3538                     sizeof(bond->to_atom_id));
3539                 if(tng_data->input_endianness_swap_func_64)
3540                 {
3541                     if(tng_data->input_endianness_swap_func_64(tng_data,
3542                                                                &bond->to_atom_id)
3543                         != TNG_SUCCESS)
3544                     {
3545                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3546                                 __FILE__, __LINE__);
3547                     }
3548                 }
3549                 offset += sizeof(bond->to_atom_id);
3550
3551                 bond++;
3552             }
3553         }
3554         else
3555         {
3556             molecule->bonds = 0;
3557         }
3558     }
3559
3560     return(TNG_SUCCESS);
3561 }
3562
3563 /** Write a molecules block.
3564  * @param tng_data is a trajectory data container.
3565  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3566  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3567  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3568  * error has occured.
3569  */
3570 static tng_function_status tng_molecules_block_write
3571                 (tng_trajectory_t tng_data,
3572                  const char hash_mode)
3573 {
3574     int len = 0, name_len, offset = 0;
3575     int64_t i, j, k, l;
3576     tng_molecule_t molecule;
3577     tng_chain_t chain;
3578     tng_residue_t residue;
3579     tng_atom_t atom;
3580     tng_bond_t bond;
3581     tng_gen_block_t block;
3582
3583     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3584     {
3585         return(TNG_CRITICAL);
3586     }
3587
3588     tng_block_init(&block);
3589
3590     name_len = (int)strlen("MOLECULES");
3591
3592     block->name = malloc(name_len + 1);
3593     if(!block->name)
3594     {
3595         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3596                 name_len+1, __FILE__, __LINE__);
3597         tng_block_destroy(&block);
3598         return(TNG_CRITICAL);
3599     }
3600
3601     strcpy(block->name, "MOLECULES");
3602     block->id = TNG_MOLECULES;
3603
3604     if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3605         TNG_SUCCESS)
3606     {
3607         fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3608                 __FILE__, __LINE__);
3609         tng_block_destroy(&block);
3610         return(TNG_CRITICAL);
3611     }
3612
3613     block->block_contents = malloc(block->block_contents_size);
3614     if(!block->block_contents)
3615     {
3616         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3617                block->block_contents_size, __FILE__, __LINE__);
3618         tng_block_destroy(&block);
3619         return(TNG_CRITICAL);
3620     }
3621
3622     memcpy(block->block_contents+offset, &tng_data->n_molecules,
3623            sizeof(tng_data->n_molecules));
3624     if(tng_data->output_endianness_swap_func_64)
3625     {
3626         if(tng_data->output_endianness_swap_func_64(tng_data,
3627                                       (int64_t *)block->header_contents+offset)
3628             != TNG_SUCCESS)
3629         {
3630             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3631                     __FILE__, __LINE__);
3632         }
3633     }
3634     offset += sizeof(tng_data->n_molecules);
3635
3636     for(i = 0; i < tng_data->n_molecules; i++)
3637     {
3638         molecule = &tng_data->molecules[i];
3639         memcpy(block->block_contents+offset, &molecule->id,
3640                sizeof(molecule->id));
3641         if(tng_data->output_endianness_swap_func_64)
3642         {
3643             if(tng_data->output_endianness_swap_func_64(tng_data,
3644                                         (int64_t *)block->header_contents+offset)
3645                 != TNG_SUCCESS)
3646             {
3647                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3648                         __FILE__, __LINE__);
3649             }
3650         }
3651         offset += sizeof(molecule->id);
3652
3653 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
3654         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3655         strncpy(block->block_contents + offset, molecule->name, len);
3656         offset += len;
3657
3658         memcpy(block->block_contents+offset, &molecule->quaternary_str,
3659                sizeof(molecule->quaternary_str));
3660         if(tng_data->output_endianness_swap_func_64)
3661         {
3662             if(tng_data->output_endianness_swap_func_64(tng_data,
3663                                         (int64_t *)block->header_contents+offset)
3664                 != TNG_SUCCESS)
3665             {
3666                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3667                         __FILE__, __LINE__);
3668             }
3669         }
3670         offset += sizeof(molecule->quaternary_str);
3671
3672         if(!tng_data->var_num_atoms_flag)
3673         {
3674             memcpy(block->block_contents+offset,
3675                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
3676             if(tng_data->output_endianness_swap_func_64)
3677             {
3678                 if(tng_data->output_endianness_swap_func_64(tng_data,
3679                                             (int64_t *)block->header_contents+offset)
3680                     != TNG_SUCCESS)
3681                 {
3682                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3683                             __FILE__, __LINE__);
3684                 }
3685             }
3686             offset += sizeof(int64_t);
3687         }
3688
3689         memcpy(block->block_contents+offset, &molecule->n_chains,
3690                sizeof(molecule->n_chains));
3691         if(tng_data->output_endianness_swap_func_64)
3692         {
3693             if(tng_data->output_endianness_swap_func_64(tng_data,
3694                                         (int64_t *)block->header_contents+offset)
3695                 != TNG_SUCCESS)
3696             {
3697                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3698                         __FILE__, __LINE__);
3699             }
3700         }
3701         offset += sizeof(molecule->n_chains);
3702
3703         memcpy(block->block_contents+offset, &molecule->n_residues,
3704                sizeof(molecule->n_residues));
3705         if(tng_data->output_endianness_swap_func_64)
3706         {
3707             if(tng_data->output_endianness_swap_func_64(tng_data,
3708                                         (int64_t *)block->header_contents+offset)
3709                 != TNG_SUCCESS)
3710             {
3711                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3712                         __FILE__, __LINE__);
3713             }
3714         }
3715         offset += sizeof(molecule->n_residues);
3716
3717         memcpy(block->block_contents+offset, &molecule->n_atoms,
3718                sizeof(molecule->n_atoms));
3719         if(tng_data->output_endianness_swap_func_64)
3720         {
3721             if(tng_data->output_endianness_swap_func_64(tng_data,
3722                                         (int64_t *)block->header_contents+offset)
3723                 != TNG_SUCCESS)
3724             {
3725                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3726                         __FILE__, __LINE__);
3727             }
3728         }
3729         offset += sizeof(molecule->n_atoms);
3730
3731         if(molecule->n_chains > 0)
3732         {
3733             chain = molecule->chains;
3734             for(j = 0; j < molecule->n_chains; j++)
3735             {
3736                 tng_chain_data_write(tng_data, block, chain, &offset);
3737
3738                 residue = chain->residues;
3739                 for(k = 0; k < chain->n_residues; k++)
3740                 {
3741                     tng_residue_data_write(tng_data, block, residue, &offset);
3742
3743                     atom = molecule->atoms + residue->atoms_offset;
3744                     for(l = 0; l < residue->n_atoms; l++)
3745                     {
3746                         tng_atom_data_write(tng_data, block, atom, &offset);
3747
3748                         atom++;
3749                     }
3750                     residue++;
3751                 }
3752                 chain++;
3753             }
3754         }
3755         else
3756         {
3757             if(molecule->n_residues > 0)
3758             {
3759                 residue = molecule->residues;
3760                 for(k = 0; k < molecule->n_residues; k++)
3761                 {
3762                     tng_residue_data_write(tng_data, block, residue, &offset);
3763
3764                     atom = molecule->atoms + residue->atoms_offset;
3765                     for(l = 0; l < residue->n_atoms; l++)
3766                     {
3767                         tng_atom_data_write(tng_data, block, atom, &offset);
3768
3769                         atom++;
3770                     }
3771                     residue++;
3772                 }
3773             }
3774             else
3775             {
3776                 atom = molecule->atoms;
3777                 for(l = 0; l < molecule->n_atoms; l++)
3778                 {
3779                     tng_atom_data_write(tng_data, block, atom, &offset);
3780
3781                     atom++;
3782                 }
3783             }
3784         }
3785
3786         memcpy(block->block_contents+offset, &molecule->n_bonds,
3787                sizeof(molecule->n_bonds));
3788         if(tng_data->output_endianness_swap_func_64)
3789         {
3790             if(tng_data->output_endianness_swap_func_64(tng_data,
3791                                         (int64_t *)block->header_contents+offset)
3792                 != TNG_SUCCESS)
3793             {
3794                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3795                         __FILE__, __LINE__);
3796             }
3797         }
3798         offset += sizeof(molecule->n_bonds);
3799
3800         bond = molecule->bonds;
3801         for(j = 0; j < molecule->n_bonds; j++)
3802         {
3803             memcpy(block->block_contents+offset, &bond->from_atom_id,
3804                    sizeof(bond->from_atom_id));
3805             if(tng_data->output_endianness_swap_func_64)
3806             {
3807                 if(tng_data->output_endianness_swap_func_64(tng_data,
3808                                             (int64_t *)block->header_contents+offset)
3809                     != TNG_SUCCESS)
3810                 {
3811                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3812                             __FILE__, __LINE__);
3813                 }
3814             }
3815             offset += sizeof(bond->from_atom_id);
3816
3817             memcpy(block->block_contents+offset, &bond->to_atom_id,
3818                    sizeof(bond->to_atom_id));
3819             if(tng_data->output_endianness_swap_func_64)
3820             {
3821                 if(tng_data->output_endianness_swap_func_64(tng_data,
3822                                             (int64_t *)block->header_contents+offset)
3823                     != TNG_SUCCESS)
3824                 {
3825                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3826                             __FILE__, __LINE__);
3827                 }
3828             }
3829             offset += sizeof(bond->to_atom_id);
3830
3831             bond++;
3832         }
3833     }
3834
3835     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3836     {
3837         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3838                tng_data->output_file_path, __FILE__, __LINE__);
3839         tng_block_destroy(&block);
3840         return(TNG_CRITICAL);
3841     }
3842
3843     if(fwrite(block->block_contents, block->block_contents_size, 1,
3844               tng_data->output_file) != 1)
3845     {
3846         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
3847                __FILE__, __LINE__);
3848         tng_block_destroy(&block);
3849         return(TNG_CRITICAL);
3850     }
3851
3852     tng_block_destroy(&block);
3853
3854     return(TNG_SUCCESS);
3855 }
3856
3857 static tng_function_status tng_frame_set_block_len_calculate
3858                 (const tng_trajectory_t tng_data,
3859                  int64_t *len)
3860 {
3861     *len = sizeof(int64_t) * 8;
3862     *len += sizeof(double) * 2;
3863
3864     if(tng_data->var_num_atoms_flag)
3865     {
3866         *len += sizeof(int64_t) * tng_data->n_molecules;
3867     }
3868     return(TNG_SUCCESS);
3869 }
3870
3871 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
3872  * @param tng_data is a trajectory data container.
3873  * @param block is a general block container.
3874  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3875  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3876  * compared to the md5 hash of the read contents to ensure valid data.
3877  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3878  * error has occured.
3879  */
3880 static tng_function_status tng_frame_set_block_read
3881                 (tng_trajectory_t tng_data,
3882                  tng_gen_block_t block,
3883                  const char hash_mode)
3884 {
3885     int offset = 0;
3886     int64_t file_pos, i, prev_n_particles;
3887     tng_bool same_hash;
3888     tng_trajectory_frame_set_t frame_set =
3889     &tng_data->current_trajectory_frame_set;
3890
3891     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3892     {
3893         return(TNG_CRITICAL);
3894     }
3895
3896     if(block->block_contents)
3897     {
3898         free(block->block_contents);
3899     }
3900
3901     block->block_contents = malloc(block->block_contents_size);
3902     if(!block->block_contents)
3903     {
3904         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3905                block->block_contents_size, __FILE__, __LINE__);
3906         return(TNG_CRITICAL);
3907     }
3908
3909     /* Read the whole block into block_contents to be able to write it to
3910      * disk even if it cannot be interpreted. */
3911     if(fread(block->block_contents, block->block_contents_size, 1,
3912              tng_data->input_file) == 0)
3913     {
3914         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3915         return(TNG_CRITICAL);
3916     }
3917
3918     /* FIXME: Does not check if the size of the contents matches the expected
3919      * size or if the contents can be read. */
3920
3921     file_pos = (int64_t)ftello(tng_data->input_file) -
3922                (block->block_contents_size + block->header_contents_size);
3923
3924     if(hash_mode == TNG_USE_HASH)
3925     {
3926         tng_md5_hash_match_verify(block, &same_hash);
3927         if(same_hash != TNG_TRUE)
3928         {
3929             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %"PRId64" Hashes do not match. "
3930                 "%s: %d\n",
3931                 file_pos, __FILE__, __LINE__);
3932     /*         return(TNG_FAILURE); */
3933         }
3934     }
3935
3936     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3937
3938     tng_frame_set_particle_mapping_free(tng_data);
3939
3940     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3941     {
3942         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3943     }
3944     /* FIXME: Should check the frame number instead of the file_pos, in case
3945      * frame sets are not in order */
3946     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3947     {
3948         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3949     }
3950
3951     memcpy(&frame_set->first_frame, block->block_contents,
3952            sizeof(frame_set->first_frame));
3953     if(tng_data->input_endianness_swap_func_64)
3954     {
3955         if(tng_data->input_endianness_swap_func_64(tng_data,
3956                                                    &frame_set->first_frame)
3957             != TNG_SUCCESS)
3958         {
3959             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3960                     __FILE__, __LINE__);
3961         }
3962     }
3963     offset += sizeof(frame_set->first_frame);
3964
3965     memcpy(&frame_set->n_frames, block->block_contents + offset,
3966            sizeof(frame_set->n_frames));
3967     if(tng_data->input_endianness_swap_func_64)
3968     {
3969         if(tng_data->input_endianness_swap_func_64(tng_data,
3970                                                    &frame_set->n_frames)
3971             != TNG_SUCCESS)
3972         {
3973             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3974                     __FILE__, __LINE__);
3975         }
3976     }
3977     offset += sizeof(frame_set->n_frames);
3978
3979     if(tng_data->var_num_atoms_flag)
3980     {
3981         prev_n_particles = frame_set->n_particles;
3982         frame_set->n_particles = 0;
3983         /* If the list of molecule counts has already been created assume that
3984          * it is of correct size. */
3985         if(!frame_set->molecule_cnt_list)
3986         {
3987                 frame_set->molecule_cnt_list =
3988                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3989
3990                 if(!frame_set->molecule_cnt_list)
3991                 {
3992                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3993                            sizeof(int64_t) * tng_data->n_molecules,
3994                            __FILE__, __LINE__);
3995                     return(TNG_CRITICAL);
3996                 }
3997         }
3998         for(i = 0; i < tng_data->n_molecules; i++)
3999         {
4000             memcpy(&frame_set->molecule_cnt_list[i],
4001                    block->block_contents + offset,
4002                    sizeof(int64_t));
4003             if(tng_data->input_endianness_swap_func_64)
4004             {
4005                 if(tng_data->input_endianness_swap_func_64(tng_data,
4006                                               &frame_set->molecule_cnt_list[i])
4007                     != TNG_SUCCESS)
4008                 {
4009                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4010                             __FILE__, __LINE__);
4011                 }
4012             }
4013             offset += sizeof(int64_t);
4014             frame_set->n_particles += tng_data->molecules[i].n_atoms *
4015                                       frame_set->molecule_cnt_list[i];
4016         }
4017         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
4018         {
4019             /* FIXME: Particle dependent data memory management */
4020         }
4021     }
4022
4023     memcpy(&frame_set->next_frame_set_file_pos,
4024            block->block_contents + offset,
4025            sizeof(frame_set->next_frame_set_file_pos));
4026     if(tng_data->input_endianness_swap_func_64)
4027     {
4028         if(tng_data->input_endianness_swap_func_64(tng_data,
4029                                            &frame_set->next_frame_set_file_pos)
4030             != TNG_SUCCESS)
4031         {
4032             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4033                     __FILE__, __LINE__);
4034         }
4035     }
4036     offset += sizeof(frame_set->next_frame_set_file_pos);
4037
4038     memcpy(&frame_set->prev_frame_set_file_pos,
4039            block->block_contents + offset,
4040            sizeof(frame_set->prev_frame_set_file_pos));
4041     if(tng_data->input_endianness_swap_func_64)
4042     {
4043         if(tng_data->input_endianness_swap_func_64(tng_data,
4044                                            &frame_set->prev_frame_set_file_pos)
4045             != TNG_SUCCESS)
4046         {
4047             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4048                     __FILE__, __LINE__);
4049         }
4050     }
4051     offset += sizeof(frame_set->prev_frame_set_file_pos);
4052
4053     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
4054            block->block_contents + offset,
4055            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4056     if(tng_data->input_endianness_swap_func_64)
4057     {
4058         if(tng_data->input_endianness_swap_func_64(tng_data,
4059                              &frame_set->medium_stride_next_frame_set_file_pos)
4060             != TNG_SUCCESS)
4061         {
4062             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4063                     __FILE__, __LINE__);
4064         }
4065     }
4066     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4067
4068     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
4069            block->block_contents + offset,
4070            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4071     if(tng_data->input_endianness_swap_func_64)
4072     {
4073         if(tng_data->input_endianness_swap_func_64(tng_data,
4074                              &frame_set->medium_stride_prev_frame_set_file_pos)
4075             != TNG_SUCCESS)
4076         {
4077             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4078                     __FILE__, __LINE__);
4079         }
4080     }
4081     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4082
4083     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
4084            block->block_contents + offset,
4085            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4086     if(tng_data->input_endianness_swap_func_64)
4087     {
4088         if(tng_data->input_endianness_swap_func_64(tng_data,
4089                                &frame_set->long_stride_next_frame_set_file_pos)
4090             != TNG_SUCCESS)
4091         {
4092             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4093                     __FILE__, __LINE__);
4094         }
4095     }
4096     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4097
4098     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
4099            block->block_contents + offset,
4100            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4101     if(tng_data->input_endianness_swap_func_64)
4102     {
4103         if(tng_data->input_endianness_swap_func_64(tng_data,
4104                                &frame_set->long_stride_prev_frame_set_file_pos)
4105             != TNG_SUCCESS)
4106         {
4107             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4108                     __FILE__, __LINE__);
4109         }
4110     }
4111     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4112
4113     if(block->block_version >= 3)
4114     {
4115         memcpy(&frame_set->first_frame_time,
4116             block->block_contents + offset,
4117             sizeof(frame_set->first_frame_time));
4118         if(tng_data->input_endianness_swap_func_64)
4119         {
4120             if(tng_data->input_endianness_swap_func_64(tng_data,
4121                                 (int64_t *)&frame_set->first_frame_time)
4122                 != TNG_SUCCESS)
4123             {
4124                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4125                         __FILE__, __LINE__);
4126             }
4127         }
4128         offset += sizeof(frame_set->first_frame_time);
4129
4130         memcpy(&tng_data->time_per_frame,
4131             block->block_contents + offset,
4132             sizeof(tng_data->time_per_frame));
4133         if(tng_data->input_endianness_swap_func_64)
4134         {
4135             if(tng_data->input_endianness_swap_func_64(tng_data,
4136                                 (int64_t *)&tng_data->time_per_frame)
4137                 != TNG_SUCCESS)
4138             {
4139                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4140                         __FILE__, __LINE__);
4141             }
4142         }
4143     }
4144     else
4145     {
4146         frame_set->first_frame_time = -1;
4147         tng_data->time_per_frame = -1;
4148     }
4149
4150     /* If the output file and the input files are the same the number of
4151      * frames in the file are the same number as has just been read.
4152      * This is updated here to later on see if there have been new frames
4153      * added and thereby the frame set needs to be rewritten. */
4154     if(tng_data->output_file == tng_data->input_file)
4155     {
4156         frame_set->n_written_frames = frame_set->n_frames;
4157     }
4158
4159     return(TNG_SUCCESS);
4160 }
4161
4162 /** Write tng_data->current_trajectory_frame_set to file
4163  * @param tng_data is a trajectory data container.
4164  * @param block is a general block container.
4165  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4166  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4167  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4168  * error has occured.
4169  */
4170 static tng_function_status tng_frame_set_block_write
4171                 (tng_trajectory_t tng_data,
4172                  tng_gen_block_t block,
4173                  const char hash_mode)
4174 {
4175     char *temp_name;
4176     int64_t i;
4177     int offset = 0;
4178     unsigned int name_len;
4179     tng_trajectory_frame_set_t frame_set =
4180     &tng_data->current_trajectory_frame_set;
4181
4182     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4183     {
4184         return(TNG_CRITICAL);
4185     }
4186
4187     name_len = (int)strlen("TRAJECTORY FRAME SET");
4188
4189     if(!block->name || strlen(block->name) < name_len)
4190     {
4191         temp_name = realloc(block->name, name_len + 1);
4192         if(!temp_name)
4193         {
4194             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4195                    name_len+1, __FILE__, __LINE__);
4196             free(block->name);
4197             block->name = 0;
4198             return(TNG_CRITICAL);
4199         }
4200         block->name = temp_name;
4201     }
4202     strcpy(block->name, "TRAJECTORY FRAME SET");
4203     block->id = TNG_TRAJECTORY_FRAME_SET;
4204
4205     if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
4206         TNG_SUCCESS)
4207     {
4208         fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
4209                 __FILE__, __LINE__);
4210         return(TNG_CRITICAL);
4211     }
4212
4213     if(block->block_contents)
4214     {
4215         free(block->block_contents);
4216     }
4217     block->block_contents = malloc(block->block_contents_size);
4218     if(!block->block_contents)
4219     {
4220         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4221                block->block_contents_size, __FILE__, __LINE__);
4222         return(TNG_CRITICAL);
4223     }
4224
4225     memcpy(block->block_contents, &frame_set->first_frame,
4226            sizeof(frame_set->first_frame));
4227     if(tng_data->output_endianness_swap_func_64)
4228     {
4229         if(tng_data->output_endianness_swap_func_64(tng_data,
4230                                       (int64_t *)block->header_contents+offset)
4231             != TNG_SUCCESS)
4232         {
4233             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4234                     __FILE__, __LINE__);
4235         }
4236     }
4237     offset += sizeof(frame_set->first_frame);
4238
4239     memcpy(block->block_contents+offset, &frame_set->n_frames,
4240            sizeof(frame_set->n_frames));
4241     if(tng_data->output_endianness_swap_func_64)
4242     {
4243         if(tng_data->output_endianness_swap_func_64(tng_data,
4244                                       (int64_t *)block->header_contents+offset)
4245             != TNG_SUCCESS)
4246         {
4247             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4248                     __FILE__, __LINE__);
4249         }
4250     }
4251     offset += sizeof(frame_set->n_frames);
4252
4253     if(tng_data->var_num_atoms_flag)
4254     {
4255         for(i = 0; i < tng_data->n_molecules; i++)
4256         {
4257             memcpy(block->block_contents+offset,
4258                    &frame_set->molecule_cnt_list[i],
4259                    sizeof(int64_t));
4260             if(tng_data->output_endianness_swap_func_64)
4261             {
4262                 if(tng_data->output_endianness_swap_func_64(tng_data,
4263                                             (int64_t *)block->header_contents+offset)
4264                     != TNG_SUCCESS)
4265                 {
4266                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4267                             __FILE__, __LINE__);
4268                 }
4269             }
4270             offset += sizeof(int64_t);
4271         }
4272     }
4273
4274
4275     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
4276            sizeof(frame_set->next_frame_set_file_pos));
4277     if(tng_data->output_endianness_swap_func_64)
4278     {
4279         if(tng_data->output_endianness_swap_func_64(tng_data,
4280                                       (int64_t *)block->header_contents+offset)
4281             != TNG_SUCCESS)
4282         {
4283             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4284                     __FILE__, __LINE__);
4285         }
4286     }
4287     offset += sizeof(frame_set->next_frame_set_file_pos);
4288
4289     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
4290            sizeof(frame_set->prev_frame_set_file_pos));
4291     if(tng_data->output_endianness_swap_func_64)
4292     {
4293         if(tng_data->output_endianness_swap_func_64(tng_data,
4294                                       (int64_t *)block->header_contents+offset)
4295             != TNG_SUCCESS)
4296         {
4297             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4298                     __FILE__, __LINE__);
4299         }
4300     }
4301     offset += sizeof(frame_set->prev_frame_set_file_pos);
4302
4303     memcpy(block->block_contents+offset,
4304            &frame_set->medium_stride_next_frame_set_file_pos,
4305            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4306     if(tng_data->output_endianness_swap_func_64)
4307     {
4308         if(tng_data->output_endianness_swap_func_64(tng_data,
4309                                       (int64_t *)block->header_contents+offset)
4310             != TNG_SUCCESS)
4311         {
4312             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4313                     __FILE__, __LINE__);
4314         }
4315     }
4316     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4317
4318     memcpy(block->block_contents+offset,
4319            &frame_set->medium_stride_prev_frame_set_file_pos,
4320            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4321     if(tng_data->output_endianness_swap_func_64)
4322     {
4323         if(tng_data->output_endianness_swap_func_64(tng_data,
4324                                       (int64_t *)block->header_contents+offset)
4325             != TNG_SUCCESS)
4326         {
4327             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4328                     __FILE__, __LINE__);
4329         }
4330     }
4331     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4332
4333     memcpy(block->block_contents+offset,
4334            &frame_set->long_stride_next_frame_set_file_pos,
4335            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4336     if(tng_data->output_endianness_swap_func_64)
4337     {
4338         if(tng_data->output_endianness_swap_func_64(tng_data,
4339                                       (int64_t *)block->header_contents+offset)
4340             != TNG_SUCCESS)
4341         {
4342             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4343                     __FILE__, __LINE__);
4344         }
4345     }
4346     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4347
4348     memcpy(block->block_contents+offset,
4349            &frame_set->long_stride_prev_frame_set_file_pos,
4350            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4351     if(tng_data->output_endianness_swap_func_64)
4352     {
4353         if(tng_data->output_endianness_swap_func_64(tng_data,
4354                                       (int64_t *)block->header_contents+offset)
4355             != TNG_SUCCESS)
4356         {
4357             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4358                     __FILE__, __LINE__);
4359         }
4360     }
4361     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4362
4363     memcpy(block->block_contents+offset,
4364            &frame_set->first_frame_time,
4365            sizeof(frame_set->first_frame_time));
4366     if(tng_data->output_endianness_swap_func_64)
4367     {
4368         if(tng_data->output_endianness_swap_func_64(tng_data,
4369                                       (int64_t *)block->header_contents+offset)
4370             != TNG_SUCCESS)
4371         {
4372             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4373                     __FILE__, __LINE__);
4374         }
4375     }
4376     offset += sizeof(frame_set->first_frame_time);
4377
4378     memcpy(block->block_contents+offset,
4379            &tng_data->time_per_frame,
4380            sizeof(tng_data->time_per_frame));
4381     if(tng_data->output_endianness_swap_func_64)
4382     {
4383         if(tng_data->output_endianness_swap_func_64(tng_data,
4384                                       (int64_t *)block->header_contents+offset)
4385             != TNG_SUCCESS)
4386         {
4387             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4388                     __FILE__, __LINE__);
4389         }
4390     }
4391
4392     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4393     {
4394         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4395                tng_data->output_file_path, __FILE__, __LINE__);
4396         return(TNG_CRITICAL);
4397     }
4398
4399     if(fwrite(block->block_contents, block->block_contents_size, 1,
4400               tng_data->output_file) != 1)
4401     {
4402         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4403         return(TNG_CRITICAL);
4404     }
4405
4406     return(TNG_SUCCESS);
4407 }
4408
4409 static tng_function_status tng_trajectory_mapping_block_len_calculate
4410                 (const tng_trajectory_t tng_data,
4411                  const int64_t n_particles,
4412                  int64_t *len)
4413 {
4414     (void)tng_data;
4415     *len = sizeof(int64_t) * (2 + n_particles);
4416
4417     return(TNG_SUCCESS);
4418 }
4419
4420 /** Read an atom mappings block (translating between real atom indexes and how
4421  *  the atom info is written in this frame set).
4422  * @param tng_data is a trajectory data container.
4423  * @param block is a general block container.
4424  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4425  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
4426  * compared to the md5 hash of the read contents to ensure valid data.
4427  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4428  * error has occured.
4429  */
4430 static tng_function_status tng_trajectory_mapping_block_read
4431                 (tng_trajectory_t tng_data,
4432                  tng_gen_block_t block,
4433                  const char hash_mode)
4434 {
4435     int64_t i;
4436     int offset = 0;
4437     tng_bool same_hash;
4438     tng_trajectory_frame_set_t frame_set =
4439     &tng_data->current_trajectory_frame_set;
4440
4441     tng_particle_mapping_t mapping, mappings;
4442
4443     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
4444     {
4445         return(TNG_CRITICAL);
4446     }
4447
4448     if(block->block_contents)
4449     {
4450         free(block->block_contents);
4451     }
4452
4453     block->block_contents = malloc(block->block_contents_size);
4454     if(!block->block_contents)
4455     {
4456         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4457                block->block_contents_size, __FILE__, __LINE__);
4458         return(TNG_CRITICAL);
4459     }
4460
4461     /* Read the whole block into block_contents to be able to write it to disk
4462      *  even if it cannot be interpreted. */
4463     if(fread(block->block_contents, block->block_contents_size, 1,
4464         tng_data->input_file) == 0)
4465     {
4466         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
4467         return(TNG_CRITICAL);
4468     }
4469
4470     /* FIXME: Does not check if the size of the contents matches the expected
4471      * size or if the contents can be read. */
4472
4473     if(hash_mode == TNG_USE_HASH)
4474     {
4475         tng_md5_hash_match_verify(block, &same_hash);
4476         if(same_hash != TNG_TRUE)
4477         {
4478             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4479                 "%s: %d\n",
4480                 __FILE__, __LINE__);
4481     /*         return(TNG_FAILURE); */
4482         }
4483     }
4484
4485     frame_set->n_mapping_blocks++;
4486     mappings = realloc(frame_set->mappings,
4487                        sizeof(struct tng_particle_mapping) *
4488                        frame_set->n_mapping_blocks);
4489     if(!mappings)
4490     {
4491         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4492                block->block_contents_size, __FILE__, __LINE__);
4493         free(frame_set->mappings);
4494         frame_set->mappings = 0;
4495         return(TNG_CRITICAL);
4496     }
4497     frame_set->mappings = mappings;
4498     mapping = &mappings[frame_set->n_mapping_blocks - 1];
4499
4500
4501     memcpy(&mapping->num_first_particle, block->block_contents+offset,
4502            sizeof(mapping->num_first_particle));
4503     if(tng_data->input_endianness_swap_func_64)
4504     {
4505         if(tng_data->input_endianness_swap_func_64(tng_data,
4506                                                    &mapping->num_first_particle)
4507             != TNG_SUCCESS)
4508         {
4509             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4510                     __FILE__, __LINE__);
4511         }
4512     }
4513     offset += sizeof(mapping->num_first_particle);
4514
4515     memcpy(&mapping->n_particles, block->block_contents+offset,
4516            sizeof(mapping->n_particles));
4517     if(tng_data->input_endianness_swap_func_64)
4518     {
4519         if(tng_data->input_endianness_swap_func_64(tng_data,
4520                                                    &mapping->n_particles)
4521             != TNG_SUCCESS)
4522         {
4523             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4524                     __FILE__, __LINE__);
4525         }
4526     }
4527     offset += sizeof(mapping->n_particles);
4528
4529     mapping->real_particle_numbers = malloc(mapping->n_particles *
4530                                             sizeof(int64_t));
4531     if(!mapping->real_particle_numbers)
4532     {
4533         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4534                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
4535         return(TNG_CRITICAL);
4536     }
4537
4538     /* If the byte order needs to be swapped the data must be read one value at
4539      * a time and swapped */
4540     if(tng_data->input_endianness_swap_func_64)
4541     {
4542         for(i = 0; i < mapping->n_particles; i++)
4543         {
4544             memcpy(&mapping->real_particle_numbers[i],
4545                     block->block_contents + offset,
4546                     sizeof(int64_t));
4547             if(tng_data->input_endianness_swap_func_64(tng_data,
4548                                             &mapping->real_particle_numbers[i])
4549                 != TNG_SUCCESS)
4550             {
4551                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4552                         __FILE__, __LINE__);
4553             }
4554             offset += sizeof(int64_t);
4555         }
4556     }
4557     /* Otherwise the data can be read all at once */
4558     else
4559     {
4560         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
4561                mapping->n_particles * sizeof(int64_t));
4562     }
4563
4564
4565     return(TNG_SUCCESS);
4566 }
4567
4568 /** Write the atom mappings of the current trajectory frame set
4569  * @param tng_data is a trajectory data container.
4570  * @param block is a general block container.
4571  * @param mapping_block_nr is the index of the mapping block to write.
4572  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4573  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4574  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4575  * has occurred or TNG_CRITICAL (2) if a major error has occured.
4576  */
4577 static tng_function_status tng_trajectory_mapping_block_write
4578                 (tng_trajectory_t tng_data,
4579                  tng_gen_block_t block,
4580                  int mapping_block_nr,
4581                  const char hash_mode)
4582 {
4583     char *temp_name;
4584     int i, offset = 0;
4585     unsigned int name_len;
4586     tng_particle_mapping_t mapping =
4587     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4588
4589     if(mapping_block_nr >=
4590        tng_data->current_trajectory_frame_set.n_mapping_blocks)
4591     {
4592         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4593                __FILE__, __LINE__);
4594         return(TNG_FAILURE);
4595     }
4596
4597     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4598     {
4599         return(TNG_CRITICAL);
4600     }
4601
4602     name_len = (int)strlen("PARTICLE MAPPING");
4603
4604     if(!block->name || strlen(block->name) < name_len)
4605     {
4606         temp_name = realloc(block->name, name_len + 1);
4607         if(!temp_name)
4608         {
4609             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
4610                    name_len+1, __FILE__, __LINE__);
4611             free(block->name);
4612             block->name = 0;
4613             return(TNG_CRITICAL);
4614         }
4615         block->name = temp_name;
4616     }
4617     strcpy(block->name, "PARTICLE MAPPING");
4618     block->id = TNG_PARTICLE_MAPPING;
4619
4620     if(tng_trajectory_mapping_block_len_calculate(tng_data,
4621                                                   mapping->n_particles,
4622                                                   &block->block_contents_size) !=
4623         TNG_SUCCESS)
4624     {
4625         fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4626                 __FILE__, __LINE__);
4627         return(TNG_CRITICAL);
4628     }
4629
4630     if(block->block_contents)
4631     {
4632         free(block->block_contents);
4633     }
4634     block->block_contents = malloc(block->block_contents_size);
4635     if(!block->block_contents)
4636     {
4637         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4638                block->block_contents_size, __FILE__, __LINE__);
4639         return(TNG_CRITICAL);
4640     }
4641
4642     memcpy(block->block_contents, &mapping->num_first_particle,
4643            sizeof(mapping->num_first_particle));
4644     if(tng_data->output_endianness_swap_func_64)
4645     {
4646         if(tng_data->output_endianness_swap_func_64(tng_data,
4647                                       (int64_t *)block->header_contents+offset)
4648             != TNG_SUCCESS)
4649         {
4650             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4651                     __FILE__, __LINE__);
4652         }
4653     }
4654     offset += sizeof(mapping->num_first_particle);
4655
4656     memcpy(block->block_contents+offset, &mapping->n_particles,
4657            sizeof(mapping->n_particles));
4658     if(tng_data->output_endianness_swap_func_64)
4659     {
4660         if(tng_data->output_endianness_swap_func_64(tng_data,
4661                                       (int64_t *)block->header_contents+offset)
4662             != TNG_SUCCESS)
4663         {
4664             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4665                     __FILE__, __LINE__);
4666         }
4667     }
4668     offset += sizeof(mapping->n_particles);
4669
4670     if(tng_data->output_endianness_swap_func_64)
4671     {
4672         for(i = 0; i < mapping->n_particles; i++)
4673         {
4674             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
4675                 sizeof(int64_t));
4676             if(tng_data->output_endianness_swap_func_64(tng_data,
4677                                         (int64_t *)block->header_contents+offset)
4678                 != TNG_SUCCESS)
4679             {
4680                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4681                         __FILE__, __LINE__);
4682             }
4683             offset += sizeof(int64_t);
4684         }
4685     }
4686     else
4687     {
4688         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
4689                mapping->n_particles * sizeof(int64_t));
4690     }
4691
4692
4693     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4694     {
4695         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4696                tng_data->output_file_path, __FILE__, __LINE__);
4697         return(TNG_CRITICAL);
4698     }
4699
4700     if(fwrite(block->block_contents, block->block_contents_size, 1,
4701               tng_data->output_file) != 1)
4702     {
4703         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4704         return(TNG_CRITICAL);
4705     }
4706
4707     return(TNG_SUCCESS);
4708 }
4709
4710 /** Prepare a block for storing particle data
4711  * @param tng_data is a trajectory data container.
4712  * @param block_type_flag specifies if this is a trajectory block or a
4713  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4714  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4715  * error has occured.
4716  */
4717 static tng_function_status tng_particle_data_block_create
4718                 (tng_trajectory_t tng_data,
4719                  const char block_type_flag)
4720 {
4721     tng_trajectory_frame_set_t frame_set =
4722     &tng_data->current_trajectory_frame_set;
4723
4724     tng_particle_data_t data;
4725
4726     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4727     {
4728         frame_set->n_particle_data_blocks++;
4729         data = realloc(frame_set->tr_particle_data,
4730                     sizeof(struct tng_particle_data) *
4731                     frame_set->n_particle_data_blocks);
4732         if(!data)
4733         {
4734             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4735                 sizeof(struct tng_particle_data) *
4736                 frame_set->n_particle_data_blocks,
4737                 __FILE__, __LINE__);
4738             free(frame_set->tr_particle_data);
4739             frame_set->tr_particle_data = 0;
4740             return(TNG_CRITICAL);
4741         }
4742         frame_set->tr_particle_data = data;
4743     }
4744     else
4745     {
4746         tng_data->n_particle_data_blocks++;
4747         data = realloc(tng_data->non_tr_particle_data,
4748                         sizeof(struct tng_particle_data) *
4749                         tng_data->n_particle_data_blocks);
4750         if(!data)
4751         {
4752             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
4753                     sizeof(struct tng_particle_data) *
4754                     tng_data->n_particle_data_blocks,
4755                     __FILE__, __LINE__);
4756             free(tng_data->non_tr_particle_data);
4757             tng_data->non_tr_particle_data = 0;
4758             return(TNG_CRITICAL);
4759         }
4760         tng_data->non_tr_particle_data = data;
4761     }
4762
4763     return(TNG_SUCCESS);
4764 }
4765
4766 static tng_function_status tng_compress(tng_trajectory_t tng_data,
4767                                         tng_gen_block_t block,
4768                                         const int64_t n_frames,
4769                                         const int64_t n_particles,
4770                                         const char type,
4771                                         void *start_pos)
4772 {
4773     int nalgo;
4774     int new_len;
4775     int *alt_algo = 0;
4776     char *dest, *temp, *temp_data_contents;
4777     int64_t algo_find_n_frames, compressed_len, offset;
4778     float f_precision;
4779     double d_precision;
4780
4781     if(block->id != TNG_TRAJ_POSITIONS &&
4782        block->id != TNG_TRAJ_VELOCITIES)
4783     {
4784         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4785                "TNG method. %s: %d\n", __FILE__, __LINE__);
4786         return(TNG_FAILURE);
4787     }
4788     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4789     {
4790         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4791         return(TNG_FAILURE);
4792     }
4793
4794     if(n_frames <= 0 || n_particles <= 0)
4795     {
4796         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4797                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4798         return(TNG_FAILURE);
4799     }
4800
4801     f_precision = 1/(float)tng_data->compression_precision;
4802     d_precision = 1/tng_data->compression_precision;
4803
4804     compressed_len = block->block_contents_size - (int64_t)((char *)start_pos - (char *)block->block_contents);
4805     temp_data_contents = malloc(compressed_len);
4806     if(!temp_data_contents)
4807     {
4808         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4809                 compressed_len, __FILE__, __LINE__);
4810         return(TNG_CRITICAL);
4811     }
4812
4813     memcpy(temp_data_contents, (char *)start_pos, compressed_len);
4814
4815     if(block->id == TNG_TRAJ_POSITIONS)
4816     {
4817         /* If there is only one frame in this frame set and there might be more
4818          * do not store the algorithm as the compression algorithm, but find
4819          * the best one without storing it */
4820         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4821         {
4822             nalgo = tng_compress_nalgo();
4823             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4824             if(type == TNG_FLOAT_DATA)
4825             {
4826                 dest = tng_compress_pos_float_find_algo((float *)temp_data_contents, (int)n_particles,
4827                                                         (int)n_frames,
4828                                                         f_precision,
4829                                                         0, alt_algo,
4830                                                         &new_len);
4831
4832             }
4833             else
4834             {
4835                 dest = tng_compress_pos_find_algo((double *)temp_data_contents, (int)n_particles,
4836                                            (int)n_frames,
4837                                            d_precision,
4838                                            0, alt_algo,
4839                                            &new_len);
4840             }
4841         }
4842         else if(!tng_data->compress_algo_pos)
4843         {
4844             if(n_frames > 10)
4845             {
4846                 algo_find_n_frames = 5;
4847             }
4848             else
4849             {
4850                 algo_find_n_frames = n_frames;
4851             }
4852
4853             nalgo = tng_compress_nalgo();
4854             tng_data->compress_algo_pos=malloc(nalgo *
4855                                            sizeof *tng_data->compress_algo_pos);
4856             if(type == TNG_FLOAT_DATA)
4857             {
4858                 dest = tng_compress_pos_float_find_algo((float *)temp_data_contents, (int)n_particles,
4859                                                         (int)algo_find_n_frames,
4860                                                         f_precision,
4861                                                         0, tng_data->
4862                                                         compress_algo_pos,
4863                                                         &new_len);
4864
4865                 if(algo_find_n_frames < n_frames)
4866                 {
4867                     dest = tng_compress_pos_float((float *)temp_data_contents, (int)n_particles,
4868                                                   (int)n_frames,
4869                                                   f_precision,
4870                                                   0, tng_data->compress_algo_pos,
4871                                                   &new_len);
4872                 }
4873             }
4874             else
4875             {
4876                 dest = tng_compress_pos_find_algo((double *)temp_data_contents, (int)n_particles,
4877                                            (int)algo_find_n_frames,
4878                                            d_precision,
4879                                            0, tng_data->
4880                                            compress_algo_pos,
4881                                            &new_len);
4882
4883                 if(algo_find_n_frames < n_frames)
4884                 {
4885                     dest = tng_compress_pos((double *)temp_data_contents, (int)n_particles,
4886                                             (int)n_frames,
4887                                             d_precision, 0,
4888                                             tng_data->compress_algo_pos,
4889                                             &new_len);
4890                 }
4891             }
4892         }
4893         else
4894         {
4895             if(type == TNG_FLOAT_DATA)
4896             {
4897                 dest = tng_compress_pos_float((float *)temp_data_contents, (int)n_particles,
4898                                               (int)n_frames,
4899                                               f_precision, 0,
4900                                               tng_data->compress_algo_pos, &new_len);
4901             }
4902             else
4903             {
4904                 dest = tng_compress_pos((double *)temp_data_contents, (int)n_particles,
4905                                         (int)n_frames,
4906                                         d_precision, 0,
4907                                         tng_data->compress_algo_pos,
4908                                         &new_len);
4909             }
4910         }
4911     }
4912     else if(block->id == TNG_TRAJ_VELOCITIES)
4913     {
4914         /* If there is only one frame in this frame set and there might be more
4915          * do not store the algorithm as the compression algorithm, but find
4916          * the best one without storing it */
4917         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4918         {
4919             nalgo = tng_compress_nalgo();
4920             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4921             if(type == TNG_FLOAT_DATA)
4922             {
4923                 dest = tng_compress_vel_float_find_algo((float *)temp_data_contents, (int)n_particles,
4924                                                         (int)n_frames,
4925                                                         f_precision,
4926                                                         0, alt_algo,
4927                                                         &new_len);
4928
4929             }
4930             else
4931             {
4932                 dest = tng_compress_vel_find_algo((double *)temp_data_contents, (int)n_particles,
4933                                                   (int)n_frames,
4934                                                   d_precision,
4935                                                   0, alt_algo,
4936                                                   &new_len);
4937             }
4938         }
4939         else if(!tng_data->compress_algo_vel)
4940         {
4941             if(n_frames > 10)
4942             {
4943                 algo_find_n_frames = 5;
4944             }
4945             else
4946             {
4947                 algo_find_n_frames = n_frames;
4948             }
4949
4950             nalgo = tng_compress_nalgo();
4951             tng_data->compress_algo_vel=malloc(nalgo *
4952                                            sizeof *tng_data->compress_algo_vel);
4953
4954             if(type == TNG_FLOAT_DATA)
4955             {
4956                 dest = tng_compress_vel_float_find_algo((float *)temp_data_contents, (int)n_particles,
4957                                                         (int)algo_find_n_frames,
4958                                                         f_precision,
4959                                                         0, tng_data->
4960                                                         compress_algo_vel,
4961                                                         &new_len);
4962                 if(algo_find_n_frames < n_frames)
4963                 {
4964                     dest = tng_compress_vel_float((float *)temp_data_contents, (int)n_particles,
4965                                                   (int)n_frames,
4966                                                   f_precision,
4967                                                   0, tng_data->compress_algo_vel,
4968                                                   &new_len);
4969                 }
4970             }
4971             else
4972             {
4973                 dest = tng_compress_vel_find_algo((double *)temp_data_contents, (int)n_particles,
4974                                                   (int)algo_find_n_frames,
4975                                                   d_precision,
4976                                                   0, tng_data->
4977                                                   compress_algo_vel,
4978                                                   &new_len);
4979                 if(algo_find_n_frames < n_frames)
4980                 {
4981                     dest = tng_compress_vel((double *)temp_data_contents, (int)n_particles,
4982                                             (int)n_frames,
4983                                             d_precision,
4984                                             0, tng_data->compress_algo_vel,
4985                                             &new_len);
4986                 }
4987             }
4988         }
4989         else
4990         {
4991             if(type == TNG_FLOAT_DATA)
4992             {
4993                 dest = tng_compress_vel_float((float *)temp_data_contents, (int)n_particles,
4994                                               (int)n_frames,
4995                                               f_precision,
4996                                               0, tng_data->
4997                                               compress_algo_vel,
4998                                               &new_len);
4999             }
5000             else
5001             {
5002                 dest = tng_compress_vel((double *)temp_data_contents, (int)n_particles,
5003                                         (int)n_frames,
5004                                         d_precision,
5005                                         0, tng_data->
5006                                         compress_algo_vel,
5007                                         &new_len);
5008             }
5009         }
5010     }
5011     else
5012     {
5013         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
5014         free(temp_data_contents);
5015         return(TNG_FAILURE);
5016     }
5017
5018     offset = (unsigned long)((char *)start_pos - block->block_contents);
5019
5020     if(alt_algo)
5021     {
5022         free(alt_algo);
5023     }
5024
5025     block->block_contents_size = new_len + offset;
5026
5027     free(temp_data_contents);
5028
5029     temp = realloc(block->block_contents, block->block_contents_size);
5030     if(!temp)
5031     {
5032         free(block->block_contents);
5033         block->block_contents = 0;
5034         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5035                block->block_contents_size, __FILE__, __LINE__);
5036         return(TNG_CRITICAL);
5037     }
5038     block->block_contents = temp;
5039     if(dest)
5040     {
5041         memcpy(temp + offset, dest, new_len);
5042         free(dest);
5043     }
5044     else
5045     {
5046         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
5047         return(TNG_FAILURE);
5048     }
5049
5050     return(TNG_SUCCESS);
5051 }
5052
5053 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
5054                                           tng_gen_block_t block,
5055                                           const char type,
5056                                           void *start_pos,
5057                                           const int64_t uncompressed_len)
5058 {
5059     char *temp, *temp_data_contents;
5060     int64_t compressed_len;
5061     double *d_dest = 0;
5062     float *f_dest = 0;
5063     int64_t offset;
5064     int result;
5065     (void)tng_data;
5066
5067     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
5068
5069     if(block->id != TNG_TRAJ_POSITIONS &&
5070        block->id != TNG_TRAJ_VELOCITIES)
5071     {
5072         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
5073                "TNG method.\n");
5074         return(TNG_FAILURE);
5075     }
5076     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
5077     {
5078         fprintf(stderr, "TNG library: Data type not supported.\n");
5079         return(TNG_FAILURE);
5080     }
5081
5082     compressed_len = block->block_contents_size - (int64_t)((char *)start_pos - (char *)block->block_contents);
5083     temp_data_contents = malloc(compressed_len);
5084     if(!temp_data_contents)
5085     {
5086         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5087                 uncompressed_len, __FILE__, __LINE__);
5088         return(TNG_CRITICAL);
5089     }
5090
5091     memcpy(temp_data_contents, (char *)start_pos, compressed_len);
5092
5093     if(type == TNG_FLOAT_DATA)
5094     {
5095         f_dest = malloc(uncompressed_len);
5096         if(!f_dest)
5097         {
5098             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5099                 uncompressed_len, __FILE__, __LINE__);
5100             free(temp_data_contents);
5101             return(TNG_CRITICAL);
5102         }
5103         result = tng_compress_uncompress_float(temp_data_contents, f_dest);
5104     }
5105     else
5106     {
5107         d_dest = malloc(uncompressed_len);
5108         if(!d_dest)
5109         {
5110             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5111                 uncompressed_len, __FILE__, __LINE__);
5112             free(temp_data_contents);
5113             return(TNG_CRITICAL);
5114         }
5115         result = tng_compress_uncompress(temp_data_contents, d_dest);
5116     }
5117
5118     if(result == 1)
5119     {
5120         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
5121         free(temp_data_contents);
5122         return(TNG_FAILURE);
5123     }
5124
5125     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
5126
5127     block->block_contents_size = (int64_t)(uncompressed_len + offset);
5128
5129     temp = realloc(block->block_contents, uncompressed_len + offset);
5130     if(!temp)
5131     {
5132         free(block->block_contents);
5133         block->block_contents = 0;
5134         if(d_dest)
5135         {
5136             free(d_dest);
5137         }
5138         if(f_dest)
5139         {
5140             free(f_dest);
5141         }
5142         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5143                block->block_contents_size, __FILE__, __LINE__);
5144         free(temp_data_contents);
5145         return(TNG_CRITICAL);
5146     }
5147
5148     if(type == TNG_FLOAT_DATA)
5149     {
5150         memcpy(temp + offset, f_dest, uncompressed_len);
5151     }
5152     else
5153     {
5154         memcpy(temp + offset, d_dest, uncompressed_len);
5155     }
5156
5157     block->block_contents = temp;
5158
5159     free(temp_data_contents);
5160     if(d_dest)
5161     {
5162         free(d_dest);
5163     }
5164     if(f_dest)
5165     {
5166         free(f_dest);
5167     }
5168     return(TNG_SUCCESS);
5169 }
5170
5171 #ifdef USE_ZLIB
5172 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
5173                                              tng_gen_block_t block,
5174                                              void *start_pos, const int len)
5175 {
5176     Bytef *dest;
5177     char *temp;
5178     unsigned long max_len, stat, offset;
5179     (void)tng_data;
5180
5181     max_len = compressBound(len);
5182     dest = malloc(max_len);
5183     if(!dest)
5184     {
5185         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
5186                max_len, __FILE__, __LINE__);
5187         return(TNG_CRITICAL);
5188     }
5189
5190     stat = compress(dest, &max_len, start_pos, len);
5191     if(stat != (unsigned long)Z_OK)
5192     {
5193         free(dest);
5194         if(stat == (unsigned long)Z_MEM_ERROR)
5195         {
5196             fprintf(stderr, "TNG library: Not enough memory. ");
5197         }
5198         else if(stat == (unsigned long)Z_BUF_ERROR)
5199         {
5200             fprintf(stderr, "TNG library: Destination buffer too small. ");
5201         }
5202         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
5203         return(TNG_FAILURE);
5204     }
5205
5206     offset = (char *)start_pos - block->block_contents;
5207
5208     block->block_contents_size = max_len + offset;
5209
5210     temp = realloc(block->block_contents, block->block_contents_size);
5211     if(!temp)
5212     {
5213         free(block->block_contents);
5214         free(dest);
5215         block->block_contents = 0;
5216         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5217                block->block_contents_size, __FILE__, __LINE__);
5218         return(TNG_CRITICAL);
5219     }
5220
5221     block->block_contents = temp;
5222
5223     memcpy(temp + offset, dest, max_len);
5224
5225     free(dest);
5226
5227     return(TNG_SUCCESS);
5228 }
5229
5230 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
5231                                                tng_gen_block_t block,
5232                                                void *start_pos,
5233                                                unsigned long uncompressed_len)
5234 {
5235     Bytef *dest;
5236     char *temp;
5237     unsigned long stat;
5238     int offset;
5239     (void)tng_data;
5240
5241     offset = (char *)start_pos - (char *)block->block_contents;
5242
5243     dest = malloc(uncompressed_len);
5244     if(!dest)
5245     {
5246         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
5247                uncompressed_len, __FILE__, __LINE__);
5248         return(TNG_CRITICAL);
5249     }
5250
5251     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
5252                       block->block_contents_size - offset);
5253
5254     if(stat != Z_OK)
5255     {
5256         free(dest);
5257         if(stat == (unsigned long)Z_MEM_ERROR)
5258         {
5259             fprintf(stderr, "TNG library: Not enough memory. ");
5260         }
5261         else if(stat == (unsigned long)Z_BUF_ERROR)
5262         {
5263             fprintf(stderr, "TNG library: Destination buffer too small. ");
5264         }
5265         else if(stat == (unsigned long)Z_DATA_ERROR)
5266         {
5267             fprintf(stderr, "TNG library: Data corrupt. ");
5268         }
5269         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
5270                __LINE__);
5271         return(TNG_FAILURE);
5272     }
5273
5274
5275     block->block_contents_size = uncompressed_len + offset;
5276
5277     temp = realloc(block->block_contents, uncompressed_len + offset);
5278     if(!temp)
5279     {
5280         free(block->block_contents);
5281         block->block_contents = 0;
5282         free(dest);
5283         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5284                block->block_contents_size, __FILE__, __LINE__);
5285         return(TNG_CRITICAL);
5286     }
5287
5288     memcpy(temp + offset, dest, uncompressed_len);
5289
5290     block->block_contents = temp;
5291
5292     free(dest);
5293     return(TNG_SUCCESS);
5294 }
5295 #endif
5296
5297 /** Allocate memory for storing particle data.
5298  * The allocated block will be refered to by data->values.
5299  * @param tng_data is a trajectory data container.
5300  * @param data is the data struct, which will contain the allocated memory in
5301  * data->values.
5302  * @param n_frames is the number of frames of data to store.
5303  * @param n_particles is the number of particles with data.
5304  * @param n_values_per_frame is the number of data values per particle and
5305  * frame.
5306  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5307  * error has occured.
5308  */
5309 static tng_function_status tng_allocate_particle_data_mem
5310                 (tng_trajectory_t tng_data,
5311                  tng_particle_data_t data,
5312                  int64_t n_frames,
5313                  int64_t stride_length,
5314                  const int64_t n_particles,
5315                  const int64_t n_values_per_frame)
5316 {
5317     void ***values;
5318     int64_t i, j, k, size, frame_alloc;
5319     (void)tng_data;
5320
5321     if(n_particles == 0 || n_values_per_frame == 0)
5322     {
5323         return(TNG_FAILURE);
5324     }
5325
5326     if(data->strings && data->datatype == TNG_CHAR_DATA)
5327     {
5328         for(i = 0; i < data->n_frames; i++)
5329         {
5330             for(j = 0; j < n_particles; j++)
5331             {
5332                 for(k = 0; k < data->n_values_per_frame; k++)
5333                 {
5334                     if(data->strings[i][j][k])
5335                     {
5336                         free(data->strings[i][j][k]);
5337                     }
5338                 }
5339                 free(data->strings[i][j]);
5340             }
5341             free(data->strings[i]);
5342         }
5343         free(data->strings);
5344     }
5345     data->n_frames = n_frames;
5346     n_frames = tng_max_i64(1, n_frames);
5347     data->stride_length = tng_max_i64(1, stride_length);
5348     data->n_values_per_frame = n_values_per_frame;
5349     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5350
5351     if(data->datatype == TNG_CHAR_DATA)
5352     {
5353         data->strings = malloc(sizeof(char ***) * frame_alloc);
5354         for(i = 0; i < frame_alloc; i++)
5355         {
5356             data->strings[i] = malloc(sizeof(char **) *
5357                                     n_particles);
5358             if(!data->strings[i])
5359             {
5360                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5361                     sizeof(union data_values *) * n_particles,
5362                     __FILE__, __LINE__);
5363                 return(TNG_CRITICAL);
5364             }
5365             for(j = 0; j < n_particles; j++)
5366             {
5367                 data->strings[i][j] = malloc(sizeof(char *) *
5368                                             n_values_per_frame);
5369                 if(!data->strings[i][j])
5370                 {
5371                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5372                         sizeof(union data_values) * n_values_per_frame,
5373                         __FILE__, __LINE__);
5374                     return(TNG_CRITICAL);
5375                 }
5376                 for(k = 0; k < n_values_per_frame; k++)
5377                 {
5378                     data->strings[i][j][k] = 0;
5379                 }
5380             }
5381         }
5382     }
5383     else
5384     {
5385         switch(data->datatype)
5386         {
5387         case TNG_INT_DATA:
5388             size = sizeof(int64_t);
5389             break;
5390         case TNG_FLOAT_DATA:
5391             size = sizeof(float);
5392             break;
5393         case TNG_DOUBLE_DATA:
5394         default:
5395             size = sizeof(double);
5396         }
5397
5398         values = realloc(data->values,
5399                          size * frame_alloc *
5400                          n_particles * n_values_per_frame);
5401         if(!values)
5402         {
5403             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5404                    size * frame_alloc *
5405                    n_particles * n_values_per_frame,
5406                    __FILE__, __LINE__);
5407             free(data->values);
5408             data->values = 0;
5409             return(TNG_CRITICAL);
5410         }
5411         data->values = values;
5412     }
5413     return(TNG_SUCCESS);
5414 }
5415
5416 static tng_function_status tng_particle_data_find
5417                 (tng_trajectory_t tng_data,
5418                  const int64_t id,
5419                  tng_particle_data_t *data)
5420 {
5421     int64_t block_index, i;
5422     tng_trajectory_frame_set_t frame_set = &tng_data->
5423                                            current_trajectory_frame_set;
5424     char block_type_flag;
5425
5426     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5427        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5428     {
5429         block_type_flag = TNG_TRAJECTORY_BLOCK;
5430     }
5431     else
5432     {
5433         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5434     }
5435
5436     block_index = -1;
5437     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5438     {
5439         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
5440         {
5441             *data = &frame_set->tr_particle_data[i];
5442             if((*data)->block_id == id)
5443             {
5444                 block_index = i;
5445                 break;
5446             }
5447         }
5448     }
5449     else
5450     {
5451         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
5452         {
5453             *data = &tng_data->non_tr_particle_data[i];
5454             if((*data)->block_id == id)
5455             {
5456                 block_index = i;
5457                 break;
5458             }
5459         }
5460     }
5461     if(block_index == -1)
5462     {
5463         return(TNG_FAILURE);
5464     }
5465     return(TNG_SUCCESS);
5466 }
5467
5468 static tng_function_status tng_data_find
5469                 (tng_trajectory_t tng_data,
5470                  const int64_t id,
5471                  tng_non_particle_data_t *data)
5472 {
5473     int64_t block_index, i;
5474     tng_trajectory_frame_set_t frame_set = &tng_data->
5475                                            current_trajectory_frame_set;
5476     char block_type_flag;
5477
5478     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5479        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5480     {
5481         block_type_flag = TNG_TRAJECTORY_BLOCK;
5482     }
5483     else
5484     {
5485         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5486     }
5487
5488     block_index = -1;
5489     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5490     {
5491         for(i = 0; i < frame_set->n_data_blocks; i++)
5492         {
5493             *data = &frame_set->tr_data[i];
5494             if((*data)->block_id == id)
5495             {
5496                 block_index = i;
5497                 break;
5498             }
5499         }
5500         if(block_index == -1)
5501         {
5502             for(i = 0; i < tng_data->n_data_blocks; i++)
5503             {
5504                 *data = &tng_data->non_tr_data[i];
5505                 if((*data)->block_id == id)
5506                 {
5507                     block_index = i;
5508                     break;
5509                 }
5510             }
5511         }
5512     }
5513     else
5514     {
5515         for(i = 0; i < tng_data->n_data_blocks; i++)
5516         {
5517             *data = &tng_data->non_tr_data[i];
5518             if((*data)->block_id == id)
5519             {
5520                 block_index = i;
5521                 break;
5522             }
5523         }
5524     }
5525     if(block_index == -1)
5526     {
5527         return(TNG_FAILURE);
5528     }
5529     return(TNG_SUCCESS);
5530 }
5531
5532 static tng_function_status tng_data_block_len_calculate
5533                 (const tng_trajectory_t tng_data,
5534                  const tng_particle_data_t data,
5535                  const tng_bool is_particle_data,
5536                  const int64_t n_frames,
5537                  const int64_t frame_step,
5538                  const int64_t stride_length,
5539                  const int64_t num_first_particle,
5540                  const int64_t n_particles,
5541                  const char dependency,
5542                  int64_t *data_start_pos,
5543                  int64_t *len)
5544 {
5545     int size;
5546     int64_t i, j, k;
5547     char ***first_dim_values, **second_dim_values;
5548     (void)tng_data;
5549
5550     if(data == 0)
5551     {
5552         return(TNG_SUCCESS);
5553     }
5554
5555     switch(data->datatype)
5556     {
5557     case TNG_CHAR_DATA:
5558         size = 1;
5559         break;
5560     case TNG_INT_DATA:
5561         size = sizeof(int64_t);
5562         break;
5563     case TNG_FLOAT_DATA:
5564         size = sizeof(float);
5565         break;
5566     case TNG_DOUBLE_DATA:
5567     default:
5568         size = sizeof(double);
5569     }
5570
5571     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5572            sizeof(data->codec_id);
5573     if(is_particle_data)
5574     {
5575         *len += sizeof(num_first_particle) + sizeof(n_particles);
5576     }
5577
5578     if(stride_length > 1)
5579     {
5580         *len += sizeof(data->first_frame_with_data) +
5581                 sizeof(data->stride_length);
5582     }
5583
5584     if(data->codec_id != TNG_UNCOMPRESSED)
5585     {
5586         *len += sizeof(data->compression_multiplier);
5587     }
5588
5589     if(dependency & TNG_FRAME_DEPENDENT)
5590     {
5591         *len += sizeof(char);
5592     }
5593
5594     *data_start_pos = *len;
5595
5596     if(data->datatype == TNG_CHAR_DATA)
5597     {
5598         if(is_particle_data)
5599         {
5600             for(i = 0; i < n_frames; i++)
5601             {
5602                 first_dim_values = data->strings[i];
5603                 for(j = num_first_particle; j < num_first_particle + n_particles;
5604                     j++)
5605                 {
5606                     second_dim_values = first_dim_values[j];
5607                     for(k = 0; k < data->n_values_per_frame; k++)
5608                     {
5609                         *len += strlen(second_dim_values[k]) + 1;
5610                     }
5611                 }
5612             }
5613         }
5614         else
5615         {
5616             for(i = 0; i < n_frames; i++)
5617             {
5618                 second_dim_values = ((tng_non_particle_data_t)data)->strings[i];
5619                 for(j = 0; j < data->n_values_per_frame; j++)
5620                 {
5621                     *len += strlen(second_dim_values[j]) + 1;
5622                 }
5623             }
5624         }
5625     }
5626     else
5627     {
5628         *len += size * frame_step * n_particles * data->n_values_per_frame;
5629     }
5630
5631     return(TNG_SUCCESS);
5632 }
5633
5634 /** Read the values of a particle data block
5635  * @param tng_data is a trajectory data container.
5636  * @param block is the block to store the data (should already contain
5637  * the block headers and the block contents).
5638  * @param offset is the reading offset to point at the place where the actual
5639  * values are stored, starting from the beginning of the block_contents. The
5640  * offset is changed during the reading.
5641  * @param datatype is the type of data of the data block (char, int, float or
5642  * double).
5643  * @param num_first_particle is the number of the first particle in the data
5644  * block. This should be the same as in the corresponding particle mapping
5645  * block.
5646  * @param n_particles is the number of particles in the data block. This should
5647  * be the same as in the corresponding particle mapping block.
5648  * @param first_frame_with_data is the frame number of the first frame with data
5649  * in this data block.
5650  * @param stride_length is the number of frames between each data entry.
5651  * @param n_frames is the number of frames in this data block.
5652  * @param n_values is the number of values per particle and frame stored in this
5653  * data block.
5654  * @param codec_id is the ID of the codec to compress the data.
5655  * @param multiplier is the multiplication factor applied to each data value
5656  * before compression. This factor is applied since some compression algorithms
5657  * work only on integers.
5658  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5659  * error has occured.
5660  */
5661 static tng_function_status tng_particle_data_read
5662                 (tng_trajectory_t tng_data,
5663                  tng_gen_block_t block,
5664                  int *offset,
5665                  const char datatype,
5666                  const int64_t num_first_particle,
5667                  const int64_t n_particles,
5668                  const int64_t first_frame_with_data,
5669                  const int64_t stride_length,
5670                  int64_t n_frames,
5671                  const int64_t n_values,
5672                  const int64_t codec_id,
5673                  const double multiplier)
5674 {
5675     int64_t i, j, k, tot_n_particles, n_frames_div;
5676     int size, len;
5677     int64_t data_size;
5678     char ***first_dim_values, **second_dim_values;
5679     tng_particle_data_t data;
5680     tng_trajectory_frame_set_t frame_set =
5681     &tng_data->current_trajectory_frame_set;
5682     char block_type_flag;
5683
5684     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5685
5686     switch(datatype)
5687     {
5688     case TNG_CHAR_DATA:
5689         size = 1;
5690         break;
5691     case TNG_INT_DATA:
5692         size = sizeof(int64_t);
5693         break;
5694     case TNG_FLOAT_DATA:
5695         size = sizeof(float);
5696         break;
5697     case TNG_DOUBLE_DATA:
5698     default:
5699         size = sizeof(double);
5700     }
5701
5702     /* If the block does not exist, create it */
5703     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5704     {
5705         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5706         {
5707             block_type_flag = TNG_TRAJECTORY_BLOCK;
5708         }
5709         else
5710         {
5711             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5712         }
5713
5714         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
5715            TNG_SUCCESS)
5716         {
5717             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5718                    __FILE__, __LINE__);
5719             return(TNG_CRITICAL);
5720         }
5721         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5722         {
5723             data = &frame_set->tr_particle_data[frame_set->
5724                                                 n_particle_data_blocks - 1];
5725         }
5726         else
5727         {
5728             data = &tng_data->non_tr_particle_data[tng_data->
5729                                                    n_particle_data_blocks - 1];
5730         }
5731         data->block_id = block->id;
5732
5733         data->block_name = malloc(strlen(block->name) + 1);
5734         if(!data->block_name)
5735         {
5736             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5737                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5738             return(TNG_CRITICAL);
5739         }
5740         strcpy(data->block_name, block->name);
5741
5742         data->datatype = datatype;
5743
5744         data->values = 0;
5745         /* FIXME: Memory leak from strings. */
5746         data->strings = 0;
5747         data->n_frames = 0;
5748         data->codec_id = codec_id;
5749         data->compression_multiplier = multiplier;
5750         data->last_retrieved_frame = -1;
5751     }
5752
5753     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
5754        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
5755        tng_data->var_num_atoms_flag)
5756     {
5757         tot_n_particles = frame_set->n_particles;
5758     }
5759     else
5760     {
5761         tot_n_particles = tng_data->n_particles;
5762     }
5763
5764     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5765
5766     if(codec_id != TNG_UNCOMPRESSED)
5767     {
5768         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
5769         switch(codec_id)
5770         {
5771         case TNG_XTC_COMPRESSION:
5772             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5773             break;
5774         case TNG_TNG_COMPRESSION:
5775 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5776             if(tng_uncompress(tng_data, block, datatype,
5777                               block->block_contents + *offset,
5778                               data_size) != TNG_SUCCESS)
5779             {
5780                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5781                        __FILE__, __LINE__);
5782                 return(TNG_CRITICAL);
5783             }
5784 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5785             break;
5786 #ifdef USE_ZLIB
5787         case TNG_GZIP_COMPRESSION:
5788 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5789             if(tng_gzip_uncompress(tng_data, block,
5790                                    block->block_contents + *offset,
5791                                    data_size) != TNG_SUCCESS)
5792             {
5793                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5794                     __LINE__);
5795                 return(TNG_CRITICAL);
5796             }
5797 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5798             break;
5799 #endif
5800         }
5801     }
5802     /* Allocate memory */
5803     if(!data->values || data->n_frames != n_frames ||
5804        data->n_values_per_frame != n_values)
5805     {
5806         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
5807                                           stride_length,
5808                                           tot_n_particles, n_values) !=
5809            TNG_SUCCESS)
5810         {
5811             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
5812                    __FILE__, __LINE__);
5813             return(TNG_CRITICAL);
5814         }
5815     }
5816
5817     data->first_frame_with_data = first_frame_with_data;
5818
5819     if(datatype == TNG_CHAR_DATA)
5820     {
5821         for(i = 0; i < n_frames_div; i++)
5822         {
5823             first_dim_values = data->strings[i];
5824             for(j = num_first_particle; j < num_first_particle + n_particles;
5825                 j++)
5826             {
5827                 second_dim_values = first_dim_values[j];
5828                 for(k = 0; k < n_values; k++)
5829                 {
5830                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5831                               TNG_MAX_STR_LEN);
5832                     if(second_dim_values[k])
5833                     {
5834                         free(second_dim_values[k]);
5835                     }
5836                     second_dim_values[k] = malloc(len);
5837                     if(!second_dim_values[k])
5838                     {
5839                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5840                             len, __FILE__, __LINE__);
5841                         return(TNG_CRITICAL);
5842                     }
5843                     strncpy(second_dim_values[k],
5844                             block->block_contents+*offset, len);
5845                     *offset += len;
5846                 }
5847             }
5848         }
5849     }
5850     else
5851     {
5852         memcpy((char *)data->values + n_frames_div * size * n_values *
5853                num_first_particle,
5854                block->block_contents + *offset,
5855                block->block_contents_size - *offset);
5856         switch(datatype)
5857         {
5858         case TNG_FLOAT_DATA:
5859             if(tng_data->input_endianness_swap_func_32)
5860             {
5861                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5862                 {
5863                     if(tng_data->input_endianness_swap_func_32(tng_data,
5864                         (int32_t *)((char *)data->values + i))
5865                         != TNG_SUCCESS)
5866                     {
5867                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5868                                 __FILE__, __LINE__);
5869                     }
5870                 }
5871             }
5872             break;
5873         case TNG_INT_DATA:
5874         case TNG_DOUBLE_DATA:
5875             if(tng_data->input_endianness_swap_func_64)
5876             {
5877                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5878                 {
5879                     if(tng_data->input_endianness_swap_func_64(tng_data,
5880                         (int64_t *)((char *)data->values + i))
5881                         != TNG_SUCCESS)
5882                     {
5883                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5884                                 __FILE__, __LINE__);
5885                     }
5886                 }
5887             }
5888             break;
5889         case TNG_CHAR_DATA:
5890             break;
5891         }
5892     }
5893     return(TNG_SUCCESS);
5894 }
5895
5896 /** Write a particle data block
5897  * @param tng_data is a trajectory data container.
5898  * @param block is the block to store the data (should already contain
5899  * the block headers and the block contents).
5900  * @param block_index is the index number of the data block in the frame set.
5901  * @param mapping is the particle mapping that is relevant for the data block.
5902  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5903  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5904  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5905  * error has occured.
5906  */
5907 static tng_function_status tng_particle_data_block_write
5908                 (tng_trajectory_t tng_data,
5909                  tng_gen_block_t block,
5910                  const int64_t block_index,
5911                  const tng_particle_mapping_t mapping,
5912                  const char hash_mode)
5913 {
5914     int64_t n_particles, num_first_particle, n_frames, stride_length;
5915     int64_t frame_step, data_start_pos;
5916     int64_t i, j, k;
5917     int size;
5918     size_t len, offset = 0;
5919     char dependency, temp, *temp_name;
5920     double multiplier;
5921     char ***first_dim_values, **second_dim_values;
5922     tng_trajectory_frame_set_t frame_set;
5923     tng_function_status stat;
5924
5925     tng_particle_data_t data;
5926     char block_type_flag;
5927
5928     frame_set = &tng_data->current_trajectory_frame_set;
5929
5930     /* If we have already started writing frame sets it is too late to write
5931      * non-trajectory data blocks */
5932     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5933     {
5934         block_type_flag = TNG_TRAJECTORY_BLOCK;
5935     }
5936     else
5937     {
5938         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5939     }
5940
5941     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5942     {
5943         return(TNG_CRITICAL);
5944     }
5945
5946     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5947     {
5948         data = &frame_set->tr_particle_data[block_index];
5949
5950         /* If this data block has not had any data added in this frame set
5951          * do not write it. */
5952         if(data->first_frame_with_data < frame_set->first_frame)
5953         {
5954             return(TNG_SUCCESS);
5955         }
5956
5957         stride_length = tng_max_i64(1, data->stride_length);
5958     }
5959     else
5960     {
5961         data = &tng_data->non_tr_particle_data[block_index];
5962         stride_length = 1;
5963     }
5964
5965     switch(data->datatype)
5966     {
5967     case TNG_CHAR_DATA:
5968         size = 1;
5969         break;
5970     case TNG_INT_DATA:
5971         size = sizeof(int64_t);
5972         break;
5973     case TNG_FLOAT_DATA:
5974         size = sizeof(float);
5975         break;
5976     case TNG_DOUBLE_DATA:
5977     default:
5978         size = sizeof(double);
5979     }
5980
5981     len = strlen(data->block_name) + 1;
5982
5983     if(!block->name || strlen(block->name) < len)
5984     {
5985         temp_name = realloc(block->name, len);
5986         if(!temp_name)
5987         {
5988             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
5989                    __FILE__, __LINE__);
5990             free(block->name);
5991             block->name = 0;
5992             return(TNG_CRITICAL);
5993         }
5994         block->name = temp_name;
5995     }
5996     strncpy(block->name, data->block_name, len);
5997     block->id = data->block_id;
5998
5999     /* If writing frame independent data data->n_frames is 0, but n_frames
6000        is used for the loop writing the data (and reserving memory) and needs
6001        to be at least 1 */
6002     n_frames = tng_max_i64(1, data->n_frames);
6003
6004     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6005     {
6006         /* If the frame set is finished before writing the full number of frames
6007            make sure the data block is not longer than the frame set. */
6008         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6009
6010         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6011     }
6012
6013     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6014                  n_frames / stride_length;
6015
6016     /* TNG compression will use compression precision to get integers from
6017      * floating point data. The compression multiplier stores that information
6018      * to be able to return the precision of the compressed data. */
6019     if(data->codec_id == TNG_TNG_COMPRESSION)
6020     {
6021         data->compression_multiplier = tng_data->compression_precision;
6022     }
6023     /* Uncompressed data blocks do not use compression multipliers at all.
6024      * GZip compression does not need it either. */
6025     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6026     {
6027         data->compression_multiplier = 1.0;
6028     }
6029
6030     if(mapping && mapping->n_particles != 0)
6031     {
6032         n_particles = mapping->n_particles;
6033         num_first_particle = mapping->num_first_particle;
6034     }
6035     else
6036     {
6037         num_first_particle = 0;
6038         if(tng_data->var_num_atoms_flag)
6039         {
6040             n_particles = frame_set->n_particles;
6041         }
6042         else
6043         {
6044             n_particles = tng_data->n_particles;
6045         }
6046     }
6047
6048     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6049     {
6050         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
6051     }
6052     else
6053     {
6054         dependency = TNG_PARTICLE_DEPENDENT;
6055     }
6056
6057     if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
6058                                     frame_step, stride_length, num_first_particle,
6059                                     n_particles, dependency, &data_start_pos,
6060                                     &block->block_contents_size) != TNG_SUCCESS)
6061     {
6062         fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
6063                 __FILE__, __LINE__);
6064         return(TNG_CRITICAL);
6065     }
6066
6067     if(block->block_contents)
6068     {
6069         free(block->block_contents);
6070     }
6071     block->block_contents = malloc(block->block_contents_size);
6072     if(!block->block_contents)
6073     {
6074         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6075                block->block_contents_size, __FILE__, __LINE__);
6076         return(TNG_CRITICAL);
6077     }
6078
6079
6080     memcpy(block->block_contents, &data->datatype, sizeof(char));
6081     offset += sizeof(char);
6082
6083     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6084     offset += sizeof(char);
6085
6086     if(dependency & TNG_FRAME_DEPENDENT)
6087     {
6088         if(stride_length > 1)
6089         {
6090             temp = 1;
6091         }
6092         else
6093         {
6094             temp = 0;
6095         }
6096         memcpy(block->block_contents+offset, &temp, sizeof(char));
6097         offset += sizeof(char);
6098     }
6099
6100     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6101            sizeof(data->n_values_per_frame));
6102     if(tng_data->output_endianness_swap_func_64)
6103     {
6104         if(tng_data->output_endianness_swap_func_64(tng_data,
6105            (int64_t *)block->header_contents+offset)
6106             != TNG_SUCCESS)
6107         {
6108             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6109                     __FILE__, __LINE__);
6110         }
6111     }
6112     offset += sizeof(data->n_values_per_frame);
6113
6114     memcpy(block->block_contents+offset, &data->codec_id,
6115            sizeof(data->codec_id));
6116     if(tng_data->output_endianness_swap_func_64)
6117     {
6118         if(tng_data->output_endianness_swap_func_64(tng_data,
6119            (int64_t *)block->header_contents+offset)
6120             != TNG_SUCCESS)
6121         {
6122             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6123                     __FILE__, __LINE__);
6124         }
6125     }
6126     offset += sizeof(data->codec_id);
6127
6128     if(data->codec_id != TNG_UNCOMPRESSED)
6129     {
6130         memcpy(block->block_contents+offset, &data->compression_multiplier,
6131                sizeof(data->compression_multiplier));
6132         if(tng_data->output_endianness_swap_func_64)
6133         {
6134             if(tng_data->output_endianness_swap_func_64(tng_data,
6135                (int64_t *)block->header_contents+offset)
6136                 != TNG_SUCCESS)
6137             {
6138                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6139                         __FILE__, __LINE__);
6140             }
6141         }
6142         offset += sizeof(data->compression_multiplier);
6143     }
6144
6145     if(data->n_frames > 0 && stride_length > 1)
6146     {
6147         /* FIXME: first_frame_with_data is not reliably set */
6148         if(data->first_frame_with_data == 0)
6149         {
6150             data->first_frame_with_data = frame_set->first_frame;
6151         }
6152         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6153                sizeof(data->first_frame_with_data));
6154         if(tng_data->output_endianness_swap_func_64)
6155         {
6156             if(tng_data->output_endianness_swap_func_64(tng_data,
6157                (int64_t *)block->header_contents+offset)
6158                 != TNG_SUCCESS)
6159             {
6160                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6161                         __FILE__, __LINE__);
6162             }
6163         }
6164         offset += sizeof(data->first_frame_with_data);
6165
6166         memcpy(block->block_contents+offset, &stride_length,
6167                sizeof(stride_length));
6168         if(tng_data->output_endianness_swap_func_64)
6169         {
6170             if(tng_data->output_endianness_swap_func_64(tng_data,
6171                (int64_t *)block->header_contents+offset)
6172                 != TNG_SUCCESS)
6173             {
6174                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6175                         __FILE__, __LINE__);
6176             }
6177         }
6178         offset += sizeof(stride_length);
6179     }
6180
6181
6182     memcpy(block->block_contents+offset, &num_first_particle,
6183            sizeof(num_first_particle));
6184     if(tng_data->output_endianness_swap_func_64)
6185     {
6186         if(tng_data->output_endianness_swap_func_64(tng_data,
6187            (int64_t *)block->header_contents+offset)
6188             != TNG_SUCCESS)
6189         {
6190             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6191                     __FILE__, __LINE__);
6192         }
6193     }
6194     offset += sizeof(num_first_particle);
6195
6196     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
6197     if(tng_data->output_endianness_swap_func_64)
6198     {
6199         if(tng_data->output_endianness_swap_func_64(tng_data,
6200            (int64_t *)block->header_contents+offset)
6201             != TNG_SUCCESS)
6202         {
6203             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6204                     __FILE__, __LINE__);
6205         }
6206     }
6207     offset += sizeof(n_particles);
6208
6209     if(data->datatype == TNG_CHAR_DATA)
6210     {
6211         if(data->strings)
6212         {
6213             for(i = 0; i < frame_step; i++)
6214             {
6215                 first_dim_values = data->strings[i];
6216                 for(j = num_first_particle; j < num_first_particle + n_particles;
6217                     j++)
6218                 {
6219                     second_dim_values = first_dim_values[j];
6220                     for(k = 0; k < data->n_values_per_frame; k++)
6221                     {
6222                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
6223                         strncpy(block->block_contents+offset,
6224                                 second_dim_values[k], len);
6225                         offset += len;
6226                     }
6227                 }
6228             }
6229         }
6230     }
6231     else if(data->values)
6232     {
6233         memcpy(block->block_contents + offset, data->values,
6234                block->block_contents_size - offset);
6235
6236         switch(data->datatype)
6237         {
6238         case TNG_FLOAT_DATA:
6239             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6240                data->codec_id == TNG_TNG_COMPRESSION)
6241             {
6242                 if(tng_data->input_endianness_swap_func_32)
6243                 {
6244                     for(i = offset; i < block->block_contents_size; i+=size)
6245                     {
6246                         if(tng_data->input_endianness_swap_func_32(tng_data,
6247                            (int32_t *)(block->block_contents + i))
6248                            != TNG_SUCCESS)
6249                         {
6250                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6251                                     __FILE__, __LINE__);
6252                         }
6253                     }
6254                 }
6255             }
6256             else
6257             {
6258                 multiplier = data->compression_multiplier;
6259                 if(fabs(multiplier - 1.0) > 0.00001 ||
6260                    tng_data->input_endianness_swap_func_32)
6261                 {
6262                     for(i = offset; i < block->block_contents_size; i+=size)
6263                     {
6264                         *(float *)(block->block_contents + i) *= (float)multiplier;
6265                         if(tng_data->input_endianness_swap_func_32 &&
6266                         tng_data->input_endianness_swap_func_32(tng_data,
6267                         (int32_t *)(block->block_contents + i))
6268                         != TNG_SUCCESS)
6269                         {
6270                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6271                                     __FILE__, __LINE__);
6272                         }
6273                     }
6274                 }
6275             }
6276             break;
6277         case TNG_INT_DATA:
6278             if(tng_data->input_endianness_swap_func_64)
6279             {
6280                 for(i = offset; i < block->block_contents_size; i+=size)
6281                 {
6282                     if(tng_data->input_endianness_swap_func_64(tng_data,
6283                        (int64_t *)(block->block_contents + i))
6284                        != TNG_SUCCESS)
6285                     {
6286                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6287                                 __FILE__, __LINE__);
6288                     }
6289                 }
6290             }
6291             break;
6292         case TNG_DOUBLE_DATA:
6293             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6294                data->codec_id == TNG_TNG_COMPRESSION)
6295             {
6296                 if(tng_data->input_endianness_swap_func_64)
6297                 {
6298                     for(i = offset; i < block->block_contents_size; i+=size)
6299                     {
6300                         if(tng_data->input_endianness_swap_func_64(tng_data,
6301                            (int64_t *)(block->block_contents + i))
6302                            != TNG_SUCCESS)
6303                         {
6304                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6305                                     __FILE__, __LINE__);
6306                         }
6307                     }
6308                 }
6309             }
6310             else
6311             {
6312                 multiplier = data->compression_multiplier;
6313                 if(fabs(multiplier - 1.0) > 0.00001 ||
6314                    tng_data->input_endianness_swap_func_64)
6315                 {
6316                     for(i = offset; i < block->block_contents_size; i+=size)
6317                     {
6318                         *(double *)(block->block_contents + i) *= multiplier;
6319                         if(tng_data->input_endianness_swap_func_64 &&
6320                         tng_data->input_endianness_swap_func_64(tng_data,
6321                         (int64_t *)(block->block_contents + i))
6322                         != TNG_SUCCESS)
6323                         {
6324                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6325                                     __FILE__, __LINE__);
6326                         }
6327                     }
6328                 }
6329             }
6330             break;
6331         case TNG_CHAR_DATA:
6332             break;
6333         }
6334     }
6335     else
6336     {
6337         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6338     }
6339
6340     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6341     frame_set->n_unwritten_frames = 0;
6342
6343     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6344     {
6345         switch(data->codec_id)
6346         {
6347         case TNG_XTC_COMPRESSION:
6348             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6349             data->codec_id = TNG_UNCOMPRESSED;
6350             break;
6351         case TNG_TNG_COMPRESSION:
6352             stat = tng_compress(tng_data, block, frame_step,
6353                                 n_particles, data->datatype,
6354                                 block->block_contents + data_start_pos);
6355             if(stat != TNG_SUCCESS)
6356             {
6357                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
6358                     __FILE__, __LINE__);
6359                 if(stat == TNG_CRITICAL)
6360                 {
6361                     return(TNG_CRITICAL);
6362                 }
6363                 /* Set the data again, but with no compression (to write only
6364                  * the relevant data) */
6365                 data->codec_id = TNG_UNCOMPRESSED;
6366                 stat = tng_particle_data_block_write(tng_data, block,
6367                                                      block_index, mapping,
6368                                                      hash_mode);
6369                 return(stat);
6370             }
6371             break;
6372 #ifdef USE_ZLIB
6373         case TNG_GZIP_COMPRESSION:
6374     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
6375             stat = tng_gzip_compress(tng_data, block,
6376                                      block->block_contents + data_start_pos,
6377                                      block->block_contents_size - data_start_pos);
6378             if(stat != TNG_SUCCESS)
6379             {
6380                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6381                     __LINE__);
6382                 if(stat == TNG_CRITICAL)
6383                 {
6384                     return(TNG_CRITICAL);
6385                 }
6386                 /* Set the data again, but with no compression (to write only
6387                  * the relevant data) */
6388                 data->codec_id = TNG_UNCOMPRESSED;
6389                 stat = tng_particle_data_block_write(tng_data, block,
6390                                                      block_index, mapping,
6391                                                      hash_mode);
6392                 return(stat);
6393             }
6394     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
6395             break;
6396 #endif
6397         }
6398     }
6399
6400     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6401     {
6402         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6403                tng_data->output_file_path, __FILE__, __LINE__);
6404         return(TNG_CRITICAL);
6405     }
6406
6407     if(fwrite(block->block_contents, block->block_contents_size, 1,
6408         tng_data->output_file) != 1)
6409     {
6410         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6411                 __LINE__);
6412         return(TNG_CRITICAL);
6413     }
6414
6415     return(TNG_SUCCESS);
6416 }
6417
6418 /* TEST: */
6419 /** Create a non-particle data block
6420  * @param tng_data is a trajectory data container.
6421  * @param block_type_flag specifies if this is a trajectory block or a
6422  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
6423  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6424  * error has occured.
6425  */
6426 static tng_function_status tng_data_block_create
6427                 (tng_trajectory_t tng_data,
6428                  const char block_type_flag)
6429 {
6430     tng_trajectory_frame_set_t frame_set =
6431     &tng_data->current_trajectory_frame_set;
6432
6433     tng_non_particle_data_t data;
6434
6435     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6436     {
6437         frame_set->n_data_blocks++;
6438         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
6439                        frame_set->n_data_blocks);
6440         if(!data)
6441         {
6442             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6443                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
6444                 __FILE__, __LINE__);
6445             free(frame_set->tr_data);
6446             frame_set->tr_data = 0;
6447             return(TNG_CRITICAL);
6448         }
6449         frame_set->tr_data = data;
6450     }
6451     else
6452     {
6453         tng_data->n_data_blocks++;
6454         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
6455                         tng_data->n_data_blocks);
6456         if(!data)
6457         {
6458             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6459                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
6460                 __FILE__, __LINE__);
6461             free(tng_data->non_tr_data);
6462             tng_data->non_tr_data = 0;
6463             return(TNG_CRITICAL);
6464         }
6465         tng_data->non_tr_data = data;
6466     }
6467
6468     return(TNG_SUCCESS);
6469 }
6470
6471 /* TEST: */
6472 /** Allocate memory for storing non-particle data.
6473  * The allocated block will be refered to by data->values.
6474  * @param tng_data is a trajectory data container.
6475  * @param data is the data struct, which will contain the allocated memory in
6476  * data->values.
6477  * @param n_frames is the number of frames of data to store.
6478  * @param n_values_per_frame is the number of data values per frame.
6479  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6480  * error has occured.
6481  */
6482 static tng_function_status tng_allocate_data_mem
6483                 (tng_trajectory_t tng_data,
6484                  tng_non_particle_data_t data,
6485                  int64_t n_frames,
6486                  int64_t stride_length,
6487                  const int64_t n_values_per_frame)
6488 {
6489     void **values;
6490     int64_t i, j, size, frame_alloc;
6491     (void)tng_data;
6492
6493     if(n_values_per_frame == 0)
6494     {
6495         return(TNG_FAILURE);
6496     }
6497
6498     if(data->strings && data->datatype == TNG_CHAR_DATA)
6499     {
6500         for(i = 0; i < data->n_frames; i++)
6501         {
6502             for(j = 0; j < data->n_values_per_frame; j++)
6503             {
6504                 if(data->strings[i][j])
6505                 {
6506                     free(data->strings[i][j]);
6507                     data->strings[i][j] = 0;
6508                 }
6509             }
6510             free(data->strings[i]);
6511             data->strings[i] = 0;
6512         }
6513         free(data->strings);
6514     }
6515     data->n_frames = n_frames;
6516     data->stride_length = tng_max_i64(1, stride_length);
6517     n_frames = tng_max_i64(1, n_frames);
6518     data->n_values_per_frame = n_values_per_frame;
6519     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6520
6521     if(data->datatype == TNG_CHAR_DATA)
6522     {
6523         data->strings = malloc(sizeof(char **) * frame_alloc);
6524         for(i = 0; i < frame_alloc; i++)
6525         {
6526             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
6527             if(!data->strings[i])
6528             {
6529                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6530                        n_values_per_frame,
6531                        __FILE__, __LINE__);
6532                 return(TNG_CRITICAL);
6533             }
6534             for(j = 0; j < n_values_per_frame; j++)
6535             {
6536                 data->strings[i][j] = 0;
6537             }
6538         }
6539     }
6540     else
6541     {
6542         switch(data->datatype)
6543         {
6544         case TNG_INT_DATA:
6545             size = sizeof(int64_t);
6546             break;
6547         case TNG_FLOAT_DATA:
6548             size = sizeof(float);
6549             break;
6550         case TNG_DOUBLE_DATA:
6551         default:
6552             size = sizeof(double);
6553         }
6554
6555         values = realloc(data->values,
6556                          size * frame_alloc *
6557                          n_values_per_frame);
6558         if(!values)
6559         {
6560             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6561                    size * frame_alloc *
6562                    n_values_per_frame,
6563                    __FILE__, __LINE__);
6564             free(data->values);
6565             data->values = 0;
6566             return(TNG_CRITICAL);
6567         }
6568         data->values = values;
6569     }
6570
6571     return(TNG_SUCCESS);
6572 }
6573
6574 /** Read the values of a non-particle data block
6575  * @param tng_data is a trajectory data container.
6576  * @param block is the block to store the data (should already contain
6577  * the block headers and the block contents).
6578  * @param offset is the reading offset to point at the place where the actual
6579  * values are stored, starting from the beginning of the block_contents. The
6580  * offset is changed during the reading.
6581  * @param datatype is the type of data of the data block (char, int, float or
6582  * double).
6583  * @param first_frame_with_data is the frame number of the first frame with data
6584  * in this data block.
6585  * @param stride_length is the number of frames between each data entry.
6586  * @param n_frames is the number of frames in this data block.
6587  * @param n_values is the number of values per frame stored in this data block.
6588  * @param codec_id is the ID of the codec to compress the data.
6589  * @param multiplier is the multiplication factor applied to each data value
6590  * before compression. This factor is applied since some compression algorithms
6591  * work only on integers.
6592  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6593  * error has occured.
6594  */
6595 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
6596                                          tng_gen_block_t block,
6597                                          int *offset,
6598                                          const char datatype,
6599                                          const int64_t first_frame_with_data,
6600                                          const int64_t stride_length,
6601                                          int64_t n_frames,
6602                                          const int64_t n_values,
6603                                          const int64_t codec_id,
6604                                          const double multiplier)
6605 {
6606     int64_t i, j, n_frames_div;
6607     int size, len;
6608 #ifdef USE_ZLIB
6609     int64_t data_size;
6610 #endif
6611     tng_non_particle_data_t data;
6612     tng_trajectory_frame_set_t frame_set =
6613     &tng_data->current_trajectory_frame_set;
6614     char block_type_flag;
6615
6616     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
6617
6618 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
6619
6620     switch(datatype)
6621     {
6622     case TNG_CHAR_DATA:
6623         size = 1;
6624         break;
6625     case TNG_INT_DATA:
6626         size = sizeof(int64_t);
6627         break;
6628     case TNG_FLOAT_DATA:
6629         size = sizeof(float);
6630         break;
6631     case TNG_DOUBLE_DATA:
6632     default:
6633         size = sizeof(double);
6634     }
6635
6636     /* If the block does not exist, create it */
6637     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
6638     {
6639         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
6640         {
6641             block_type_flag = TNG_TRAJECTORY_BLOCK;
6642         }
6643         else
6644         {
6645             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6646         }
6647
6648         if(tng_data_block_create(tng_data, block_type_flag) !=
6649             TNG_SUCCESS)
6650         {
6651             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
6652                    __FILE__, __LINE__);
6653             return(TNG_CRITICAL);
6654         }
6655         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6656         {
6657             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
6658         }
6659         else
6660         {
6661             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
6662         }
6663         data->block_id = block->id;
6664
6665         data->block_name = malloc(strlen(block->name) + 1);
6666         if(!data->block_name)
6667         {
6668             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6669                    (int)strlen(block->name)+1, __FILE__, __LINE__);
6670             return(TNG_CRITICAL);
6671         }
6672         strcpy(data->block_name, block->name);
6673
6674         data->datatype = datatype;
6675
6676         data->values = 0;
6677         /* FIXME: Memory leak from strings. */
6678         data->strings = 0;
6679         data->n_frames = 0;
6680         data->codec_id = codec_id;
6681         data->compression_multiplier = multiplier;
6682         data->last_retrieved_frame = -1;
6683     }
6684
6685     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6686
6687     if(codec_id != TNG_UNCOMPRESSED)
6688     {
6689         switch(codec_id)
6690         {
6691 #ifdef USE_ZLIB
6692         case TNG_GZIP_COMPRESSION:
6693             data_size = n_frames_div * size * n_values;
6694     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6695             if(tng_gzip_uncompress(tng_data, block,
6696                                    block->block_contents + *offset,
6697                                    data_size) != TNG_SUCCESS)
6698             {
6699                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
6700                     __LINE__);
6701                 return(TNG_CRITICAL);
6702             }
6703     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6704             break;
6705 #endif
6706         }
6707     }
6708
6709     /* Allocate memory */
6710     if(!data->values || data->n_frames != n_frames ||
6711        data->n_values_per_frame != n_values)
6712     {
6713         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
6714                                  n_values) !=
6715            TNG_SUCCESS)
6716         {
6717             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
6718                    __FILE__, __LINE__);
6719             return(TNG_CRITICAL);
6720         }
6721     }
6722
6723     data->first_frame_with_data = first_frame_with_data;
6724
6725     if(datatype == TNG_CHAR_DATA)
6726     {
6727         for(i = 0; i < n_frames_div; i++)
6728         {
6729             for(j = 0; j < n_values; j++)
6730             {
6731                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
6732                               TNG_MAX_STR_LEN);
6733                 if(data->strings[i][j])
6734                 {
6735                     free(data->strings[i][j]);
6736                 }
6737                 data->strings[i][j] = malloc(len);
6738                 if(!data->strings[i][j])
6739                 {
6740                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6741                            len, __FILE__, __LINE__);
6742                     return(TNG_CRITICAL);
6743                 }
6744                 strncpy(data->strings[i][j], block->block_contents+*offset,
6745                         len);
6746                 *offset += len;
6747             }
6748         }
6749     }
6750     else
6751     {
6752         memcpy(data->values, block->block_contents + *offset,
6753                block->block_contents_size - *offset);
6754         switch(datatype)
6755         {
6756         case TNG_FLOAT_DATA:
6757             if(tng_data->input_endianness_swap_func_32)
6758             {
6759                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6760                 {
6761                     if(tng_data->input_endianness_swap_func_32(tng_data,
6762                         (int32_t *)((char *)data->values + i))
6763                         != TNG_SUCCESS)
6764                     {
6765                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6766                                 __FILE__, __LINE__);
6767                     }
6768                 }
6769             }
6770             break;
6771         case TNG_INT_DATA:
6772         case TNG_DOUBLE_DATA:
6773             if(tng_data->input_endianness_swap_func_64)
6774             {
6775                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6776                 {
6777                     if(tng_data->input_endianness_swap_func_64(tng_data,
6778                         (int64_t *)((char *)data->values + i))
6779                         != TNG_SUCCESS)
6780                     {
6781                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6782                                 __FILE__, __LINE__);
6783                     }
6784                 }
6785             }
6786             break;
6787         case TNG_CHAR_DATA:
6788             break;
6789         }
6790     }
6791     return(TNG_SUCCESS);
6792 }
6793
6794 /** Write a non-particle data block
6795  * @param tng_data is a trajectory data container.
6796  * @param block is the block to store the data (should already contain
6797  * the block headers and the block contents).
6798  * @param block_index is the index number of the data block in the frame set.
6799  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6800  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
6801  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6802  * error has occured.
6803  */
6804 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
6805                                                 tng_gen_block_t block,
6806                                                 const int64_t block_index,
6807                                                 const char hash_mode)
6808 {
6809     int64_t n_frames, stride_length, frame_step, data_start_pos;
6810     int64_t i, j;
6811     int offset = 0, size;
6812     unsigned int len;
6813 #ifdef USE_ZLIB
6814     tng_function_status stat;
6815 #endif
6816     char temp, dependency, *temp_name;
6817     double multiplier;
6818     tng_trajectory_frame_set_t frame_set =
6819     &tng_data->current_trajectory_frame_set;
6820
6821     tng_non_particle_data_t data;
6822     char block_type_flag;
6823
6824     /* If we have already started writing frame sets it is too late to write
6825      * non-trajectory data blocks */
6826     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
6827     {
6828         block_type_flag = TNG_TRAJECTORY_BLOCK;
6829     }
6830     else
6831     {
6832         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6833     }
6834
6835     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6836     {
6837         return(TNG_CRITICAL);
6838     }
6839
6840     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6841     {
6842         data = &frame_set->tr_data[block_index];
6843
6844         /* If this data block has not had any data added in this frame set
6845          * do not write it. */
6846         if(data->first_frame_with_data < frame_set->first_frame)
6847         {
6848             return(TNG_SUCCESS);
6849         }
6850
6851         stride_length = tng_max_i64(1, data->stride_length);
6852     }
6853     else
6854     {
6855         data = &tng_data->non_tr_data[block_index];
6856         stride_length = 1;
6857     }
6858
6859     switch(data->datatype)
6860     {
6861     case TNG_CHAR_DATA:
6862         size = 1;
6863         break;
6864     case TNG_INT_DATA:
6865         size = sizeof(int64_t);
6866         break;
6867     case TNG_FLOAT_DATA:
6868         size = sizeof(float);
6869         break;
6870     case TNG_DOUBLE_DATA:
6871     default:
6872         size = sizeof(double);
6873     }
6874
6875     len = (unsigned int)strlen(data->block_name) + 1;
6876
6877     if(!block->name || strlen(block->name) < len)
6878     {
6879         temp_name = realloc(block->name, len);
6880         if(!temp_name)
6881         {
6882             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
6883                    __FILE__, __LINE__);
6884             free(block->name);
6885             block->name = 0;
6886             return(TNG_CRITICAL);
6887         }
6888         block->name = temp_name;
6889     }
6890     strncpy(block->name, data->block_name, len);
6891     block->id = data->block_id;
6892
6893     /* If writing frame independent data data->n_frames is 0, but n_frames
6894        is used for the loop writing the data (and reserving memory) and needs
6895        to be at least 1 */
6896     n_frames = tng_max_i64(1, data->n_frames);
6897
6898     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6899     {
6900         /* If the frame set is finished before writing the full number of frames
6901            make sure the data block is not longer than the frame set. */
6902         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6903
6904         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6905     }
6906
6907     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6908                  n_frames / stride_length;
6909
6910     /* TNG compression will use compression precision to get integers from
6911      * floating point data. The compression multiplier stores that information
6912      * to be able to return the precision of the compressed data. */
6913     if(data->codec_id == TNG_TNG_COMPRESSION)
6914     {
6915         data->compression_multiplier = tng_data->compression_precision;
6916     }
6917     /* Uncompressed data blocks do not use compression multipliers at all.
6918      * GZip compression does not need it either. */
6919     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6920     {
6921         data->compression_multiplier = 1.0;
6922     }
6923
6924     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6925     {
6926         dependency = TNG_FRAME_DEPENDENT;
6927     }
6928     else
6929     {
6930         dependency = 0;
6931     }
6932
6933     if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames,
6934                                     frame_step, stride_length, 0,
6935                                     1, dependency, &data_start_pos,
6936                                     &block->block_contents_size) != TNG_SUCCESS)
6937     {
6938         fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
6939                 __FILE__, __LINE__);
6940         return(TNG_CRITICAL);
6941     }
6942
6943     if(block->block_contents)
6944     {
6945         free(block->block_contents);
6946     }
6947     block->block_contents = malloc(block->block_contents_size);
6948     if(!block->block_contents)
6949     {
6950         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6951                block->block_contents_size, __FILE__, __LINE__);
6952         return(TNG_CRITICAL);
6953     }
6954
6955
6956     memcpy(block->block_contents, &data->datatype, sizeof(char));
6957     offset += sizeof(char);
6958
6959     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6960     offset += sizeof(char);
6961
6962     if(dependency & TNG_FRAME_DEPENDENT)
6963     {
6964         if(stride_length > 1)
6965         {
6966             temp = 1;
6967         }
6968         else
6969         {
6970             temp = 0;
6971         }
6972         memcpy(block->block_contents+offset, &temp, sizeof(char));
6973         offset += sizeof(char);
6974     }
6975
6976     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6977            sizeof(data->n_values_per_frame));
6978     if(tng_data->output_endianness_swap_func_64)
6979     {
6980         if(tng_data->output_endianness_swap_func_64(tng_data,
6981            (int64_t *)block->header_contents+offset)
6982             != TNG_SUCCESS)
6983         {
6984             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6985                     __FILE__, __LINE__);
6986         }
6987     }
6988     offset += sizeof(data->n_values_per_frame);
6989
6990     memcpy(block->block_contents+offset, &data->codec_id,
6991            sizeof(data->codec_id));
6992     if(tng_data->output_endianness_swap_func_64)
6993     {
6994         if(tng_data->output_endianness_swap_func_64(tng_data,
6995            (int64_t *)block->header_contents+offset)
6996             != TNG_SUCCESS)
6997         {
6998             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6999                     __FILE__, __LINE__);
7000         }
7001     }
7002     offset += sizeof(data->codec_id);
7003
7004     if(data->codec_id != TNG_UNCOMPRESSED)
7005     {
7006         memcpy(block->block_contents+offset, &data->compression_multiplier,
7007                sizeof(data->compression_multiplier));
7008         if(tng_data->output_endianness_swap_func_64)
7009         {
7010             if(tng_data->output_endianness_swap_func_64(tng_data,
7011             (int64_t *)block->header_contents+offset)
7012                 != TNG_SUCCESS)
7013             {
7014                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7015                         __FILE__, __LINE__);
7016             }
7017         }
7018         offset += sizeof(data->compression_multiplier);
7019     }
7020
7021     if(data->n_frames > 0 && stride_length > 1)
7022     {
7023         /* FIXME: first_frame_with_data is not reliably set */
7024         if(data->first_frame_with_data == 0)
7025         {
7026             data->first_frame_with_data = frame_set->first_frame;
7027         }
7028         memcpy(block->block_contents+offset, &data->first_frame_with_data,
7029                sizeof(data->first_frame_with_data));
7030         if(tng_data->output_endianness_swap_func_64)
7031         {
7032             if(tng_data->output_endianness_swap_func_64(tng_data,
7033             (int64_t *)block->header_contents+offset)
7034                 != TNG_SUCCESS)
7035             {
7036                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7037                         __FILE__, __LINE__);
7038             }
7039         }
7040         offset += sizeof(data->first_frame_with_data);
7041
7042         memcpy(block->block_contents+offset, &stride_length,
7043                sizeof(data->stride_length));
7044         if(tng_data->output_endianness_swap_func_64)
7045         {
7046             if(tng_data->output_endianness_swap_func_64(tng_data,
7047             (int64_t *)block->header_contents+offset)
7048                 != TNG_SUCCESS)
7049             {
7050                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7051                         __FILE__, __LINE__);
7052             }
7053         }
7054         offset += sizeof(data->stride_length);
7055     }
7056
7057     if(data->datatype == TNG_CHAR_DATA)
7058     {
7059         if(data->strings)
7060         {
7061             for(i = 0; i < frame_step; i++)
7062             {
7063                 for(j = 0; j < data->n_values_per_frame; j++)
7064                 {
7065                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
7066                     strncpy(block->block_contents+offset, data->strings[i][j],
7067                             len);
7068                     offset += len;
7069                 }
7070             }
7071         }
7072     }
7073     else if(data->values)
7074     {
7075         memcpy(block->block_contents + offset, data->values,
7076                block->block_contents_size - offset);
7077         switch(data->datatype)
7078         {
7079         case TNG_FLOAT_DATA:
7080             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7081                data->codec_id == TNG_TNG_COMPRESSION)
7082             {
7083                 if(tng_data->input_endianness_swap_func_32)
7084                 {
7085                     for(i = offset; i < block->block_contents_size; i+=size)
7086                     {
7087                         if(tng_data->input_endianness_swap_func_32(tng_data,
7088                            (int32_t *)(block->block_contents + i))
7089                            != TNG_SUCCESS)
7090                         {
7091                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7092                                     __FILE__, __LINE__);
7093                         }
7094                     }
7095                 }
7096             }
7097             else
7098             {
7099                 multiplier = data->compression_multiplier;
7100                 if(fabs(multiplier - 1.0) > 0.00001 ||
7101                    tng_data->input_endianness_swap_func_32)
7102                 {
7103                     for(i = offset; block->block_contents_size; i+=size)
7104                     {
7105                         *(float *)(block->block_contents + i) *= (float)multiplier;
7106                         if(tng_data->input_endianness_swap_func_32 &&
7107                         tng_data->input_endianness_swap_func_32(tng_data,
7108                         (int32_t *)(block->block_contents + i))
7109                         != TNG_SUCCESS)
7110                         {
7111                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7112                                     __FILE__, __LINE__);
7113                         }
7114                     }
7115                 }
7116             }
7117             break;
7118         case TNG_INT_DATA:
7119             if(tng_data->input_endianness_swap_func_64)
7120             {
7121                 for(i = offset; i < block->block_contents_size; i+=size)
7122                 {
7123                     if(tng_data->input_endianness_swap_func_64(tng_data,
7124                        (int64_t *)(block->block_contents + i))
7125                        != TNG_SUCCESS)
7126                     {
7127                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7128                                 __FILE__, __LINE__);
7129                     }
7130                 }
7131             }
7132             break;
7133         case TNG_DOUBLE_DATA:
7134             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7135                data->codec_id == TNG_TNG_COMPRESSION)
7136             {
7137                 if(tng_data->input_endianness_swap_func_64)
7138                 {
7139                     for(i = offset; i < block->block_contents_size; i+=size)
7140                     {
7141                         if(tng_data->input_endianness_swap_func_64(tng_data,
7142                            (int64_t *)(block->block_contents + i))
7143                            != TNG_SUCCESS)
7144                         {
7145                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7146                                     __FILE__, __LINE__);
7147                         }
7148                     }
7149                 }
7150             }
7151             else
7152             {
7153                 multiplier = data->compression_multiplier;
7154                 if(fabs(multiplier - 1.0) > 0.00001 ||
7155                    tng_data->input_endianness_swap_func_64)
7156                 {
7157                     for(i = offset; i < block->block_contents_size; i+=size)
7158                     {
7159                         *(double *)(block->block_contents + i) *= multiplier;
7160                         if(tng_data->input_endianness_swap_func_64 &&
7161                         tng_data->input_endianness_swap_func_64(tng_data,
7162                         (int64_t *)(block->block_contents + i))
7163                         != TNG_SUCCESS)
7164                         {
7165                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7166                                     __FILE__, __LINE__);
7167                         }
7168                     }
7169                 }
7170             }
7171             break;
7172         case TNG_CHAR_DATA:
7173             break;
7174         }
7175     }
7176     else
7177     {
7178         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
7179     }
7180
7181     frame_set->n_written_frames += frame_set->n_unwritten_frames;
7182     frame_set->n_unwritten_frames = 0;
7183
7184     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
7185     {
7186         switch(data->codec_id)
7187         {
7188 #ifdef USE_ZLIB
7189         case TNG_GZIP_COMPRESSION:
7190     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
7191             stat = tng_gzip_compress(tng_data, block,
7192                                      block->block_contents + data_start_pos,
7193                                      block->block_contents_size - data_start_pos);
7194             if(stat != TNG_SUCCESS)
7195             {
7196                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
7197                     __LINE__);
7198                 if(stat == TNG_CRITICAL)
7199                 {
7200                     return(TNG_CRITICAL);
7201                 }
7202                 data->codec_id = TNG_UNCOMPRESSED;
7203             }
7204     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
7205             break;
7206 #endif
7207         }
7208     }
7209
7210     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
7211     {
7212         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
7213                tng_data->output_file_path, __FILE__, __LINE__);
7214         return(TNG_CRITICAL);
7215     }
7216
7217     if(fwrite(block->block_contents, block->block_contents_size, 1,
7218               tng_data->output_file) != 1)
7219     {
7220         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
7221                __FILE__, __LINE__);
7222         return(TNG_CRITICAL);
7223     }
7224
7225     return(TNG_SUCCESS);
7226 }
7227
7228 /** Read the meta information of a data block (particle or non-particle data).
7229  * @param tng_data is a trajectory data container.
7230  * @param block is the block to store the data (should already contain
7231  * the block headers).
7232  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7233  * error has occured.
7234  */
7235 static tng_function_status tng_data_block_meta_information_read
7236                 (tng_trajectory_t tng_data,
7237                  tng_gen_block_t block,
7238                  int *offset,
7239                  char *datatype,
7240                  char *dependency,
7241                  char *sparse_data,
7242                  int64_t *n_values,
7243                  int64_t *codec_id,
7244                  int64_t *first_frame_with_data,
7245                  int64_t *stride_length,
7246                  int64_t *n_frames,
7247                  int64_t *num_first_particle,
7248                  int64_t *block_n_particles,
7249                  double *multiplier)
7250 {
7251     int meta_size;
7252     char *contents;
7253
7254     if(block->block_contents)
7255     {
7256         contents = block->block_contents;
7257     }
7258     else
7259     {
7260         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
7261         contents = malloc(meta_size);
7262         if(!contents)
7263         {
7264             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
7265                meta_size, __FILE__, __LINE__);
7266         }
7267
7268         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
7269         {
7270             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
7271             free(contents);
7272             return(TNG_CRITICAL);
7273         }
7274     }
7275
7276     memcpy(datatype, contents+*offset,
7277            sizeof(*datatype));
7278     *offset += sizeof(*datatype);
7279
7280     memcpy(dependency, contents+*offset,
7281            sizeof(*dependency));
7282     *offset += sizeof(*dependency);
7283
7284     if(*dependency & TNG_FRAME_DEPENDENT)
7285     {
7286         memcpy(sparse_data, contents+*offset,
7287                sizeof(*sparse_data));
7288         *offset += sizeof(*sparse_data);
7289     }
7290
7291     memcpy(n_values, contents+*offset,
7292         sizeof(*n_values));
7293     if(tng_data->input_endianness_swap_func_64)
7294     {
7295         if(tng_data->input_endianness_swap_func_64(tng_data,
7296                                                    n_values)
7297             != TNG_SUCCESS)
7298         {
7299             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7300                     __FILE__, __LINE__);
7301         }
7302     }
7303     *offset += sizeof(*n_values);
7304
7305     memcpy(codec_id, contents+*offset,
7306         sizeof(*codec_id));
7307     if(tng_data->input_endianness_swap_func_64)
7308     {
7309         if(tng_data->input_endianness_swap_func_64(tng_data,
7310                                                    codec_id)
7311             != TNG_SUCCESS)
7312         {
7313             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7314                     __FILE__, __LINE__);
7315         }
7316     }
7317     *offset += sizeof(*codec_id);
7318
7319     if(*codec_id != TNG_UNCOMPRESSED)
7320     {
7321         memcpy(multiplier, contents+*offset,
7322             sizeof(*multiplier));
7323         if(tng_data->input_endianness_swap_func_64)
7324         {
7325             if(tng_data->input_endianness_swap_func_64(tng_data,
7326                                                        (int64_t *) multiplier)
7327                 != TNG_SUCCESS)
7328             {
7329                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7330                         __FILE__, __LINE__);
7331             }
7332         }
7333         *offset += sizeof(*multiplier);
7334     }
7335     else
7336     {
7337         *multiplier = 1;
7338     }
7339
7340     if(*dependency & TNG_FRAME_DEPENDENT)
7341     {
7342         if(*sparse_data)
7343         {
7344             memcpy(first_frame_with_data, contents+*offset,
7345                 sizeof(*first_frame_with_data));
7346             if(tng_data->input_endianness_swap_func_64)
7347             {
7348                 if(tng_data->input_endianness_swap_func_64(tng_data,
7349                                                            first_frame_with_data)
7350                     != TNG_SUCCESS)
7351                 {
7352                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7353                             __FILE__, __LINE__);
7354                 }
7355             }
7356             *offset += sizeof(*first_frame_with_data);
7357
7358             memcpy(stride_length, contents+*offset,
7359                 sizeof(*stride_length));
7360             if(tng_data->input_endianness_swap_func_64)
7361             {
7362                 if(tng_data->input_endianness_swap_func_64(tng_data,
7363                                                            stride_length)
7364                     != TNG_SUCCESS)
7365                 {
7366                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7367                             __FILE__, __LINE__);
7368                 }
7369             }
7370             *offset += sizeof(*stride_length);
7371             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
7372                         (*first_frame_with_data -
7373                         tng_data->current_trajectory_frame_set.first_frame);
7374         }
7375         else
7376         {
7377             *first_frame_with_data = 0;
7378             *stride_length = 1;
7379             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
7380         }
7381     }
7382     else
7383     {
7384         *first_frame_with_data = 0;
7385         *stride_length = 1;
7386         *n_frames = 1;
7387     }
7388
7389     if (*dependency & TNG_PARTICLE_DEPENDENT)
7390     {
7391         memcpy(num_first_particle, contents+*offset,
7392                sizeof(*num_first_particle));
7393         if(tng_data->input_endianness_swap_func_64)
7394         {
7395             if(tng_data->input_endianness_swap_func_64(tng_data,
7396                                                        num_first_particle)
7397                 != TNG_SUCCESS)
7398             {
7399                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7400                         __FILE__, __LINE__);
7401             }
7402         }
7403         *offset += sizeof(*num_first_particle);
7404
7405         memcpy(block_n_particles, contents+*offset,
7406             sizeof(*block_n_particles));
7407         if(tng_data->input_endianness_swap_func_64)
7408         {
7409             if(tng_data->input_endianness_swap_func_64(tng_data,
7410                                                        block_n_particles)
7411                 != TNG_SUCCESS)
7412             {
7413                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7414                         __FILE__, __LINE__);
7415             }
7416         }
7417         *offset += sizeof(*block_n_particles);
7418     }
7419
7420     if(!block->block_contents)
7421     {
7422         free(contents);
7423     }
7424     return(TNG_SUCCESS);
7425 }
7426
7427 /** Read the contents of a data block (particle or non-particle data).
7428  * @param tng_data is a trajectory data container.
7429  * @param block is the block to store the data (should already contain
7430  * the block headers).
7431  * @param hash_mode is an option to decide whether to use the md5 hash or not.
7432  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
7433  * compared to the md5 hash of the read contents to ensure valid data.
7434  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7435  * error has occured.
7436  */
7437 static tng_function_status tng_data_block_contents_read
7438                 (tng_trajectory_t tng_data,
7439                  tng_gen_block_t block,
7440                  const char hash_mode)
7441 {
7442     int64_t n_values, codec_id, n_frames, first_frame_with_data;
7443     int64_t stride_length, block_n_particles, num_first_particle;
7444     double multiplier;
7445     char datatype, dependency, sparse_data;
7446     int offset = 0;
7447     tng_bool same_hash;
7448
7449     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
7450     {
7451         return(TNG_CRITICAL);
7452     }
7453
7454     if(block->block_contents)
7455     {
7456         free(block->block_contents);
7457     }
7458
7459     block->block_contents = malloc(block->block_contents_size);
7460     if(!block->block_contents)
7461     {
7462         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7463                block->block_contents_size, __FILE__, __LINE__);
7464         return(TNG_CRITICAL);
7465     }
7466
7467     /* Read the whole block into block_contents to be able to write it to
7468      * disk even if it cannot be interpreted. */
7469     if(fread(block->block_contents, block->block_contents_size, 1,
7470              tng_data->input_file) == 0)
7471     {
7472         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
7473         return(TNG_CRITICAL);
7474     }
7475
7476     /* FIXME: Does not check if the size of the contents matches the expected
7477      * size or if the contents can be read. */
7478
7479     if(hash_mode == TNG_USE_HASH)
7480     {
7481         tng_md5_hash_match_verify(block, &same_hash);
7482         if(same_hash != TNG_TRUE)
7483         {
7484             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
7485                 block->name, __FILE__, __LINE__);
7486     /*         return(TNG_FAILURE); */
7487         }
7488     }
7489
7490     if(tng_data_block_meta_information_read(tng_data, block,
7491                                             &offset, &datatype,
7492                                             &dependency, &sparse_data,
7493                                             &n_values, &codec_id,
7494                                             &first_frame_with_data,
7495                                             &stride_length, &n_frames,
7496                                             &num_first_particle,
7497                                             &block_n_particles,
7498                                             &multiplier) == TNG_CRITICAL)
7499     {
7500         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
7501             block->name, __FILE__, __LINE__);
7502         return(TNG_CRITICAL);
7503     }
7504
7505     if (dependency & TNG_PARTICLE_DEPENDENT)
7506     {
7507         return(tng_particle_data_read(tng_data, block,
7508                                       &offset, datatype,
7509                                       num_first_particle,
7510                                       block_n_particles,
7511                                       first_frame_with_data,
7512                                       stride_length,
7513                                       n_frames, n_values,
7514                                       codec_id, multiplier));
7515     }
7516     else
7517     {
7518         return(tng_data_read(tng_data, block,
7519                              &offset, datatype,
7520                              first_frame_with_data,
7521                              stride_length,
7522                              n_frames, n_values,
7523                              codec_id, multiplier));
7524     }
7525 }
7526
7527 /*
7528 // ** Move the blocks in a frame set so that there is no unused space between
7529 //  * them. This can only be done on the last frame set in the file and should
7530 //  * be done e.g. if the last frame set in the file has fewer frames than
7531 //  * default or after compressing data blocks in a frame set.
7532 //  * @param tng_data is a trajectory data container.
7533 //  * @details the current_trajectory_frame_set is the one that will be modified.
7534 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
7535 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
7536 //  * FIXME: This function is not finished!!!
7537 //  *
7538 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
7539 // {
7540 //     tng_gen_block_t block;
7541 //     tng_trajectory_frame_set_t frame_set;
7542 //     FILE *temp = tng_data->input_file;
7543 //     int64_t pos, contents_start_pos, output_file_len;
7544 //
7545 //     frame_set = &tng_data->current_trajectory_frame_set;
7546 //
7547 //     if(frame_set->n_written_frames == frame_set->n_frames)
7548 //     {
7549 //         return(TNG_SUCCESS);
7550 //     }
7551 //
7552 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
7553 //        tng_data->last_trajectory_frame_set_output_file_pos)
7554 //     {
7555 //     }
7556 //
7557 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7558 //     {
7559 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7560 //                __FILE__, __LINE__);
7561 //         return(TNG_CRITICAL);
7562 //     }
7563 //
7564 //     tng_block_init(&block);
7565 // //     output_file_pos = ftello(tng_data->output_file);
7566 //
7567 //     tng_data->input_file = tng_data->output_file;
7568 //
7569 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7570 //
7571 //     fseeko(tng_data->output_file, pos, SEEK_SET);
7572 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7573 //     {
7574 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7575 //             __FILE__, __LINE__);
7576 //         tng_data->input_file = temp;
7577 //         tng_block_destroy(&block);
7578 //         return(TNG_CRITICAL);
7579 //     }
7580 //
7581 //     contents_start_pos = ftello(tng_data->output_file);
7582 //
7583 //     fseeko(tng_data->output_file, 0, SEEK_END);
7584 //     output_file_len = ftello(tng_data->output_file);
7585 //     pos = contents_start_pos + block->block_contents_size;
7586 //     fseeko(tng_data->output_file, pos,
7587 //           SEEK_SET);
7588 //
7589 //     while(pos < output_file_len)
7590 //     {
7591 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7592 //         {
7593 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7594 //                    __FILE__, __LINE__);
7595 //             tng_data->input_file = temp;
7596 //             tng_block_destroy(&block);
7597 //             return(TNG_CRITICAL);
7598 //         }
7599 //         pos += block->header_contents_size + block->block_contents_size;
7600 //         fseeko(tng_data->output_file, pos, SEEK_SET);
7601 //     }
7602 //
7603 //     return(TNG_SUCCESS);
7604 // }
7605 */
7606 /** Finish writing the current frame set. Update the number of frames
7607  * and the hashes of the frame set and all its data blocks (if hash_mode
7608  * == TNG_USE_HASH).
7609  * @param tng_data is a trajectory data container.
7610  * @param hash_mode specifies whether to update the block md5 hash when
7611  * updating the pointers.
7612  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7613  * error has occured.
7614  */
7615 static tng_function_status tng_frame_set_finalize
7616                 (tng_trajectory_t tng_data, const char hash_mode)
7617 {
7618     tng_gen_block_t block;
7619     tng_trajectory_frame_set_t frame_set;
7620     FILE *temp = tng_data->input_file;
7621     int64_t pos, contents_start_pos, output_file_len;
7622
7623     frame_set = &tng_data->current_trajectory_frame_set;
7624
7625     if(frame_set->n_written_frames == frame_set->n_frames)
7626     {
7627         return(TNG_SUCCESS);
7628     }
7629
7630     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7631     {
7632         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7633                __FILE__, __LINE__);
7634         return(TNG_CRITICAL);
7635     }
7636
7637     tng_block_init(&block);
7638 /*     output_file_pos = ftello(tng_data->output_file); */
7639
7640     tng_data->input_file = tng_data->output_file;
7641
7642     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7643
7644     fseeko(tng_data->output_file, pos, SEEK_SET);
7645
7646     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7647     {
7648         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7649             __FILE__, __LINE__);
7650         tng_data->input_file = temp;
7651         tng_block_destroy(&block);
7652         return(TNG_CRITICAL);
7653     }
7654
7655     contents_start_pos = ftello(tng_data->output_file);
7656
7657     fseeko(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7658     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7659               1, tng_data->output_file) != 1)
7660     {
7661         tng_data->input_file = temp;
7662         tng_block_destroy(&block);
7663         return(TNG_CRITICAL);
7664     }
7665
7666
7667     if(hash_mode == TNG_USE_HASH)
7668     {
7669         tng_md5_hash_update(tng_data, block, pos,
7670                             pos + block->header_contents_size);
7671     }
7672
7673     fseeko(tng_data->output_file, 0, SEEK_END);
7674     output_file_len = ftello(tng_data->output_file);
7675     pos = contents_start_pos + block->block_contents_size;
7676     fseeko(tng_data->output_file, pos, SEEK_SET);
7677
7678     while(pos < output_file_len)
7679     {
7680         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7681         {
7682             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7683                    __FILE__, __LINE__);
7684             tng_data->input_file = temp;
7685             tng_block_destroy(&block);
7686             return(TNG_CRITICAL);
7687         }
7688
7689         if(hash_mode == TNG_USE_HASH)
7690         {
7691             tng_md5_hash_update(tng_data, block, pos,
7692                                 pos + block->header_contents_size);
7693         }
7694         pos += block->header_contents_size + block->block_contents_size;
7695         fseeko(tng_data->output_file, pos, SEEK_SET);
7696     }
7697
7698     tng_data->input_file = temp;
7699     tng_block_destroy(&block);
7700     return(TNG_SUCCESS);
7701 }
7702
7703 /*
7704 // ** Sets the name of a file contents block
7705 //  * @param tng_data is a trajectory data container.
7706 //  * @param block is the block, of which to change names.
7707 //  * @param new_name is the new name of the block.
7708 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7709 //  * error has occured.
7710 //
7711 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7712 //                                               tng_gen_block_t block,
7713 //                                               const char *new_name)
7714 // {
7715 //     int len;
7716 //
7717 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7718 //
7719 //      * If the currently stored string length is not enough to store the new
7720 //      * string it is freed and reallocated. *
7721 //     if(block->name && strlen(block->name) < len)
7722 //     {
7723 //         free(block->name);
7724 //         block->name = 0;
7725 //     }
7726 //     if(!block->name)
7727 //     {
7728 //         block->name = malloc(len);
7729 //         if(!block->name)
7730 //         {
7731 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7732 //                    __FILE__, __LINE__);
7733 //             return(TNG_CRITICAL);
7734 //         }
7735 //     }
7736 //
7737 //     strncpy(block->name, new_name, len);
7738 //
7739 //     return(TNG_SUCCESS);
7740 // }
7741 */
7742
7743 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7744                                          const tng_atom_t atom,
7745                                          tng_residue_t *residue)
7746 {
7747     (void) tng_data;
7748
7749     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7750
7751     *residue = atom->residue;
7752
7753     return(TNG_SUCCESS);
7754 }
7755
7756 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7757                                       const tng_atom_t atom,
7758                                       char *name,
7759                                       const int max_len)
7760 {
7761     (void) tng_data;
7762     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7763     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7764
7765     strncpy(name, atom->name, max_len - 1);
7766     name[max_len - 1] = 0;
7767
7768     if(strlen(atom->name) > (unsigned int)max_len - 1)
7769     {
7770         return(TNG_FAILURE);
7771     }
7772     return(TNG_SUCCESS);
7773 }
7774
7775 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7776                                       tng_atom_t atom,
7777                                       const char *new_name)
7778 {
7779     unsigned int len;
7780     (void)tng_data;
7781
7782     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7783     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7784
7785     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7786
7787     /* If the currently stored string length is not enough to store the new
7788      * string it is freed and reallocated. */
7789     if(atom->name && strlen(atom->name) < len)
7790     {
7791         free(atom->name);
7792         atom->name = 0;
7793     }
7794     if(!atom->name)
7795     {
7796         atom->name = malloc(len);
7797         if(!atom->name)
7798         {
7799             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7800                    __FILE__, __LINE__);
7801             return(TNG_CRITICAL);
7802         }
7803     }
7804
7805     strncpy(atom->name, new_name, len);
7806
7807     return(TNG_SUCCESS);
7808 }
7809
7810 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7811                                       const tng_atom_t atom,
7812                                       char *type,
7813                                       const int max_len)
7814 {
7815     (void) tng_data;
7816     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7817     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7818
7819     strncpy(type, atom->atom_type, max_len - 1);
7820     type[max_len - 1] = 0;
7821
7822     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7823     {
7824         return(TNG_FAILURE);
7825     }
7826     return(TNG_SUCCESS);
7827 }
7828
7829 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7830                                       tng_atom_t atom,
7831                                       const char *new_type)
7832 {
7833     unsigned int len;
7834     (void)tng_data;
7835
7836     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7837     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7838
7839     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7840
7841     /* If the currently stored string length is not enough to store the new
7842      * string it is freed and reallocated. */
7843     if(atom->atom_type && strlen(atom->atom_type) < len)
7844     {
7845         free(atom->atom_type);
7846         atom->atom_type = 0;
7847     }
7848     if(!atom->atom_type)
7849     {
7850         atom->atom_type = malloc(len);
7851         if(!atom->atom_type)
7852         {
7853             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7854                    __FILE__, __LINE__);
7855             return(TNG_CRITICAL);
7856         }
7857     }
7858
7859     strncpy(atom->atom_type, new_type, len);
7860
7861     return(TNG_SUCCESS);
7862 }
7863
7864 /** Initialise an atom struct
7865  * @param atom is the atom to initialise.
7866  * @return TNG_SUCCESS (0) if successful.
7867  */
7868 static tng_function_status tng_atom_init(tng_atom_t atom)
7869 {
7870     atom->name = 0;
7871     atom->atom_type = 0;
7872
7873     return(TNG_SUCCESS);
7874 }
7875
7876 /** Free the memory in an atom struct
7877  * @param atom is the atom to destroy.
7878  * @return TNG_SUCCESS (0) if successful.
7879  */
7880 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7881 {
7882     if(atom->name)
7883     {
7884         free(atom->name);
7885         atom->name = 0;
7886     }
7887     if(atom->atom_type)
7888     {
7889         free(atom->atom_type);
7890         atom->atom_type = 0;
7891     }
7892
7893     return(TNG_SUCCESS);
7894 }
7895
7896 tng_function_status DECLSPECDLLEXPORT tng_version_major
7897                 (const tng_trajectory_t tng_data,
7898                  int *version)
7899 {
7900     (void)tng_data;
7901
7902     *version = TNG_VERSION_MAJOR;
7903
7904     return(TNG_SUCCESS);
7905 }
7906
7907 tng_function_status DECLSPECDLLEXPORT tng_version_minor
7908                 (const tng_trajectory_t tng_data,
7909                  int *version)
7910 {
7911     (void)tng_data;
7912
7913     *version = TNG_VERSION_MINOR;
7914
7915     return(TNG_SUCCESS);
7916 }
7917
7918 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
7919                 (const tng_trajectory_t tng_data,
7920                  int *patch_level)
7921 {
7922     (void)tng_data;
7923
7924     *patch_level = TNG_VERSION_PATCHLEVEL;
7925
7926     return(TNG_SUCCESS);
7927 }
7928
7929 tng_function_status DECLSPECDLLEXPORT tng_version
7930                 (const tng_trajectory_t tng_data,
7931                  char *version,
7932                  const int max_len)
7933 {
7934     (void)tng_data;
7935     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
7936
7937     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
7938
7939     return(TNG_SUCCESS);
7940 }
7941
7942 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7943                 (tng_trajectory_t tng_data,
7944                  const char *name,
7945                  tng_molecule_t *molecule)
7946 {
7947     int64_t id;
7948
7949     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7950     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7951
7952     /* Set ID to the ID of the last molecule + 1 */
7953     if(tng_data->n_molecules)
7954     {
7955         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7956     }
7957     else
7958     {
7959         id = 1;
7960     }
7961
7962     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7963 }
7964
7965 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7966                 (tng_trajectory_t tng_data,
7967                  const char *name,
7968                  const int64_t id,
7969                  tng_molecule_t *molecule)
7970 {
7971     tng_molecule_t new_molecules;
7972     int64_t *new_molecule_cnt_list;
7973     tng_function_status stat = TNG_SUCCESS;
7974
7975     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7976     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7977
7978     new_molecules = realloc(tng_data->molecules,
7979                             sizeof(struct tng_molecule) *
7980                             (tng_data->n_molecules + 1));
7981
7982     if(!new_molecules)
7983     {
7984         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7985                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7986                __FILE__, __LINE__);
7987         free(tng_data->molecules);
7988         tng_data->molecules = 0;
7989         return(TNG_CRITICAL);
7990     }
7991
7992     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7993                                     sizeof(int64_t) *
7994                                     (tng_data->n_molecules + 1));
7995
7996     if(!new_molecule_cnt_list)
7997     {
7998         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7999                sizeof(int64_t) * (tng_data->n_molecules + 1),
8000                __FILE__, __LINE__);
8001         free(tng_data->molecule_cnt_list);
8002         tng_data->molecule_cnt_list = 0;
8003         free(new_molecules);
8004         return(TNG_CRITICAL);
8005     }
8006
8007     tng_data->molecules = new_molecules;
8008     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8009
8010     *molecule = &new_molecules[tng_data->n_molecules];
8011
8012     tng_molecule_init(tng_data, *molecule);
8013     tng_molecule_name_set(tng_data, *molecule, name);
8014
8015     /* FIXME: Should this be a function argument instead? */
8016     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8017
8018     (*molecule)->id = id;
8019
8020     tng_data->n_molecules++;
8021
8022     return(stat);
8023 }
8024
8025 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
8026                 (tng_trajectory_t tng_data,
8027                  tng_molecule_t *molecule_p)
8028 {
8029     int64_t *new_molecule_cnt_list, id;
8030     tng_molecule_t new_molecules, molecule;
8031
8032     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8033
8034     /* Set ID to the ID of the last molecule + 1 */
8035     if(tng_data->n_molecules)
8036     {
8037         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
8038     }
8039     else
8040     {
8041         id = 1;
8042     }
8043
8044     new_molecules = realloc(tng_data->molecules,
8045                             sizeof(struct tng_molecule) *
8046                             (tng_data->n_molecules + 1));
8047
8048     if(!new_molecules)
8049     {
8050         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8051                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
8052                __FILE__, __LINE__);
8053         free(tng_data->molecules);
8054         tng_data->molecules = 0;
8055         return(TNG_CRITICAL);
8056     }
8057
8058     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
8059                                     sizeof(int64_t) *
8060                                     (tng_data->n_molecules + 1));
8061
8062     if(!new_molecule_cnt_list)
8063     {
8064         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8065                sizeof(int64_t) * (tng_data->n_molecules + 1),
8066                __FILE__, __LINE__);
8067         free(tng_data->molecule_cnt_list);
8068         tng_data->molecule_cnt_list = 0;
8069         free(new_molecules);
8070         return(TNG_CRITICAL);
8071     }
8072
8073     molecule = *molecule_p;
8074
8075     tng_data->molecules = new_molecules;
8076     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8077
8078     new_molecules[tng_data->n_molecules] = *molecule;
8079
8080     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8081
8082     free(*molecule_p);
8083
8084     molecule = &new_molecules[tng_data->n_molecules];
8085
8086     *molecule_p = molecule;
8087
8088     molecule->id = id;
8089
8090     tng_data->n_molecules++;
8091
8092     return(TNG_SUCCESS);
8093 }
8094
8095 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
8096                                           const tng_molecule_t molecule,
8097                                           char *name,
8098                                           const int max_len)
8099 {
8100     (void) tng_data;
8101     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8102     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8103
8104     strncpy(name, molecule->name, max_len - 1);
8105     name[max_len - 1] = 0;
8106
8107     if(strlen(molecule->name) > (unsigned int)max_len - 1)
8108     {
8109         return(TNG_FAILURE);
8110     }
8111     return(TNG_SUCCESS);
8112 }
8113
8114 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
8115                 (tng_trajectory_t tng_data,
8116                  tng_molecule_t molecule,
8117                  const char *new_name)
8118 {
8119     unsigned int len;
8120     (void)tng_data;
8121
8122     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8123     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8124
8125     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8126
8127     /* If the currently stored string length is not enough to store the new
8128      * string it is freed and reallocated. */
8129     if(molecule->name && strlen(molecule->name) < len)
8130     {
8131         free(molecule->name);
8132         molecule->name = 0;
8133     }
8134     if(!molecule->name)
8135     {
8136         molecule->name = malloc(len);
8137         if(!molecule->name)
8138         {
8139             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8140                    __FILE__, __LINE__);
8141             return(TNG_CRITICAL);
8142         }
8143     }
8144
8145     strncpy(molecule->name, new_name, len);
8146
8147     return(TNG_SUCCESS);
8148 }
8149
8150 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
8151                 (const tng_trajectory_t tng_data,
8152                  const tng_molecule_t molecule,
8153                  int64_t *cnt)
8154 {
8155     int64_t i, index = -1;
8156
8157     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8158     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
8159
8160     for(i = 0; i < tng_data->n_molecules; i++)
8161     {
8162         if(&tng_data->molecules[i] == molecule)
8163         {
8164             index = i;
8165             break;
8166         }
8167     }
8168     if(index == -1)
8169     {
8170         return(TNG_FAILURE);
8171     }
8172     *cnt = tng_data->molecule_cnt_list[index];
8173
8174     return(TNG_SUCCESS);
8175 }
8176
8177 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
8178                 (tng_trajectory_t tng_data,
8179                  tng_molecule_t molecule,
8180                  const int64_t cnt)
8181 {
8182     int64_t i, old_cnt, index = -1;
8183
8184     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8185
8186     for(i = 0; i < tng_data->n_molecules; i++)
8187     {
8188         if(&tng_data->molecules[i] == molecule)
8189         {
8190             index = i;
8191             break;
8192         }
8193     }
8194     if(index == -1)
8195     {
8196         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
8197                __FILE__, __LINE__);
8198         return(TNG_FAILURE);
8199     }
8200     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
8201     {
8202         old_cnt = tng_data->molecule_cnt_list[index];
8203         tng_data->molecule_cnt_list[index] = cnt;
8204
8205         tng_data->n_particles += (cnt-old_cnt) *
8206                                  tng_data->molecules[index].n_atoms;
8207     }
8208     else
8209     {
8210         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
8211         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
8212
8213         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
8214                 tng_data->molecules[index].n_atoms;
8215     }
8216
8217     return(TNG_SUCCESS);
8218 }
8219
8220 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
8221                 (tng_trajectory_t tng_data,
8222                  const char *name,
8223                  int64_t nr,
8224                  tng_molecule_t *molecule)
8225 {
8226     int64_t i, n_molecules;
8227
8228     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8229     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8230     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8231
8232     n_molecules = tng_data->n_molecules;
8233
8234     for(i = n_molecules - 1; i >= 0; i--)
8235     {
8236         *molecule = &tng_data->molecules[i];
8237         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
8238         {
8239             if(nr == -1 || nr == (*molecule)->id)
8240             {
8241                 return(TNG_SUCCESS);
8242             }
8243         }
8244     }
8245
8246     *molecule = 0;
8247
8248     return(TNG_FAILURE);
8249 }
8250
8251 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
8252                 (tng_trajectory_t tng_data,
8253                  int64_t index,
8254                  tng_molecule_t *molecule)
8255 {
8256     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8257     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8258
8259     if(index >= tng_data->n_molecules)
8260     {
8261         *molecule = 0;
8262         return(TNG_FAILURE);
8263     }
8264     *molecule = &tng_data->molecules[index];
8265     return(TNG_SUCCESS);
8266 }
8267
8268 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
8269                                                                tng_trajectory_t tng_data_dest)
8270 {
8271     tng_molecule_t molecule, molecule_temp;
8272     tng_chain_t chain, chain_temp;
8273     tng_residue_t residue, residue_temp;
8274     tng_atom_t atom, atom_temp;
8275     tng_bond_t bond_temp;
8276     tng_function_status stat;
8277     int64_t i, j, k, l, *list_temp;
8278
8279     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
8280     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
8281
8282     for(i = 0; i < tng_data_dest->n_molecules; i++)
8283     {
8284         molecule = &tng_data_dest->molecules[i];
8285         tng_molecule_destroy(tng_data_dest, molecule);
8286     }
8287
8288     tng_data_dest->n_molecules = 0;
8289     tng_data_dest->n_particles = 0;
8290
8291     molecule_temp = realloc(tng_data_dest->molecules,
8292                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
8293     if(!molecule_temp)
8294     {
8295         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8296                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
8297                __FILE__, __LINE__);
8298         free(tng_data_dest->molecules);
8299         tng_data_dest->molecules = 0;
8300         return(TNG_CRITICAL);
8301     }
8302     list_temp = realloc(tng_data_dest->molecule_cnt_list,
8303                                      sizeof(int64_t) * tng_data_src->n_molecules);
8304     if(!list_temp)
8305     {
8306         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8307                sizeof(int64_t) * tng_data_src->n_molecules,
8308                __FILE__, __LINE__);
8309         free(tng_data_dest->molecule_cnt_list);
8310         tng_data_dest->molecule_cnt_list = 0;
8311         free(molecule_temp);
8312         return(TNG_CRITICAL);
8313     }
8314
8315     tng_data_dest->molecules = molecule_temp;
8316     tng_data_dest->molecule_cnt_list = list_temp;
8317
8318     for(i = 0; i < tng_data_src->n_molecules; i++)
8319     {
8320         molecule = &tng_data_src->molecules[i];
8321         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
8322                                      &molecule_temp);
8323         if(stat != TNG_SUCCESS)
8324         {
8325             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
8326                    __FILE__, __LINE__);
8327             return(stat);
8328         }
8329         molecule_temp->quaternary_str = molecule->quaternary_str;
8330         for(j = 0; j < molecule->n_chains; j++)
8331         {
8332             chain = &molecule->chains[j];
8333             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
8334                                                chain->name, chain->id,
8335                                                &chain_temp);
8336             if(stat != TNG_SUCCESS)
8337             {
8338                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
8339                        __FILE__, __LINE__);
8340                 return(stat);
8341             }
8342             for(k = 0; k < chain->n_residues; k++)
8343             {
8344                 residue = &chain->residues[k];
8345                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
8346                                                   residue->name, residue->id,
8347                                                   &residue_temp);
8348                 if(stat != TNG_SUCCESS)
8349                 {
8350                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
8351                            __FILE__, __LINE__);
8352                     return(stat);
8353                 }
8354                 for(l = 0; l < residue->n_atoms; l++)
8355                 {
8356                     atom = &molecule->atoms[residue->atoms_offset + l];
8357                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
8358                                                      atom->name, atom->atom_type,
8359                                                      atom->id, &atom_temp);
8360                     if(stat != TNG_SUCCESS)
8361                     {
8362                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
8363                            __FILE__, __LINE__);
8364                         return(stat);
8365                     }
8366                 }
8367             }
8368         }
8369         molecule_temp->n_bonds = molecule->n_bonds;
8370         if(molecule->n_bonds > 0)
8371         {
8372             bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
8373                                 molecule->n_bonds);
8374             if(!bond_temp)
8375             {
8376                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8377                        sizeof(struct tng_bond) * molecule->n_bonds,
8378                        __FILE__, __LINE__);
8379                 free(molecule_temp->bonds);
8380                 molecule_temp->n_bonds = 0;
8381                 return(TNG_CRITICAL);
8382             }
8383             molecule_temp->bonds = bond_temp;
8384             for(j = 0; j < molecule->n_bonds; j++)
8385             {
8386                 molecule_temp->bonds[j] = molecule->bonds[j];
8387             }
8388         }
8389         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
8390                                     tng_data_src->molecule_cnt_list[i]);
8391         if(stat != TNG_SUCCESS)
8392         {
8393             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
8394                    __FILE__, __LINE__);
8395             return(stat);
8396         }
8397     }
8398     return(TNG_SUCCESS);
8399 }
8400
8401 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
8402                 (const tng_trajectory_t tng_data,
8403                  const tng_molecule_t molecule,
8404                  int64_t *n)
8405 {
8406     (void) tng_data;
8407     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8408     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8409
8410     *n = molecule->n_chains;
8411
8412     return(TNG_SUCCESS);
8413 }
8414
8415 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
8416                 (tng_trajectory_t tng_data,
8417                  tng_molecule_t molecule,
8418                  int64_t index,
8419                  tng_chain_t *chain)
8420 {
8421     (void) tng_data;
8422     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8423     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8424
8425     if(index >= molecule->n_chains)
8426     {
8427         *chain = 0;
8428         return(TNG_FAILURE);
8429     }
8430     *chain = &molecule->chains[index];
8431     return(TNG_SUCCESS);
8432 }
8433
8434 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
8435                 (const tng_trajectory_t tng_data,
8436                  const tng_molecule_t molecule,
8437                  int64_t *n)
8438 {
8439     (void) tng_data;
8440     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8441     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8442
8443     *n = molecule->n_residues;
8444
8445     return(TNG_SUCCESS);
8446 }
8447
8448 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
8449                 (const tng_trajectory_t tng_data,
8450                  const tng_molecule_t molecule,
8451                  const int64_t index,
8452                  tng_residue_t *residue)
8453 {
8454     (void) tng_data;
8455     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8456     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8457
8458     if(index >= molecule->n_residues)
8459     {
8460         *residue = 0;
8461         return(TNG_FAILURE);
8462     }
8463     *residue = &molecule->residues[index];
8464     return(TNG_SUCCESS);
8465 }
8466
8467 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
8468                 (const tng_trajectory_t tng_data,
8469                  const tng_molecule_t molecule,
8470                  int64_t *n)
8471 {
8472     (void) tng_data;
8473     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8474     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8475
8476     *n = molecule->n_atoms;
8477
8478     return(TNG_SUCCESS);
8479 }
8480
8481 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
8482                 (const tng_trajectory_t tng_data,
8483                  const tng_molecule_t molecule,
8484                  const int64_t index,
8485                  tng_atom_t *atom)
8486 {
8487     (void) tng_data;
8488     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8489     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8490
8491     if(index >= molecule->n_atoms)
8492     {
8493         *atom = 0;
8494         return(TNG_FAILURE);
8495     }
8496     *atom = &molecule->atoms[index];
8497     return(TNG_SUCCESS);
8498 }
8499
8500 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
8501                 (tng_trajectory_t tng_data,
8502                  tng_molecule_t molecule,
8503                  const char *name,
8504                  int64_t nr,
8505                  tng_chain_t *chain)
8506 {
8507     int64_t i, n_chains;
8508     (void)tng_data;
8509
8510     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8511     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8512
8513     n_chains = molecule->n_chains;
8514
8515     for(i = n_chains - 1; i >= 0; i--)
8516     {
8517         *chain = &molecule->chains[i];
8518         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
8519         {
8520             if(nr == -1 || nr == (*chain)->id)
8521             {
8522                 return(TNG_SUCCESS);
8523             }
8524         }
8525     }
8526
8527     *chain = 0;
8528
8529     return(TNG_FAILURE);
8530 }
8531
8532 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
8533                 (tng_trajectory_t tng_data,
8534                  tng_molecule_t molecule,
8535                  const char *name,
8536                  tng_chain_t *chain)
8537 {
8538     int64_t id;
8539
8540     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8541     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8542
8543     /* Set ID to the ID of the last chain + 1 */
8544     if(molecule->n_chains)
8545     {
8546         id = molecule->chains[molecule->n_chains-1].id + 1;
8547     }
8548     else
8549     {
8550         id = 1;
8551     }
8552
8553     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
8554                                        id, chain));
8555 }
8556
8557 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
8558                 (tng_trajectory_t tng_data,
8559                  tng_molecule_t molecule,
8560                  const char *name,
8561                  const int64_t id,
8562                  tng_chain_t *chain)
8563 {
8564     tng_chain_t new_chains;
8565     tng_function_status stat = TNG_SUCCESS;
8566
8567     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8568     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8569
8570     new_chains = realloc(molecule->chains,
8571                          sizeof(struct tng_chain) *
8572                          (molecule->n_chains + 1));
8573
8574     if(!new_chains)
8575     {
8576         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8577                sizeof(struct tng_chain) * (molecule->n_chains + 1),
8578                __FILE__, __LINE__);
8579         free(molecule->chains);
8580         molecule->chains = 0;
8581         return(TNG_CRITICAL);
8582     }
8583
8584     molecule->chains = new_chains;
8585
8586     *chain = &new_chains[molecule->n_chains];
8587     (*chain)->name = 0;
8588
8589     tng_chain_name_set(tng_data, *chain, name);
8590
8591     (*chain)->molecule = molecule;
8592     (*chain)->n_residues = 0;
8593
8594     molecule->n_chains++;
8595
8596     (*chain)->id = id;
8597
8598     return(stat);
8599 }
8600
8601 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
8602                 (const tng_trajectory_t tng_data,
8603                  tng_molecule_t molecule,
8604                  const int64_t from_atom_id,
8605                  const int64_t to_atom_id,
8606                  tng_bond_t *bond)
8607 {
8608     tng_bond_t new_bonds;
8609     (void)tng_data;
8610
8611     new_bonds = realloc(molecule->bonds,
8612                         sizeof(struct tng_bond) *
8613                         (molecule->n_bonds + 1));
8614
8615     if(!new_bonds)
8616     {
8617         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8618                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
8619                __FILE__, __LINE__);
8620         *bond = 0;
8621         free(molecule->bonds);
8622         molecule->bonds = 0;
8623         return(TNG_CRITICAL);
8624     }
8625
8626     molecule->bonds = new_bonds;
8627
8628     *bond = &new_bonds[molecule->n_bonds];
8629
8630     (*bond)->from_atom_id = from_atom_id;
8631     (*bond)->to_atom_id = to_atom_id;
8632
8633     molecule->n_bonds++;
8634
8635     return(TNG_SUCCESS);
8636 }
8637
8638 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
8639                 (tng_trajectory_t tng_data,
8640                  tng_molecule_t molecule,
8641                  const char *name,
8642                  int64_t id,
8643                  tng_atom_t *atom)
8644 {
8645     int64_t i, n_atoms;
8646     (void)tng_data;
8647
8648     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8649
8650     n_atoms = molecule->n_atoms;
8651
8652     for(i = n_atoms - 1; i >= 0; i--)
8653     {
8654         *atom = &molecule->atoms[i];
8655         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8656         {
8657             if(id == -1 || id == (*atom)->id)
8658             {
8659                 return(TNG_SUCCESS);
8660             }
8661         }
8662     }
8663
8664     *atom = 0;
8665
8666     return(TNG_FAILURE);
8667 }
8668
8669 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8670                                        const tng_chain_t chain,
8671                                        char *name,
8672                                        const int max_len)
8673 {
8674     (void) tng_data;
8675     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8676     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8677
8678     strncpy(name, chain->name, max_len - 1);
8679     name[max_len - 1] = 0;
8680
8681     if(strlen(chain->name) > (unsigned int)max_len - 1)
8682     {
8683         return(TNG_FAILURE);
8684     }
8685     return(TNG_SUCCESS);
8686 }
8687
8688 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8689                 (tng_trajectory_t tng_data,
8690                  tng_chain_t chain,
8691                  const char *new_name)
8692 {
8693     unsigned int len;
8694     (void)tng_data;
8695
8696     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8697
8698     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8699
8700     /* If the currently stored string length is not enough to store the new
8701      * string it is freed and reallocated. */
8702     if(chain->name && strlen(chain->name) < len)
8703     {
8704         free(chain->name);
8705         chain->name = 0;
8706     }
8707     if(!chain->name)
8708     {
8709         chain->name = malloc(len);
8710         if(!chain->name)
8711         {
8712             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8713                    __FILE__, __LINE__);
8714             return(TNG_CRITICAL);
8715         }
8716     }
8717
8718     strncpy(chain->name, new_name, len);
8719
8720     return(TNG_SUCCESS);
8721 }
8722
8723 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8724                 (const tng_trajectory_t tng_data,
8725                  const tng_chain_t chain,
8726                  int64_t *n)
8727 {
8728     (void) tng_data;
8729     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8730     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8731
8732     *n = chain->n_residues;
8733
8734     return(TNG_SUCCESS);
8735 }
8736
8737 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8738                 (const tng_trajectory_t tng_data,
8739                  const tng_chain_t chain,
8740                  const int64_t index,
8741                  tng_residue_t *residue)
8742 {
8743     (void) tng_data;
8744     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8745     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8746
8747     if(index >= chain->n_residues)
8748     {
8749         *residue = 0;
8750         return(TNG_FAILURE);
8751     }
8752     *residue = &chain->residues[index];
8753     return(TNG_SUCCESS);
8754 }
8755
8756 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8757                 (tng_trajectory_t tng_data,
8758                  tng_chain_t chain,
8759                  const char *name,
8760                  int64_t id,
8761                  tng_residue_t *residue)
8762 {
8763     int64_t i, n_residues;
8764     (void)tng_data;
8765
8766     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8767
8768     n_residues = chain->n_residues;
8769
8770     for(i = n_residues - 1; i >= 0; i--)
8771     {
8772         *residue = &chain->residues[i];
8773         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8774         {
8775             if(id == -1 || id == (*residue)->id)
8776             {
8777                 return(TNG_SUCCESS);
8778             }
8779         }
8780     }
8781
8782     *residue = 0;
8783
8784     return(TNG_FAILURE);
8785 }
8786
8787 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8788                 (tng_trajectory_t tng_data,
8789                  tng_chain_t chain,
8790                  const char *name,
8791                  tng_residue_t *residue)
8792 {
8793     int64_t id;
8794
8795     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8796     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8797
8798     /* Set ID to the ID of the last residue + 1 */
8799     if(chain->n_residues)
8800     {
8801         id = chain->residues[chain->n_residues-1].id + 1;
8802     }
8803     else
8804     {
8805         id = 0;
8806     }
8807
8808     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8809                                       id, residue));
8810 }
8811
8812 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8813                 (tng_trajectory_t tng_data,
8814                  tng_chain_t chain,
8815                  const char *name,
8816                  const int64_t id,
8817                  tng_residue_t *residue)
8818 {
8819     int64_t curr_index;
8820     tng_residue_t new_residues, temp_residue, last_residue;
8821     tng_molecule_t molecule = chain->molecule;
8822     tng_function_status stat = TNG_SUCCESS;
8823
8824     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8825     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8826
8827     if(chain->n_residues)
8828     {
8829         curr_index = chain->residues - molecule->residues;
8830     }
8831     else
8832     {
8833         curr_index = -1;
8834     }
8835
8836     new_residues = realloc(molecule->residues,
8837                            sizeof(struct tng_residue) *
8838                            (molecule->n_residues + 1));
8839
8840     if(!new_residues)
8841     {
8842         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8843                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8844                __FILE__, __LINE__);
8845         free(molecule->residues);
8846         molecule->residues = 0;
8847         return(TNG_CRITICAL);
8848     }
8849
8850     molecule->residues = new_residues;
8851
8852     if(curr_index != -1)
8853     {
8854         chain->residues = new_residues + curr_index;
8855         if(molecule->n_residues)
8856         {
8857             last_residue = &new_residues[molecule->n_residues - 1];
8858
8859             temp_residue = chain->residues + (chain->n_residues - 1);
8860             /* Make space in list of residues to add the new residues together with the other
8861             * residues of this chain */
8862             if(temp_residue != last_residue)
8863             {
8864                 ++temp_residue;
8865                 memmove(temp_residue + 1, temp_residue,
8866                         last_residue - temp_residue);
8867             }
8868         }
8869     }
8870     else
8871     {
8872         curr_index = molecule->n_residues;
8873     }
8874
8875     *residue = &molecule->residues[curr_index + chain->n_residues];
8876
8877     if(!chain->n_residues)
8878     {
8879         chain->residues = *residue;
8880     }
8881     else
8882     {
8883         chain->residues = &molecule->residues[curr_index];
8884     }
8885
8886     (*residue)->name = 0;
8887     tng_residue_name_set(tng_data, *residue, name);
8888
8889     (*residue)->chain = chain;
8890     (*residue)->n_atoms = 0;
8891     (*residue)->atoms_offset = 0;
8892
8893     chain->n_residues++;
8894     molecule->n_residues++;
8895
8896     (*residue)->id = id;
8897
8898     return(stat);
8899 }
8900
8901 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8902                                          const tng_residue_t residue,
8903                                          char *name,
8904                                          const int max_len)
8905 {
8906     (void) tng_data;
8907     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8908     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8909
8910     strncpy(name, residue->name, max_len - 1);
8911     name[max_len - 1] = 0;
8912
8913     if(strlen(residue->name) > (unsigned int)max_len - 1)
8914     {
8915         return(TNG_FAILURE);
8916     }
8917     return(TNG_SUCCESS);
8918 }
8919
8920 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8921                                                            tng_residue_t residue,
8922                                                            const char *new_name)
8923 {
8924     unsigned int len;
8925     (void)tng_data;
8926
8927     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8928     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8929
8930     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8931
8932     /* If the currently stored string length is not enough to store the new
8933      * string it is freed and reallocated. */
8934     if(residue->name && strlen(residue->name) < len)
8935     {
8936         free(residue->name);
8937         residue->name = 0;
8938     }
8939     if(!residue->name)
8940     {
8941         residue->name = malloc(len);
8942         if(!residue->name)
8943         {
8944             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8945                    __FILE__, __LINE__);
8946             return(TNG_CRITICAL);
8947         }
8948     }
8949
8950     strncpy(residue->name, new_name, len);
8951
8952     return(TNG_SUCCESS);
8953 }
8954
8955 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8956                 (const tng_trajectory_t tng_data,
8957                  const tng_residue_t residue,
8958                  int64_t *n)
8959 {
8960     (void) tng_data;
8961     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8962     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8963
8964     *n = residue->n_atoms;
8965
8966     return(TNG_SUCCESS);
8967 }
8968
8969 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8970                 (const tng_trajectory_t tng_data,
8971                  const tng_residue_t residue,
8972                  const int64_t index,
8973                  tng_atom_t *atom)
8974 {
8975     tng_chain_t chain;
8976     tng_molecule_t molecule;
8977
8978     (void) tng_data;
8979     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8980     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8981
8982     if(index >= residue->n_atoms)
8983     {
8984         *atom = 0;
8985         return(TNG_FAILURE);
8986     }
8987     chain = residue->chain;
8988     molecule = chain->molecule;
8989
8990     if(index + residue->atoms_offset >= molecule->n_atoms)
8991     {
8992         *atom = 0;
8993         return(TNG_FAILURE);
8994     }
8995
8996     *atom = &molecule->atoms[residue->atoms_offset + index];
8997     return(TNG_SUCCESS);
8998 }
8999
9000 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
9001                 (tng_trajectory_t tng_data,
9002                  tng_residue_t residue,
9003                  const char *atom_name,
9004                  const char *atom_type,
9005                  tng_atom_t *atom)
9006 {
9007     int64_t id;
9008
9009     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9010     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
9011     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
9012
9013     /* Set ID to the ID of the last atom + 1 */
9014     if(residue->chain->molecule->n_atoms)
9015     {
9016         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
9017     }
9018     else
9019     {
9020         id = 0;
9021     }
9022
9023     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
9024                                      id, atom));
9025 }
9026
9027 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
9028                 (tng_trajectory_t tng_data,
9029                  tng_residue_t residue,
9030                  const char *atom_name,
9031                  const char *atom_type,
9032                  const int64_t id,
9033                  tng_atom_t *atom)
9034 {
9035     tng_atom_t new_atoms;
9036     tng_molecule_t molecule = residue->chain->molecule;
9037     tng_function_status stat = TNG_SUCCESS;
9038
9039     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9040     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
9041     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
9042
9043     if(!residue->n_atoms)
9044     {
9045         residue->atoms_offset = molecule->n_atoms;
9046     }
9047
9048     new_atoms = realloc(molecule->atoms,
9049                         sizeof(struct tng_atom) *
9050                         (molecule->n_atoms + 1));
9051
9052     if(!new_atoms)
9053     {
9054         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9055                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
9056                __FILE__, __LINE__);
9057         free(molecule->atoms);
9058         molecule->atoms = 0;
9059         return(TNG_CRITICAL);
9060     }
9061
9062     molecule->atoms = new_atoms;
9063
9064     *atom = &new_atoms[molecule->n_atoms];
9065
9066     tng_atom_init(*atom);
9067     tng_atom_name_set(tng_data, *atom, atom_name);
9068     tng_atom_type_set(tng_data, *atom, atom_type);
9069
9070     (*atom)->residue = residue;
9071
9072     residue->n_atoms++;
9073     molecule->n_atoms++;
9074
9075     (*atom)->id = id;
9076
9077     return(stat);
9078 }
9079
9080 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
9081                                                          tng_molecule_t *molecule_p)
9082 {
9083     *molecule_p = malloc(sizeof(struct tng_molecule));
9084     if(!*molecule_p)
9085     {
9086         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9087                sizeof(struct tng_molecule), __FILE__, __LINE__);
9088         return(TNG_CRITICAL);
9089     }
9090
9091     tng_molecule_init(tng_data, *molecule_p);
9092
9093     return(TNG_SUCCESS);
9094 }
9095
9096 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
9097                                                         tng_molecule_t *molecule_p)
9098 {
9099     if(!*molecule_p)
9100     {
9101         return(TNG_SUCCESS);
9102     }
9103
9104     tng_molecule_destroy(tng_data, *molecule_p);
9105
9106     free(*molecule_p);
9107     *molecule_p = 0;
9108
9109     return(TNG_SUCCESS);
9110 }
9111
9112 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
9113                                                         tng_molecule_t molecule)
9114 {
9115     (void)tng_data;
9116     molecule->quaternary_str = 1;
9117     molecule->name = 0;
9118     molecule->n_chains = 0;
9119     molecule->chains = 0;
9120     molecule->n_residues = 0;
9121     molecule->residues = 0;
9122     molecule->n_atoms = 0;
9123     molecule->atoms = 0;
9124     molecule->n_bonds = 0;
9125     molecule->bonds = 0;
9126
9127     return(TNG_SUCCESS);
9128 }
9129
9130 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
9131                                                            tng_molecule_t molecule)
9132 {
9133     int64_t i;
9134     (void)tng_data;
9135
9136     if(molecule->name)
9137     {
9138         free(molecule->name);
9139         molecule->name = 0;
9140     }
9141
9142     if(molecule->chains)
9143     {
9144         for(i = 0; i < molecule->n_chains; i++)
9145         {
9146             if(molecule->chains[i].name)
9147             {
9148                 free(molecule->chains[i].name);
9149                 molecule->chains[i].name = 0;
9150             }
9151         }
9152         free(molecule->chains);
9153         molecule->chains = 0;
9154     }
9155     molecule->n_chains = 0;
9156
9157     if(molecule->residues)
9158     {
9159         for(i = 0; i < molecule->n_residues; i++)
9160         {
9161             if(molecule->residues[i].name)
9162             {
9163                 free(molecule->residues[i].name);
9164                 molecule->residues[i].name = 0;
9165             }
9166         }
9167         free(molecule->residues);
9168         molecule->residues = 0;
9169     }
9170     molecule->n_residues = 0;
9171
9172     if(molecule->atoms)
9173     {
9174         for(i = 0; i < molecule->n_atoms; i++)
9175         {
9176             tng_atom_destroy(&molecule->atoms[i]);
9177         }
9178         free(molecule->atoms);
9179         molecule->atoms = 0;
9180     }
9181     molecule->n_atoms = 0;
9182
9183     if(molecule->bonds)
9184     {
9185         free(molecule->bonds);
9186         molecule->bonds = 0;
9187     }
9188     molecule->n_bonds = 0;
9189
9190     return(TNG_SUCCESS);
9191 }
9192
9193 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
9194                 (const tng_trajectory_t tng_data,
9195                  const int64_t nr,
9196                  char *name,
9197                  int max_len)
9198 {
9199     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9200     tng_molecule_t mol;
9201     tng_bool found = TNG_FALSE;
9202
9203     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9204     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9205
9206     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9207
9208     if(!molecule_cnt_list)
9209     {
9210         return(TNG_FAILURE);
9211     }
9212
9213     for(i = 0; i < tng_data->n_molecules; i++)
9214     {
9215         mol = &tng_data->molecules[i];
9216         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9217         {
9218             cnt += mol->n_atoms * molecule_cnt_list[i];
9219             continue;
9220         }
9221         found = TNG_TRUE;
9222         break;
9223     }
9224     if(!found)
9225     {
9226         return(TNG_FAILURE);
9227     }
9228
9229     strncpy(name, mol->name, max_len - 1);
9230     name[max_len - 1] = 0;
9231
9232     if(strlen(mol->name) > (unsigned int)max_len - 1)
9233     {
9234         return(TNG_FAILURE);
9235     }
9236     return(TNG_SUCCESS);
9237 }
9238
9239 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
9240                 (const tng_trajectory_t tng_data,
9241                  const int64_t nr,
9242                  int64_t *id)
9243 {
9244     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9245     tng_molecule_t mol;
9246     tng_bool found = TNG_FALSE;
9247
9248     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9249     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9250
9251     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9252
9253     if(!molecule_cnt_list)
9254     {
9255         return(TNG_FAILURE);
9256     }
9257
9258     for(i = 0; i < tng_data->n_molecules; i++)
9259     {
9260         mol = &tng_data->molecules[i];
9261         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9262         {
9263             cnt += mol->n_atoms * molecule_cnt_list[i];
9264             continue;
9265         }
9266         found = TNG_TRUE;
9267         break;
9268     }
9269     if(!found)
9270     {
9271         return(TNG_FAILURE);
9272     }
9273
9274     *id = mol->id;
9275
9276     return(TNG_SUCCESS);
9277 }
9278
9279 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
9280                 (const tng_trajectory_t tng_data,
9281                  int64_t *n_bonds,
9282                  int64_t **from_atoms,
9283                  int64_t **to_atoms)
9284 {
9285     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
9286     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
9287     tng_molecule_t mol;
9288     tng_bond_t bond;
9289
9290     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9291     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
9292     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
9293     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
9294
9295     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9296
9297     if(!molecule_cnt_list)
9298     {
9299         return(TNG_FAILURE);
9300     }
9301
9302     *n_bonds = 0;
9303     /* First count the total number of bonds to allocate memory */
9304     for(i = 0; i < tng_data->n_molecules; i++)
9305     {
9306         mol = &tng_data->molecules[i];
9307         mol_cnt = molecule_cnt_list[i];
9308         *n_bonds += mol_cnt * mol->n_bonds;
9309     }
9310     if(*n_bonds == 0)
9311     {
9312         return(TNG_SUCCESS);
9313     }
9314
9315     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9316     if(!*from_atoms)
9317     {
9318         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9319                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9320         return(TNG_CRITICAL);
9321     }
9322     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9323     if(!*to_atoms)
9324     {
9325         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9326                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9327         free(*from_atoms);
9328         *from_atoms = 0;
9329         return(TNG_CRITICAL);
9330     }
9331
9332     cnt = 0;
9333     for(i = 0; i < tng_data->n_molecules; i++)
9334     {
9335         mol = &tng_data->molecules[i];
9336         mol_cnt = molecule_cnt_list[i];
9337         for(j = 0; j < mol_cnt; j++)
9338         {
9339             for(k = 0; k < mol->n_bonds; k++)
9340             {
9341                 bond = &mol->bonds[k];
9342                 from_atom = atom_cnt + bond->from_atom_id;
9343                 to_atom = atom_cnt + bond->to_atom_id;
9344                 (*from_atoms)[cnt] = from_atom;
9345                 (*to_atoms)[cnt++] = to_atom;
9346             }
9347             atom_cnt += mol->n_atoms;
9348         }
9349     }
9350
9351     return(TNG_SUCCESS);
9352 }
9353
9354 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
9355                 (const tng_trajectory_t tng_data,
9356                  const int64_t nr,
9357                  char *name,
9358                  int max_len)
9359 {
9360     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9361     tng_molecule_t mol;
9362     tng_atom_t atom;
9363     tng_bool found = TNG_FALSE;
9364
9365     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9366     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9367
9368     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9369
9370     if(!molecule_cnt_list)
9371     {
9372         return(TNG_FAILURE);
9373     }
9374
9375     for(i = 0; i < tng_data->n_molecules; i++)
9376     {
9377         mol = &tng_data->molecules[i];
9378         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9379         {
9380             cnt += mol->n_atoms * molecule_cnt_list[i];
9381             continue;
9382         }
9383         atom = &mol->atoms[nr % mol->n_atoms];
9384         found = TNG_TRUE;
9385         break;
9386     }
9387     if(!found)
9388     {
9389         return(TNG_FAILURE);
9390     }
9391     if(!atom->residue || !atom->residue->chain)
9392     {
9393         return(TNG_FAILURE);
9394     }
9395
9396     strncpy(name, atom->residue->chain->name, max_len - 1);
9397     name[max_len - 1] = 0;
9398
9399     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
9400     {
9401         return(TNG_FAILURE);
9402     }
9403     return(TNG_SUCCESS);
9404 }
9405
9406 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
9407                 (const tng_trajectory_t tng_data,
9408                  const int64_t nr,
9409                  char *name,
9410                  int max_len)
9411 {
9412     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9413     tng_molecule_t mol;
9414     tng_atom_t atom;
9415     tng_bool found = TNG_FALSE;
9416
9417     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9418     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9419
9420     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9421
9422     if(!molecule_cnt_list)
9423     {
9424         return(TNG_FAILURE);
9425     }
9426
9427     for(i = 0; i < tng_data->n_molecules; i++)
9428     {
9429         mol = &tng_data->molecules[i];
9430         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9431         {
9432             cnt += mol->n_atoms * molecule_cnt_list[i];
9433             continue;
9434         }
9435         atom = &mol->atoms[nr % mol->n_atoms];
9436         found = TNG_TRUE;
9437         break;
9438     }
9439     if(!found)
9440     {
9441         return(TNG_FAILURE);
9442     }
9443     if(!atom->residue)
9444     {
9445         return(TNG_FAILURE);
9446     }
9447
9448     strncpy(name, atom->residue->name, max_len - 1);
9449     name[max_len - 1] = 0;
9450
9451     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
9452     {
9453         return(TNG_FAILURE);
9454     }
9455     return(TNG_SUCCESS);
9456 }
9457
9458 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
9459                 (const tng_trajectory_t tng_data,
9460                  const int64_t nr,
9461                  int64_t *id)
9462 {
9463     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9464     tng_molecule_t mol;
9465     tng_atom_t atom;
9466     tng_bool found = TNG_FALSE;
9467
9468     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9469     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9470
9471     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9472
9473     if(!molecule_cnt_list)
9474     {
9475         return(TNG_FAILURE);
9476     }
9477
9478     for(i = 0; i < tng_data->n_molecules; i++)
9479     {
9480         mol = &tng_data->molecules[i];
9481         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9482         {
9483             cnt += mol->n_atoms * molecule_cnt_list[i];
9484             continue;
9485         }
9486         atom = &mol->atoms[nr % mol->n_atoms];
9487         found = TNG_TRUE;
9488         break;
9489     }
9490     if(!found)
9491     {
9492         return(TNG_FAILURE);
9493     }
9494     if(!atom->residue)
9495     {
9496         return(TNG_FAILURE);
9497     }
9498
9499     *id = atom->residue->id;
9500
9501     return(TNG_SUCCESS);
9502 }
9503
9504 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
9505                 (const tng_trajectory_t tng_data,
9506                  const int64_t nr,
9507                  int64_t *id)
9508 {
9509     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
9510     tng_molecule_t mol;
9511     tng_atom_t atom;
9512     tng_bool found = TNG_FALSE;
9513
9514     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9515     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9516
9517     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9518
9519     if(!molecule_cnt_list)
9520     {
9521         return(TNG_FAILURE);
9522     }
9523
9524     for(i = 0; i < tng_data->n_molecules; i++)
9525     {
9526         mol = &tng_data->molecules[i];
9527         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9528         {
9529             cnt += mol->n_atoms * molecule_cnt_list[i];
9530             offset += mol->n_residues * molecule_cnt_list[i];
9531             continue;
9532         }
9533         atom = &mol->atoms[nr % mol->n_atoms];
9534         found = TNG_TRUE;
9535         break;
9536     }
9537     if(!found)
9538     {
9539         return(TNG_FAILURE);
9540     }
9541     if(!atom->residue)
9542     {
9543         return(TNG_FAILURE);
9544     }
9545
9546     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
9547
9548     *id = atom->residue->id + offset;
9549
9550     return(TNG_SUCCESS);
9551 }
9552
9553 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
9554                 (const tng_trajectory_t tng_data,
9555                  const int64_t nr,
9556                  char *name,
9557                  int max_len)
9558 {
9559     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9560     tng_molecule_t mol;
9561     tng_atom_t atom;
9562     tng_bool found = TNG_FALSE;
9563
9564     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9565     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9566
9567     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9568
9569     if(!molecule_cnt_list)
9570     {
9571         return(TNG_FAILURE);
9572     }
9573
9574     for(i = 0; i < tng_data->n_molecules; i++)
9575     {
9576         mol = &tng_data->molecules[i];
9577         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9578         {
9579             cnt += mol->n_atoms * molecule_cnt_list[i];
9580             continue;
9581         }
9582         atom = &mol->atoms[nr % mol->n_atoms];
9583         found = TNG_TRUE;
9584         break;
9585     }
9586     if(!found)
9587     {
9588         return(TNG_FAILURE);
9589     }
9590
9591     strncpy(name, atom->name, max_len - 1);
9592     name[max_len - 1] = 0;
9593
9594     if(strlen(atom->name) > (unsigned int)max_len - 1)
9595     {
9596         return(TNG_FAILURE);
9597     }
9598     return(TNG_SUCCESS);
9599 }
9600
9601 tng_function_status tng_atom_type_of_particle_nr_get
9602                 (const tng_trajectory_t tng_data,
9603                  const int64_t nr,
9604                  char *type,
9605                  int max_len)
9606 {
9607     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9608     tng_molecule_t mol;
9609     tng_atom_t atom;
9610     tng_bool found = TNG_FALSE;
9611
9612     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9613     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
9614
9615     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9616
9617     if(!molecule_cnt_list)
9618     {
9619         return(TNG_FAILURE);
9620     }
9621
9622     for(i = 0; i < tng_data->n_molecules; i++)
9623     {
9624         mol = &tng_data->molecules[i];
9625         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9626         {
9627             cnt += mol->n_atoms * molecule_cnt_list[i];
9628             continue;
9629         }
9630         atom = &mol->atoms[nr % mol->n_atoms];
9631         found = TNG_TRUE;
9632         break;
9633     }
9634     if(!found)
9635     {
9636         return(TNG_FAILURE);
9637     }
9638
9639     strncpy(type, atom->atom_type, max_len - 1);
9640     type[max_len - 1] = 0;
9641
9642     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
9643     {
9644         return(TNG_FAILURE);
9645     }
9646     return(TNG_SUCCESS);
9647 }
9648
9649 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9650                 (tng_trajectory_t tng_data,
9651                  const int64_t num_first_particle,
9652                  const int64_t n_particles,
9653                  const int64_t *mapping_table)
9654 {
9655     int64_t i;
9656     tng_particle_mapping_t mapping;
9657     tng_trajectory_frame_set_t frame_set;
9658
9659     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9660
9661     frame_set = &tng_data->current_trajectory_frame_set;
9662
9663     /* Sanity check of the particle ranges. Split into multiple if
9664      * statements for improved readability */
9665     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9666     {
9667         mapping = &frame_set->mappings[i];
9668         if(num_first_particle >= mapping->num_first_particle &&
9669            num_first_particle < mapping->num_first_particle +
9670                                    mapping->n_particles)
9671         {
9672             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9673             return(TNG_FAILURE);
9674         }
9675         if(num_first_particle + n_particles >=
9676            mapping->num_first_particle &&
9677            num_first_particle + n_particles <
9678            mapping->num_first_particle + mapping->n_particles)
9679         {
9680             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9681             return(TNG_FAILURE);
9682         }
9683         if(mapping->num_first_particle >= num_first_particle &&
9684            mapping->num_first_particle < num_first_particle +
9685                                             n_particles)
9686         {
9687             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9688             return(TNG_FAILURE);
9689         }
9690         if(mapping->num_first_particle + mapping->n_particles >
9691            num_first_particle &&
9692            mapping->num_first_particle + mapping->n_particles <
9693            num_first_particle + n_particles)
9694         {
9695             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9696             return(TNG_FAILURE);
9697         }
9698     }
9699
9700     frame_set->n_mapping_blocks++;
9701
9702     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9703                       frame_set->n_mapping_blocks);
9704
9705     if(!mapping)
9706     {
9707         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9708                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9709                __FILE__, __LINE__);
9710         free(frame_set->mappings);
9711         frame_set->mappings = 0;
9712         return(TNG_CRITICAL);
9713     }
9714     frame_set->mappings = mapping;
9715
9716     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9717     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9718
9719     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9720     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9721     {
9722         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9723                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9724         return(TNG_CRITICAL);
9725     }
9726
9727     for(i=0; i<n_particles; i++)
9728     {
9729         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9730     }
9731
9732     return(TNG_SUCCESS);
9733 }
9734
9735 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9736 {
9737     tng_trajectory_frame_set_t frame_set;
9738     tng_particle_mapping_t mapping;
9739     int64_t i;
9740
9741     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9742
9743     frame_set = &tng_data->current_trajectory_frame_set;
9744
9745     if(frame_set->n_mapping_blocks && frame_set->mappings)
9746     {
9747         for(i = 0; i < frame_set->n_mapping_blocks; i++)
9748         {
9749             mapping = &frame_set->mappings[i];
9750             if(mapping->real_particle_numbers)
9751             {
9752                 free(mapping->real_particle_numbers);
9753                 mapping->real_particle_numbers = 0;
9754             }
9755         }
9756         free(frame_set->mappings);
9757         frame_set->mappings = 0;
9758         frame_set->n_mapping_blocks = 0;
9759     }
9760
9761     return(TNG_SUCCESS);
9762 }
9763
9764 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9765 {
9766     time_t seconds;
9767     tng_trajectory_frame_set_t frame_set;
9768     tng_trajectory_t tng_data;
9769
9770     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9771     if(!*tng_data_p)
9772     {
9773         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9774                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9775         return(TNG_CRITICAL);
9776     }
9777
9778     tng_data = *tng_data_p;
9779
9780     frame_set = &tng_data->current_trajectory_frame_set;
9781
9782     tng_data->input_file_path = 0;
9783     tng_data->input_file = 0;
9784     tng_data->input_file_len = 0;
9785     tng_data->output_file_path = 0;
9786     tng_data->output_file = 0;
9787
9788     tng_data->first_program_name = 0;
9789     tng_data->first_user_name = 0;
9790     tng_data->first_computer_name = 0;
9791     tng_data->first_pgp_signature = 0;
9792     tng_data->last_program_name = 0;
9793     tng_data->last_user_name = 0;
9794     tng_data->last_computer_name = 0;
9795     tng_data->last_pgp_signature = 0;
9796     tng_data->forcefield_name = 0;
9797
9798     seconds = time(0);
9799     if ( seconds == -1)
9800     {
9801         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9802     }
9803     else
9804     {
9805         tng_data->time = seconds;
9806     }
9807
9808     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9809     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9810     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9811     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9812     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9813     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9814     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9815     tng_data->frame_set_n_frames = 100;
9816     tng_data->n_trajectory_frame_sets = 0;
9817     tng_data->medium_stride_length = 100;
9818     tng_data->long_stride_length = 10000;
9819
9820     tng_data->time_per_frame = -1;
9821
9822     tng_data->n_particle_data_blocks = 0;
9823     tng_data->n_data_blocks = 0;
9824
9825     tng_data->non_tr_particle_data = 0;
9826     tng_data->non_tr_data = 0;
9827
9828     tng_data->compress_algo_pos = 0;
9829     tng_data->compress_algo_vel = 0;
9830     tng_data->compression_precision = 1000;
9831     tng_data->distance_unit_exponential = -9;
9832
9833     frame_set->first_frame = -1;
9834     frame_set->n_mapping_blocks = 0;
9835     frame_set->mappings = 0;
9836     frame_set->molecule_cnt_list = 0;
9837
9838     frame_set->n_particle_data_blocks = 0;
9839     frame_set->n_data_blocks = 0;
9840
9841     frame_set->tr_particle_data = 0;
9842     frame_set->tr_data = 0;
9843
9844     frame_set->n_written_frames = 0;
9845     frame_set->n_unwritten_frames = 0;
9846
9847     frame_set->next_frame_set_file_pos = -1;
9848     frame_set->prev_frame_set_file_pos = -1;
9849     frame_set->medium_stride_next_frame_set_file_pos = -1;
9850     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9851     frame_set->long_stride_next_frame_set_file_pos = -1;
9852     frame_set->long_stride_prev_frame_set_file_pos = -1;
9853
9854     frame_set->first_frame_time = -1;
9855
9856     tng_data->n_molecules = 0;
9857     tng_data->molecules = 0;
9858     tng_data->molecule_cnt_list = 0;
9859     tng_data->n_particles = 0;
9860
9861     {
9862       /* Check the endianness of the computer */
9863       static int32_t endianness_32 = 0x01234567;
9864       /* 0x01234567 */
9865       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9866         {
9867           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9868         }
9869
9870       /* 0x67452301 */
9871       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9872         {
9873           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9874
9875         }
9876
9877       /* 0x45670123 */
9878       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9879         {
9880           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9881         }
9882     }
9883     {
9884       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9885       /* 0x0123456789ABCDEF */
9886       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9887         {
9888           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9889         }
9890
9891       /* 0xEFCDAB8967452301 */
9892       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9893         {
9894           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9895         }
9896
9897       /* 0x89ABCDEF01234567 */
9898       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9899         {
9900           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9901         }
9902
9903       /* 0x45670123CDEF89AB */
9904       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9905         {
9906           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9907         }
9908
9909       /* 0x23016745AB89EFCD */
9910       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9911         {
9912           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9913         }
9914     }
9915
9916     /* By default do not swap the byte order, i.e. keep the byte order of the
9917      * architecture. The input file endianness will be set when reading the
9918      * header. The output endianness can be changed - before the file is
9919      * written. */
9920     tng_data->input_endianness_swap_func_32 = 0;
9921     tng_data->input_endianness_swap_func_64 = 0;
9922     tng_data->output_endianness_swap_func_32 = 0;
9923     tng_data->output_endianness_swap_func_64 = 0;
9924
9925     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9926     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9927     tng_data->current_trajectory_frame_set.n_frames = 0;
9928
9929     return(TNG_SUCCESS);
9930 }
9931
9932 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9933 {
9934     int64_t i, j, k, l;
9935     int64_t n_particles, n_values_per_frame;
9936     tng_trajectory_t tng_data = *tng_data_p;
9937     tng_trajectory_frame_set_t frame_set;
9938
9939     if(!*tng_data_p)
9940     {
9941         return(TNG_SUCCESS);
9942     }
9943
9944     frame_set = &tng_data->current_trajectory_frame_set;
9945
9946     if(tng_data->input_file_path)
9947     {
9948         free(tng_data->input_file_path);
9949         tng_data->input_file_path = 0;
9950     }
9951
9952     if(tng_data->input_file)
9953     {
9954         if(tng_data->output_file == tng_data->input_file)
9955         {
9956             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9957             tng_data->output_file = 0;
9958         }
9959         fclose(tng_data->input_file);
9960         tng_data->input_file = 0;
9961     }
9962
9963     if(tng_data->output_file_path)
9964     {
9965         free(tng_data->output_file_path);
9966         tng_data->output_file_path = 0;
9967     }
9968
9969     if(tng_data->output_file)
9970     {
9971         /* FIXME: Do not always write the hash */
9972         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9973         fclose(tng_data->output_file);
9974         tng_data->output_file = 0;
9975     }
9976
9977     if(tng_data->first_program_name)
9978     {
9979         free(tng_data->first_program_name);
9980         tng_data->first_program_name = 0;
9981     }
9982
9983     if(tng_data->last_program_name)
9984     {
9985         free(tng_data->last_program_name);
9986         tng_data->last_program_name = 0;
9987     }
9988
9989     if(tng_data->first_user_name)
9990     {
9991         free(tng_data->first_user_name);
9992         tng_data->first_user_name = 0;
9993     }
9994
9995     if(tng_data->last_user_name)
9996     {
9997         free(tng_data->last_user_name);
9998         tng_data->last_user_name = 0;
9999     }
10000
10001     if(tng_data->first_computer_name)
10002     {
10003         free(tng_data->first_computer_name);
10004         tng_data->first_computer_name = 0;
10005     }
10006
10007     if(tng_data->last_computer_name)
10008     {
10009         free(tng_data->last_computer_name);
10010         tng_data->last_computer_name = 0;
10011     }
10012
10013     if(tng_data->first_pgp_signature)
10014     {
10015         free(tng_data->first_pgp_signature);
10016         tng_data->first_pgp_signature = 0;
10017     }
10018
10019     if(tng_data->last_pgp_signature)
10020     {
10021         free(tng_data->last_pgp_signature);
10022         tng_data->last_pgp_signature = 0;
10023     }
10024
10025     if(tng_data->forcefield_name)
10026     {
10027         free(tng_data->forcefield_name);
10028         tng_data->forcefield_name = 0;
10029     }
10030
10031     tng_frame_set_particle_mapping_free(tng_data);
10032
10033     if(frame_set->molecule_cnt_list)
10034     {
10035         free(frame_set->molecule_cnt_list);
10036         frame_set->molecule_cnt_list = 0;
10037     }
10038
10039     if(tng_data->var_num_atoms_flag)
10040     {
10041         n_particles = frame_set->n_particles;
10042     }
10043     else
10044     {
10045         n_particles = tng_data->n_particles;
10046     }
10047
10048     if(tng_data->non_tr_particle_data)
10049     {
10050         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
10051         {
10052             if(tng_data->non_tr_particle_data[i].values)
10053             {
10054                 free(tng_data->non_tr_particle_data[i].values);
10055                 tng_data->non_tr_particle_data[i].values = 0;
10056             }
10057
10058             if(tng_data->non_tr_particle_data[i].strings)
10059             {
10060                 n_values_per_frame = tng_data->non_tr_particle_data[i].
10061                                      n_values_per_frame;
10062                 if(tng_data->non_tr_particle_data[i].strings[0])
10063                 {
10064                     for(j = 0; j < n_particles; j++)
10065                     {
10066                         if(tng_data->non_tr_particle_data[i].strings[0][j])
10067                         {
10068                             for(k = 0; k < n_values_per_frame; k++)
10069                             {
10070                                 if(tng_data->non_tr_particle_data[i].
10071                                    strings[0][j][k])
10072                                 {
10073                                     free(tng_data->non_tr_particle_data[i].
10074                                          strings[0][j][k]);
10075                                     tng_data->non_tr_particle_data[i].
10076                                     strings[0][j][k] = 0;
10077                                 }
10078                             }
10079                             free(tng_data->non_tr_particle_data[i].
10080                                  strings[0][j]);
10081                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
10082                         }
10083                     }
10084                     free(tng_data->non_tr_particle_data[i].strings[0]);
10085                     tng_data->non_tr_particle_data[i].strings[0] = 0;
10086                 }
10087                 free(tng_data->non_tr_particle_data[i].strings);
10088                 tng_data->non_tr_particle_data[i].strings = 0;
10089             }
10090
10091             if(tng_data->non_tr_particle_data[i].block_name)
10092             {
10093                 free(tng_data->non_tr_particle_data[i].block_name);
10094                 tng_data->non_tr_particle_data[i].block_name = 0;
10095             }
10096         }
10097         free(tng_data->non_tr_particle_data);
10098         tng_data->non_tr_particle_data = 0;
10099     }
10100
10101     if(tng_data->non_tr_data)
10102     {
10103         for(i = 0; i < tng_data->n_data_blocks; i++)
10104         {
10105             if(tng_data->non_tr_data[i].values)
10106             {
10107                 free(tng_data->non_tr_data[i].values);
10108                 tng_data->non_tr_data[i].values = 0;
10109             }
10110
10111             if(tng_data->non_tr_data[i].strings)
10112             {
10113                 n_values_per_frame = tng_data->non_tr_data[i].
10114                                      n_values_per_frame;
10115                 if(tng_data->non_tr_data[i].strings[0])
10116                 {
10117                     for(j = 0; j < n_values_per_frame; j++)
10118                     {
10119                         if(tng_data->non_tr_data[i].strings[0][j])
10120                         {
10121                             free(tng_data->non_tr_data[i].strings[0][j]);
10122                             tng_data->non_tr_data[i].strings[0][j] = 0;
10123                         }
10124                     }
10125                     free(tng_data->non_tr_data[i].strings[0]);
10126                     tng_data->non_tr_data[i].strings[0] = 0;
10127                 }
10128                 free(tng_data->non_tr_data[i].strings);
10129                 tng_data->non_tr_data[i].strings = 0;
10130             }
10131
10132             if(tng_data->non_tr_data[i].block_name)
10133             {
10134                 free(tng_data->non_tr_data[i].block_name);
10135                 tng_data->non_tr_data[i].block_name = 0;
10136             }
10137         }
10138         free(tng_data->non_tr_data);
10139         tng_data->non_tr_data = 0;
10140     }
10141
10142     tng_data->n_particle_data_blocks = 0;
10143     tng_data->n_data_blocks = 0;
10144
10145     if(tng_data->compress_algo_pos)
10146     {
10147         free(tng_data->compress_algo_pos);
10148         tng_data->compress_algo_pos = 0;
10149     }
10150     if(tng_data->compress_algo_vel)
10151     {
10152         free(tng_data->compress_algo_vel);
10153         tng_data->compress_algo_vel = 0;
10154     }
10155
10156     if(frame_set->tr_particle_data)
10157     {
10158         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
10159         {
10160             if(frame_set->tr_particle_data[i].values)
10161             {
10162                 free(frame_set->tr_particle_data[i].values);
10163                 frame_set->tr_particle_data[i].values = 0;
10164             }
10165
10166             if(frame_set->tr_particle_data[i].strings)
10167             {
10168                 n_values_per_frame = frame_set->tr_particle_data[i].
10169                                      n_values_per_frame;
10170                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
10171                 {
10172                     if(frame_set->tr_particle_data[i].strings[j])
10173                     {
10174                         for(k = 0; k < n_particles; k++)
10175                         {
10176                             if(frame_set->tr_particle_data[i].
10177                                 strings[j][k])
10178                             {
10179                                 for(l = 0; l < n_values_per_frame; l++)
10180                                 {
10181                                     if(frame_set->tr_particle_data[i].
10182                                         strings[j][k][l])
10183                                     {
10184                                         free(frame_set->tr_particle_data[i].
10185                                                 strings[j][k][l]);
10186                                         frame_set->tr_particle_data[i].
10187                                         strings[j][k][l] = 0;
10188                                     }
10189                                 }
10190                                 free(frame_set->tr_particle_data[i].
10191                                         strings[j][k]);
10192                                 frame_set->tr_particle_data[i].
10193                                 strings[j][k] = 0;
10194                             }
10195                         }
10196                         free(frame_set->tr_particle_data[i].strings[j]);
10197                         frame_set->tr_particle_data[i].strings[j] = 0;
10198                     }
10199                 }
10200                 free(frame_set->tr_particle_data[i].strings);
10201                 frame_set->tr_particle_data[i].strings = 0;
10202             }
10203
10204             if(frame_set->tr_particle_data[i].block_name)
10205             {
10206                 free(frame_set->tr_particle_data[i].block_name);
10207                 frame_set->tr_particle_data[i].block_name = 0;
10208             }
10209         }
10210         free(frame_set->tr_particle_data);
10211         frame_set->tr_particle_data = 0;
10212     }
10213
10214     if(frame_set->tr_data)
10215     {
10216         for(i = 0; i < frame_set->n_data_blocks; i++)
10217         {
10218             if(frame_set->tr_data[i].values)
10219             {
10220                 free(frame_set->tr_data[i].values);
10221                 frame_set->tr_data[i].values = 0;
10222             }
10223
10224             if(frame_set->tr_data[i].strings)
10225             {
10226                 n_values_per_frame = frame_set->tr_data[i].
10227                                      n_values_per_frame;
10228                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
10229                 {
10230                     if(frame_set->tr_data[i].strings[j])
10231                     {
10232                         for(k = 0; k < n_values_per_frame; k++)
10233                         {
10234                             if(frame_set->tr_data[i].strings[j][k])
10235                             {
10236                                 free(frame_set->tr_data[i].strings[j][k]);
10237                                 frame_set->tr_data[i].strings[j][k] = 0;
10238                             }
10239                         }
10240                         free(frame_set->tr_data[i].strings[j]);
10241                         frame_set->tr_data[i].strings[j] = 0;
10242                     }
10243                 }
10244                 free(frame_set->tr_data[i].strings);
10245                 frame_set->tr_data[i].strings = 0;
10246             }
10247
10248             if(frame_set->tr_data[i].block_name)
10249             {
10250                 free(frame_set->tr_data[i].block_name);
10251                 frame_set->tr_data[i].block_name = 0;
10252             }
10253         }
10254         free(frame_set->tr_data);
10255         frame_set->tr_data = 0;
10256     }
10257
10258     frame_set->n_particle_data_blocks = 0;
10259     frame_set->n_data_blocks = 0;
10260
10261     if(tng_data->molecules)
10262     {
10263         for(i = 0; i < tng_data->n_molecules; i++)
10264         {
10265             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
10266         }
10267         free(tng_data->molecules);
10268         tng_data->molecules = 0;
10269         tng_data->n_molecules = 0;
10270     }
10271     if(tng_data->molecule_cnt_list)
10272     {
10273         free(tng_data->molecule_cnt_list);
10274         tng_data->molecule_cnt_list = 0;
10275     }
10276
10277     free(*tng_data_p);
10278     *tng_data_p = 0;
10279
10280     return(TNG_SUCCESS);
10281 }
10282
10283 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
10284                                                  tng_trajectory_t *dest_p)
10285 {
10286     tng_trajectory_frame_set_t frame_set;
10287     tng_trajectory_t dest;
10288
10289     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
10290
10291     *dest_p = malloc(sizeof(struct tng_trajectory));
10292     if(!*dest_p)
10293     {
10294         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
10295                sizeof(struct tng_trajectory), __FILE__, __LINE__);
10296         return(TNG_CRITICAL);
10297     }
10298
10299     dest = *dest_p;
10300
10301     frame_set = &dest->current_trajectory_frame_set;
10302
10303     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
10304     if(!dest->input_file_path)
10305     {
10306         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10307                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
10308         return(TNG_CRITICAL);
10309     }
10310     strcpy(dest->input_file_path, src->input_file_path);
10311     dest->input_file = 0;
10312     dest->input_file_len = src->input_file_len;
10313     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
10314     if(!dest->output_file_path)
10315     {
10316         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10317                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
10318         return(TNG_CRITICAL);
10319     }
10320     strcpy(dest->output_file_path, src->output_file_path);
10321     dest->output_file = 0;
10322
10323     dest->first_program_name = 0;
10324     dest->first_user_name = 0;
10325     dest->first_computer_name = 0;
10326     dest->first_pgp_signature = 0;
10327     dest->last_program_name = 0;
10328     dest->last_user_name = 0;
10329     dest->last_computer_name = 0;
10330     dest->last_pgp_signature = 0;
10331     dest->forcefield_name = 0;
10332
10333     dest->var_num_atoms_flag = src->var_num_atoms_flag;
10334     dest->first_trajectory_frame_set_input_file_pos =
10335     src->first_trajectory_frame_set_input_file_pos;
10336     dest->last_trajectory_frame_set_input_file_pos =
10337     src->last_trajectory_frame_set_input_file_pos;
10338     dest->current_trajectory_frame_set_input_file_pos =
10339     src->current_trajectory_frame_set_input_file_pos;
10340     dest->first_trajectory_frame_set_output_file_pos =
10341     src->first_trajectory_frame_set_output_file_pos;
10342     dest->last_trajectory_frame_set_output_file_pos =
10343     src->last_trajectory_frame_set_output_file_pos;
10344     dest->current_trajectory_frame_set_output_file_pos =
10345     src->current_trajectory_frame_set_output_file_pos;
10346     dest->frame_set_n_frames = src->frame_set_n_frames;
10347     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
10348     dest->medium_stride_length = src->medium_stride_length;
10349     dest->long_stride_length = src->long_stride_length;
10350
10351     dest->time_per_frame = src->time_per_frame;
10352
10353     /* Currently the non trajectory data blocks are not copied since it
10354      * can lead to problems when freeing memory in a parallel block. */
10355     dest->n_particle_data_blocks = 0;
10356     dest->n_data_blocks = 0;
10357     dest->non_tr_particle_data = 0;
10358     dest->non_tr_data = 0;
10359
10360     dest->compress_algo_pos = 0;
10361     dest->compress_algo_vel = 0;
10362     dest->distance_unit_exponential = -9;
10363     dest->compression_precision = 1000;
10364
10365     frame_set->n_mapping_blocks = 0;
10366     frame_set->mappings = 0;
10367     frame_set->molecule_cnt_list = 0;
10368
10369     frame_set->n_particle_data_blocks = 0;
10370     frame_set->n_data_blocks = 0;
10371
10372     frame_set->tr_particle_data = 0;
10373     frame_set->tr_data = 0;
10374
10375     frame_set->next_frame_set_file_pos = -1;
10376     frame_set->prev_frame_set_file_pos = -1;
10377     frame_set->medium_stride_next_frame_set_file_pos = -1;
10378     frame_set->medium_stride_prev_frame_set_file_pos = -1;
10379     frame_set->long_stride_next_frame_set_file_pos = -1;
10380     frame_set->long_stride_prev_frame_set_file_pos = -1;
10381     frame_set->first_frame = -1;
10382
10383     dest->n_molecules = 0;
10384     dest->molecules = 0;
10385     dest->molecule_cnt_list = 0;
10386     dest->n_particles = src->n_particles;
10387
10388     dest->endianness_32 = src->endianness_32;
10389     dest->endianness_64 = src->endianness_64;
10390     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
10391     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
10392     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
10393     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
10394
10395     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
10396     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
10397     dest->current_trajectory_frame_set.n_frames = 0;
10398
10399     return(TNG_SUCCESS);
10400 }
10401
10402 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
10403                                        char *file_name, const int max_len)
10404 {
10405     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10406     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10407
10408     strncpy(file_name, tng_data->input_file_path, max_len - 1);
10409     file_name[max_len - 1] = 0;
10410
10411     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
10412     {
10413         return(TNG_FAILURE);
10414     }
10415     return(TNG_SUCCESS);
10416 }
10417
10418 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
10419                                                          const char *file_name)
10420 {
10421     unsigned int len;
10422     char *temp;
10423
10424     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10425     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10426
10427
10428     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
10429                                            file_name) == 0)
10430     {
10431         return(TNG_SUCCESS);
10432     }
10433
10434     if(tng_data->input_file)
10435     {
10436         fclose(tng_data->input_file);
10437     }
10438
10439     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10440     temp = realloc(tng_data->input_file_path, len);
10441     if(!temp)
10442     {
10443         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10444                __FILE__, __LINE__);
10445         free(tng_data->input_file_path);
10446         tng_data->input_file_path = 0;
10447         return(TNG_CRITICAL);
10448     }
10449     tng_data->input_file_path = temp;
10450
10451     strncpy(tng_data->input_file_path, file_name, len);
10452
10453     return(tng_input_file_init(tng_data));
10454 }
10455
10456 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
10457                                        char *file_name, const int max_len)
10458 {
10459     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10460     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10461
10462     strncpy(file_name, tng_data->output_file_path, max_len - 1);
10463     file_name[max_len - 1] = 0;
10464
10465     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
10466     {
10467         return(TNG_FAILURE);
10468     }
10469     return(TNG_SUCCESS);
10470 }
10471
10472 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
10473                                                           const char *file_name)
10474 {
10475     int len;
10476     char *temp;
10477
10478     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10479     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10480
10481     if(tng_data->output_file_path &&
10482        strcmp(tng_data->output_file_path, file_name) == 0)
10483     {
10484         return(TNG_SUCCESS);
10485     }
10486
10487     if(tng_data->output_file)
10488     {
10489         fclose(tng_data->output_file);
10490     }
10491
10492     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10493     temp = realloc(tng_data->output_file_path, len);
10494     if(!temp)
10495     {
10496         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10497                __FILE__, __LINE__);
10498         free(tng_data->output_file_path);
10499         tng_data->output_file_path = 0;
10500         return(TNG_CRITICAL);
10501     }
10502     tng_data->output_file_path = temp;
10503
10504     strncpy(tng_data->output_file_path, file_name, len);
10505
10506     return(tng_output_file_init(tng_data));
10507 }
10508
10509 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
10510                 (tng_trajectory_t tng_data,
10511                  const char *file_name)
10512 {
10513     int len;
10514     char *temp;
10515
10516     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10517     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10518
10519     if(tng_data->output_file_path &&
10520        strcmp(tng_data->output_file_path, file_name) == 0)
10521     {
10522         return(TNG_SUCCESS);
10523     }
10524
10525     if(tng_data->output_file)
10526     {
10527         fclose(tng_data->output_file);
10528     }
10529
10530     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10531     temp = realloc(tng_data->output_file_path, len);
10532     if(!temp)
10533     {
10534         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10535                __FILE__, __LINE__);
10536         free(tng_data->output_file_path);
10537         tng_data->output_file_path = 0;
10538         return(TNG_CRITICAL);
10539     }
10540     tng_data->output_file_path = temp;
10541
10542     strncpy(tng_data->output_file_path, file_name, len);
10543
10544     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
10545     if(!tng_data->output_file)
10546     {
10547         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
10548                 tng_data->output_file_path, __FILE__, __LINE__);
10549         return(TNG_CRITICAL);
10550     }
10551     tng_data->input_file = tng_data->output_file;
10552
10553     return(TNG_SUCCESS);
10554 }
10555
10556 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
10557                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
10558 {
10559     tng_endianness_32 end_32;
10560     tng_endianness_64 end_64;
10561
10562     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10563     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
10564
10565     if(tng_data->output_endianness_swap_func_32)
10566     {
10567         /* If other endianness variants are added they must be added here as well */
10568         if(tng_data->output_endianness_swap_func_32 ==
10569            &tng_swap_byte_order_big_endian_32)
10570         {
10571             end_32 = TNG_BIG_ENDIAN_32;
10572         }
10573         else if(tng_data->output_endianness_swap_func_32 ==
10574                 &tng_swap_byte_order_little_endian_32)
10575         {
10576             end_32 = TNG_LITTLE_ENDIAN_32;
10577         }
10578         else
10579         {
10580             return(TNG_FAILURE);
10581         }
10582     }
10583     else
10584     {
10585         end_32 = (tng_endianness_32)tng_data->endianness_32;
10586     }
10587
10588     if(tng_data->output_endianness_swap_func_64)
10589     {
10590         /* If other endianness variants are added they must be added here as well */
10591         if(tng_data->output_endianness_swap_func_64 ==
10592            &tng_swap_byte_order_big_endian_64)
10593         {
10594             end_64 = TNG_BIG_ENDIAN_64;
10595         }
10596         else if(tng_data->output_endianness_swap_func_64 ==
10597                 &tng_swap_byte_order_little_endian_64)
10598         {
10599             end_64 = TNG_LITTLE_ENDIAN_64;
10600         }
10601         else
10602         {
10603             return(TNG_FAILURE);
10604         }
10605     }
10606     else
10607     {
10608         end_64 = (tng_endianness_64)tng_data->endianness_64;
10609     }
10610
10611     if((int)end_32 != (int)end_64)
10612     {
10613         return(TNG_FAILURE);
10614     }
10615
10616     if(end_32 == TNG_LITTLE_ENDIAN_32)
10617     {
10618         *endianness = TNG_LITTLE_ENDIAN;
10619     }
10620
10621     else if(end_32 == TNG_BIG_ENDIAN_32)
10622     {
10623         *endianness = TNG_BIG_ENDIAN;
10624     }
10625     else
10626     {
10627         return(TNG_FAILURE);
10628     }
10629
10630     return(TNG_SUCCESS);
10631 }
10632
10633 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
10634                 (tng_trajectory_t tng_data,
10635                  const tng_file_endianness endianness)
10636 {
10637     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10638
10639     /* Tne endianness cannot be changed if the data has already been written
10640      * to the output file. */
10641     if(ftello(tng_data->output_file) > 0)
10642     {
10643         return(TNG_FAILURE);
10644     }
10645
10646     if(endianness == TNG_BIG_ENDIAN)
10647     {
10648         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
10649         {
10650             tng_data->output_endianness_swap_func_32 = 0;
10651         }
10652         else
10653         {
10654             tng_data->output_endianness_swap_func_32 =
10655             &tng_swap_byte_order_big_endian_32;
10656         }
10657         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10658         {
10659             tng_data->output_endianness_swap_func_64 = 0;
10660         }
10661         else
10662         {
10663             tng_data->output_endianness_swap_func_64 =
10664             &tng_swap_byte_order_big_endian_64;
10665         }
10666         return(TNG_SUCCESS);
10667     }
10668     else if(endianness == TNG_LITTLE_ENDIAN)
10669     {
10670         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10671         {
10672             tng_data->output_endianness_swap_func_32 = 0;
10673         }
10674         else
10675         {
10676             tng_data->output_endianness_swap_func_32 =
10677             &tng_swap_byte_order_little_endian_32;
10678         }
10679         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10680         {
10681             tng_data->output_endianness_swap_func_64 = 0;
10682         }
10683         else
10684         {
10685             tng_data->output_endianness_swap_func_64 =
10686             &tng_swap_byte_order_little_endian_64;
10687         }
10688         return(TNG_SUCCESS);
10689     }
10690
10691     /* If the specified endianness is neither big nor little endian return a
10692      * failure. */
10693     return(TNG_FAILURE);
10694 }
10695
10696 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10697                     (const tng_trajectory_t tng_data,
10698                      char *name, const int max_len)
10699 {
10700     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10701     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10702
10703     strncpy(name, tng_data->first_program_name, max_len - 1);
10704     name[max_len - 1] = 0;
10705
10706     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10707     {
10708         return(TNG_FAILURE);
10709     }
10710     return(TNG_SUCCESS);
10711 }
10712
10713 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10714                                                                  const char *new_name)
10715 {
10716     unsigned int len;
10717
10718     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10719     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10720
10721     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10722
10723     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10724     {
10725         free(tng_data->first_program_name);
10726         tng_data->first_program_name = 0;
10727     }
10728     if(!tng_data->first_program_name)
10729     {
10730         tng_data->first_program_name = malloc(len);
10731         if(!tng_data->first_program_name)
10732         {
10733             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10734                    __FILE__, __LINE__);
10735             return(TNG_CRITICAL);
10736         }
10737     }
10738
10739     strncpy(tng_data->first_program_name, new_name, len);
10740
10741     return(TNG_SUCCESS);
10742 }
10743
10744 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10745                     (const tng_trajectory_t tng_data,
10746                      char *name, const int max_len)
10747 {
10748     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10749     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10750
10751     strncpy(name, tng_data->last_program_name, max_len - 1);
10752     name[max_len - 1] = 0;
10753
10754     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10755     {
10756         return(TNG_FAILURE);
10757     }
10758     return(TNG_SUCCESS);
10759 }
10760
10761 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10762                     (tng_trajectory_t tng_data,
10763                      const char *new_name)
10764 {
10765     unsigned int len;
10766
10767     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10768     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10769
10770     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10771
10772     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10773     {
10774         free(tng_data->last_program_name);
10775         tng_data->last_program_name = 0;
10776     }
10777     if(!tng_data->last_program_name)
10778     {
10779         tng_data->last_program_name = malloc(len);
10780         if(!tng_data->last_program_name)
10781         {
10782             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10783                    __FILE__, __LINE__);
10784             return(TNG_CRITICAL);
10785         }
10786     }
10787
10788     strncpy(tng_data->last_program_name, new_name, len);
10789
10790     return(TNG_SUCCESS);
10791 }
10792
10793 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10794                     (const tng_trajectory_t tng_data,
10795                      char *name, const int max_len)
10796 {
10797     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10798     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10799
10800     strncpy(name, tng_data->first_user_name, max_len - 1);
10801     name[max_len - 1] = 0;
10802
10803     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10804     {
10805         return(TNG_FAILURE);
10806     }
10807     return(TNG_SUCCESS);
10808 }
10809
10810 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10811                     (tng_trajectory_t tng_data,
10812                      const char *new_name)
10813 {
10814     unsigned int len;
10815
10816     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10817     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10818
10819     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10820
10821     /* If the currently stored string length is not enough to store the new
10822      * string it is freed and reallocated. */
10823     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10824     {
10825         free(tng_data->first_user_name);
10826         tng_data->first_user_name = 0;
10827     }
10828     if(!tng_data->first_user_name)
10829     {
10830         tng_data->first_user_name = malloc(len);
10831         if(!tng_data->first_user_name)
10832         {
10833             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10834                    __FILE__, __LINE__);
10835             return(TNG_CRITICAL);
10836         }
10837     }
10838
10839     strncpy(tng_data->first_user_name, new_name, len);
10840
10841     return(TNG_SUCCESS);
10842 }
10843
10844 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10845                     (const tng_trajectory_t tng_data,
10846                      char *name, const int max_len)
10847 {
10848     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10849     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10850
10851     strncpy(name, tng_data->last_user_name, max_len - 1);
10852     name[max_len - 1] = 0;
10853
10854     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10855     {
10856         return(TNG_FAILURE);
10857     }
10858     return(TNG_SUCCESS);
10859 }
10860
10861 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10862                     (tng_trajectory_t tng_data,
10863                      const char *new_name)
10864 {
10865     unsigned int len;
10866
10867     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10868     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10869
10870     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10871
10872     /* If the currently stored string length is not enough to store the new
10873      * string it is freed and reallocated. */
10874     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10875     {
10876         free(tng_data->last_user_name);
10877         tng_data->last_user_name = 0;
10878     }
10879     if(!tng_data->last_user_name)
10880     {
10881         tng_data->last_user_name = malloc(len);
10882         if(!tng_data->last_user_name)
10883         {
10884             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10885                    __FILE__, __LINE__);
10886             return(TNG_CRITICAL);
10887         }
10888     }
10889
10890     strncpy(tng_data->last_user_name, new_name, len);
10891
10892     return(TNG_SUCCESS);
10893 }
10894
10895 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10896                     (const tng_trajectory_t tng_data,
10897                      char *name, const int max_len)
10898 {
10899     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10900     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10901
10902     strncpy(name, tng_data->first_computer_name, max_len - 1);
10903     name[max_len - 1] = 0;
10904
10905     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10906     {
10907         return(TNG_FAILURE);
10908     }
10909     return(TNG_SUCCESS);
10910 }
10911
10912 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10913                     (tng_trajectory_t tng_data,
10914                      const char *new_name)
10915 {
10916     unsigned int len;
10917
10918     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10919     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10920
10921     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10922
10923     /* If the currently stored string length is not enough to store the new
10924      * string it is freed and reallocated. */
10925     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10926     {
10927         free(tng_data->first_computer_name);
10928         tng_data->first_computer_name = 0;
10929     }
10930     if(!tng_data->first_computer_name)
10931     {
10932         tng_data->first_computer_name = malloc(len);
10933         if(!tng_data->first_computer_name)
10934         {
10935             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10936                    __FILE__, __LINE__);
10937             return(TNG_CRITICAL);
10938         }
10939     }
10940
10941     strncpy(tng_data->first_computer_name, new_name, len);
10942
10943     return(TNG_SUCCESS);
10944 }
10945
10946 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10947                     (const tng_trajectory_t tng_data,
10948                      char *name, const int max_len)
10949 {
10950     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10951     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10952
10953     strncpy(name, tng_data->last_computer_name, max_len - 1);
10954     name[max_len - 1] = 0;
10955
10956     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10957     {
10958         return(TNG_FAILURE);
10959     }
10960     return(TNG_SUCCESS);
10961 }
10962
10963 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10964                     (tng_trajectory_t tng_data,
10965                      const char *new_name)
10966 {
10967     unsigned int len;
10968
10969     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10970     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10971
10972     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10973
10974     /* If the currently stored string length is not enough to store the new
10975      * string it is freed and reallocated. */
10976     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10977         len)
10978     {
10979         free(tng_data->last_computer_name);
10980         tng_data->last_computer_name = 0;
10981     }
10982     if(!tng_data->last_computer_name)
10983     {
10984         tng_data->last_computer_name = malloc(len);
10985         if(!tng_data->last_computer_name)
10986         {
10987             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10988                    __FILE__, __LINE__);
10989             return(TNG_CRITICAL);
10990         }
10991     }
10992
10993     strncpy(tng_data->last_computer_name, new_name, len);
10994
10995     return(TNG_SUCCESS);
10996 }
10997
10998 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10999                     (const tng_trajectory_t tng_data,
11000                      char *signature, const int max_len)
11001 {
11002     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11003     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11004
11005     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
11006     signature[max_len - 1] = 0;
11007
11008     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
11009     {
11010         return(TNG_FAILURE);
11011     }
11012     return(TNG_SUCCESS);
11013 }
11014
11015 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
11016                     (tng_trajectory_t tng_data,
11017                      const char *signature)
11018 {
11019     unsigned int len;
11020
11021     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11022     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11023
11024     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11025
11026     /* If the currently stored string length is not enough to store the new
11027      * string it is freed and reallocated. */
11028     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
11029         len)
11030     {
11031         free(tng_data->first_pgp_signature);
11032         tng_data->first_pgp_signature = 0;
11033     }
11034     if(!tng_data->first_pgp_signature)
11035     {
11036         tng_data->first_pgp_signature = malloc(len);
11037         if(!tng_data->first_pgp_signature)
11038         {
11039             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11040                    __FILE__, __LINE__);
11041             return(TNG_CRITICAL);
11042         }
11043     }
11044
11045     strncpy(tng_data->first_pgp_signature, signature, len);
11046
11047     return(TNG_SUCCESS);
11048 }
11049
11050 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
11051                     (const tng_trajectory_t tng_data,
11052                      char *signature, const int max_len)
11053 {
11054     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11055     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11056
11057     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
11058     signature[max_len - 1] = 0;
11059
11060     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
11061     {
11062         return(TNG_FAILURE);
11063     }
11064     return(TNG_SUCCESS);
11065 }
11066
11067 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
11068                     (tng_trajectory_t tng_data,
11069                      const char *signature)
11070 {
11071     unsigned int len;
11072
11073     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11074     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11075
11076     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11077
11078     /* If the currently stored string length is not enough to store the new
11079      * string it is freed and reallocated. */
11080     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
11081         len)
11082     {
11083         free(tng_data->last_pgp_signature);
11084         tng_data->last_pgp_signature = 0;
11085     }
11086     if(!tng_data->last_pgp_signature)
11087     {
11088         tng_data->last_pgp_signature = malloc(len);
11089         if(!tng_data->last_pgp_signature)
11090         {
11091             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11092                    __FILE__, __LINE__);
11093             return(TNG_CRITICAL);
11094         }
11095     }
11096
11097     strncpy(tng_data->last_pgp_signature, signature, len);
11098
11099     return(TNG_SUCCESS);
11100 }
11101
11102 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
11103                     (const tng_trajectory_t tng_data,
11104                      char *name, const int max_len)
11105 {
11106     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11107     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
11108
11109     strncpy(name, tng_data->forcefield_name, max_len - 1);
11110     name[max_len - 1] = 0;
11111
11112     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
11113     {
11114         return(TNG_FAILURE);
11115     }
11116     return(TNG_SUCCESS);
11117 }
11118
11119 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
11120                     (tng_trajectory_t tng_data,
11121                      const char *new_name)
11122 {
11123     unsigned int len;
11124
11125     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11126     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
11127
11128     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11129
11130     /* If the currently stored string length is not enough to store the new
11131      * string it is freed and reallocated. */
11132     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
11133     {
11134         free(tng_data->forcefield_name);
11135         tng_data->forcefield_name = 0;
11136     }
11137     if(!tng_data->forcefield_name)
11138     {
11139         tng_data->forcefield_name = malloc(len);
11140         if(!tng_data->forcefield_name)
11141         {
11142             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11143                    __FILE__, __LINE__);
11144             return(TNG_CRITICAL);
11145         }
11146     }
11147
11148     strncpy(tng_data->forcefield_name, new_name, len);
11149
11150     return(TNG_SUCCESS);
11151 }
11152
11153 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
11154                     (const tng_trajectory_t tng_data,
11155                      int64_t *len)
11156 {
11157     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11158     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11159
11160     *len = tng_data->medium_stride_length;
11161
11162     return(TNG_SUCCESS);
11163 }
11164
11165 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
11166                     (tng_trajectory_t tng_data,
11167                      const int64_t len)
11168 {
11169     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11170
11171     if(len >= tng_data->long_stride_length)
11172     {
11173         return(TNG_FAILURE);
11174     }
11175     tng_data->medium_stride_length = len;
11176
11177     return(TNG_SUCCESS);
11178 }
11179
11180 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
11181                 (const tng_trajectory_t tng_data,
11182                  int64_t *len)
11183 {
11184     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11185     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11186
11187     *len = tng_data->long_stride_length;
11188
11189     return(TNG_SUCCESS);
11190 }
11191
11192 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
11193                 (tng_trajectory_t tng_data,
11194                  const int64_t len)
11195 {
11196     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11197
11198     if(len <= tng_data->medium_stride_length)
11199     {
11200         return(TNG_FAILURE);
11201     }
11202     tng_data->long_stride_length = len;
11203
11204     return(TNG_SUCCESS);
11205 }
11206
11207 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
11208                 (const tng_trajectory_t tng_data,
11209                  double *time)
11210 {
11211     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11212     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
11213
11214     *time = tng_data->time_per_frame;
11215
11216     return(TNG_SUCCESS);
11217 }
11218
11219 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
11220                 (tng_trajectory_t tng_data,
11221                  const double time)
11222 {
11223     tng_trajectory_frame_set_t frame_set;
11224
11225     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11226     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
11227
11228     if(fabs(time - tng_data->time_per_frame) < 0.00001)
11229     {
11230         return(TNG_SUCCESS);
11231     }
11232
11233     frame_set = &tng_data->current_trajectory_frame_set;
11234
11235     /* If the current frame set is not finished write it to disk before
11236        changing time per frame. */
11237     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
11238     {
11239         frame_set->n_frames = frame_set->n_unwritten_frames;
11240         tng_frame_set_write(tng_data, TNG_USE_HASH);
11241     }
11242     tng_data->time_per_frame = time;
11243
11244     return(TNG_SUCCESS);
11245 }
11246
11247 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
11248                     (const tng_trajectory_t tng_data,
11249                      int64_t *len)
11250 {
11251     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11252     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11253
11254     *len = tng_data->input_file_len;
11255
11256     return(TNG_SUCCESS);
11257 }
11258
11259 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
11260                     (const tng_trajectory_t tng_data,
11261                      int64_t *n)
11262 {
11263     tng_gen_block_t block;
11264     tng_function_status stat;
11265     int64_t file_pos, last_file_pos, first_frame, n_frames;
11266
11267     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11268     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
11269     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11270
11271     file_pos = ftello(tng_data->input_file);
11272     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11273
11274     if(last_file_pos <= 0)
11275     {
11276         return(TNG_FAILURE);
11277     }
11278
11279     tng_block_init(&block);
11280     fseeko(tng_data->input_file,
11281            last_file_pos,
11282            SEEK_SET);
11283     /* Read block headers first to see that a frame set block is found. */
11284     stat = tng_block_header_read(tng_data, block);
11285     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11286     {
11287         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
11288                 __FILE__, __LINE__);
11289         tng_block_destroy(&block);
11290         return(TNG_FAILURE);
11291     }
11292     tng_block_destroy(&block);
11293
11294     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
11295     {
11296         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
11297                __FILE__, __LINE__);
11298         return(TNG_CRITICAL);
11299     }
11300     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
11301     {
11302         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
11303                __FILE__, __LINE__);
11304         return(TNG_CRITICAL);
11305     }
11306     fseeko(tng_data->input_file, file_pos, SEEK_SET);
11307
11308     *n = first_frame + n_frames;
11309
11310     return(TNG_SUCCESS);
11311 }
11312
11313 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
11314                 (const tng_trajectory_t tng_data,
11315                  double *precision)
11316 {
11317     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11318
11319     *precision = tng_data->compression_precision;
11320
11321     return(TNG_SUCCESS);
11322 }
11323
11324 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
11325                 (tng_trajectory_t tng_data,
11326                  const double precision)
11327 {
11328     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11329
11330     tng_data->compression_precision = precision;
11331
11332     return(TNG_SUCCESS);
11333 }
11334
11335 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
11336                 (tng_trajectory_t tng_data,
11337                  const int64_t n)
11338 {
11339     tng_molecule_t mol;
11340     tng_chain_t chain;
11341     tng_residue_t res;
11342     tng_atom_t atom;
11343     tng_function_status stat;
11344     int64_t diff, n_mod, n_impl;
11345
11346     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
11347
11348     diff = n - tng_data->n_particles;
11349
11350     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
11351     if(stat == TNG_SUCCESS)
11352     {
11353         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
11354         {
11355             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
11356                     __FILE__, __LINE__);
11357             return(TNG_FAILURE);
11358         }
11359         diff -= n_impl * mol->n_atoms;
11360     }
11361
11362     if(diff == 0)
11363     {
11364         if(stat == TNG_SUCCESS)
11365         {
11366             stat = tng_molecule_cnt_set(tng_data, mol, 0);
11367             return(stat);
11368         }
11369         return(TNG_SUCCESS);
11370     }
11371     else if(diff < 0)
11372     {
11373         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
11374         fprintf(stderr, "particle count.\n");
11375         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11376                 __FILE__, __LINE__);
11377         /* FIXME: Should we set the count of all other molecules to 0 and add
11378          * implicit molecules? */
11379         return(TNG_FAILURE);
11380     }
11381     if(stat != TNG_SUCCESS)
11382     {
11383         stat = tng_molecule_add(tng_data,
11384                                 "TNG_IMPLICIT_MOL",
11385                                 &mol);
11386         if(stat != TNG_SUCCESS)
11387         {
11388             return(stat);
11389         }
11390         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
11391         if(stat != TNG_SUCCESS)
11392         {
11393             return(stat);
11394         }
11395         stat = tng_chain_residue_add(tng_data, chain, "", &res);
11396         if(stat != TNG_SUCCESS)
11397         {
11398             return(stat);
11399         }
11400         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
11401         if(stat != TNG_SUCCESS)
11402         {
11403             return(stat);
11404         }
11405     }
11406     else
11407     {
11408         if(mol->n_atoms > 1)
11409         {
11410             n_mod = diff % mol->n_atoms;
11411             if(n_mod != 0)
11412             {
11413                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
11414                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
11415                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11416                         __FILE__, __LINE__);
11417                 return(TNG_FAILURE);
11418             }
11419             diff /= mol->n_atoms;
11420         }
11421     }
11422     stat = tng_molecule_cnt_set(tng_data, mol, diff);
11423
11424     return(stat);
11425 }
11426
11427 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
11428                 (const tng_trajectory_t tng_data,
11429                  int64_t *n)
11430 {
11431     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11432     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11433
11434     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
11435     {
11436         *n = tng_data->n_particles;
11437     }
11438     else
11439     {
11440         *n = tng_data->current_trajectory_frame_set.n_particles;
11441     }
11442
11443     return(TNG_SUCCESS);
11444 }
11445
11446 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
11447                 (const tng_trajectory_t tng_data,
11448                  char *variable)
11449 {
11450     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11451     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
11452
11453     *variable = tng_data->var_num_atoms_flag;
11454
11455     return(TNG_SUCCESS);
11456 }
11457
11458 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
11459                     (const tng_trajectory_t tng_data,
11460                      int64_t *n)
11461 {
11462     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11463     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11464
11465     *n = tng_data->n_molecules;
11466
11467     return(TNG_SUCCESS);
11468 }
11469
11470 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
11471                     (const tng_trajectory_t tng_data,
11472                      int64_t *n)
11473 {
11474     int64_t *cnt_list = 0, cnt = 0, i;
11475
11476     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11477     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11478
11479     tng_molecule_cnt_list_get(tng_data, &cnt_list);
11480
11481     if(!cnt_list)
11482     {
11483         return(TNG_FAILURE);
11484     }
11485
11486     for(i = 0; i < tng_data->n_molecules; i++)
11487     {
11488         cnt += cnt_list[i];
11489     }
11490
11491     *n = cnt;
11492
11493     return(TNG_SUCCESS);
11494 }
11495
11496 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
11497                 (const tng_trajectory_t tng_data,
11498                  int64_t **mol_cnt_list)
11499 {
11500     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11501
11502     if(tng_data->var_num_atoms_flag)
11503     {
11504         *mol_cnt_list = tng_data->current_trajectory_frame_set.
11505                        molecule_cnt_list;
11506     }
11507     else
11508     {
11509         *mol_cnt_list = tng_data->molecule_cnt_list;
11510     }
11511     if(*mol_cnt_list == 0)
11512     {
11513         return(TNG_FAILURE);
11514     }
11515     return(TNG_SUCCESS);
11516 }
11517
11518 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
11519                 (const tng_trajectory_t tng_data,
11520                  int64_t *exp)
11521 {
11522     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11523     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
11524
11525     *exp = tng_data->distance_unit_exponential;
11526
11527     return(TNG_SUCCESS);
11528 }
11529
11530 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
11531                 (const tng_trajectory_t tng_data,
11532                  const int64_t exp)
11533 {
11534     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11535
11536     tng_data->distance_unit_exponential = exp;
11537
11538     return(TNG_SUCCESS);
11539 }
11540
11541 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
11542                 (const tng_trajectory_t tng_data,
11543                  int64_t *n)
11544 {
11545     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11546     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11547
11548     *n = tng_data->frame_set_n_frames;
11549
11550     return(TNG_SUCCESS);
11551 }
11552
11553 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
11554                 (const tng_trajectory_t tng_data,
11555                  const int64_t n)
11556 {
11557     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11558
11559     tng_data->frame_set_n_frames = n;
11560
11561     return(TNG_SUCCESS);
11562 }
11563
11564 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
11565                 (const tng_trajectory_t tng_data,
11566                  int64_t *n)
11567 {
11568     int64_t long_stride_length, medium_stride_length;
11569     int64_t file_pos, orig_frame_set_file_pos;
11570     tng_trajectory_frame_set_t frame_set;
11571     struct tng_trajectory_frame_set orig_frame_set;
11572     tng_gen_block_t block;
11573     tng_function_status stat;
11574     int64_t cnt = 0;
11575
11576     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11577     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11578
11579     orig_frame_set = tng_data->current_trajectory_frame_set;
11580
11581     frame_set = &tng_data->current_trajectory_frame_set;
11582
11583     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11584     file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11585
11586     if(file_pos < 0)
11587     {
11588         *n = tng_data->n_trajectory_frame_sets = cnt;
11589         return(TNG_SUCCESS);
11590     }
11591
11592     tng_block_init(&block);
11593     fseeko(tng_data->input_file,
11594           file_pos,
11595           SEEK_SET);
11596     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11597     /* Read block headers first to see what block is found. */
11598     stat = tng_block_header_read(tng_data, block);
11599     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11600     {
11601         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11602                 __FILE__, __LINE__);
11603         tng_block_destroy(&block);
11604         return(TNG_CRITICAL);
11605     }
11606
11607     if(tng_block_read_next(tng_data, block,
11608                         TNG_SKIP_HASH) != TNG_SUCCESS)
11609     {
11610         tng_block_destroy(&block);
11611         return(TNG_CRITICAL);
11612     }
11613
11614     ++cnt;
11615
11616     long_stride_length = tng_data->long_stride_length;
11617     medium_stride_length = tng_data->medium_stride_length;
11618
11619     /* Take long steps forward until a long step forward would be too long or
11620      * the last frame set is found */
11621     file_pos = frame_set->long_stride_next_frame_set_file_pos;
11622     while(file_pos > 0)
11623     {
11624         if(file_pos > 0)
11625         {
11626             cnt += long_stride_length;
11627             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11628             /* Read block headers first to see what block is found. */
11629             stat = tng_block_header_read(tng_data, block);
11630             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11631             {
11632                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11633                        file_pos, __FILE__, __LINE__);
11634                 tng_block_destroy(&block);
11635                 return(TNG_CRITICAL);
11636             }
11637
11638             if(tng_block_read_next(tng_data, block,
11639                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11640             {
11641                 tng_block_destroy(&block);
11642                 return(TNG_CRITICAL);
11643             }
11644         }
11645         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11646     }
11647
11648     /* Take medium steps forward until a medium step forward would be too long
11649      * or the last frame set is found */
11650     file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11651     while(file_pos > 0)
11652     {
11653         if(file_pos > 0)
11654         {
11655             cnt += medium_stride_length;
11656             fseeko(tng_data->input_file,
11657                   file_pos,
11658                   SEEK_SET);
11659             /* Read block headers first to see what block is found. */
11660             stat = tng_block_header_read(tng_data, block);
11661             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11662             {
11663                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11664                        file_pos, __FILE__, __LINE__);
11665                 tng_block_destroy(&block);
11666                 return(TNG_CRITICAL);
11667             }
11668
11669             if(tng_block_read_next(tng_data, block,
11670                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11671             {
11672                 tng_block_destroy(&block);
11673                 return(TNG_CRITICAL);
11674             }
11675         }
11676         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11677     }
11678
11679     /* Take one step forward until the last frame set is found */
11680     file_pos = frame_set->next_frame_set_file_pos;
11681     while(file_pos > 0)
11682     {
11683         if(file_pos > 0)
11684         {
11685             ++cnt;
11686             fseeko(tng_data->input_file,
11687                   file_pos,
11688                   SEEK_SET);
11689             /* Read block headers first to see what block is found. */
11690             stat = tng_block_header_read(tng_data, block);
11691             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11692             {
11693                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11694                        file_pos, __FILE__, __LINE__);
11695                 tng_block_destroy(&block);
11696                 return(TNG_CRITICAL);
11697             }
11698
11699             if(tng_block_read_next(tng_data, block,
11700                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11701             {
11702                 tng_block_destroy(&block);
11703                 return(TNG_CRITICAL);
11704             }
11705         }
11706         file_pos = frame_set->next_frame_set_file_pos;
11707     }
11708
11709     tng_block_destroy(&block);
11710
11711     *n = tng_data->n_trajectory_frame_sets = cnt;
11712
11713     *frame_set = orig_frame_set;
11714     /* The mapping block in the original frame set has been freed when reading
11715      * other frame sets. */
11716     frame_set->mappings = 0;
11717     frame_set->n_mapping_blocks = 0;
11718
11719     fseeko(tng_data->input_file,
11720            tng_data->first_trajectory_frame_set_input_file_pos,
11721            SEEK_SET);
11722
11723     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11724
11725     return(TNG_SUCCESS);
11726 }
11727
11728 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11729                 (const tng_trajectory_t tng_data,
11730                  tng_trajectory_frame_set_t *frame_set_p)
11731 {
11732     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11733
11734     *frame_set_p = &tng_data->current_trajectory_frame_set;
11735
11736     return(TNG_SUCCESS);
11737 }
11738
11739 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11740                 (tng_trajectory_t tng_data,
11741                  const int64_t nr)
11742 {
11743     int64_t long_stride_length, medium_stride_length;
11744     int64_t file_pos, curr_nr = 0, n_frame_sets;
11745     tng_trajectory_frame_set_t frame_set;
11746     tng_gen_block_t block;
11747     tng_function_status stat;
11748
11749     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11750     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11751
11752     frame_set = &tng_data->current_trajectory_frame_set;
11753
11754     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11755
11756     if(stat != TNG_SUCCESS)
11757     {
11758         return(stat);
11759     }
11760
11761     if(nr >= n_frame_sets)
11762     {
11763         return(TNG_FAILURE);
11764     }
11765
11766     long_stride_length = tng_data->long_stride_length;
11767     medium_stride_length = tng_data->medium_stride_length;
11768
11769     /* FIXME: The frame set number of the current frame set is not stored */
11770
11771     if(nr < n_frame_sets - 1 - nr)
11772     {
11773         /* Start from the beginning */
11774         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11775     }
11776     else
11777     {
11778         /* Start from the end */
11779         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11780         curr_nr = n_frame_sets - 1;
11781     }
11782     if(file_pos <= 0)
11783     {
11784         return(TNG_FAILURE);
11785     }
11786
11787     tng_block_init(&block);
11788     fseeko(tng_data->input_file,
11789            file_pos,
11790            SEEK_SET);
11791     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11792     /* Read block headers first to see what block is found. */
11793     stat = tng_block_header_read(tng_data, block);
11794     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11795     {
11796         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11797                 __FILE__, __LINE__);
11798         tng_block_destroy(&block);
11799         return(TNG_CRITICAL);
11800     }
11801
11802     if(tng_block_read_next(tng_data, block,
11803                         TNG_SKIP_HASH) != TNG_SUCCESS)
11804     {
11805         tng_block_destroy(&block);
11806         return(TNG_CRITICAL);
11807     }
11808
11809     if(curr_nr == nr)
11810     {
11811         tng_block_destroy(&block);
11812         return(TNG_SUCCESS);
11813     }
11814
11815     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11816
11817     /* Take long steps forward until a long step forward would be too long or
11818      * the right frame set is found */
11819     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11820     {
11821         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11822         if(file_pos > 0)
11823         {
11824             curr_nr += long_stride_length;
11825             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11826             /* Read block headers first to see what block is found. */
11827             stat = tng_block_header_read(tng_data, block);
11828             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11829             {
11830                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11831                        file_pos,  __FILE__, __LINE__);
11832                 tng_block_destroy(&block);
11833                 return(TNG_CRITICAL);
11834             }
11835
11836             if(tng_block_read_next(tng_data, block,
11837                                    TNG_SKIP_HASH) != TNG_SUCCESS)
11838             {
11839                 tng_block_destroy(&block);
11840                 return(TNG_CRITICAL);
11841             }
11842             if(curr_nr == nr)
11843             {
11844                 tng_block_destroy(&block);
11845                 return(TNG_SUCCESS);
11846             }
11847         }
11848     }
11849
11850     /* Take medium steps forward until a medium step forward would be too long
11851      * or the right frame set is found */
11852     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11853     {
11854         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11855         if(file_pos > 0)
11856         {
11857             curr_nr += medium_stride_length;
11858             fseeko(tng_data->input_file,
11859                    file_pos,
11860                    SEEK_SET);
11861             /* Read block headers first to see what block is found. */
11862             stat = tng_block_header_read(tng_data, block);
11863             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11864             {
11865                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11866                        file_pos, __FILE__, __LINE__);
11867                 tng_block_destroy(&block);
11868                 return(TNG_CRITICAL);
11869             }
11870
11871             if(tng_block_read_next(tng_data, block,
11872                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11873             {
11874                 tng_block_destroy(&block);
11875                 return(TNG_CRITICAL);
11876             }
11877             if(curr_nr == nr)
11878             {
11879                 tng_block_destroy(&block);
11880                 return(TNG_SUCCESS);
11881             }
11882         }
11883     }
11884
11885     /* Take one step forward until the right frame set is found */
11886     while(file_pos > 0 && curr_nr < nr)
11887     {
11888         file_pos = frame_set->next_frame_set_file_pos;
11889
11890         if(file_pos > 0)
11891         {
11892             ++curr_nr;
11893             fseeko(tng_data->input_file,
11894                    file_pos,
11895                    SEEK_SET);
11896             /* Read block headers first to see what block is found. */
11897             stat = tng_block_header_read(tng_data, block);
11898             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11899             {
11900                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11901                        file_pos, __FILE__, __LINE__);
11902                 tng_block_destroy(&block);
11903                 return(TNG_CRITICAL);
11904             }
11905
11906             if(tng_block_read_next(tng_data, block,
11907                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11908             {
11909                 tng_block_destroy(&block);
11910                 return(TNG_CRITICAL);
11911             }
11912             if(curr_nr == nr)
11913             {
11914                 tng_block_destroy(&block);
11915                 return(TNG_SUCCESS);
11916             }
11917         }
11918     }
11919
11920     /* Take long steps backward until a long step backward would be too long
11921      * or the right frame set is found */
11922     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11923     {
11924         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11925         if(file_pos > 0)
11926         {
11927             curr_nr -= long_stride_length;
11928             fseeko(tng_data->input_file,
11929                    file_pos,
11930                    SEEK_SET);
11931             /* Read block headers first to see what block is found. */
11932             stat = tng_block_header_read(tng_data, block);
11933             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11934             {
11935                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11936                        file_pos, __FILE__, __LINE__);
11937                 tng_block_destroy(&block);
11938                 return(TNG_CRITICAL);
11939             }
11940
11941             if(tng_block_read_next(tng_data, block,
11942                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11943             {
11944                 tng_block_destroy(&block);
11945                 return(TNG_CRITICAL);
11946             }
11947             if(curr_nr == nr)
11948             {
11949                 tng_block_destroy(&block);
11950                 return(TNG_SUCCESS);
11951             }
11952         }
11953     }
11954
11955     /* Take medium steps backward until a medium step backward would be too long
11956      * or the right frame set is found */
11957     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11958     {
11959         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11960         if(file_pos > 0)
11961         {
11962             curr_nr -= medium_stride_length;
11963             fseeko(tng_data->input_file,
11964                    file_pos,
11965                    SEEK_SET);
11966             /* Read block headers first to see what block is found. */
11967             stat = tng_block_header_read(tng_data, block);
11968             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11969             {
11970                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11971                        file_pos, __FILE__, __LINE__);
11972                 tng_block_destroy(&block);
11973                 return(TNG_CRITICAL);
11974             }
11975
11976             if(tng_block_read_next(tng_data, block,
11977                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11978             {
11979                 tng_block_destroy(&block);
11980                 return(TNG_CRITICAL);
11981             }
11982             if(curr_nr == nr)
11983             {
11984                 tng_block_destroy(&block);
11985                 return(TNG_SUCCESS);
11986             }
11987         }
11988     }
11989
11990     /* Take one step backward until the right frame set is found */
11991     while(file_pos > 0 && curr_nr > nr)
11992     {
11993         file_pos = frame_set->prev_frame_set_file_pos;
11994         if(file_pos > 0)
11995         {
11996             --curr_nr;
11997             fseeko(tng_data->input_file,
11998                    file_pos,
11999                    SEEK_SET);
12000             /* Read block headers first to see what block is found. */
12001             stat = tng_block_header_read(tng_data, block);
12002             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12003             {
12004                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12005                        file_pos, __FILE__, __LINE__);
12006                 tng_block_destroy(&block);
12007                 return(TNG_CRITICAL);
12008             }
12009
12010             if(tng_block_read_next(tng_data, block,
12011                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12012             {
12013                 tng_block_destroy(&block);
12014                 return(TNG_CRITICAL);
12015             }
12016             if(curr_nr == nr)
12017             {
12018                 tng_block_destroy(&block);
12019                 return(TNG_SUCCESS);
12020             }
12021         }
12022     }
12023
12024     /* If for some reason the current frame set is not yet found,
12025      * take one step forward until the right frame set is found */
12026     while(file_pos > 0 && curr_nr < nr)
12027     {
12028         file_pos = frame_set->next_frame_set_file_pos;
12029         if(file_pos > 0)
12030         {
12031             ++curr_nr;
12032             fseeko(tng_data->input_file,
12033                    file_pos,
12034                    SEEK_SET);
12035             /* Read block headers first to see what block is found. */
12036             stat = tng_block_header_read(tng_data, block);
12037             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12038             {
12039                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12040                        file_pos, __FILE__, __LINE__);
12041                 tng_block_destroy(&block);
12042                 return(TNG_CRITICAL);
12043             }
12044
12045             if(tng_block_read_next(tng_data, block,
12046                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12047             {
12048                 tng_block_destroy(&block);
12049                 return(TNG_CRITICAL);
12050             }
12051             if(curr_nr == nr)
12052             {
12053                 tng_block_destroy(&block);
12054                 return(TNG_SUCCESS);
12055             }
12056         }
12057     }
12058
12059     tng_block_destroy(&block);
12060     return(TNG_FAILURE);
12061 }
12062
12063 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
12064                 (tng_trajectory_t tng_data,
12065                  const int64_t frame)
12066 {
12067     int64_t first_frame, last_frame, n_frames_per_frame_set;
12068     int64_t long_stride_length, medium_stride_length;
12069     int64_t file_pos, temp_frame, n_frames;
12070     tng_trajectory_frame_set_t frame_set;
12071     tng_gen_block_t block;
12072     tng_function_status stat;
12073
12074     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12075     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
12076
12077     frame_set = &tng_data->current_trajectory_frame_set;
12078
12079     tng_block_init(&block);
12080
12081     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
12082     {
12083         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12084         fseeko(tng_data->input_file,
12085                file_pos,
12086                SEEK_SET);
12087         tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12088         /* Read block headers first to see what block is found. */
12089         stat = tng_block_header_read(tng_data, block);
12090         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12091         {
12092             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12093                     file_pos, __FILE__, __LINE__);
12094             tng_block_destroy(&block);
12095             return(TNG_CRITICAL);
12096         }
12097
12098         if(tng_block_read_next(tng_data, block,
12099                             TNG_SKIP_HASH) != TNG_SUCCESS)
12100         {
12101             tng_block_destroy(&block);
12102             return(TNG_CRITICAL);
12103         }
12104     }
12105
12106     first_frame = tng_max_i64(frame_set->first_frame, 0);
12107     last_frame = first_frame + frame_set->n_frames - 1;
12108     /* Is this the right frame set? */
12109     if(first_frame <= frame && frame <= last_frame)
12110     {
12111         tng_block_destroy(&block);
12112         return(TNG_SUCCESS);
12113     }
12114
12115     n_frames_per_frame_set = tng_data->frame_set_n_frames;
12116     long_stride_length = tng_data->long_stride_length;
12117     medium_stride_length = tng_data->medium_stride_length;
12118
12119     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
12120        TNG_SUCCESS)
12121     {
12122         if(temp_frame - first_frame > n_frames_per_frame_set)
12123         {
12124             n_frames_per_frame_set = temp_frame - first_frame;
12125         }
12126     }
12127
12128     tng_num_frames_get(tng_data, &n_frames);
12129
12130     if(frame >= n_frames)
12131     {
12132         tng_block_destroy(&block);
12133         return(TNG_FAILURE);
12134     }
12135
12136     if(first_frame - frame >= frame ||
12137        frame - last_frame >
12138        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
12139     {
12140         /* Start from the beginning */
12141         if(first_frame - frame >= frame)
12142         {
12143             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12144
12145             if(file_pos <= 0)
12146             {
12147                 tng_block_destroy(&block);
12148                 return(TNG_FAILURE);
12149             }
12150         }
12151         /* Start from the end */
12152         else if(frame - first_frame > (n_frames - 1) - frame)
12153         {
12154             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
12155
12156             /* If the last frame set position is not set start from the current
12157              * frame set, since it will be closer than the first frame set. */
12158         }
12159         /* Start from current */
12160         else
12161         {
12162             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12163         }
12164
12165         if(file_pos > 0)
12166         {
12167             fseeko(tng_data->input_file,
12168                    file_pos,
12169                    SEEK_SET);
12170             tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12171             /* Read block headers first to see what block is found. */
12172             stat = tng_block_header_read(tng_data, block);
12173             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12174             {
12175                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12176                        file_pos, __FILE__, __LINE__);
12177                 tng_block_destroy(&block);
12178                 return(TNG_CRITICAL);
12179             }
12180
12181             if(tng_block_read_next(tng_data, block,
12182                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12183             {
12184                 tng_block_destroy(&block);
12185                 return(TNG_CRITICAL);
12186             }
12187         }
12188     }
12189
12190     first_frame = tng_max_i64(frame_set->first_frame, 0);
12191     last_frame = first_frame + frame_set->n_frames - 1;
12192
12193     if(frame >= first_frame && frame <= last_frame)
12194     {
12195         tng_block_destroy(&block);
12196         return(TNG_SUCCESS);
12197     }
12198
12199     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12200
12201     /* Take long steps forward until a long step forward would be too long or
12202      * the right frame set is found */
12203     while(file_pos > 0 && first_frame + long_stride_length *
12204           n_frames_per_frame_set <= frame)
12205     {
12206         file_pos = frame_set->long_stride_next_frame_set_file_pos;
12207         if(file_pos > 0)
12208         {
12209             fseeko(tng_data->input_file, file_pos, SEEK_SET);
12210             /* Read block headers first to see what block is found. */
12211             stat = tng_block_header_read(tng_data, block);
12212             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12213             {
12214                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12215                        file_pos, __FILE__, __LINE__);
12216                 tng_block_destroy(&block);
12217                 return(TNG_CRITICAL);
12218             }
12219
12220             if(tng_block_read_next(tng_data, block,
12221                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12222             {
12223                 tng_block_destroy(&block);
12224                 return(TNG_CRITICAL);
12225             }
12226         }
12227         first_frame = tng_max_i64(frame_set->first_frame, 0);
12228         last_frame = first_frame + frame_set->n_frames - 1;
12229         if(frame >= first_frame && frame <= last_frame)
12230         {
12231             tng_block_destroy(&block);
12232             return(TNG_SUCCESS);
12233         }
12234     }
12235
12236     /* Take medium steps forward until a medium step forward would be too long
12237      * or the right frame set is found */
12238     while(file_pos > 0 && first_frame + medium_stride_length *
12239           n_frames_per_frame_set <= frame)
12240     {
12241         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
12242         if(file_pos > 0)
12243         {
12244             fseeko(tng_data->input_file,
12245                    file_pos,
12246                    SEEK_SET);
12247             /* Read block headers first to see what block is found. */
12248             stat = tng_block_header_read(tng_data, block);
12249             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12250             {
12251                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12252                        file_pos, __FILE__, __LINE__);
12253                 tng_block_destroy(&block);
12254                 return(TNG_CRITICAL);
12255             }
12256
12257             if(tng_block_read_next(tng_data, block,
12258                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12259             {
12260                 tng_block_destroy(&block);
12261                 return(TNG_CRITICAL);
12262             }
12263         }
12264         first_frame = tng_max_i64(frame_set->first_frame, 0);
12265         last_frame = first_frame + frame_set->n_frames - 1;
12266         if(frame >= first_frame && frame <= last_frame)
12267         {
12268             tng_block_destroy(&block);
12269             return(TNG_SUCCESS);
12270         }
12271     }
12272
12273     /* Take one step forward until the right frame set is found */
12274     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12275     {
12276         file_pos = frame_set->next_frame_set_file_pos;
12277         if(file_pos > 0)
12278         {
12279             fseeko(tng_data->input_file,
12280                    file_pos,
12281                    SEEK_SET);
12282             /* Read block headers first to see what block is found. */
12283             stat = tng_block_header_read(tng_data, block);
12284             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12285             {
12286                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12287                        file_pos, __FILE__, __LINE__);
12288                 tng_block_destroy(&block);
12289                 return(TNG_CRITICAL);
12290             }
12291
12292             if(tng_block_read_next(tng_data, block,
12293                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12294             {
12295                 tng_block_destroy(&block);
12296                 return(TNG_CRITICAL);
12297             }
12298         }
12299         first_frame = tng_max_i64(frame_set->first_frame, 0);
12300         last_frame = first_frame + frame_set->n_frames - 1;
12301         if(frame >= first_frame && frame <= last_frame)
12302         {
12303             tng_block_destroy(&block);
12304             return(TNG_SUCCESS);
12305         }
12306     }
12307
12308     /* Take long steps backward until a long step backward would be too long
12309      * or the right frame set is found */
12310     while(file_pos > 0 && first_frame - long_stride_length *
12311           n_frames_per_frame_set >= frame)
12312     {
12313         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
12314         if(file_pos > 0)
12315         {
12316             fseeko(tng_data->input_file,
12317                    file_pos,
12318                    SEEK_SET);
12319             /* Read block headers first to see what block is found. */
12320             stat = tng_block_header_read(tng_data, block);
12321             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12322             {
12323                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12324                        file_pos, __FILE__, __LINE__);
12325                 tng_block_destroy(&block);
12326                 return(TNG_CRITICAL);
12327             }
12328
12329             if(tng_block_read_next(tng_data, block,
12330                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12331             {
12332                 tng_block_destroy(&block);
12333                 return(TNG_CRITICAL);
12334             }
12335         }
12336         first_frame = tng_max_i64(frame_set->first_frame, 0);
12337         last_frame = first_frame + frame_set->n_frames - 1;
12338         if(frame >= first_frame && frame <= last_frame)
12339         {
12340             tng_block_destroy(&block);
12341             return(TNG_SUCCESS);
12342         }
12343     }
12344
12345     /* Take medium steps backward until a medium step backward would be too long
12346      * or the right frame set is found */
12347     while(file_pos > 0 && first_frame - medium_stride_length *
12348           n_frames_per_frame_set >= frame)
12349     {
12350         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
12351         if(file_pos > 0)
12352         {
12353             fseeko(tng_data->input_file,
12354                    file_pos,
12355                    SEEK_SET);
12356             /* Read block headers first to see what block is found. */
12357             stat = tng_block_header_read(tng_data, block);
12358             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12359             {
12360                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12361                        file_pos, __FILE__, __LINE__);
12362                 tng_block_destroy(&block);
12363                 return(TNG_CRITICAL);
12364             }
12365
12366             if(tng_block_read_next(tng_data, block,
12367                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12368             {
12369                 tng_block_destroy(&block);
12370                 return(TNG_CRITICAL);
12371             }
12372         }
12373         first_frame = tng_max_i64(frame_set->first_frame, 0);
12374         last_frame = first_frame + frame_set->n_frames - 1;
12375         if(frame >= first_frame && frame <= last_frame)
12376         {
12377             tng_block_destroy(&block);
12378             return(TNG_SUCCESS);
12379         }
12380     }
12381
12382     /* Take one step backward until the right frame set is found */
12383     while(file_pos > 0 && first_frame > frame && last_frame > frame)
12384     {
12385         file_pos = frame_set->prev_frame_set_file_pos;
12386         if(file_pos > 0)
12387         {
12388             fseeko(tng_data->input_file,
12389                    file_pos,
12390                    SEEK_SET);
12391             /* Read block headers first to see what block is found. */
12392             stat = tng_block_header_read(tng_data, block);
12393             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12394             {
12395                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12396                        file_pos, __FILE__, __LINE__);
12397                 tng_block_destroy(&block);
12398                 return(TNG_CRITICAL);
12399             }
12400
12401             if(tng_block_read_next(tng_data, block,
12402                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12403             {
12404                 tng_block_destroy(&block);
12405                 return(TNG_CRITICAL);
12406             }
12407         }
12408         first_frame = tng_max_i64(frame_set->first_frame, 0);
12409         last_frame = first_frame + frame_set->n_frames - 1;
12410         if(frame >= first_frame && frame <= last_frame)
12411         {
12412             tng_block_destroy(&block);
12413             return(TNG_SUCCESS);
12414         }
12415     }
12416
12417     /* If for some reason the current frame set is not yet found,
12418      * take one step forward until the right frame set is found */
12419     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12420     {
12421         file_pos = frame_set->next_frame_set_file_pos;
12422         if(file_pos > 0)
12423         {
12424             fseeko(tng_data->input_file,
12425                    file_pos,
12426                    SEEK_SET);
12427             /* Read block headers first to see what block is found. */
12428             stat = tng_block_header_read(tng_data, block);
12429             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12430             {
12431                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12432                        file_pos, __FILE__, __LINE__);
12433                 tng_block_destroy(&block);
12434                 return(TNG_CRITICAL);
12435             }
12436
12437             if(tng_block_read_next(tng_data, block,
12438                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12439             {
12440                 tng_block_destroy(&block);
12441                 return(TNG_CRITICAL);
12442             }
12443         }
12444         first_frame = tng_max_i64(frame_set->first_frame, 0);
12445         last_frame = first_frame + frame_set->n_frames - 1;
12446         if(frame >= first_frame && frame <= last_frame)
12447         {
12448             tng_block_destroy(&block);
12449             return(TNG_SUCCESS);
12450         }
12451     }
12452
12453     tng_block_destroy(&block);
12454     return(TNG_FAILURE);
12455 }
12456
12457 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
12458                 (const tng_trajectory_t tng_data,
12459                  const tng_trajectory_frame_set_t frame_set,
12460                  int64_t *pos)
12461 {
12462     (void)tng_data;
12463
12464     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12465     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12466
12467     *pos = frame_set->next_frame_set_file_pos;
12468
12469     return(TNG_SUCCESS);
12470 }
12471
12472 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
12473                 (const tng_trajectory_t tng_data,
12474                  const tng_trajectory_frame_set_t frame_set,
12475                  int64_t *pos)
12476 {
12477     (void)tng_data;
12478
12479     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12480     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12481
12482     *pos = frame_set->prev_frame_set_file_pos;
12483
12484     return(TNG_SUCCESS);
12485 }
12486
12487 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
12488                 (const tng_trajectory_t tng_data,
12489                  const tng_trajectory_frame_set_t frame_set,
12490                  int64_t *first_frame,
12491                  int64_t *last_frame)
12492 {
12493     (void)tng_data;
12494
12495     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
12496     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
12497     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
12498
12499     *first_frame = frame_set->first_frame;
12500     *last_frame = *first_frame + frame_set->n_frames - 1;
12501
12502     return(TNG_SUCCESS);
12503 }
12504
12505 /** Translate from the particle numbering used in a frame set to the real
12506  *  particle numbering - used in the molecule description.
12507  * @param frame_set is the frame_set containing the mappings to use.
12508  * @param local is the index number of the atom in this frame set
12509  * @param real is set to the index of the atom in the molecular system.
12510  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12511  * cannot be found.
12512  */
12513 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
12514                 (const tng_trajectory_frame_set_t frame_set,
12515                  const int64_t local,
12516                  int64_t *real)
12517 {
12518     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
12519     tng_particle_mapping_t mapping;
12520     if(n_blocks <= 0)
12521     {
12522         *real = local;
12523         return(TNG_SUCCESS);
12524     }
12525     for(i = 0; i < n_blocks; i++)
12526     {
12527         mapping = &frame_set->mappings[i];
12528         first = mapping->num_first_particle;
12529         if(local < first ||
12530            local >= first + mapping->n_particles)
12531         {
12532             continue;
12533         }
12534         *real = mapping->real_particle_numbers[local-first];
12535         return(TNG_SUCCESS);
12536     }
12537     *real = local;
12538     return(TNG_FAILURE);
12539 }
12540
12541 /** Translate from the real particle numbering to the particle numbering
12542  *  used in a frame set.
12543  * @param frame_set is the frame_set containing the mappings to use.
12544  * @param real is the index number of the atom in the molecular system.
12545  * @param local is set to the index of the atom in this frame set.
12546  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12547  * cannot be found.
12548  */
12549 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
12550                 (const tng_trajectory_frame_set_t frame_set,
12551                  const int64_t real,
12552                  int64_t *local)
12553 {
12554     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
12555     tng_particle_mapping_t mapping;
12556     if(n_blocks <= 0)
12557     {
12558         *local = real;
12559         return(TNG_SUCCESS);
12560     }
12561     for(i = 0; i < n_blocks; i++)
12562     {
12563         mapping = &frame_set->mappings[i];
12564         for(j = mapping->n_particles; j--;)
12565         {
12566             if(mapping->real_particle_numbers[j] == real)
12567             {
12568                 *local = j;
12569                 return(TNG_SUCCESS);
12570             }
12571         }
12572     }
12573     return(TNG_FAILURE);
12574 }
12575 */
12576
12577 static tng_function_status tng_file_headers_len_get
12578                 (tng_trajectory_t tng_data,
12579                  int64_t *len)
12580 {
12581     int64_t orig_pos;
12582     tng_gen_block_t block;
12583
12584     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12585
12586     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12587     {
12588         return(TNG_CRITICAL);
12589     }
12590
12591     *len = 0;
12592
12593     orig_pos = ftello(tng_data->input_file);
12594
12595     if(!tng_data->input_file_len)
12596     {
12597         fseeko(tng_data->input_file, 0, SEEK_END);
12598         tng_data->input_file_len = ftello(tng_data->input_file);
12599     }
12600     fseeko(tng_data->input_file, 0, SEEK_SET);
12601
12602     tng_block_init(&block);
12603     /* Read through the headers of non-trajectory blocks (they come before the
12604      * trajectory blocks in the file) */
12605     while (*len < tng_data->input_file_len &&
12606            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12607            block->id != -1 &&
12608            block->id != TNG_TRAJECTORY_FRAME_SET)
12609     {
12610         *len += block->header_contents_size + block->block_contents_size;
12611         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12612     }
12613
12614     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
12615
12616     tng_block_destroy(&block);
12617
12618     return(TNG_SUCCESS);
12619 }
12620
12621 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
12622                 (tng_trajectory_t tng_data,
12623                  const char hash_mode)
12624 {
12625     int64_t prev_pos = 0;
12626     tng_gen_block_t block;
12627
12628     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12629
12630     tng_data->n_trajectory_frame_sets = 0;
12631
12632     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12633     {
12634         return(TNG_CRITICAL);
12635     }
12636
12637     if(!tng_data->input_file_len)
12638     {
12639         fseeko(tng_data->input_file, 0, SEEK_END);
12640         tng_data->input_file_len = ftello(tng_data->input_file);
12641     }
12642     fseeko(tng_data->input_file, 0, SEEK_SET);
12643
12644     tng_block_init(&block);
12645     /* Non trajectory blocks (they come before the trajectory
12646      * blocks in the file) */
12647     while (prev_pos < tng_data->input_file_len &&
12648            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12649            block->id != -1 &&
12650            block->id != TNG_TRAJECTORY_FRAME_SET)
12651     {
12652         tng_block_read_next(tng_data, block, hash_mode);
12653         prev_pos = ftello(tng_data->input_file);
12654     }
12655
12656     /* Go back if a trajectory block was encountered */
12657     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12658     {
12659         fseeko(tng_data->input_file, prev_pos, SEEK_SET);
12660     }
12661
12662     tng_block_destroy(&block);
12663
12664     return(TNG_SUCCESS);
12665 }
12666
12667 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
12668                 (tng_trajectory_t tng_data,
12669                  const char hash_mode)
12670 {
12671     int i;
12672     int64_t len, orig_len, tot_len = 0, data_start_pos;
12673     tng_function_status stat;
12674     tng_gen_block_t block;
12675
12676     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12677
12678     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
12679     {
12680         return(TNG_CRITICAL);
12681     }
12682
12683     if(tng_data->n_trajectory_frame_sets > 0)
12684     {
12685         stat = tng_file_headers_len_get(tng_data, &orig_len);
12686         if(stat != TNG_SUCCESS)
12687         {
12688             return(stat);
12689         }
12690
12691         tng_block_init(&block);
12692         block->name = malloc(TNG_MAX_STR_LEN);
12693         if(!block->name)
12694         {
12695             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12696                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
12697             tng_block_destroy(&block);
12698             return(TNG_CRITICAL);
12699         }
12700         strcpy(block->name, "GENERAL INFO");
12701         tng_block_header_len_calculate(tng_data, block, &len);
12702         tot_len += len;
12703         tng_general_info_block_len_calculate(tng_data, &len);
12704         tot_len += len;
12705         strcpy(block->name, "MOLECULES");
12706         tng_block_header_len_calculate(tng_data, block, &len);
12707         tot_len += len;
12708         tng_molecules_block_len_calculate(tng_data, &len);
12709         tot_len += len;
12710
12711         for(i = 0; i < tng_data->n_data_blocks; i++)
12712         {
12713             strcpy(block->name, tng_data->non_tr_data[i].block_name);
12714             tng_block_header_len_calculate(tng_data, block, &len);
12715             tot_len += len;
12716             tng_data_block_len_calculate(tng_data,
12717                                         (tng_particle_data_t)&tng_data->non_tr_data[i],
12718                                         TNG_FALSE, 1, 1, 1, 0,
12719                                         1, 0, &data_start_pos,
12720                                         &len);
12721             tot_len += len;
12722         }
12723         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12724         {
12725             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
12726             tng_block_header_len_calculate(tng_data, block, &len);
12727             tot_len += len;
12728             tng_data_block_len_calculate(tng_data,
12729                                         &tng_data->non_tr_particle_data[i],
12730                                         TNG_TRUE, 1, 1, 1, 0,
12731                                         tng_data->n_particles, TNG_PARTICLE_DEPENDENT,
12732                                         &data_start_pos,
12733                                         &len);
12734             tot_len += len;
12735         }
12736         tng_block_destroy(&block);
12737
12738         if(tot_len > orig_len)
12739         {
12740             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len);
12741         }
12742
12743         tng_data->current_trajectory_frame_set_output_file_pos = -1;
12744     }
12745
12746     /* TODO: If there is already frame set data written to this file (e.g. when
12747      * appending to an already existing file we might need to move frame sets to
12748      * the end of the file. */
12749
12750     if(tng_general_info_block_write(tng_data, hash_mode)
12751        != TNG_SUCCESS)
12752     {
12753         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
12754                 tng_data->input_file_path, __FILE__, __LINE__);
12755         return(TNG_CRITICAL);
12756     }
12757
12758     if(tng_molecules_block_write(tng_data, hash_mode)
12759         != TNG_SUCCESS)
12760     {
12761         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
12762                 tng_data->input_file_path, __FILE__, __LINE__);
12763         return(TNG_CRITICAL);
12764     }
12765
12766     /* FIXME: Currently writing non-trajectory data blocks here.
12767      * Should perhaps be moved. */
12768     tng_block_init(&block);
12769     for(i = 0; i < tng_data->n_data_blocks; i++)
12770     {
12771         block->id = tng_data->non_tr_data[i].block_id;
12772         tng_data_block_write(tng_data, block,
12773                              i, hash_mode);
12774     }
12775
12776     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12777     {
12778         block->id = tng_data->non_tr_particle_data[i].block_id;
12779         tng_particle_data_block_write(tng_data, block,
12780                                       i, 0, hash_mode);
12781     }
12782
12783     tng_block_destroy(&block);
12784
12785     return(TNG_SUCCESS);
12786 }
12787
12788 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12789                                         tng_gen_block_t block,
12790                                         const char hash_mode)
12791 {
12792     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12793     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12794
12795     switch(block->id)
12796     {
12797     case TNG_TRAJECTORY_FRAME_SET:
12798         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12799     case TNG_PARTICLE_MAPPING:
12800         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12801     case TNG_GENERAL_INFO:
12802         return(tng_general_info_block_read(tng_data, block, hash_mode));
12803     case TNG_MOLECULES:
12804         return(tng_molecules_block_read(tng_data, block, hash_mode));
12805     default:
12806         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12807         {
12808             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12809         }
12810         else
12811         {
12812             /* Skip to the next block */
12813             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12814             return(TNG_FAILURE);
12815         }
12816     }
12817 }
12818
12819 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12820                 (tng_trajectory_t tng_data,
12821                  const char hash_mode)
12822 {
12823     int64_t file_pos;
12824     tng_gen_block_t block;
12825     tng_function_status stat;
12826
12827     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12828
12829     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12830     {
12831         return(TNG_CRITICAL);
12832     }
12833
12834     file_pos = ftello(tng_data->input_file);
12835
12836     tng_block_init(&block);
12837
12838     if(!tng_data->input_file_len)
12839     {
12840         fseeko(tng_data->input_file, 0, SEEK_END);
12841         tng_data->input_file_len = ftello(tng_data->input_file);
12842         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12843     }
12844
12845     /* Read block headers first to see what block is found. */
12846     stat = tng_block_header_read(tng_data, block);
12847     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
12848        block->id == -1)
12849     {
12850         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12851                file_pos, __FILE__, __LINE__);
12852         tng_block_destroy(&block);
12853         return(TNG_CRITICAL);
12854     }
12855
12856     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12857
12858     if(tng_block_read_next(tng_data, block,
12859                            hash_mode) == TNG_SUCCESS)
12860     {
12861         tng_data->n_trajectory_frame_sets++;
12862         file_pos = ftello(tng_data->input_file);
12863         /* Read all blocks until next frame set block */
12864         stat = tng_block_header_read(tng_data, block);
12865         while(file_pos < tng_data->input_file_len &&
12866               stat != TNG_CRITICAL &&
12867               block->id != TNG_TRAJECTORY_FRAME_SET &&
12868               block->id != -1)
12869         {
12870             stat = tng_block_read_next(tng_data, block,
12871                                        hash_mode);
12872             if(stat != TNG_CRITICAL)
12873             {
12874                 file_pos = ftello(tng_data->input_file);
12875                 if(file_pos < tng_data->input_file_len)
12876                 {
12877                     stat = tng_block_header_read(tng_data, block);
12878                 }
12879             }
12880         }
12881         if(stat == TNG_CRITICAL)
12882         {
12883             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12884                    file_pos, __FILE__, __LINE__);
12885             tng_block_destroy(&block);
12886             return(stat);
12887         }
12888
12889         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12890         {
12891             fseeko(tng_data->input_file, file_pos, SEEK_SET);
12892         }
12893     }
12894
12895     tng_block_destroy(&block);
12896
12897     return(TNG_SUCCESS);
12898 }
12899
12900
12901 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12902                 (tng_trajectory_t tng_data,
12903                  const char hash_mode,
12904                  const int64_t block_id)
12905 {
12906     int64_t file_pos;
12907     tng_gen_block_t block;
12908     tng_function_status stat;
12909     int found_flag = 1;
12910
12911     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12912
12913     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12914     {
12915         return(TNG_CRITICAL);
12916     }
12917
12918     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12919
12920     if(file_pos < 0)
12921     {
12922         /* No current frame set. This means that the first frame set must be
12923          * read */
12924         found_flag = 0;
12925         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12926     }
12927
12928     if(file_pos > 0)
12929     {
12930         fseeko(tng_data->input_file,
12931               file_pos,
12932               SEEK_SET);
12933     }
12934     else
12935     {
12936         return(TNG_FAILURE);
12937     }
12938
12939     tng_block_init(&block);
12940
12941     if(!tng_data->input_file_len)
12942     {
12943         fseeko(tng_data->input_file, 0, SEEK_END);
12944         tng_data->input_file_len = ftello(tng_data->input_file);
12945         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12946     }
12947
12948     /* Read block headers first to see what block is found. */
12949     stat = tng_block_header_read(tng_data, block);
12950     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12951     {
12952         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12953                file_pos, __FILE__, __LINE__);
12954         tng_block_destroy(&block);
12955         return(TNG_CRITICAL);
12956     }
12957     /* If the current frame set had already been read skip its block contents */
12958     if(found_flag)
12959     {
12960         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12961     }
12962     /* Otherwiese read the frame set block */
12963     else
12964     {
12965         stat = tng_block_read_next(tng_data, block,
12966                                    hash_mode);
12967         if(stat != TNG_SUCCESS)
12968         {
12969             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12970             tng_block_destroy(&block);
12971             return(stat);
12972         }
12973     }
12974     file_pos = ftello(tng_data->input_file);
12975
12976     found_flag = 0;
12977
12978     /* Read only blocks of the requested ID
12979         * until next frame set block */
12980     stat = tng_block_header_read(tng_data, block);
12981     while(file_pos < tng_data->input_file_len &&
12982             stat != TNG_CRITICAL &&
12983             block->id != TNG_TRAJECTORY_FRAME_SET &&
12984             block->id != -1)
12985     {
12986         if(block->id == block_id)
12987         {
12988             stat = tng_block_read_next(tng_data, block,
12989                                        hash_mode);
12990             if(stat != TNG_CRITICAL)
12991             {
12992                 file_pos = ftello(tng_data->input_file);
12993                 found_flag = 1;
12994                 if(file_pos < tng_data->input_file_len)
12995                 {
12996                     stat = tng_block_header_read(tng_data, block);
12997                 }
12998             }
12999         }
13000         else
13001         {
13002             file_pos += (block->block_contents_size + block->header_contents_size);
13003             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
13004             if(file_pos < tng_data->input_file_len)
13005             {
13006                 stat = tng_block_header_read(tng_data, block);
13007             }
13008         }
13009     }
13010     if(stat == TNG_CRITICAL)
13011     {
13012         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13013                 file_pos, __FILE__, __LINE__);
13014         tng_block_destroy(&block);
13015         return(stat);
13016     }
13017
13018     if(block->id == TNG_TRAJECTORY_FRAME_SET)
13019     {
13020         fseeko(tng_data->input_file, file_pos, SEEK_SET);
13021     }
13022
13023     tng_block_destroy(&block);
13024
13025     if(found_flag)
13026     {
13027         return(TNG_SUCCESS);
13028     }
13029     else
13030     {
13031         return(TNG_FAILURE);
13032     }
13033 }
13034
13035 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
13036                 (tng_trajectory_t tng_data,
13037                  const char hash_mode)
13038 {
13039     int64_t file_pos;
13040
13041     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13042
13043     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13044     {
13045         return(TNG_CRITICAL);
13046     }
13047
13048     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13049
13050     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13051     {
13052         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13053     }
13054
13055     if(file_pos > 0)
13056     {
13057         fseeko(tng_data->input_file,
13058               file_pos,
13059               SEEK_SET);
13060     }
13061     else
13062     {
13063         return(TNG_FAILURE);
13064     }
13065
13066     return(tng_frame_set_read(tng_data, hash_mode));
13067 }
13068
13069 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
13070                 (tng_trajectory_t tng_data,
13071                  const char hash_mode,
13072                  const int64_t block_id)
13073 {
13074     int64_t file_pos;
13075     tng_gen_block_t block;
13076     tng_function_status stat;
13077
13078     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13079
13080     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13081     {
13082         return(TNG_CRITICAL);
13083     }
13084
13085     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13086
13087     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13088     {
13089         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13090     }
13091
13092     if(file_pos > 0)
13093     {
13094         fseeko(tng_data->input_file,
13095               file_pos,
13096               SEEK_SET);
13097     }
13098     else
13099     {
13100         return(TNG_FAILURE);
13101     }
13102
13103     tng_block_init(&block);
13104
13105     if(!tng_data->input_file_len)
13106     {
13107         fseeko(tng_data->input_file, 0, SEEK_END);
13108         tng_data->input_file_len = ftello(tng_data->input_file);
13109         fseeko(tng_data->input_file, file_pos, SEEK_SET);
13110     }
13111
13112     /* Read block headers first to see what block is found. */
13113     stat = tng_block_header_read(tng_data, block);
13114     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13115     {
13116         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13117                file_pos, __FILE__, __LINE__);
13118         tng_block_destroy(&block);
13119         return(TNG_CRITICAL);
13120     }
13121
13122     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
13123
13124     if(tng_block_read_next(tng_data, block,
13125                            hash_mode) == TNG_SUCCESS)
13126     {
13127         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
13128     }
13129
13130     tng_block_destroy(&block);
13131
13132     return(stat);
13133 }
13134
13135 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
13136                                         const char hash_mode)
13137 {
13138     int i, j;
13139     tng_gen_block_t block;
13140     tng_trajectory_frame_set_t frame_set;
13141     tng_function_status stat;
13142
13143     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13144
13145     frame_set = &tng_data->current_trajectory_frame_set;
13146
13147     if(frame_set->n_written_frames == frame_set->n_frames)
13148     {
13149         return(TNG_SUCCESS);
13150     }
13151
13152     tng_data->current_trajectory_frame_set_output_file_pos =
13153     ftello(tng_data->output_file);
13154     tng_data->last_trajectory_frame_set_output_file_pos =
13155     tng_data->current_trajectory_frame_set_output_file_pos;
13156
13157     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
13158     {
13159         return(TNG_FAILURE);
13160     }
13161
13162     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
13163     {
13164         tng_data->first_trajectory_frame_set_output_file_pos =
13165         tng_data->current_trajectory_frame_set_output_file_pos;
13166     }
13167
13168     tng_block_init(&block);
13169
13170     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
13171     {
13172         tng_block_destroy(&block);
13173         return(TNG_FAILURE);
13174     }
13175
13176     /* Write non-particle data blocks */
13177     for(i = 0; i<frame_set->n_data_blocks; i++)
13178     {
13179         block->id = frame_set->tr_data[i].block_id;
13180         tng_data_block_write(tng_data, block, i, hash_mode);
13181     }
13182     /* Write the mapping blocks and particle data blocks*/
13183     if(frame_set->n_mapping_blocks)
13184     {
13185         for(i = 0; i < frame_set->n_mapping_blocks; i++)
13186         {
13187             block->id = TNG_PARTICLE_MAPPING;
13188             if(frame_set->mappings[i].n_particles > 0)
13189             {
13190                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
13191                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
13192                 {
13193                     block->id = frame_set->tr_particle_data[j].block_id;
13194                     tng_particle_data_block_write(tng_data, block,
13195                                                   j, &frame_set->mappings[i],
13196                                                   hash_mode);
13197                 }
13198             }
13199         }
13200     }
13201     else
13202     {
13203         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
13204         {
13205             block->id = frame_set->tr_particle_data[i].block_id;
13206             tng_particle_data_block_write(tng_data, block,
13207                                           i, 0, hash_mode);
13208         }
13209     }
13210
13211
13212     /* Update pointers in the general info block */
13213     stat = tng_header_pointers_update(tng_data, hash_mode);
13214
13215     if(stat == TNG_SUCCESS)
13216     {
13217         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
13218     }
13219
13220     tng_block_destroy(&block);
13221
13222     frame_set->n_unwritten_frames = 0;
13223
13224     fflush(tng_data->output_file);
13225
13226     return(stat);
13227 }
13228
13229 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
13230                 (tng_trajectory_t tng_data,
13231                  const char hash_mode)
13232 {
13233     tng_trajectory_frame_set_t frame_set;
13234
13235     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13236
13237     frame_set = &tng_data->current_trajectory_frame_set;
13238
13239     if(frame_set->n_unwritten_frames == 0)
13240     {
13241         return(TNG_SUCCESS);
13242     }
13243     frame_set->n_frames = frame_set->n_unwritten_frames;
13244
13245     return(tng_frame_set_write(tng_data, hash_mode));
13246 }
13247
13248 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
13249                 (tng_trajectory_t tng_data,
13250                  const int64_t first_frame,
13251                  const int64_t n_frames)
13252 {
13253     tng_gen_block_t block;
13254     tng_trajectory_frame_set_t frame_set;
13255     FILE *temp = tng_data->input_file;
13256     int64_t curr_pos;
13257
13258     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13259     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13260     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13261
13262     frame_set = &tng_data->current_trajectory_frame_set;
13263
13264     curr_pos = ftello(tng_data->output_file);
13265
13266     if(curr_pos <= 10)
13267     {
13268         tng_file_headers_write(tng_data, TNG_USE_HASH);
13269     }
13270
13271     /* Set pointer to previous frame set to the one that was loaded
13272      * before.
13273      * FIXME: This is a bit risky. If they are not added in order
13274      * it will be wrong. */
13275     if(tng_data->n_trajectory_frame_sets)
13276     {
13277         frame_set->prev_frame_set_file_pos =
13278         tng_data->current_trajectory_frame_set_output_file_pos;
13279     }
13280
13281     tng_data->current_trajectory_frame_set_output_file_pos =
13282     ftello(tng_data->output_file);
13283
13284     tng_data->n_trajectory_frame_sets++;
13285
13286     /* Set the medium range pointers */
13287     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
13288     {
13289         frame_set->medium_stride_prev_frame_set_file_pos =
13290         tng_data->first_trajectory_frame_set_output_file_pos;
13291     }
13292     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13293     {
13294         /* FIXME: Currently only working if the previous frame set has its
13295          * medium stride pointer already set. This might need some fixing. */
13296         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
13297            frame_set->medium_stride_prev_frame_set_file_pos != 0)
13298         {
13299             tng_block_init(&block);
13300             tng_data->input_file = tng_data->output_file;
13301
13302             curr_pos = ftello(tng_data->output_file);
13303             fseeko(tng_data->output_file,
13304                    frame_set->medium_stride_prev_frame_set_file_pos,
13305                    SEEK_SET);
13306
13307             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13308             {
13309                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13310                     __FILE__, __LINE__);
13311                 tng_data->input_file = temp;
13312                 tng_block_destroy(&block);
13313                 return(TNG_CRITICAL);
13314             }
13315
13316             /* Read the next frame set from the previous frame set and one
13317              * medium stride step back */
13318             fseeko(tng_data->output_file, block->block_contents_size - (6 *
13319             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13320             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
13321                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
13322                1, tng_data->output_file) == 0)
13323             {
13324                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13325                 tng_data->input_file = temp;
13326                 tng_block_destroy(&block);
13327                 return(TNG_CRITICAL);
13328             }
13329
13330             if(tng_data->input_endianness_swap_func_64)
13331             {
13332                 if(tng_data->input_endianness_swap_func_64(tng_data,
13333                    &frame_set->medium_stride_prev_frame_set_file_pos)
13334                     != TNG_SUCCESS)
13335                 {
13336                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13337                             __FILE__, __LINE__);
13338                 }
13339             }
13340
13341             tng_block_destroy(&block);
13342
13343             /* Set the long range pointers */
13344             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
13345             {
13346                 frame_set->long_stride_prev_frame_set_file_pos =
13347                 tng_data->first_trajectory_frame_set_output_file_pos;
13348             }
13349             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13350             {
13351                 /* FIXME: Currently only working if the previous frame set has its
13352                 * long stride pointer already set. This might need some fixing. */
13353                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
13354                 frame_set->long_stride_prev_frame_set_file_pos != 0)
13355                 {
13356                     tng_block_init(&block);
13357                     tng_data->input_file = tng_data->output_file;
13358
13359                     fseeko(tng_data->output_file,
13360                            frame_set->long_stride_prev_frame_set_file_pos,
13361                            SEEK_SET);
13362
13363                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13364                     {
13365                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13366                             __FILE__, __LINE__);
13367                         tng_data->input_file = temp;
13368                         tng_block_destroy(&block);
13369                         return(TNG_CRITICAL);
13370                     }
13371
13372                     /* Read the next frame set from the previous frame set and one
13373                     * long stride step back */
13374                     fseeko(tng_data->output_file, block->block_contents_size - (6 *
13375                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13376
13377                     tng_block_destroy(&block);
13378
13379                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
13380                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
13381                     1, tng_data->output_file) == 0)
13382                     {
13383                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13384                         tng_data->input_file = temp;
13385                         return(TNG_CRITICAL);
13386                     }
13387
13388                     if(tng_data->input_endianness_swap_func_64)
13389                     {
13390                         if(tng_data->input_endianness_swap_func_64(tng_data,
13391                            &frame_set->long_stride_prev_frame_set_file_pos)
13392                             != TNG_SUCCESS)
13393                         {
13394                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13395                                     __FILE__, __LINE__);
13396                         }
13397                     }
13398
13399                 }
13400             }
13401
13402             tng_data->input_file = temp;
13403             fseeko(tng_data->output_file, curr_pos, SEEK_SET);
13404         }
13405     }
13406
13407     frame_set->first_frame = first_frame;
13408     frame_set->n_frames = n_frames;
13409     frame_set->n_written_frames = 0;
13410     frame_set->n_unwritten_frames = 0;
13411     frame_set->first_frame_time = -1;
13412
13413     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
13414        tng_data->first_trajectory_frame_set_output_file_pos == 0)
13415     {
13416         tng_data->first_trajectory_frame_set_output_file_pos =
13417         tng_data->current_trajectory_frame_set_output_file_pos;
13418     }
13419     /* FIXME: Should check the frame number instead of the file_pos,
13420      * in case frame sets are not in order */
13421     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
13422        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
13423        tng_data->last_trajectory_frame_set_output_file_pos <
13424        tng_data->current_trajectory_frame_set_output_file_pos)
13425     {
13426         tng_data->last_trajectory_frame_set_output_file_pos =
13427         tng_data->current_trajectory_frame_set_output_file_pos;
13428     }
13429
13430     return(TNG_SUCCESS);
13431 }
13432
13433 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
13434                 (tng_trajectory_t tng_data,
13435                  const int64_t first_frame,
13436                  const int64_t n_frames,
13437                  const double first_frame_time)
13438 {
13439     tng_function_status stat;
13440
13441     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13442     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13443     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13444     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13445
13446
13447     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
13448     if(stat != TNG_SUCCESS)
13449     {
13450         return(stat);
13451     }
13452     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
13453
13454     return(stat);
13455 }
13456
13457 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
13458                 (tng_trajectory_t tng_data,
13459                  const double first_frame_time)
13460 {
13461     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13462     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13463
13464     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
13465
13466     return(TNG_SUCCESS);
13467 }
13468
13469 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
13470                 (const tng_trajectory_t tng_data,
13471                  int64_t *frame)
13472 {
13473     int64_t file_pos, next_frame_set_file_pos;
13474     tng_gen_block_t block;
13475     tng_function_status stat;
13476
13477     tng_trajectory_frame_set_t frame_set;
13478
13479     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13480     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
13481     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
13482
13483     file_pos = ftello(tng_data->input_file);
13484
13485     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13486     {
13487         next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13488     }
13489     else
13490     {
13491         frame_set = &tng_data->current_trajectory_frame_set;
13492         next_frame_set_file_pos = frame_set->next_frame_set_file_pos;
13493     }
13494
13495     if(next_frame_set_file_pos <= 0)
13496     {
13497         return(TNG_FAILURE);
13498     }
13499
13500     fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET);
13501     /* Read block headers first to see that a frame set block is found. */
13502     tng_block_init(&block);
13503     stat = tng_block_header_read(tng_data, block);
13504     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13505     {
13506         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13507                file_pos, __FILE__, __LINE__);
13508         return(TNG_CRITICAL);
13509     }
13510 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13511     {
13512         tng_block_read_next(tng_data, block, TNG_USE_HASH);
13513     }*/
13514     tng_block_destroy(&block);
13515
13516     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
13517     {
13518         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
13519                __FILE__, __LINE__);
13520         return(TNG_CRITICAL);
13521     }
13522     fseeko(tng_data->input_file, file_pos, SEEK_SET);
13523
13524     return(TNG_SUCCESS);
13525 }
13526
13527 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
13528                 (tng_trajectory_t tng_data,
13529                  const int64_t id,
13530                  const char *block_name,
13531                  const char datatype,
13532                  const char block_type_flag,
13533                  int64_t n_frames,
13534                  const int64_t n_values_per_frame,
13535                  int64_t stride_length,
13536                  const int64_t codec_id,
13537                  void *new_data)
13538 {
13539     int i, j, size, len;
13540     tng_trajectory_frame_set_t frame_set;
13541     tng_non_particle_data_t data;
13542     char **first_dim_values;
13543     char *new_data_c=new_data;
13544     int64_t n_frames_div;
13545
13546     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13547     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
13548     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13549
13550     frame_set = &tng_data->current_trajectory_frame_set;
13551
13552     if(stride_length <= 0)
13553     {
13554         stride_length = 1;
13555     }
13556
13557     /* If the block does not exist, create it */
13558     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
13559     {
13560         if(tng_data_block_create(tng_data, block_type_flag) !=
13561             TNG_SUCCESS)
13562         {
13563             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
13564                    __FILE__, __LINE__);
13565             return(TNG_CRITICAL);
13566         }
13567         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13568         {
13569             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
13570         }
13571         else
13572         {
13573             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
13574         }
13575         data->block_id = id;
13576
13577         data->block_name = malloc(strlen(block_name) + 1);
13578         if(!data->block_name)
13579         {
13580             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13581                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13582             return(TNG_CRITICAL);
13583         }
13584         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13585
13586         data->values = 0;
13587         /* FIXME: Memory leak from strings. */
13588         data->strings = 0;
13589         data->last_retrieved_frame = -1;
13590     }
13591
13592     data->datatype = datatype;
13593     data->stride_length = tng_max_i64(stride_length, 1);
13594     data->n_values_per_frame = n_values_per_frame;
13595     data->n_frames = n_frames;
13596     data->codec_id = codec_id;
13597     data->compression_multiplier = 1.0;
13598     /* FIXME: This can cause problems. */
13599     data->first_frame_with_data = frame_set->first_frame;
13600
13601     switch(datatype)
13602     {
13603     case TNG_FLOAT_DATA:
13604         size = sizeof(float);
13605         break;
13606     case TNG_INT_DATA:
13607         size = sizeof(int64_t);
13608         break;
13609     case TNG_DOUBLE_DATA:
13610     default:
13611         size = sizeof(double);
13612         break;
13613     }
13614
13615     if(new_data_c)
13616     {
13617         /* Allocate memory */
13618         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
13619                                  n_values_per_frame) !=
13620         TNG_SUCCESS)
13621         {
13622             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
13623                 __FILE__, __LINE__);
13624             return(TNG_CRITICAL);
13625         }
13626
13627         if(n_frames > frame_set->n_unwritten_frames)
13628         {
13629             frame_set->n_unwritten_frames = n_frames;
13630         }
13631
13632         n_frames_div = (n_frames % stride_length) ?
13633                      n_frames / stride_length + 1:
13634                      n_frames / stride_length;
13635
13636         if(datatype == TNG_CHAR_DATA)
13637         {
13638             for(i = 0; i < n_frames_div; i++)
13639             {
13640                 first_dim_values = data->strings[i];
13641                 for(j = 0; j < n_values_per_frame; j++)
13642                 {
13643                     len = tng_min_i((int)strlen(new_data_c) + 1,
13644                                 TNG_MAX_STR_LEN);
13645                     if(first_dim_values[j])
13646                     {
13647                         free(first_dim_values[j]);
13648                     }
13649                     first_dim_values[j] = malloc(len);
13650                     if(!first_dim_values[j])
13651                     {
13652                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13653                             len, __FILE__, __LINE__);
13654                         return(TNG_CRITICAL);
13655                     }
13656                     strncpy(first_dim_values[j],
13657                             new_data_c, len);
13658                     new_data_c += len;
13659                 }
13660             }
13661         }
13662         else
13663         {
13664             memcpy(data->values, new_data, size * n_frames_div *
13665                    n_values_per_frame);
13666         }
13667     }
13668
13669     return(TNG_SUCCESS);
13670 }
13671
13672 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
13673                 (tng_trajectory_t tng_data,
13674                  const int64_t id,
13675                  const char *block_name,
13676                  const char datatype,
13677                  const char block_type_flag,
13678                  int64_t n_frames,
13679                  const int64_t n_values_per_frame,
13680                  int64_t stride_length,
13681                  const int64_t num_first_particle,
13682                  const int64_t n_particles,
13683                  const int64_t codec_id,
13684                  void *new_data)
13685 {
13686     int i, size, len;
13687     int64_t j, k;
13688     int64_t tot_n_particles, n_frames_div;
13689     char ***first_dim_values, **second_dim_values;
13690     tng_trajectory_frame_set_t frame_set;
13691     tng_particle_data_t data;
13692     char *new_data_c=new_data;
13693
13694     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13695     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
13696     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13697     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
13698     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
13699
13700
13701     frame_set = &tng_data->current_trajectory_frame_set;
13702
13703     if(stride_length <= 0)
13704     {
13705         stride_length = 1;
13706     }
13707
13708     /* If the block does not exist, create it */
13709     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
13710     {
13711         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
13712             TNG_SUCCESS)
13713         {
13714             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
13715                    __FILE__, __LINE__);
13716             return(TNG_CRITICAL);
13717         }
13718         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13719         {
13720             data = &frame_set->tr_particle_data[frame_set->
13721                                                 n_particle_data_blocks - 1];
13722         }
13723         else
13724         {
13725             data = &tng_data->non_tr_particle_data[tng_data->
13726                                                    n_particle_data_blocks - 1];
13727         }
13728         data->block_id = id;
13729
13730         data->block_name = malloc(strlen(block_name) + 1);
13731         if(!data->block_name)
13732         {
13733             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13734                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13735             return(TNG_CRITICAL);
13736         }
13737         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13738
13739         data->datatype = datatype;
13740
13741         data->values = 0;
13742         /* FIXME: Memory leak from strings. */
13743         data->strings = 0;
13744         data->last_retrieved_frame = -1;
13745     }
13746
13747     data->stride_length = tng_max_i64(stride_length, 1);
13748     data->n_values_per_frame = n_values_per_frame;
13749     data->n_frames = n_frames;
13750     data->codec_id = codec_id;
13751     data->compression_multiplier = 1.0;
13752     /* FIXME: This can cause problems. */
13753     data->first_frame_with_data = frame_set->first_frame;
13754
13755     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
13756     {
13757         tot_n_particles = frame_set->n_particles;
13758     }
13759     else
13760     {
13761         tot_n_particles = tng_data->n_particles;
13762     }
13763
13764     /* If data values are supplied add that data to the data block. */
13765     if(new_data_c)
13766     {
13767         /* Allocate memory */
13768         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
13769                                           stride_length, tot_n_particles,
13770                                           n_values_per_frame) !=
13771         TNG_SUCCESS)
13772         {
13773             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13774                 __FILE__, __LINE__);
13775             return(TNG_CRITICAL);
13776         }
13777
13778         if(n_frames > frame_set->n_unwritten_frames)
13779         {
13780             frame_set->n_unwritten_frames = n_frames;
13781         }
13782
13783         n_frames_div = (n_frames % stride_length) ?
13784                      n_frames / stride_length + 1:
13785                      n_frames / stride_length;
13786
13787         if(datatype == TNG_CHAR_DATA)
13788         {
13789             for(i = 0; i < n_frames_div; i++)
13790             {
13791                 first_dim_values = data->strings[i];
13792                 for(j = num_first_particle; j < num_first_particle + n_particles;
13793                     j++)
13794                 {
13795                     second_dim_values = first_dim_values[j];
13796                     for(k = 0; k < n_values_per_frame; k++)
13797                     {
13798                         len = tng_min_i((int)strlen(new_data_c) + 1,
13799                                 TNG_MAX_STR_LEN);
13800                         if(second_dim_values[k])
13801                         {
13802                             free(second_dim_values[k]);
13803                         }
13804                         second_dim_values[k] = malloc(len);
13805                         if(!second_dim_values[k])
13806                         {
13807                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13808                                 len, __FILE__, __LINE__);
13809                             return(TNG_CRITICAL);
13810                         }
13811                         strncpy(second_dim_values[k],
13812                                 new_data_c, len);
13813                         new_data_c += len;
13814                     }
13815                 }
13816             }
13817         }
13818         else
13819         {
13820             switch(datatype)
13821             {
13822             case TNG_INT_DATA:
13823                 size = sizeof(int64_t);
13824                 break;
13825             case TNG_FLOAT_DATA:
13826                 size = sizeof(float);
13827                 break;
13828             case TNG_DOUBLE_DATA:
13829             default:
13830                 size = sizeof(double);
13831             }
13832
13833             memcpy(data->values, new_data, size * n_frames_div *
13834                    n_particles * n_values_per_frame);
13835         }
13836     }
13837
13838     return(TNG_SUCCESS);
13839 }
13840
13841 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13842                 (tng_trajectory_t tng_data,
13843                  int64_t block_id,
13844                  char *name,
13845                  int max_len)
13846 {
13847     int64_t i;
13848     tng_trajectory_frame_set_t frame_set;
13849     tng_function_status stat;
13850     tng_particle_data_t p_data;
13851     tng_non_particle_data_t np_data;
13852     int block_type = -1;
13853
13854     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13855     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13856
13857     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13858     {
13859         p_data = &tng_data->non_tr_particle_data[i];
13860         if(p_data->block_id == block_id)
13861         {
13862             strncpy(name, p_data->block_name, max_len);
13863             name[max_len - 1] = '\0';
13864             return(TNG_SUCCESS);
13865         }
13866     }
13867     for(i = 0; i < tng_data->n_data_blocks; i++)
13868     {
13869         np_data = &tng_data->non_tr_data[i];
13870         if(np_data->block_id == block_id)
13871         {
13872             strncpy(name, np_data->block_name, max_len);
13873             name[max_len - 1] = '\0';
13874             return(TNG_SUCCESS);
13875         }
13876     }
13877
13878     frame_set = &tng_data->current_trajectory_frame_set;
13879
13880     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13881     if(stat == TNG_SUCCESS)
13882     {
13883         block_type = TNG_PARTICLE_BLOCK_DATA;
13884     }
13885     else
13886     {
13887         stat = tng_data_find(tng_data, block_id, &np_data);
13888         if(stat == TNG_SUCCESS)
13889         {
13890             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13891         }
13892         else
13893         {
13894             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13895             if(stat != TNG_SUCCESS)
13896             {
13897                 return(stat);
13898             }
13899             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13900             if(stat == TNG_SUCCESS)
13901             {
13902                 block_type = TNG_PARTICLE_BLOCK_DATA;
13903             }
13904             else
13905             {
13906                 stat = tng_data_find(tng_data, block_id, &np_data);
13907                 if(stat == TNG_SUCCESS)
13908                 {
13909                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13910                 }
13911             }
13912         }
13913     }
13914     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13915     {
13916         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13917         {
13918             p_data = &frame_set->tr_particle_data[i];
13919             if(p_data->block_id == block_id)
13920             {
13921                 strncpy(name, p_data->block_name, max_len);
13922                 name[max_len - 1] = '\0';
13923                 return(TNG_SUCCESS);
13924             }
13925         }
13926     }
13927     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13928     {
13929         for(i = 0; i < frame_set->n_data_blocks; i++)
13930         {
13931             np_data = &frame_set->tr_data[i];
13932             if(np_data->block_id == block_id)
13933             {
13934                 strncpy(name, np_data->block_name, max_len);
13935                 name[max_len - 1] = '\0';
13936                 return(TNG_SUCCESS);
13937             }
13938         }
13939     }
13940
13941     return(TNG_FAILURE);
13942 }
13943
13944 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13945                 (const tng_trajectory_t tng_data,
13946                  int64_t block_id,
13947                  int *block_dependency)
13948 {
13949     int64_t i;
13950     tng_function_status stat;
13951     tng_particle_data_t p_data;
13952     tng_non_particle_data_t np_data;
13953
13954     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13955     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13956
13957     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13958     {
13959         p_data = &tng_data->non_tr_particle_data[i];
13960         if(p_data->block_id == block_id)
13961         {
13962             *block_dependency = TNG_PARTICLE_DEPENDENT;
13963             return(TNG_SUCCESS);
13964         }
13965     }
13966     for(i = 0; i < tng_data->n_data_blocks; i++)
13967     {
13968         np_data = &tng_data->non_tr_data[i];
13969         if(np_data->block_id == block_id)
13970         {
13971             *block_dependency = 0;
13972             return(TNG_SUCCESS);
13973         }
13974     }
13975
13976     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13977     if(stat == TNG_SUCCESS)
13978     {
13979         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13980         return(TNG_SUCCESS);
13981     }
13982     else
13983     {
13984         stat = tng_data_find(tng_data, block_id, &np_data);
13985         if(stat == TNG_SUCCESS)
13986         {
13987             *block_dependency = TNG_FRAME_DEPENDENT;
13988             return(TNG_SUCCESS);
13989         }
13990         else
13991         {
13992             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13993             if(stat != TNG_SUCCESS)
13994             {
13995                 return(stat);
13996             }
13997             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13998             if(stat == TNG_SUCCESS)
13999             {
14000                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
14001                 return(TNG_SUCCESS);
14002             }
14003             else
14004             {
14005                 stat = tng_data_find(tng_data, block_id, &np_data);
14006                 if(stat == TNG_SUCCESS)
14007                 {
14008                     *block_dependency = TNG_FRAME_DEPENDENT;
14009                     return(TNG_SUCCESS);
14010                 }
14011             }
14012         }
14013     }
14014
14015     return(TNG_FAILURE);
14016 }
14017
14018 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
14019                 (const tng_trajectory_t tng_data,
14020                  int64_t block_id,
14021                  int64_t *n_values_per_frame)
14022 {
14023     int64_t i;
14024     tng_function_status stat;
14025     tng_particle_data_t p_data;
14026     tng_non_particle_data_t np_data;
14027
14028     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14029     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14030
14031     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
14032     {
14033         p_data = &tng_data->non_tr_particle_data[i];
14034         if(p_data->block_id == block_id)
14035         {
14036             *n_values_per_frame = p_data->n_values_per_frame;
14037             return(TNG_SUCCESS);
14038         }
14039     }
14040     for(i = 0; i < tng_data->n_data_blocks; i++)
14041     {
14042         np_data = &tng_data->non_tr_data[i];
14043         if(np_data->block_id == block_id)
14044         {
14045             *n_values_per_frame = np_data->n_values_per_frame;
14046             return(TNG_SUCCESS);
14047         }
14048     }
14049
14050     stat = tng_particle_data_find(tng_data, block_id, &p_data);
14051     if(stat == TNG_SUCCESS)
14052     {
14053         *n_values_per_frame = p_data->n_values_per_frame;
14054         return(TNG_SUCCESS);
14055     }
14056     else
14057     {
14058         stat = tng_data_find(tng_data, block_id, &np_data);
14059         if(stat == TNG_SUCCESS)
14060         {
14061             *n_values_per_frame = np_data->n_values_per_frame;
14062             return(TNG_SUCCESS);
14063         }
14064         else
14065         {
14066             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
14067             if(stat != TNG_SUCCESS)
14068             {
14069                 return(stat);
14070             }
14071             stat = tng_particle_data_find(tng_data, block_id, &p_data);
14072             if(stat == TNG_SUCCESS)
14073             {
14074                 *n_values_per_frame = p_data->n_values_per_frame;
14075                 return(TNG_SUCCESS);
14076             }
14077             else
14078             {
14079                 stat = tng_data_find(tng_data, block_id, &np_data);
14080                 if(stat == TNG_SUCCESS)
14081                 {
14082                     *n_values_per_frame = np_data->n_values_per_frame;
14083                     return(TNG_SUCCESS);
14084                 }
14085             }
14086         }
14087     }
14088
14089     return(TNG_FAILURE);
14090 }
14091
14092 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
14093                 (tng_trajectory_t tng_data,
14094                  const int64_t frame_nr,
14095                  const int64_t block_id,
14096                  const void *values,
14097                  const char hash_mode)
14098 {
14099     int64_t header_pos, file_pos;
14100     int64_t output_file_len, n_values_per_frame, size, contents_size;
14101     int64_t header_size, temp_first, temp_last;
14102     int64_t i, last_frame, temp_current;
14103     tng_gen_block_t block;
14104     tng_trajectory_frame_set_t frame_set;
14105     FILE *temp = tng_data->input_file;
14106     struct tng_non_particle_data data;
14107     tng_function_status stat;
14108     char dependency, sparse_data, datatype;
14109     void *copy;
14110
14111     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14112     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14113     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14114
14115     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14116     {
14117         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14118                __FILE__, __LINE__);
14119         return(TNG_CRITICAL);
14120     }
14121
14122     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14123     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14124     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14125     tng_data->first_trajectory_frame_set_input_file_pos =
14126     tng_data->first_trajectory_frame_set_output_file_pos;
14127     tng_data->last_trajectory_frame_set_input_file_pos =
14128     tng_data->last_trajectory_frame_set_output_file_pos;
14129     tng_data->current_trajectory_frame_set_input_file_pos =
14130     tng_data->current_trajectory_frame_set_output_file_pos;
14131
14132     tng_data->input_file = tng_data->output_file;
14133
14134     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14135
14136     frame_set = &tng_data->current_trajectory_frame_set;
14137
14138     if(stat != TNG_SUCCESS)
14139     {
14140         last_frame = frame_set->first_frame +
14141                      frame_set->n_frames - 1;
14142         /* If the wanted frame would be in the frame set after the last
14143             * frame set create a new frame set. */
14144         if(stat == TNG_FAILURE &&
14145             last_frame < frame_nr)
14146 /*           (last_frame < frame_nr &&
14147             tng_data->current_trajectory_frame_set.first_frame +
14148             tng_data->frame_set_n_frames >= frame_nr))*/
14149         {
14150             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14151             {
14152                 last_frame = frame_nr - 1;
14153             }
14154             tng_frame_set_new(tng_data,
14155                               last_frame+1,
14156                               tng_data->frame_set_n_frames);
14157             file_pos = ftello(tng_data->output_file);
14158             fseeko(tng_data->output_file, 0, SEEK_END);
14159             output_file_len = ftello(tng_data->output_file);
14160             fseeko(tng_data->output_file, file_pos, SEEK_SET);
14161
14162             /* Read mapping blocks from the last frame set */
14163             tng_block_init(&block);
14164
14165             stat = tng_block_header_read(tng_data, block);
14166             while(file_pos < output_file_len &&
14167                   stat != TNG_CRITICAL &&
14168                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14169                   block->id != -1)
14170             {
14171                 if(block->id == TNG_PARTICLE_MAPPING)
14172                 {
14173                     tng_trajectory_mapping_block_read(tng_data, block,
14174                                                       hash_mode);
14175                 }
14176                 else
14177                 {
14178                     fseeko(tng_data->output_file, block->block_contents_size,
14179                            SEEK_CUR);
14180                 }
14181                 file_pos = ftello(tng_data->output_file);
14182                 if(file_pos < output_file_len)
14183                 {
14184                     stat = tng_block_header_read(tng_data, block);
14185                 }
14186             }
14187
14188             tng_block_destroy(&block);
14189             /* Write the frame set to disk */
14190             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14191             {
14192                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14193                 return(TNG_CRITICAL);
14194             }
14195         }
14196         else
14197         {
14198             tng_data->input_file = temp;
14199             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14200             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14201             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14202             return(stat);
14203         }
14204     }
14205
14206     tng_block_init(&block);
14207
14208     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14209
14210     fseeko(tng_data->output_file, 0, SEEK_END);
14211     output_file_len = ftello(tng_data->output_file);
14212     fseeko(tng_data->output_file, file_pos, SEEK_SET);
14213
14214     /* Read past the frame set block first */
14215     stat = tng_block_header_read(tng_data, block);
14216     if(stat == TNG_CRITICAL)
14217     {
14218         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14219                file_pos, __FILE__, __LINE__);
14220         tng_block_destroy(&block);
14221         tng_data->input_file = temp;
14222
14223         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14224         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14225         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14226         return(stat);
14227     }
14228     fseeko(tng_data->output_file, block->block_contents_size,
14229            SEEK_CUR);
14230
14231     /* Read all block headers until next frame set block or
14232      * until the wanted block id is found */
14233     stat = tng_block_header_read(tng_data, block);
14234     while(file_pos < output_file_len &&
14235             stat != TNG_CRITICAL &&
14236             block->id != block_id &&
14237             block->id != TNG_TRAJECTORY_FRAME_SET &&
14238             block->id != -1)
14239     {
14240         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
14241         file_pos = ftello(tng_data->output_file);
14242         if(file_pos < output_file_len)
14243         {
14244             stat = tng_block_header_read(tng_data, block);
14245         }
14246     }
14247     if(stat == TNG_CRITICAL)
14248     {
14249         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14250                file_pos, __FILE__, __LINE__);
14251         tng_block_destroy(&block);
14252         tng_data->input_file = temp;
14253         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14254         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14255         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14256         return(stat);
14257     }
14258
14259     contents_size = block->block_contents_size;
14260     header_size = block->header_contents_size;
14261
14262     header_pos = ftello(tng_data->output_file) - header_size;
14263     frame_set = &tng_data->current_trajectory_frame_set;
14264
14265     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14266     {
14267         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14268         tng_block_destroy(&block);
14269         return(TNG_CRITICAL);
14270     }
14271     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14272     {
14273         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14274         tng_block_destroy(&block);
14275         return(TNG_CRITICAL);
14276     }
14277     data.datatype = datatype;
14278
14279     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14280        (dependency & TNG_PARTICLE_DEPENDENT))
14281     {
14282         tng_block_destroy(&block);
14283         tng_data->input_file = temp;
14284
14285         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14286         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14287         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14288         return(TNG_FAILURE);
14289     }
14290
14291     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14292     {
14293         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14294         tng_block_destroy(&block);
14295         return(TNG_CRITICAL);
14296     }
14297
14298     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14299              tng_data->input_file) == 0)
14300     {
14301         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14302         tng_block_destroy(&block);
14303         return(TNG_CRITICAL);
14304     }
14305     if(tng_data->output_endianness_swap_func_64)
14306     {
14307         if(tng_data->output_endianness_swap_func_64(tng_data,
14308             &data.n_values_per_frame)
14309             != TNG_SUCCESS)
14310         {
14311             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14312                     __FILE__, __LINE__);
14313         }
14314     }
14315
14316     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14317              tng_data->input_file) == 0)
14318     {
14319         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14320         tng_block_destroy(&block);
14321         return(TNG_CRITICAL);
14322     }
14323     if(tng_data->output_endianness_swap_func_64)
14324     {
14325         if(tng_data->output_endianness_swap_func_64(tng_data,
14326             &data.codec_id)
14327             != TNG_SUCCESS)
14328         {
14329             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14330                     __FILE__, __LINE__);
14331         }
14332     }
14333
14334     if(data.codec_id != TNG_UNCOMPRESSED)
14335     {
14336         if(fread(&data.compression_multiplier,
14337                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14338             == 0)
14339         {
14340             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14341             tng_block_destroy(&block);
14342             return(TNG_CRITICAL);
14343         }
14344         if(tng_data->output_endianness_swap_func_64)
14345         {
14346             if(tng_data->output_endianness_swap_func_64(tng_data,
14347                 (int64_t *)&data.compression_multiplier)
14348                 != TNG_SUCCESS)
14349             {
14350                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14351                         __FILE__, __LINE__);
14352             }
14353         }
14354     }
14355     else
14356     {
14357         data.compression_multiplier = 1;
14358     }
14359
14360     if(sparse_data)
14361     {
14362         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
14363                  1, tng_data->input_file) == 0)
14364         {
14365             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14366             tng_block_destroy(&block);
14367             return(TNG_CRITICAL);
14368         }
14369         if(tng_data->output_endianness_swap_func_64)
14370         {
14371             if(tng_data->output_endianness_swap_func_64(tng_data,
14372                 &data.first_frame_with_data)
14373                 != TNG_SUCCESS)
14374             {
14375                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14376                         __FILE__, __LINE__);
14377             }
14378         }
14379
14380         if(fread(&data.stride_length, sizeof(data.stride_length),
14381                  1, tng_data->input_file) == 0)
14382         {
14383             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14384             tng_block_destroy(&block);
14385             return(TNG_CRITICAL);
14386         }
14387         if(tng_data->output_endianness_swap_func_64)
14388         {
14389             if(tng_data->output_endianness_swap_func_64(tng_data,
14390                 &data.stride_length)
14391                 != TNG_SUCCESS)
14392             {
14393                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14394                         __FILE__, __LINE__);
14395             }
14396         }
14397     }
14398     else
14399     {
14400         data.first_frame_with_data = 0;
14401         data.stride_length = 1;
14402     }
14403     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14404
14405     tng_data->input_file = temp;
14406
14407     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14408     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14409     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14410
14411     switch(data.datatype)
14412     {
14413         case(TNG_INT_DATA):
14414             size = sizeof(int64_t);
14415             break;
14416         case(TNG_FLOAT_DATA):
14417             size = sizeof(float);
14418             break;
14419         case(TNG_DOUBLE_DATA):
14420             size = sizeof(double);
14421             break;
14422         default:
14423             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14424                    __LINE__);
14425             tng_block_destroy(&block);
14426             return(TNG_FAILURE);
14427     }
14428
14429     n_values_per_frame = data.n_values_per_frame;
14430
14431     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14432                                data.first_frame_with_data)) /
14433                 data.stride_length;
14434     file_pos *= size * n_values_per_frame;
14435
14436     if(file_pos > contents_size)
14437     {
14438         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14439                __LINE__);
14440         tng_block_destroy(&block);
14441         return(TNG_FAILURE);
14442     }
14443
14444     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
14445
14446     /* If the endianness is not big endian the data needs to be swapped */
14447     if((data.datatype == TNG_INT_DATA ||
14448         data.datatype == TNG_DOUBLE_DATA) &&
14449        tng_data->output_endianness_swap_func_64)
14450     {
14451         copy = malloc(n_values_per_frame * size);
14452         memcpy(copy, values, n_values_per_frame * size);
14453         for(i = 0; i < n_values_per_frame; i++)
14454         {
14455             if(tng_data->output_endianness_swap_func_64(tng_data,
14456                 (int64_t *)copy+i)
14457                 != TNG_SUCCESS)
14458             {
14459                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14460                         __FILE__, __LINE__);
14461             }
14462         }
14463         fwrite(copy, n_values_per_frame, size,
14464                tng_data->output_file);
14465         free(copy);
14466     }
14467     else if(data.datatype == TNG_FLOAT_DATA &&
14468             tng_data->output_endianness_swap_func_32)
14469     {
14470         copy = malloc(n_values_per_frame * size);
14471         memcpy(copy, values, n_values_per_frame * size);
14472         for(i = 0; i < n_values_per_frame; i++)
14473         {
14474             if(tng_data->output_endianness_swap_func_32(tng_data,
14475                 (int32_t *)copy+i)
14476                 != TNG_SUCCESS)
14477             {
14478                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14479                         __FILE__, __LINE__);
14480             }
14481         }
14482         fwrite(copy, n_values_per_frame, size,
14483                tng_data->output_file);
14484         free(copy);
14485     }
14486
14487     else
14488     {
14489         fwrite(values, n_values_per_frame, size, tng_data->output_file);
14490     }
14491
14492     fflush(tng_data->output_file);
14493
14494     /* Update the number of written frames in the frame set. */
14495     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14496     {
14497         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14498     }
14499
14500     /* If the last frame has been written update the hash */
14501     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14502        data.first_frame_with_data) >=
14503        frame_set->n_frames)
14504     {
14505         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14506                             header_size);
14507     }
14508
14509     tng_block_destroy(&block);
14510
14511     return(TNG_SUCCESS);
14512 }
14513
14514 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
14515                 (tng_trajectory_t tng_data,
14516                  const int64_t frame_nr,
14517                  const int64_t block_id,
14518                  const int64_t val_first_particle,
14519                  const int64_t val_n_particles,
14520                  const void *values,
14521                  const char hash_mode)
14522 {
14523     int64_t header_pos, file_pos, tot_n_particles;
14524     int64_t output_file_len, n_values_per_frame, size, contents_size;
14525     int64_t header_size, temp_first, temp_last;
14526     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
14527     int64_t i, last_frame, temp_current;
14528     tng_gen_block_t block;
14529     tng_trajectory_frame_set_t frame_set;
14530     FILE *temp = tng_data->input_file;
14531     struct tng_particle_data data;
14532     tng_function_status stat;
14533     tng_particle_mapping_t mapping;
14534     char dependency, sparse_data, datatype;
14535     void *copy;
14536
14537     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14538     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14539     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14540     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
14541     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
14542
14543     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14544     {
14545         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14546                __FILE__, __LINE__);
14547         return(TNG_CRITICAL);
14548     }
14549
14550     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14551     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14552     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14553     tng_data->first_trajectory_frame_set_input_file_pos =
14554     tng_data->first_trajectory_frame_set_output_file_pos;
14555     tng_data->last_trajectory_frame_set_input_file_pos =
14556     tng_data->last_trajectory_frame_set_output_file_pos;
14557     tng_data->current_trajectory_frame_set_input_file_pos =
14558     tng_data->current_trajectory_frame_set_output_file_pos;
14559
14560     tng_data->input_file = tng_data->output_file;
14561
14562     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14563
14564     frame_set = &tng_data->current_trajectory_frame_set;
14565
14566     if(stat != TNG_SUCCESS)
14567     {
14568         last_frame = frame_set->first_frame +
14569                      frame_set->n_frames - 1;
14570 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
14571                   last_frame); */
14572         /* If the wanted frame would be in the frame set after the last
14573          * frame set create a new frame set. */
14574         if(stat == TNG_FAILURE &&
14575            (last_frame < frame_nr &&
14576             last_frame + tng_data->frame_set_n_frames >= frame_nr))
14577         {
14578             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14579             {
14580                 last_frame = frame_nr - 1;
14581             }
14582             tng_frame_set_new(tng_data,
14583                               last_frame+1,
14584                               tng_data->frame_set_n_frames);
14585
14586             file_pos = ftello(tng_data->output_file);
14587             fseeko(tng_data->output_file, 0, SEEK_END);
14588             output_file_len = ftello(tng_data->output_file);
14589             fseeko(tng_data->output_file, file_pos, SEEK_SET);
14590
14591             /* Read mapping blocks from the last frame set */
14592             tng_block_init(&block);
14593
14594             stat = tng_block_header_read(tng_data, block);
14595             while(file_pos < output_file_len &&
14596                   stat != TNG_CRITICAL &&
14597                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14598                   block->id != -1)
14599             {
14600                 if(block->id == TNG_PARTICLE_MAPPING)
14601                 {
14602                     tng_trajectory_mapping_block_read(tng_data, block,
14603                                                       hash_mode);
14604                 }
14605                 else
14606                 {
14607                     fseeko(tng_data->output_file, block->block_contents_size,
14608                         SEEK_CUR);
14609                 }
14610                 file_pos = ftello(tng_data->output_file);
14611                 if(file_pos < output_file_len)
14612                 {
14613                     stat = tng_block_header_read(tng_data, block);
14614                 }
14615             }
14616
14617             tng_block_destroy(&block);
14618             /* Write the frame set to disk */
14619             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14620             {
14621                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14622                 exit(1);
14623             }
14624         }
14625         else
14626         {
14627             tng_data->input_file = temp;
14628             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14629             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14630             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14631             return(stat);
14632         }
14633     }
14634
14635
14636     tng_block_init(&block);
14637
14638     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14639
14640     fseeko(tng_data->output_file, 0, SEEK_END);
14641     output_file_len = ftello(tng_data->output_file);
14642     fseeko(tng_data->output_file, file_pos, SEEK_SET);
14643
14644     /* Read past the frame set block first */
14645     stat = tng_block_header_read(tng_data, block);
14646     if(stat == TNG_CRITICAL)
14647     {
14648         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14649                file_pos, __FILE__, __LINE__);
14650         tng_block_destroy(&block);
14651         tng_data->input_file = temp;
14652
14653         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14654         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14655         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14656         return(stat);
14657     }
14658     fseeko(tng_data->output_file, block->block_contents_size,
14659             SEEK_CUR);
14660
14661     if(tng_data->var_num_atoms_flag)
14662     {
14663         tot_n_particles = frame_set->n_particles;
14664     }
14665     else
14666     {
14667         tot_n_particles = tng_data->n_particles;
14668     }
14669
14670     if(val_n_particles < tot_n_particles)
14671     {
14672         mapping_block_end_pos = -1;
14673         /* Read all mapping blocks to find the right place to put the data */
14674         stat = tng_block_header_read(tng_data, block);
14675         while(file_pos < output_file_len &&
14676                 stat != TNG_CRITICAL &&
14677                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14678                 block->id != -1)
14679         {
14680             if(block->id == TNG_PARTICLE_MAPPING)
14681             {
14682                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
14683             }
14684             else
14685             {
14686                 fseeko(tng_data->output_file, block->block_contents_size,
14687                       SEEK_CUR);
14688             }
14689             file_pos = ftello(tng_data->output_file);
14690             if(block->id == TNG_PARTICLE_MAPPING)
14691             {
14692                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
14693                 if(val_first_particle >= mapping->num_first_particle &&
14694                    val_first_particle < mapping->num_first_particle +
14695                    mapping->n_particles &&
14696                    val_first_particle + val_n_particles <=
14697                    mapping->num_first_particle + mapping->n_particles)
14698                 {
14699                     mapping_block_end_pos = file_pos;
14700                 }
14701             }
14702             if(file_pos < output_file_len)
14703             {
14704                 stat = tng_block_header_read(tng_data, block);
14705             }
14706         }
14707         if(stat == TNG_CRITICAL)
14708         {
14709             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14710                    file_pos, __FILE__, __LINE__);
14711             tng_block_destroy(&block);
14712             tng_data->input_file = temp;
14713
14714             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14715             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14716             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14717             return(stat);
14718         }
14719         if(mapping_block_end_pos < 0)
14720         {
14721             tng_block_destroy(&block);
14722             tng_data->input_file = temp;
14723
14724             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14725             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14726             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14727             return(TNG_FAILURE);
14728         }
14729         fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET);
14730     }
14731
14732     /* Read all block headers until next frame set block or
14733      * until the wanted block id is found */
14734     stat = tng_block_header_read(tng_data, block);
14735     while(file_pos < output_file_len &&
14736             stat != TNG_CRITICAL &&
14737             block->id != block_id &&
14738             block->id != TNG_PARTICLE_MAPPING &&
14739             block->id != TNG_TRAJECTORY_FRAME_SET &&
14740             block->id != -1)
14741     {
14742         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
14743         file_pos = ftello(tng_data->output_file);
14744         if(file_pos < output_file_len)
14745         {
14746             stat = tng_block_header_read(tng_data, block);
14747         }
14748     }
14749     if(stat == TNG_CRITICAL)
14750     {
14751         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14752                 file_pos, __FILE__, __LINE__);
14753         tng_block_destroy(&block);
14754         tng_data->input_file = temp;
14755
14756         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14757         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14758         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14759         return(stat);
14760     }
14761
14762     contents_size = block->block_contents_size;
14763     header_size = block->header_contents_size;
14764
14765     header_pos = ftello(tng_data->output_file) - header_size;
14766     frame_set = &tng_data->current_trajectory_frame_set;
14767
14768     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14769     {
14770         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14771         tng_block_destroy(&block);
14772         return(TNG_CRITICAL);
14773     }
14774
14775     data.datatype = datatype;
14776
14777     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14778     {
14779         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14780         tng_block_destroy(&block);
14781         return(TNG_CRITICAL);
14782     }
14783
14784     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14785        !(dependency & TNG_PARTICLE_DEPENDENT))
14786     {
14787         tng_block_destroy(&block);
14788         tng_data->input_file = temp;
14789
14790         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14791         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14792         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14793         return(TNG_FAILURE);
14794     }
14795
14796     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14797     {
14798         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14799         tng_block_destroy(&block);
14800         return(TNG_CRITICAL);
14801     }
14802
14803     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14804              tng_data->input_file) == 0)
14805     {
14806         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14807         tng_block_destroy(&block);
14808         return(TNG_CRITICAL);
14809     }
14810     if(tng_data->output_endianness_swap_func_64)
14811     {
14812         if(tng_data->output_endianness_swap_func_64(tng_data,
14813             &data.n_values_per_frame)
14814             != TNG_SUCCESS)
14815         {
14816             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14817                     __FILE__, __LINE__);
14818         }
14819     }
14820
14821     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14822              tng_data->input_file) == 0)
14823     {
14824         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14825         tng_block_destroy(&block);
14826         return(TNG_CRITICAL);
14827     }
14828     if(tng_data->output_endianness_swap_func_64)
14829     {
14830         if(tng_data->output_endianness_swap_func_64(tng_data,
14831             &data.codec_id)
14832             != TNG_SUCCESS)
14833         {
14834             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14835                     __FILE__, __LINE__);
14836         }
14837     }
14838
14839     if(data.codec_id != TNG_UNCOMPRESSED)
14840     {
14841         if(fread(&data.compression_multiplier,
14842                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14843             == 0)
14844         {
14845             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14846             tng_block_destroy(&block);
14847             return(TNG_CRITICAL);
14848         }
14849
14850         if(tng_data->output_endianness_swap_func_64)
14851         {
14852             if(tng_data->output_endianness_swap_func_64(tng_data,
14853                (int64_t *)&data.compression_multiplier)
14854                 != TNG_SUCCESS)
14855             {
14856                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14857                         __FILE__, __LINE__);
14858             }
14859         }
14860     }
14861     else
14862     {
14863         data.compression_multiplier = 1;
14864     }
14865
14866     if(sparse_data)
14867     {
14868         if(fread(&data.first_frame_with_data,
14869                  sizeof(data.first_frame_with_data),
14870                  1, tng_data->input_file) == 0)
14871         {
14872             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14873             tng_block_destroy(&block);
14874             return(TNG_CRITICAL);
14875         }
14876         if(tng_data->output_endianness_swap_func_64)
14877         {
14878             if(tng_data->output_endianness_swap_func_64(tng_data,
14879                 &data.first_frame_with_data)
14880                 != TNG_SUCCESS)
14881             {
14882                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14883                         __FILE__, __LINE__);
14884             }
14885         }
14886
14887         if(fread(&data.stride_length, sizeof(data.stride_length),
14888                  1, tng_data->input_file) == 0)
14889         {
14890             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14891             tng_block_destroy(&block);
14892             return(TNG_CRITICAL);
14893         }
14894         if(tng_data->output_endianness_swap_func_64)
14895         {
14896             if(tng_data->output_endianness_swap_func_64(tng_data,
14897                 &data.stride_length)
14898                 != TNG_SUCCESS)
14899             {
14900                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14901                         __FILE__, __LINE__);
14902             }
14903         }
14904     }
14905     else
14906     {
14907         data.first_frame_with_data = 0;
14908         data.stride_length = 1;
14909     }
14910     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14911
14912     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14913              tng_data->input_file) == 0)
14914     {
14915         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14916         tng_block_destroy(&block);
14917         return(TNG_CRITICAL);
14918     }
14919     if(tng_data->output_endianness_swap_func_64)
14920     {
14921         if(tng_data->output_endianness_swap_func_64(tng_data,
14922             &num_first_particle)
14923             != TNG_SUCCESS)
14924         {
14925             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14926                     __FILE__, __LINE__);
14927         }
14928     }
14929
14930     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14931              tng_data->input_file) == 0)
14932     {
14933         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14934         tng_block_destroy(&block);
14935         return(TNG_CRITICAL);
14936     }
14937     if(tng_data->output_endianness_swap_func_64)
14938     {
14939         if(tng_data->output_endianness_swap_func_64(tng_data,
14940             &block_n_particles)
14941             != TNG_SUCCESS)
14942         {
14943             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14944                     __FILE__, __LINE__);
14945         }
14946     }
14947
14948
14949     tng_data->input_file = temp;
14950
14951     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14952     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14953     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14954
14955
14956     switch(data.datatype)
14957     {
14958         case(TNG_INT_DATA):
14959             size = sizeof(int64_t);
14960             break;
14961         case(TNG_FLOAT_DATA):
14962             size = sizeof(float);
14963             break;
14964         case(TNG_DOUBLE_DATA):
14965             size = sizeof(double);
14966             break;
14967         default:
14968             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14969                    __LINE__);
14970             tng_block_destroy(&block);
14971             return(TNG_FAILURE);
14972     }
14973
14974     n_values_per_frame = data.n_values_per_frame;
14975
14976     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14977                                data.first_frame_with_data)) /
14978                 data.stride_length;
14979     file_pos *= block_n_particles * size * n_values_per_frame;
14980
14981     if(file_pos > contents_size)
14982     {
14983         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14984                __LINE__);
14985         tng_block_destroy(&block);
14986         return(TNG_FAILURE);
14987     }
14988
14989     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
14990
14991     /* If the endianness is not big endian the data needs to be swapped */
14992     if((data.datatype == TNG_INT_DATA ||
14993         data.datatype == TNG_DOUBLE_DATA) &&
14994        tng_data->output_endianness_swap_func_64)
14995     {
14996         copy = malloc(val_n_particles * n_values_per_frame * size);
14997         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14998         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14999         {
15000             if(tng_data->output_endianness_swap_func_64(tng_data,
15001                 (int64_t *) copy+i)
15002                 != TNG_SUCCESS)
15003             {
15004                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
15005                         __FILE__, __LINE__);
15006             }
15007         }
15008         fwrite(copy, val_n_particles * n_values_per_frame, size,
15009                tng_data->output_file);
15010         free(copy);
15011     }
15012     else if(data.datatype == TNG_FLOAT_DATA &&
15013        tng_data->output_endianness_swap_func_32)
15014     {
15015         copy = malloc(val_n_particles * n_values_per_frame * size);
15016         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
15017         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
15018         {
15019             if(tng_data->output_endianness_swap_func_32(tng_data,
15020                 (int32_t *) copy+i)
15021                 != TNG_SUCCESS)
15022             {
15023                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
15024                         __FILE__, __LINE__);
15025             }
15026         }
15027         fwrite(copy, val_n_particles * n_values_per_frame, size,
15028                tng_data->output_file);
15029         free(copy);
15030     }
15031
15032     else
15033     {
15034         fwrite(values, val_n_particles * n_values_per_frame, size,
15035                tng_data->output_file);
15036     }
15037     fflush(tng_data->output_file);
15038
15039     /* Update the number of written frames in the frame set. */
15040     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
15041     {
15042         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
15043     }
15044
15045     /* If the last frame has been written update the hash */
15046     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
15047        data.first_frame_with_data) >=
15048        frame_set->n_frames)
15049     {
15050         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
15051                             header_size);
15052     }
15053
15054     tng_block_destroy(&block);
15055     return(TNG_SUCCESS);
15056 }
15057
15058 static tng_function_status tng_data_values_alloc
15059                 (const tng_trajectory_t tng_data,
15060                  union data_values ***values,
15061                  const int64_t n_frames,
15062                  const int64_t n_values_per_frame,
15063                  const char type)
15064 {
15065     int64_t i;
15066     tng_function_status stat;
15067
15068     if(n_frames <= 0 || n_values_per_frame <= 0)
15069     {
15070         return(TNG_FAILURE);
15071     }
15072
15073     if(*values)
15074     {
15075         stat = tng_data_values_free(tng_data, *values, n_frames,
15076                                     n_values_per_frame,
15077                                     type);
15078         if(stat != TNG_SUCCESS)
15079         {
15080             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15081                    __FILE__, __LINE__);
15082             return(stat);
15083         }
15084     }
15085     *values = malloc(sizeof(union data_values *) * n_frames);
15086     if(!*values)
15087     {
15088         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15089                sizeof(union data_values **) * n_frames,
15090                __FILE__, __LINE__);
15091         return(TNG_CRITICAL);
15092
15093     }
15094
15095     for(i = 0; i < n_frames; i++)
15096     {
15097         (*values)[i] = malloc(sizeof(union data_values) *
15098                            n_values_per_frame);
15099         if(!(*values)[i])
15100         {
15101             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15102                    sizeof(union data_values) * n_values_per_frame,
15103                    __FILE__, __LINE__);
15104             free(values);
15105             values = 0;
15106             return(TNG_CRITICAL);
15107         }
15108     }
15109     return(TNG_SUCCESS);
15110 }
15111
15112 /* FIXME: This needs ***values */
15113 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
15114                 (const tng_trajectory_t tng_data,
15115                  union data_values **values,
15116                  const int64_t n_frames,
15117                  const int64_t n_values_per_frame,
15118                  const char type)
15119 {
15120     int64_t i, j;
15121     (void)tng_data;
15122
15123     if(values)
15124     {
15125         for(i = 0; i < n_frames; i++)
15126         {
15127             if(values[i])
15128             {
15129                 if(type == TNG_CHAR_DATA)
15130                 {
15131                     for(j = 0; j < n_values_per_frame; j++)
15132                     {
15133                         if(values[i][j].c)
15134                         {
15135                             free(values[i][j].c);
15136                             values[i][j].c = 0;
15137                         }
15138                     }
15139                 }
15140                 free(values[i]);
15141                 values[i] = 0;
15142             }
15143         }
15144         free(values);
15145         values = 0;
15146     }
15147
15148     return(TNG_SUCCESS);
15149 }
15150
15151 static tng_function_status tng_particle_data_values_alloc
15152                 (const tng_trajectory_t tng_data,
15153                  union data_values ****values,
15154                  const int64_t n_frames,
15155                  const int64_t n_particles,
15156                  const int64_t n_values_per_frame,
15157                  const char type)
15158 {
15159     int64_t i, j;
15160     tng_function_status stat;
15161
15162     if(n_particles == 0 || n_values_per_frame == 0)
15163     {
15164         return(TNG_FAILURE);
15165     }
15166
15167     if(*values)
15168     {
15169         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
15170                                              n_particles, n_values_per_frame,
15171                                              type);
15172         if(stat != TNG_SUCCESS)
15173         {
15174             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15175                    __FILE__, __LINE__);
15176             return(stat);
15177         }
15178     }
15179     *values = malloc(sizeof(union data_values **) * n_frames);
15180     if(!*values)
15181     {
15182         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15183                sizeof(union data_values **) * n_frames,
15184                __FILE__, __LINE__);
15185         return(TNG_CRITICAL);
15186
15187     }
15188
15189     for(i = 0; i < n_frames; i++)
15190     {
15191         (*values)[i] = malloc(sizeof(union data_values *) *
15192                            n_particles);
15193         if(!(*values)[i])
15194         {
15195             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15196                    sizeof(union data_values *) * n_particles,
15197                    __FILE__, __LINE__);
15198             free(*values);
15199             *values = 0;
15200             return(TNG_CRITICAL);
15201         }
15202         for(j = 0; j < n_particles; j++)
15203         {
15204             (*values)[i][j] = malloc(sizeof(union data_values) *
15205                                   n_values_per_frame);
15206             if(!(*values)[i][j])
15207             {
15208                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15209                     sizeof(union data_values *) * n_particles,
15210                     __FILE__, __LINE__);
15211                 tng_particle_data_values_free(tng_data, *values, n_frames,
15212                                               n_particles, n_values_per_frame,
15213                                               type);
15214                 *values = 0;
15215                 return(TNG_CRITICAL);
15216             }
15217         }
15218     }
15219     return(TNG_SUCCESS);
15220 }
15221
15222 /* FIXME: This needs ****values */
15223 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
15224                 (const tng_trajectory_t tng_data,
15225                  union data_values ***values,
15226                  const int64_t n_frames,
15227                  const int64_t n_particles,
15228                  const int64_t n_values_per_frame,
15229                  const char type)
15230 {
15231     int64_t i, j, k;
15232     (void)tng_data;
15233
15234     if(values)
15235     {
15236         for(i = 0; i < n_frames; i++)
15237         {
15238             if(values[i])
15239             {
15240                 for(j = 0; j < n_particles; j++)
15241                 {
15242                     if(type == TNG_CHAR_DATA)
15243                     {
15244                         for(k = 0; k < n_values_per_frame; k++)
15245                         {
15246                             if(values[i][j][k].c)
15247                             {
15248                                 free(values[i][j][k].c);
15249                                 values[i][j][k].c = 0;
15250                             }
15251                         }
15252                     }
15253                     free(values[i][j]);
15254                     values[i][j] = 0;
15255                 }
15256                 free(values[i]);
15257                 values[i] = 0;
15258             }
15259         }
15260         free(values);
15261         values = 0;
15262     }
15263
15264     return(TNG_SUCCESS);
15265 }
15266
15267
15268 tng_function_status DECLSPECDLLEXPORT tng_data_get
15269                 (tng_trajectory_t tng_data,
15270                  const int64_t block_id,
15271                  union data_values ***values,
15272                  int64_t *n_frames,
15273                  int64_t *n_values_per_frame,
15274                  char *type)
15275 {
15276     int64_t i, j, file_pos, block_index;
15277     int size;
15278     size_t len;
15279     tng_non_particle_data_t data;
15280     tng_trajectory_frame_set_t frame_set;
15281     tng_gen_block_t block;
15282     tng_function_status stat;
15283
15284     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15285     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15286     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15287     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15288
15289     frame_set = &tng_data->current_trajectory_frame_set;
15290
15291     block_index = -1;
15292     data = 0;
15293
15294     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15295     {
15296         tng_block_init(&block);
15297         file_pos = ftello(tng_data->input_file);
15298         /* Read all blocks until next frame set block */
15299         stat = tng_block_header_read(tng_data, block);
15300         while(file_pos < tng_data->input_file_len &&
15301                 stat != TNG_CRITICAL &&
15302                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15303                 block->id != -1)
15304         {
15305             /* Use hash by default */
15306             stat = tng_block_read_next(tng_data, block,
15307                                     TNG_USE_HASH);
15308             if(stat != TNG_CRITICAL)
15309             {
15310                 file_pos = ftello(tng_data->input_file);
15311                 if(file_pos < tng_data->input_file_len)
15312                 {
15313                     stat = tng_block_header_read(tng_data, block);
15314                 }
15315             }
15316         }
15317         tng_block_destroy(&block);
15318         if(stat == TNG_CRITICAL)
15319         {
15320             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15321                     file_pos, __FILE__, __LINE__);
15322             return(stat);
15323         }
15324
15325         for(i = 0; i < frame_set->n_data_blocks; i++)
15326         {
15327             data = &frame_set->tr_data[i];
15328             if(data->block_id == block_id)
15329             {
15330                 block_index = i;
15331                 break;
15332             }
15333         }
15334         if(block_index < 0)
15335         {
15336             return(TNG_FAILURE);
15337         }
15338     }
15339
15340     *n_frames = tng_max_i64(1, data->n_frames);
15341     *n_values_per_frame = data->n_values_per_frame;
15342     *type = data->datatype;
15343
15344     if(*values == 0)
15345     {
15346         if(tng_data_values_alloc(tng_data, values, *n_frames,
15347                                  *n_values_per_frame,
15348                                  *type)
15349         != TNG_SUCCESS)
15350         {
15351             return(TNG_CRITICAL);
15352         }
15353     }
15354
15355     switch(*type)
15356     {
15357     case TNG_CHAR_DATA:
15358         for(i = 0; i < *n_frames; i++)
15359         {
15360             for(j = 0; j < *n_values_per_frame; j++)
15361             {
15362                 len = strlen(data->strings[i][j]) + 1;
15363                 (*values)[i][j].c = malloc(len);
15364                 strncpy((*values)[i][j].c, data->strings[i][j], len);
15365             }
15366         }
15367         break;
15368     case TNG_INT_DATA:
15369         size = sizeof(int);
15370         for(i = 0; i < *n_frames; i++)
15371         {
15372             for(j = 0; j < *n_values_per_frame; j++)
15373             {
15374                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15375                                              (i*(*n_values_per_frame) + j));
15376             }
15377         }
15378         break;
15379     case TNG_FLOAT_DATA:
15380         size = sizeof(float);
15381         for(i = 0; i < *n_frames; i++)
15382         {
15383             for(j = 0; j < *n_values_per_frame; j++)
15384             {
15385                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15386                                                (i*(*n_values_per_frame) + j));
15387             }
15388         }
15389         break;
15390     case TNG_DOUBLE_DATA:
15391     default:
15392         size = sizeof(double);
15393         for(i = 0; i < *n_frames; i++)
15394         {
15395             for(j = 0; j < *n_values_per_frame; j++)
15396             {
15397                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15398                                                 (i*(*n_values_per_frame) + j));
15399             }
15400         }
15401     }
15402
15403     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15404
15405     return(TNG_SUCCESS);
15406 }
15407
15408 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
15409                                         const int64_t block_id,
15410                                         void **values,
15411                                         int64_t *n_frames,
15412                                         int64_t *stride_length,
15413                                         int64_t *n_values_per_frame,
15414                                         char *type)
15415 {
15416     int64_t file_pos, data_size, n_frames_div, block_index;
15417     int i, size;
15418     tng_non_particle_data_t data;
15419     tng_trajectory_frame_set_t frame_set;
15420     tng_gen_block_t block;
15421     void *temp;
15422     tng_function_status stat;
15423
15424     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15425     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15426     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15427     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15428     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15429
15430     frame_set = &tng_data->current_trajectory_frame_set;
15431
15432     block_index = -1;
15433     data = 0;
15434
15435     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15436     {
15437         tng_block_init(&block);
15438         file_pos = ftello(tng_data->input_file);
15439         /* Read all blocks until next frame set block */
15440         stat = tng_block_header_read(tng_data, block);
15441         while(file_pos < tng_data->input_file_len &&
15442                 stat != TNG_CRITICAL &&
15443                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15444                 block->id != -1)
15445         {
15446             /* Use hash by default */
15447             stat = tng_block_read_next(tng_data, block,
15448                                     TNG_USE_HASH);
15449             if(stat != TNG_CRITICAL)
15450             {
15451                 file_pos = ftello(tng_data->input_file);
15452                 if(file_pos < tng_data->input_file_len)
15453                 {
15454                     stat = tng_block_header_read(tng_data, block);
15455                 }
15456             }
15457         }
15458         tng_block_destroy(&block);
15459         if(stat == TNG_CRITICAL)
15460         {
15461             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15462                     file_pos, __FILE__, __LINE__);
15463             return(stat);
15464         }
15465
15466         for(i = 0; i < frame_set->n_data_blocks; i++)
15467         {
15468             data = &frame_set->tr_data[i];
15469             if(data->block_id == block_id)
15470             {
15471                 block_index = i;
15472                 break;
15473             }
15474         }
15475         if(block_index < 0)
15476         {
15477             return(TNG_FAILURE);
15478         }
15479     }
15480
15481     *type = data->datatype;
15482
15483     switch(*type)
15484     {
15485     case TNG_CHAR_DATA:
15486         return(TNG_FAILURE);
15487     case TNG_INT_DATA:
15488         size = sizeof(int64_t);
15489         break;
15490     case TNG_FLOAT_DATA:
15491         size = sizeof(float);
15492         break;
15493     case TNG_DOUBLE_DATA:
15494     default:
15495         size = sizeof(double);
15496     }
15497
15498     *n_frames = data->n_frames;
15499     *n_values_per_frame = data->n_values_per_frame;
15500     *stride_length = data->stride_length;
15501     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
15502                    *n_frames / *stride_length;
15503
15504     data_size = n_frames_div * size *
15505                 *n_values_per_frame;
15506
15507     temp = realloc(*values, data_size);
15508     if(!temp)
15509     {
15510         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15511                data_size, __FILE__, __LINE__);
15512         free(*values);
15513         *values = 0;
15514         return(TNG_CRITICAL);
15515     }
15516
15517     *values = temp;
15518
15519     memcpy(*values, data->values, data_size);
15520
15521     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15522
15523     return(TNG_SUCCESS);
15524 }
15525
15526 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
15527                 (tng_trajectory_t tng_data,
15528                  const int64_t block_id,
15529                  const int64_t start_frame_nr,
15530                  const int64_t end_frame_nr,
15531                  const char hash_mode,
15532                  union data_values ***values,
15533                  int64_t *n_values_per_frame,
15534                  char *type)
15535 {
15536     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
15537     int64_t block_index;
15538     int size;
15539     size_t len;
15540     tng_non_particle_data_t data;
15541     tng_trajectory_frame_set_t frame_set;
15542     tng_gen_block_t block;
15543     tng_function_status stat;
15544
15545     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15546     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15547     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15548     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15549
15550     block_index = -1;
15551
15552     frame_set = &tng_data->current_trajectory_frame_set;
15553     first_frame = frame_set->first_frame;
15554
15555     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15556     if(stat != TNG_SUCCESS)
15557     {
15558         return(stat);
15559     }
15560
15561
15562     /* Do not re-read the frame set. */
15563     if(first_frame != frame_set->first_frame ||
15564        frame_set->n_data_blocks <= 0)
15565     {
15566         tng_block_init(&block);
15567         file_pos = ftello(tng_data->input_file);
15568         /* Read all blocks until next frame set block */
15569         stat = tng_block_header_read(tng_data, block);
15570         while(file_pos < tng_data->input_file_len &&
15571             stat != TNG_CRITICAL &&
15572             block->id != TNG_TRAJECTORY_FRAME_SET &&
15573             block->id != -1)
15574         {
15575             stat = tng_block_read_next(tng_data, block,
15576                                     hash_mode);
15577             if(stat != TNG_CRITICAL)
15578             {
15579                 file_pos = ftello(tng_data->input_file);
15580                 if(file_pos < tng_data->input_file_len)
15581                 {
15582                     stat = tng_block_header_read(tng_data, block);
15583                 }
15584             }
15585         }
15586         tng_block_destroy(&block);
15587         if(stat == TNG_CRITICAL)
15588         {
15589             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15590                     file_pos, __FILE__, __LINE__);
15591             return(stat);
15592         }
15593     }
15594
15595
15596     /* See if there is a data block of this ID.
15597      * Start checking the last read frame set */
15598     for(i = 0; i < frame_set->n_data_blocks; i++)
15599     {
15600         data = &frame_set->tr_data[i];
15601         if(data->block_id == block_id)
15602         {
15603             block_index = i;
15604             break;
15605         }
15606     }
15607
15608     if(block_index < 0)
15609     {
15610         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
15611                 block_id, __FILE__, __LINE__);
15612         return(TNG_FAILURE);
15613     }
15614
15615     n_frames = end_frame_nr - start_frame_nr + 1;
15616     *n_values_per_frame = data->n_values_per_frame;
15617     *type = data->datatype;
15618
15619     if(*values == 0)
15620     {
15621         if(tng_data_values_alloc(tng_data, values, n_frames,
15622                                  *n_values_per_frame,
15623                                  *type) != TNG_SUCCESS)
15624         {
15625             return(TNG_CRITICAL);
15626         }
15627     }
15628
15629     current_frame_pos = start_frame_nr - frame_set->first_frame;
15630     /* It's not very elegant to reuse so much of the code in the different case
15631      * statements, but it's unnecessarily slow to have the switch-case block
15632      * inside the for loops. */
15633     switch(*type)
15634     {
15635     case TNG_CHAR_DATA:
15636         for(i=0; i<n_frames; i++)
15637         {
15638             if(current_frame_pos == frame_set->n_frames)
15639             {
15640                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15641                 if(stat != TNG_SUCCESS)
15642                 {
15643                     return(stat);
15644                 }
15645                 current_frame_pos = 0;
15646             }
15647             for(j = 0; j < *n_values_per_frame; j++)
15648             {
15649                 len = strlen(data->strings[current_frame_pos][j]) + 1;
15650                 (*values)[i][j].c = malloc(len);
15651                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
15652             }
15653             current_frame_pos++;
15654         }
15655         break;
15656     case TNG_INT_DATA:
15657         size = sizeof(int);
15658         for(i=0; i<n_frames; i++)
15659         {
15660             if(current_frame_pos == frame_set->n_frames)
15661             {
15662                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15663                 if(stat != TNG_SUCCESS)
15664                 {
15665                     return(stat);
15666                 }
15667                 current_frame_pos = 0;
15668             }
15669             for(j = 0; j < *n_values_per_frame; j++)
15670             {
15671                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15672                                             (current_frame_pos *
15673                                              (*n_values_per_frame) + j));
15674             }
15675             current_frame_pos++;
15676         }
15677         break;
15678     case TNG_FLOAT_DATA:
15679         size = sizeof(float);
15680         for(i=0; i<n_frames; i++)
15681         {
15682             if(current_frame_pos == frame_set->n_frames)
15683             {
15684                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15685                 if(stat != TNG_SUCCESS)
15686                 {
15687                     return(stat);
15688                 }
15689                 current_frame_pos = 0;
15690             }
15691             for(j = 0; j < *n_values_per_frame; j++)
15692             {
15693                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15694                                                (current_frame_pos *
15695                                                 (*n_values_per_frame) + j));
15696             }
15697             current_frame_pos++;
15698         }
15699         break;
15700     case TNG_DOUBLE_DATA:
15701     default:
15702         size = sizeof(double);
15703         for(i=0; i<n_frames; i++)
15704         {
15705             if(current_frame_pos == frame_set->n_frames)
15706             {
15707                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15708                 if(stat != TNG_SUCCESS)
15709                 {
15710                     return(stat);
15711                 }
15712                 current_frame_pos = 0;
15713             }
15714             for(j = 0; j < *n_values_per_frame; j++)
15715             {
15716                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15717                                                 (current_frame_pos *
15718                                                  (*n_values_per_frame) + j));
15719             }
15720             current_frame_pos++;
15721         }
15722     }
15723
15724     data->last_retrieved_frame = end_frame_nr;
15725
15726     return(TNG_SUCCESS);
15727 }
15728
15729 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
15730                 (tng_trajectory_t tng_data,
15731                  const int64_t block_id,
15732                  const int64_t start_frame_nr,
15733                  const int64_t end_frame_nr,
15734                  const char hash_mode,
15735                  void **values,
15736                  int64_t *stride_length,
15737                  int64_t *n_values_per_frame,
15738                  char *type)
15739 {
15740     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15741     int64_t file_pos, current_frame_pos, data_size, frame_size;
15742     int64_t last_frame_pos;
15743     int size;
15744     tng_trajectory_frame_set_t frame_set;
15745     tng_non_particle_data_t np_data;
15746     tng_gen_block_t block;
15747     void *current_values = 0, *temp;
15748     tng_function_status stat;
15749
15750     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15751     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15752     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15753     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15754     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15755
15756     frame_set = &tng_data->current_trajectory_frame_set;
15757     first_frame = frame_set->first_frame;
15758
15759     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15760     if(stat != TNG_SUCCESS)
15761     {
15762         return(stat);
15763     }
15764
15765     /* Do not re-read the frame set and only need the requested block. */
15766     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
15767     stat = tng_data_find(tng_data, block_id, &np_data);
15768     if(first_frame != frame_set->first_frame ||
15769        stat != TNG_SUCCESS)
15770     {
15771         tng_block_init(&block);
15772         if(stat != TNG_SUCCESS)
15773         {
15774             fseeko(tng_data->input_file,
15775                    tng_data->current_trajectory_frame_set_input_file_pos,
15776                    SEEK_SET);
15777             stat = tng_block_header_read(tng_data, block);
15778             if(stat != TNG_SUCCESS)
15779             {
15780                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15781                         __FILE__, __LINE__);
15782                 return(stat);
15783             }
15784
15785             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
15786         }
15787         file_pos = ftello(tng_data->input_file);
15788         /* Read until next frame set block */
15789         stat = tng_block_header_read(tng_data, block);
15790         while(file_pos < tng_data->input_file_len &&
15791             stat != TNG_CRITICAL &&
15792             block->id != TNG_TRAJECTORY_FRAME_SET &&
15793             block->id != -1)
15794         {
15795             if(block->id == block_id)
15796             {
15797                 stat = tng_block_read_next(tng_data, block,
15798                                         hash_mode);
15799                 if(stat != TNG_CRITICAL)
15800                 {
15801                     file_pos = ftello(tng_data->input_file);
15802                     if(file_pos < tng_data->input_file_len)
15803                     {
15804                         stat = tng_block_header_read(tng_data, block);
15805                     }
15806                 }
15807             }
15808             else
15809             {
15810                 file_pos += block->block_contents_size + block->header_contents_size;
15811                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
15812                 if(file_pos < tng_data->input_file_len)
15813                 {
15814                     stat = tng_block_header_read(tng_data, block);
15815                 }
15816             }
15817         }
15818         tng_block_destroy(&block);
15819         if(stat == TNG_CRITICAL)
15820         {
15821             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15822                     file_pos, __FILE__, __LINE__);
15823             return(stat);
15824         }
15825     }
15826
15827     stat = tng_data_find(tng_data, block_id, &np_data);
15828     if(stat != TNG_SUCCESS)
15829     {
15830         return(stat);
15831     }
15832
15833     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15834                                &n_frames, stride_length,
15835                                n_values_per_frame, type);
15836
15837     if(stat != TNG_SUCCESS)
15838     {
15839         if(current_values)
15840         {
15841             free(current_values);
15842         }
15843         return(stat);
15844     }
15845
15846     if(n_frames == 1 && n_frames < frame_set->n_frames)
15847     {
15848         tot_n_frames = 1;
15849     }
15850     else
15851     {
15852         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15853     }
15854
15855     switch(*type)
15856     {
15857     case TNG_CHAR_DATA:
15858         return(TNG_FAILURE);
15859     case TNG_INT_DATA:
15860         size = sizeof(int64_t);
15861         break;
15862     case TNG_FLOAT_DATA:
15863         size = sizeof(float);
15864         break;
15865     case TNG_DOUBLE_DATA:
15866     default:
15867         size = sizeof(double);
15868     }
15869
15870     n_frames_div = (tot_n_frames % *stride_length) ?
15871                  tot_n_frames / *stride_length + 1:
15872                  tot_n_frames / *stride_length;
15873     data_size = n_frames_div * size * (*n_values_per_frame);
15874
15875 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15876               size, n_frames_div, data_size);
15877 */
15878     temp = realloc(*values, data_size);
15879     if(!temp)
15880     {
15881         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15882                data_size, __FILE__, __LINE__);
15883         free(*values);
15884         *values = 0;
15885         return(TNG_CRITICAL);
15886     }
15887
15888     *values = temp;
15889
15890     if( n_frames == 1 && n_frames < frame_set->n_frames)
15891     {
15892         memcpy(*values, current_values, size * (*n_values_per_frame));
15893     }
15894     else
15895     {
15896         current_frame_pos = start_frame_nr - frame_set->first_frame;
15897
15898         frame_size = size * (*n_values_per_frame);
15899
15900         last_frame_pos = tng_min_i64(n_frames,
15901                                      end_frame_nr - start_frame_nr);
15902
15903         n_frames_div = current_frame_pos / *stride_length;
15904         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15905                        last_frame_pos / *stride_length + 1:
15906                        last_frame_pos / *stride_length;
15907         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15908
15909         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15910                n_frames_div_2 * frame_size);
15911
15912         current_frame_pos += n_frames - current_frame_pos;
15913
15914         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15915         {
15916             stat = tng_frame_set_read_next(tng_data, hash_mode);
15917             if(stat != TNG_SUCCESS)
15918             {
15919                 if(current_values)
15920                 {
15921                     free(current_values);
15922                 }
15923                 free(*values);
15924                 *values = 0;
15925                 return(stat);
15926             }
15927
15928             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15929                                     &n_frames, stride_length,
15930                                     n_values_per_frame, type);
15931
15932             if(stat != TNG_SUCCESS)
15933             {
15934                 if(current_values)
15935                 {
15936                     free(current_values);
15937                 }
15938                 free(*values);
15939                 *values = 0;
15940                 return(stat);
15941             }
15942
15943             last_frame_pos = tng_min_i64(n_frames,
15944                                          end_frame_nr - current_frame_pos);
15945
15946             n_frames_div = current_frame_pos / *stride_length;
15947             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15948                            last_frame_pos / *stride_length + 1:
15949                            last_frame_pos / *stride_length;
15950             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15951
15952             memcpy(((char *)*values) + n_frames_div * frame_size,
15953                    current_values,
15954                    n_frames_div_2 * frame_size);
15955
15956             current_frame_pos += n_frames;
15957         }
15958     }
15959
15960     if(current_values)
15961     {
15962         free(current_values);
15963     }
15964
15965     np_data->last_retrieved_frame = end_frame_nr;
15966
15967     return(TNG_SUCCESS);
15968 }
15969
15970 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15971                 (tng_trajectory_t tng_data,
15972                  const int64_t block_id,
15973                  union data_values ****values,
15974                  int64_t *n_frames,
15975                  int64_t *n_particles,
15976                  int64_t *n_values_per_frame,
15977                  char *type)
15978 {
15979     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15980     int size;
15981     size_t len;
15982     tng_particle_data_t data;
15983     tng_trajectory_frame_set_t frame_set;
15984     tng_gen_block_t block;
15985     char block_type_flag;
15986     tng_function_status stat;
15987
15988     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15989     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15990     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15991     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15992     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15993
15994     frame_set = &tng_data->current_trajectory_frame_set;
15995
15996     block_index = -1;
15997     data = 0;
15998
15999     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16000     {
16001         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16002         {
16003             block_type_flag = TNG_TRAJECTORY_BLOCK;
16004         }
16005         else
16006         {
16007             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16008         }
16009
16010         tng_block_init(&block);
16011         file_pos = ftello(tng_data->input_file);
16012         /* Read all blocks until next frame set block */
16013         stat = tng_block_header_read(tng_data, block);
16014         while(file_pos < tng_data->input_file_len &&
16015                 stat != TNG_CRITICAL &&
16016                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16017                 block->id != -1)
16018         {
16019             /* Use hash by default */
16020             stat = tng_block_read_next(tng_data, block,
16021                                     TNG_USE_HASH);
16022             if(stat != TNG_CRITICAL)
16023             {
16024                 file_pos = ftello(tng_data->input_file);
16025                 if(file_pos < tng_data->input_file_len)
16026                 {
16027                     stat = tng_block_header_read(tng_data, block);
16028                 }
16029             }
16030         }
16031         tng_block_destroy(&block);
16032         if(stat == TNG_CRITICAL)
16033         {
16034             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16035                     file_pos, __FILE__, __LINE__);
16036             return(stat);
16037         }
16038
16039         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16040         {
16041             data = &frame_set->tr_particle_data[i];
16042             if(data->block_id == block_id)
16043             {
16044                 block_index = i;
16045                 block_type_flag = TNG_TRAJECTORY_BLOCK;
16046                 break;
16047             }
16048         }
16049         if(block_index < 0)
16050         {
16051             return(TNG_FAILURE);
16052         }
16053     }
16054     else
16055     {
16056         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16057         {
16058             block_type_flag = TNG_TRAJECTORY_BLOCK;
16059         }
16060         else
16061         {
16062             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16063         }
16064     }
16065
16066     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16067        tng_data->var_num_atoms_flag)
16068     {
16069         *n_particles = frame_set->n_particles;
16070     }
16071     else
16072     {
16073         *n_particles = tng_data->n_particles;
16074     }
16075
16076     *n_frames = tng_max_i64(1, data->n_frames);
16077     *n_values_per_frame = data->n_values_per_frame;
16078     *type = data->datatype;
16079
16080     if(*values == 0)
16081     {
16082         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
16083                                          *n_particles, *n_values_per_frame,
16084                                          *type)
16085             != TNG_SUCCESS)
16086         {
16087             return(TNG_CRITICAL);
16088         }
16089     }
16090
16091     /* It's not very elegant to reuse so much of the code in the different case
16092      * statements, but it's unnecessarily slow to have the switch-case block
16093      * inside the for loops. */
16094     switch(*type)
16095     {
16096     case TNG_CHAR_DATA:
16097         for(i = 0; i < *n_frames; i++)
16098         {
16099             for(j = 0; j < *n_particles; j++)
16100             {
16101                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16102                 for(k = 0; k < *n_values_per_frame; k++)
16103                 {
16104                     len = strlen(data->strings[i][j][k]) + 1;
16105                     (*values)[i][mapping][k].c = malloc(len);
16106                     strncpy((*values)[i][mapping][k].c,
16107                             data->strings[i][j][k], len);
16108                 }
16109             }
16110         }
16111         break;
16112     case TNG_INT_DATA:
16113         size = sizeof(int);
16114         i_step = (*n_particles) * (*n_values_per_frame);
16115         for(i = 0; i < *n_frames; i++)
16116         {
16117             for(j = 0; j < *n_particles; j++)
16118             {
16119                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16120                 for(k = 0; k < *n_values_per_frame; k++)
16121                 {
16122                     (*values)[i][mapping][k].i = *(int *)
16123                                                  ((char *)data->values + size *
16124                                                  (i * i_step + j *
16125                                                   (*n_values_per_frame) + k));
16126                 }
16127             }
16128         }
16129         break;
16130     case TNG_FLOAT_DATA:
16131         size = sizeof(float);
16132         i_step = (*n_particles) * (*n_values_per_frame);
16133         for(i = 0; i < *n_frames; i++)
16134         {
16135             for(j = 0; j < *n_particles; j++)
16136             {
16137                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16138                 for(k = 0; k < *n_values_per_frame; k++)
16139                 {
16140                     (*values)[i][mapping][k].f = *(float *)
16141                                                  ((char *)data->values + size *
16142                                                  (i * i_step + j *
16143                                                   (*n_values_per_frame) + k));
16144                 }
16145             }
16146         }
16147         break;
16148     case TNG_DOUBLE_DATA:
16149     default:
16150         size = sizeof(double);
16151         i_step = (*n_particles) * (*n_values_per_frame);
16152         for(i = 0; i < *n_frames; i++)
16153         {
16154             for(j = 0; j < *n_particles; j++)
16155             {
16156                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16157                 for(k = 0; k < *n_values_per_frame; k++)
16158                 {
16159                     (*values)[i][mapping][k].d = *(double *)
16160                                                  ((char *)data->values + size *
16161                                                  (i * i_step + j *
16162                                                   (*n_values_per_frame) + k));
16163                 }
16164             }
16165         }
16166     }
16167
16168     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16169
16170     return(TNG_SUCCESS);
16171 }
16172
16173 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
16174                 (tng_trajectory_t tng_data,
16175                  const int64_t block_id,
16176                  void **values,
16177                  int64_t *n_frames,
16178                  int64_t *stride_length,
16179                  int64_t *n_particles,
16180                  int64_t *n_values_per_frame,
16181                  char *type)
16182 {
16183     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
16184     int64_t block_index;
16185     int size;
16186     tng_particle_data_t data;
16187     tng_trajectory_frame_set_t frame_set;
16188     tng_gen_block_t block;
16189     void *temp;
16190     char block_type_flag;
16191     tng_function_status stat;
16192
16193     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16194     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16195     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16196     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16197     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16198
16199     frame_set = &tng_data->current_trajectory_frame_set;
16200
16201     block_index = -1;
16202     data = 0;
16203
16204     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16205     {
16206         tng_block_init(&block);
16207         file_pos = ftello(tng_data->input_file);
16208         /* Read all blocks until next frame set block */
16209         stat = tng_block_header_read(tng_data, block);
16210         while(file_pos < tng_data->input_file_len &&
16211                 stat != TNG_CRITICAL &&
16212                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16213                 block->id != -1)
16214         {
16215             /* Use hash by default */
16216             stat = tng_block_read_next(tng_data, block,
16217                                     TNG_USE_HASH);
16218             if(stat != TNG_CRITICAL)
16219             {
16220                 file_pos = ftello(tng_data->input_file);
16221                 if(file_pos < tng_data->input_file_len)
16222                 {
16223                     stat = tng_block_header_read(tng_data, block);
16224                 }
16225             }
16226         }
16227         tng_block_destroy(&block);
16228         if(stat == TNG_CRITICAL)
16229         {
16230             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16231                     file_pos, __FILE__, __LINE__);
16232             return(stat);
16233         }
16234
16235         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16236         {
16237             data = &frame_set->tr_particle_data[i];
16238             if(data->block_id == block_id)
16239             {
16240                 block_index = i;
16241                 break;
16242             }
16243         }
16244         if(block_index < 0)
16245         {
16246             return(TNG_FAILURE);
16247         }
16248     }
16249
16250     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16251     {
16252         block_type_flag = TNG_TRAJECTORY_BLOCK;
16253     }
16254     else
16255     {
16256         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16257     }
16258
16259    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16260       tng_data->var_num_atoms_flag)
16261     {
16262         *n_particles = frame_set->n_particles;
16263     }
16264     else
16265     {
16266         *n_particles = tng_data->n_particles;
16267     }
16268
16269     *type = data->datatype;
16270
16271     switch(*type)
16272     {
16273     case TNG_CHAR_DATA:
16274         return(TNG_FAILURE);
16275     case TNG_INT_DATA:
16276         size = sizeof(int64_t);
16277         break;
16278     case TNG_FLOAT_DATA:
16279         size = sizeof(float);
16280         break;
16281     case TNG_DOUBLE_DATA:
16282     default:
16283         size = sizeof(double);
16284     }
16285
16286     *n_frames = tng_max_i64(1, data->n_frames);
16287     *n_values_per_frame = data->n_values_per_frame;
16288     *stride_length = data->stride_length;
16289
16290     n_frames_div = (*n_frames % *stride_length) ?
16291                    *n_frames / *stride_length + 1:
16292                    *n_frames / *stride_length;
16293
16294     data_size = n_frames_div * size * (*n_particles) *
16295                 (*n_values_per_frame);
16296
16297     temp = realloc(*values, data_size);
16298     if(!temp)
16299     {
16300         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16301                data_size, __FILE__, __LINE__);
16302         free(*values);
16303         *values = 0;
16304         return(TNG_CRITICAL);
16305     }
16306
16307     *values = temp;
16308
16309     if(frame_set->n_mapping_blocks <= 0)
16310     {
16311         memcpy(*values, data->values, data_size);
16312     }
16313     else
16314     {
16315         i_step = (*n_particles) * (*n_values_per_frame);
16316         for(i = 0; i < *n_frames; i++)
16317         {
16318             for(j = 0; j < *n_particles; j++)
16319             {
16320                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16321                 memcpy(((char *)*values) + size * (i * i_step + mapping *
16322                        (*n_values_per_frame)),
16323                        (char *)data->values + size *
16324                        (i * i_step + j * (*n_values_per_frame)),
16325                        size * (*n_values_per_frame));
16326             }
16327         }
16328     }
16329
16330     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16331
16332     return(TNG_SUCCESS);
16333 }
16334
16335 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
16336                 (tng_trajectory_t tng_data,
16337                  const int64_t block_id,
16338                  const int64_t start_frame_nr,
16339                  const int64_t end_frame_nr,
16340                  const char hash_mode,
16341                  union data_values ****values,
16342                  int64_t *n_particles,
16343                  int64_t *n_values_per_frame,
16344                  char *type)
16345 {
16346     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
16347     int64_t first_frame, block_index;
16348     int size;
16349     size_t len;
16350     tng_particle_data_t data;
16351     tng_trajectory_frame_set_t frame_set;
16352     tng_gen_block_t block;
16353     char block_type_flag;
16354     tng_function_status stat;
16355
16356     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16357     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16358     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16359     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16360     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16361
16362     block_index = -1;
16363
16364     frame_set = &tng_data->current_trajectory_frame_set;
16365     first_frame = frame_set->first_frame;
16366
16367     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16368     if(stat != TNG_SUCCESS)
16369     {
16370         return(stat);
16371     }
16372
16373     /* Do not re-read the frame set. */
16374     if(first_frame != frame_set->first_frame ||
16375        frame_set->n_particle_data_blocks <= 0)
16376     {
16377         tng_block_init(&block);
16378         file_pos = ftello(tng_data->input_file);
16379         /* Read all blocks until next frame set block */
16380         stat = tng_block_header_read(tng_data, block);
16381         while(file_pos < tng_data->input_file_len &&
16382                 stat != TNG_CRITICAL &&
16383                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16384                 block->id != -1)
16385         {
16386             stat = tng_block_read_next(tng_data, block,
16387                                     hash_mode);
16388             if(stat != TNG_CRITICAL)
16389             {
16390                 file_pos = ftello(tng_data->input_file);
16391                 if(file_pos < tng_data->input_file_len)
16392                 {
16393                     stat = tng_block_header_read(tng_data, block);
16394                 }
16395             }
16396         }
16397         tng_block_destroy(&block);
16398         if(stat == TNG_CRITICAL)
16399         {
16400             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16401                     file_pos, __FILE__, __LINE__);
16402             return(stat);
16403         }
16404     }
16405
16406     /* See if there is already a data block of this ID.
16407      * Start checking the last read frame set */
16408     for(i = frame_set->n_particle_data_blocks; i-- ;)
16409     {
16410         data = &frame_set->tr_particle_data[i];
16411         if(data->block_id == block_id)
16412         {
16413             block_index = i;
16414             block_type_flag = TNG_TRAJECTORY_BLOCK;
16415             break;
16416         }
16417     }
16418
16419     if(block_index < 0)
16420     {
16421         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
16422                 block_id, __FILE__, __LINE__);
16423         return(TNG_FAILURE);
16424     }
16425
16426     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16427        tng_data->var_num_atoms_flag)
16428     {
16429         *n_particles = frame_set->n_particles;
16430     }
16431     else
16432     {
16433         *n_particles = tng_data->n_particles;
16434     }
16435
16436     n_frames = end_frame_nr - start_frame_nr + 1;
16437     *n_values_per_frame = data->n_values_per_frame;
16438     *type = data->datatype;
16439
16440     if(*values == 0)
16441     {
16442         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
16443                                          *n_particles, *n_values_per_frame,
16444                                          *type)
16445             != TNG_SUCCESS)
16446         {
16447             return(TNG_CRITICAL);
16448         }
16449     }
16450
16451     current_frame_pos = start_frame_nr - frame_set->first_frame;
16452     /* It's not very elegant to reuse so much of the code in the different case
16453      * statements, but it's unnecessarily slow to have the switch-case block
16454      * inside the for loops. */
16455     switch(*type)
16456     {
16457     case TNG_CHAR_DATA:
16458         for(i=0; i<n_frames; i++)
16459         {
16460             if(current_frame_pos == frame_set->n_frames)
16461             {
16462                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16463                 if(stat != TNG_SUCCESS)
16464                 {
16465                     return(stat);
16466                 }
16467                 current_frame_pos = 0;
16468             }
16469             for(j = 0; j < *n_particles; j++)
16470             {
16471                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16472                 for(k = 0; k < *n_values_per_frame; k++)
16473                 {
16474                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
16475                     (*values)[i][mapping][k].c = malloc(len);
16476                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
16477                 }
16478             }
16479             current_frame_pos++;
16480         }
16481         break;
16482     case TNG_INT_DATA:
16483         size = sizeof(int);
16484         i_step = (*n_particles) * (*n_values_per_frame);
16485         for(i=0; i<n_frames; i++)
16486         {
16487             if(current_frame_pos == frame_set->n_frames)
16488             {
16489                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16490                 if(stat != TNG_SUCCESS)
16491                 {
16492                     return(stat);
16493                 }
16494                 current_frame_pos = 0;
16495             }
16496             for(j = 0; j < *n_particles; j++)
16497             {
16498                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16499                 for(k = 0; k < *n_values_per_frame; k++)
16500                 {
16501                     (*values)[i][mapping][k].i = *(int *)
16502                                                  ((char *)data->values + size *
16503                                                   (current_frame_pos *
16504                                                    i_step + j *
16505                                                    (*n_values_per_frame) + k));
16506                 }
16507             }
16508             current_frame_pos++;
16509         }
16510         break;
16511     case TNG_FLOAT_DATA:
16512         size = sizeof(float);
16513         i_step = (*n_particles) * (*n_values_per_frame);
16514         for(i=0; i<n_frames; i++)
16515         {
16516             if(current_frame_pos == frame_set->n_frames)
16517             {
16518                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16519                 if(stat != TNG_SUCCESS)
16520                 {
16521                     return(stat);
16522                 }
16523                 current_frame_pos = 0;
16524             }
16525             for(j=0; j<*n_particles; j++)
16526             {
16527                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16528                 for(k=0; k<*n_values_per_frame; k++)
16529                 {
16530                     (*values)[i][mapping][k].f = *(float *)
16531                                                  ((char *)data->values + size *
16532                                                   (current_frame_pos *
16533                                                    i_step + j *
16534                                                    (*n_values_per_frame) + k));
16535                 }
16536             }
16537             current_frame_pos++;
16538         }
16539         break;
16540     case TNG_DOUBLE_DATA:
16541     default:
16542         size = sizeof(double);
16543         i_step = (*n_particles) * (*n_values_per_frame);
16544         for(i=0; i<n_frames; i++)
16545         {
16546             if(current_frame_pos == frame_set->n_frames)
16547             {
16548                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16549                 if(stat != TNG_SUCCESS)
16550                 {
16551                     return(stat);
16552                 }
16553                 current_frame_pos = 0;
16554             }
16555             for(j=0; j<*n_particles; j++)
16556             {
16557                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16558                 for(k=0; k<*n_values_per_frame; k++)
16559                 {
16560                     (*values)[i][mapping][k].d = *(double *)
16561                                                  ((char *)data->values + size *
16562                                                   (current_frame_pos *
16563                                                    i_step + j *
16564                                                    (*n_values_per_frame) + k));
16565                 }
16566             }
16567             current_frame_pos++;
16568         }
16569     }
16570
16571     data->last_retrieved_frame = end_frame_nr;
16572
16573     return(TNG_SUCCESS);
16574 }
16575
16576 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
16577                 (tng_trajectory_t tng_data,
16578                  const int64_t block_id,
16579                  const int64_t start_frame_nr,
16580                  const int64_t end_frame_nr,
16581                  const char hash_mode,
16582                  void **values,
16583                  int64_t *n_particles,
16584                  int64_t *stride_length,
16585                  int64_t *n_values_per_frame,
16586                  char *type)
16587 {
16588     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
16589     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
16590     int size;
16591     tng_trajectory_frame_set_t frame_set;
16592     tng_particle_data_t p_data;
16593     tng_gen_block_t block;
16594     void *current_values = 0, *temp;
16595     tng_function_status stat;
16596
16597     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16598     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16599     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16600     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16601     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16602     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16603
16604     frame_set = &tng_data->current_trajectory_frame_set;
16605     first_frame = frame_set->first_frame;
16606
16607     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16608     if(stat != TNG_SUCCESS)
16609     {
16610         return(stat);
16611     }
16612
16613     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
16614     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
16615     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16616     if(first_frame != frame_set->first_frame ||
16617        stat != TNG_SUCCESS)
16618     {
16619         tng_block_init(&block);
16620         if(stat != TNG_SUCCESS)
16621         {
16622             fseeko(tng_data->input_file,
16623                    tng_data->current_trajectory_frame_set_input_file_pos,
16624                    SEEK_SET);
16625             stat = tng_block_header_read(tng_data, block);
16626             if(stat != TNG_SUCCESS)
16627             {
16628                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
16629                         __FILE__, __LINE__);
16630                 return(stat);
16631             }
16632
16633             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
16634         }
16635         file_pos = ftello(tng_data->input_file);
16636         /* Read until next frame set block */
16637         stat = tng_block_header_read(tng_data, block);
16638         while(file_pos < tng_data->input_file_len &&
16639             stat != TNG_CRITICAL &&
16640             block->id != TNG_TRAJECTORY_FRAME_SET &&
16641             block->id != -1)
16642         {
16643             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
16644             {
16645                 stat = tng_block_read_next(tng_data, block,
16646                                         hash_mode);
16647                 if(stat != TNG_CRITICAL)
16648                 {
16649                     file_pos = ftello(tng_data->input_file);
16650                     if(file_pos < tng_data->input_file_len)
16651                     {
16652                         stat = tng_block_header_read(tng_data, block);
16653                     }
16654                 }
16655             }
16656             else
16657             {
16658                 file_pos += block->block_contents_size + block->header_contents_size;
16659                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
16660                 if(file_pos < tng_data->input_file_len)
16661                 {
16662                     stat = tng_block_header_read(tng_data, block);
16663                 }
16664             }
16665         }
16666         tng_block_destroy(&block);
16667         if(stat == TNG_CRITICAL)
16668         {
16669             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16670                     file_pos, __FILE__, __LINE__);
16671             return(stat);
16672         }
16673     }
16674     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16675     if(stat != TNG_SUCCESS)
16676     {
16677         return(stat);
16678     }
16679
16680     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16681                                         &n_frames, stride_length, n_particles,
16682                                         n_values_per_frame, type);
16683
16684     if(stat != TNG_SUCCESS || *n_particles == 0)
16685     {
16686         if(current_values)
16687         {
16688             free(current_values);
16689         }
16690         return(stat);
16691     }
16692
16693     if(n_frames == 1 && n_frames < frame_set->n_frames)
16694     {
16695         tot_n_frames = 1;
16696     }
16697     else
16698     {
16699         tot_n_frames = end_frame_nr - start_frame_nr + 1;
16700     }
16701
16702     switch(*type)
16703     {
16704     case TNG_CHAR_DATA:
16705         return(TNG_FAILURE);
16706     case TNG_INT_DATA:
16707         size = sizeof(int64_t);
16708         break;
16709     case TNG_FLOAT_DATA:
16710         size = sizeof(float);
16711         break;
16712     case TNG_DOUBLE_DATA:
16713     default:
16714         size = sizeof(double);
16715     }
16716
16717     n_frames_div = (tot_n_frames % *stride_length) ?
16718                  tot_n_frames / *stride_length + 1:
16719                  tot_n_frames / *stride_length;
16720
16721     data_size = n_frames_div * size * (*n_particles) *
16722                 (*n_values_per_frame);
16723
16724     temp = realloc(*values, data_size);
16725     if(!temp)
16726     {
16727         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16728                data_size, __FILE__, __LINE__);
16729         free(*values);
16730         *values = 0;
16731         return(TNG_CRITICAL);
16732     }
16733
16734     *values = temp;
16735
16736     if( n_frames == 1 && n_frames < frame_set->n_frames)
16737     {
16738         memcpy(*values, current_values, size * (*n_particles) *
16739                (*n_values_per_frame));
16740     }
16741     else
16742     {
16743         current_frame_pos = start_frame_nr - frame_set->first_frame;
16744
16745         frame_size = size * (*n_particles) * (*n_values_per_frame);
16746
16747         last_frame_pos = tng_min_i64(n_frames,
16748                                      end_frame_nr - start_frame_nr);
16749
16750         n_frames_div = current_frame_pos / *stride_length;
16751         n_frames_div_2 = (last_frame_pos % *stride_length) ?
16752                        last_frame_pos / *stride_length + 1:
16753                        last_frame_pos / *stride_length;
16754         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
16755
16756         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
16757                n_frames_div_2 * frame_size);
16758
16759         current_frame_pos += n_frames - current_frame_pos;
16760
16761         while(current_frame_pos <= end_frame_nr - start_frame_nr)
16762         {
16763             stat = tng_frame_set_read_next(tng_data, hash_mode);
16764             if(stat != TNG_SUCCESS)
16765             {
16766                 if(current_values)
16767                 {
16768                     free(current_values);
16769                 }
16770                 free(*values);
16771                 *values = 0;
16772                 return(stat);
16773             }
16774
16775             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16776                                                 &n_frames, stride_length, n_particles,
16777                                                 n_values_per_frame, type);
16778
16779             if(stat != TNG_SUCCESS)
16780             {
16781                 if(current_values)
16782                 {
16783                     free(current_values);
16784                 }
16785                 free(*values);
16786                 *values = 0;
16787                 return(stat);
16788             }
16789
16790             last_frame_pos = tng_min_i64(n_frames,
16791                                          end_frame_nr - current_frame_pos);
16792
16793             n_frames_div = current_frame_pos / *stride_length;
16794             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16795                            last_frame_pos / *stride_length + 1:
16796                            last_frame_pos / *stride_length;
16797             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16798
16799             memcpy(((char *)*values) + n_frames_div * frame_size,
16800                    current_values,
16801                    n_frames_div_2 * frame_size);
16802
16803             current_frame_pos += n_frames;
16804         }
16805     }
16806
16807     if(current_values)
16808     {
16809         free(current_values);
16810     }
16811
16812     p_data->last_retrieved_frame = end_frame_nr;
16813
16814     return(TNG_SUCCESS);
16815 }
16816
16817 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16818                 (const tng_trajectory_t tng_data,
16819                  const int64_t block_id,
16820                  int64_t frame,
16821                  int64_t *stride_length)
16822 {
16823     tng_function_status stat;
16824     tng_non_particle_data_t np_data;
16825     tng_particle_data_t p_data;
16826     int64_t orig_file_pos, file_pos;
16827     int is_particle_data;
16828
16829     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16830     {
16831         frame = 0;
16832     }
16833
16834     if(frame >= 0)
16835     {
16836         stat = tng_frame_set_of_frame_find(tng_data, frame);
16837         if(stat != TNG_SUCCESS)
16838         {
16839             return(stat);
16840         }
16841     }
16842     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16843     stat = tng_data_find(tng_data, block_id, &np_data);
16844     if(stat != TNG_SUCCESS)
16845     {
16846         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16847         if(stat != TNG_SUCCESS)
16848         {
16849             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16850             /* If no specific frame was required read until this data block is found */
16851             if(frame < 0)
16852             {
16853                 file_pos = ftello(tng_data->input_file);
16854                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16855                 {
16856                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16857                     file_pos = ftello(tng_data->input_file);
16858                 }
16859             }
16860             if(stat != TNG_SUCCESS)
16861             {
16862                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16863
16864                 return(stat);
16865             }
16866             stat = tng_data_find(tng_data, block_id, &np_data);
16867             if(stat != TNG_SUCCESS)
16868             {
16869                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16870                 if(stat != TNG_SUCCESS)
16871                 {
16872                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16873
16874                     return(stat);
16875                 }
16876                 else
16877                 {
16878                     is_particle_data = 1;
16879                 }
16880             }
16881             else
16882             {
16883                 is_particle_data = 0;
16884             }
16885         }
16886         else
16887         {
16888             is_particle_data = 1;
16889         }
16890     }
16891     else
16892     {
16893         is_particle_data = 0;
16894     }
16895     if(is_particle_data)
16896     {
16897         *stride_length = p_data->stride_length;
16898     }
16899     else
16900     {
16901         *stride_length = np_data->stride_length;
16902     }
16903     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16904
16905     return(TNG_SUCCESS);
16906 }
16907
16908 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16909                 (const tng_trajectory_t tng_data,
16910                  char *time)
16911 {
16912     struct tm *time_data;
16913     time_t secs;
16914
16915     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16916     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16917
16918     secs = tng_data->time;
16919
16920     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16921     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16922              "%4d-%02d-%02d %02d:%02d:%02d",
16923              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16924              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16925
16926     return(TNG_SUCCESS);
16927 }
16928
16929
16930 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16931                 (const char *filename,
16932                  const char mode,
16933                  tng_trajectory_t *tng_data_p)
16934 {
16935     tng_function_status stat;
16936
16937     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16938
16939     if(mode != 'r' && mode != 'w' && mode != 'a')
16940     {
16941         return(TNG_FAILURE);
16942     }
16943
16944     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16945     {
16946         tng_trajectory_destroy(tng_data_p);
16947         return(TNG_CRITICAL);
16948     }
16949
16950     if(mode == 'r' || mode == 'a')
16951     {
16952         tng_input_file_set(*tng_data_p, filename);
16953
16954         /* Read the file headers */
16955         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16956
16957         stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16958
16959         if(stat != TNG_SUCCESS)
16960         {
16961             return(stat);
16962         }
16963     }
16964
16965     if(mode == 'w')
16966     {
16967         tng_output_file_set(*tng_data_p, filename);
16968     }
16969     else if(mode == 'a')
16970     {
16971         if((*tng_data_p)->output_file)
16972         {
16973             fclose((*tng_data_p)->output_file);
16974         }
16975         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
16976         fseeko((*tng_data_p)->input_file,
16977                (*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16978                SEEK_SET);
16979
16980         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16981         if(stat != TNG_SUCCESS)
16982         {
16983             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16984                    __FILE__, __LINE__);
16985         }
16986         (*tng_data_p)->output_file = 0;
16987
16988         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16989         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16990         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16991         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16992         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16993         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16994         if((*tng_data_p)->input_file)
16995         {
16996             fclose((*tng_data_p)->input_file);
16997             (*tng_data_p)->input_file = 0;
16998         }
16999         if((*tng_data_p)->input_file_path)
17000         {
17001             free((*tng_data_p)->input_file_path);
17002             (*tng_data_p)->input_file_path = 0;
17003         }
17004         tng_output_append_file_set(*tng_data_p, filename);
17005
17006         fseeko((*tng_data_p)->output_file, 0, SEEK_END);
17007     }
17008
17009     return(TNG_SUCCESS);
17010 }
17011
17012 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
17013                 (tng_trajectory_t *tng_data_p)
17014 {
17015     tng_trajectory_frame_set_t frame_set;
17016
17017     if(tng_data_p == 0)
17018     {
17019         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
17020                __FILE__, __LINE__);
17021         return(TNG_FAILURE);
17022     }
17023
17024     if(*tng_data_p == 0)
17025     {
17026         return(TNG_SUCCESS);
17027     }
17028
17029     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
17030
17031     if(frame_set->n_unwritten_frames > 0)
17032     {
17033         frame_set->n_frames = frame_set->n_unwritten_frames;
17034         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
17035     }
17036
17037     return(tng_trajectory_destroy(tng_data_p));
17038 }
17039
17040 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
17041                 (tng_trajectory_t tng_data,
17042                  const int64_t frame_nr,
17043                  double *time)
17044 {
17045     int64_t first_frame;
17046     tng_trajectory_frame_set_t frame_set;
17047     tng_function_status stat;
17048
17049     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17050     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
17051
17052     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
17053     if(stat != TNG_SUCCESS)
17054     {
17055         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
17056                frame_nr, __FILE__, __LINE__);
17057         return(stat);
17058     }
17059
17060     frame_set = &tng_data->current_trajectory_frame_set;
17061     first_frame = frame_set->first_frame;
17062
17063     if(tng_data->time_per_frame <= 0)
17064     {
17065         return(TNG_FAILURE);
17066     }
17067
17068     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
17069
17070     return(TNG_SUCCESS);
17071 }
17072
17073 /*
17074 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
17075                 (tng_trajectory_t tng_data,
17076                  int64_t *n_mols,
17077                  int64_t **molecule_cnt_list,
17078                  tng_molecule_t *mols)
17079 {
17080     tng_trajectory_frame_set_t frame_set;
17081
17082     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17083     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
17084
17085     *n_mols = tng_data->n_molecules;
17086
17087     frame_set = &tng_data->current_trajectory_frame_set;
17088     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
17089     {
17090         *molecule_cnt_list = frame_set->molecule_cnt_list;
17091     }
17092     else
17093     {
17094         *molecule_cnt_list = tng_data->molecule_cnt_list;
17095     }
17096
17097     *mols = tng_data->molecules;
17098
17099     return(TNG_SUCCESS);
17100 }
17101 */
17102 /*
17103 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
17104                 (tng_trajectory_t tng_data,
17105                  const char *name,
17106                  const int64_t cnt,
17107                  tng_molecule_t *mol)
17108 {
17109     tng_function_status stat;
17110
17111     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
17112     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
17113
17114     stat = tng_molecule_add(tng_data, name, mol);
17115     if(stat != TNG_SUCCESS)
17116     {
17117         return(stat);
17118     }
17119     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
17120
17121     return(stat);
17122 }
17123 */
17124 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
17125                 (tng_trajectory_t tng_data,
17126                  const tng_molecule_t mol,
17127                  int64_t *n_particles,
17128                  char ***names,
17129                  char ***types,
17130                  char ***res_names,
17131                  int64_t **res_ids,
17132                  char ***chain_names,
17133                  int64_t **chain_ids)
17134 {
17135     tng_atom_t atom;
17136     tng_residue_t res;
17137     tng_chain_t chain;
17138     int64_t i;
17139     (void)tng_data;
17140
17141     *n_particles = mol->n_atoms;
17142
17143     *names = malloc(sizeof(char *) * *n_particles);
17144     *types = malloc(sizeof(char *) * *n_particles);
17145     *res_names = malloc(sizeof(char *) * *n_particles);
17146     *chain_names = malloc(sizeof(char *) * *n_particles);
17147     *res_ids = malloc(sizeof(int64_t) * *n_particles);
17148     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
17149
17150     for(i = 0; i < *n_particles; i++)
17151     {
17152         atom = &mol->atoms[i];
17153         res = atom->residue;
17154         chain = res->chain;
17155         (*names)[i] = malloc(strlen(atom->name));
17156         strcpy(*names[i], atom->name);
17157         (*types)[i] = malloc(strlen(atom->atom_type));
17158         strcpy(*types[i], atom->atom_type);
17159         (*res_names)[i] = malloc(strlen(res->name));
17160         strcpy(*res_names[i], res->name);
17161         (*chain_names)[i] = malloc(strlen(chain->name));
17162         strcpy(*chain_names[i], chain->name);
17163         (*res_ids)[i] = res->id;
17164         (*chain_ids)[i] = chain->id;
17165     }
17166
17167     return(TNG_SUCCESS);
17168 }
17169
17170 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
17171                 (tng_trajectory_t tng_data,
17172                  tng_molecule_t mol,
17173                  const int64_t n_particles,
17174                  const char **names,
17175                  const char **types,
17176                  const char **res_names,
17177                  const int64_t *res_ids,
17178                  const char **chain_names,
17179                  const int64_t *chain_ids)
17180 {
17181     int64_t i;
17182     tng_chain_t chain;
17183     tng_residue_t residue;
17184     tng_atom_t atom;
17185     tng_function_status stat;
17186
17187     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17188     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
17189     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
17190     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
17191     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
17192     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
17193     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
17194
17195     for(i = 0; i < n_particles; i++)
17196     {
17197         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
17198            &chain) == TNG_FAILURE)
17199         {
17200             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
17201                                           &chain);
17202             if(stat != TNG_SUCCESS)
17203             {
17204                 return(stat);
17205             }
17206         }
17207         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
17208            &residue) == TNG_FAILURE)
17209         {
17210             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
17211                                          &residue);
17212             if(stat != TNG_SUCCESS)
17213             {
17214                 return(stat);
17215             }
17216         }
17217         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
17218         if(stat != TNG_SUCCESS)
17219         {
17220             return(stat);
17221         }
17222     }
17223     return(TNG_SUCCESS);
17224 }
17225
17226 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
17227                 (tng_trajectory_t tng_data,
17228                  float **positions, int64_t *stride_length)
17229 {
17230     int64_t n_frames, n_particles, n_values_per_frame;
17231     char type;
17232     tng_function_status stat;
17233
17234     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17235     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17236     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17237
17238     stat = tng_num_frames_get(tng_data, &n_frames);
17239     if(stat != TNG_SUCCESS)
17240     {
17241         return(stat);
17242     }
17243
17244     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17245                                                  0, n_frames - 1, TNG_USE_HASH,
17246                                                  (void **)positions,
17247                                                  &n_particles,
17248                                                  stride_length,
17249                                                  &n_values_per_frame,
17250                                                  &type);
17251
17252     return(stat);
17253 }
17254
17255 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
17256                 (tng_trajectory_t tng_data,
17257                  float **velocities, int64_t *stride_length)
17258 {
17259     int64_t n_frames, n_particles, n_values_per_frame;
17260     char type;
17261     tng_function_status stat;
17262
17263     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17264     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17265     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17266
17267     stat = tng_num_frames_get(tng_data, &n_frames);
17268     if(stat != TNG_SUCCESS)
17269     {
17270         return(stat);
17271     }
17272
17273     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17274                                                  0, n_frames - 1, TNG_USE_HASH,
17275                                                  (void **)velocities,
17276                                                  &n_particles,
17277                                                  stride_length,
17278                                                  &n_values_per_frame,
17279                                                  &type);
17280
17281     return(stat);
17282 }
17283
17284 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
17285                 (tng_trajectory_t tng_data,
17286                  float **forces, int64_t *stride_length)
17287 {
17288     int64_t n_frames, n_particles, n_values_per_frame;
17289     char type;
17290     tng_function_status stat;
17291
17292     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17293     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17294     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17295
17296     stat = tng_num_frames_get(tng_data, &n_frames);
17297     if(stat != TNG_SUCCESS)
17298     {
17299         return(stat);
17300     }
17301
17302     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17303                                                  0, n_frames - 1, TNG_USE_HASH,
17304                                                  (void **)forces,
17305                                                  &n_particles,
17306                                                  stride_length,
17307                                                  &n_values_per_frame,
17308                                                  &type);
17309
17310     return(stat);
17311 }
17312
17313 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
17314                 (tng_trajectory_t tng_data,
17315                  float **box_shape,
17316                  int64_t *stride_length)
17317 {
17318     int64_t n_frames, n_values_per_frame;
17319     char type;
17320     tng_function_status stat;
17321
17322     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17323     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17324     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17325
17326     stat = tng_num_frames_get(tng_data, &n_frames);
17327     if(stat != TNG_SUCCESS)
17328     {
17329         return(stat);
17330     }
17331
17332     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17333                                         0, n_frames - 1, TNG_USE_HASH,
17334                                         (void **)box_shape,
17335                                         stride_length,
17336                                         &n_values_per_frame,
17337                                         &type);
17338
17339     return(stat);
17340 }
17341
17342 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
17343                 (tng_trajectory_t tng_data,
17344                  const int64_t block_id,
17345                  void **values,
17346                  char *data_type,
17347                  int64_t *retrieved_frame_number,
17348                  double *retrieved_time)
17349 {
17350     tng_trajectory_frame_set_t frame_set;
17351     tng_particle_data_t data = 0;
17352     tng_function_status stat;
17353     int size;
17354     int64_t i, data_size, n_particles, file_pos;
17355     void *temp;
17356
17357     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17358     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17359     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17360     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17361     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17362
17363     frame_set = &tng_data->current_trajectory_frame_set;
17364
17365     stat = tng_particle_data_find(tng_data, block_id, &data);
17366     if(stat != TNG_SUCCESS)
17367     {
17368         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17369         file_pos = ftello(tng_data->input_file);
17370         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17371         {
17372             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17373             file_pos = ftello(tng_data->input_file);
17374         }
17375         if(stat != TNG_SUCCESS)
17376         {
17377             return(stat);
17378         }
17379         stat = tng_particle_data_find(tng_data, block_id, &data);
17380         if(stat != TNG_SUCCESS)
17381         {
17382             return(stat);
17383         }
17384     }
17385     if(data->last_retrieved_frame < 0)
17386     {
17387         fseeko(tng_data->input_file,
17388                tng_data->first_trajectory_frame_set_input_file_pos,
17389                SEEK_SET);
17390         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17391         if(stat != TNG_SUCCESS)
17392         {
17393             return(stat);
17394         }
17395         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17396         if(stat != TNG_SUCCESS)
17397         {
17398             return(stat);
17399         }
17400
17401         i = data->first_frame_with_data;
17402     }
17403     else
17404     {
17405         if(data->n_frames == 1)
17406         {
17407             i = data->last_retrieved_frame + 1;
17408         }
17409         else
17410         {
17411             i = data->last_retrieved_frame + data->stride_length;
17412         }
17413         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17414         {
17415             stat = tng_frame_set_of_frame_find(tng_data, i);
17416             if(stat != TNG_SUCCESS)
17417             {
17418                 /* If the frame set search found the frame set after the starting
17419                  * frame set there is a gap in the frame sets. So, even if the frame
17420                  * was not found the next frame with data is still in the found
17421                  * frame set. */
17422                 if(stat == TNG_CRITICAL)
17423                 {
17424                     return(stat);
17425                 }
17426                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17427                 {
17428                     return(TNG_FAILURE);
17429                 }
17430                 i = frame_set->first_frame;
17431             }
17432         }
17433         if(data->last_retrieved_frame < frame_set->first_frame)
17434         {
17435             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17436             if(stat != TNG_SUCCESS)
17437             {
17438                 return(stat);
17439             }
17440         }
17441     }
17442     data->last_retrieved_frame = i;
17443     *retrieved_frame_number = i;
17444     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17445     {
17446         *retrieved_time = frame_set->first_frame_time +
17447                         (i - frame_set->first_frame) *
17448                         tng_data->time_per_frame;
17449     }
17450     else
17451     {
17452         *retrieved_time = 0;
17453     }
17454
17455     if(data->stride_length > 1)
17456     {
17457         i = (i - data->first_frame_with_data) / data->stride_length;
17458     }
17459     else
17460     {
17461         i = (i - frame_set->first_frame);
17462     }
17463
17464     tng_num_particles_get(tng_data, &n_particles);
17465
17466     *data_type = data->datatype;
17467
17468     switch(*data_type)
17469     {
17470     case TNG_CHAR_DATA:
17471         return(TNG_FAILURE);
17472     case TNG_INT_DATA:
17473         size = sizeof(int64_t);
17474         break;
17475     case TNG_FLOAT_DATA:
17476         size = sizeof(float);
17477         break;
17478     case TNG_DOUBLE_DATA:
17479     default:
17480         size = sizeof(double);
17481     }
17482
17483     data_size = size * n_particles * data->n_values_per_frame;
17484
17485 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
17486 //            i, data_size, size, n_particles, data->n_values_per_frame);
17487
17488     temp = realloc(*values, data_size);
17489     if(!temp)
17490     {
17491         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17492                data_size, __FILE__, __LINE__);
17493         free(*values);
17494         *values = 0;
17495         return(TNG_CRITICAL);
17496     }
17497
17498     *values = temp;
17499
17500     memcpy(*values, (char *)data->values + i * data_size, data_size);
17501
17502     return(TNG_SUCCESS);
17503 }
17504
17505 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
17506                 (tng_trajectory_t tng_data,
17507                  const int64_t block_id,
17508                  void **values,
17509                  char *data_type,
17510                  int64_t *retrieved_frame_number,
17511                  double *retrieved_time)
17512 {
17513     tng_trajectory_frame_set_t frame_set;
17514     tng_non_particle_data_t data = 0;
17515     tng_function_status stat;
17516     int size;
17517     int64_t i, data_size, file_pos;
17518     void *temp;
17519
17520     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17521     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17522     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17523     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17524     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17525
17526     frame_set = &tng_data->current_trajectory_frame_set;
17527
17528     stat = tng_data_find(tng_data, block_id, &data);
17529     if(stat != TNG_SUCCESS)
17530     {
17531         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17532         file_pos = ftello(tng_data->input_file);
17533         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17534         {
17535             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17536             file_pos = ftello(tng_data->input_file);
17537         }
17538         if(stat != TNG_SUCCESS)
17539         {
17540             return(stat);
17541         }
17542         stat = tng_data_find(tng_data, block_id, &data);
17543         if(stat != TNG_SUCCESS)
17544         {
17545             return(stat);
17546         }
17547     }
17548     if(data->last_retrieved_frame < 0)
17549     {
17550         fseeko(tng_data->input_file,
17551                tng_data->first_trajectory_frame_set_input_file_pos,
17552                SEEK_SET);
17553         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17554         if(stat != TNG_SUCCESS)
17555         {
17556             return(stat);
17557         }
17558         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17559         if(stat != TNG_SUCCESS)
17560         {
17561             return(stat);
17562         }
17563
17564         i = data->first_frame_with_data;
17565     }
17566     else
17567     {
17568         if(data->n_frames == 1)
17569         {
17570             i = data->last_retrieved_frame + 1;
17571         }
17572         else
17573         {
17574             i = data->last_retrieved_frame + data->stride_length;
17575         }
17576         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17577         {
17578             stat = tng_frame_set_of_frame_find(tng_data, i);
17579             if(stat != TNG_SUCCESS)
17580             {
17581                 /* If the frame set search found the frame set after the starting
17582                  * frame set there is a gap in the frame sets. So, even if the frame
17583                  * was not found the next frame with data is still in the found
17584                  * frame set. */
17585                 if(stat == TNG_CRITICAL)
17586                 {
17587                     return(stat);
17588                 }
17589                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17590                 {
17591                     return(TNG_FAILURE);
17592                 }
17593                 i = frame_set->first_frame;
17594             }
17595         }
17596         if(data->last_retrieved_frame < frame_set->first_frame)
17597         {
17598             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17599             if(stat != TNG_SUCCESS)
17600             {
17601                 return(stat);
17602             }
17603         }
17604     }
17605     data->last_retrieved_frame = i;
17606     *retrieved_frame_number = i;
17607     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17608     {
17609         *retrieved_time = frame_set->first_frame_time +
17610                         (i - frame_set->first_frame) *
17611                         tng_data->time_per_frame;
17612     }
17613     else
17614     {
17615         *retrieved_time = 0;
17616     }
17617
17618     if(data->stride_length > 1)
17619     {
17620         i = (i - data->first_frame_with_data) / data->stride_length;
17621     }
17622     else
17623     {
17624         i = (i - frame_set->first_frame);
17625     }
17626
17627     *data_type = data->datatype;
17628
17629     switch(*data_type)
17630     {
17631     case TNG_CHAR_DATA:
17632         return(TNG_FAILURE);
17633     case TNG_INT_DATA:
17634         size = sizeof(int64_t);
17635         break;
17636     case TNG_FLOAT_DATA:
17637         size = sizeof(float);
17638         break;
17639     case TNG_DOUBLE_DATA:
17640     default:
17641         size = sizeof(double);
17642     }
17643
17644     data_size = size * data->n_values_per_frame;
17645
17646     temp = realloc(*values, data_size);
17647     if(!temp)
17648     {
17649         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17650                data_size, __FILE__, __LINE__);
17651         free(*values);
17652         *values = 0;
17653         return(TNG_CRITICAL);
17654     }
17655
17656     *values = temp;
17657
17658     memcpy(*values, (char *)data->values + i * data_size, data_size);
17659
17660     return(TNG_SUCCESS);
17661 }
17662
17663 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
17664                 (tng_trajectory_t tng_data,
17665                  const int64_t first_frame,
17666                  const int64_t last_frame,
17667                  float **positions,
17668                  int64_t *stride_length)
17669 {
17670     int64_t n_particles, n_values_per_frame;
17671     char type;
17672     tng_function_status stat;
17673
17674     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17675     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17676     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17677     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17678
17679     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17680                                                  first_frame, last_frame,
17681                                                  TNG_USE_HASH,
17682                                                  (void **)positions,
17683                                                  &n_particles,
17684                                                  stride_length,
17685                                                  &n_values_per_frame,
17686                                                  &type);
17687
17688     return(stat);
17689 }
17690
17691 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
17692                 (tng_trajectory_t tng_data,
17693                  const int64_t first_frame,
17694                  const int64_t last_frame,
17695                  float **velocities,
17696                  int64_t *stride_length)
17697 {
17698     int64_t n_particles, n_values_per_frame;
17699     char type;
17700     tng_function_status stat;
17701
17702     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17703     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17704     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17705     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17706
17707     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17708                                                  first_frame, last_frame,
17709                                                  TNG_USE_HASH,
17710                                                  (void **)velocities,
17711                                                  &n_particles,
17712                                                  stride_length,
17713                                                  &n_values_per_frame,
17714                                                  &type);
17715
17716     return(stat);
17717 }
17718
17719 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
17720                 (tng_trajectory_t tng_data,
17721                  const int64_t first_frame,
17722                  const int64_t last_frame,
17723                  float **forces,
17724                  int64_t *stride_length)
17725 {
17726     int64_t n_particles, n_values_per_frame;
17727     char type;
17728     tng_function_status stat;
17729
17730     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17731     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17732     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17733     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17734
17735     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17736                                                  first_frame, last_frame,
17737                                                  TNG_USE_HASH,
17738                                                  (void **)forces,
17739                                                  &n_particles,
17740                                                  stride_length,
17741                                                  &n_values_per_frame,
17742                                                  &type);
17743
17744     return(stat);
17745 }
17746
17747 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
17748                 (tng_trajectory_t tng_data,
17749                  const int64_t first_frame,
17750                  const int64_t last_frame,
17751                  float **box_shape,
17752                  int64_t *stride_length)
17753 {
17754     int64_t n_values_per_frame;
17755     char type;
17756     tng_function_status stat;
17757
17758     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17759     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17760     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17761     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17762
17763     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17764                                         first_frame, last_frame,
17765                                         TNG_USE_HASH,
17766                                         (void **)box_shape,
17767                                         stride_length,
17768                                         &n_values_per_frame,
17769                                         &type);
17770
17771     return(stat);
17772 }
17773
17774 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
17775                 (tng_trajectory_t tng_data,
17776                  const int64_t i,
17777                  const int64_t n_values_per_frame,
17778                  const int64_t block_id,
17779                  const char *block_name,
17780                  const char particle_dependency,
17781                  const char compression)
17782 {
17783     tng_trajectory_frame_set_t frame_set;
17784     tng_particle_data_t p_data;
17785     tng_non_particle_data_t np_data;
17786     int64_t n_particles, n_frames;
17787     tng_function_status stat;
17788
17789     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17790     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17791
17792     if(i <= 0)
17793     {
17794         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17795                i, __FILE__, __LINE__);
17796         return(TNG_FAILURE);
17797     }
17798
17799     frame_set = &tng_data->current_trajectory_frame_set;
17800
17801     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17802     {
17803         n_frames = tng_data->frame_set_n_frames;
17804
17805         stat = tng_frame_set_new(tng_data, 0, n_frames);
17806         if(stat != TNG_SUCCESS)
17807         {
17808             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17809                 __LINE__);
17810             return(stat);
17811         }
17812     }
17813     else
17814     {
17815         n_frames = frame_set->n_frames;
17816     }
17817
17818     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17819     {
17820         tng_num_particles_get(tng_data, &n_particles);
17821         if(n_particles <= 0)
17822         {
17823             return(TNG_FAILURE);
17824         }
17825
17826         if(tng_particle_data_find(tng_data, block_id, &p_data)
17827         != TNG_SUCCESS)
17828         {
17829             stat = tng_particle_data_block_add(tng_data, block_id,
17830                                                block_name,
17831                                                TNG_FLOAT_DATA,
17832                                                TNG_TRAJECTORY_BLOCK,
17833                                                n_frames, n_values_per_frame, i,
17834                                                0, n_particles,
17835                                                compression, 0);
17836             if(stat != TNG_SUCCESS)
17837             {
17838                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17839                        __FILE__, __LINE__);
17840                 return(stat);
17841             }
17842             p_data = &frame_set->tr_particle_data[frame_set->
17843                                                   n_particle_data_blocks - 1];
17844             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17845                                                   i, n_particles,
17846                                                   n_values_per_frame);
17847             if(stat != TNG_SUCCESS)
17848             {
17849                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17850                        __FILE__, __LINE__);
17851                 return(stat);
17852             }
17853         }
17854         else
17855         {
17856             if(p_data->stride_length != i)
17857             {
17858                 p_data->stride_length = i;
17859                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17860                                                       i, n_particles,
17861                                                       n_values_per_frame);
17862                 if(stat != TNG_SUCCESS)
17863                 {
17864                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17865                            __FILE__, __LINE__);
17866                     return(stat);
17867                 }
17868             }
17869         }
17870     }
17871     else
17872     {
17873         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17874         {
17875             stat = tng_data_block_add(tng_data, block_id, block_name,
17876                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17877                                       n_frames, n_values_per_frame,
17878                                       i, compression, 0);
17879             if(stat != TNG_SUCCESS)
17880             {
17881                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17882                        __FILE__, __LINE__);
17883                 return(stat);
17884             }
17885             np_data = &frame_set->tr_data[frame_set->
17886                                           n_data_blocks - 1];
17887             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17888                                          i, n_values_per_frame);
17889             if(stat != TNG_SUCCESS)
17890             {
17891                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17892                        __FILE__, __LINE__);
17893                 return(stat);
17894             }
17895         }
17896         else
17897         {
17898             if(np_data->stride_length != i)
17899             {
17900                 np_data->stride_length = i;
17901                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17902                                              i, n_values_per_frame);
17903                 if(stat != TNG_SUCCESS)
17904                 {
17905                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17906                            __FILE__, __LINE__);
17907                     return(stat);
17908                 }
17909             }
17910         }
17911     }
17912
17913     return(TNG_SUCCESS);
17914 }
17915
17916 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17917                 (tng_trajectory_t tng_data,
17918                  const int64_t i,
17919                  const int64_t n_values_per_frame,
17920                  const int64_t block_id,
17921                  const char *block_name,
17922                  const char particle_dependency,
17923                  const char compression)
17924 {
17925     tng_trajectory_frame_set_t frame_set;
17926     tng_particle_data_t p_data;
17927     tng_non_particle_data_t np_data;
17928     int64_t n_particles, n_frames;
17929     tng_function_status stat;
17930
17931     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17932     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17933
17934     if(i <= 0)
17935     {
17936         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17937                i, __FILE__, __LINE__);
17938         return(TNG_FAILURE);
17939     }
17940
17941     frame_set = &tng_data->current_trajectory_frame_set;
17942
17943     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17944     {
17945         n_frames = tng_data->frame_set_n_frames;
17946
17947         stat = tng_frame_set_new(tng_data, 0, n_frames);
17948         if(stat != TNG_SUCCESS)
17949         {
17950             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17951                 __LINE__);
17952             return(stat);
17953         }
17954     }
17955     else
17956     {
17957         n_frames = frame_set->n_frames;
17958     }
17959
17960     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17961     {
17962         tng_num_particles_get(tng_data, &n_particles);
17963
17964         if(n_particles <= 0)
17965         {
17966             return(TNG_FAILURE);
17967         }
17968
17969         if(tng_particle_data_find(tng_data, block_id, &p_data)
17970         != TNG_SUCCESS)
17971         {
17972             stat = tng_particle_data_block_add(tng_data, block_id,
17973                                             block_name,
17974                                             TNG_DOUBLE_DATA,
17975                                             TNG_TRAJECTORY_BLOCK,
17976                                             n_frames, n_values_per_frame, i,
17977                                             0, n_particles,
17978                                             compression, 0);
17979             if(stat != TNG_SUCCESS)
17980             {
17981                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17982                        __FILE__, __LINE__);
17983                 return(stat);
17984             }
17985             p_data = &frame_set->tr_particle_data[frame_set->
17986                                                   n_particle_data_blocks - 1];
17987             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17988                                                   i, n_particles,
17989                                                   n_values_per_frame);
17990             if(stat != TNG_SUCCESS)
17991             {
17992                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17993                        __FILE__, __LINE__);
17994                 return(stat);
17995             }
17996         }
17997         else
17998         {
17999             p_data->stride_length = i;
18000         }
18001     }
18002     else
18003     {
18004         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18005         {
18006             stat = tng_data_block_add(tng_data, block_id, block_name,
18007                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
18008                                       n_frames, n_values_per_frame,
18009                                       i, compression, 0);
18010             if(stat != TNG_SUCCESS)
18011             {
18012                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18013                        __FILE__, __LINE__);
18014                 return(stat);
18015             }
18016             np_data = &frame_set->tr_data[frame_set->
18017                                           n_data_blocks - 1];
18018             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18019                                          i, n_values_per_frame);
18020             if(stat != TNG_SUCCESS)
18021             {
18022                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18023                        __FILE__, __LINE__);
18024                 return(stat);
18025             }
18026         }
18027         else
18028         {
18029             np_data->stride_length = i;
18030         }
18031     }
18032
18033     return(TNG_SUCCESS);
18034 }
18035
18036 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
18037                 (tng_trajectory_t tng_data,
18038                  const int64_t i,
18039                  const int64_t n_values_per_frame,
18040                  const int64_t block_id,
18041                  const char *block_name,
18042                  const char particle_dependency,
18043                  const char compression)
18044 {
18045     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
18046            "See documentation. %s: %d", __FILE__, __LINE__);
18047     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
18048                                                block_id, block_name,
18049                                                particle_dependency,
18050                                                compression));
18051 }
18052 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
18053                 (tng_trajectory_t tng_data,
18054                  const int64_t i)
18055 {
18056     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18057     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18058
18059     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18060                                                TNG_TRAJ_POSITIONS,
18061                                                "POSITIONS",
18062                                                TNG_PARTICLE_BLOCK_DATA,
18063                                                TNG_TNG_COMPRESSION));
18064 }
18065
18066 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
18067                 (tng_trajectory_t tng_data,
18068                  const int64_t i)
18069 {
18070     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18071     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18072
18073     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18074                                                       TNG_TRAJ_POSITIONS,
18075                                                       "POSITIONS",
18076                                                       TNG_PARTICLE_BLOCK_DATA,
18077                                                       TNG_TNG_COMPRESSION));
18078 }
18079
18080 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
18081                 (tng_trajectory_t tng_data,
18082                  const int64_t i)
18083 {
18084     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
18085            "See documentation. %s: %d", __FILE__, __LINE__);
18086     return(tng_util_pos_write_interval_set(tng_data, i));
18087 }
18088
18089 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
18090                 (tng_trajectory_t tng_data,
18091                  const int64_t i)
18092 {
18093     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18094     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18095
18096     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18097                                                TNG_TRAJ_VELOCITIES,
18098                                                "VELOCITIES",
18099                                                TNG_PARTICLE_BLOCK_DATA,
18100                                                TNG_TNG_COMPRESSION));
18101 }
18102
18103 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
18104                 (tng_trajectory_t tng_data,
18105                  const int64_t i)
18106 {
18107     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18108     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18109
18110     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18111                                                       TNG_TRAJ_VELOCITIES,
18112                                                       "VELOCITIES",
18113                                                       TNG_PARTICLE_BLOCK_DATA,
18114                                                       TNG_TNG_COMPRESSION));
18115 }
18116
18117 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
18118                 (tng_trajectory_t tng_data,
18119                  const int64_t i)
18120 {
18121     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
18122            "See documentation. %s: %d", __FILE__, __LINE__);
18123     return(tng_util_vel_write_interval_set(tng_data, i));
18124 }
18125
18126 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
18127                 (tng_trajectory_t tng_data,
18128                  const int64_t i)
18129 {
18130     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18131     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18132
18133     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18134                                                TNG_TRAJ_FORCES,
18135                                                "FORCES",
18136                                                TNG_PARTICLE_BLOCK_DATA,
18137                                                TNG_GZIP_COMPRESSION));
18138 }
18139
18140 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
18141                 (tng_trajectory_t tng_data,
18142                  const int64_t i)
18143 {
18144     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18145     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18146
18147     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18148                                                       TNG_TRAJ_FORCES,
18149                                                       "FORCES",
18150                                                       TNG_PARTICLE_BLOCK_DATA,
18151                                                       TNG_GZIP_COMPRESSION));
18152 }
18153
18154 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
18155                 (tng_trajectory_t tng_data,
18156                  const int64_t i)
18157 {
18158     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
18159            "See documentation. %s: %d", __FILE__, __LINE__);
18160     return(tng_util_force_write_interval_set(tng_data, i));
18161 }
18162
18163 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
18164                 (tng_trajectory_t tng_data,
18165                  const int64_t i)
18166 {
18167     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18168     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18169
18170     return(tng_util_generic_write_interval_set(tng_data, i, 9,
18171                                                TNG_TRAJ_BOX_SHAPE,
18172                                                "BOX SHAPE",
18173                                                TNG_NON_PARTICLE_BLOCK_DATA,
18174                                                TNG_GZIP_COMPRESSION));
18175 }
18176
18177 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
18178                 (tng_trajectory_t tng_data,
18179                  const int64_t i)
18180 {
18181     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18182     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18183
18184     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
18185                                                       TNG_TRAJ_BOX_SHAPE,
18186                                                       "BOX SHAPE",
18187                                                       TNG_NON_PARTICLE_BLOCK_DATA,
18188                                                       TNG_GZIP_COMPRESSION));
18189 }
18190
18191 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
18192                 (tng_trajectory_t tng_data,
18193                  const int64_t i)
18194 {
18195     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
18196            "See documentation. %s: %d", __FILE__, __LINE__);
18197     return(tng_util_box_shape_write_interval_set(tng_data, i));
18198 }
18199
18200 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
18201                 (tng_trajectory_t tng_data,
18202                  const int64_t frame_nr,
18203                  const float *values,
18204                  const int64_t n_values_per_frame,
18205                  const int64_t block_id,
18206                  const char *block_name,
18207                  const char particle_dependency,
18208                  const char compression)
18209 {
18210     tng_trajectory_frame_set_t frame_set;
18211     tng_particle_data_t p_data;
18212     tng_non_particle_data_t np_data;
18213     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18214     int64_t last_frame;
18215     int is_first_frame_flag = 0;
18216     char block_type_flag;
18217     tng_function_status stat;
18218
18219     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18220     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18221     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18222
18223     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18224     {
18225         tng_num_particles_get(tng_data, &n_particles);
18226         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18227     }
18228
18229     if(values == 0)
18230     {
18231         return(TNG_FAILURE);
18232     }
18233
18234     frame_set = &tng_data->current_trajectory_frame_set;
18235
18236     if(frame_nr < 0)
18237     {
18238         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18239         n_frames = stride_length = 1;
18240     }
18241     else
18242     {
18243         block_type_flag = TNG_TRAJECTORY_BLOCK;
18244
18245         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18246         {
18247             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
18248             if(stat != TNG_SUCCESS)
18249             {
18250                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18251                     __LINE__);
18252                 return(stat);
18253             }
18254         }
18255         last_frame = frame_set->first_frame +
18256                      frame_set->n_frames - 1;
18257         if(frame_nr > last_frame)
18258         {
18259             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18260             if(stat != TNG_SUCCESS)
18261             {
18262                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18263                     __LINE__);
18264                 return(stat);
18265             }
18266             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18267             {
18268                 last_frame = frame_nr - 1;
18269             }
18270             stat = tng_frame_set_new(tng_data, last_frame + 1,
18271                                      tng_data->frame_set_n_frames);
18272             if(stat != TNG_SUCCESS)
18273             {
18274                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18275                     __LINE__);
18276                 return(stat);
18277             }
18278         }
18279         if(frame_set->n_unwritten_frames == 0)
18280         {
18281             is_first_frame_flag = 1;
18282         }
18283         frame_set->n_unwritten_frames = frame_nr -
18284                                         frame_set->first_frame + 1;
18285
18286         n_frames = frame_set->n_frames;
18287     }
18288
18289     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18290     {
18291         if(tng_particle_data_find(tng_data, block_id, &p_data)
18292         != TNG_SUCCESS)
18293         {
18294             stat = tng_particle_data_block_add(tng_data, block_id,
18295                                                block_name,
18296                                                TNG_FLOAT_DATA,
18297                                                block_type_flag,
18298                                                n_frames, n_values_per_frame,
18299                                                stride_length,
18300                                                0, n_particles,
18301                                                compression, 0);
18302             if(stat != TNG_SUCCESS)
18303             {
18304                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18305                        __FILE__, __LINE__);
18306                 return(stat);
18307             }
18308             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18309             {
18310                 p_data = &frame_set->tr_particle_data[frame_set->
18311                                                     n_particle_data_blocks - 1];
18312             }
18313             else
18314             {
18315                 p_data = &tng_data->non_tr_particle_data[tng_data->
18316                                                     n_particle_data_blocks - 1];
18317             }
18318             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18319                                                   stride_length, n_particles,
18320                                                   n_values_per_frame);
18321             if(stat != TNG_SUCCESS)
18322             {
18323                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18324                        __FILE__, __LINE__);
18325                 return(stat);
18326             }
18327         }
18328
18329         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18330         {
18331             stride_length = p_data->stride_length;
18332
18333             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
18334             {
18335                 p_data->first_frame_with_data = frame_nr;
18336                 frame_pos = 0;
18337             }
18338             else
18339             {
18340                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18341             }
18342
18343             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
18344                    n_values_per_frame, values, sizeof(float) *
18345                    n_particles * n_values_per_frame);
18346         }
18347         else
18348         {
18349             memcpy(p_data->values, values, sizeof(float) * n_particles *
18350                    n_values_per_frame);
18351         }
18352     }
18353     else
18354     {
18355         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18356         {
18357             stat = tng_data_block_add(tng_data, block_id, block_name,
18358                                       TNG_FLOAT_DATA, block_type_flag,
18359                                       n_frames, n_values_per_frame,
18360                                       stride_length, compression, 0);
18361             if(stat != TNG_SUCCESS)
18362             {
18363                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18364                        __FILE__, __LINE__);
18365                 return(stat);
18366             }
18367             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18368             {
18369                 np_data = &frame_set->tr_data[frame_set->
18370                                               n_data_blocks - 1];
18371             }
18372             else
18373             {
18374                 np_data = &tng_data->non_tr_data[tng_data->
18375                                                  n_data_blocks - 1];
18376             }
18377             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18378                                          stride_length, n_values_per_frame);
18379             if(stat != TNG_SUCCESS)
18380             {
18381                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18382                        __FILE__, __LINE__);
18383                 return(stat);
18384             }
18385         }
18386
18387         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18388         {
18389             stride_length = np_data->stride_length;
18390
18391             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
18392             {
18393                 np_data->first_frame_with_data = frame_nr;
18394                 frame_pos = 0;
18395             }
18396             else
18397             {
18398                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18399             }
18400
18401             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
18402                    n_values_per_frame, values, sizeof(float) *
18403                    n_values_per_frame);
18404         }
18405         else
18406         {
18407             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
18408         }
18409     }
18410
18411     return(TNG_SUCCESS);
18412 }
18413
18414 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
18415                 (tng_trajectory_t tng_data,
18416                  const int64_t frame_nr,
18417                  const double *values,
18418                  const int64_t n_values_per_frame,
18419                  const int64_t block_id,
18420                  const char *block_name,
18421                  const char particle_dependency,
18422                  const char compression)
18423 {
18424     tng_trajectory_frame_set_t frame_set;
18425     tng_particle_data_t p_data;
18426     tng_non_particle_data_t np_data;
18427     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18428     int64_t last_frame;
18429     int is_first_frame_flag = 0;
18430     char block_type_flag;
18431     tng_function_status stat;
18432
18433     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18434     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18435     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18436
18437     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18438     {
18439         tng_num_particles_get(tng_data, &n_particles);
18440         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18441     }
18442
18443     if(values == 0)
18444     {
18445         return(TNG_FAILURE);
18446     }
18447
18448     frame_set = &tng_data->current_trajectory_frame_set;
18449
18450     if(frame_nr < 0)
18451     {
18452         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18453         n_frames = stride_length = 1;
18454     }
18455     else
18456     {
18457         block_type_flag = TNG_TRAJECTORY_BLOCK;
18458
18459         n_frames = tng_data->frame_set_n_frames;
18460
18461         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18462         {
18463             stat = tng_frame_set_new(tng_data, 0, n_frames);
18464             if(stat != TNG_SUCCESS)
18465             {
18466                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18467                     __LINE__);
18468                 return(stat);
18469             }
18470         }
18471         else
18472         {
18473             n_frames = frame_set->n_frames;
18474         }
18475         last_frame = frame_set->first_frame +
18476                      frame_set->n_frames - 1;
18477         if(frame_nr > last_frame)
18478         {
18479             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18480             if(stat != TNG_SUCCESS)
18481             {
18482                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18483                     __LINE__);
18484                 return(stat);
18485             }
18486             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18487             {
18488                 last_frame = frame_nr - 1;
18489             }
18490             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
18491             if(stat != TNG_SUCCESS)
18492             {
18493                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18494                     __LINE__);
18495                 return(stat);
18496             }
18497         }
18498         if(frame_set->n_unwritten_frames == 0)
18499         {
18500             is_first_frame_flag = 1;
18501         }
18502         frame_set->n_unwritten_frames = frame_nr -
18503                                         frame_set->first_frame + 1;
18504     }
18505
18506     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18507     {
18508         if(tng_particle_data_find(tng_data, block_id, &p_data)
18509         != TNG_SUCCESS)
18510         {
18511             stat = tng_particle_data_block_add(tng_data, block_id,
18512                                             block_name,
18513                                             TNG_DOUBLE_DATA,
18514                                             block_type_flag,
18515                                             n_frames, n_values_per_frame,
18516                                             stride_length,
18517                                             0, n_particles,
18518                                             compression, 0);
18519             if(stat != TNG_SUCCESS)
18520             {
18521                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18522                        __FILE__, __LINE__);
18523                 return(stat);
18524             }
18525             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18526             {
18527                 p_data = &frame_set->tr_particle_data[frame_set->
18528                                                     n_particle_data_blocks - 1];
18529             }
18530             else
18531             {
18532                 p_data = &tng_data->non_tr_particle_data[tng_data->
18533                                                     n_particle_data_blocks - 1];
18534             }
18535             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18536                                                   stride_length, n_particles,
18537                                                   n_values_per_frame);
18538             if(stat != TNG_SUCCESS)
18539             {
18540                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18541                        __FILE__, __LINE__);
18542                 return(stat);
18543             }
18544         }
18545
18546         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18547         {
18548             stride_length = p_data->stride_length;
18549
18550             if(is_first_frame_flag)
18551             {
18552                 p_data->first_frame_with_data = frame_nr;
18553                 frame_pos = 0;
18554             }
18555             else
18556             {
18557                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18558             }
18559
18560             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
18561                    n_values_per_frame, values, sizeof(double) *
18562                    n_particles * n_values_per_frame);
18563         }
18564         else
18565         {
18566             memcpy(p_data->values, values, sizeof(double) * n_particles *
18567                    n_values_per_frame);
18568         }
18569     }
18570     else
18571     {
18572         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18573         {
18574             stat = tng_data_block_add(tng_data, block_id, block_name,
18575                                       TNG_DOUBLE_DATA, block_type_flag,
18576                                       n_frames, n_values_per_frame,
18577                                       stride_length, compression, 0);
18578             if(stat != TNG_SUCCESS)
18579             {
18580                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18581                        __FILE__, __LINE__);
18582                 return(stat);
18583             }
18584             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18585             {
18586                 np_data = &frame_set->tr_data[frame_set->
18587                                               n_data_blocks - 1];
18588             }
18589             else
18590             {
18591                 np_data = &tng_data->non_tr_data[tng_data->
18592                                                  n_data_blocks - 1];
18593             }
18594             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18595                                          stride_length, n_values_per_frame);
18596             if(stat != TNG_SUCCESS)
18597             {
18598                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18599                        __FILE__, __LINE__);
18600                 return(stat);
18601             }
18602         }
18603
18604         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18605         {
18606             stride_length = np_data->stride_length;
18607
18608             if(is_first_frame_flag)
18609             {
18610                 np_data->first_frame_with_data = frame_nr;
18611                 frame_pos = 0;
18612             }
18613             else
18614             {
18615                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18616             }
18617
18618             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
18619                    n_values_per_frame, values, sizeof(double) *
18620                    n_values_per_frame);
18621         }
18622         else
18623         {
18624             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
18625         }
18626     }
18627
18628     return(TNG_SUCCESS);
18629 }
18630
18631 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
18632                 (tng_trajectory_t tng_data,
18633                  const int64_t frame_nr,
18634                  const float *positions)
18635 {
18636     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18637     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18638     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18639
18640     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
18641                                   TNG_TRAJ_POSITIONS, "POSITIONS",
18642                                   TNG_PARTICLE_BLOCK_DATA,
18643                                   TNG_TNG_COMPRESSION));
18644 }
18645
18646 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
18647                 (tng_trajectory_t tng_data,
18648                  const int64_t frame_nr,
18649                  const double *positions)
18650 {
18651     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18652     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18653     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18654
18655     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
18656                                          TNG_TRAJ_POSITIONS, "POSITIONS",
18657                                          TNG_PARTICLE_BLOCK_DATA,
18658                                          TNG_TNG_COMPRESSION));
18659 }
18660
18661 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
18662                 (tng_trajectory_t tng_data,
18663                  const int64_t frame_nr,
18664                  const float *velocities)
18665 {
18666     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18667     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18668     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18669
18670     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
18671                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
18672                                   TNG_PARTICLE_BLOCK_DATA,
18673                                   TNG_TNG_COMPRESSION));
18674 }
18675
18676 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
18677                 (tng_trajectory_t tng_data,
18678                  const int64_t frame_nr,
18679                  const double *velocities)
18680 {
18681     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18682     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18683     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18684
18685     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
18686                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
18687                                          TNG_PARTICLE_BLOCK_DATA,
18688                                          TNG_TNG_COMPRESSION));
18689 }
18690
18691 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
18692                 (tng_trajectory_t tng_data,
18693                  const int64_t frame_nr,
18694                  const float *forces)
18695 {
18696     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18697     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18698     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18699
18700     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
18701                                   TNG_TRAJ_FORCES, "FORCES",
18702                                   TNG_PARTICLE_BLOCK_DATA,
18703                                   TNG_GZIP_COMPRESSION));
18704 }
18705
18706 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
18707                 (tng_trajectory_t tng_data,
18708                  const int64_t frame_nr,
18709                  const double *forces)
18710 {
18711     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18712     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18713     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18714
18715     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
18716                                          TNG_TRAJ_FORCES, "FORCES",
18717                                          TNG_PARTICLE_BLOCK_DATA,
18718                                          TNG_GZIP_COMPRESSION));
18719 }
18720
18721 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
18722                 (tng_trajectory_t tng_data,
18723                  const int64_t frame_nr,
18724                  const float *box_shape)
18725 {
18726     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18727     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18728     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18729
18730     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
18731                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18732                                   TNG_NON_PARTICLE_BLOCK_DATA,
18733                                   TNG_GZIP_COMPRESSION));
18734 }
18735
18736 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
18737                 (tng_trajectory_t tng_data,
18738                  const int64_t frame_nr,
18739                  const double *box_shape)
18740 {
18741     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18742     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18743     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18744
18745     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
18746                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18747                                          TNG_NON_PARTICLE_BLOCK_DATA,
18748                                          TNG_GZIP_COMPRESSION));
18749 }
18750
18751 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
18752                 (tng_trajectory_t tng_data,
18753                  const int64_t frame_nr,
18754                  const double time,
18755                  const float *values,
18756                  const int64_t n_values_per_frame,
18757                  const int64_t block_id,
18758                  const char *block_name,
18759                  const char particle_dependency,
18760                  const char compression)
18761 {
18762     tng_trajectory_frame_set_t frame_set;
18763     tng_function_status stat;
18764
18765     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18766     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18767     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18768     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18769
18770     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
18771                                   block_id, block_name,
18772                                   particle_dependency,
18773                                   compression);
18774
18775     if(stat != TNG_SUCCESS)
18776     {
18777         return(stat);
18778     }
18779
18780     frame_set = &tng_data->current_trajectory_frame_set;
18781
18782     /* first_frame_time is -1 when it is not yet set. */
18783     if(frame_set->first_frame_time < -0.1)
18784     {
18785         if(frame_nr > frame_set->first_frame)
18786         {
18787             stat = tng_frame_set_first_frame_time_set(tng_data,
18788                                                       time -
18789                                                       (frame_nr -
18790                                                        frame_set->first_frame) *
18791                                                       tng_data->time_per_frame);
18792         }
18793         else
18794         {
18795             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18796         }
18797     }
18798     return(stat);
18799 }
18800
18801 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18802                 (tng_trajectory_t tng_data,
18803                  const int64_t frame_nr,
18804                  const double time,
18805                  const double *values,
18806                  const int64_t n_values_per_frame,
18807                  const int64_t block_id,
18808                  const char *block_name,
18809                  const char particle_dependency,
18810                  const char compression)
18811 {
18812     tng_trajectory_frame_set_t frame_set;
18813     tng_function_status stat;
18814
18815     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18816     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18817     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18818     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18819
18820     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18821                                          block_id, block_name,
18822                                          particle_dependency,
18823                                          compression);
18824
18825     if(stat != TNG_SUCCESS)
18826     {
18827         return(stat);
18828     }
18829
18830     frame_set = &tng_data->current_trajectory_frame_set;
18831
18832     /* first_frame_time is -1 when it is not yet set. */
18833     if(frame_set->first_frame_time < -0.1)
18834     {
18835         if(frame_nr > frame_set->first_frame)
18836         {
18837             stat = tng_frame_set_first_frame_time_set(tng_data,
18838                                                       time -
18839                                                       (frame_nr -
18840                                                        frame_set->first_frame) *
18841                                                       tng_data->time_per_frame);
18842         }
18843         else
18844         {
18845             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18846         }
18847     }
18848     return(stat);
18849 }
18850
18851 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18852                 (tng_trajectory_t tng_data,
18853                  const int64_t frame_nr,
18854                  const double time,
18855                  const float *positions)
18856 {
18857     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18858     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18859     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18860     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18861
18862     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18863                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18864                                             TNG_PARTICLE_BLOCK_DATA,
18865                                             TNG_TNG_COMPRESSION));
18866 }
18867
18868 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18869                 (tng_trajectory_t tng_data,
18870                  const int64_t frame_nr,
18871                  const double time,
18872                  const double *positions)
18873 {
18874     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18875     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18876     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18877     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18878
18879     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18880                                                    positions, 3,
18881                                                    TNG_TRAJ_POSITIONS,
18882                                                    "POSITIONS",
18883                                                    TNG_PARTICLE_BLOCK_DATA,
18884                                                    TNG_TNG_COMPRESSION));
18885 }
18886
18887 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18888                 (tng_trajectory_t tng_data,
18889                  const int64_t frame_nr,
18890                  const double time,
18891                  const float *velocities)
18892 {
18893     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18894     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18895     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18896     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18897
18898     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18899                                             velocities, 3,
18900                                             TNG_TRAJ_VELOCITIES,
18901                                             "VELOCITIES",
18902                                             TNG_PARTICLE_BLOCK_DATA,
18903                                             TNG_TNG_COMPRESSION));
18904 }
18905
18906 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18907                 (tng_trajectory_t tng_data,
18908                  const int64_t frame_nr,
18909                  const double time,
18910                  const double *velocities)
18911 {
18912     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18913     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18914     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18915     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18916
18917     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18918                                                    velocities, 3,
18919                                                    TNG_TRAJ_VELOCITIES,
18920                                                    "VELOCITIES",
18921                                                    TNG_PARTICLE_BLOCK_DATA,
18922                                                    TNG_TNG_COMPRESSION));
18923 }
18924
18925 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18926                 (tng_trajectory_t tng_data,
18927                  const int64_t frame_nr,
18928                  const double time,
18929                  const float *forces)
18930 {
18931     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18932     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18933     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18934     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18935
18936     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18937                                             3, TNG_TRAJ_FORCES, "FORCES",
18938                                             TNG_PARTICLE_BLOCK_DATA,
18939                                             TNG_GZIP_COMPRESSION));
18940 }
18941
18942 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18943                 (tng_trajectory_t tng_data,
18944                  const int64_t frame_nr,
18945                  const double time,
18946                  const double *forces)
18947 {
18948     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18949     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18950     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18951     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18952
18953     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18954                                                    forces, 3,
18955                                                    TNG_TRAJ_FORCES, "FORCES",
18956                                                    TNG_PARTICLE_BLOCK_DATA,
18957                                                    TNG_GZIP_COMPRESSION));
18958 }
18959
18960 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18961                 (tng_trajectory_t tng_data,
18962                  const int64_t frame_nr,
18963                  const double time,
18964                  const float *box_shape)
18965 {
18966     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18967     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18968     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18969     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18970
18971     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18972                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18973                                             TNG_NON_PARTICLE_BLOCK_DATA,
18974                                             TNG_GZIP_COMPRESSION));
18975 }
18976
18977 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18978                 (tng_trajectory_t tng_data,
18979                  const int64_t frame_nr,
18980                  const double time,
18981                  const double *box_shape)
18982 {
18983     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18984     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18985     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18986     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18987
18988     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18989                                                    time, box_shape, 9,
18990                                                    TNG_TRAJ_BOX_SHAPE,
18991                                                    "BOX SHAPE",
18992                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18993                                                    TNG_GZIP_COMPRESSION));
18994 }
18995
18996 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18997                 (tng_trajectory_t tng_data,
18998                  const int64_t block_id,
18999                  int64_t *codec_id,
19000                  double *factor)
19001 {
19002     tng_trajectory_frame_set_t frame_set;
19003     tng_particle_data_t p_data = 0;
19004     tng_non_particle_data_t np_data = 0;
19005     tng_function_status stat;
19006     int64_t i;
19007     int block_type = -1;
19008
19009     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19010     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
19011     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
19012
19013     frame_set = &tng_data->current_trajectory_frame_set;
19014
19015     stat = tng_particle_data_find(tng_data, block_id, &p_data);
19016     if(stat == TNG_SUCCESS)
19017     {
19018         block_type = TNG_PARTICLE_BLOCK_DATA;
19019     }
19020     else
19021     {
19022         stat = tng_data_find(tng_data, block_id, &np_data);
19023         if(stat == TNG_SUCCESS)
19024         {
19025             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19026         }
19027         else
19028         {
19029             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19030             if(stat != TNG_SUCCESS)
19031             {
19032                 return(stat);
19033             }
19034             stat = tng_particle_data_find(tng_data, block_id, &p_data);
19035             if(stat == TNG_SUCCESS)
19036             {
19037                 block_type = TNG_PARTICLE_BLOCK_DATA;
19038             }
19039             else
19040             {
19041                 stat = tng_data_find(tng_data, block_id, &np_data);
19042                 if(stat == TNG_SUCCESS)
19043                 {
19044                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19045                 }
19046                 else
19047                 {
19048                     return(stat);
19049                 }
19050             }
19051         }
19052     }
19053     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19054     {
19055         if(p_data->last_retrieved_frame < 0)
19056         {
19057             i = p_data->first_frame_with_data;
19058         }
19059         else
19060         {
19061             i = p_data->last_retrieved_frame;
19062         }
19063     }
19064     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19065     {
19066         if(np_data->last_retrieved_frame < 0)
19067         {
19068             i = np_data->first_frame_with_data;
19069         }
19070         else
19071         {
19072             i = np_data->last_retrieved_frame;
19073         }
19074     }
19075     else
19076     {
19077         return(TNG_FAILURE);
19078     }
19079     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
19080     {
19081         stat = tng_frame_set_of_frame_find(tng_data, i);
19082         if(stat != TNG_SUCCESS)
19083         {
19084             return(stat);
19085         }
19086         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19087         if(stat != TNG_SUCCESS)
19088         {
19089             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19090                 __FILE__, __LINE__);
19091             return(stat);
19092         }
19093     }
19094     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19095     {
19096         *codec_id = p_data->codec_id;
19097         *factor   = p_data->compression_multiplier;
19098     }
19099     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19100     {
19101         *codec_id = np_data->codec_id;
19102         *factor   = np_data->compression_multiplier;
19103     }
19104     return(TNG_SUCCESS);
19105 }
19106
19107 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
19108                 (tng_trajectory_t tng_data,
19109                  int64_t current_frame,
19110                  const int64_t n_requested_data_block_ids,
19111                  const int64_t *requested_data_block_ids,
19112                  int64_t *next_frame,
19113                  int64_t *n_data_blocks_in_next_frame,
19114                  int64_t **data_block_ids_in_next_frame)
19115 {
19116     tng_trajectory_frame_set_t frame_set;
19117     tng_function_status stat;
19118     tng_particle_data_t p_data;
19119     tng_non_particle_data_t np_data;
19120     tng_gen_block_t block;
19121     int64_t i, j, block_id, *temp;
19122     int64_t data_frame, frame_diff, min_diff;
19123     int64_t size, frame_set_file_pos, file_pos;
19124     int found, read_all = 0;
19125
19126     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19127     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
19128     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
19129     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19130
19131     if(n_requested_data_block_ids)
19132     {
19133         TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
19134         size = sizeof(int64_t) * n_requested_data_block_ids;
19135         temp = realloc(*data_block_ids_in_next_frame, size);
19136         if(!temp)
19137         {
19138             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19139                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19140                     __FILE__, __LINE__);
19141             free(*data_block_ids_in_next_frame);
19142             *data_block_ids_in_next_frame = 0;
19143             return(TNG_CRITICAL);
19144         }
19145         *data_block_ids_in_next_frame = temp;
19146     }
19147
19148     frame_set = &tng_data->current_trajectory_frame_set;
19149
19150     current_frame += 1;
19151
19152     if(current_frame < frame_set->first_frame ||
19153        current_frame >= frame_set->first_frame + frame_set->n_frames)
19154     {
19155         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
19156         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
19157         if(stat != TNG_SUCCESS)
19158         {
19159             /* If the frame set search found the frame set after the starting
19160              * frame set there is a gap in the frame sets. So, even if the frame
19161              * was not found the next frame with data is still in the found
19162              * frame set. */
19163             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
19164                frame_set_file_pos)
19165             {
19166                 return(stat);
19167             }
19168             current_frame = frame_set->first_frame;
19169         }
19170     }
19171
19172     /* Check for data blocks only if they have not already been found. */
19173     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
19174     {
19175         file_pos = ftello(tng_data->input_file);
19176         if(file_pos < tng_data->input_file_len)
19177         {
19178             tng_block_init(&block);
19179             stat = tng_block_header_read(tng_data, block);
19180             while(file_pos < tng_data->input_file_len &&
19181                 stat != TNG_CRITICAL &&
19182                 block->id != TNG_TRAJECTORY_FRAME_SET &&
19183                 block->id != -1)
19184             {
19185                 stat = tng_block_read_next(tng_data, block,
19186                                         TNG_USE_HASH);
19187                 if(stat != TNG_CRITICAL)
19188                 {
19189                     file_pos = ftello(tng_data->input_file);
19190                     if(file_pos < tng_data->input_file_len)
19191                     {
19192                         stat = tng_block_header_read(tng_data, block);
19193                     }
19194                 }
19195             }
19196             tng_block_destroy(&block);
19197             if(stat == TNG_CRITICAL)
19198             {
19199                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
19200                         file_pos, __FILE__, __LINE__);
19201                 return(stat);
19202             }
19203         }
19204         read_all = 1;
19205     }
19206
19207     min_diff = -1;
19208
19209     *n_data_blocks_in_next_frame = 0;
19210
19211     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
19212     {
19213         p_data = &frame_set->tr_particle_data[i];
19214         block_id = p_data->block_id;
19215
19216         if(n_requested_data_block_ids > 0)
19217         {
19218             found = 0;
19219             for(j = 0; j < n_requested_data_block_ids; j++)
19220             {
19221                 if(block_id == requested_data_block_ids[j])
19222                 {
19223                     found = 1;
19224                     break;
19225                 }
19226             }
19227             if(!found)
19228             {
19229                 continue;
19230             }
19231         }
19232
19233         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
19234            p_data->last_retrieved_frame >=
19235            frame_set->first_frame + frame_set->n_frames))
19236         {
19237             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19238                                                                       TNG_USE_HASH, block_id);
19239             if(stat == TNG_CRITICAL)
19240             {
19241                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19242                     __FILE__, __LINE__);
19243                 return(stat);
19244             }
19245             if(stat == TNG_FAILURE)
19246             {
19247                 continue;
19248             }
19249         }
19250         if(frame_set->first_frame != current_frame &&
19251            p_data->last_retrieved_frame >= 0)
19252         {
19253             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
19254         }
19255         else
19256         {
19257             data_frame = p_data->first_frame_with_data;
19258         }
19259         frame_diff = data_frame - current_frame;
19260         if(frame_diff < 0)
19261         {
19262             continue;
19263         }
19264         if(min_diff == -1 || frame_diff <= min_diff)
19265         {
19266             if(frame_diff < min_diff)
19267             {
19268                 *n_data_blocks_in_next_frame = 1;
19269             }
19270             else
19271             {
19272                 *n_data_blocks_in_next_frame += 1;
19273             }
19274             if(n_requested_data_block_ids <= 0)
19275             {
19276                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19277                 temp = realloc(*data_block_ids_in_next_frame, size);
19278                 if(!temp)
19279                 {
19280                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19281                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19282                            __FILE__, __LINE__);
19283                     free(*data_block_ids_in_next_frame);
19284                     *data_block_ids_in_next_frame = 0;
19285                     return(TNG_CRITICAL);
19286                 }
19287                 *data_block_ids_in_next_frame = temp;
19288             }
19289             else
19290             {
19291                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19292             }
19293             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19294
19295             min_diff = frame_diff;
19296         }
19297     }
19298     for(i = 0; i < frame_set->n_data_blocks; i++)
19299     {
19300         np_data = &frame_set->tr_data[i];
19301         block_id = np_data->block_id;
19302
19303         if(n_requested_data_block_ids > 0)
19304         {
19305             found = 0;
19306             for(j = 0; j < n_requested_data_block_ids; j++)
19307             {
19308                 if(block_id == requested_data_block_ids[j])
19309                 {
19310                     found = 1;
19311                     break;
19312                 }
19313             }
19314             if(!found)
19315             {
19316                 continue;
19317             }
19318         }
19319
19320         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
19321            np_data->last_retrieved_frame >=
19322            frame_set->first_frame + frame_set->n_frames))
19323         {
19324             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19325                                                                       TNG_USE_HASH, block_id);
19326             if(stat == TNG_CRITICAL)
19327             {
19328                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19329                     __FILE__, __LINE__);
19330                 return(stat);
19331             }
19332             if(stat == TNG_FAILURE)
19333             {
19334                 continue;
19335             }
19336         }
19337         if(frame_set->first_frame != current_frame &&
19338            np_data->last_retrieved_frame >= 0)
19339         {
19340             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
19341         }
19342         else
19343         {
19344             data_frame = np_data->first_frame_with_data;
19345         }
19346         frame_diff = data_frame - current_frame;
19347         if(frame_diff < 0)
19348         {
19349             continue;
19350         }
19351         if(min_diff == -1 || frame_diff <= min_diff)
19352         {
19353             if(frame_diff < min_diff)
19354             {
19355                 *n_data_blocks_in_next_frame = 1;
19356             }
19357             else
19358             {
19359                 *n_data_blocks_in_next_frame += 1;
19360             }
19361             if(n_requested_data_block_ids <= 0)
19362             {
19363                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19364                 temp = realloc(*data_block_ids_in_next_frame, size);
19365                 if(!temp)
19366                 {
19367                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19368                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19369                            __FILE__, __LINE__);
19370                     free(*data_block_ids_in_next_frame);
19371                     *data_block_ids_in_next_frame = 0;
19372                     return(TNG_CRITICAL);
19373                 }
19374                 *data_block_ids_in_next_frame = temp;
19375             }
19376             else
19377             {
19378                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19379             }
19380             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19381
19382             min_diff = frame_diff;
19383         }
19384     }
19385     if(min_diff < 0)
19386     {
19387         return(TNG_FAILURE);
19388     }
19389     *next_frame = current_frame + min_diff;
19390
19391     return(TNG_SUCCESS);
19392 }
19393
19394 /*
19395 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
19396                 (tng_trajectory_t tng_data,
19397                  int64_t *n_data_blocks,
19398                  int64_t **data_block_ids,
19399                  char ***data_block_names,
19400                  int64_t **stride_lengths,
19401                  int64_t **n_values_per_frame,
19402                  char **block_types,
19403                  char **dependencies,
19404                  char **compressions)
19405 {
19406     tng_gen_block_t block;
19407     int64_t orig_file_pos, file_pos;
19408
19409     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19410     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
19411     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19412     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
19413     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
19414
19415     orig_file_pos = ftello(tng_data->input_file);
19416
19417     if(!tng_data->input_file_len)
19418     {
19419         fseeko(tng_data->input_file, 0, SEEK_END);
19420         tng_data->input_file_len = ftello(tng_data->input_file);
19421     }
19422
19423     fseeko(tng_data->input_file, 0, SEEK_SET);
19424     file_pos = 0;
19425
19426     *n_data_blocks = 0;
19427
19428     tng_block_init(&block);
19429
19430     while(file_pos < tng_data->input_file_len &&
19431           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
19432     {
19433         if(block->id > TNG_TRAJECTORY_FRAME_SET)
19434         {
19435
19436         }
19437         file_pos += (block->block_contents_size + block->header_contents_size);
19438         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
19439     }
19440
19441     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
19442
19443     return(TNG_SUCCESS);
19444 }
19445 */
19446 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
19447                 (tng_trajectory_t tng_data,
19448                  const int64_t prev_frame)
19449 {
19450     tng_function_status stat;
19451     FILE *temp = tng_data->input_file;
19452
19453     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19454     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
19455
19456     tng_data->input_file = tng_data->output_file;
19457
19458     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
19459     if(stat != TNG_SUCCESS)
19460     {
19461         return(stat);
19462     }
19463
19464     tng_data->current_trajectory_frame_set_output_file_pos =
19465     tng_data->current_trajectory_frame_set_input_file_pos;
19466
19467     tng_data->input_file = temp;
19468
19469     return(TNG_SUCCESS);
19470 }