TNG: Handle large files on 32 bit systems.
[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     double *d_dest = 0;
5061     float *f_dest = 0;
5062     int64_t offset;
5063     int result;
5064     (void)tng_data;
5065
5066     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
5067
5068     if(block->id != TNG_TRAJ_POSITIONS &&
5069        block->id != TNG_TRAJ_VELOCITIES)
5070     {
5071         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
5072                "TNG method.\n");
5073         return(TNG_FAILURE);
5074     }
5075     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
5076     {
5077         fprintf(stderr, "TNG library: Data type not supported.\n");
5078         return(TNG_FAILURE);
5079     }
5080
5081     temp_data_contents = malloc(uncompressed_len);
5082     if(!temp_data_contents)
5083     {
5084         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5085                 uncompressed_len, __FILE__, __LINE__);
5086         return(TNG_CRITICAL);
5087     }
5088
5089     memcpy(temp_data_contents, (char *)start_pos, uncompressed_len);
5090
5091     if(type == TNG_FLOAT_DATA)
5092     {
5093         f_dest = malloc(uncompressed_len);
5094         if(!f_dest)
5095         {
5096             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5097                 uncompressed_len, __FILE__, __LINE__);
5098             free(temp_data_contents);
5099             return(TNG_CRITICAL);
5100         }
5101         result = tng_compress_uncompress_float(temp_data_contents, f_dest);
5102     }
5103     else
5104     {
5105         d_dest = malloc(uncompressed_len);
5106         if(!d_dest)
5107         {
5108             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5109                 uncompressed_len, __FILE__, __LINE__);
5110             free(temp_data_contents);
5111             return(TNG_CRITICAL);
5112         }
5113         result = tng_compress_uncompress(temp_data_contents, d_dest);
5114     }
5115
5116     if(result == 1)
5117     {
5118         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
5119         free(temp_data_contents);
5120         return(TNG_FAILURE);
5121     }
5122
5123     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
5124
5125     block->block_contents_size = (int64_t)(uncompressed_len + offset);
5126
5127     temp = realloc(block->block_contents, uncompressed_len + offset);
5128     if(!temp)
5129     {
5130         free(block->block_contents);
5131         block->block_contents = 0;
5132         if(d_dest)
5133         {
5134             free(d_dest);
5135         }
5136         if(f_dest)
5137         {
5138             free(f_dest);
5139         }
5140         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5141                block->block_contents_size, __FILE__, __LINE__);
5142         free(temp_data_contents);
5143         return(TNG_CRITICAL);
5144     }
5145
5146     if(type == TNG_FLOAT_DATA)
5147     {
5148         memcpy(temp + offset, f_dest, uncompressed_len);
5149     }
5150     else
5151     {
5152         memcpy(temp + offset, d_dest, uncompressed_len);
5153     }
5154
5155     block->block_contents = temp;
5156
5157     free(temp_data_contents);
5158     if(d_dest)
5159     {
5160         free(d_dest);
5161     }
5162     if(f_dest)
5163     {
5164         free(f_dest);
5165     }
5166     return(TNG_SUCCESS);
5167 }
5168
5169 #ifdef USE_ZLIB
5170 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
5171                                              tng_gen_block_t block,
5172                                              void *start_pos, const int len)
5173 {
5174     Bytef *dest;
5175     char *temp;
5176     unsigned long max_len, stat, offset;
5177     (void)tng_data;
5178
5179     max_len = compressBound(len);
5180     dest = malloc(max_len);
5181     if(!dest)
5182     {
5183         fprintf(stderr, "TNG library: Cannot allocate memory (%ld bytes). %s: %d\n",
5184                max_len, __FILE__, __LINE__);
5185         return(TNG_CRITICAL);
5186     }
5187
5188     stat = compress(dest, &max_len, start_pos, len);
5189     if(stat != (unsigned long)Z_OK)
5190     {
5191         free(dest);
5192         if(stat == (unsigned long)Z_MEM_ERROR)
5193         {
5194             fprintf(stderr, "TNG library: Not enough memory. ");
5195         }
5196         else if(stat == (unsigned long)Z_BUF_ERROR)
5197         {
5198             fprintf(stderr, "TNG library: Destination buffer too small. ");
5199         }
5200         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
5201         return(TNG_FAILURE);
5202     }
5203
5204     offset = (char *)start_pos - block->block_contents;
5205
5206     block->block_contents_size = max_len + offset;
5207
5208     temp = realloc(block->block_contents, block->block_contents_size);
5209     if(!temp)
5210     {
5211         free(block->block_contents);
5212         free(dest);
5213         block->block_contents = 0;
5214         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5215                block->block_contents_size, __FILE__, __LINE__);
5216         return(TNG_CRITICAL);
5217     }
5218
5219     block->block_contents = temp;
5220
5221     memcpy(temp + offset, dest, max_len);
5222
5223     free(dest);
5224
5225     return(TNG_SUCCESS);
5226 }
5227
5228 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
5229                                                tng_gen_block_t block,
5230                                                void *start_pos,
5231                                                unsigned long uncompressed_len)
5232 {
5233     Bytef *dest;
5234     char *temp;
5235     unsigned long stat;
5236     int offset;
5237     (void)tng_data;
5238
5239     offset = (char *)start_pos - (char *)block->block_contents;
5240
5241     dest = malloc(uncompressed_len);
5242     if(!dest)
5243     {
5244         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
5245                uncompressed_len, __FILE__, __LINE__);
5246         return(TNG_CRITICAL);
5247     }
5248
5249     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
5250                       block->block_contents_size - offset);
5251
5252     if(stat != Z_OK)
5253     {
5254         free(dest);
5255         if(stat == (unsigned long)Z_MEM_ERROR)
5256         {
5257             fprintf(stderr, "TNG library: Not enough memory. ");
5258         }
5259         else if(stat == (unsigned long)Z_BUF_ERROR)
5260         {
5261             fprintf(stderr, "TNG library: Destination buffer too small. ");
5262         }
5263         else if(stat == (unsigned long)Z_DATA_ERROR)
5264         {
5265             fprintf(stderr, "TNG library: Data corrupt. ");
5266         }
5267         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
5268                __LINE__);
5269         return(TNG_FAILURE);
5270     }
5271
5272
5273     block->block_contents_size = uncompressed_len + offset;
5274
5275     temp = realloc(block->block_contents, uncompressed_len + offset);
5276     if(!temp)
5277     {
5278         free(block->block_contents);
5279         block->block_contents = 0;
5280         free(dest);
5281         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5282                block->block_contents_size, __FILE__, __LINE__);
5283         return(TNG_CRITICAL);
5284     }
5285
5286     memcpy(temp + offset, dest, uncompressed_len);
5287
5288     block->block_contents = temp;
5289
5290     free(dest);
5291     return(TNG_SUCCESS);
5292 }
5293 #endif
5294
5295 /** Allocate memory for storing particle data.
5296  * The allocated block will be refered to by data->values.
5297  * @param tng_data is a trajectory data container.
5298  * @param data is the data struct, which will contain the allocated memory in
5299  * data->values.
5300  * @param n_frames is the number of frames of data to store.
5301  * @param n_particles is the number of particles with data.
5302  * @param n_values_per_frame is the number of data values per particle and
5303  * frame.
5304  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5305  * error has occured.
5306  */
5307 static tng_function_status tng_allocate_particle_data_mem
5308                 (tng_trajectory_t tng_data,
5309                  tng_particle_data_t data,
5310                  int64_t n_frames,
5311                  int64_t stride_length,
5312                  const int64_t n_particles,
5313                  const int64_t n_values_per_frame)
5314 {
5315     void ***values;
5316     int64_t i, j, k, size, frame_alloc;
5317     (void)tng_data;
5318
5319     if(n_particles == 0 || n_values_per_frame == 0)
5320     {
5321         return(TNG_FAILURE);
5322     }
5323
5324     if(data->strings && data->datatype == TNG_CHAR_DATA)
5325     {
5326         for(i = 0; i < data->n_frames; i++)
5327         {
5328             for(j = 0; j < n_particles; j++)
5329             {
5330                 for(k = 0; k < data->n_values_per_frame; k++)
5331                 {
5332                     if(data->strings[i][j][k])
5333                     {
5334                         free(data->strings[i][j][k]);
5335                     }
5336                 }
5337                 free(data->strings[i][j]);
5338             }
5339             free(data->strings[i]);
5340         }
5341         free(data->strings);
5342     }
5343     data->n_frames = n_frames;
5344     n_frames = tng_max_i64(1, n_frames);
5345     data->stride_length = tng_max_i64(1, stride_length);
5346     data->n_values_per_frame = n_values_per_frame;
5347     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5348
5349     if(data->datatype == TNG_CHAR_DATA)
5350     {
5351         data->strings = malloc(sizeof(char ***) * frame_alloc);
5352         for(i = 0; i < frame_alloc; i++)
5353         {
5354             data->strings[i] = malloc(sizeof(char **) *
5355                                     n_particles);
5356             if(!data->strings[i])
5357             {
5358                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5359                     sizeof(union data_values *) * n_particles,
5360                     __FILE__, __LINE__);
5361                 return(TNG_CRITICAL);
5362             }
5363             for(j = 0; j < n_particles; j++)
5364             {
5365                 data->strings[i][j] = malloc(sizeof(char *) *
5366                                             n_values_per_frame);
5367                 if(!data->strings[i][j])
5368                 {
5369                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5370                         sizeof(union data_values) * n_values_per_frame,
5371                         __FILE__, __LINE__);
5372                     return(TNG_CRITICAL);
5373                 }
5374                 for(k = 0; k < n_values_per_frame; k++)
5375                 {
5376                     data->strings[i][j][k] = 0;
5377                 }
5378             }
5379         }
5380     }
5381     else
5382     {
5383         switch(data->datatype)
5384         {
5385         case TNG_INT_DATA:
5386             size = sizeof(int64_t);
5387             break;
5388         case TNG_FLOAT_DATA:
5389             size = sizeof(float);
5390             break;
5391         case TNG_DOUBLE_DATA:
5392         default:
5393             size = sizeof(double);
5394         }
5395
5396         values = realloc(data->values,
5397                          size * frame_alloc *
5398                          n_particles * n_values_per_frame);
5399         if(!values)
5400         {
5401             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5402                    size * frame_alloc *
5403                    n_particles * n_values_per_frame,
5404                    __FILE__, __LINE__);
5405             free(data->values);
5406             data->values = 0;
5407             return(TNG_CRITICAL);
5408         }
5409         data->values = values;
5410     }
5411     return(TNG_SUCCESS);
5412 }
5413
5414 static tng_function_status tng_particle_data_find
5415                 (tng_trajectory_t tng_data,
5416                  const int64_t id,
5417                  tng_particle_data_t *data)
5418 {
5419     int64_t block_index, i;
5420     tng_trajectory_frame_set_t frame_set = &tng_data->
5421                                            current_trajectory_frame_set;
5422     char block_type_flag;
5423
5424     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5425        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5426     {
5427         block_type_flag = TNG_TRAJECTORY_BLOCK;
5428     }
5429     else
5430     {
5431         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5432     }
5433
5434     block_index = -1;
5435     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5436     {
5437         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
5438         {
5439             *data = &frame_set->tr_particle_data[i];
5440             if((*data)->block_id == id)
5441             {
5442                 block_index = i;
5443                 break;
5444             }
5445         }
5446     }
5447     else
5448     {
5449         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
5450         {
5451             *data = &tng_data->non_tr_particle_data[i];
5452             if((*data)->block_id == id)
5453             {
5454                 block_index = i;
5455                 break;
5456             }
5457         }
5458     }
5459     if(block_index == -1)
5460     {
5461         return(TNG_FAILURE);
5462     }
5463     return(TNG_SUCCESS);
5464 }
5465
5466 static tng_function_status tng_data_find
5467                 (tng_trajectory_t tng_data,
5468                  const int64_t id,
5469                  tng_non_particle_data_t *data)
5470 {
5471     int64_t block_index, i;
5472     tng_trajectory_frame_set_t frame_set = &tng_data->
5473                                            current_trajectory_frame_set;
5474     char block_type_flag;
5475
5476     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5477        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5478     {
5479         block_type_flag = TNG_TRAJECTORY_BLOCK;
5480     }
5481     else
5482     {
5483         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5484     }
5485
5486     block_index = -1;
5487     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5488     {
5489         for(i = 0; i < frame_set->n_data_blocks; i++)
5490         {
5491             *data = &frame_set->tr_data[i];
5492             if((*data)->block_id == id)
5493             {
5494                 block_index = i;
5495                 break;
5496             }
5497         }
5498         if(block_index == -1)
5499         {
5500             for(i = 0; i < tng_data->n_data_blocks; i++)
5501             {
5502                 *data = &tng_data->non_tr_data[i];
5503                 if((*data)->block_id == id)
5504                 {
5505                     block_index = i;
5506                     break;
5507                 }
5508             }
5509         }
5510     }
5511     else
5512     {
5513         for(i = 0; i < tng_data->n_data_blocks; i++)
5514         {
5515             *data = &tng_data->non_tr_data[i];
5516             if((*data)->block_id == id)
5517             {
5518                 block_index = i;
5519                 break;
5520             }
5521         }
5522     }
5523     if(block_index == -1)
5524     {
5525         return(TNG_FAILURE);
5526     }
5527     return(TNG_SUCCESS);
5528 }
5529
5530 static tng_function_status tng_data_block_len_calculate
5531                 (const tng_trajectory_t tng_data,
5532                  const tng_particle_data_t data,
5533                  const tng_bool is_particle_data,
5534                  const int64_t n_frames,
5535                  const int64_t frame_step,
5536                  const int64_t stride_length,
5537                  const int64_t num_first_particle,
5538                  const int64_t n_particles,
5539                  const char dependency,
5540                  int64_t *data_start_pos,
5541                  int64_t *len)
5542 {
5543     int size;
5544     int64_t i, j, k;
5545     char ***first_dim_values, **second_dim_values;
5546     (void)tng_data;
5547
5548     if(data == 0)
5549     {
5550         return(TNG_SUCCESS);
5551     }
5552
5553     switch(data->datatype)
5554     {
5555     case TNG_CHAR_DATA:
5556         size = 1;
5557         break;
5558     case TNG_INT_DATA:
5559         size = sizeof(int64_t);
5560         break;
5561     case TNG_FLOAT_DATA:
5562         size = sizeof(float);
5563         break;
5564     case TNG_DOUBLE_DATA:
5565     default:
5566         size = sizeof(double);
5567     }
5568
5569     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5570            sizeof(data->codec_id);
5571     if(is_particle_data)
5572     {
5573         *len += sizeof(num_first_particle) + sizeof(n_particles);
5574     }
5575
5576     if(stride_length > 1)
5577     {
5578         *len += sizeof(data->first_frame_with_data) +
5579                 sizeof(data->stride_length);
5580     }
5581
5582     if(data->codec_id != TNG_UNCOMPRESSED)
5583     {
5584         *len += sizeof(data->compression_multiplier);
5585     }
5586
5587     if(dependency & TNG_FRAME_DEPENDENT)
5588     {
5589         *len += sizeof(char);
5590     }
5591
5592     *data_start_pos = *len;
5593
5594     if(data->datatype == TNG_CHAR_DATA)
5595     {
5596         if(is_particle_data)
5597         {
5598             for(i = 0; i < n_frames; i++)
5599             {
5600                 first_dim_values = data->strings[i];
5601                 for(j = num_first_particle; j < num_first_particle + n_particles;
5602                     j++)
5603                 {
5604                     second_dim_values = first_dim_values[j];
5605                     for(k = 0; k < data->n_values_per_frame; k++)
5606                     {
5607                         *len += strlen(second_dim_values[k]) + 1;
5608                     }
5609                 }
5610             }
5611         }
5612         else
5613         {
5614             for(i = 0; i < n_frames; i++)
5615             {
5616                 second_dim_values = ((tng_non_particle_data_t)data)->strings[i];
5617                 for(j = 0; j < data->n_values_per_frame; j++)
5618                 {
5619                     *len += strlen(second_dim_values[j]) + 1;
5620                 }
5621             }
5622         }
5623     }
5624     else
5625     {
5626         *len += size * frame_step * n_particles * data->n_values_per_frame;
5627     }
5628
5629     return(TNG_SUCCESS);
5630 }
5631
5632 /** Read the values of a particle data block
5633  * @param tng_data is a trajectory data container.
5634  * @param block is the block to store the data (should already contain
5635  * the block headers and the block contents).
5636  * @param offset is the reading offset to point at the place where the actual
5637  * values are stored, starting from the beginning of the block_contents. The
5638  * offset is changed during the reading.
5639  * @param datatype is the type of data of the data block (char, int, float or
5640  * double).
5641  * @param num_first_particle is the number of the first particle in the data
5642  * block. This should be the same as in the corresponding particle mapping
5643  * block.
5644  * @param n_particles is the number of particles in the data block. This should
5645  * be the same as in the corresponding particle mapping block.
5646  * @param first_frame_with_data is the frame number of the first frame with data
5647  * in this data block.
5648  * @param stride_length is the number of frames between each data entry.
5649  * @param n_frames is the number of frames in this data block.
5650  * @param n_values is the number of values per particle and frame stored in this
5651  * data block.
5652  * @param codec_id is the ID of the codec to compress the data.
5653  * @param multiplier is the multiplication factor applied to each data value
5654  * before compression. This factor is applied since some compression algorithms
5655  * work only on integers.
5656  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5657  * error has occured.
5658  */
5659 static tng_function_status tng_particle_data_read
5660                 (tng_trajectory_t tng_data,
5661                  tng_gen_block_t block,
5662                  int *offset,
5663                  const char datatype,
5664                  const int64_t num_first_particle,
5665                  const int64_t n_particles,
5666                  const int64_t first_frame_with_data,
5667                  const int64_t stride_length,
5668                  int64_t n_frames,
5669                  const int64_t n_values,
5670                  const int64_t codec_id,
5671                  const double multiplier)
5672 {
5673     int64_t i, j, k, tot_n_particles, n_frames_div;
5674     int size, len;
5675     int64_t data_size;
5676     char ***first_dim_values, **second_dim_values;
5677     tng_particle_data_t data;
5678     tng_trajectory_frame_set_t frame_set =
5679     &tng_data->current_trajectory_frame_set;
5680     char block_type_flag;
5681
5682     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5683
5684     switch(datatype)
5685     {
5686     case TNG_CHAR_DATA:
5687         size = 1;
5688         break;
5689     case TNG_INT_DATA:
5690         size = sizeof(int64_t);
5691         break;
5692     case TNG_FLOAT_DATA:
5693         size = sizeof(float);
5694         break;
5695     case TNG_DOUBLE_DATA:
5696     default:
5697         size = sizeof(double);
5698     }
5699
5700     /* If the block does not exist, create it */
5701     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5702     {
5703         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5704         {
5705             block_type_flag = TNG_TRAJECTORY_BLOCK;
5706         }
5707         else
5708         {
5709             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5710         }
5711
5712         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
5713            TNG_SUCCESS)
5714         {
5715             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5716                    __FILE__, __LINE__);
5717             return(TNG_CRITICAL);
5718         }
5719         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5720         {
5721             data = &frame_set->tr_particle_data[frame_set->
5722                                                 n_particle_data_blocks - 1];
5723         }
5724         else
5725         {
5726             data = &tng_data->non_tr_particle_data[tng_data->
5727                                                    n_particle_data_blocks - 1];
5728         }
5729         data->block_id = block->id;
5730
5731         data->block_name = malloc(strlen(block->name) + 1);
5732         if(!data->block_name)
5733         {
5734             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5735                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5736             return(TNG_CRITICAL);
5737         }
5738         strcpy(data->block_name, block->name);
5739
5740         data->datatype = datatype;
5741
5742         data->values = 0;
5743         /* FIXME: Memory leak from strings. */
5744         data->strings = 0;
5745         data->n_frames = 0;
5746         data->codec_id = codec_id;
5747         data->compression_multiplier = multiplier;
5748         data->last_retrieved_frame = -1;
5749     }
5750
5751     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
5752        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
5753        tng_data->var_num_atoms_flag)
5754     {
5755         tot_n_particles = frame_set->n_particles;
5756     }
5757     else
5758     {
5759         tot_n_particles = tng_data->n_particles;
5760     }
5761
5762     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5763
5764     if(codec_id != TNG_UNCOMPRESSED)
5765     {
5766         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
5767         switch(codec_id)
5768         {
5769         case TNG_XTC_COMPRESSION:
5770             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5771             break;
5772         case TNG_TNG_COMPRESSION:
5773 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5774             if(tng_uncompress(tng_data, block, datatype,
5775                               block->block_contents + *offset,
5776                               data_size) != TNG_SUCCESS)
5777             {
5778                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5779                        __FILE__, __LINE__);
5780                 return(TNG_CRITICAL);
5781             }
5782 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5783             break;
5784 #ifdef USE_ZLIB
5785         case TNG_GZIP_COMPRESSION:
5786 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5787             if(tng_gzip_uncompress(tng_data, block,
5788                                    block->block_contents + *offset,
5789                                    data_size) != TNG_SUCCESS)
5790             {
5791                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5792                     __LINE__);
5793                 return(TNG_CRITICAL);
5794             }
5795 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5796             break;
5797 #endif
5798         }
5799     }
5800     /* Allocate memory */
5801     if(!data->values || data->n_frames != n_frames ||
5802        data->n_values_per_frame != n_values)
5803     {
5804         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
5805                                           stride_length,
5806                                           tot_n_particles, n_values) !=
5807            TNG_SUCCESS)
5808         {
5809             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
5810                    __FILE__, __LINE__);
5811             return(TNG_CRITICAL);
5812         }
5813     }
5814
5815     data->first_frame_with_data = first_frame_with_data;
5816
5817     if(datatype == TNG_CHAR_DATA)
5818     {
5819         for(i = 0; i < n_frames_div; i++)
5820         {
5821             first_dim_values = data->strings[i];
5822             for(j = num_first_particle; j < num_first_particle + n_particles;
5823                 j++)
5824             {
5825                 second_dim_values = first_dim_values[j];
5826                 for(k = 0; k < n_values; k++)
5827                 {
5828                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5829                               TNG_MAX_STR_LEN);
5830                     if(second_dim_values[k])
5831                     {
5832                         free(second_dim_values[k]);
5833                     }
5834                     second_dim_values[k] = malloc(len);
5835                     if(!second_dim_values[k])
5836                     {
5837                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5838                             len, __FILE__, __LINE__);
5839                         return(TNG_CRITICAL);
5840                     }
5841                     strncpy(second_dim_values[k],
5842                             block->block_contents+*offset, len);
5843                     *offset += len;
5844                 }
5845             }
5846         }
5847     }
5848     else
5849     {
5850         memcpy((char *)data->values + n_frames_div * size * n_values *
5851                num_first_particle,
5852                block->block_contents + *offset,
5853                block->block_contents_size - *offset);
5854         switch(datatype)
5855         {
5856         case TNG_FLOAT_DATA:
5857             if(tng_data->input_endianness_swap_func_32)
5858             {
5859                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5860                 {
5861                     if(tng_data->input_endianness_swap_func_32(tng_data,
5862                         (int32_t *)((char *)data->values + i))
5863                         != TNG_SUCCESS)
5864                     {
5865                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5866                                 __FILE__, __LINE__);
5867                     }
5868                 }
5869             }
5870             break;
5871         case TNG_INT_DATA:
5872         case TNG_DOUBLE_DATA:
5873             if(tng_data->input_endianness_swap_func_64)
5874             {
5875                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5876                 {
5877                     if(tng_data->input_endianness_swap_func_64(tng_data,
5878                         (int64_t *)((char *)data->values + i))
5879                         != TNG_SUCCESS)
5880                     {
5881                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5882                                 __FILE__, __LINE__);
5883                     }
5884                 }
5885             }
5886             break;
5887         case TNG_CHAR_DATA:
5888             break;
5889         }
5890     }
5891     return(TNG_SUCCESS);
5892 }
5893
5894 /** Write a particle data block
5895  * @param tng_data is a trajectory data container.
5896  * @param block is the block to store the data (should already contain
5897  * the block headers and the block contents).
5898  * @param block_index is the index number of the data block in the frame set.
5899  * @param mapping is the particle mapping that is relevant for the data block.
5900  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5901  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5902  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5903  * error has occured.
5904  */
5905 static tng_function_status tng_particle_data_block_write
5906                 (tng_trajectory_t tng_data,
5907                  tng_gen_block_t block,
5908                  const int64_t block_index,
5909                  const tng_particle_mapping_t mapping,
5910                  const char hash_mode)
5911 {
5912     int64_t n_particles, num_first_particle, n_frames, stride_length;
5913     int64_t frame_step, data_start_pos;
5914     int64_t i, j, k;
5915     int size;
5916     size_t len, offset = 0;
5917     char dependency, temp, *temp_name;
5918     double multiplier;
5919     char ***first_dim_values, **second_dim_values;
5920     tng_trajectory_frame_set_t frame_set;
5921     tng_function_status stat;
5922
5923     tng_particle_data_t data;
5924     char block_type_flag;
5925
5926     frame_set = &tng_data->current_trajectory_frame_set;
5927
5928     /* If we have already started writing frame sets it is too late to write
5929      * non-trajectory data blocks */
5930     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5931     {
5932         block_type_flag = TNG_TRAJECTORY_BLOCK;
5933     }
5934     else
5935     {
5936         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5937     }
5938
5939     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5940     {
5941         return(TNG_CRITICAL);
5942     }
5943
5944     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5945     {
5946         data = &frame_set->tr_particle_data[block_index];
5947
5948         /* If this data block has not had any data added in this frame set
5949          * do not write it. */
5950         if(data->first_frame_with_data < frame_set->first_frame)
5951         {
5952             return(TNG_SUCCESS);
5953         }
5954
5955         stride_length = tng_max_i64(1, data->stride_length);
5956     }
5957     else
5958     {
5959         data = &tng_data->non_tr_particle_data[block_index];
5960         stride_length = 1;
5961     }
5962
5963     switch(data->datatype)
5964     {
5965     case TNG_CHAR_DATA:
5966         size = 1;
5967         break;
5968     case TNG_INT_DATA:
5969         size = sizeof(int64_t);
5970         break;
5971     case TNG_FLOAT_DATA:
5972         size = sizeof(float);
5973         break;
5974     case TNG_DOUBLE_DATA:
5975     default:
5976         size = sizeof(double);
5977     }
5978
5979     len = strlen(data->block_name) + 1;
5980
5981     if(!block->name || strlen(block->name) < len)
5982     {
5983         temp_name = realloc(block->name, len);
5984         if(!temp_name)
5985         {
5986             fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n", len,
5987                    __FILE__, __LINE__);
5988             free(block->name);
5989             block->name = 0;
5990             return(TNG_CRITICAL);
5991         }
5992         block->name = temp_name;
5993     }
5994     strncpy(block->name, data->block_name, len);
5995     block->id = data->block_id;
5996
5997     /* If writing frame independent data data->n_frames is 0, but n_frames
5998        is used for the loop writing the data (and reserving memory) and needs
5999        to be at least 1 */
6000     n_frames = tng_max_i64(1, data->n_frames);
6001
6002     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6003     {
6004         /* If the frame set is finished before writing the full number of frames
6005            make sure the data block is not longer than the frame set. */
6006         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6007
6008         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6009     }
6010
6011     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6012                  n_frames / stride_length;
6013
6014     /* TNG compression will use compression precision to get integers from
6015      * floating point data. The compression multiplier stores that information
6016      * to be able to return the precision of the compressed data. */
6017     if(data->codec_id == TNG_TNG_COMPRESSION)
6018     {
6019         data->compression_multiplier = tng_data->compression_precision;
6020     }
6021     /* Uncompressed data blocks do not use compression multipliers at all.
6022      * GZip compression does not need it either. */
6023     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6024     {
6025         data->compression_multiplier = 1.0;
6026     }
6027
6028     if(mapping && mapping->n_particles != 0)
6029     {
6030         n_particles = mapping->n_particles;
6031         num_first_particle = mapping->num_first_particle;
6032     }
6033     else
6034     {
6035         num_first_particle = 0;
6036         if(tng_data->var_num_atoms_flag)
6037         {
6038             n_particles = frame_set->n_particles;
6039         }
6040         else
6041         {
6042             n_particles = tng_data->n_particles;
6043         }
6044     }
6045
6046     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6047     {
6048         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
6049     }
6050     else
6051     {
6052         dependency = TNG_PARTICLE_DEPENDENT;
6053     }
6054
6055     if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
6056                                     frame_step, stride_length, num_first_particle,
6057                                     n_particles, dependency, &data_start_pos,
6058                                     &block->block_contents_size) != TNG_SUCCESS)
6059     {
6060         fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
6061                 __FILE__, __LINE__);
6062         return(TNG_CRITICAL);
6063     }
6064
6065     if(block->block_contents)
6066     {
6067         free(block->block_contents);
6068     }
6069     block->block_contents = malloc(block->block_contents_size);
6070     if(!block->block_contents)
6071     {
6072         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6073                block->block_contents_size, __FILE__, __LINE__);
6074         return(TNG_CRITICAL);
6075     }
6076
6077
6078     memcpy(block->block_contents, &data->datatype, sizeof(char));
6079     offset += sizeof(char);
6080
6081     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6082     offset += sizeof(char);
6083
6084     if(dependency & TNG_FRAME_DEPENDENT)
6085     {
6086         if(stride_length > 1)
6087         {
6088             temp = 1;
6089         }
6090         else
6091         {
6092             temp = 0;
6093         }
6094         memcpy(block->block_contents+offset, &temp, sizeof(char));
6095         offset += sizeof(char);
6096     }
6097
6098     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6099            sizeof(data->n_values_per_frame));
6100     if(tng_data->output_endianness_swap_func_64)
6101     {
6102         if(tng_data->output_endianness_swap_func_64(tng_data,
6103            (int64_t *)block->header_contents+offset)
6104             != TNG_SUCCESS)
6105         {
6106             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6107                     __FILE__, __LINE__);
6108         }
6109     }
6110     offset += sizeof(data->n_values_per_frame);
6111
6112     memcpy(block->block_contents+offset, &data->codec_id,
6113            sizeof(data->codec_id));
6114     if(tng_data->output_endianness_swap_func_64)
6115     {
6116         if(tng_data->output_endianness_swap_func_64(tng_data,
6117            (int64_t *)block->header_contents+offset)
6118             != TNG_SUCCESS)
6119         {
6120             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6121                     __FILE__, __LINE__);
6122         }
6123     }
6124     offset += sizeof(data->codec_id);
6125
6126     if(data->codec_id != TNG_UNCOMPRESSED)
6127     {
6128         memcpy(block->block_contents+offset, &data->compression_multiplier,
6129                sizeof(data->compression_multiplier));
6130         if(tng_data->output_endianness_swap_func_64)
6131         {
6132             if(tng_data->output_endianness_swap_func_64(tng_data,
6133                (int64_t *)block->header_contents+offset)
6134                 != TNG_SUCCESS)
6135             {
6136                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6137                         __FILE__, __LINE__);
6138             }
6139         }
6140         offset += sizeof(data->compression_multiplier);
6141     }
6142
6143     if(data->n_frames > 0 && stride_length > 1)
6144     {
6145         /* FIXME: first_frame_with_data is not reliably set */
6146         if(data->first_frame_with_data == 0)
6147         {
6148             data->first_frame_with_data = frame_set->first_frame;
6149         }
6150         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6151                sizeof(data->first_frame_with_data));
6152         if(tng_data->output_endianness_swap_func_64)
6153         {
6154             if(tng_data->output_endianness_swap_func_64(tng_data,
6155                (int64_t *)block->header_contents+offset)
6156                 != TNG_SUCCESS)
6157             {
6158                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6159                         __FILE__, __LINE__);
6160             }
6161         }
6162         offset += sizeof(data->first_frame_with_data);
6163
6164         memcpy(block->block_contents+offset, &stride_length,
6165                sizeof(stride_length));
6166         if(tng_data->output_endianness_swap_func_64)
6167         {
6168             if(tng_data->output_endianness_swap_func_64(tng_data,
6169                (int64_t *)block->header_contents+offset)
6170                 != TNG_SUCCESS)
6171             {
6172                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6173                         __FILE__, __LINE__);
6174             }
6175         }
6176         offset += sizeof(stride_length);
6177     }
6178
6179
6180     memcpy(block->block_contents+offset, &num_first_particle,
6181            sizeof(num_first_particle));
6182     if(tng_data->output_endianness_swap_func_64)
6183     {
6184         if(tng_data->output_endianness_swap_func_64(tng_data,
6185            (int64_t *)block->header_contents+offset)
6186             != TNG_SUCCESS)
6187         {
6188             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6189                     __FILE__, __LINE__);
6190         }
6191     }
6192     offset += sizeof(num_first_particle);
6193
6194     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
6195     if(tng_data->output_endianness_swap_func_64)
6196     {
6197         if(tng_data->output_endianness_swap_func_64(tng_data,
6198            (int64_t *)block->header_contents+offset)
6199             != TNG_SUCCESS)
6200         {
6201             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6202                     __FILE__, __LINE__);
6203         }
6204     }
6205     offset += sizeof(n_particles);
6206
6207     if(data->datatype == TNG_CHAR_DATA)
6208     {
6209         if(data->strings)
6210         {
6211             for(i = 0; i < frame_step; i++)
6212             {
6213                 first_dim_values = data->strings[i];
6214                 for(j = num_first_particle; j < num_first_particle + n_particles;
6215                     j++)
6216                 {
6217                     second_dim_values = first_dim_values[j];
6218                     for(k = 0; k < data->n_values_per_frame; k++)
6219                     {
6220                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
6221                         strncpy(block->block_contents+offset,
6222                                 second_dim_values[k], len);
6223                         offset += len;
6224                     }
6225                 }
6226             }
6227         }
6228     }
6229     else if(data->values)
6230     {
6231         memcpy(block->block_contents + offset, data->values,
6232                block->block_contents_size - offset);
6233
6234         switch(data->datatype)
6235         {
6236         case TNG_FLOAT_DATA:
6237             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6238                data->codec_id == TNG_TNG_COMPRESSION)
6239             {
6240                 if(tng_data->input_endianness_swap_func_32)
6241                 {
6242                     for(i = offset; i < block->block_contents_size; i+=size)
6243                     {
6244                         if(tng_data->input_endianness_swap_func_32(tng_data,
6245                            (int32_t *)(block->block_contents + i))
6246                            != TNG_SUCCESS)
6247                         {
6248                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6249                                     __FILE__, __LINE__);
6250                         }
6251                     }
6252                 }
6253             }
6254             else
6255             {
6256                 multiplier = data->compression_multiplier;
6257                 if(fabs(multiplier - 1.0) > 0.00001 ||
6258                    tng_data->input_endianness_swap_func_32)
6259                 {
6260                     for(i = offset; i < block->block_contents_size; i+=size)
6261                     {
6262                         *(float *)(block->block_contents + i) *= (float)multiplier;
6263                         if(tng_data->input_endianness_swap_func_32 &&
6264                         tng_data->input_endianness_swap_func_32(tng_data,
6265                         (int32_t *)(block->block_contents + i))
6266                         != TNG_SUCCESS)
6267                         {
6268                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6269                                     __FILE__, __LINE__);
6270                         }
6271                     }
6272                 }
6273             }
6274             break;
6275         case TNG_INT_DATA:
6276             if(tng_data->input_endianness_swap_func_64)
6277             {
6278                 for(i = offset; i < block->block_contents_size; i+=size)
6279                 {
6280                     if(tng_data->input_endianness_swap_func_64(tng_data,
6281                        (int64_t *)(block->block_contents + i))
6282                        != TNG_SUCCESS)
6283                     {
6284                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6285                                 __FILE__, __LINE__);
6286                     }
6287                 }
6288             }
6289             break;
6290         case TNG_DOUBLE_DATA:
6291             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6292                data->codec_id == TNG_TNG_COMPRESSION)
6293             {
6294                 if(tng_data->input_endianness_swap_func_64)
6295                 {
6296                     for(i = offset; i < block->block_contents_size; i+=size)
6297                     {
6298                         if(tng_data->input_endianness_swap_func_64(tng_data,
6299                            (int64_t *)(block->block_contents + i))
6300                            != TNG_SUCCESS)
6301                         {
6302                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6303                                     __FILE__, __LINE__);
6304                         }
6305                     }
6306                 }
6307             }
6308             else
6309             {
6310                 multiplier = data->compression_multiplier;
6311                 if(fabs(multiplier - 1.0) > 0.00001 ||
6312                    tng_data->input_endianness_swap_func_64)
6313                 {
6314                     for(i = offset; i < block->block_contents_size; i+=size)
6315                     {
6316                         *(double *)(block->block_contents + i) *= multiplier;
6317                         if(tng_data->input_endianness_swap_func_64 &&
6318                         tng_data->input_endianness_swap_func_64(tng_data,
6319                         (int64_t *)(block->block_contents + i))
6320                         != TNG_SUCCESS)
6321                         {
6322                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6323                                     __FILE__, __LINE__);
6324                         }
6325                     }
6326                 }
6327             }
6328             break;
6329         case TNG_CHAR_DATA:
6330             break;
6331         }
6332     }
6333     else
6334     {
6335         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6336     }
6337
6338     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6339     frame_set->n_unwritten_frames = 0;
6340
6341     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6342     {
6343         switch(data->codec_id)
6344         {
6345         case TNG_XTC_COMPRESSION:
6346             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6347             data->codec_id = TNG_UNCOMPRESSED;
6348             break;
6349         case TNG_TNG_COMPRESSION:
6350             stat = tng_compress(tng_data, block, frame_step,
6351                                 n_particles, data->datatype,
6352                                 block->block_contents + data_start_pos);
6353             if(stat != TNG_SUCCESS)
6354             {
6355                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
6356                     __FILE__, __LINE__);
6357                 if(stat == TNG_CRITICAL)
6358                 {
6359                     return(TNG_CRITICAL);
6360                 }
6361                 /* Set the data again, but with no compression (to write only
6362                  * the relevant data) */
6363                 data->codec_id = TNG_UNCOMPRESSED;
6364                 stat = tng_particle_data_block_write(tng_data, block,
6365                                                      block_index, mapping,
6366                                                      hash_mode);
6367                 return(stat);
6368             }
6369             break;
6370 #ifdef USE_ZLIB
6371         case TNG_GZIP_COMPRESSION:
6372     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
6373             stat = tng_gzip_compress(tng_data, block,
6374                                      block->block_contents + data_start_pos,
6375                                      block->block_contents_size - data_start_pos);
6376             if(stat != TNG_SUCCESS)
6377             {
6378                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6379                     __LINE__);
6380                 if(stat == TNG_CRITICAL)
6381                 {
6382                     return(TNG_CRITICAL);
6383                 }
6384                 /* Set the data again, but with no compression (to write only
6385                  * the relevant data) */
6386                 data->codec_id = TNG_UNCOMPRESSED;
6387                 stat = tng_particle_data_block_write(tng_data, block,
6388                                                      block_index, mapping,
6389                                                      hash_mode);
6390                 return(stat);
6391             }
6392     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
6393             break;
6394 #endif
6395         }
6396     }
6397
6398     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6399     {
6400         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6401                tng_data->output_file_path, __FILE__, __LINE__);
6402         return(TNG_CRITICAL);
6403     }
6404
6405     if(fwrite(block->block_contents, block->block_contents_size, 1,
6406         tng_data->output_file) != 1)
6407     {
6408         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6409                 __LINE__);
6410         return(TNG_CRITICAL);
6411     }
6412
6413     return(TNG_SUCCESS);
6414 }
6415
6416 /* TEST: */
6417 /** Create a non-particle data block
6418  * @param tng_data is a trajectory data container.
6419  * @param block_type_flag specifies if this is a trajectory block or a
6420  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
6421  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6422  * error has occured.
6423  */
6424 static tng_function_status tng_data_block_create
6425                 (tng_trajectory_t tng_data,
6426                  const char block_type_flag)
6427 {
6428     tng_trajectory_frame_set_t frame_set =
6429     &tng_data->current_trajectory_frame_set;
6430
6431     tng_non_particle_data_t data;
6432
6433     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6434     {
6435         frame_set->n_data_blocks++;
6436         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
6437                        frame_set->n_data_blocks);
6438         if(!data)
6439         {
6440             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6441                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
6442                 __FILE__, __LINE__);
6443             free(frame_set->tr_data);
6444             frame_set->tr_data = 0;
6445             return(TNG_CRITICAL);
6446         }
6447         frame_set->tr_data = data;
6448     }
6449     else
6450     {
6451         tng_data->n_data_blocks++;
6452         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
6453                         tng_data->n_data_blocks);
6454         if(!data)
6455         {
6456             fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
6457                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
6458                 __FILE__, __LINE__);
6459             free(tng_data->non_tr_data);
6460             tng_data->non_tr_data = 0;
6461             return(TNG_CRITICAL);
6462         }
6463         tng_data->non_tr_data = data;
6464     }
6465
6466     return(TNG_SUCCESS);
6467 }
6468
6469 /* TEST: */
6470 /** Allocate memory for storing non-particle data.
6471  * The allocated block will be refered to by data->values.
6472  * @param tng_data is a trajectory data container.
6473  * @param data is the data struct, which will contain the allocated memory in
6474  * data->values.
6475  * @param n_frames is the number of frames of data to store.
6476  * @param n_values_per_frame is the number of data values per frame.
6477  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6478  * error has occured.
6479  */
6480 static tng_function_status tng_allocate_data_mem
6481                 (tng_trajectory_t tng_data,
6482                  tng_non_particle_data_t data,
6483                  int64_t n_frames,
6484                  int64_t stride_length,
6485                  const int64_t n_values_per_frame)
6486 {
6487     void **values;
6488     int64_t i, j, size, frame_alloc;
6489     (void)tng_data;
6490
6491     if(n_values_per_frame == 0)
6492     {
6493         return(TNG_FAILURE);
6494     }
6495
6496     if(data->strings && data->datatype == TNG_CHAR_DATA)
6497     {
6498         for(i = 0; i < data->n_frames; i++)
6499         {
6500             for(j = 0; j < data->n_values_per_frame; j++)
6501             {
6502                 if(data->strings[i][j])
6503                 {
6504                     free(data->strings[i][j]);
6505                     data->strings[i][j] = 0;
6506                 }
6507             }
6508             free(data->strings[i]);
6509             data->strings[i] = 0;
6510         }
6511         free(data->strings);
6512     }
6513     data->n_frames = n_frames;
6514     data->stride_length = tng_max_i64(1, stride_length);
6515     n_frames = tng_max_i64(1, n_frames);
6516     data->n_values_per_frame = n_values_per_frame;
6517     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6518
6519     if(data->datatype == TNG_CHAR_DATA)
6520     {
6521         data->strings = malloc(sizeof(char **) * frame_alloc);
6522         for(i = 0; i < frame_alloc; i++)
6523         {
6524             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
6525             if(!data->strings[i])
6526             {
6527                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6528                        n_values_per_frame,
6529                        __FILE__, __LINE__);
6530                 return(TNG_CRITICAL);
6531             }
6532             for(j = 0; j < n_values_per_frame; j++)
6533             {
6534                 data->strings[i][j] = 0;
6535             }
6536         }
6537     }
6538     else
6539     {
6540         switch(data->datatype)
6541         {
6542         case TNG_INT_DATA:
6543             size = sizeof(int64_t);
6544             break;
6545         case TNG_FLOAT_DATA:
6546             size = sizeof(float);
6547             break;
6548         case TNG_DOUBLE_DATA:
6549         default:
6550             size = sizeof(double);
6551         }
6552
6553         values = realloc(data->values,
6554                          size * frame_alloc *
6555                          n_values_per_frame);
6556         if(!values)
6557         {
6558             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6559                    size * frame_alloc *
6560                    n_values_per_frame,
6561                    __FILE__, __LINE__);
6562             free(data->values);
6563             data->values = 0;
6564             return(TNG_CRITICAL);
6565         }
6566         data->values = values;
6567     }
6568
6569     return(TNG_SUCCESS);
6570 }
6571
6572 /** Read the values of a non-particle data block
6573  * @param tng_data is a trajectory data container.
6574  * @param block is the block to store the data (should already contain
6575  * the block headers and the block contents).
6576  * @param offset is the reading offset to point at the place where the actual
6577  * values are stored, starting from the beginning of the block_contents. The
6578  * offset is changed during the reading.
6579  * @param datatype is the type of data of the data block (char, int, float or
6580  * double).
6581  * @param first_frame_with_data is the frame number of the first frame with data
6582  * in this data block.
6583  * @param stride_length is the number of frames between each data entry.
6584  * @param n_frames is the number of frames in this data block.
6585  * @param n_values is the number of values per frame stored in this data block.
6586  * @param codec_id is the ID of the codec to compress the data.
6587  * @param multiplier is the multiplication factor applied to each data value
6588  * before compression. This factor is applied since some compression algorithms
6589  * work only on integers.
6590  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6591  * error has occured.
6592  */
6593 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
6594                                          tng_gen_block_t block,
6595                                          int *offset,
6596                                          const char datatype,
6597                                          const int64_t first_frame_with_data,
6598                                          const int64_t stride_length,
6599                                          int64_t n_frames,
6600                                          const int64_t n_values,
6601                                          const int64_t codec_id,
6602                                          const double multiplier)
6603 {
6604     int64_t i, j, n_frames_div;
6605     int size, len;
6606 #ifdef USE_ZLIB
6607     int64_t data_size;
6608 #endif
6609     tng_non_particle_data_t data;
6610     tng_trajectory_frame_set_t frame_set =
6611     &tng_data->current_trajectory_frame_set;
6612     char block_type_flag;
6613
6614     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
6615
6616 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
6617
6618     switch(datatype)
6619     {
6620     case TNG_CHAR_DATA:
6621         size = 1;
6622         break;
6623     case TNG_INT_DATA:
6624         size = sizeof(int64_t);
6625         break;
6626     case TNG_FLOAT_DATA:
6627         size = sizeof(float);
6628         break;
6629     case TNG_DOUBLE_DATA:
6630     default:
6631         size = sizeof(double);
6632     }
6633
6634     /* If the block does not exist, create it */
6635     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
6636     {
6637         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
6638         {
6639             block_type_flag = TNG_TRAJECTORY_BLOCK;
6640         }
6641         else
6642         {
6643             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6644         }
6645
6646         if(tng_data_block_create(tng_data, block_type_flag) !=
6647             TNG_SUCCESS)
6648         {
6649             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
6650                    __FILE__, __LINE__);
6651             return(TNG_CRITICAL);
6652         }
6653         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6654         {
6655             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
6656         }
6657         else
6658         {
6659             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
6660         }
6661         data->block_id = block->id;
6662
6663         data->block_name = malloc(strlen(block->name) + 1);
6664         if(!data->block_name)
6665         {
6666             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6667                    (int)strlen(block->name)+1, __FILE__, __LINE__);
6668             return(TNG_CRITICAL);
6669         }
6670         strcpy(data->block_name, block->name);
6671
6672         data->datatype = datatype;
6673
6674         data->values = 0;
6675         /* FIXME: Memory leak from strings. */
6676         data->strings = 0;
6677         data->n_frames = 0;
6678         data->codec_id = codec_id;
6679         data->compression_multiplier = multiplier;
6680         data->last_retrieved_frame = -1;
6681     }
6682
6683     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6684
6685     if(codec_id != TNG_UNCOMPRESSED)
6686     {
6687         switch(codec_id)
6688         {
6689 #ifdef USE_ZLIB
6690         case TNG_GZIP_COMPRESSION:
6691             data_size = n_frames_div * size * n_values;
6692     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6693             if(tng_gzip_uncompress(tng_data, block,
6694                                    block->block_contents + *offset,
6695                                    data_size) != TNG_SUCCESS)
6696             {
6697                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
6698                     __LINE__);
6699                 return(TNG_CRITICAL);
6700             }
6701     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6702             break;
6703 #endif
6704         }
6705     }
6706
6707     /* Allocate memory */
6708     if(!data->values || data->n_frames != n_frames ||
6709        data->n_values_per_frame != n_values)
6710     {
6711         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
6712                                  n_values) !=
6713            TNG_SUCCESS)
6714         {
6715             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
6716                    __FILE__, __LINE__);
6717             return(TNG_CRITICAL);
6718         }
6719     }
6720
6721     data->first_frame_with_data = first_frame_with_data;
6722
6723     if(datatype == TNG_CHAR_DATA)
6724     {
6725         for(i = 0; i < n_frames_div; i++)
6726         {
6727             for(j = 0; j < n_values; j++)
6728             {
6729                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
6730                               TNG_MAX_STR_LEN);
6731                 if(data->strings[i][j])
6732                 {
6733                     free(data->strings[i][j]);
6734                 }
6735                 data->strings[i][j] = malloc(len);
6736                 if(!data->strings[i][j])
6737                 {
6738                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6739                            len, __FILE__, __LINE__);
6740                     return(TNG_CRITICAL);
6741                 }
6742                 strncpy(data->strings[i][j], block->block_contents+*offset,
6743                         len);
6744                 *offset += len;
6745             }
6746         }
6747     }
6748     else
6749     {
6750         memcpy(data->values, block->block_contents + *offset,
6751                block->block_contents_size - *offset);
6752         switch(datatype)
6753         {
6754         case TNG_FLOAT_DATA:
6755             if(tng_data->input_endianness_swap_func_32)
6756             {
6757                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6758                 {
6759                     if(tng_data->input_endianness_swap_func_32(tng_data,
6760                         (int32_t *)((char *)data->values + i))
6761                         != TNG_SUCCESS)
6762                     {
6763                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6764                                 __FILE__, __LINE__);
6765                     }
6766                 }
6767             }
6768             break;
6769         case TNG_INT_DATA:
6770         case TNG_DOUBLE_DATA:
6771             if(tng_data->input_endianness_swap_func_64)
6772             {
6773                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6774                 {
6775                     if(tng_data->input_endianness_swap_func_64(tng_data,
6776                         (int64_t *)((char *)data->values + i))
6777                         != TNG_SUCCESS)
6778                     {
6779                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6780                                 __FILE__, __LINE__);
6781                     }
6782                 }
6783             }
6784             break;
6785         case TNG_CHAR_DATA:
6786             break;
6787         }
6788     }
6789     return(TNG_SUCCESS);
6790 }
6791
6792 /** Write a non-particle data block
6793  * @param tng_data is a trajectory data container.
6794  * @param block is the block to store the data (should already contain
6795  * the block headers and the block contents).
6796  * @param block_index is the index number of the data block in the frame set.
6797  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6798  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
6799  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6800  * error has occured.
6801  */
6802 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
6803                                                 tng_gen_block_t block,
6804                                                 const int64_t block_index,
6805                                                 const char hash_mode)
6806 {
6807     int64_t n_frames, stride_length, frame_step, data_start_pos;
6808     int64_t i, j;
6809     int offset = 0, size;
6810     unsigned int len;
6811 #ifdef USE_ZLIB
6812     tng_function_status stat;
6813 #endif
6814     char temp, dependency, *temp_name;
6815     double multiplier;
6816     tng_trajectory_frame_set_t frame_set =
6817     &tng_data->current_trajectory_frame_set;
6818
6819     tng_non_particle_data_t data;
6820     char block_type_flag;
6821
6822     /* If we have already started writing frame sets it is too late to write
6823      * non-trajectory data blocks */
6824     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
6825     {
6826         block_type_flag = TNG_TRAJECTORY_BLOCK;
6827     }
6828     else
6829     {
6830         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6831     }
6832
6833     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6834     {
6835         return(TNG_CRITICAL);
6836     }
6837
6838     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6839     {
6840         data = &frame_set->tr_data[block_index];
6841
6842         /* If this data block has not had any data added in this frame set
6843          * do not write it. */
6844         if(data->first_frame_with_data < frame_set->first_frame)
6845         {
6846             return(TNG_SUCCESS);
6847         }
6848
6849         stride_length = tng_max_i64(1, data->stride_length);
6850     }
6851     else
6852     {
6853         data = &tng_data->non_tr_data[block_index];
6854         stride_length = 1;
6855     }
6856
6857     switch(data->datatype)
6858     {
6859     case TNG_CHAR_DATA:
6860         size = 1;
6861         break;
6862     case TNG_INT_DATA:
6863         size = sizeof(int64_t);
6864         break;
6865     case TNG_FLOAT_DATA:
6866         size = sizeof(float);
6867         break;
6868     case TNG_DOUBLE_DATA:
6869     default:
6870         size = sizeof(double);
6871     }
6872
6873     len = (unsigned int)strlen(data->block_name) + 1;
6874
6875     if(!block->name || strlen(block->name) < len)
6876     {
6877         temp_name = realloc(block->name, len);
6878         if(!temp_name)
6879         {
6880             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len+1,
6881                    __FILE__, __LINE__);
6882             free(block->name);
6883             block->name = 0;
6884             return(TNG_CRITICAL);
6885         }
6886         block->name = temp_name;
6887     }
6888     strncpy(block->name, data->block_name, len);
6889     block->id = data->block_id;
6890
6891     /* If writing frame independent data data->n_frames is 0, but n_frames
6892        is used for the loop writing the data (and reserving memory) and needs
6893        to be at least 1 */
6894     n_frames = tng_max_i64(1, data->n_frames);
6895
6896     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6897     {
6898         /* If the frame set is finished before writing the full number of frames
6899            make sure the data block is not longer than the frame set. */
6900         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6901
6902         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6903     }
6904
6905     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6906                  n_frames / stride_length;
6907
6908     /* TNG compression will use compression precision to get integers from
6909      * floating point data. The compression multiplier stores that information
6910      * to be able to return the precision of the compressed data. */
6911     if(data->codec_id == TNG_TNG_COMPRESSION)
6912     {
6913         data->compression_multiplier = tng_data->compression_precision;
6914     }
6915     /* Uncompressed data blocks do not use compression multipliers at all.
6916      * GZip compression does not need it either. */
6917     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6918     {
6919         data->compression_multiplier = 1.0;
6920     }
6921
6922     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6923     {
6924         dependency = TNG_FRAME_DEPENDENT;
6925     }
6926     else
6927     {
6928         dependency = 0;
6929     }
6930
6931     if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames,
6932                                     frame_step, stride_length, 0,
6933                                     1, dependency, &data_start_pos,
6934                                     &block->block_contents_size) != TNG_SUCCESS)
6935     {
6936         fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
6937                 __FILE__, __LINE__);
6938         return(TNG_CRITICAL);
6939     }
6940
6941     if(block->block_contents)
6942     {
6943         free(block->block_contents);
6944     }
6945     block->block_contents = malloc(block->block_contents_size);
6946     if(!block->block_contents)
6947     {
6948         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6949                block->block_contents_size, __FILE__, __LINE__);
6950         return(TNG_CRITICAL);
6951     }
6952
6953
6954     memcpy(block->block_contents, &data->datatype, sizeof(char));
6955     offset += sizeof(char);
6956
6957     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6958     offset += sizeof(char);
6959
6960     if(dependency & TNG_FRAME_DEPENDENT)
6961     {
6962         if(stride_length > 1)
6963         {
6964             temp = 1;
6965         }
6966         else
6967         {
6968             temp = 0;
6969         }
6970         memcpy(block->block_contents+offset, &temp, sizeof(char));
6971         offset += sizeof(char);
6972     }
6973
6974     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6975            sizeof(data->n_values_per_frame));
6976     if(tng_data->output_endianness_swap_func_64)
6977     {
6978         if(tng_data->output_endianness_swap_func_64(tng_data,
6979            (int64_t *)block->header_contents+offset)
6980             != TNG_SUCCESS)
6981         {
6982             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6983                     __FILE__, __LINE__);
6984         }
6985     }
6986     offset += sizeof(data->n_values_per_frame);
6987
6988     memcpy(block->block_contents+offset, &data->codec_id,
6989            sizeof(data->codec_id));
6990     if(tng_data->output_endianness_swap_func_64)
6991     {
6992         if(tng_data->output_endianness_swap_func_64(tng_data,
6993            (int64_t *)block->header_contents+offset)
6994             != TNG_SUCCESS)
6995         {
6996             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6997                     __FILE__, __LINE__);
6998         }
6999     }
7000     offset += sizeof(data->codec_id);
7001
7002     if(data->codec_id != TNG_UNCOMPRESSED)
7003     {
7004         memcpy(block->block_contents+offset, &data->compression_multiplier,
7005                sizeof(data->compression_multiplier));
7006         if(tng_data->output_endianness_swap_func_64)
7007         {
7008             if(tng_data->output_endianness_swap_func_64(tng_data,
7009             (int64_t *)block->header_contents+offset)
7010                 != TNG_SUCCESS)
7011             {
7012                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7013                         __FILE__, __LINE__);
7014             }
7015         }
7016         offset += sizeof(data->compression_multiplier);
7017     }
7018
7019     if(data->n_frames > 0 && stride_length > 1)
7020     {
7021         /* FIXME: first_frame_with_data is not reliably set */
7022         if(data->first_frame_with_data == 0)
7023         {
7024             data->first_frame_with_data = frame_set->first_frame;
7025         }
7026         memcpy(block->block_contents+offset, &data->first_frame_with_data,
7027                sizeof(data->first_frame_with_data));
7028         if(tng_data->output_endianness_swap_func_64)
7029         {
7030             if(tng_data->output_endianness_swap_func_64(tng_data,
7031             (int64_t *)block->header_contents+offset)
7032                 != TNG_SUCCESS)
7033             {
7034                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7035                         __FILE__, __LINE__);
7036             }
7037         }
7038         offset += sizeof(data->first_frame_with_data);
7039
7040         memcpy(block->block_contents+offset, &stride_length,
7041                sizeof(data->stride_length));
7042         if(tng_data->output_endianness_swap_func_64)
7043         {
7044             if(tng_data->output_endianness_swap_func_64(tng_data,
7045             (int64_t *)block->header_contents+offset)
7046                 != TNG_SUCCESS)
7047             {
7048                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7049                         __FILE__, __LINE__);
7050             }
7051         }
7052         offset += sizeof(data->stride_length);
7053     }
7054
7055     if(data->datatype == TNG_CHAR_DATA)
7056     {
7057         if(data->strings)
7058         {
7059             for(i = 0; i < frame_step; i++)
7060             {
7061                 for(j = 0; j < data->n_values_per_frame; j++)
7062                 {
7063                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
7064                     strncpy(block->block_contents+offset, data->strings[i][j],
7065                             len);
7066                     offset += len;
7067                 }
7068             }
7069         }
7070     }
7071     else if(data->values)
7072     {
7073         memcpy(block->block_contents + offset, data->values,
7074                block->block_contents_size - offset);
7075         switch(data->datatype)
7076         {
7077         case TNG_FLOAT_DATA:
7078             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7079                data->codec_id == TNG_TNG_COMPRESSION)
7080             {
7081                 if(tng_data->input_endianness_swap_func_32)
7082                 {
7083                     for(i = offset; i < block->block_contents_size; i+=size)
7084                     {
7085                         if(tng_data->input_endianness_swap_func_32(tng_data,
7086                            (int32_t *)(block->block_contents + i))
7087                            != TNG_SUCCESS)
7088                         {
7089                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7090                                     __FILE__, __LINE__);
7091                         }
7092                     }
7093                 }
7094             }
7095             else
7096             {
7097                 multiplier = data->compression_multiplier;
7098                 if(fabs(multiplier - 1.0) > 0.00001 ||
7099                    tng_data->input_endianness_swap_func_32)
7100                 {
7101                     for(i = offset; block->block_contents_size; i+=size)
7102                     {
7103                         *(float *)(block->block_contents + i) *= (float)multiplier;
7104                         if(tng_data->input_endianness_swap_func_32 &&
7105                         tng_data->input_endianness_swap_func_32(tng_data,
7106                         (int32_t *)(block->block_contents + i))
7107                         != TNG_SUCCESS)
7108                         {
7109                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7110                                     __FILE__, __LINE__);
7111                         }
7112                     }
7113                 }
7114             }
7115             break;
7116         case TNG_INT_DATA:
7117             if(tng_data->input_endianness_swap_func_64)
7118             {
7119                 for(i = offset; i < block->block_contents_size; i+=size)
7120                 {
7121                     if(tng_data->input_endianness_swap_func_64(tng_data,
7122                        (int64_t *)(block->block_contents + i))
7123                        != TNG_SUCCESS)
7124                     {
7125                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7126                                 __FILE__, __LINE__);
7127                     }
7128                 }
7129             }
7130             break;
7131         case TNG_DOUBLE_DATA:
7132             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7133                data->codec_id == TNG_TNG_COMPRESSION)
7134             {
7135                 if(tng_data->input_endianness_swap_func_64)
7136                 {
7137                     for(i = offset; i < block->block_contents_size; i+=size)
7138                     {
7139                         if(tng_data->input_endianness_swap_func_64(tng_data,
7140                            (int64_t *)(block->block_contents + i))
7141                            != TNG_SUCCESS)
7142                         {
7143                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7144                                     __FILE__, __LINE__);
7145                         }
7146                     }
7147                 }
7148             }
7149             else
7150             {
7151                 multiplier = data->compression_multiplier;
7152                 if(fabs(multiplier - 1.0) > 0.00001 ||
7153                    tng_data->input_endianness_swap_func_64)
7154                 {
7155                     for(i = offset; i < block->block_contents_size; i+=size)
7156                     {
7157                         *(double *)(block->block_contents + i) *= multiplier;
7158                         if(tng_data->input_endianness_swap_func_64 &&
7159                         tng_data->input_endianness_swap_func_64(tng_data,
7160                         (int64_t *)(block->block_contents + i))
7161                         != TNG_SUCCESS)
7162                         {
7163                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7164                                     __FILE__, __LINE__);
7165                         }
7166                     }
7167                 }
7168             }
7169             break;
7170         case TNG_CHAR_DATA:
7171             break;
7172         }
7173     }
7174     else
7175     {
7176         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
7177     }
7178
7179     frame_set->n_written_frames += frame_set->n_unwritten_frames;
7180     frame_set->n_unwritten_frames = 0;
7181
7182     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
7183     {
7184         switch(data->codec_id)
7185         {
7186 #ifdef USE_ZLIB
7187         case TNG_GZIP_COMPRESSION:
7188     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
7189             stat = tng_gzip_compress(tng_data, block,
7190                                      block->block_contents + data_start_pos,
7191                                      block->block_contents_size - data_start_pos);
7192             if(stat != TNG_SUCCESS)
7193             {
7194                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
7195                     __LINE__);
7196                 if(stat == TNG_CRITICAL)
7197                 {
7198                     return(TNG_CRITICAL);
7199                 }
7200                 data->codec_id = TNG_UNCOMPRESSED;
7201             }
7202     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
7203             break;
7204 #endif
7205         }
7206     }
7207
7208     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
7209     {
7210         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
7211                tng_data->output_file_path, __FILE__, __LINE__);
7212         return(TNG_CRITICAL);
7213     }
7214
7215     if(fwrite(block->block_contents, block->block_contents_size, 1,
7216               tng_data->output_file) != 1)
7217     {
7218         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
7219                __FILE__, __LINE__);
7220         return(TNG_CRITICAL);
7221     }
7222
7223     return(TNG_SUCCESS);
7224 }
7225
7226 /** Read the meta information of a data block (particle or non-particle data).
7227  * @param tng_data is a trajectory data container.
7228  * @param block is the block to store the data (should already contain
7229  * the block headers).
7230  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7231  * error has occured.
7232  */
7233 static tng_function_status tng_data_block_meta_information_read
7234                 (tng_trajectory_t tng_data,
7235                  tng_gen_block_t block,
7236                  int *offset,
7237                  char *datatype,
7238                  char *dependency,
7239                  char *sparse_data,
7240                  int64_t *n_values,
7241                  int64_t *codec_id,
7242                  int64_t *first_frame_with_data,
7243                  int64_t *stride_length,
7244                  int64_t *n_frames,
7245                  int64_t *num_first_particle,
7246                  int64_t *block_n_particles,
7247                  double *multiplier)
7248 {
7249     int meta_size;
7250     char *contents;
7251
7252     if(block->block_contents)
7253     {
7254         contents = block->block_contents;
7255     }
7256     else
7257     {
7258         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
7259         contents = malloc(meta_size);
7260         if(!contents)
7261         {
7262             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
7263                meta_size, __FILE__, __LINE__);
7264         }
7265
7266         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
7267         {
7268             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
7269             free(contents);
7270             return(TNG_CRITICAL);
7271         }
7272     }
7273
7274     memcpy(datatype, contents+*offset,
7275            sizeof(*datatype));
7276     *offset += sizeof(*datatype);
7277
7278     memcpy(dependency, contents+*offset,
7279            sizeof(*dependency));
7280     *offset += sizeof(*dependency);
7281
7282     if(*dependency & TNG_FRAME_DEPENDENT)
7283     {
7284         memcpy(sparse_data, contents+*offset,
7285                sizeof(*sparse_data));
7286         *offset += sizeof(*sparse_data);
7287     }
7288
7289     memcpy(n_values, contents+*offset,
7290         sizeof(*n_values));
7291     if(tng_data->input_endianness_swap_func_64)
7292     {
7293         if(tng_data->input_endianness_swap_func_64(tng_data,
7294                                                    n_values)
7295             != TNG_SUCCESS)
7296         {
7297             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7298                     __FILE__, __LINE__);
7299         }
7300     }
7301     *offset += sizeof(*n_values);
7302
7303     memcpy(codec_id, contents+*offset,
7304         sizeof(*codec_id));
7305     if(tng_data->input_endianness_swap_func_64)
7306     {
7307         if(tng_data->input_endianness_swap_func_64(tng_data,
7308                                                    codec_id)
7309             != TNG_SUCCESS)
7310         {
7311             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7312                     __FILE__, __LINE__);
7313         }
7314     }
7315     *offset += sizeof(*codec_id);
7316
7317     if(*codec_id != TNG_UNCOMPRESSED)
7318     {
7319         memcpy(multiplier, contents+*offset,
7320             sizeof(*multiplier));
7321         if(tng_data->input_endianness_swap_func_64)
7322         {
7323             if(tng_data->input_endianness_swap_func_64(tng_data,
7324                                                        (int64_t *) multiplier)
7325                 != TNG_SUCCESS)
7326             {
7327                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7328                         __FILE__, __LINE__);
7329             }
7330         }
7331         *offset += sizeof(*multiplier);
7332     }
7333     else
7334     {
7335         *multiplier = 1;
7336     }
7337
7338     if(*dependency & TNG_FRAME_DEPENDENT)
7339     {
7340         if(*sparse_data)
7341         {
7342             memcpy(first_frame_with_data, contents+*offset,
7343                 sizeof(*first_frame_with_data));
7344             if(tng_data->input_endianness_swap_func_64)
7345             {
7346                 if(tng_data->input_endianness_swap_func_64(tng_data,
7347                                                            first_frame_with_data)
7348                     != TNG_SUCCESS)
7349                 {
7350                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7351                             __FILE__, __LINE__);
7352                 }
7353             }
7354             *offset += sizeof(*first_frame_with_data);
7355
7356             memcpy(stride_length, contents+*offset,
7357                 sizeof(*stride_length));
7358             if(tng_data->input_endianness_swap_func_64)
7359             {
7360                 if(tng_data->input_endianness_swap_func_64(tng_data,
7361                                                            stride_length)
7362                     != TNG_SUCCESS)
7363                 {
7364                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7365                             __FILE__, __LINE__);
7366                 }
7367             }
7368             *offset += sizeof(*stride_length);
7369             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
7370                         (*first_frame_with_data -
7371                         tng_data->current_trajectory_frame_set.first_frame);
7372         }
7373         else
7374         {
7375             *first_frame_with_data = 0;
7376             *stride_length = 1;
7377             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
7378         }
7379     }
7380     else
7381     {
7382         *first_frame_with_data = 0;
7383         *stride_length = 1;
7384         *n_frames = 1;
7385     }
7386
7387     if (*dependency & TNG_PARTICLE_DEPENDENT)
7388     {
7389         memcpy(num_first_particle, contents+*offset,
7390                sizeof(*num_first_particle));
7391         if(tng_data->input_endianness_swap_func_64)
7392         {
7393             if(tng_data->input_endianness_swap_func_64(tng_data,
7394                                                        num_first_particle)
7395                 != TNG_SUCCESS)
7396             {
7397                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7398                         __FILE__, __LINE__);
7399             }
7400         }
7401         *offset += sizeof(*num_first_particle);
7402
7403         memcpy(block_n_particles, contents+*offset,
7404             sizeof(*block_n_particles));
7405         if(tng_data->input_endianness_swap_func_64)
7406         {
7407             if(tng_data->input_endianness_swap_func_64(tng_data,
7408                                                        block_n_particles)
7409                 != TNG_SUCCESS)
7410             {
7411                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7412                         __FILE__, __LINE__);
7413             }
7414         }
7415         *offset += sizeof(*block_n_particles);
7416     }
7417
7418     if(!block->block_contents)
7419     {
7420         free(contents);
7421     }
7422     return(TNG_SUCCESS);
7423 }
7424
7425 /** Read the contents of a data block (particle or non-particle data).
7426  * @param tng_data is a trajectory data container.
7427  * @param block is the block to store the data (should already contain
7428  * the block headers).
7429  * @param hash_mode is an option to decide whether to use the md5 hash or not.
7430  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
7431  * compared to the md5 hash of the read contents to ensure valid data.
7432  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7433  * error has occured.
7434  */
7435 static tng_function_status tng_data_block_contents_read
7436                 (tng_trajectory_t tng_data,
7437                  tng_gen_block_t block,
7438                  const char hash_mode)
7439 {
7440     int64_t n_values, codec_id, n_frames, first_frame_with_data;
7441     int64_t stride_length, block_n_particles, num_first_particle;
7442     double multiplier;
7443     char datatype, dependency, sparse_data;
7444     int offset = 0;
7445     tng_bool same_hash;
7446
7447     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
7448     {
7449         return(TNG_CRITICAL);
7450     }
7451
7452     if(block->block_contents)
7453     {
7454         free(block->block_contents);
7455     }
7456
7457     block->block_contents = malloc(block->block_contents_size);
7458     if(!block->block_contents)
7459     {
7460         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7461                block->block_contents_size, __FILE__, __LINE__);
7462         return(TNG_CRITICAL);
7463     }
7464
7465     /* Read the whole block into block_contents to be able to write it to
7466      * disk even if it cannot be interpreted. */
7467     if(fread(block->block_contents, block->block_contents_size, 1,
7468              tng_data->input_file) == 0)
7469     {
7470         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
7471         return(TNG_CRITICAL);
7472     }
7473
7474     /* FIXME: Does not check if the size of the contents matches the expected
7475      * size or if the contents can be read. */
7476
7477     if(hash_mode == TNG_USE_HASH)
7478     {
7479         tng_md5_hash_match_verify(block, &same_hash);
7480         if(same_hash != TNG_TRUE)
7481         {
7482             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
7483                 block->name, __FILE__, __LINE__);
7484     /*         return(TNG_FAILURE); */
7485         }
7486     }
7487
7488     if(tng_data_block_meta_information_read(tng_data, block,
7489                                             &offset, &datatype,
7490                                             &dependency, &sparse_data,
7491                                             &n_values, &codec_id,
7492                                             &first_frame_with_data,
7493                                             &stride_length, &n_frames,
7494                                             &num_first_particle,
7495                                             &block_n_particles,
7496                                             &multiplier) == TNG_CRITICAL)
7497     {
7498         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
7499             block->name, __FILE__, __LINE__);
7500         return(TNG_CRITICAL);
7501     }
7502
7503     if (dependency & TNG_PARTICLE_DEPENDENT)
7504     {
7505         return(tng_particle_data_read(tng_data, block,
7506                                       &offset, datatype,
7507                                       num_first_particle,
7508                                       block_n_particles,
7509                                       first_frame_with_data,
7510                                       stride_length,
7511                                       n_frames, n_values,
7512                                       codec_id, multiplier));
7513     }
7514     else
7515     {
7516         return(tng_data_read(tng_data, block,
7517                              &offset, datatype,
7518                              first_frame_with_data,
7519                              stride_length,
7520                              n_frames, n_values,
7521                              codec_id, multiplier));
7522     }
7523 }
7524
7525 /*
7526 // ** Move the blocks in a frame set so that there is no unused space between
7527 //  * them. This can only be done on the last frame set in the file and should
7528 //  * be done e.g. if the last frame set in the file has fewer frames than
7529 //  * default or after compressing data blocks in a frame set.
7530 //  * @param tng_data is a trajectory data container.
7531 //  * @details the current_trajectory_frame_set is the one that will be modified.
7532 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
7533 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
7534 //  * FIXME: This function is not finished!!!
7535 //  *
7536 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
7537 // {
7538 //     tng_gen_block_t block;
7539 //     tng_trajectory_frame_set_t frame_set;
7540 //     FILE *temp = tng_data->input_file;
7541 //     int64_t pos, contents_start_pos, output_file_len;
7542 //
7543 //     frame_set = &tng_data->current_trajectory_frame_set;
7544 //
7545 //     if(frame_set->n_written_frames == frame_set->n_frames)
7546 //     {
7547 //         return(TNG_SUCCESS);
7548 //     }
7549 //
7550 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
7551 //        tng_data->last_trajectory_frame_set_output_file_pos)
7552 //     {
7553 //     }
7554 //
7555 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7556 //     {
7557 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7558 //                __FILE__, __LINE__);
7559 //         return(TNG_CRITICAL);
7560 //     }
7561 //
7562 //     tng_block_init(&block);
7563 // //     output_file_pos = ftello(tng_data->output_file);
7564 //
7565 //     tng_data->input_file = tng_data->output_file;
7566 //
7567 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7568 //
7569 //     fseeko(tng_data->output_file, pos, SEEK_SET);
7570 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7571 //     {
7572 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7573 //             __FILE__, __LINE__);
7574 //         tng_data->input_file = temp;
7575 //         tng_block_destroy(&block);
7576 //         return(TNG_CRITICAL);
7577 //     }
7578 //
7579 //     contents_start_pos = ftello(tng_data->output_file);
7580 //
7581 //     fseeko(tng_data->output_file, 0, SEEK_END);
7582 //     output_file_len = ftello(tng_data->output_file);
7583 //     pos = contents_start_pos + block->block_contents_size;
7584 //     fseeko(tng_data->output_file, pos,
7585 //           SEEK_SET);
7586 //
7587 //     while(pos < output_file_len)
7588 //     {
7589 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7590 //         {
7591 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7592 //                    __FILE__, __LINE__);
7593 //             tng_data->input_file = temp;
7594 //             tng_block_destroy(&block);
7595 //             return(TNG_CRITICAL);
7596 //         }
7597 //         pos += block->header_contents_size + block->block_contents_size;
7598 //         fseeko(tng_data->output_file, pos, SEEK_SET);
7599 //     }
7600 //
7601 //     return(TNG_SUCCESS);
7602 // }
7603 */
7604 /** Finish writing the current frame set. Update the number of frames
7605  * and the hashes of the frame set and all its data blocks (if hash_mode
7606  * == TNG_USE_HASH).
7607  * @param tng_data is a trajectory data container.
7608  * @param hash_mode specifies whether to update the block md5 hash when
7609  * updating the pointers.
7610  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7611  * error has occured.
7612  */
7613 static tng_function_status tng_frame_set_finalize
7614                 (tng_trajectory_t tng_data, const char hash_mode)
7615 {
7616     tng_gen_block_t block;
7617     tng_trajectory_frame_set_t frame_set;
7618     FILE *temp = tng_data->input_file;
7619     int64_t pos, contents_start_pos, output_file_len;
7620
7621     frame_set = &tng_data->current_trajectory_frame_set;
7622
7623     if(frame_set->n_written_frames == frame_set->n_frames)
7624     {
7625         return(TNG_SUCCESS);
7626     }
7627
7628     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7629     {
7630         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7631                __FILE__, __LINE__);
7632         return(TNG_CRITICAL);
7633     }
7634
7635     tng_block_init(&block);
7636 /*     output_file_pos = ftello(tng_data->output_file); */
7637
7638     tng_data->input_file = tng_data->output_file;
7639
7640     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7641
7642     fseeko(tng_data->output_file, pos, SEEK_SET);
7643
7644     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7645     {
7646         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7647             __FILE__, __LINE__);
7648         tng_data->input_file = temp;
7649         tng_block_destroy(&block);
7650         return(TNG_CRITICAL);
7651     }
7652
7653     contents_start_pos = ftello(tng_data->output_file);
7654
7655     fseeko(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7656     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7657               1, tng_data->output_file) != 1)
7658     {
7659         tng_data->input_file = temp;
7660         tng_block_destroy(&block);
7661         return(TNG_CRITICAL);
7662     }
7663
7664
7665     if(hash_mode == TNG_USE_HASH)
7666     {
7667         tng_md5_hash_update(tng_data, block, pos,
7668                             pos + block->header_contents_size);
7669     }
7670
7671     fseeko(tng_data->output_file, 0, SEEK_END);
7672     output_file_len = ftello(tng_data->output_file);
7673     pos = contents_start_pos + block->block_contents_size;
7674     fseeko(tng_data->output_file, pos, SEEK_SET);
7675
7676     while(pos < output_file_len)
7677     {
7678         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7679         {
7680             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7681                    __FILE__, __LINE__);
7682             tng_data->input_file = temp;
7683             tng_block_destroy(&block);
7684             return(TNG_CRITICAL);
7685         }
7686
7687         if(hash_mode == TNG_USE_HASH)
7688         {
7689             tng_md5_hash_update(tng_data, block, pos,
7690                                 pos + block->header_contents_size);
7691         }
7692         pos += block->header_contents_size + block->block_contents_size;
7693         fseeko(tng_data->output_file, pos, SEEK_SET);
7694     }
7695
7696     tng_data->input_file = temp;
7697     tng_block_destroy(&block);
7698     return(TNG_SUCCESS);
7699 }
7700
7701 /*
7702 // ** Sets the name of a file contents block
7703 //  * @param tng_data is a trajectory data container.
7704 //  * @param block is the block, of which to change names.
7705 //  * @param new_name is the new name of the block.
7706 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7707 //  * error has occured.
7708 //
7709 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7710 //                                               tng_gen_block_t block,
7711 //                                               const char *new_name)
7712 // {
7713 //     int len;
7714 //
7715 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7716 //
7717 //      * If the currently stored string length is not enough to store the new
7718 //      * string it is freed and reallocated. *
7719 //     if(block->name && strlen(block->name) < len)
7720 //     {
7721 //         free(block->name);
7722 //         block->name = 0;
7723 //     }
7724 //     if(!block->name)
7725 //     {
7726 //         block->name = malloc(len);
7727 //         if(!block->name)
7728 //         {
7729 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7730 //                    __FILE__, __LINE__);
7731 //             return(TNG_CRITICAL);
7732 //         }
7733 //     }
7734 //
7735 //     strncpy(block->name, new_name, len);
7736 //
7737 //     return(TNG_SUCCESS);
7738 // }
7739 */
7740
7741 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7742                                          const tng_atom_t atom,
7743                                          tng_residue_t *residue)
7744 {
7745     (void) tng_data;
7746
7747     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7748
7749     *residue = atom->residue;
7750
7751     return(TNG_SUCCESS);
7752 }
7753
7754 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7755                                       const tng_atom_t atom,
7756                                       char *name,
7757                                       const int max_len)
7758 {
7759     (void) tng_data;
7760     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7761     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7762
7763     strncpy(name, atom->name, max_len - 1);
7764     name[max_len - 1] = 0;
7765
7766     if(strlen(atom->name) > (unsigned int)max_len - 1)
7767     {
7768         return(TNG_FAILURE);
7769     }
7770     return(TNG_SUCCESS);
7771 }
7772
7773 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7774                                       tng_atom_t atom,
7775                                       const char *new_name)
7776 {
7777     unsigned int len;
7778     (void)tng_data;
7779
7780     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7781     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7782
7783     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7784
7785     /* If the currently stored string length is not enough to store the new
7786      * string it is freed and reallocated. */
7787     if(atom->name && strlen(atom->name) < len)
7788     {
7789         free(atom->name);
7790         atom->name = 0;
7791     }
7792     if(!atom->name)
7793     {
7794         atom->name = malloc(len);
7795         if(!atom->name)
7796         {
7797             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7798                    __FILE__, __LINE__);
7799             return(TNG_CRITICAL);
7800         }
7801     }
7802
7803     strncpy(atom->name, new_name, len);
7804
7805     return(TNG_SUCCESS);
7806 }
7807
7808 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7809                                       const tng_atom_t atom,
7810                                       char *type,
7811                                       const int max_len)
7812 {
7813     (void) tng_data;
7814     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7815     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7816
7817     strncpy(type, atom->atom_type, max_len - 1);
7818     type[max_len - 1] = 0;
7819
7820     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7821     {
7822         return(TNG_FAILURE);
7823     }
7824     return(TNG_SUCCESS);
7825 }
7826
7827 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7828                                       tng_atom_t atom,
7829                                       const char *new_type)
7830 {
7831     unsigned int len;
7832     (void)tng_data;
7833
7834     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7835     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7836
7837     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7838
7839     /* If the currently stored string length is not enough to store the new
7840      * string it is freed and reallocated. */
7841     if(atom->atom_type && strlen(atom->atom_type) < len)
7842     {
7843         free(atom->atom_type);
7844         atom->atom_type = 0;
7845     }
7846     if(!atom->atom_type)
7847     {
7848         atom->atom_type = malloc(len);
7849         if(!atom->atom_type)
7850         {
7851             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7852                    __FILE__, __LINE__);
7853             return(TNG_CRITICAL);
7854         }
7855     }
7856
7857     strncpy(atom->atom_type, new_type, len);
7858
7859     return(TNG_SUCCESS);
7860 }
7861
7862 /** Initialise an atom struct
7863  * @param atom is the atom to initialise.
7864  * @return TNG_SUCCESS (0) if successful.
7865  */
7866 static tng_function_status tng_atom_init(tng_atom_t atom)
7867 {
7868     atom->name = 0;
7869     atom->atom_type = 0;
7870
7871     return(TNG_SUCCESS);
7872 }
7873
7874 /** Free the memory in an atom struct
7875  * @param atom is the atom to destroy.
7876  * @return TNG_SUCCESS (0) if successful.
7877  */
7878 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7879 {
7880     if(atom->name)
7881     {
7882         free(atom->name);
7883         atom->name = 0;
7884     }
7885     if(atom->atom_type)
7886     {
7887         free(atom->atom_type);
7888         atom->atom_type = 0;
7889     }
7890
7891     return(TNG_SUCCESS);
7892 }
7893
7894 tng_function_status DECLSPECDLLEXPORT tng_version_major
7895                 (const tng_trajectory_t tng_data,
7896                  int *version)
7897 {
7898     (void)tng_data;
7899
7900     *version = TNG_VERSION_MAJOR;
7901
7902     return(TNG_SUCCESS);
7903 }
7904
7905 tng_function_status DECLSPECDLLEXPORT tng_version_minor
7906                 (const tng_trajectory_t tng_data,
7907                  int *version)
7908 {
7909     (void)tng_data;
7910
7911     *version = TNG_VERSION_MINOR;
7912
7913     return(TNG_SUCCESS);
7914 }
7915
7916 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
7917                 (const tng_trajectory_t tng_data,
7918                  int *patch_level)
7919 {
7920     (void)tng_data;
7921
7922     *patch_level = TNG_VERSION_PATCHLEVEL;
7923
7924     return(TNG_SUCCESS);
7925 }
7926
7927 tng_function_status DECLSPECDLLEXPORT tng_version
7928                 (const tng_trajectory_t tng_data,
7929                  char *version,
7930                  const int max_len)
7931 {
7932     (void)tng_data;
7933     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
7934
7935     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
7936
7937     return(TNG_SUCCESS);
7938 }
7939
7940 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7941                 (tng_trajectory_t tng_data,
7942                  const char *name,
7943                  tng_molecule_t *molecule)
7944 {
7945     int64_t id;
7946
7947     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7948     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7949
7950     /* Set ID to the ID of the last molecule + 1 */
7951     if(tng_data->n_molecules)
7952     {
7953         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7954     }
7955     else
7956     {
7957         id = 1;
7958     }
7959
7960     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7961 }
7962
7963 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7964                 (tng_trajectory_t tng_data,
7965                  const char *name,
7966                  const int64_t id,
7967                  tng_molecule_t *molecule)
7968 {
7969     tng_molecule_t new_molecules;
7970     int64_t *new_molecule_cnt_list;
7971     tng_function_status stat = TNG_SUCCESS;
7972
7973     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7974     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7975
7976     new_molecules = realloc(tng_data->molecules,
7977                             sizeof(struct tng_molecule) *
7978                             (tng_data->n_molecules + 1));
7979
7980     if(!new_molecules)
7981     {
7982         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7983                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
7984                __FILE__, __LINE__);
7985         free(tng_data->molecules);
7986         tng_data->molecules = 0;
7987         return(TNG_CRITICAL);
7988     }
7989
7990     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
7991                                     sizeof(int64_t) *
7992                                     (tng_data->n_molecules + 1));
7993
7994     if(!new_molecule_cnt_list)
7995     {
7996         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7997                sizeof(int64_t) * (tng_data->n_molecules + 1),
7998                __FILE__, __LINE__);
7999         free(tng_data->molecule_cnt_list);
8000         tng_data->molecule_cnt_list = 0;
8001         free(new_molecules);
8002         return(TNG_CRITICAL);
8003     }
8004
8005     tng_data->molecules = new_molecules;
8006     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8007
8008     *molecule = &new_molecules[tng_data->n_molecules];
8009
8010     tng_molecule_init(tng_data, *molecule);
8011     tng_molecule_name_set(tng_data, *molecule, name);
8012
8013     /* FIXME: Should this be a function argument instead? */
8014     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8015
8016     (*molecule)->id = id;
8017
8018     tng_data->n_molecules++;
8019
8020     return(stat);
8021 }
8022
8023 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
8024                 (tng_trajectory_t tng_data,
8025                  tng_molecule_t *molecule_p)
8026 {
8027     int64_t *new_molecule_cnt_list, id;
8028     tng_molecule_t new_molecules, molecule;
8029
8030     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8031
8032     /* Set ID to the ID of the last molecule + 1 */
8033     if(tng_data->n_molecules)
8034     {
8035         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
8036     }
8037     else
8038     {
8039         id = 1;
8040     }
8041
8042     new_molecules = realloc(tng_data->molecules,
8043                             sizeof(struct tng_molecule) *
8044                             (tng_data->n_molecules + 1));
8045
8046     if(!new_molecules)
8047     {
8048         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8049                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
8050                __FILE__, __LINE__);
8051         free(tng_data->molecules);
8052         tng_data->molecules = 0;
8053         return(TNG_CRITICAL);
8054     }
8055
8056     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
8057                                     sizeof(int64_t) *
8058                                     (tng_data->n_molecules + 1));
8059
8060     if(!new_molecule_cnt_list)
8061     {
8062         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8063                sizeof(int64_t) * (tng_data->n_molecules + 1),
8064                __FILE__, __LINE__);
8065         free(tng_data->molecule_cnt_list);
8066         tng_data->molecule_cnt_list = 0;
8067         free(new_molecules);
8068         return(TNG_CRITICAL);
8069     }
8070
8071     molecule = *molecule_p;
8072
8073     tng_data->molecules = new_molecules;
8074     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8075
8076     new_molecules[tng_data->n_molecules] = *molecule;
8077
8078     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8079
8080     free(*molecule_p);
8081
8082     molecule = &new_molecules[tng_data->n_molecules];
8083
8084     *molecule_p = molecule;
8085
8086     molecule->id = id;
8087
8088     tng_data->n_molecules++;
8089
8090     return(TNG_SUCCESS);
8091 }
8092
8093 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
8094                                           const tng_molecule_t molecule,
8095                                           char *name,
8096                                           const int max_len)
8097 {
8098     (void) tng_data;
8099     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8100     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8101
8102     strncpy(name, molecule->name, max_len - 1);
8103     name[max_len - 1] = 0;
8104
8105     if(strlen(molecule->name) > (unsigned int)max_len - 1)
8106     {
8107         return(TNG_FAILURE);
8108     }
8109     return(TNG_SUCCESS);
8110 }
8111
8112 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
8113                 (tng_trajectory_t tng_data,
8114                  tng_molecule_t molecule,
8115                  const char *new_name)
8116 {
8117     unsigned int len;
8118     (void)tng_data;
8119
8120     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8121     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8122
8123     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8124
8125     /* If the currently stored string length is not enough to store the new
8126      * string it is freed and reallocated. */
8127     if(molecule->name && strlen(molecule->name) < len)
8128     {
8129         free(molecule->name);
8130         molecule->name = 0;
8131     }
8132     if(!molecule->name)
8133     {
8134         molecule->name = malloc(len);
8135         if(!molecule->name)
8136         {
8137             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8138                    __FILE__, __LINE__);
8139             return(TNG_CRITICAL);
8140         }
8141     }
8142
8143     strncpy(molecule->name, new_name, len);
8144
8145     return(TNG_SUCCESS);
8146 }
8147
8148 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
8149                 (const tng_trajectory_t tng_data,
8150                  const tng_molecule_t molecule,
8151                  int64_t *cnt)
8152 {
8153     int64_t i, index = -1;
8154
8155     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8156     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
8157
8158     for(i = 0; i < tng_data->n_molecules; i++)
8159     {
8160         if(&tng_data->molecules[i] == molecule)
8161         {
8162             index = i;
8163             break;
8164         }
8165     }
8166     if(index == -1)
8167     {
8168         return(TNG_FAILURE);
8169     }
8170     *cnt = tng_data->molecule_cnt_list[index];
8171
8172     return(TNG_SUCCESS);
8173 }
8174
8175 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
8176                 (tng_trajectory_t tng_data,
8177                  tng_molecule_t molecule,
8178                  const int64_t cnt)
8179 {
8180     int64_t i, old_cnt, index = -1;
8181
8182     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8183
8184     for(i = 0; i < tng_data->n_molecules; i++)
8185     {
8186         if(&tng_data->molecules[i] == molecule)
8187         {
8188             index = i;
8189             break;
8190         }
8191     }
8192     if(index == -1)
8193     {
8194         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
8195                __FILE__, __LINE__);
8196         return(TNG_FAILURE);
8197     }
8198     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
8199     {
8200         old_cnt = tng_data->molecule_cnt_list[index];
8201         tng_data->molecule_cnt_list[index] = cnt;
8202
8203         tng_data->n_particles += (cnt-old_cnt) *
8204                                  tng_data->molecules[index].n_atoms;
8205     }
8206     else
8207     {
8208         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
8209         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
8210
8211         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
8212                 tng_data->molecules[index].n_atoms;
8213     }
8214
8215     return(TNG_SUCCESS);
8216 }
8217
8218 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
8219                 (tng_trajectory_t tng_data,
8220                  const char *name,
8221                  int64_t nr,
8222                  tng_molecule_t *molecule)
8223 {
8224     int64_t i, n_molecules;
8225
8226     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8227     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8228     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8229
8230     n_molecules = tng_data->n_molecules;
8231
8232     for(i = n_molecules - 1; i >= 0; i--)
8233     {
8234         *molecule = &tng_data->molecules[i];
8235         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
8236         {
8237             if(nr == -1 || nr == (*molecule)->id)
8238             {
8239                 return(TNG_SUCCESS);
8240             }
8241         }
8242     }
8243
8244     *molecule = 0;
8245
8246     return(TNG_FAILURE);
8247 }
8248
8249 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
8250                 (tng_trajectory_t tng_data,
8251                  int64_t index,
8252                  tng_molecule_t *molecule)
8253 {
8254     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8255     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8256
8257     if(index >= tng_data->n_molecules)
8258     {
8259         *molecule = 0;
8260         return(TNG_FAILURE);
8261     }
8262     *molecule = &tng_data->molecules[index];
8263     return(TNG_SUCCESS);
8264 }
8265
8266 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
8267                                                                tng_trajectory_t tng_data_dest)
8268 {
8269     tng_molecule_t molecule, molecule_temp;
8270     tng_chain_t chain, chain_temp;
8271     tng_residue_t residue, residue_temp;
8272     tng_atom_t atom, atom_temp;
8273     tng_bond_t bond_temp;
8274     tng_function_status stat;
8275     int64_t i, j, k, l, *list_temp;
8276
8277     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
8278     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
8279
8280     for(i = 0; i < tng_data_dest->n_molecules; i++)
8281     {
8282         molecule = &tng_data_dest->molecules[i];
8283         tng_molecule_destroy(tng_data_dest, molecule);
8284     }
8285
8286     tng_data_dest->n_molecules = 0;
8287     tng_data_dest->n_particles = 0;
8288
8289     molecule_temp = realloc(tng_data_dest->molecules,
8290                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
8291     if(!molecule_temp)
8292     {
8293         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8294                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
8295                __FILE__, __LINE__);
8296         free(tng_data_dest->molecules);
8297         tng_data_dest->molecules = 0;
8298         return(TNG_CRITICAL);
8299     }
8300     list_temp = realloc(tng_data_dest->molecule_cnt_list,
8301                                      sizeof(int64_t) * tng_data_src->n_molecules);
8302     if(!list_temp)
8303     {
8304         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8305                sizeof(int64_t) * tng_data_src->n_molecules,
8306                __FILE__, __LINE__);
8307         free(tng_data_dest->molecule_cnt_list);
8308         tng_data_dest->molecule_cnt_list = 0;
8309         free(molecule_temp);
8310         return(TNG_CRITICAL);
8311     }
8312
8313     tng_data_dest->molecules = molecule_temp;
8314     tng_data_dest->molecule_cnt_list = list_temp;
8315
8316     for(i = 0; i < tng_data_src->n_molecules; i++)
8317     {
8318         molecule = &tng_data_src->molecules[i];
8319         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
8320                                      &molecule_temp);
8321         if(stat != TNG_SUCCESS)
8322         {
8323             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
8324                    __FILE__, __LINE__);
8325             return(stat);
8326         }
8327         molecule_temp->quaternary_str = molecule->quaternary_str;
8328         for(j = 0; j < molecule->n_chains; j++)
8329         {
8330             chain = &molecule->chains[j];
8331             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
8332                                                chain->name, chain->id,
8333                                                &chain_temp);
8334             if(stat != TNG_SUCCESS)
8335             {
8336                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
8337                        __FILE__, __LINE__);
8338                 return(stat);
8339             }
8340             for(k = 0; k < chain->n_residues; k++)
8341             {
8342                 residue = &chain->residues[k];
8343                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
8344                                                   residue->name, residue->id,
8345                                                   &residue_temp);
8346                 if(stat != TNG_SUCCESS)
8347                 {
8348                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
8349                            __FILE__, __LINE__);
8350                     return(stat);
8351                 }
8352                 for(l = 0; l < residue->n_atoms; l++)
8353                 {
8354                     atom = &molecule->atoms[residue->atoms_offset + l];
8355                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
8356                                                      atom->name, atom->atom_type,
8357                                                      atom->id, &atom_temp);
8358                     if(stat != TNG_SUCCESS)
8359                     {
8360                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
8361                            __FILE__, __LINE__);
8362                         return(stat);
8363                     }
8364                 }
8365             }
8366         }
8367         molecule_temp->n_bonds = molecule->n_bonds;
8368         bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
8369                             molecule->n_bonds);
8370         if(!bond_temp)
8371         {
8372             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8373                    sizeof(struct tng_bond) * molecule->n_bonds,
8374                    __FILE__, __LINE__);
8375             free(molecule_temp->bonds);
8376             molecule_temp->n_bonds = 0;
8377             return(TNG_CRITICAL);
8378         }
8379         molecule_temp->bonds = bond_temp;
8380         for(j = 0; j < molecule->n_bonds; j++)
8381         {
8382             molecule_temp->bonds[j] = molecule->bonds[j];
8383         }
8384         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
8385                                     tng_data_src->molecule_cnt_list[i]);
8386         if(stat != TNG_SUCCESS)
8387         {
8388             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
8389                    __FILE__, __LINE__);
8390             return(stat);
8391         }
8392     }
8393     return(TNG_SUCCESS);
8394 }
8395
8396 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
8397                 (const tng_trajectory_t tng_data,
8398                  const tng_molecule_t molecule,
8399                  int64_t *n)
8400 {
8401     (void) tng_data;
8402     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8403     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8404
8405     *n = molecule->n_chains;
8406
8407     return(TNG_SUCCESS);
8408 }
8409
8410 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
8411                 (tng_trajectory_t tng_data,
8412                  tng_molecule_t molecule,
8413                  int64_t index,
8414                  tng_chain_t *chain)
8415 {
8416     (void) tng_data;
8417     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8418     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8419
8420     if(index >= molecule->n_chains)
8421     {
8422         *chain = 0;
8423         return(TNG_FAILURE);
8424     }
8425     *chain = &molecule->chains[index];
8426     return(TNG_SUCCESS);
8427 }
8428
8429 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
8430                 (const tng_trajectory_t tng_data,
8431                  const tng_molecule_t molecule,
8432                  int64_t *n)
8433 {
8434     (void) tng_data;
8435     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8436     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8437
8438     *n = molecule->n_residues;
8439
8440     return(TNG_SUCCESS);
8441 }
8442
8443 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
8444                 (const tng_trajectory_t tng_data,
8445                  const tng_molecule_t molecule,
8446                  const int64_t index,
8447                  tng_residue_t *residue)
8448 {
8449     (void) tng_data;
8450     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8451     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8452
8453     if(index >= molecule->n_residues)
8454     {
8455         *residue = 0;
8456         return(TNG_FAILURE);
8457     }
8458     *residue = &molecule->residues[index];
8459     return(TNG_SUCCESS);
8460 }
8461
8462 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
8463                 (const tng_trajectory_t tng_data,
8464                  const tng_molecule_t molecule,
8465                  int64_t *n)
8466 {
8467     (void) tng_data;
8468     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8469     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8470
8471     *n = molecule->n_atoms;
8472
8473     return(TNG_SUCCESS);
8474 }
8475
8476 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
8477                 (const tng_trajectory_t tng_data,
8478                  const tng_molecule_t molecule,
8479                  const int64_t index,
8480                  tng_atom_t *atom)
8481 {
8482     (void) tng_data;
8483     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8484     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8485
8486     if(index >= molecule->n_atoms)
8487     {
8488         *atom = 0;
8489         return(TNG_FAILURE);
8490     }
8491     *atom = &molecule->atoms[index];
8492     return(TNG_SUCCESS);
8493 }
8494
8495 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
8496                 (tng_trajectory_t tng_data,
8497                  tng_molecule_t molecule,
8498                  const char *name,
8499                  int64_t nr,
8500                  tng_chain_t *chain)
8501 {
8502     int64_t i, n_chains;
8503     (void)tng_data;
8504
8505     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8506     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8507
8508     n_chains = molecule->n_chains;
8509
8510     for(i = n_chains - 1; i >= 0; i--)
8511     {
8512         *chain = &molecule->chains[i];
8513         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
8514         {
8515             if(nr == -1 || nr == (*chain)->id)
8516             {
8517                 return(TNG_SUCCESS);
8518             }
8519         }
8520     }
8521
8522     *chain = 0;
8523
8524     return(TNG_FAILURE);
8525 }
8526
8527 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
8528                 (tng_trajectory_t tng_data,
8529                  tng_molecule_t molecule,
8530                  const char *name,
8531                  tng_chain_t *chain)
8532 {
8533     int64_t id;
8534
8535     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8536     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8537
8538     /* Set ID to the ID of the last chain + 1 */
8539     if(molecule->n_chains)
8540     {
8541         id = molecule->chains[molecule->n_chains-1].id + 1;
8542     }
8543     else
8544     {
8545         id = 1;
8546     }
8547
8548     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
8549                                        id, chain));
8550 }
8551
8552 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
8553                 (tng_trajectory_t tng_data,
8554                  tng_molecule_t molecule,
8555                  const char *name,
8556                  const int64_t id,
8557                  tng_chain_t *chain)
8558 {
8559     tng_chain_t new_chains;
8560     tng_function_status stat = TNG_SUCCESS;
8561
8562     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8563     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8564
8565     new_chains = realloc(molecule->chains,
8566                          sizeof(struct tng_chain) *
8567                          (molecule->n_chains + 1));
8568
8569     if(!new_chains)
8570     {
8571         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8572                sizeof(struct tng_chain) * (molecule->n_chains + 1),
8573                __FILE__, __LINE__);
8574         free(molecule->chains);
8575         molecule->chains = 0;
8576         return(TNG_CRITICAL);
8577     }
8578
8579     molecule->chains = new_chains;
8580
8581     *chain = &new_chains[molecule->n_chains];
8582     (*chain)->name = 0;
8583
8584     tng_chain_name_set(tng_data, *chain, name);
8585
8586     (*chain)->molecule = molecule;
8587     (*chain)->n_residues = 0;
8588
8589     molecule->n_chains++;
8590
8591     (*chain)->id = id;
8592
8593     return(stat);
8594 }
8595
8596 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
8597                 (const tng_trajectory_t tng_data,
8598                  tng_molecule_t molecule,
8599                  const int64_t from_atom_id,
8600                  const int64_t to_atom_id,
8601                  tng_bond_t *bond)
8602 {
8603     tng_bond_t new_bonds;
8604     (void)tng_data;
8605
8606     new_bonds = realloc(molecule->bonds,
8607                         sizeof(struct tng_bond) *
8608                         (molecule->n_bonds + 1));
8609
8610     if(!new_bonds)
8611     {
8612         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8613                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
8614                __FILE__, __LINE__);
8615         *bond = 0;
8616         free(molecule->bonds);
8617         molecule->bonds = 0;
8618         return(TNG_CRITICAL);
8619     }
8620
8621     molecule->bonds = new_bonds;
8622
8623     *bond = &new_bonds[molecule->n_bonds];
8624
8625     (*bond)->from_atom_id = from_atom_id;
8626     (*bond)->to_atom_id = to_atom_id;
8627
8628     molecule->n_bonds++;
8629
8630     return(TNG_SUCCESS);
8631 }
8632
8633 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
8634                 (tng_trajectory_t tng_data,
8635                  tng_molecule_t molecule,
8636                  const char *name,
8637                  int64_t id,
8638                  tng_atom_t *atom)
8639 {
8640     int64_t i, n_atoms;
8641     (void)tng_data;
8642
8643     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8644
8645     n_atoms = molecule->n_atoms;
8646
8647     for(i = n_atoms - 1; i >= 0; i--)
8648     {
8649         *atom = &molecule->atoms[i];
8650         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8651         {
8652             if(id == -1 || id == (*atom)->id)
8653             {
8654                 return(TNG_SUCCESS);
8655             }
8656         }
8657     }
8658
8659     *atom = 0;
8660
8661     return(TNG_FAILURE);
8662 }
8663
8664 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8665                                        const tng_chain_t chain,
8666                                        char *name,
8667                                        const int max_len)
8668 {
8669     (void) tng_data;
8670     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8671     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8672
8673     strncpy(name, chain->name, max_len - 1);
8674     name[max_len - 1] = 0;
8675
8676     if(strlen(chain->name) > (unsigned int)max_len - 1)
8677     {
8678         return(TNG_FAILURE);
8679     }
8680     return(TNG_SUCCESS);
8681 }
8682
8683 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8684                 (tng_trajectory_t tng_data,
8685                  tng_chain_t chain,
8686                  const char *new_name)
8687 {
8688     unsigned int len;
8689     (void)tng_data;
8690
8691     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8692
8693     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8694
8695     /* If the currently stored string length is not enough to store the new
8696      * string it is freed and reallocated. */
8697     if(chain->name && strlen(chain->name) < len)
8698     {
8699         free(chain->name);
8700         chain->name = 0;
8701     }
8702     if(!chain->name)
8703     {
8704         chain->name = malloc(len);
8705         if(!chain->name)
8706         {
8707             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8708                    __FILE__, __LINE__);
8709             return(TNG_CRITICAL);
8710         }
8711     }
8712
8713     strncpy(chain->name, new_name, len);
8714
8715     return(TNG_SUCCESS);
8716 }
8717
8718 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8719                 (const tng_trajectory_t tng_data,
8720                  const tng_chain_t chain,
8721                  int64_t *n)
8722 {
8723     (void) tng_data;
8724     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8725     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8726
8727     *n = chain->n_residues;
8728
8729     return(TNG_SUCCESS);
8730 }
8731
8732 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8733                 (const tng_trajectory_t tng_data,
8734                  const tng_chain_t chain,
8735                  const int64_t index,
8736                  tng_residue_t *residue)
8737 {
8738     (void) tng_data;
8739     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8740     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8741
8742     if(index >= chain->n_residues)
8743     {
8744         *residue = 0;
8745         return(TNG_FAILURE);
8746     }
8747     *residue = &chain->residues[index];
8748     return(TNG_SUCCESS);
8749 }
8750
8751 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8752                 (tng_trajectory_t tng_data,
8753                  tng_chain_t chain,
8754                  const char *name,
8755                  int64_t id,
8756                  tng_residue_t *residue)
8757 {
8758     int64_t i, n_residues;
8759     (void)tng_data;
8760
8761     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8762
8763     n_residues = chain->n_residues;
8764
8765     for(i = n_residues - 1; i >= 0; i--)
8766     {
8767         *residue = &chain->residues[i];
8768         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8769         {
8770             if(id == -1 || id == (*residue)->id)
8771             {
8772                 return(TNG_SUCCESS);
8773             }
8774         }
8775     }
8776
8777     *residue = 0;
8778
8779     return(TNG_FAILURE);
8780 }
8781
8782 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8783                 (tng_trajectory_t tng_data,
8784                  tng_chain_t chain,
8785                  const char *name,
8786                  tng_residue_t *residue)
8787 {
8788     int64_t id;
8789
8790     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8791     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8792
8793     /* Set ID to the ID of the last residue + 1 */
8794     if(chain->n_residues)
8795     {
8796         id = chain->residues[chain->n_residues-1].id + 1;
8797     }
8798     else
8799     {
8800         id = 0;
8801     }
8802
8803     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8804                                       id, residue));
8805 }
8806
8807 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8808                 (tng_trajectory_t tng_data,
8809                  tng_chain_t chain,
8810                  const char *name,
8811                  const int64_t id,
8812                  tng_residue_t *residue)
8813 {
8814     int64_t curr_index;
8815     tng_residue_t new_residues, temp_residue, last_residue;
8816     tng_molecule_t molecule = chain->molecule;
8817     tng_function_status stat = TNG_SUCCESS;
8818
8819     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8820     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8821
8822     if(chain->n_residues)
8823     {
8824         curr_index = chain->residues - molecule->residues;
8825     }
8826     else
8827     {
8828         curr_index = -1;
8829     }
8830
8831     new_residues = realloc(molecule->residues,
8832                            sizeof(struct tng_residue) *
8833                            (molecule->n_residues + 1));
8834
8835     if(!new_residues)
8836     {
8837         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
8838                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8839                __FILE__, __LINE__);
8840         free(molecule->residues);
8841         molecule->residues = 0;
8842         return(TNG_CRITICAL);
8843     }
8844
8845     molecule->residues = new_residues;
8846
8847     if(curr_index != -1)
8848     {
8849         chain->residues = new_residues + curr_index;
8850         if(molecule->n_residues)
8851         {
8852             last_residue = &new_residues[molecule->n_residues - 1];
8853
8854             temp_residue = chain->residues + (chain->n_residues - 1);
8855             /* Make space in list of residues to add the new residues together with the other
8856             * residues of this chain */
8857             if(temp_residue != last_residue)
8858             {
8859                 ++temp_residue;
8860                 memmove(temp_residue + 1, temp_residue,
8861                         last_residue - temp_residue);
8862             }
8863         }
8864     }
8865     else
8866     {
8867         curr_index = molecule->n_residues;
8868     }
8869
8870     *residue = &molecule->residues[curr_index + chain->n_residues];
8871
8872     if(!chain->n_residues)
8873     {
8874         chain->residues = *residue;
8875     }
8876     else
8877     {
8878         chain->residues = &molecule->residues[curr_index];
8879     }
8880
8881     (*residue)->name = 0;
8882     tng_residue_name_set(tng_data, *residue, name);
8883
8884     (*residue)->chain = chain;
8885     (*residue)->n_atoms = 0;
8886     (*residue)->atoms_offset = 0;
8887
8888     chain->n_residues++;
8889     molecule->n_residues++;
8890
8891     (*residue)->id = id;
8892
8893     return(stat);
8894 }
8895
8896 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8897                                          const tng_residue_t residue,
8898                                          char *name,
8899                                          const int max_len)
8900 {
8901     (void) tng_data;
8902     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8903     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8904
8905     strncpy(name, residue->name, max_len - 1);
8906     name[max_len - 1] = 0;
8907
8908     if(strlen(residue->name) > (unsigned int)max_len - 1)
8909     {
8910         return(TNG_FAILURE);
8911     }
8912     return(TNG_SUCCESS);
8913 }
8914
8915 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8916                                                            tng_residue_t residue,
8917                                                            const char *new_name)
8918 {
8919     unsigned int len;
8920     (void)tng_data;
8921
8922     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8923     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8924
8925     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8926
8927     /* If the currently stored string length is not enough to store the new
8928      * string it is freed and reallocated. */
8929     if(residue->name && strlen(residue->name) < len)
8930     {
8931         free(residue->name);
8932         residue->name = 0;
8933     }
8934     if(!residue->name)
8935     {
8936         residue->name = malloc(len);
8937         if(!residue->name)
8938         {
8939             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8940                    __FILE__, __LINE__);
8941             return(TNG_CRITICAL);
8942         }
8943     }
8944
8945     strncpy(residue->name, new_name, len);
8946
8947     return(TNG_SUCCESS);
8948 }
8949
8950 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8951                 (const tng_trajectory_t tng_data,
8952                  const tng_residue_t residue,
8953                  int64_t *n)
8954 {
8955     (void) tng_data;
8956     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8957     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8958
8959     *n = residue->n_atoms;
8960
8961     return(TNG_SUCCESS);
8962 }
8963
8964 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8965                 (const tng_trajectory_t tng_data,
8966                  const tng_residue_t residue,
8967                  const int64_t index,
8968                  tng_atom_t *atom)
8969 {
8970     tng_chain_t chain;
8971     tng_molecule_t molecule;
8972
8973     (void) tng_data;
8974     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8975     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8976
8977     if(index >= residue->n_atoms)
8978     {
8979         *atom = 0;
8980         return(TNG_FAILURE);
8981     }
8982     chain = residue->chain;
8983     molecule = chain->molecule;
8984
8985     if(index + residue->atoms_offset >= molecule->n_atoms)
8986     {
8987         *atom = 0;
8988         return(TNG_FAILURE);
8989     }
8990
8991     *atom = &molecule->atoms[residue->atoms_offset + index];
8992     return(TNG_SUCCESS);
8993 }
8994
8995 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
8996                 (tng_trajectory_t tng_data,
8997                  tng_residue_t residue,
8998                  const char *atom_name,
8999                  const char *atom_type,
9000                  tng_atom_t *atom)
9001 {
9002     int64_t id;
9003
9004     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9005     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
9006     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
9007
9008     /* Set ID to the ID of the last atom + 1 */
9009     if(residue->chain->molecule->n_atoms)
9010     {
9011         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
9012     }
9013     else
9014     {
9015         id = 0;
9016     }
9017
9018     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
9019                                      id, atom));
9020 }
9021
9022 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
9023                 (tng_trajectory_t tng_data,
9024                  tng_residue_t residue,
9025                  const char *atom_name,
9026                  const char *atom_type,
9027                  const int64_t id,
9028                  tng_atom_t *atom)
9029 {
9030     tng_atom_t new_atoms;
9031     tng_molecule_t molecule = residue->chain->molecule;
9032     tng_function_status stat = TNG_SUCCESS;
9033
9034     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9035     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
9036     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
9037
9038     if(!residue->n_atoms)
9039     {
9040         residue->atoms_offset = molecule->n_atoms;
9041     }
9042
9043     new_atoms = realloc(molecule->atoms,
9044                         sizeof(struct tng_atom) *
9045                         (molecule->n_atoms + 1));
9046
9047     if(!new_atoms)
9048     {
9049         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9050                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
9051                __FILE__, __LINE__);
9052         free(molecule->atoms);
9053         molecule->atoms = 0;
9054         return(TNG_CRITICAL);
9055     }
9056
9057     molecule->atoms = new_atoms;
9058
9059     *atom = &new_atoms[molecule->n_atoms];
9060
9061     tng_atom_init(*atom);
9062     tng_atom_name_set(tng_data, *atom, atom_name);
9063     tng_atom_type_set(tng_data, *atom, atom_type);
9064
9065     (*atom)->residue = residue;
9066
9067     residue->n_atoms++;
9068     molecule->n_atoms++;
9069
9070     (*atom)->id = id;
9071
9072     return(stat);
9073 }
9074
9075 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
9076                                                          tng_molecule_t *molecule_p)
9077 {
9078     *molecule_p = malloc(sizeof(struct tng_molecule));
9079     if(!*molecule_p)
9080     {
9081         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9082                sizeof(struct tng_molecule), __FILE__, __LINE__);
9083         return(TNG_CRITICAL);
9084     }
9085
9086     tng_molecule_init(tng_data, *molecule_p);
9087
9088     return(TNG_SUCCESS);
9089 }
9090
9091 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
9092                                                         tng_molecule_t *molecule_p)
9093 {
9094     if(!*molecule_p)
9095     {
9096         return(TNG_SUCCESS);
9097     }
9098
9099     tng_molecule_destroy(tng_data, *molecule_p);
9100
9101     free(*molecule_p);
9102     *molecule_p = 0;
9103
9104     return(TNG_SUCCESS);
9105 }
9106
9107 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
9108                                                         tng_molecule_t molecule)
9109 {
9110     (void)tng_data;
9111     molecule->quaternary_str = 1;
9112     molecule->name = 0;
9113     molecule->n_chains = 0;
9114     molecule->chains = 0;
9115     molecule->n_residues = 0;
9116     molecule->residues = 0;
9117     molecule->n_atoms = 0;
9118     molecule->atoms = 0;
9119     molecule->n_bonds = 0;
9120     molecule->bonds = 0;
9121
9122     return(TNG_SUCCESS);
9123 }
9124
9125 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
9126                                                            tng_molecule_t molecule)
9127 {
9128     int64_t i;
9129     (void)tng_data;
9130
9131     if(molecule->name)
9132     {
9133         free(molecule->name);
9134         molecule->name = 0;
9135     }
9136
9137     if(molecule->chains)
9138     {
9139         for(i = 0; i < molecule->n_chains; i++)
9140         {
9141             if(molecule->chains[i].name)
9142             {
9143                 free(molecule->chains[i].name);
9144                 molecule->chains[i].name = 0;
9145             }
9146         }
9147         free(molecule->chains);
9148         molecule->chains = 0;
9149     }
9150     molecule->n_chains = 0;
9151
9152     if(molecule->residues)
9153     {
9154         for(i = 0; i < molecule->n_residues; i++)
9155         {
9156             if(molecule->residues[i].name)
9157             {
9158                 free(molecule->residues[i].name);
9159                 molecule->residues[i].name = 0;
9160             }
9161         }
9162         free(molecule->residues);
9163         molecule->residues = 0;
9164     }
9165     molecule->n_residues = 0;
9166
9167     if(molecule->atoms)
9168     {
9169         for(i = 0; i < molecule->n_atoms; i++)
9170         {
9171             tng_atom_destroy(&molecule->atoms[i]);
9172         }
9173         free(molecule->atoms);
9174         molecule->atoms = 0;
9175     }
9176     molecule->n_atoms = 0;
9177
9178     if(molecule->bonds)
9179     {
9180         free(molecule->bonds);
9181         molecule->bonds = 0;
9182     }
9183     molecule->n_bonds = 0;
9184
9185     return(TNG_SUCCESS);
9186 }
9187
9188 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
9189                 (const tng_trajectory_t tng_data,
9190                  const int64_t nr,
9191                  char *name,
9192                  int max_len)
9193 {
9194     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9195     tng_molecule_t mol;
9196     tng_bool found = TNG_FALSE;
9197
9198     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9199     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9200
9201     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9202
9203     if(!molecule_cnt_list)
9204     {
9205         return(TNG_FAILURE);
9206     }
9207
9208     for(i = 0; i < tng_data->n_molecules; i++)
9209     {
9210         mol = &tng_data->molecules[i];
9211         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9212         {
9213             cnt += mol->n_atoms * molecule_cnt_list[i];
9214             continue;
9215         }
9216         found = TNG_TRUE;
9217         break;
9218     }
9219     if(!found)
9220     {
9221         return(TNG_FAILURE);
9222     }
9223
9224     strncpy(name, mol->name, max_len - 1);
9225     name[max_len - 1] = 0;
9226
9227     if(strlen(mol->name) > (unsigned int)max_len - 1)
9228     {
9229         return(TNG_FAILURE);
9230     }
9231     return(TNG_SUCCESS);
9232 }
9233
9234 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
9235                 (const tng_trajectory_t tng_data,
9236                  const int64_t nr,
9237                  int64_t *id)
9238 {
9239     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9240     tng_molecule_t mol;
9241     tng_bool found = TNG_FALSE;
9242
9243     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9244     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9245
9246     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9247
9248     if(!molecule_cnt_list)
9249     {
9250         return(TNG_FAILURE);
9251     }
9252
9253     for(i = 0; i < tng_data->n_molecules; i++)
9254     {
9255         mol = &tng_data->molecules[i];
9256         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9257         {
9258             cnt += mol->n_atoms * molecule_cnt_list[i];
9259             continue;
9260         }
9261         found = TNG_TRUE;
9262         break;
9263     }
9264     if(!found)
9265     {
9266         return(TNG_FAILURE);
9267     }
9268
9269     *id = mol->id;
9270
9271     return(TNG_SUCCESS);
9272 }
9273
9274 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
9275                 (const tng_trajectory_t tng_data,
9276                  int64_t *n_bonds,
9277                  int64_t **from_atoms,
9278                  int64_t **to_atoms)
9279 {
9280     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
9281     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
9282     tng_molecule_t mol;
9283     tng_bond_t bond;
9284
9285     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9286     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
9287     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
9288     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
9289
9290     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9291
9292     if(!molecule_cnt_list)
9293     {
9294         return(TNG_FAILURE);
9295     }
9296
9297     *n_bonds = 0;
9298     /* First count the total number of bonds to allocate memory */
9299     for(i = 0; i < tng_data->n_molecules; i++)
9300     {
9301         mol = &tng_data->molecules[i];
9302         mol_cnt = molecule_cnt_list[i];
9303         *n_bonds += mol_cnt * mol->n_bonds;
9304     }
9305     if(*n_bonds == 0)
9306     {
9307         return(TNG_SUCCESS);
9308     }
9309
9310     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9311     if(!*from_atoms)
9312     {
9313         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9314                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9315         return(TNG_CRITICAL);
9316     }
9317     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9318     if(!*to_atoms)
9319     {
9320         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9321                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9322         free(*from_atoms);
9323         *from_atoms = 0;
9324         return(TNG_CRITICAL);
9325     }
9326
9327     cnt = 0;
9328     for(i = 0; i < tng_data->n_molecules; i++)
9329     {
9330         mol = &tng_data->molecules[i];
9331         mol_cnt = molecule_cnt_list[i];
9332         for(j = 0; j < mol_cnt; j++)
9333         {
9334             for(k = 0; k < mol->n_bonds; k++)
9335             {
9336                 bond = &mol->bonds[k];
9337                 from_atom = atom_cnt + bond->from_atom_id;
9338                 to_atom = atom_cnt + bond->to_atom_id;
9339                 (*from_atoms)[cnt] = from_atom;
9340                 (*to_atoms)[cnt++] = to_atom;
9341             }
9342             atom_cnt += mol->n_atoms;
9343         }
9344     }
9345
9346     return(TNG_SUCCESS);
9347 }
9348
9349 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
9350                 (const tng_trajectory_t tng_data,
9351                  const int64_t nr,
9352                  char *name,
9353                  int max_len)
9354 {
9355     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9356     tng_molecule_t mol;
9357     tng_atom_t atom;
9358     tng_bool found = TNG_FALSE;
9359
9360     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9361     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9362
9363     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9364
9365     if(!molecule_cnt_list)
9366     {
9367         return(TNG_FAILURE);
9368     }
9369
9370     for(i = 0; i < tng_data->n_molecules; i++)
9371     {
9372         mol = &tng_data->molecules[i];
9373         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9374         {
9375             cnt += mol->n_atoms * molecule_cnt_list[i];
9376             continue;
9377         }
9378         atom = &mol->atoms[nr % mol->n_atoms];
9379         found = TNG_TRUE;
9380         break;
9381     }
9382     if(!found)
9383     {
9384         return(TNG_FAILURE);
9385     }
9386     if(!atom->residue || !atom->residue->chain)
9387     {
9388         return(TNG_FAILURE);
9389     }
9390
9391     strncpy(name, atom->residue->chain->name, max_len - 1);
9392     name[max_len - 1] = 0;
9393
9394     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
9395     {
9396         return(TNG_FAILURE);
9397     }
9398     return(TNG_SUCCESS);
9399 }
9400
9401 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
9402                 (const tng_trajectory_t tng_data,
9403                  const int64_t nr,
9404                  char *name,
9405                  int max_len)
9406 {
9407     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9408     tng_molecule_t mol;
9409     tng_atom_t atom;
9410     tng_bool found = TNG_FALSE;
9411
9412     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9413     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9414
9415     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9416
9417     if(!molecule_cnt_list)
9418     {
9419         return(TNG_FAILURE);
9420     }
9421
9422     for(i = 0; i < tng_data->n_molecules; i++)
9423     {
9424         mol = &tng_data->molecules[i];
9425         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9426         {
9427             cnt += mol->n_atoms * molecule_cnt_list[i];
9428             continue;
9429         }
9430         atom = &mol->atoms[nr % mol->n_atoms];
9431         found = TNG_TRUE;
9432         break;
9433     }
9434     if(!found)
9435     {
9436         return(TNG_FAILURE);
9437     }
9438     if(!atom->residue)
9439     {
9440         return(TNG_FAILURE);
9441     }
9442
9443     strncpy(name, atom->residue->name, max_len - 1);
9444     name[max_len - 1] = 0;
9445
9446     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
9447     {
9448         return(TNG_FAILURE);
9449     }
9450     return(TNG_SUCCESS);
9451 }
9452
9453 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
9454                 (const tng_trajectory_t tng_data,
9455                  const int64_t nr,
9456                  int64_t *id)
9457 {
9458     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9459     tng_molecule_t mol;
9460     tng_atom_t atom;
9461     tng_bool found = TNG_FALSE;
9462
9463     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9464     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9465
9466     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9467
9468     if(!molecule_cnt_list)
9469     {
9470         return(TNG_FAILURE);
9471     }
9472
9473     for(i = 0; i < tng_data->n_molecules; i++)
9474     {
9475         mol = &tng_data->molecules[i];
9476         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9477         {
9478             cnt += mol->n_atoms * molecule_cnt_list[i];
9479             continue;
9480         }
9481         atom = &mol->atoms[nr % mol->n_atoms];
9482         found = TNG_TRUE;
9483         break;
9484     }
9485     if(!found)
9486     {
9487         return(TNG_FAILURE);
9488     }
9489     if(!atom->residue)
9490     {
9491         return(TNG_FAILURE);
9492     }
9493
9494     *id = atom->residue->id;
9495
9496     return(TNG_SUCCESS);
9497 }
9498
9499 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
9500                 (const tng_trajectory_t tng_data,
9501                  const int64_t nr,
9502                  int64_t *id)
9503 {
9504     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
9505     tng_molecule_t mol;
9506     tng_atom_t atom;
9507     tng_bool found = TNG_FALSE;
9508
9509     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9510     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9511
9512     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9513
9514     if(!molecule_cnt_list)
9515     {
9516         return(TNG_FAILURE);
9517     }
9518
9519     for(i = 0; i < tng_data->n_molecules; i++)
9520     {
9521         mol = &tng_data->molecules[i];
9522         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9523         {
9524             cnt += mol->n_atoms * molecule_cnt_list[i];
9525             offset += mol->n_residues * molecule_cnt_list[i];
9526             continue;
9527         }
9528         atom = &mol->atoms[nr % mol->n_atoms];
9529         found = TNG_TRUE;
9530         break;
9531     }
9532     if(!found)
9533     {
9534         return(TNG_FAILURE);
9535     }
9536     if(!atom->residue)
9537     {
9538         return(TNG_FAILURE);
9539     }
9540
9541     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
9542
9543     *id = atom->residue->id + offset;
9544
9545     return(TNG_SUCCESS);
9546 }
9547
9548 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
9549                 (const tng_trajectory_t tng_data,
9550                  const int64_t nr,
9551                  char *name,
9552                  int max_len)
9553 {
9554     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9555     tng_molecule_t mol;
9556     tng_atom_t atom;
9557     tng_bool found = TNG_FALSE;
9558
9559     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9560     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9561
9562     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9563
9564     if(!molecule_cnt_list)
9565     {
9566         return(TNG_FAILURE);
9567     }
9568
9569     for(i = 0; i < tng_data->n_molecules; i++)
9570     {
9571         mol = &tng_data->molecules[i];
9572         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9573         {
9574             cnt += mol->n_atoms * molecule_cnt_list[i];
9575             continue;
9576         }
9577         atom = &mol->atoms[nr % mol->n_atoms];
9578         found = TNG_TRUE;
9579         break;
9580     }
9581     if(!found)
9582     {
9583         return(TNG_FAILURE);
9584     }
9585
9586     strncpy(name, atom->name, max_len - 1);
9587     name[max_len - 1] = 0;
9588
9589     if(strlen(atom->name) > (unsigned int)max_len - 1)
9590     {
9591         return(TNG_FAILURE);
9592     }
9593     return(TNG_SUCCESS);
9594 }
9595
9596 tng_function_status tng_atom_type_of_particle_nr_get
9597                 (const tng_trajectory_t tng_data,
9598                  const int64_t nr,
9599                  char *type,
9600                  int max_len)
9601 {
9602     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9603     tng_molecule_t mol;
9604     tng_atom_t atom;
9605     tng_bool found = TNG_FALSE;
9606
9607     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9608     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
9609
9610     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9611
9612     if(!molecule_cnt_list)
9613     {
9614         return(TNG_FAILURE);
9615     }
9616
9617     for(i = 0; i < tng_data->n_molecules; i++)
9618     {
9619         mol = &tng_data->molecules[i];
9620         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9621         {
9622             cnt += mol->n_atoms * molecule_cnt_list[i];
9623             continue;
9624         }
9625         atom = &mol->atoms[nr % mol->n_atoms];
9626         found = TNG_TRUE;
9627         break;
9628     }
9629     if(!found)
9630     {
9631         return(TNG_FAILURE);
9632     }
9633
9634     strncpy(type, atom->atom_type, max_len - 1);
9635     type[max_len - 1] = 0;
9636
9637     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
9638     {
9639         return(TNG_FAILURE);
9640     }
9641     return(TNG_SUCCESS);
9642 }
9643
9644 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9645                 (tng_trajectory_t tng_data,
9646                  const int64_t num_first_particle,
9647                  const int64_t n_particles,
9648                  const int64_t *mapping_table)
9649 {
9650     int64_t i;
9651     tng_particle_mapping_t mapping;
9652     tng_trajectory_frame_set_t frame_set;
9653
9654     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9655
9656     frame_set = &tng_data->current_trajectory_frame_set;
9657
9658     /* Sanity check of the particle ranges. Split into multiple if
9659      * statements for improved readability */
9660     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9661     {
9662         mapping = &frame_set->mappings[i];
9663         if(num_first_particle >= mapping->num_first_particle &&
9664            num_first_particle < mapping->num_first_particle +
9665                                    mapping->n_particles)
9666         {
9667             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9668             return(TNG_FAILURE);
9669         }
9670         if(num_first_particle + n_particles >=
9671            mapping->num_first_particle &&
9672            num_first_particle + n_particles <
9673            mapping->num_first_particle + mapping->n_particles)
9674         {
9675             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9676             return(TNG_FAILURE);
9677         }
9678         if(mapping->num_first_particle >= num_first_particle &&
9679            mapping->num_first_particle < num_first_particle +
9680                                             n_particles)
9681         {
9682             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9683             return(TNG_FAILURE);
9684         }
9685         if(mapping->num_first_particle + mapping->n_particles >
9686            num_first_particle &&
9687            mapping->num_first_particle + mapping->n_particles <
9688            num_first_particle + n_particles)
9689         {
9690             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9691             return(TNG_FAILURE);
9692         }
9693     }
9694
9695     frame_set->n_mapping_blocks++;
9696
9697     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9698                       frame_set->n_mapping_blocks);
9699
9700     if(!mapping)
9701     {
9702         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9703                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9704                __FILE__, __LINE__);
9705         free(frame_set->mappings);
9706         frame_set->mappings = 0;
9707         return(TNG_CRITICAL);
9708     }
9709     frame_set->mappings = mapping;
9710
9711     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9712     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9713
9714     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9715     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9716     {
9717         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
9718                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9719         return(TNG_CRITICAL);
9720     }
9721
9722     for(i=0; i<n_particles; i++)
9723     {
9724         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9725     }
9726
9727     return(TNG_SUCCESS);
9728 }
9729
9730 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9731 {
9732     tng_trajectory_frame_set_t frame_set;
9733     tng_particle_mapping_t mapping;
9734     int64_t i;
9735
9736     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9737
9738     frame_set = &tng_data->current_trajectory_frame_set;
9739
9740     if(frame_set->n_mapping_blocks && frame_set->mappings)
9741     {
9742         for(i = 0; i < frame_set->n_mapping_blocks; i++)
9743         {
9744             mapping = &frame_set->mappings[i];
9745             if(mapping->real_particle_numbers)
9746             {
9747                 free(mapping->real_particle_numbers);
9748                 mapping->real_particle_numbers = 0;
9749             }
9750         }
9751         free(frame_set->mappings);
9752         frame_set->mappings = 0;
9753         frame_set->n_mapping_blocks = 0;
9754     }
9755
9756     return(TNG_SUCCESS);
9757 }
9758
9759 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9760 {
9761     time_t seconds;
9762     tng_trajectory_frame_set_t frame_set;
9763     tng_trajectory_t tng_data;
9764
9765     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9766     if(!*tng_data_p)
9767     {
9768         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
9769                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9770         return(TNG_CRITICAL);
9771     }
9772
9773     tng_data = *tng_data_p;
9774
9775     frame_set = &tng_data->current_trajectory_frame_set;
9776
9777     tng_data->input_file_path = 0;
9778     tng_data->input_file = 0;
9779     tng_data->input_file_len = 0;
9780     tng_data->output_file_path = 0;
9781     tng_data->output_file = 0;
9782
9783     tng_data->first_program_name = 0;
9784     tng_data->first_user_name = 0;
9785     tng_data->first_computer_name = 0;
9786     tng_data->first_pgp_signature = 0;
9787     tng_data->last_program_name = 0;
9788     tng_data->last_user_name = 0;
9789     tng_data->last_computer_name = 0;
9790     tng_data->last_pgp_signature = 0;
9791     tng_data->forcefield_name = 0;
9792
9793     seconds = time(0);
9794     if ( seconds == -1)
9795     {
9796         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9797     }
9798     else
9799     {
9800         tng_data->time = seconds;
9801     }
9802
9803     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9804     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9805     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9806     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9807     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9808     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9809     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9810     tng_data->frame_set_n_frames = 100;
9811     tng_data->n_trajectory_frame_sets = 0;
9812     tng_data->medium_stride_length = 100;
9813     tng_data->long_stride_length = 10000;
9814
9815     tng_data->time_per_frame = -1;
9816
9817     tng_data->n_particle_data_blocks = 0;
9818     tng_data->n_data_blocks = 0;
9819
9820     tng_data->non_tr_particle_data = 0;
9821     tng_data->non_tr_data = 0;
9822
9823     tng_data->compress_algo_pos = 0;
9824     tng_data->compress_algo_vel = 0;
9825     tng_data->compression_precision = 1000;
9826     tng_data->distance_unit_exponential = -9;
9827
9828     frame_set->first_frame = -1;
9829     frame_set->n_mapping_blocks = 0;
9830     frame_set->mappings = 0;
9831     frame_set->molecule_cnt_list = 0;
9832
9833     frame_set->n_particle_data_blocks = 0;
9834     frame_set->n_data_blocks = 0;
9835
9836     frame_set->tr_particle_data = 0;
9837     frame_set->tr_data = 0;
9838
9839     frame_set->n_written_frames = 0;
9840     frame_set->n_unwritten_frames = 0;
9841
9842     frame_set->next_frame_set_file_pos = -1;
9843     frame_set->prev_frame_set_file_pos = -1;
9844     frame_set->medium_stride_next_frame_set_file_pos = -1;
9845     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9846     frame_set->long_stride_next_frame_set_file_pos = -1;
9847     frame_set->long_stride_prev_frame_set_file_pos = -1;
9848
9849     frame_set->first_frame_time = -1;
9850
9851     tng_data->n_molecules = 0;
9852     tng_data->molecules = 0;
9853     tng_data->molecule_cnt_list = 0;
9854     tng_data->n_particles = 0;
9855
9856     {
9857       /* Check the endianness of the computer */
9858       static int32_t endianness_32 = 0x01234567;
9859       /* 0x01234567 */
9860       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9861         {
9862           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9863         }
9864
9865       /* 0x67452301 */
9866       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9867         {
9868           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9869
9870         }
9871
9872       /* 0x45670123 */
9873       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9874         {
9875           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9876         }
9877     }
9878     {
9879       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9880       /* 0x0123456789ABCDEF */
9881       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9882         {
9883           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9884         }
9885
9886       /* 0xEFCDAB8967452301 */
9887       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9888         {
9889           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9890         }
9891
9892       /* 0x89ABCDEF01234567 */
9893       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9894         {
9895           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9896         }
9897
9898       /* 0x45670123CDEF89AB */
9899       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9900         {
9901           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9902         }
9903
9904       /* 0x23016745AB89EFCD */
9905       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9906         {
9907           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9908         }
9909     }
9910
9911     /* By default do not swap the byte order, i.e. keep the byte order of the
9912      * architecture. The input file endianness will be set when reading the
9913      * header. The output endianness can be changed - before the file is
9914      * written. */
9915     tng_data->input_endianness_swap_func_32 = 0;
9916     tng_data->input_endianness_swap_func_64 = 0;
9917     tng_data->output_endianness_swap_func_32 = 0;
9918     tng_data->output_endianness_swap_func_64 = 0;
9919
9920     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9921     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9922     tng_data->current_trajectory_frame_set.n_frames = 0;
9923
9924     return(TNG_SUCCESS);
9925 }
9926
9927 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9928 {
9929     int64_t i, j, k, l;
9930     int64_t n_particles, n_values_per_frame;
9931     tng_trajectory_t tng_data = *tng_data_p;
9932     tng_trajectory_frame_set_t frame_set;
9933
9934     if(!*tng_data_p)
9935     {
9936         return(TNG_SUCCESS);
9937     }
9938
9939     frame_set = &tng_data->current_trajectory_frame_set;
9940
9941     if(tng_data->input_file_path)
9942     {
9943         free(tng_data->input_file_path);
9944         tng_data->input_file_path = 0;
9945     }
9946
9947     if(tng_data->input_file)
9948     {
9949         if(tng_data->output_file == tng_data->input_file)
9950         {
9951             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9952             tng_data->output_file = 0;
9953         }
9954         fclose(tng_data->input_file);
9955         tng_data->input_file = 0;
9956     }
9957
9958     if(tng_data->output_file_path)
9959     {
9960         free(tng_data->output_file_path);
9961         tng_data->output_file_path = 0;
9962     }
9963
9964     if(tng_data->output_file)
9965     {
9966         /* FIXME: Do not always write the hash */
9967         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9968         fclose(tng_data->output_file);
9969         tng_data->output_file = 0;
9970     }
9971
9972     if(tng_data->first_program_name)
9973     {
9974         free(tng_data->first_program_name);
9975         tng_data->first_program_name = 0;
9976     }
9977
9978     if(tng_data->last_program_name)
9979     {
9980         free(tng_data->last_program_name);
9981         tng_data->last_program_name = 0;
9982     }
9983
9984     if(tng_data->first_user_name)
9985     {
9986         free(tng_data->first_user_name);
9987         tng_data->first_user_name = 0;
9988     }
9989
9990     if(tng_data->last_user_name)
9991     {
9992         free(tng_data->last_user_name);
9993         tng_data->last_user_name = 0;
9994     }
9995
9996     if(tng_data->first_computer_name)
9997     {
9998         free(tng_data->first_computer_name);
9999         tng_data->first_computer_name = 0;
10000     }
10001
10002     if(tng_data->last_computer_name)
10003     {
10004         free(tng_data->last_computer_name);
10005         tng_data->last_computer_name = 0;
10006     }
10007
10008     if(tng_data->first_pgp_signature)
10009     {
10010         free(tng_data->first_pgp_signature);
10011         tng_data->first_pgp_signature = 0;
10012     }
10013
10014     if(tng_data->last_pgp_signature)
10015     {
10016         free(tng_data->last_pgp_signature);
10017         tng_data->last_pgp_signature = 0;
10018     }
10019
10020     if(tng_data->forcefield_name)
10021     {
10022         free(tng_data->forcefield_name);
10023         tng_data->forcefield_name = 0;
10024     }
10025
10026     tng_frame_set_particle_mapping_free(tng_data);
10027
10028     if(frame_set->molecule_cnt_list)
10029     {
10030         free(frame_set->molecule_cnt_list);
10031         frame_set->molecule_cnt_list = 0;
10032     }
10033
10034     if(tng_data->var_num_atoms_flag)
10035     {
10036         n_particles = frame_set->n_particles;
10037     }
10038     else
10039     {
10040         n_particles = tng_data->n_particles;
10041     }
10042
10043     if(tng_data->non_tr_particle_data)
10044     {
10045         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
10046         {
10047             if(tng_data->non_tr_particle_data[i].values)
10048             {
10049                 free(tng_data->non_tr_particle_data[i].values);
10050                 tng_data->non_tr_particle_data[i].values = 0;
10051             }
10052
10053             if(tng_data->non_tr_particle_data[i].strings)
10054             {
10055                 n_values_per_frame = tng_data->non_tr_particle_data[i].
10056                                      n_values_per_frame;
10057                 if(tng_data->non_tr_particle_data[i].strings[0])
10058                 {
10059                     for(j = 0; j < n_particles; j++)
10060                     {
10061                         if(tng_data->non_tr_particle_data[i].strings[0][j])
10062                         {
10063                             for(k = 0; k < n_values_per_frame; k++)
10064                             {
10065                                 if(tng_data->non_tr_particle_data[i].
10066                                    strings[0][j][k])
10067                                 {
10068                                     free(tng_data->non_tr_particle_data[i].
10069                                          strings[0][j][k]);
10070                                     tng_data->non_tr_particle_data[i].
10071                                     strings[0][j][k] = 0;
10072                                 }
10073                             }
10074                             free(tng_data->non_tr_particle_data[i].
10075                                  strings[0][j]);
10076                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
10077                         }
10078                     }
10079                     free(tng_data->non_tr_particle_data[i].strings[0]);
10080                     tng_data->non_tr_particle_data[i].strings[0] = 0;
10081                 }
10082                 free(tng_data->non_tr_particle_data[i].strings);
10083                 tng_data->non_tr_particle_data[i].strings = 0;
10084             }
10085
10086             if(tng_data->non_tr_particle_data[i].block_name)
10087             {
10088                 free(tng_data->non_tr_particle_data[i].block_name);
10089                 tng_data->non_tr_particle_data[i].block_name = 0;
10090             }
10091         }
10092         free(tng_data->non_tr_particle_data);
10093         tng_data->non_tr_particle_data = 0;
10094     }
10095
10096     if(tng_data->non_tr_data)
10097     {
10098         for(i = 0; i < tng_data->n_data_blocks; i++)
10099         {
10100             if(tng_data->non_tr_data[i].values)
10101             {
10102                 free(tng_data->non_tr_data[i].values);
10103                 tng_data->non_tr_data[i].values = 0;
10104             }
10105
10106             if(tng_data->non_tr_data[i].strings)
10107             {
10108                 n_values_per_frame = tng_data->non_tr_data[i].
10109                                      n_values_per_frame;
10110                 if(tng_data->non_tr_data[i].strings[0])
10111                 {
10112                     for(j = 0; j < n_values_per_frame; j++)
10113                     {
10114                         if(tng_data->non_tr_data[i].strings[0][j])
10115                         {
10116                             free(tng_data->non_tr_data[i].strings[0][j]);
10117                             tng_data->non_tr_data[i].strings[0][j] = 0;
10118                         }
10119                     }
10120                     free(tng_data->non_tr_data[i].strings[0]);
10121                     tng_data->non_tr_data[i].strings[0] = 0;
10122                 }
10123                 free(tng_data->non_tr_data[i].strings);
10124                 tng_data->non_tr_data[i].strings = 0;
10125             }
10126
10127             if(tng_data->non_tr_data[i].block_name)
10128             {
10129                 free(tng_data->non_tr_data[i].block_name);
10130                 tng_data->non_tr_data[i].block_name = 0;
10131             }
10132         }
10133         free(tng_data->non_tr_data);
10134         tng_data->non_tr_data = 0;
10135     }
10136
10137     tng_data->n_particle_data_blocks = 0;
10138     tng_data->n_data_blocks = 0;
10139
10140     if(tng_data->compress_algo_pos)
10141     {
10142         free(tng_data->compress_algo_pos);
10143         tng_data->compress_algo_pos = 0;
10144     }
10145     if(tng_data->compress_algo_vel)
10146     {
10147         free(tng_data->compress_algo_vel);
10148         tng_data->compress_algo_vel = 0;
10149     }
10150
10151     if(frame_set->tr_particle_data)
10152     {
10153         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
10154         {
10155             if(frame_set->tr_particle_data[i].values)
10156             {
10157                 free(frame_set->tr_particle_data[i].values);
10158                 frame_set->tr_particle_data[i].values = 0;
10159             }
10160
10161             if(frame_set->tr_particle_data[i].strings)
10162             {
10163                 n_values_per_frame = frame_set->tr_particle_data[i].
10164                                      n_values_per_frame;
10165                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
10166                 {
10167                     if(frame_set->tr_particle_data[i].strings[j])
10168                     {
10169                         for(k = 0; k < n_particles; k++)
10170                         {
10171                             if(frame_set->tr_particle_data[i].
10172                                 strings[j][k])
10173                             {
10174                                 for(l = 0; l < n_values_per_frame; l++)
10175                                 {
10176                                     if(frame_set->tr_particle_data[i].
10177                                         strings[j][k][l])
10178                                     {
10179                                         free(frame_set->tr_particle_data[i].
10180                                                 strings[j][k][l]);
10181                                         frame_set->tr_particle_data[i].
10182                                         strings[j][k][l] = 0;
10183                                     }
10184                                 }
10185                                 free(frame_set->tr_particle_data[i].
10186                                         strings[j][k]);
10187                                 frame_set->tr_particle_data[i].
10188                                 strings[j][k] = 0;
10189                             }
10190                         }
10191                         free(frame_set->tr_particle_data[i].strings[j]);
10192                         frame_set->tr_particle_data[i].strings[j] = 0;
10193                     }
10194                 }
10195                 free(frame_set->tr_particle_data[i].strings);
10196                 frame_set->tr_particle_data[i].strings = 0;
10197             }
10198
10199             if(frame_set->tr_particle_data[i].block_name)
10200             {
10201                 free(frame_set->tr_particle_data[i].block_name);
10202                 frame_set->tr_particle_data[i].block_name = 0;
10203             }
10204         }
10205         free(frame_set->tr_particle_data);
10206         frame_set->tr_particle_data = 0;
10207     }
10208
10209     if(frame_set->tr_data)
10210     {
10211         for(i = 0; i < frame_set->n_data_blocks; i++)
10212         {
10213             if(frame_set->tr_data[i].values)
10214             {
10215                 free(frame_set->tr_data[i].values);
10216                 frame_set->tr_data[i].values = 0;
10217             }
10218
10219             if(frame_set->tr_data[i].strings)
10220             {
10221                 n_values_per_frame = frame_set->tr_data[i].
10222                                      n_values_per_frame;
10223                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
10224                 {
10225                     if(frame_set->tr_data[i].strings[j])
10226                     {
10227                         for(k = 0; k < n_values_per_frame; k++)
10228                         {
10229                             if(frame_set->tr_data[i].strings[j][k])
10230                             {
10231                                 free(frame_set->tr_data[i].strings[j][k]);
10232                                 frame_set->tr_data[i].strings[j][k] = 0;
10233                             }
10234                         }
10235                         free(frame_set->tr_data[i].strings[j]);
10236                         frame_set->tr_data[i].strings[j] = 0;
10237                     }
10238                 }
10239                 free(frame_set->tr_data[i].strings);
10240                 frame_set->tr_data[i].strings = 0;
10241             }
10242
10243             if(frame_set->tr_data[i].block_name)
10244             {
10245                 free(frame_set->tr_data[i].block_name);
10246                 frame_set->tr_data[i].block_name = 0;
10247             }
10248         }
10249         free(frame_set->tr_data);
10250         frame_set->tr_data = 0;
10251     }
10252
10253     frame_set->n_particle_data_blocks = 0;
10254     frame_set->n_data_blocks = 0;
10255
10256     if(tng_data->molecules)
10257     {
10258         for(i = 0; i < tng_data->n_molecules; i++)
10259         {
10260             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
10261         }
10262         free(tng_data->molecules);
10263         tng_data->molecules = 0;
10264         tng_data->n_molecules = 0;
10265     }
10266     if(tng_data->molecule_cnt_list)
10267     {
10268         free(tng_data->molecule_cnt_list);
10269         tng_data->molecule_cnt_list = 0;
10270     }
10271
10272     free(*tng_data_p);
10273     *tng_data_p = 0;
10274
10275     return(TNG_SUCCESS);
10276 }
10277
10278 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
10279                                                  tng_trajectory_t *dest_p)
10280 {
10281     tng_trajectory_frame_set_t frame_set;
10282     tng_trajectory_t dest;
10283
10284     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
10285
10286     *dest_p = malloc(sizeof(struct tng_trajectory));
10287     if(!*dest_p)
10288     {
10289         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
10290                sizeof(struct tng_trajectory), __FILE__, __LINE__);
10291         return(TNG_CRITICAL);
10292     }
10293
10294     dest = *dest_p;
10295
10296     frame_set = &dest->current_trajectory_frame_set;
10297
10298     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
10299     if(!dest->input_file_path)
10300     {
10301         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10302                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
10303         return(TNG_CRITICAL);
10304     }
10305     strcpy(dest->input_file_path, src->input_file_path);
10306     dest->input_file = 0;
10307     dest->input_file_len = src->input_file_len;
10308     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
10309     if(!dest->output_file_path)
10310     {
10311         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10312                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
10313         return(TNG_CRITICAL);
10314     }
10315     strcpy(dest->output_file_path, src->output_file_path);
10316     dest->output_file = 0;
10317
10318     dest->first_program_name = 0;
10319     dest->first_user_name = 0;
10320     dest->first_computer_name = 0;
10321     dest->first_pgp_signature = 0;
10322     dest->last_program_name = 0;
10323     dest->last_user_name = 0;
10324     dest->last_computer_name = 0;
10325     dest->last_pgp_signature = 0;
10326     dest->forcefield_name = 0;
10327
10328     dest->var_num_atoms_flag = src->var_num_atoms_flag;
10329     dest->first_trajectory_frame_set_input_file_pos =
10330     src->first_trajectory_frame_set_input_file_pos;
10331     dest->last_trajectory_frame_set_input_file_pos =
10332     src->last_trajectory_frame_set_input_file_pos;
10333     dest->current_trajectory_frame_set_input_file_pos =
10334     src->current_trajectory_frame_set_input_file_pos;
10335     dest->first_trajectory_frame_set_output_file_pos =
10336     src->first_trajectory_frame_set_output_file_pos;
10337     dest->last_trajectory_frame_set_output_file_pos =
10338     src->last_trajectory_frame_set_output_file_pos;
10339     dest->current_trajectory_frame_set_output_file_pos =
10340     src->current_trajectory_frame_set_output_file_pos;
10341     dest->frame_set_n_frames = src->frame_set_n_frames;
10342     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
10343     dest->medium_stride_length = src->medium_stride_length;
10344     dest->long_stride_length = src->long_stride_length;
10345
10346     dest->time_per_frame = src->time_per_frame;
10347
10348     /* Currently the non trajectory data blocks are not copied since it
10349      * can lead to problems when freeing memory in a parallel block. */
10350     dest->n_particle_data_blocks = 0;
10351     dest->n_data_blocks = 0;
10352     dest->non_tr_particle_data = 0;
10353     dest->non_tr_data = 0;
10354
10355     dest->compress_algo_pos = 0;
10356     dest->compress_algo_vel = 0;
10357     dest->distance_unit_exponential = -9;
10358     dest->compression_precision = 1000;
10359
10360     frame_set->n_mapping_blocks = 0;
10361     frame_set->mappings = 0;
10362     frame_set->molecule_cnt_list = 0;
10363
10364     frame_set->n_particle_data_blocks = 0;
10365     frame_set->n_data_blocks = 0;
10366
10367     frame_set->tr_particle_data = 0;
10368     frame_set->tr_data = 0;
10369
10370     frame_set->next_frame_set_file_pos = -1;
10371     frame_set->prev_frame_set_file_pos = -1;
10372     frame_set->medium_stride_next_frame_set_file_pos = -1;
10373     frame_set->medium_stride_prev_frame_set_file_pos = -1;
10374     frame_set->long_stride_next_frame_set_file_pos = -1;
10375     frame_set->long_stride_prev_frame_set_file_pos = -1;
10376     frame_set->first_frame = -1;
10377
10378     dest->n_molecules = 0;
10379     dest->molecules = 0;
10380     dest->molecule_cnt_list = 0;
10381     dest->n_particles = src->n_particles;
10382
10383     dest->endianness_32 = src->endianness_32;
10384     dest->endianness_64 = src->endianness_64;
10385     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
10386     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
10387     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
10388     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
10389
10390     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
10391     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
10392     dest->current_trajectory_frame_set.n_frames = 0;
10393
10394     return(TNG_SUCCESS);
10395 }
10396
10397 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
10398                                        char *file_name, const int max_len)
10399 {
10400     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10401     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10402
10403     strncpy(file_name, tng_data->input_file_path, max_len - 1);
10404     file_name[max_len - 1] = 0;
10405
10406     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
10407     {
10408         return(TNG_FAILURE);
10409     }
10410     return(TNG_SUCCESS);
10411 }
10412
10413 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
10414                                                          const char *file_name)
10415 {
10416     unsigned int len;
10417     char *temp;
10418
10419     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10420     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10421
10422
10423     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
10424                                            file_name) == 0)
10425     {
10426         return(TNG_SUCCESS);
10427     }
10428
10429     if(tng_data->input_file)
10430     {
10431         fclose(tng_data->input_file);
10432     }
10433
10434     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10435     temp = realloc(tng_data->input_file_path, len);
10436     if(!temp)
10437     {
10438         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10439                __FILE__, __LINE__);
10440         free(tng_data->input_file_path);
10441         tng_data->input_file_path = 0;
10442         return(TNG_CRITICAL);
10443     }
10444     tng_data->input_file_path = temp;
10445
10446     strncpy(tng_data->input_file_path, file_name, len);
10447
10448     return(tng_input_file_init(tng_data));
10449 }
10450
10451 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
10452                                        char *file_name, const int max_len)
10453 {
10454     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10455     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10456
10457     strncpy(file_name, tng_data->output_file_path, max_len - 1);
10458     file_name[max_len - 1] = 0;
10459
10460     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
10461     {
10462         return(TNG_FAILURE);
10463     }
10464     return(TNG_SUCCESS);
10465 }
10466
10467 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
10468                                                           const char *file_name)
10469 {
10470     int len;
10471     char *temp;
10472
10473     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10474     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10475
10476     if(tng_data->output_file_path &&
10477        strcmp(tng_data->output_file_path, file_name) == 0)
10478     {
10479         return(TNG_SUCCESS);
10480     }
10481
10482     if(tng_data->output_file)
10483     {
10484         fclose(tng_data->output_file);
10485     }
10486
10487     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10488     temp = realloc(tng_data->output_file_path, len);
10489     if(!temp)
10490     {
10491         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10492                __FILE__, __LINE__);
10493         free(tng_data->output_file_path);
10494         tng_data->output_file_path = 0;
10495         return(TNG_CRITICAL);
10496     }
10497     tng_data->output_file_path = temp;
10498
10499     strncpy(tng_data->output_file_path, file_name, len);
10500
10501     return(tng_output_file_init(tng_data));
10502 }
10503
10504 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
10505                 (tng_trajectory_t tng_data,
10506                  const char *file_name)
10507 {
10508     int len;
10509     char *temp;
10510
10511     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10512     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10513
10514     if(tng_data->output_file_path &&
10515        strcmp(tng_data->output_file_path, file_name) == 0)
10516     {
10517         return(TNG_SUCCESS);
10518     }
10519
10520     if(tng_data->output_file)
10521     {
10522         fclose(tng_data->output_file);
10523     }
10524
10525     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10526     temp = realloc(tng_data->output_file_path, len);
10527     if(!temp)
10528     {
10529         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10530                __FILE__, __LINE__);
10531         free(tng_data->output_file_path);
10532         tng_data->output_file_path = 0;
10533         return(TNG_CRITICAL);
10534     }
10535     tng_data->output_file_path = temp;
10536
10537     strncpy(tng_data->output_file_path, file_name, len);
10538
10539     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
10540     if(!tng_data->output_file)
10541     {
10542         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
10543                 tng_data->output_file_path, __FILE__, __LINE__);
10544         return(TNG_CRITICAL);
10545     }
10546     tng_data->input_file = tng_data->output_file;
10547
10548     return(TNG_SUCCESS);
10549 }
10550
10551 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
10552                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
10553 {
10554     tng_endianness_32 end_32;
10555     tng_endianness_64 end_64;
10556
10557     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10558     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
10559
10560     if(tng_data->output_endianness_swap_func_32)
10561     {
10562         /* If other endianness variants are added they must be added here as well */
10563         if(tng_data->output_endianness_swap_func_32 ==
10564            &tng_swap_byte_order_big_endian_32)
10565         {
10566             end_32 = TNG_BIG_ENDIAN_32;
10567         }
10568         else if(tng_data->output_endianness_swap_func_32 ==
10569                 &tng_swap_byte_order_little_endian_32)
10570         {
10571             end_32 = TNG_LITTLE_ENDIAN_32;
10572         }
10573         else
10574         {
10575             return(TNG_FAILURE);
10576         }
10577     }
10578     else
10579     {
10580         end_32 = (tng_endianness_32)tng_data->endianness_32;
10581     }
10582
10583     if(tng_data->output_endianness_swap_func_64)
10584     {
10585         /* If other endianness variants are added they must be added here as well */
10586         if(tng_data->output_endianness_swap_func_64 ==
10587            &tng_swap_byte_order_big_endian_64)
10588         {
10589             end_64 = TNG_BIG_ENDIAN_64;
10590         }
10591         else if(tng_data->output_endianness_swap_func_64 ==
10592                 &tng_swap_byte_order_little_endian_64)
10593         {
10594             end_64 = TNG_LITTLE_ENDIAN_64;
10595         }
10596         else
10597         {
10598             return(TNG_FAILURE);
10599         }
10600     }
10601     else
10602     {
10603         end_64 = (tng_endianness_64)tng_data->endianness_64;
10604     }
10605
10606     if((int)end_32 != (int)end_64)
10607     {
10608         return(TNG_FAILURE);
10609     }
10610
10611     if(end_32 == TNG_LITTLE_ENDIAN_32)
10612     {
10613         *endianness = TNG_LITTLE_ENDIAN;
10614     }
10615
10616     else if(end_32 == TNG_BIG_ENDIAN_32)
10617     {
10618         *endianness = TNG_BIG_ENDIAN;
10619     }
10620     else
10621     {
10622         return(TNG_FAILURE);
10623     }
10624
10625     return(TNG_SUCCESS);
10626 }
10627
10628 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
10629                 (tng_trajectory_t tng_data,
10630                  const tng_file_endianness endianness)
10631 {
10632     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10633
10634     /* Tne endianness cannot be changed if the data has already been written
10635      * to the output file. */
10636     if(ftello(tng_data->output_file) > 0)
10637     {
10638         return(TNG_FAILURE);
10639     }
10640
10641     if(endianness == TNG_BIG_ENDIAN)
10642     {
10643         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
10644         {
10645             tng_data->output_endianness_swap_func_32 = 0;
10646         }
10647         else
10648         {
10649             tng_data->output_endianness_swap_func_32 =
10650             &tng_swap_byte_order_big_endian_32;
10651         }
10652         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10653         {
10654             tng_data->output_endianness_swap_func_64 = 0;
10655         }
10656         else
10657         {
10658             tng_data->output_endianness_swap_func_64 =
10659             &tng_swap_byte_order_big_endian_64;
10660         }
10661         return(TNG_SUCCESS);
10662     }
10663     else if(endianness == TNG_LITTLE_ENDIAN)
10664     {
10665         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10666         {
10667             tng_data->output_endianness_swap_func_32 = 0;
10668         }
10669         else
10670         {
10671             tng_data->output_endianness_swap_func_32 =
10672             &tng_swap_byte_order_little_endian_32;
10673         }
10674         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10675         {
10676             tng_data->output_endianness_swap_func_64 = 0;
10677         }
10678         else
10679         {
10680             tng_data->output_endianness_swap_func_64 =
10681             &tng_swap_byte_order_little_endian_64;
10682         }
10683         return(TNG_SUCCESS);
10684     }
10685
10686     /* If the specified endianness is neither big nor little endian return a
10687      * failure. */
10688     return(TNG_FAILURE);
10689 }
10690
10691 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10692                     (const tng_trajectory_t tng_data,
10693                      char *name, const int max_len)
10694 {
10695     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10696     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10697
10698     strncpy(name, tng_data->first_program_name, max_len - 1);
10699     name[max_len - 1] = 0;
10700
10701     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10702     {
10703         return(TNG_FAILURE);
10704     }
10705     return(TNG_SUCCESS);
10706 }
10707
10708 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10709                                                                  const char *new_name)
10710 {
10711     unsigned int len;
10712
10713     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10714     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10715
10716     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10717
10718     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10719     {
10720         free(tng_data->first_program_name);
10721         tng_data->first_program_name = 0;
10722     }
10723     if(!tng_data->first_program_name)
10724     {
10725         tng_data->first_program_name = malloc(len);
10726         if(!tng_data->first_program_name)
10727         {
10728             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10729                    __FILE__, __LINE__);
10730             return(TNG_CRITICAL);
10731         }
10732     }
10733
10734     strncpy(tng_data->first_program_name, new_name, len);
10735
10736     return(TNG_SUCCESS);
10737 }
10738
10739 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10740                     (const tng_trajectory_t tng_data,
10741                      char *name, const int max_len)
10742 {
10743     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10744     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10745
10746     strncpy(name, tng_data->last_program_name, max_len - 1);
10747     name[max_len - 1] = 0;
10748
10749     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10750     {
10751         return(TNG_FAILURE);
10752     }
10753     return(TNG_SUCCESS);
10754 }
10755
10756 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10757                     (tng_trajectory_t tng_data,
10758                      const char *new_name)
10759 {
10760     unsigned int len;
10761
10762     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10763     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10764
10765     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10766
10767     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10768     {
10769         free(tng_data->last_program_name);
10770         tng_data->last_program_name = 0;
10771     }
10772     if(!tng_data->last_program_name)
10773     {
10774         tng_data->last_program_name = malloc(len);
10775         if(!tng_data->last_program_name)
10776         {
10777             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10778                    __FILE__, __LINE__);
10779             return(TNG_CRITICAL);
10780         }
10781     }
10782
10783     strncpy(tng_data->last_program_name, new_name, len);
10784
10785     return(TNG_SUCCESS);
10786 }
10787
10788 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10789                     (const tng_trajectory_t tng_data,
10790                      char *name, const int max_len)
10791 {
10792     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10793     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10794
10795     strncpy(name, tng_data->first_user_name, max_len - 1);
10796     name[max_len - 1] = 0;
10797
10798     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10799     {
10800         return(TNG_FAILURE);
10801     }
10802     return(TNG_SUCCESS);
10803 }
10804
10805 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10806                     (tng_trajectory_t tng_data,
10807                      const char *new_name)
10808 {
10809     unsigned int len;
10810
10811     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10812     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10813
10814     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10815
10816     /* If the currently stored string length is not enough to store the new
10817      * string it is freed and reallocated. */
10818     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10819     {
10820         free(tng_data->first_user_name);
10821         tng_data->first_user_name = 0;
10822     }
10823     if(!tng_data->first_user_name)
10824     {
10825         tng_data->first_user_name = malloc(len);
10826         if(!tng_data->first_user_name)
10827         {
10828             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10829                    __FILE__, __LINE__);
10830             return(TNG_CRITICAL);
10831         }
10832     }
10833
10834     strncpy(tng_data->first_user_name, new_name, len);
10835
10836     return(TNG_SUCCESS);
10837 }
10838
10839 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10840                     (const tng_trajectory_t tng_data,
10841                      char *name, const int max_len)
10842 {
10843     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10844     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10845
10846     strncpy(name, tng_data->last_user_name, max_len - 1);
10847     name[max_len - 1] = 0;
10848
10849     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10850     {
10851         return(TNG_FAILURE);
10852     }
10853     return(TNG_SUCCESS);
10854 }
10855
10856 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10857                     (tng_trajectory_t tng_data,
10858                      const char *new_name)
10859 {
10860     unsigned int len;
10861
10862     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10863     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10864
10865     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10866
10867     /* If the currently stored string length is not enough to store the new
10868      * string it is freed and reallocated. */
10869     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10870     {
10871         free(tng_data->last_user_name);
10872         tng_data->last_user_name = 0;
10873     }
10874     if(!tng_data->last_user_name)
10875     {
10876         tng_data->last_user_name = malloc(len);
10877         if(!tng_data->last_user_name)
10878         {
10879             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10880                    __FILE__, __LINE__);
10881             return(TNG_CRITICAL);
10882         }
10883     }
10884
10885     strncpy(tng_data->last_user_name, new_name, len);
10886
10887     return(TNG_SUCCESS);
10888 }
10889
10890 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10891                     (const tng_trajectory_t tng_data,
10892                      char *name, const int max_len)
10893 {
10894     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10895     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10896
10897     strncpy(name, tng_data->first_computer_name, max_len - 1);
10898     name[max_len - 1] = 0;
10899
10900     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10901     {
10902         return(TNG_FAILURE);
10903     }
10904     return(TNG_SUCCESS);
10905 }
10906
10907 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10908                     (tng_trajectory_t tng_data,
10909                      const char *new_name)
10910 {
10911     unsigned int len;
10912
10913     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10914     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10915
10916     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10917
10918     /* If the currently stored string length is not enough to store the new
10919      * string it is freed and reallocated. */
10920     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10921     {
10922         free(tng_data->first_computer_name);
10923         tng_data->first_computer_name = 0;
10924     }
10925     if(!tng_data->first_computer_name)
10926     {
10927         tng_data->first_computer_name = malloc(len);
10928         if(!tng_data->first_computer_name)
10929         {
10930             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10931                    __FILE__, __LINE__);
10932             return(TNG_CRITICAL);
10933         }
10934     }
10935
10936     strncpy(tng_data->first_computer_name, new_name, len);
10937
10938     return(TNG_SUCCESS);
10939 }
10940
10941 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10942                     (const tng_trajectory_t tng_data,
10943                      char *name, const int max_len)
10944 {
10945     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10946     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10947
10948     strncpy(name, tng_data->last_computer_name, max_len - 1);
10949     name[max_len - 1] = 0;
10950
10951     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10952     {
10953         return(TNG_FAILURE);
10954     }
10955     return(TNG_SUCCESS);
10956 }
10957
10958 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10959                     (tng_trajectory_t tng_data,
10960                      const char *new_name)
10961 {
10962     unsigned int len;
10963
10964     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10965     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10966
10967     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10968
10969     /* If the currently stored string length is not enough to store the new
10970      * string it is freed and reallocated. */
10971     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
10972         len)
10973     {
10974         free(tng_data->last_computer_name);
10975         tng_data->last_computer_name = 0;
10976     }
10977     if(!tng_data->last_computer_name)
10978     {
10979         tng_data->last_computer_name = malloc(len);
10980         if(!tng_data->last_computer_name)
10981         {
10982             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10983                    __FILE__, __LINE__);
10984             return(TNG_CRITICAL);
10985         }
10986     }
10987
10988     strncpy(tng_data->last_computer_name, new_name, len);
10989
10990     return(TNG_SUCCESS);
10991 }
10992
10993 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
10994                     (const tng_trajectory_t tng_data,
10995                      char *signature, const int max_len)
10996 {
10997     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10998     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10999
11000     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
11001     signature[max_len - 1] = 0;
11002
11003     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
11004     {
11005         return(TNG_FAILURE);
11006     }
11007     return(TNG_SUCCESS);
11008 }
11009
11010 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
11011                     (tng_trajectory_t tng_data,
11012                      const char *signature)
11013 {
11014     unsigned int len;
11015
11016     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11017     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11018
11019     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11020
11021     /* If the currently stored string length is not enough to store the new
11022      * string it is freed and reallocated. */
11023     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
11024         len)
11025     {
11026         free(tng_data->first_pgp_signature);
11027         tng_data->first_pgp_signature = 0;
11028     }
11029     if(!tng_data->first_pgp_signature)
11030     {
11031         tng_data->first_pgp_signature = malloc(len);
11032         if(!tng_data->first_pgp_signature)
11033         {
11034             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11035                    __FILE__, __LINE__);
11036             return(TNG_CRITICAL);
11037         }
11038     }
11039
11040     strncpy(tng_data->first_pgp_signature, signature, len);
11041
11042     return(TNG_SUCCESS);
11043 }
11044
11045 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
11046                     (const tng_trajectory_t tng_data,
11047                      char *signature, const int max_len)
11048 {
11049     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11050     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11051
11052     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
11053     signature[max_len - 1] = 0;
11054
11055     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
11056     {
11057         return(TNG_FAILURE);
11058     }
11059     return(TNG_SUCCESS);
11060 }
11061
11062 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
11063                     (tng_trajectory_t tng_data,
11064                      const char *signature)
11065 {
11066     unsigned int len;
11067
11068     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11069     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11070
11071     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11072
11073     /* If the currently stored string length is not enough to store the new
11074      * string it is freed and reallocated. */
11075     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
11076         len)
11077     {
11078         free(tng_data->last_pgp_signature);
11079         tng_data->last_pgp_signature = 0;
11080     }
11081     if(!tng_data->last_pgp_signature)
11082     {
11083         tng_data->last_pgp_signature = malloc(len);
11084         if(!tng_data->last_pgp_signature)
11085         {
11086             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11087                    __FILE__, __LINE__);
11088             return(TNG_CRITICAL);
11089         }
11090     }
11091
11092     strncpy(tng_data->last_pgp_signature, signature, len);
11093
11094     return(TNG_SUCCESS);
11095 }
11096
11097 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
11098                     (const tng_trajectory_t tng_data,
11099                      char *name, const int max_len)
11100 {
11101     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11102     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
11103
11104     strncpy(name, tng_data->forcefield_name, max_len - 1);
11105     name[max_len - 1] = 0;
11106
11107     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
11108     {
11109         return(TNG_FAILURE);
11110     }
11111     return(TNG_SUCCESS);
11112 }
11113
11114 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
11115                     (tng_trajectory_t tng_data,
11116                      const char *new_name)
11117 {
11118     unsigned int len;
11119
11120     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11121     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
11122
11123     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11124
11125     /* If the currently stored string length is not enough to store the new
11126      * string it is freed and reallocated. */
11127     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
11128     {
11129         free(tng_data->forcefield_name);
11130         tng_data->forcefield_name = 0;
11131     }
11132     if(!tng_data->forcefield_name)
11133     {
11134         tng_data->forcefield_name = malloc(len);
11135         if(!tng_data->forcefield_name)
11136         {
11137             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11138                    __FILE__, __LINE__);
11139             return(TNG_CRITICAL);
11140         }
11141     }
11142
11143     strncpy(tng_data->forcefield_name, new_name, len);
11144
11145     return(TNG_SUCCESS);
11146 }
11147
11148 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
11149                     (const tng_trajectory_t tng_data,
11150                      int64_t *len)
11151 {
11152     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11153     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11154
11155     *len = tng_data->medium_stride_length;
11156
11157     return(TNG_SUCCESS);
11158 }
11159
11160 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
11161                     (tng_trajectory_t tng_data,
11162                      const int64_t len)
11163 {
11164     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11165
11166     if(len >= tng_data->long_stride_length)
11167     {
11168         return(TNG_FAILURE);
11169     }
11170     tng_data->medium_stride_length = len;
11171
11172     return(TNG_SUCCESS);
11173 }
11174
11175 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
11176                 (const tng_trajectory_t tng_data,
11177                  int64_t *len)
11178 {
11179     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11180     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11181
11182     *len = tng_data->long_stride_length;
11183
11184     return(TNG_SUCCESS);
11185 }
11186
11187 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
11188                 (tng_trajectory_t tng_data,
11189                  const int64_t len)
11190 {
11191     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11192
11193     if(len <= tng_data->medium_stride_length)
11194     {
11195         return(TNG_FAILURE);
11196     }
11197     tng_data->long_stride_length = len;
11198
11199     return(TNG_SUCCESS);
11200 }
11201
11202 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
11203                 (const tng_trajectory_t tng_data,
11204                  double *time)
11205 {
11206     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11207     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
11208
11209     *time = tng_data->time_per_frame;
11210
11211     return(TNG_SUCCESS);
11212 }
11213
11214 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
11215                 (tng_trajectory_t tng_data,
11216                  const double time)
11217 {
11218     tng_trajectory_frame_set_t frame_set;
11219
11220     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11221     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
11222
11223     if(fabs(time - tng_data->time_per_frame) < 0.00001)
11224     {
11225         return(TNG_SUCCESS);
11226     }
11227
11228     frame_set = &tng_data->current_trajectory_frame_set;
11229
11230     /* If the current frame set is not finished write it to disk before
11231        changing time per frame. */
11232     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
11233     {
11234         frame_set->n_frames = frame_set->n_unwritten_frames;
11235         tng_frame_set_write(tng_data, TNG_USE_HASH);
11236     }
11237     tng_data->time_per_frame = time;
11238
11239     return(TNG_SUCCESS);
11240 }
11241
11242 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
11243                     (const tng_trajectory_t tng_data,
11244                      int64_t *len)
11245 {
11246     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11247     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11248
11249     *len = tng_data->input_file_len;
11250
11251     return(TNG_SUCCESS);
11252 }
11253
11254 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
11255                     (const tng_trajectory_t tng_data,
11256                      int64_t *n)
11257 {
11258     tng_gen_block_t block;
11259     tng_function_status stat;
11260     int64_t file_pos, last_file_pos, first_frame, n_frames;
11261
11262     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11263     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
11264     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11265
11266     file_pos = ftello(tng_data->input_file);
11267     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11268
11269     if(last_file_pos <= 0)
11270     {
11271         return(TNG_FAILURE);
11272     }
11273
11274     tng_block_init(&block);
11275     fseeko(tng_data->input_file,
11276            last_file_pos,
11277            SEEK_SET);
11278     /* Read block headers first to see that a frame set block is found. */
11279     stat = tng_block_header_read(tng_data, block);
11280     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11281     {
11282         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
11283                 __FILE__, __LINE__);
11284         tng_block_destroy(&block);
11285         return(TNG_FAILURE);
11286     }
11287     tng_block_destroy(&block);
11288
11289     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
11290     {
11291         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
11292                __FILE__, __LINE__);
11293         return(TNG_CRITICAL);
11294     }
11295     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
11296     {
11297         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
11298                __FILE__, __LINE__);
11299         return(TNG_CRITICAL);
11300     }
11301     fseeko(tng_data->input_file, file_pos, SEEK_SET);
11302
11303     *n = first_frame + n_frames;
11304
11305     return(TNG_SUCCESS);
11306 }
11307
11308 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
11309                 (const tng_trajectory_t tng_data,
11310                  double *precision)
11311 {
11312     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11313
11314     *precision = tng_data->compression_precision;
11315
11316     return(TNG_SUCCESS);
11317 }
11318
11319 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
11320                 (tng_trajectory_t tng_data,
11321                  const double precision)
11322 {
11323     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11324
11325     tng_data->compression_precision = precision;
11326
11327     return(TNG_SUCCESS);
11328 }
11329
11330 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
11331                 (tng_trajectory_t tng_data,
11332                  const int64_t n)
11333 {
11334     tng_molecule_t mol;
11335     tng_chain_t chain;
11336     tng_residue_t res;
11337     tng_atom_t atom;
11338     tng_function_status stat;
11339     int64_t diff, n_mod, n_impl;
11340
11341     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
11342
11343     diff = n - tng_data->n_particles;
11344
11345     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
11346     if(stat == TNG_SUCCESS)
11347     {
11348         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
11349         {
11350             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
11351                     __FILE__, __LINE__);
11352             return(TNG_FAILURE);
11353         }
11354         diff -= n_impl * mol->n_atoms;
11355     }
11356
11357     if(diff == 0)
11358     {
11359         if(stat == TNG_SUCCESS)
11360         {
11361             stat = tng_molecule_cnt_set(tng_data, mol, 0);
11362             return(stat);
11363         }
11364         return(TNG_SUCCESS);
11365     }
11366     else if(diff < 0)
11367     {
11368         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
11369         fprintf(stderr, "particle count.\n");
11370         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11371                 __FILE__, __LINE__);
11372         /* FIXME: Should we set the count of all other molecules to 0 and add
11373          * implicit molecules? */
11374         return(TNG_FAILURE);
11375     }
11376     if(stat != TNG_SUCCESS)
11377     {
11378         stat = tng_molecule_add(tng_data,
11379                                 "TNG_IMPLICIT_MOL",
11380                                 &mol);
11381         if(stat != TNG_SUCCESS)
11382         {
11383             return(stat);
11384         }
11385         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
11386         if(stat != TNG_SUCCESS)
11387         {
11388             return(stat);
11389         }
11390         stat = tng_chain_residue_add(tng_data, chain, "", &res);
11391         if(stat != TNG_SUCCESS)
11392         {
11393             return(stat);
11394         }
11395         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
11396         if(stat != TNG_SUCCESS)
11397         {
11398             return(stat);
11399         }
11400     }
11401     else
11402     {
11403         if(mol->n_atoms > 1)
11404         {
11405             n_mod = diff % mol->n_atoms;
11406             if(n_mod != 0)
11407             {
11408                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
11409                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
11410                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11411                         __FILE__, __LINE__);
11412                 return(TNG_FAILURE);
11413             }
11414             diff /= mol->n_atoms;
11415         }
11416     }
11417     stat = tng_molecule_cnt_set(tng_data, mol, diff);
11418
11419     return(stat);
11420 }
11421
11422 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
11423                 (const tng_trajectory_t tng_data,
11424                  int64_t *n)
11425 {
11426     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11427     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11428
11429     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
11430     {
11431         *n = tng_data->n_particles;
11432     }
11433     else
11434     {
11435         *n = tng_data->current_trajectory_frame_set.n_particles;
11436     }
11437
11438     return(TNG_SUCCESS);
11439 }
11440
11441 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
11442                 (const tng_trajectory_t tng_data,
11443                  char *variable)
11444 {
11445     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11446     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
11447
11448     *variable = tng_data->var_num_atoms_flag;
11449
11450     return(TNG_SUCCESS);
11451 }
11452
11453 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
11454                     (const tng_trajectory_t tng_data,
11455                      int64_t *n)
11456 {
11457     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11458     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11459
11460     *n = tng_data->n_molecules;
11461
11462     return(TNG_SUCCESS);
11463 }
11464
11465 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
11466                     (const tng_trajectory_t tng_data,
11467                      int64_t *n)
11468 {
11469     int64_t *cnt_list = 0, cnt = 0, i;
11470
11471     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11472     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11473
11474     tng_molecule_cnt_list_get(tng_data, &cnt_list);
11475
11476     if(!cnt_list)
11477     {
11478         return(TNG_FAILURE);
11479     }
11480
11481     for(i = 0; i < tng_data->n_molecules; i++)
11482     {
11483         cnt += cnt_list[i];
11484     }
11485
11486     *n = cnt;
11487
11488     return(TNG_SUCCESS);
11489 }
11490
11491 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
11492                 (const tng_trajectory_t tng_data,
11493                  int64_t **mol_cnt_list)
11494 {
11495     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11496
11497     if(tng_data->var_num_atoms_flag)
11498     {
11499         *mol_cnt_list = tng_data->current_trajectory_frame_set.
11500                        molecule_cnt_list;
11501     }
11502     else
11503     {
11504         *mol_cnt_list = tng_data->molecule_cnt_list;
11505     }
11506     if(*mol_cnt_list == 0)
11507     {
11508         return(TNG_FAILURE);
11509     }
11510     return(TNG_SUCCESS);
11511 }
11512
11513 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
11514                 (const tng_trajectory_t tng_data,
11515                  int64_t *exp)
11516 {
11517     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11518     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
11519
11520     *exp = tng_data->distance_unit_exponential;
11521
11522     return(TNG_SUCCESS);
11523 }
11524
11525 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
11526                 (const tng_trajectory_t tng_data,
11527                  const int64_t exp)
11528 {
11529     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11530
11531     tng_data->distance_unit_exponential = exp;
11532
11533     return(TNG_SUCCESS);
11534 }
11535
11536 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
11537                 (const tng_trajectory_t tng_data,
11538                  int64_t *n)
11539 {
11540     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11541     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11542
11543     *n = tng_data->frame_set_n_frames;
11544
11545     return(TNG_SUCCESS);
11546 }
11547
11548 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
11549                 (const tng_trajectory_t tng_data,
11550                  const int64_t n)
11551 {
11552     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11553
11554     tng_data->frame_set_n_frames = n;
11555
11556     return(TNG_SUCCESS);
11557 }
11558
11559 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
11560                 (const tng_trajectory_t tng_data,
11561                  int64_t *n)
11562 {
11563     int64_t long_stride_length, medium_stride_length;
11564     int64_t file_pos, orig_frame_set_file_pos;
11565     tng_trajectory_frame_set_t frame_set;
11566     struct tng_trajectory_frame_set orig_frame_set;
11567     tng_gen_block_t block;
11568     tng_function_status stat;
11569     int64_t cnt = 0;
11570
11571     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11572     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11573
11574     orig_frame_set = tng_data->current_trajectory_frame_set;
11575
11576     frame_set = &tng_data->current_trajectory_frame_set;
11577
11578     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11579     file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11580
11581     if(file_pos < 0)
11582     {
11583         *n = tng_data->n_trajectory_frame_sets = cnt;
11584         return(TNG_SUCCESS);
11585     }
11586
11587     tng_block_init(&block);
11588     fseeko(tng_data->input_file,
11589           file_pos,
11590           SEEK_SET);
11591     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11592     /* Read block headers first to see what block is found. */
11593     stat = tng_block_header_read(tng_data, block);
11594     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11595     {
11596         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11597                 __FILE__, __LINE__);
11598         tng_block_destroy(&block);
11599         return(TNG_CRITICAL);
11600     }
11601
11602     if(tng_block_read_next(tng_data, block,
11603                         TNG_SKIP_HASH) != TNG_SUCCESS)
11604     {
11605         tng_block_destroy(&block);
11606         return(TNG_CRITICAL);
11607     }
11608
11609     ++cnt;
11610
11611     long_stride_length = tng_data->long_stride_length;
11612     medium_stride_length = tng_data->medium_stride_length;
11613
11614     /* Take long steps forward until a long step forward would be too long or
11615      * the last frame set is found */
11616     file_pos = frame_set->long_stride_next_frame_set_file_pos;
11617     while(file_pos > 0)
11618     {
11619         if(file_pos > 0)
11620         {
11621             cnt += long_stride_length;
11622             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11623             /* Read block headers first to see what block is found. */
11624             stat = tng_block_header_read(tng_data, block);
11625             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11626             {
11627                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11628                        file_pos, __FILE__, __LINE__);
11629                 tng_block_destroy(&block);
11630                 return(TNG_CRITICAL);
11631             }
11632
11633             if(tng_block_read_next(tng_data, block,
11634                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11635             {
11636                 tng_block_destroy(&block);
11637                 return(TNG_CRITICAL);
11638             }
11639         }
11640         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11641     }
11642
11643     /* Take medium steps forward until a medium step forward would be too long
11644      * or the last frame set is found */
11645     file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11646     while(file_pos > 0)
11647     {
11648         if(file_pos > 0)
11649         {
11650             cnt += medium_stride_length;
11651             fseeko(tng_data->input_file,
11652                   file_pos,
11653                   SEEK_SET);
11654             /* Read block headers first to see what block is found. */
11655             stat = tng_block_header_read(tng_data, block);
11656             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11657             {
11658                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11659                        file_pos, __FILE__, __LINE__);
11660                 tng_block_destroy(&block);
11661                 return(TNG_CRITICAL);
11662             }
11663
11664             if(tng_block_read_next(tng_data, block,
11665                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11666             {
11667                 tng_block_destroy(&block);
11668                 return(TNG_CRITICAL);
11669             }
11670         }
11671         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11672     }
11673
11674     /* Take one step forward until the last frame set is found */
11675     file_pos = frame_set->next_frame_set_file_pos;
11676     while(file_pos > 0)
11677     {
11678         if(file_pos > 0)
11679         {
11680             ++cnt;
11681             fseeko(tng_data->input_file,
11682                   file_pos,
11683                   SEEK_SET);
11684             /* Read block headers first to see what block is found. */
11685             stat = tng_block_header_read(tng_data, block);
11686             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11687             {
11688                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11689                        file_pos, __FILE__, __LINE__);
11690                 tng_block_destroy(&block);
11691                 return(TNG_CRITICAL);
11692             }
11693
11694             if(tng_block_read_next(tng_data, block,
11695                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11696             {
11697                 tng_block_destroy(&block);
11698                 return(TNG_CRITICAL);
11699             }
11700         }
11701         file_pos = frame_set->next_frame_set_file_pos;
11702     }
11703
11704     tng_block_destroy(&block);
11705
11706     *n = tng_data->n_trajectory_frame_sets = cnt;
11707
11708     *frame_set = orig_frame_set;
11709     /* The mapping block in the original frame set has been freed when reading
11710      * other frame sets. */
11711     frame_set->mappings = 0;
11712     frame_set->n_mapping_blocks = 0;
11713
11714     fseeko(tng_data->input_file,
11715            tng_data->first_trajectory_frame_set_input_file_pos,
11716            SEEK_SET);
11717
11718     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11719
11720     return(TNG_SUCCESS);
11721 }
11722
11723 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11724                 (const tng_trajectory_t tng_data,
11725                  tng_trajectory_frame_set_t *frame_set_p)
11726 {
11727     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11728
11729     *frame_set_p = &tng_data->current_trajectory_frame_set;
11730
11731     return(TNG_SUCCESS);
11732 }
11733
11734 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11735                 (tng_trajectory_t tng_data,
11736                  const int64_t nr)
11737 {
11738     int64_t long_stride_length, medium_stride_length;
11739     int64_t file_pos, curr_nr = 0, n_frame_sets;
11740     tng_trajectory_frame_set_t frame_set;
11741     tng_gen_block_t block;
11742     tng_function_status stat;
11743
11744     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11745     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11746
11747     frame_set = &tng_data->current_trajectory_frame_set;
11748
11749     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11750
11751     if(stat != TNG_SUCCESS)
11752     {
11753         return(stat);
11754     }
11755
11756     if(nr >= n_frame_sets)
11757     {
11758         return(TNG_FAILURE);
11759     }
11760
11761     long_stride_length = tng_data->long_stride_length;
11762     medium_stride_length = tng_data->medium_stride_length;
11763
11764     /* FIXME: The frame set number of the current frame set is not stored */
11765
11766     if(nr < n_frame_sets - 1 - nr)
11767     {
11768         /* Start from the beginning */
11769         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11770     }
11771     else
11772     {
11773         /* Start from the end */
11774         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11775         curr_nr = n_frame_sets - 1;
11776     }
11777     if(file_pos <= 0)
11778     {
11779         return(TNG_FAILURE);
11780     }
11781
11782     tng_block_init(&block);
11783     fseeko(tng_data->input_file,
11784            file_pos,
11785            SEEK_SET);
11786     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11787     /* Read block headers first to see what block is found. */
11788     stat = tng_block_header_read(tng_data, block);
11789     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11790     {
11791         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11792                 __FILE__, __LINE__);
11793         tng_block_destroy(&block);
11794         return(TNG_CRITICAL);
11795     }
11796
11797     if(tng_block_read_next(tng_data, block,
11798                         TNG_SKIP_HASH) != TNG_SUCCESS)
11799     {
11800         tng_block_destroy(&block);
11801         return(TNG_CRITICAL);
11802     }
11803
11804     if(curr_nr == nr)
11805     {
11806         tng_block_destroy(&block);
11807         return(TNG_SUCCESS);
11808     }
11809
11810     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11811
11812     /* Take long steps forward until a long step forward would be too long or
11813      * the right frame set is found */
11814     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11815     {
11816         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11817         if(file_pos > 0)
11818         {
11819             curr_nr += long_stride_length;
11820             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11821             /* Read block headers first to see what block is found. */
11822             stat = tng_block_header_read(tng_data, block);
11823             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11824             {
11825                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11826                        file_pos,  __FILE__, __LINE__);
11827                 tng_block_destroy(&block);
11828                 return(TNG_CRITICAL);
11829             }
11830
11831             if(tng_block_read_next(tng_data, block,
11832                                    TNG_SKIP_HASH) != TNG_SUCCESS)
11833             {
11834                 tng_block_destroy(&block);
11835                 return(TNG_CRITICAL);
11836             }
11837             if(curr_nr == nr)
11838             {
11839                 tng_block_destroy(&block);
11840                 return(TNG_SUCCESS);
11841             }
11842         }
11843     }
11844
11845     /* Take medium steps forward until a medium step forward would be too long
11846      * or the right frame set is found */
11847     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11848     {
11849         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11850         if(file_pos > 0)
11851         {
11852             curr_nr += medium_stride_length;
11853             fseeko(tng_data->input_file,
11854                    file_pos,
11855                    SEEK_SET);
11856             /* Read block headers first to see what block is found. */
11857             stat = tng_block_header_read(tng_data, block);
11858             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11859             {
11860                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11861                        file_pos, __FILE__, __LINE__);
11862                 tng_block_destroy(&block);
11863                 return(TNG_CRITICAL);
11864             }
11865
11866             if(tng_block_read_next(tng_data, block,
11867                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11868             {
11869                 tng_block_destroy(&block);
11870                 return(TNG_CRITICAL);
11871             }
11872             if(curr_nr == nr)
11873             {
11874                 tng_block_destroy(&block);
11875                 return(TNG_SUCCESS);
11876             }
11877         }
11878     }
11879
11880     /* Take one step forward until the right frame set is found */
11881     while(file_pos > 0 && curr_nr < nr)
11882     {
11883         file_pos = frame_set->next_frame_set_file_pos;
11884
11885         if(file_pos > 0)
11886         {
11887             ++curr_nr;
11888             fseeko(tng_data->input_file,
11889                    file_pos,
11890                    SEEK_SET);
11891             /* Read block headers first to see what block is found. */
11892             stat = tng_block_header_read(tng_data, block);
11893             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11894             {
11895                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11896                        file_pos, __FILE__, __LINE__);
11897                 tng_block_destroy(&block);
11898                 return(TNG_CRITICAL);
11899             }
11900
11901             if(tng_block_read_next(tng_data, block,
11902                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11903             {
11904                 tng_block_destroy(&block);
11905                 return(TNG_CRITICAL);
11906             }
11907             if(curr_nr == nr)
11908             {
11909                 tng_block_destroy(&block);
11910                 return(TNG_SUCCESS);
11911             }
11912         }
11913     }
11914
11915     /* Take long steps backward until a long step backward would be too long
11916      * or the right frame set is found */
11917     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11918     {
11919         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11920         if(file_pos > 0)
11921         {
11922             curr_nr -= long_stride_length;
11923             fseeko(tng_data->input_file,
11924                    file_pos,
11925                    SEEK_SET);
11926             /* Read block headers first to see what block is found. */
11927             stat = tng_block_header_read(tng_data, block);
11928             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11929             {
11930                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11931                        file_pos, __FILE__, __LINE__);
11932                 tng_block_destroy(&block);
11933                 return(TNG_CRITICAL);
11934             }
11935
11936             if(tng_block_read_next(tng_data, block,
11937                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11938             {
11939                 tng_block_destroy(&block);
11940                 return(TNG_CRITICAL);
11941             }
11942             if(curr_nr == nr)
11943             {
11944                 tng_block_destroy(&block);
11945                 return(TNG_SUCCESS);
11946             }
11947         }
11948     }
11949
11950     /* Take medium steps backward until a medium step backward would be too long
11951      * or the right frame set is found */
11952     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11953     {
11954         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11955         if(file_pos > 0)
11956         {
11957             curr_nr -= medium_stride_length;
11958             fseeko(tng_data->input_file,
11959                    file_pos,
11960                    SEEK_SET);
11961             /* Read block headers first to see what block is found. */
11962             stat = tng_block_header_read(tng_data, block);
11963             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11964             {
11965                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11966                        file_pos, __FILE__, __LINE__);
11967                 tng_block_destroy(&block);
11968                 return(TNG_CRITICAL);
11969             }
11970
11971             if(tng_block_read_next(tng_data, block,
11972                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11973             {
11974                 tng_block_destroy(&block);
11975                 return(TNG_CRITICAL);
11976             }
11977             if(curr_nr == nr)
11978             {
11979                 tng_block_destroy(&block);
11980                 return(TNG_SUCCESS);
11981             }
11982         }
11983     }
11984
11985     /* Take one step backward until the right frame set is found */
11986     while(file_pos > 0 && curr_nr > nr)
11987     {
11988         file_pos = frame_set->prev_frame_set_file_pos;
11989         if(file_pos > 0)
11990         {
11991             --curr_nr;
11992             fseeko(tng_data->input_file,
11993                    file_pos,
11994                    SEEK_SET);
11995             /* Read block headers first to see what block is found. */
11996             stat = tng_block_header_read(tng_data, block);
11997             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11998             {
11999                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12000                        file_pos, __FILE__, __LINE__);
12001                 tng_block_destroy(&block);
12002                 return(TNG_CRITICAL);
12003             }
12004
12005             if(tng_block_read_next(tng_data, block,
12006                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12007             {
12008                 tng_block_destroy(&block);
12009                 return(TNG_CRITICAL);
12010             }
12011             if(curr_nr == nr)
12012             {
12013                 tng_block_destroy(&block);
12014                 return(TNG_SUCCESS);
12015             }
12016         }
12017     }
12018
12019     /* If for some reason the current frame set is not yet found,
12020      * take one step forward until the right frame set is found */
12021     while(file_pos > 0 && curr_nr < nr)
12022     {
12023         file_pos = frame_set->next_frame_set_file_pos;
12024         if(file_pos > 0)
12025         {
12026             ++curr_nr;
12027             fseeko(tng_data->input_file,
12028                    file_pos,
12029                    SEEK_SET);
12030             /* Read block headers first to see what block is found. */
12031             stat = tng_block_header_read(tng_data, block);
12032             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12033             {
12034                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12035                        file_pos, __FILE__, __LINE__);
12036                 tng_block_destroy(&block);
12037                 return(TNG_CRITICAL);
12038             }
12039
12040             if(tng_block_read_next(tng_data, block,
12041                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12042             {
12043                 tng_block_destroy(&block);
12044                 return(TNG_CRITICAL);
12045             }
12046             if(curr_nr == nr)
12047             {
12048                 tng_block_destroy(&block);
12049                 return(TNG_SUCCESS);
12050             }
12051         }
12052     }
12053
12054     tng_block_destroy(&block);
12055     return(TNG_FAILURE);
12056 }
12057
12058 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
12059                 (tng_trajectory_t tng_data,
12060                  const int64_t frame)
12061 {
12062     int64_t first_frame, last_frame, n_frames_per_frame_set;
12063     int64_t long_stride_length, medium_stride_length;
12064     int64_t file_pos, temp_frame, n_frames;
12065     tng_trajectory_frame_set_t frame_set;
12066     tng_gen_block_t block;
12067     tng_function_status stat;
12068
12069     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12070     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
12071
12072     frame_set = &tng_data->current_trajectory_frame_set;
12073
12074     tng_block_init(&block);
12075
12076     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
12077     {
12078         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12079         fseeko(tng_data->input_file,
12080                file_pos,
12081                SEEK_SET);
12082         tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12083         /* Read block headers first to see what block is found. */
12084         stat = tng_block_header_read(tng_data, block);
12085         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12086         {
12087             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12088                     file_pos, __FILE__, __LINE__);
12089             tng_block_destroy(&block);
12090             return(TNG_CRITICAL);
12091         }
12092
12093         if(tng_block_read_next(tng_data, block,
12094                             TNG_SKIP_HASH) != TNG_SUCCESS)
12095         {
12096             tng_block_destroy(&block);
12097             return(TNG_CRITICAL);
12098         }
12099     }
12100
12101     first_frame = tng_max_i64(frame_set->first_frame, 0);
12102     last_frame = first_frame + frame_set->n_frames - 1;
12103     /* Is this the right frame set? */
12104     if(first_frame <= frame && frame <= last_frame)
12105     {
12106         tng_block_destroy(&block);
12107         return(TNG_SUCCESS);
12108     }
12109
12110     n_frames_per_frame_set = tng_data->frame_set_n_frames;
12111     long_stride_length = tng_data->long_stride_length;
12112     medium_stride_length = tng_data->medium_stride_length;
12113
12114     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
12115        TNG_SUCCESS)
12116     {
12117         if(temp_frame - first_frame > n_frames_per_frame_set)
12118         {
12119             n_frames_per_frame_set = temp_frame - first_frame;
12120         }
12121     }
12122
12123     tng_num_frames_get(tng_data, &n_frames);
12124
12125     if(frame >= n_frames)
12126     {
12127         tng_block_destroy(&block);
12128         return(TNG_FAILURE);
12129     }
12130
12131     if(first_frame - frame >= frame ||
12132        frame - last_frame >
12133        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
12134     {
12135         /* Start from the beginning */
12136         if(first_frame - frame >= frame)
12137         {
12138             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12139
12140             if(file_pos <= 0)
12141             {
12142                 tng_block_destroy(&block);
12143                 return(TNG_FAILURE);
12144             }
12145         }
12146         /* Start from the end */
12147         else if(frame - first_frame > (n_frames - 1) - frame)
12148         {
12149             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
12150
12151             /* If the last frame set position is not set start from the current
12152              * frame set, since it will be closer than the first frame set. */
12153         }
12154         /* Start from current */
12155         else
12156         {
12157             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12158         }
12159
12160         if(file_pos > 0)
12161         {
12162             fseeko(tng_data->input_file,
12163                    file_pos,
12164                    SEEK_SET);
12165             tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12166             /* Read block headers first to see what block is found. */
12167             stat = tng_block_header_read(tng_data, block);
12168             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12169             {
12170                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12171                        file_pos, __FILE__, __LINE__);
12172                 tng_block_destroy(&block);
12173                 return(TNG_CRITICAL);
12174             }
12175
12176             if(tng_block_read_next(tng_data, block,
12177                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12178             {
12179                 tng_block_destroy(&block);
12180                 return(TNG_CRITICAL);
12181             }
12182         }
12183     }
12184
12185     first_frame = tng_max_i64(frame_set->first_frame, 0);
12186     last_frame = first_frame + frame_set->n_frames - 1;
12187
12188     if(frame >= first_frame && frame <= last_frame)
12189     {
12190         tng_block_destroy(&block);
12191         return(TNG_SUCCESS);
12192     }
12193
12194     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12195
12196     /* Take long steps forward until a long step forward would be too long or
12197      * the right frame set is found */
12198     while(file_pos > 0 && first_frame + long_stride_length *
12199           n_frames_per_frame_set <= frame)
12200     {
12201         file_pos = frame_set->long_stride_next_frame_set_file_pos;
12202         if(file_pos > 0)
12203         {
12204             fseeko(tng_data->input_file, file_pos, SEEK_SET);
12205             /* Read block headers first to see what block is found. */
12206             stat = tng_block_header_read(tng_data, block);
12207             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12208             {
12209                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12210                        file_pos, __FILE__, __LINE__);
12211                 tng_block_destroy(&block);
12212                 return(TNG_CRITICAL);
12213             }
12214
12215             if(tng_block_read_next(tng_data, block,
12216                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12217             {
12218                 tng_block_destroy(&block);
12219                 return(TNG_CRITICAL);
12220             }
12221         }
12222         first_frame = tng_max_i64(frame_set->first_frame, 0);
12223         last_frame = first_frame + frame_set->n_frames - 1;
12224         if(frame >= first_frame && frame <= last_frame)
12225         {
12226             tng_block_destroy(&block);
12227             return(TNG_SUCCESS);
12228         }
12229     }
12230
12231     /* Take medium steps forward until a medium step forward would be too long
12232      * or the right frame set is found */
12233     while(file_pos > 0 && first_frame + medium_stride_length *
12234           n_frames_per_frame_set <= frame)
12235     {
12236         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
12237         if(file_pos > 0)
12238         {
12239             fseeko(tng_data->input_file,
12240                    file_pos,
12241                    SEEK_SET);
12242             /* Read block headers first to see what block is found. */
12243             stat = tng_block_header_read(tng_data, block);
12244             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12245             {
12246                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12247                        file_pos, __FILE__, __LINE__);
12248                 tng_block_destroy(&block);
12249                 return(TNG_CRITICAL);
12250             }
12251
12252             if(tng_block_read_next(tng_data, block,
12253                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12254             {
12255                 tng_block_destroy(&block);
12256                 return(TNG_CRITICAL);
12257             }
12258         }
12259         first_frame = tng_max_i64(frame_set->first_frame, 0);
12260         last_frame = first_frame + frame_set->n_frames - 1;
12261         if(frame >= first_frame && frame <= last_frame)
12262         {
12263             tng_block_destroy(&block);
12264             return(TNG_SUCCESS);
12265         }
12266     }
12267
12268     /* Take one step forward until the right frame set is found */
12269     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12270     {
12271         file_pos = frame_set->next_frame_set_file_pos;
12272         if(file_pos > 0)
12273         {
12274             fseeko(tng_data->input_file,
12275                    file_pos,
12276                    SEEK_SET);
12277             /* Read block headers first to see what block is found. */
12278             stat = tng_block_header_read(tng_data, block);
12279             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12280             {
12281                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12282                        file_pos, __FILE__, __LINE__);
12283                 tng_block_destroy(&block);
12284                 return(TNG_CRITICAL);
12285             }
12286
12287             if(tng_block_read_next(tng_data, block,
12288                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12289             {
12290                 tng_block_destroy(&block);
12291                 return(TNG_CRITICAL);
12292             }
12293         }
12294         first_frame = tng_max_i64(frame_set->first_frame, 0);
12295         last_frame = first_frame + frame_set->n_frames - 1;
12296         if(frame >= first_frame && frame <= last_frame)
12297         {
12298             tng_block_destroy(&block);
12299             return(TNG_SUCCESS);
12300         }
12301     }
12302
12303     /* Take long steps backward until a long step backward would be too long
12304      * or the right frame set is found */
12305     while(file_pos > 0 && first_frame - long_stride_length *
12306           n_frames_per_frame_set >= frame)
12307     {
12308         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
12309         if(file_pos > 0)
12310         {
12311             fseeko(tng_data->input_file,
12312                    file_pos,
12313                    SEEK_SET);
12314             /* Read block headers first to see what block is found. */
12315             stat = tng_block_header_read(tng_data, block);
12316             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12317             {
12318                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12319                        file_pos, __FILE__, __LINE__);
12320                 tng_block_destroy(&block);
12321                 return(TNG_CRITICAL);
12322             }
12323
12324             if(tng_block_read_next(tng_data, block,
12325                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12326             {
12327                 tng_block_destroy(&block);
12328                 return(TNG_CRITICAL);
12329             }
12330         }
12331         first_frame = tng_max_i64(frame_set->first_frame, 0);
12332         last_frame = first_frame + frame_set->n_frames - 1;
12333         if(frame >= first_frame && frame <= last_frame)
12334         {
12335             tng_block_destroy(&block);
12336             return(TNG_SUCCESS);
12337         }
12338     }
12339
12340     /* Take medium steps backward until a medium step backward would be too long
12341      * or the right frame set is found */
12342     while(file_pos > 0 && first_frame - medium_stride_length *
12343           n_frames_per_frame_set >= frame)
12344     {
12345         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
12346         if(file_pos > 0)
12347         {
12348             fseeko(tng_data->input_file,
12349                    file_pos,
12350                    SEEK_SET);
12351             /* Read block headers first to see what block is found. */
12352             stat = tng_block_header_read(tng_data, block);
12353             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12354             {
12355                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12356                        file_pos, __FILE__, __LINE__);
12357                 tng_block_destroy(&block);
12358                 return(TNG_CRITICAL);
12359             }
12360
12361             if(tng_block_read_next(tng_data, block,
12362                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12363             {
12364                 tng_block_destroy(&block);
12365                 return(TNG_CRITICAL);
12366             }
12367         }
12368         first_frame = tng_max_i64(frame_set->first_frame, 0);
12369         last_frame = first_frame + frame_set->n_frames - 1;
12370         if(frame >= first_frame && frame <= last_frame)
12371         {
12372             tng_block_destroy(&block);
12373             return(TNG_SUCCESS);
12374         }
12375     }
12376
12377     /* Take one step backward until the right frame set is found */
12378     while(file_pos > 0 && first_frame > frame && last_frame > frame)
12379     {
12380         file_pos = frame_set->prev_frame_set_file_pos;
12381         if(file_pos > 0)
12382         {
12383             fseeko(tng_data->input_file,
12384                    file_pos,
12385                    SEEK_SET);
12386             /* Read block headers first to see what block is found. */
12387             stat = tng_block_header_read(tng_data, block);
12388             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12389             {
12390                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12391                        file_pos, __FILE__, __LINE__);
12392                 tng_block_destroy(&block);
12393                 return(TNG_CRITICAL);
12394             }
12395
12396             if(tng_block_read_next(tng_data, block,
12397                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12398             {
12399                 tng_block_destroy(&block);
12400                 return(TNG_CRITICAL);
12401             }
12402         }
12403         first_frame = tng_max_i64(frame_set->first_frame, 0);
12404         last_frame = first_frame + frame_set->n_frames - 1;
12405         if(frame >= first_frame && frame <= last_frame)
12406         {
12407             tng_block_destroy(&block);
12408             return(TNG_SUCCESS);
12409         }
12410     }
12411
12412     /* If for some reason the current frame set is not yet found,
12413      * take one step forward until the right frame set is found */
12414     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12415     {
12416         file_pos = frame_set->next_frame_set_file_pos;
12417         if(file_pos > 0)
12418         {
12419             fseeko(tng_data->input_file,
12420                    file_pos,
12421                    SEEK_SET);
12422             /* Read block headers first to see what block is found. */
12423             stat = tng_block_header_read(tng_data, block);
12424             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12425             {
12426                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12427                        file_pos, __FILE__, __LINE__);
12428                 tng_block_destroy(&block);
12429                 return(TNG_CRITICAL);
12430             }
12431
12432             if(tng_block_read_next(tng_data, block,
12433                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12434             {
12435                 tng_block_destroy(&block);
12436                 return(TNG_CRITICAL);
12437             }
12438         }
12439         first_frame = tng_max_i64(frame_set->first_frame, 0);
12440         last_frame = first_frame + frame_set->n_frames - 1;
12441         if(frame >= first_frame && frame <= last_frame)
12442         {
12443             tng_block_destroy(&block);
12444             return(TNG_SUCCESS);
12445         }
12446     }
12447
12448     tng_block_destroy(&block);
12449     return(TNG_FAILURE);
12450 }
12451
12452 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
12453                 (const tng_trajectory_t tng_data,
12454                  const tng_trajectory_frame_set_t frame_set,
12455                  int64_t *pos)
12456 {
12457     (void)tng_data;
12458
12459     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12460     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12461
12462     *pos = frame_set->next_frame_set_file_pos;
12463
12464     return(TNG_SUCCESS);
12465 }
12466
12467 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
12468                 (const tng_trajectory_t tng_data,
12469                  const tng_trajectory_frame_set_t frame_set,
12470                  int64_t *pos)
12471 {
12472     (void)tng_data;
12473
12474     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12475     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12476
12477     *pos = frame_set->prev_frame_set_file_pos;
12478
12479     return(TNG_SUCCESS);
12480 }
12481
12482 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
12483                 (const tng_trajectory_t tng_data,
12484                  const tng_trajectory_frame_set_t frame_set,
12485                  int64_t *first_frame,
12486                  int64_t *last_frame)
12487 {
12488     (void)tng_data;
12489
12490     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
12491     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
12492     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
12493
12494     *first_frame = frame_set->first_frame;
12495     *last_frame = *first_frame + frame_set->n_frames - 1;
12496
12497     return(TNG_SUCCESS);
12498 }
12499
12500 /** Translate from the particle numbering used in a frame set to the real
12501  *  particle numbering - used in the molecule description.
12502  * @param frame_set is the frame_set containing the mappings to use.
12503  * @param local is the index number of the atom in this frame set
12504  * @param real is set to the index of the atom in the molecular system.
12505  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12506  * cannot be found.
12507  */
12508 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
12509                 (const tng_trajectory_frame_set_t frame_set,
12510                  const int64_t local,
12511                  int64_t *real)
12512 {
12513     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
12514     tng_particle_mapping_t mapping;
12515     if(n_blocks <= 0)
12516     {
12517         *real = local;
12518         return(TNG_SUCCESS);
12519     }
12520     for(i = 0; i < n_blocks; i++)
12521     {
12522         mapping = &frame_set->mappings[i];
12523         first = mapping->num_first_particle;
12524         if(local < first ||
12525            local >= first + mapping->n_particles)
12526         {
12527             continue;
12528         }
12529         *real = mapping->real_particle_numbers[local-first];
12530         return(TNG_SUCCESS);
12531     }
12532     *real = local;
12533     return(TNG_FAILURE);
12534 }
12535
12536 /** Translate from the real particle numbering to the particle numbering
12537  *  used in a frame set.
12538  * @param frame_set is the frame_set containing the mappings to use.
12539  * @param real is the index number of the atom in the molecular system.
12540  * @param local is set to the index of the atom in this frame set.
12541  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12542  * cannot be found.
12543  */
12544 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
12545                 (const tng_trajectory_frame_set_t frame_set,
12546                  const int64_t real,
12547                  int64_t *local)
12548 {
12549     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
12550     tng_particle_mapping_t mapping;
12551     if(n_blocks <= 0)
12552     {
12553         *local = real;
12554         return(TNG_SUCCESS);
12555     }
12556     for(i = 0; i < n_blocks; i++)
12557     {
12558         mapping = &frame_set->mappings[i];
12559         for(j = mapping->n_particles; j--;)
12560         {
12561             if(mapping->real_particle_numbers[j] == real)
12562             {
12563                 *local = j;
12564                 return(TNG_SUCCESS);
12565             }
12566         }
12567     }
12568     return(TNG_FAILURE);
12569 }
12570 */
12571
12572 static tng_function_status tng_file_headers_len_get
12573                 (tng_trajectory_t tng_data,
12574                  int64_t *len)
12575 {
12576     int64_t orig_pos;
12577     tng_gen_block_t block;
12578
12579     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12580
12581     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12582     {
12583         return(TNG_CRITICAL);
12584     }
12585
12586     *len = 0;
12587
12588     orig_pos = ftello(tng_data->input_file);
12589
12590     if(!tng_data->input_file_len)
12591     {
12592         fseeko(tng_data->input_file, 0, SEEK_END);
12593         tng_data->input_file_len = ftello(tng_data->input_file);
12594     }
12595     fseeko(tng_data->input_file, 0, SEEK_SET);
12596
12597     tng_block_init(&block);
12598     /* Read through the headers of non-trajectory blocks (they come before the
12599      * trajectory blocks in the file) */
12600     while (*len < tng_data->input_file_len &&
12601            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12602            block->id != -1 &&
12603            block->id != TNG_TRAJECTORY_FRAME_SET)
12604     {
12605         *len += block->header_contents_size + block->block_contents_size;
12606         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12607     }
12608
12609     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
12610
12611     tng_block_destroy(&block);
12612
12613     return(TNG_SUCCESS);
12614 }
12615
12616 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
12617                 (tng_trajectory_t tng_data,
12618                  const char hash_mode)
12619 {
12620     int64_t prev_pos = 0;
12621     tng_gen_block_t block;
12622
12623     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12624
12625     tng_data->n_trajectory_frame_sets = 0;
12626
12627     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12628     {
12629         return(TNG_CRITICAL);
12630     }
12631
12632     if(!tng_data->input_file_len)
12633     {
12634         fseeko(tng_data->input_file, 0, SEEK_END);
12635         tng_data->input_file_len = ftello(tng_data->input_file);
12636     }
12637     fseeko(tng_data->input_file, 0, SEEK_SET);
12638
12639     tng_block_init(&block);
12640     /* Non trajectory blocks (they come before the trajectory
12641      * blocks in the file) */
12642     while (prev_pos < tng_data->input_file_len &&
12643            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12644            block->id != -1 &&
12645            block->id != TNG_TRAJECTORY_FRAME_SET)
12646     {
12647         tng_block_read_next(tng_data, block, hash_mode);
12648         prev_pos = ftello(tng_data->input_file);
12649     }
12650
12651     /* Go back if a trajectory block was encountered */
12652     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12653     {
12654         fseeko(tng_data->input_file, prev_pos, SEEK_SET);
12655     }
12656
12657     tng_block_destroy(&block);
12658
12659     return(TNG_SUCCESS);
12660 }
12661
12662 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
12663                 (tng_trajectory_t tng_data,
12664                  const char hash_mode)
12665 {
12666     int i;
12667     int64_t len, orig_len, tot_len = 0, data_start_pos;
12668     tng_function_status stat;
12669     tng_gen_block_t block;
12670
12671     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12672
12673     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
12674     {
12675         return(TNG_CRITICAL);
12676     }
12677
12678     if(tng_data->n_trajectory_frame_sets > 0)
12679     {
12680         stat = tng_file_headers_len_get(tng_data, &orig_len);
12681         if(stat != TNG_SUCCESS)
12682         {
12683             return(stat);
12684         }
12685
12686         tng_block_init(&block);
12687         block->name = malloc(TNG_MAX_STR_LEN);
12688         if(!block->name)
12689         {
12690             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12691                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
12692             tng_block_destroy(&block);
12693             return(TNG_CRITICAL);
12694         }
12695         strcpy(block->name, "GENERAL INFO");
12696         tng_block_header_len_calculate(tng_data, block, &len);
12697         tot_len += len;
12698         tng_general_info_block_len_calculate(tng_data, &len);
12699         tot_len += len;
12700         strcpy(block->name, "MOLECULES");
12701         tng_block_header_len_calculate(tng_data, block, &len);
12702         tot_len += len;
12703         tng_molecules_block_len_calculate(tng_data, &len);
12704         tot_len += len;
12705
12706         for(i = 0; i < tng_data->n_data_blocks; i++)
12707         {
12708             strcpy(block->name, tng_data->non_tr_data[i].block_name);
12709             tng_block_header_len_calculate(tng_data, block, &len);
12710             tot_len += len;
12711             tng_data_block_len_calculate(tng_data,
12712                                         (tng_particle_data_t)&tng_data->non_tr_data[i],
12713                                         TNG_FALSE, 1, 1, 1, 0,
12714                                         1, 0, &data_start_pos,
12715                                         &len);
12716             tot_len += len;
12717         }
12718         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12719         {
12720             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
12721             tng_block_header_len_calculate(tng_data, block, &len);
12722             tot_len += len;
12723             tng_data_block_len_calculate(tng_data,
12724                                         &tng_data->non_tr_particle_data[i],
12725                                         TNG_TRUE, 1, 1, 1, 0,
12726                                         tng_data->n_particles, TNG_PARTICLE_DEPENDENT,
12727                                         &data_start_pos,
12728                                         &len);
12729             tot_len += len;
12730         }
12731         tng_block_destroy(&block);
12732
12733         if(tot_len > orig_len)
12734         {
12735             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len);
12736         }
12737
12738         tng_data->current_trajectory_frame_set_output_file_pos = -1;
12739     }
12740
12741     /* TODO: If there is already frame set data written to this file (e.g. when
12742      * appending to an already existing file we might need to move frame sets to
12743      * the end of the file. */
12744
12745     if(tng_general_info_block_write(tng_data, hash_mode)
12746        != TNG_SUCCESS)
12747     {
12748         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
12749                 tng_data->input_file_path, __FILE__, __LINE__);
12750         return(TNG_CRITICAL);
12751     }
12752
12753     if(tng_molecules_block_write(tng_data, hash_mode)
12754         != TNG_SUCCESS)
12755     {
12756         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
12757                 tng_data->input_file_path, __FILE__, __LINE__);
12758         return(TNG_CRITICAL);
12759     }
12760
12761     /* FIXME: Currently writing non-trajectory data blocks here.
12762      * Should perhaps be moved. */
12763     tng_block_init(&block);
12764     for(i = 0; i < tng_data->n_data_blocks; i++)
12765     {
12766         block->id = tng_data->non_tr_data[i].block_id;
12767         tng_data_block_write(tng_data, block,
12768                              i, hash_mode);
12769     }
12770
12771     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12772     {
12773         block->id = tng_data->non_tr_particle_data[i].block_id;
12774         tng_particle_data_block_write(tng_data, block,
12775                                       i, 0, hash_mode);
12776     }
12777
12778     tng_block_destroy(&block);
12779
12780     return(TNG_SUCCESS);
12781 }
12782
12783 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12784                                         tng_gen_block_t block,
12785                                         const char hash_mode)
12786 {
12787     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12788     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12789
12790     switch(block->id)
12791     {
12792     case TNG_TRAJECTORY_FRAME_SET:
12793         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12794     case TNG_PARTICLE_MAPPING:
12795         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12796     case TNG_GENERAL_INFO:
12797         return(tng_general_info_block_read(tng_data, block, hash_mode));
12798     case TNG_MOLECULES:
12799         return(tng_molecules_block_read(tng_data, block, hash_mode));
12800     default:
12801         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12802         {
12803             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12804         }
12805         else
12806         {
12807             /* Skip to the next block */
12808             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12809             return(TNG_FAILURE);
12810         }
12811     }
12812 }
12813
12814 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12815                 (tng_trajectory_t tng_data,
12816                  const char hash_mode)
12817 {
12818     int64_t file_pos;
12819     tng_gen_block_t block;
12820     tng_function_status stat;
12821
12822     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12823
12824     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12825     {
12826         return(TNG_CRITICAL);
12827     }
12828
12829     file_pos = ftello(tng_data->input_file);
12830
12831     tng_block_init(&block);
12832
12833     if(!tng_data->input_file_len)
12834     {
12835         fseeko(tng_data->input_file, 0, SEEK_END);
12836         tng_data->input_file_len = ftello(tng_data->input_file);
12837         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12838     }
12839
12840     /* Read block headers first to see what block is found. */
12841     stat = tng_block_header_read(tng_data, block);
12842     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
12843        block->id == -1)
12844     {
12845         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12846                file_pos, __FILE__, __LINE__);
12847         tng_block_destroy(&block);
12848         return(TNG_CRITICAL);
12849     }
12850
12851     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12852
12853     if(tng_block_read_next(tng_data, block,
12854                            hash_mode) == TNG_SUCCESS)
12855     {
12856         tng_data->n_trajectory_frame_sets++;
12857         file_pos = ftello(tng_data->input_file);
12858         /* Read all blocks until next frame set block */
12859         stat = tng_block_header_read(tng_data, block);
12860         while(file_pos < tng_data->input_file_len &&
12861               stat != TNG_CRITICAL &&
12862               block->id != TNG_TRAJECTORY_FRAME_SET &&
12863               block->id != -1)
12864         {
12865             stat = tng_block_read_next(tng_data, block,
12866                                        hash_mode);
12867             if(stat != TNG_CRITICAL)
12868             {
12869                 file_pos = ftello(tng_data->input_file);
12870                 if(file_pos < tng_data->input_file_len)
12871                 {
12872                     stat = tng_block_header_read(tng_data, block);
12873                 }
12874             }
12875         }
12876         if(stat == TNG_CRITICAL)
12877         {
12878             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12879                    file_pos, __FILE__, __LINE__);
12880             tng_block_destroy(&block);
12881             return(stat);
12882         }
12883
12884         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12885         {
12886             fseeko(tng_data->input_file, file_pos, SEEK_SET);
12887         }
12888     }
12889
12890     tng_block_destroy(&block);
12891
12892     return(TNG_SUCCESS);
12893 }
12894
12895
12896 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12897                 (tng_trajectory_t tng_data,
12898                  const char hash_mode,
12899                  const int64_t block_id)
12900 {
12901     int64_t file_pos;
12902     tng_gen_block_t block;
12903     tng_function_status stat;
12904     int found_flag = 1;
12905
12906     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12907
12908     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12909     {
12910         return(TNG_CRITICAL);
12911     }
12912
12913     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12914
12915     if(file_pos < 0)
12916     {
12917         /* No current frame set. This means that the first frame set must be
12918          * read */
12919         found_flag = 0;
12920         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12921     }
12922
12923     if(file_pos > 0)
12924     {
12925         fseeko(tng_data->input_file,
12926               file_pos,
12927               SEEK_SET);
12928     }
12929     else
12930     {
12931         return(TNG_FAILURE);
12932     }
12933
12934     tng_block_init(&block);
12935
12936     if(!tng_data->input_file_len)
12937     {
12938         fseeko(tng_data->input_file, 0, SEEK_END);
12939         tng_data->input_file_len = ftello(tng_data->input_file);
12940         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12941     }
12942
12943     /* Read block headers first to see what block is found. */
12944     stat = tng_block_header_read(tng_data, block);
12945     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12946     {
12947         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12948                file_pos, __FILE__, __LINE__);
12949         tng_block_destroy(&block);
12950         return(TNG_CRITICAL);
12951     }
12952     /* If the current frame set had already been read skip its block contents */
12953     if(found_flag)
12954     {
12955         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12956     }
12957     /* Otherwiese read the frame set block */
12958     else
12959     {
12960         stat = tng_block_read_next(tng_data, block,
12961                                    hash_mode);
12962         if(stat != TNG_SUCCESS)
12963         {
12964             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12965             tng_block_destroy(&block);
12966             return(stat);
12967         }
12968     }
12969     file_pos = ftello(tng_data->input_file);
12970
12971     found_flag = 0;
12972
12973     /* Read only blocks of the requested ID
12974         * until next frame set block */
12975     stat = tng_block_header_read(tng_data, block);
12976     while(file_pos < tng_data->input_file_len &&
12977             stat != TNG_CRITICAL &&
12978             block->id != TNG_TRAJECTORY_FRAME_SET &&
12979             block->id != -1)
12980     {
12981         if(block->id == block_id)
12982         {
12983             stat = tng_block_read_next(tng_data, block,
12984                                        hash_mode);
12985             if(stat != TNG_CRITICAL)
12986             {
12987                 file_pos = ftello(tng_data->input_file);
12988                 found_flag = 1;
12989                 if(file_pos < tng_data->input_file_len)
12990                 {
12991                     stat = tng_block_header_read(tng_data, block);
12992                 }
12993             }
12994         }
12995         else
12996         {
12997             file_pos += (block->block_contents_size + block->header_contents_size);
12998             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12999             if(file_pos < tng_data->input_file_len)
13000             {
13001                 stat = tng_block_header_read(tng_data, block);
13002             }
13003         }
13004     }
13005     if(stat == TNG_CRITICAL)
13006     {
13007         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13008                 file_pos, __FILE__, __LINE__);
13009         tng_block_destroy(&block);
13010         return(stat);
13011     }
13012
13013     if(block->id == TNG_TRAJECTORY_FRAME_SET)
13014     {
13015         fseeko(tng_data->input_file, file_pos, SEEK_SET);
13016     }
13017
13018     tng_block_destroy(&block);
13019
13020     if(found_flag)
13021     {
13022         return(TNG_SUCCESS);
13023     }
13024     else
13025     {
13026         return(TNG_FAILURE);
13027     }
13028 }
13029
13030 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
13031                 (tng_trajectory_t tng_data,
13032                  const char hash_mode)
13033 {
13034     int64_t file_pos;
13035
13036     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13037
13038     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13039     {
13040         return(TNG_CRITICAL);
13041     }
13042
13043     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13044
13045     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13046     {
13047         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13048     }
13049
13050     if(file_pos > 0)
13051     {
13052         fseeko(tng_data->input_file,
13053               file_pos,
13054               SEEK_SET);
13055     }
13056     else
13057     {
13058         return(TNG_FAILURE);
13059     }
13060
13061     return(tng_frame_set_read(tng_data, hash_mode));
13062 }
13063
13064 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
13065                 (tng_trajectory_t tng_data,
13066                  const char hash_mode,
13067                  const int64_t block_id)
13068 {
13069     int64_t file_pos;
13070     tng_gen_block_t block;
13071     tng_function_status stat;
13072
13073     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13074
13075     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13076     {
13077         return(TNG_CRITICAL);
13078     }
13079
13080     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13081
13082     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13083     {
13084         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13085     }
13086
13087     if(file_pos > 0)
13088     {
13089         fseeko(tng_data->input_file,
13090               file_pos,
13091               SEEK_SET);
13092     }
13093     else
13094     {
13095         return(TNG_FAILURE);
13096     }
13097
13098     tng_block_init(&block);
13099
13100     if(!tng_data->input_file_len)
13101     {
13102         fseeko(tng_data->input_file, 0, SEEK_END);
13103         tng_data->input_file_len = ftello(tng_data->input_file);
13104         fseeko(tng_data->input_file, file_pos, SEEK_SET);
13105     }
13106
13107     /* Read block headers first to see what block is found. */
13108     stat = tng_block_header_read(tng_data, block);
13109     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13110     {
13111         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13112                file_pos, __FILE__, __LINE__);
13113         tng_block_destroy(&block);
13114         return(TNG_CRITICAL);
13115     }
13116
13117     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
13118
13119     if(tng_block_read_next(tng_data, block,
13120                            hash_mode) == TNG_SUCCESS)
13121     {
13122         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
13123     }
13124
13125     tng_block_destroy(&block);
13126
13127     return(stat);
13128 }
13129
13130 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
13131                                         const char hash_mode)
13132 {
13133     int i, j;
13134     tng_gen_block_t block;
13135     tng_trajectory_frame_set_t frame_set;
13136     tng_function_status stat;
13137
13138     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13139
13140     frame_set = &tng_data->current_trajectory_frame_set;
13141
13142     if(frame_set->n_written_frames == frame_set->n_frames)
13143     {
13144         return(TNG_SUCCESS);
13145     }
13146
13147     tng_data->current_trajectory_frame_set_output_file_pos =
13148     ftello(tng_data->output_file);
13149     tng_data->last_trajectory_frame_set_output_file_pos =
13150     tng_data->current_trajectory_frame_set_output_file_pos;
13151
13152     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
13153     {
13154         return(TNG_FAILURE);
13155     }
13156
13157     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
13158     {
13159         tng_data->first_trajectory_frame_set_output_file_pos =
13160         tng_data->current_trajectory_frame_set_output_file_pos;
13161     }
13162
13163     tng_block_init(&block);
13164
13165     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
13166     {
13167         tng_block_destroy(&block);
13168         return(TNG_FAILURE);
13169     }
13170
13171     /* Write non-particle data blocks */
13172     for(i = 0; i<frame_set->n_data_blocks; i++)
13173     {
13174         block->id = frame_set->tr_data[i].block_id;
13175         tng_data_block_write(tng_data, block, i, hash_mode);
13176     }
13177     /* Write the mapping blocks and particle data blocks*/
13178     if(frame_set->n_mapping_blocks)
13179     {
13180         for(i = 0; i < frame_set->n_mapping_blocks; i++)
13181         {
13182             block->id = TNG_PARTICLE_MAPPING;
13183             if(frame_set->mappings[i].n_particles > 0)
13184             {
13185                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
13186                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
13187                 {
13188                     block->id = frame_set->tr_particle_data[j].block_id;
13189                     tng_particle_data_block_write(tng_data, block,
13190                                                   j, &frame_set->mappings[i],
13191                                                   hash_mode);
13192                 }
13193             }
13194         }
13195     }
13196     else
13197     {
13198         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
13199         {
13200             block->id = frame_set->tr_particle_data[i].block_id;
13201             tng_particle_data_block_write(tng_data, block,
13202                                           i, 0, hash_mode);
13203         }
13204     }
13205
13206
13207     /* Update pointers in the general info block */
13208     stat = tng_header_pointers_update(tng_data, hash_mode);
13209
13210     if(stat == TNG_SUCCESS)
13211     {
13212         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
13213     }
13214
13215     tng_block_destroy(&block);
13216
13217     frame_set->n_unwritten_frames = 0;
13218
13219     fflush(tng_data->output_file);
13220
13221     return(stat);
13222 }
13223
13224 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
13225                 (tng_trajectory_t tng_data,
13226                  const char hash_mode)
13227 {
13228     tng_trajectory_frame_set_t frame_set;
13229
13230     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13231
13232     frame_set = &tng_data->current_trajectory_frame_set;
13233
13234     if(frame_set->n_unwritten_frames == 0)
13235     {
13236         return(TNG_SUCCESS);
13237     }
13238     frame_set->n_frames = frame_set->n_unwritten_frames;
13239
13240     return(tng_frame_set_write(tng_data, hash_mode));
13241 }
13242
13243 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
13244                 (tng_trajectory_t tng_data,
13245                  const int64_t first_frame,
13246                  const int64_t n_frames)
13247 {
13248     tng_gen_block_t block;
13249     tng_trajectory_frame_set_t frame_set;
13250     FILE *temp = tng_data->input_file;
13251     int64_t curr_pos;
13252
13253     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13254     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13255     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13256
13257     frame_set = &tng_data->current_trajectory_frame_set;
13258
13259     curr_pos = ftello(tng_data->output_file);
13260
13261     if(curr_pos <= 10)
13262     {
13263         tng_file_headers_write(tng_data, TNG_USE_HASH);
13264     }
13265
13266     /* Set pointer to previous frame set to the one that was loaded
13267      * before.
13268      * FIXME: This is a bit risky. If they are not added in order
13269      * it will be wrong. */
13270     if(tng_data->n_trajectory_frame_sets)
13271     {
13272         frame_set->prev_frame_set_file_pos =
13273         tng_data->current_trajectory_frame_set_output_file_pos;
13274     }
13275
13276     tng_data->current_trajectory_frame_set_output_file_pos =
13277     ftello(tng_data->output_file);
13278
13279     tng_data->n_trajectory_frame_sets++;
13280
13281     /* Set the medium range pointers */
13282     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
13283     {
13284         frame_set->medium_stride_prev_frame_set_file_pos =
13285         tng_data->first_trajectory_frame_set_output_file_pos;
13286     }
13287     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13288     {
13289         /* FIXME: Currently only working if the previous frame set has its
13290          * medium stride pointer already set. This might need some fixing. */
13291         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
13292            frame_set->medium_stride_prev_frame_set_file_pos != 0)
13293         {
13294             tng_block_init(&block);
13295             tng_data->input_file = tng_data->output_file;
13296
13297             curr_pos = ftello(tng_data->output_file);
13298             fseeko(tng_data->output_file,
13299                    frame_set->medium_stride_prev_frame_set_file_pos,
13300                    SEEK_SET);
13301
13302             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13303             {
13304                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13305                     __FILE__, __LINE__);
13306                 tng_data->input_file = temp;
13307                 tng_block_destroy(&block);
13308                 return(TNG_CRITICAL);
13309             }
13310
13311             /* Read the next frame set from the previous frame set and one
13312              * medium stride step back */
13313             fseeko(tng_data->output_file, block->block_contents_size - (6 *
13314             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13315             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
13316                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
13317                1, tng_data->output_file) == 0)
13318             {
13319                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13320                 tng_data->input_file = temp;
13321                 tng_block_destroy(&block);
13322                 return(TNG_CRITICAL);
13323             }
13324
13325             if(tng_data->input_endianness_swap_func_64)
13326             {
13327                 if(tng_data->input_endianness_swap_func_64(tng_data,
13328                    &frame_set->medium_stride_prev_frame_set_file_pos)
13329                     != TNG_SUCCESS)
13330                 {
13331                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13332                             __FILE__, __LINE__);
13333                 }
13334             }
13335
13336             tng_block_destroy(&block);
13337
13338             /* Set the long range pointers */
13339             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
13340             {
13341                 frame_set->long_stride_prev_frame_set_file_pos =
13342                 tng_data->first_trajectory_frame_set_output_file_pos;
13343             }
13344             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13345             {
13346                 /* FIXME: Currently only working if the previous frame set has its
13347                 * long stride pointer already set. This might need some fixing. */
13348                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
13349                 frame_set->long_stride_prev_frame_set_file_pos != 0)
13350                 {
13351                     tng_block_init(&block);
13352                     tng_data->input_file = tng_data->output_file;
13353
13354                     fseeko(tng_data->output_file,
13355                            frame_set->long_stride_prev_frame_set_file_pos,
13356                            SEEK_SET);
13357
13358                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13359                     {
13360                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13361                             __FILE__, __LINE__);
13362                         tng_data->input_file = temp;
13363                         tng_block_destroy(&block);
13364                         return(TNG_CRITICAL);
13365                     }
13366
13367                     /* Read the next frame set from the previous frame set and one
13368                     * long stride step back */
13369                     fseeko(tng_data->output_file, block->block_contents_size - (6 *
13370                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13371
13372                     tng_block_destroy(&block);
13373
13374                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
13375                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
13376                     1, tng_data->output_file) == 0)
13377                     {
13378                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13379                         tng_data->input_file = temp;
13380                         return(TNG_CRITICAL);
13381                     }
13382
13383                     if(tng_data->input_endianness_swap_func_64)
13384                     {
13385                         if(tng_data->input_endianness_swap_func_64(tng_data,
13386                            &frame_set->long_stride_prev_frame_set_file_pos)
13387                             != TNG_SUCCESS)
13388                         {
13389                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13390                                     __FILE__, __LINE__);
13391                         }
13392                     }
13393
13394                 }
13395             }
13396
13397             tng_data->input_file = temp;
13398             fseeko(tng_data->output_file, curr_pos, SEEK_SET);
13399         }
13400     }
13401
13402     frame_set->first_frame = first_frame;
13403     frame_set->n_frames = n_frames;
13404     frame_set->n_written_frames = 0;
13405     frame_set->n_unwritten_frames = 0;
13406     frame_set->first_frame_time = -1;
13407
13408     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
13409        tng_data->first_trajectory_frame_set_output_file_pos == 0)
13410     {
13411         tng_data->first_trajectory_frame_set_output_file_pos =
13412         tng_data->current_trajectory_frame_set_output_file_pos;
13413     }
13414     /* FIXME: Should check the frame number instead of the file_pos,
13415      * in case frame sets are not in order */
13416     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
13417        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
13418        tng_data->last_trajectory_frame_set_output_file_pos <
13419        tng_data->current_trajectory_frame_set_output_file_pos)
13420     {
13421         tng_data->last_trajectory_frame_set_output_file_pos =
13422         tng_data->current_trajectory_frame_set_output_file_pos;
13423     }
13424
13425     return(TNG_SUCCESS);
13426 }
13427
13428 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
13429                 (tng_trajectory_t tng_data,
13430                  const int64_t first_frame,
13431                  const int64_t n_frames,
13432                  const double first_frame_time)
13433 {
13434     tng_function_status stat;
13435
13436     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13437     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13438     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13439     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13440
13441
13442     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
13443     if(stat != TNG_SUCCESS)
13444     {
13445         return(stat);
13446     }
13447     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
13448
13449     return(stat);
13450 }
13451
13452 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
13453                 (tng_trajectory_t tng_data,
13454                  const double first_frame_time)
13455 {
13456     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13457     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13458
13459     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
13460
13461     return(TNG_SUCCESS);
13462 }
13463
13464 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
13465                 (const tng_trajectory_t tng_data,
13466                  int64_t *frame)
13467 {
13468     int64_t file_pos, next_frame_set_file_pos;
13469     tng_gen_block_t block;
13470     tng_function_status stat;
13471
13472     tng_trajectory_frame_set_t frame_set;
13473
13474     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13475     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
13476     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
13477
13478     file_pos = ftello(tng_data->input_file);
13479
13480     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13481     {
13482         next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13483     }
13484     else
13485     {
13486         frame_set = &tng_data->current_trajectory_frame_set;
13487         next_frame_set_file_pos = frame_set->next_frame_set_file_pos;
13488     }
13489
13490     if(next_frame_set_file_pos <= 0)
13491     {
13492         return(TNG_FAILURE);
13493     }
13494
13495     fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET);
13496     /* Read block headers first to see that a frame set block is found. */
13497     tng_block_init(&block);
13498     stat = tng_block_header_read(tng_data, block);
13499     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13500     {
13501         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13502                file_pos, __FILE__, __LINE__);
13503         return(TNG_CRITICAL);
13504     }
13505 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13506     {
13507         tng_block_read_next(tng_data, block, TNG_USE_HASH);
13508     }*/
13509     tng_block_destroy(&block);
13510
13511     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
13512     {
13513         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
13514                __FILE__, __LINE__);
13515         return(TNG_CRITICAL);
13516     }
13517     fseeko(tng_data->input_file, file_pos, SEEK_SET);
13518
13519     return(TNG_SUCCESS);
13520 }
13521
13522 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
13523                 (tng_trajectory_t tng_data,
13524                  const int64_t id,
13525                  const char *block_name,
13526                  const char datatype,
13527                  const char block_type_flag,
13528                  int64_t n_frames,
13529                  const int64_t n_values_per_frame,
13530                  int64_t stride_length,
13531                  const int64_t codec_id,
13532                  void *new_data)
13533 {
13534     int i, j, size, len;
13535     tng_trajectory_frame_set_t frame_set;
13536     tng_non_particle_data_t data;
13537     char **first_dim_values;
13538     char *new_data_c=new_data;
13539     int64_t n_frames_div;
13540
13541     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13542     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
13543     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13544
13545     frame_set = &tng_data->current_trajectory_frame_set;
13546
13547     if(stride_length <= 0)
13548     {
13549         stride_length = 1;
13550     }
13551
13552     /* If the block does not exist, create it */
13553     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
13554     {
13555         if(tng_data_block_create(tng_data, block_type_flag) !=
13556             TNG_SUCCESS)
13557         {
13558             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
13559                    __FILE__, __LINE__);
13560             return(TNG_CRITICAL);
13561         }
13562         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13563         {
13564             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
13565         }
13566         else
13567         {
13568             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
13569         }
13570         data->block_id = id;
13571
13572         data->block_name = malloc(strlen(block_name) + 1);
13573         if(!data->block_name)
13574         {
13575             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13576                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13577             return(TNG_CRITICAL);
13578         }
13579         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13580
13581         data->values = 0;
13582         /* FIXME: Memory leak from strings. */
13583         data->strings = 0;
13584         data->last_retrieved_frame = -1;
13585     }
13586
13587     data->datatype = datatype;
13588     data->stride_length = tng_max_i64(stride_length, 1);
13589     data->n_values_per_frame = n_values_per_frame;
13590     data->n_frames = n_frames;
13591     data->codec_id = codec_id;
13592     data->compression_multiplier = 1.0;
13593     /* FIXME: This can cause problems. */
13594     data->first_frame_with_data = frame_set->first_frame;
13595
13596     switch(datatype)
13597     {
13598     case TNG_FLOAT_DATA:
13599         size = sizeof(float);
13600         break;
13601     case TNG_INT_DATA:
13602         size = sizeof(int64_t);
13603         break;
13604     case TNG_DOUBLE_DATA:
13605     default:
13606         size = sizeof(double);
13607         break;
13608     }
13609
13610     if(new_data_c)
13611     {
13612         /* Allocate memory */
13613         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
13614                                  n_values_per_frame) !=
13615         TNG_SUCCESS)
13616         {
13617             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
13618                 __FILE__, __LINE__);
13619             return(TNG_CRITICAL);
13620         }
13621
13622         if(n_frames > frame_set->n_unwritten_frames)
13623         {
13624             frame_set->n_unwritten_frames = n_frames;
13625         }
13626
13627         n_frames_div = (n_frames % stride_length) ?
13628                      n_frames / stride_length + 1:
13629                      n_frames / stride_length;
13630
13631         if(datatype == TNG_CHAR_DATA)
13632         {
13633             for(i = 0; i < n_frames_div; i++)
13634             {
13635                 first_dim_values = data->strings[i];
13636                 for(j = 0; j < n_values_per_frame; j++)
13637                 {
13638                     len = tng_min_i((int)strlen(new_data_c) + 1,
13639                                 TNG_MAX_STR_LEN);
13640                     if(first_dim_values[j])
13641                     {
13642                         free(first_dim_values[j]);
13643                     }
13644                     first_dim_values[j] = malloc(len);
13645                     if(!first_dim_values[j])
13646                     {
13647                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13648                             len, __FILE__, __LINE__);
13649                         return(TNG_CRITICAL);
13650                     }
13651                     strncpy(first_dim_values[j],
13652                             new_data_c, len);
13653                     new_data_c += len;
13654                 }
13655             }
13656         }
13657         else
13658         {
13659             memcpy(data->values, new_data, size * n_frames_div *
13660                    n_values_per_frame);
13661         }
13662     }
13663
13664     return(TNG_SUCCESS);
13665 }
13666
13667 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
13668                 (tng_trajectory_t tng_data,
13669                  const int64_t id,
13670                  const char *block_name,
13671                  const char datatype,
13672                  const char block_type_flag,
13673                  int64_t n_frames,
13674                  const int64_t n_values_per_frame,
13675                  int64_t stride_length,
13676                  const int64_t num_first_particle,
13677                  const int64_t n_particles,
13678                  const int64_t codec_id,
13679                  void *new_data)
13680 {
13681     int i, size, len;
13682     int64_t j, k;
13683     int64_t tot_n_particles, n_frames_div;
13684     char ***first_dim_values, **second_dim_values;
13685     tng_trajectory_frame_set_t frame_set;
13686     tng_particle_data_t data;
13687     char *new_data_c=new_data;
13688
13689     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13690     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
13691     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13692     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
13693     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
13694
13695
13696     frame_set = &tng_data->current_trajectory_frame_set;
13697
13698     if(stride_length <= 0)
13699     {
13700         stride_length = 1;
13701     }
13702
13703     /* If the block does not exist, create it */
13704     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
13705     {
13706         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
13707             TNG_SUCCESS)
13708         {
13709             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
13710                    __FILE__, __LINE__);
13711             return(TNG_CRITICAL);
13712         }
13713         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13714         {
13715             data = &frame_set->tr_particle_data[frame_set->
13716                                                 n_particle_data_blocks - 1];
13717         }
13718         else
13719         {
13720             data = &tng_data->non_tr_particle_data[tng_data->
13721                                                    n_particle_data_blocks - 1];
13722         }
13723         data->block_id = id;
13724
13725         data->block_name = malloc(strlen(block_name) + 1);
13726         if(!data->block_name)
13727         {
13728             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13729                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13730             return(TNG_CRITICAL);
13731         }
13732         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13733
13734         data->datatype = datatype;
13735
13736         data->values = 0;
13737         /* FIXME: Memory leak from strings. */
13738         data->strings = 0;
13739         data->last_retrieved_frame = -1;
13740     }
13741
13742     data->stride_length = tng_max_i64(stride_length, 1);
13743     data->n_values_per_frame = n_values_per_frame;
13744     data->n_frames = n_frames;
13745     data->codec_id = codec_id;
13746     data->compression_multiplier = 1.0;
13747     /* FIXME: This can cause problems. */
13748     data->first_frame_with_data = frame_set->first_frame;
13749
13750     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
13751     {
13752         tot_n_particles = frame_set->n_particles;
13753     }
13754     else
13755     {
13756         tot_n_particles = tng_data->n_particles;
13757     }
13758
13759     /* If data values are supplied add that data to the data block. */
13760     if(new_data_c)
13761     {
13762         /* Allocate memory */
13763         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
13764                                           stride_length, tot_n_particles,
13765                                           n_values_per_frame) !=
13766         TNG_SUCCESS)
13767         {
13768             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13769                 __FILE__, __LINE__);
13770             return(TNG_CRITICAL);
13771         }
13772
13773         if(n_frames > frame_set->n_unwritten_frames)
13774         {
13775             frame_set->n_unwritten_frames = n_frames;
13776         }
13777
13778         n_frames_div = (n_frames % stride_length) ?
13779                      n_frames / stride_length + 1:
13780                      n_frames / stride_length;
13781
13782         if(datatype == TNG_CHAR_DATA)
13783         {
13784             for(i = 0; i < n_frames_div; i++)
13785             {
13786                 first_dim_values = data->strings[i];
13787                 for(j = num_first_particle; j < num_first_particle + n_particles;
13788                     j++)
13789                 {
13790                     second_dim_values = first_dim_values[j];
13791                     for(k = 0; k < n_values_per_frame; k++)
13792                     {
13793                         len = tng_min_i((int)strlen(new_data_c) + 1,
13794                                 TNG_MAX_STR_LEN);
13795                         if(second_dim_values[k])
13796                         {
13797                             free(second_dim_values[k]);
13798                         }
13799                         second_dim_values[k] = malloc(len);
13800                         if(!second_dim_values[k])
13801                         {
13802                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13803                                 len, __FILE__, __LINE__);
13804                             return(TNG_CRITICAL);
13805                         }
13806                         strncpy(second_dim_values[k],
13807                                 new_data_c, len);
13808                         new_data_c += len;
13809                     }
13810                 }
13811             }
13812         }
13813         else
13814         {
13815             switch(datatype)
13816             {
13817             case TNG_INT_DATA:
13818                 size = sizeof(int64_t);
13819                 break;
13820             case TNG_FLOAT_DATA:
13821                 size = sizeof(float);
13822                 break;
13823             case TNG_DOUBLE_DATA:
13824             default:
13825                 size = sizeof(double);
13826             }
13827
13828             memcpy(data->values, new_data, size * n_frames_div *
13829                    n_particles * n_values_per_frame);
13830         }
13831     }
13832
13833     return(TNG_SUCCESS);
13834 }
13835
13836 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13837                 (tng_trajectory_t tng_data,
13838                  int64_t block_id,
13839                  char *name,
13840                  int max_len)
13841 {
13842     int64_t i;
13843     tng_trajectory_frame_set_t frame_set;
13844     tng_function_status stat;
13845     tng_particle_data_t p_data;
13846     tng_non_particle_data_t np_data;
13847     int block_type = -1;
13848
13849     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13850     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13851
13852     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13853     {
13854         p_data = &tng_data->non_tr_particle_data[i];
13855         if(p_data->block_id == block_id)
13856         {
13857             strncpy(name, p_data->block_name, max_len);
13858             name[max_len - 1] = '\0';
13859             return(TNG_SUCCESS);
13860         }
13861     }
13862     for(i = 0; i < tng_data->n_data_blocks; i++)
13863     {
13864         np_data = &tng_data->non_tr_data[i];
13865         if(np_data->block_id == block_id)
13866         {
13867             strncpy(name, np_data->block_name, max_len);
13868             name[max_len - 1] = '\0';
13869             return(TNG_SUCCESS);
13870         }
13871     }
13872
13873     frame_set = &tng_data->current_trajectory_frame_set;
13874
13875     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13876     if(stat == TNG_SUCCESS)
13877     {
13878         block_type = TNG_PARTICLE_BLOCK_DATA;
13879     }
13880     else
13881     {
13882         stat = tng_data_find(tng_data, block_id, &np_data);
13883         if(stat == TNG_SUCCESS)
13884         {
13885             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13886         }
13887         else
13888         {
13889             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13890             if(stat != TNG_SUCCESS)
13891             {
13892                 return(stat);
13893             }
13894             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13895             if(stat == TNG_SUCCESS)
13896             {
13897                 block_type = TNG_PARTICLE_BLOCK_DATA;
13898             }
13899             else
13900             {
13901                 stat = tng_data_find(tng_data, block_id, &np_data);
13902                 if(stat == TNG_SUCCESS)
13903                 {
13904                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13905                 }
13906             }
13907         }
13908     }
13909     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13910     {
13911         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13912         {
13913             p_data = &frame_set->tr_particle_data[i];
13914             if(p_data->block_id == block_id)
13915             {
13916                 strncpy(name, p_data->block_name, max_len);
13917                 name[max_len - 1] = '\0';
13918                 return(TNG_SUCCESS);
13919             }
13920         }
13921     }
13922     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13923     {
13924         for(i = 0; i < frame_set->n_data_blocks; i++)
13925         {
13926             np_data = &frame_set->tr_data[i];
13927             if(np_data->block_id == block_id)
13928             {
13929                 strncpy(name, np_data->block_name, max_len);
13930                 name[max_len - 1] = '\0';
13931                 return(TNG_SUCCESS);
13932             }
13933         }
13934     }
13935
13936     return(TNG_FAILURE);
13937 }
13938
13939 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13940                 (const tng_trajectory_t tng_data,
13941                  int64_t block_id,
13942                  int *block_dependency)
13943 {
13944     int64_t i;
13945     tng_function_status stat;
13946     tng_particle_data_t p_data;
13947     tng_non_particle_data_t np_data;
13948
13949     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13950     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13951
13952     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13953     {
13954         p_data = &tng_data->non_tr_particle_data[i];
13955         if(p_data->block_id == block_id)
13956         {
13957             *block_dependency = TNG_PARTICLE_DEPENDENT;
13958             return(TNG_SUCCESS);
13959         }
13960     }
13961     for(i = 0; i < tng_data->n_data_blocks; i++)
13962     {
13963         np_data = &tng_data->non_tr_data[i];
13964         if(np_data->block_id == block_id)
13965         {
13966             *block_dependency = 0;
13967             return(TNG_SUCCESS);
13968         }
13969     }
13970
13971     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13972     if(stat == TNG_SUCCESS)
13973     {
13974         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13975         return(TNG_SUCCESS);
13976     }
13977     else
13978     {
13979         stat = tng_data_find(tng_data, block_id, &np_data);
13980         if(stat == TNG_SUCCESS)
13981         {
13982             *block_dependency = TNG_FRAME_DEPENDENT;
13983             return(TNG_SUCCESS);
13984         }
13985         else
13986         {
13987             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13988             if(stat != TNG_SUCCESS)
13989             {
13990                 return(stat);
13991             }
13992             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13993             if(stat == TNG_SUCCESS)
13994             {
13995                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
13996                 return(TNG_SUCCESS);
13997             }
13998             else
13999             {
14000                 stat = tng_data_find(tng_data, block_id, &np_data);
14001                 if(stat == TNG_SUCCESS)
14002                 {
14003                     *block_dependency = TNG_FRAME_DEPENDENT;
14004                     return(TNG_SUCCESS);
14005                 }
14006             }
14007         }
14008     }
14009
14010     return(TNG_FAILURE);
14011 }
14012
14013 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
14014                 (const tng_trajectory_t tng_data,
14015                  int64_t block_id,
14016                  int64_t *n_values_per_frame)
14017 {
14018     int64_t i;
14019     tng_function_status stat;
14020     tng_particle_data_t p_data;
14021     tng_non_particle_data_t np_data;
14022
14023     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14024     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14025
14026     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
14027     {
14028         p_data = &tng_data->non_tr_particle_data[i];
14029         if(p_data->block_id == block_id)
14030         {
14031             *n_values_per_frame = p_data->n_values_per_frame;
14032             return(TNG_SUCCESS);
14033         }
14034     }
14035     for(i = 0; i < tng_data->n_data_blocks; i++)
14036     {
14037         np_data = &tng_data->non_tr_data[i];
14038         if(np_data->block_id == block_id)
14039         {
14040             *n_values_per_frame = np_data->n_values_per_frame;
14041             return(TNG_SUCCESS);
14042         }
14043     }
14044
14045     stat = tng_particle_data_find(tng_data, block_id, &p_data);
14046     if(stat == TNG_SUCCESS)
14047     {
14048         *n_values_per_frame = p_data->n_values_per_frame;
14049         return(TNG_SUCCESS);
14050     }
14051     else
14052     {
14053         stat = tng_data_find(tng_data, block_id, &np_data);
14054         if(stat == TNG_SUCCESS)
14055         {
14056             *n_values_per_frame = np_data->n_values_per_frame;
14057             return(TNG_SUCCESS);
14058         }
14059         else
14060         {
14061             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
14062             if(stat != TNG_SUCCESS)
14063             {
14064                 return(stat);
14065             }
14066             stat = tng_particle_data_find(tng_data, block_id, &p_data);
14067             if(stat == TNG_SUCCESS)
14068             {
14069                 *n_values_per_frame = p_data->n_values_per_frame;
14070                 return(TNG_SUCCESS);
14071             }
14072             else
14073             {
14074                 stat = tng_data_find(tng_data, block_id, &np_data);
14075                 if(stat == TNG_SUCCESS)
14076                 {
14077                     *n_values_per_frame = np_data->n_values_per_frame;
14078                     return(TNG_SUCCESS);
14079                 }
14080             }
14081         }
14082     }
14083
14084     return(TNG_FAILURE);
14085 }
14086
14087 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
14088                 (tng_trajectory_t tng_data,
14089                  const int64_t frame_nr,
14090                  const int64_t block_id,
14091                  const void *values,
14092                  const char hash_mode)
14093 {
14094     int64_t header_pos, file_pos;
14095     int64_t output_file_len, n_values_per_frame, size, contents_size;
14096     int64_t header_size, temp_first, temp_last;
14097     int64_t i, last_frame, temp_current;
14098     tng_gen_block_t block;
14099     tng_trajectory_frame_set_t frame_set;
14100     FILE *temp = tng_data->input_file;
14101     struct tng_non_particle_data data;
14102     tng_function_status stat;
14103     char dependency, sparse_data, datatype;
14104     void *copy;
14105
14106     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14107     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14108     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14109
14110     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14111     {
14112         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14113                __FILE__, __LINE__);
14114         return(TNG_CRITICAL);
14115     }
14116
14117     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14118     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14119     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14120     tng_data->first_trajectory_frame_set_input_file_pos =
14121     tng_data->first_trajectory_frame_set_output_file_pos;
14122     tng_data->last_trajectory_frame_set_input_file_pos =
14123     tng_data->last_trajectory_frame_set_output_file_pos;
14124     tng_data->current_trajectory_frame_set_input_file_pos =
14125     tng_data->current_trajectory_frame_set_output_file_pos;
14126
14127     tng_data->input_file = tng_data->output_file;
14128
14129     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14130
14131     frame_set = &tng_data->current_trajectory_frame_set;
14132
14133     if(stat != TNG_SUCCESS)
14134     {
14135         last_frame = frame_set->first_frame +
14136                      frame_set->n_frames - 1;
14137         /* If the wanted frame would be in the frame set after the last
14138             * frame set create a new frame set. */
14139         if(stat == TNG_FAILURE &&
14140             last_frame < frame_nr)
14141 /*           (last_frame < frame_nr &&
14142             tng_data->current_trajectory_frame_set.first_frame +
14143             tng_data->frame_set_n_frames >= frame_nr))*/
14144         {
14145             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14146             {
14147                 last_frame = frame_nr - 1;
14148             }
14149             tng_frame_set_new(tng_data,
14150                               last_frame+1,
14151                               tng_data->frame_set_n_frames);
14152             file_pos = ftello(tng_data->output_file);
14153             fseeko(tng_data->output_file, 0, SEEK_END);
14154             output_file_len = ftello(tng_data->output_file);
14155             fseeko(tng_data->output_file, file_pos, SEEK_SET);
14156
14157             /* Read mapping blocks from the last frame set */
14158             tng_block_init(&block);
14159
14160             stat = tng_block_header_read(tng_data, block);
14161             while(file_pos < output_file_len &&
14162                   stat != TNG_CRITICAL &&
14163                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14164                   block->id != -1)
14165             {
14166                 if(block->id == TNG_PARTICLE_MAPPING)
14167                 {
14168                     tng_trajectory_mapping_block_read(tng_data, block,
14169                                                       hash_mode);
14170                 }
14171                 else
14172                 {
14173                     fseeko(tng_data->output_file, block->block_contents_size,
14174                            SEEK_CUR);
14175                 }
14176                 file_pos = ftello(tng_data->output_file);
14177                 if(file_pos < output_file_len)
14178                 {
14179                     stat = tng_block_header_read(tng_data, block);
14180                 }
14181             }
14182
14183             tng_block_destroy(&block);
14184             /* Write the frame set to disk */
14185             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14186             {
14187                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14188                 return(TNG_CRITICAL);
14189             }
14190         }
14191         else
14192         {
14193             tng_data->input_file = temp;
14194             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14195             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14196             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14197             return(stat);
14198         }
14199     }
14200
14201     tng_block_init(&block);
14202
14203     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14204
14205     fseeko(tng_data->output_file, 0, SEEK_END);
14206     output_file_len = ftello(tng_data->output_file);
14207     fseeko(tng_data->output_file, file_pos, SEEK_SET);
14208
14209     /* Read past the frame set block first */
14210     stat = tng_block_header_read(tng_data, block);
14211     if(stat == TNG_CRITICAL)
14212     {
14213         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14214                file_pos, __FILE__, __LINE__);
14215         tng_block_destroy(&block);
14216         tng_data->input_file = temp;
14217
14218         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14219         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14220         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14221         return(stat);
14222     }
14223     fseeko(tng_data->output_file, block->block_contents_size,
14224            SEEK_CUR);
14225
14226     /* Read all block headers until next frame set block or
14227      * until the wanted block id is found */
14228     stat = tng_block_header_read(tng_data, block);
14229     while(file_pos < output_file_len &&
14230             stat != TNG_CRITICAL &&
14231             block->id != block_id &&
14232             block->id != TNG_TRAJECTORY_FRAME_SET &&
14233             block->id != -1)
14234     {
14235         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
14236         file_pos = ftello(tng_data->output_file);
14237         if(file_pos < output_file_len)
14238         {
14239             stat = tng_block_header_read(tng_data, block);
14240         }
14241     }
14242     if(stat == TNG_CRITICAL)
14243     {
14244         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14245                file_pos, __FILE__, __LINE__);
14246         tng_block_destroy(&block);
14247         tng_data->input_file = temp;
14248         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14249         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14250         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14251         return(stat);
14252     }
14253
14254     contents_size = block->block_contents_size;
14255     header_size = block->header_contents_size;
14256
14257     header_pos = ftello(tng_data->output_file) - header_size;
14258     frame_set = &tng_data->current_trajectory_frame_set;
14259
14260     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14261     {
14262         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14263         tng_block_destroy(&block);
14264         return(TNG_CRITICAL);
14265     }
14266     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14267     {
14268         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14269         tng_block_destroy(&block);
14270         return(TNG_CRITICAL);
14271     }
14272     data.datatype = datatype;
14273
14274     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14275        (dependency & TNG_PARTICLE_DEPENDENT))
14276     {
14277         tng_block_destroy(&block);
14278         tng_data->input_file = temp;
14279
14280         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14281         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14282         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14283         return(TNG_FAILURE);
14284     }
14285
14286     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14287     {
14288         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14289         tng_block_destroy(&block);
14290         return(TNG_CRITICAL);
14291     }
14292
14293     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14294              tng_data->input_file) == 0)
14295     {
14296         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14297         tng_block_destroy(&block);
14298         return(TNG_CRITICAL);
14299     }
14300     if(tng_data->output_endianness_swap_func_64)
14301     {
14302         if(tng_data->output_endianness_swap_func_64(tng_data,
14303             &data.n_values_per_frame)
14304             != TNG_SUCCESS)
14305         {
14306             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14307                     __FILE__, __LINE__);
14308         }
14309     }
14310
14311     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14312              tng_data->input_file) == 0)
14313     {
14314         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14315         tng_block_destroy(&block);
14316         return(TNG_CRITICAL);
14317     }
14318     if(tng_data->output_endianness_swap_func_64)
14319     {
14320         if(tng_data->output_endianness_swap_func_64(tng_data,
14321             &data.codec_id)
14322             != TNG_SUCCESS)
14323         {
14324             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14325                     __FILE__, __LINE__);
14326         }
14327     }
14328
14329     if(data.codec_id != TNG_UNCOMPRESSED)
14330     {
14331         if(fread(&data.compression_multiplier,
14332                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14333             == 0)
14334         {
14335             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14336             tng_block_destroy(&block);
14337             return(TNG_CRITICAL);
14338         }
14339         if(tng_data->output_endianness_swap_func_64)
14340         {
14341             if(tng_data->output_endianness_swap_func_64(tng_data,
14342                 (int64_t *)&data.compression_multiplier)
14343                 != TNG_SUCCESS)
14344             {
14345                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14346                         __FILE__, __LINE__);
14347             }
14348         }
14349     }
14350     else
14351     {
14352         data.compression_multiplier = 1;
14353     }
14354
14355     if(sparse_data)
14356     {
14357         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
14358                  1, tng_data->input_file) == 0)
14359         {
14360             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14361             tng_block_destroy(&block);
14362             return(TNG_CRITICAL);
14363         }
14364         if(tng_data->output_endianness_swap_func_64)
14365         {
14366             if(tng_data->output_endianness_swap_func_64(tng_data,
14367                 &data.first_frame_with_data)
14368                 != TNG_SUCCESS)
14369             {
14370                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14371                         __FILE__, __LINE__);
14372             }
14373         }
14374
14375         if(fread(&data.stride_length, sizeof(data.stride_length),
14376                  1, tng_data->input_file) == 0)
14377         {
14378             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14379             tng_block_destroy(&block);
14380             return(TNG_CRITICAL);
14381         }
14382         if(tng_data->output_endianness_swap_func_64)
14383         {
14384             if(tng_data->output_endianness_swap_func_64(tng_data,
14385                 &data.stride_length)
14386                 != TNG_SUCCESS)
14387             {
14388                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14389                         __FILE__, __LINE__);
14390             }
14391         }
14392     }
14393     else
14394     {
14395         data.first_frame_with_data = 0;
14396         data.stride_length = 1;
14397     }
14398     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14399
14400     tng_data->input_file = temp;
14401
14402     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14403     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14404     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14405
14406     switch(data.datatype)
14407     {
14408         case(TNG_INT_DATA):
14409             size = sizeof(int64_t);
14410             break;
14411         case(TNG_FLOAT_DATA):
14412             size = sizeof(float);
14413             break;
14414         case(TNG_DOUBLE_DATA):
14415             size = sizeof(double);
14416             break;
14417         default:
14418             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14419                    __LINE__);
14420             tng_block_destroy(&block);
14421             return(TNG_FAILURE);
14422     }
14423
14424     n_values_per_frame = data.n_values_per_frame;
14425
14426     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14427                                data.first_frame_with_data)) /
14428                 data.stride_length;
14429     file_pos *= size * n_values_per_frame;
14430
14431     if(file_pos > contents_size)
14432     {
14433         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14434                __LINE__);
14435         tng_block_destroy(&block);
14436         return(TNG_FAILURE);
14437     }
14438
14439     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
14440
14441     /* If the endianness is not big endian the data needs to be swapped */
14442     if((data.datatype == TNG_INT_DATA ||
14443         data.datatype == TNG_DOUBLE_DATA) &&
14444        tng_data->output_endianness_swap_func_64)
14445     {
14446         copy = malloc(n_values_per_frame * size);
14447         memcpy(copy, values, n_values_per_frame * size);
14448         for(i = 0; i < n_values_per_frame; i++)
14449         {
14450             if(tng_data->output_endianness_swap_func_64(tng_data,
14451                 (int64_t *)copy+i)
14452                 != TNG_SUCCESS)
14453             {
14454                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14455                         __FILE__, __LINE__);
14456             }
14457         }
14458         fwrite(copy, n_values_per_frame, size,
14459                tng_data->output_file);
14460         free(copy);
14461     }
14462     else if(data.datatype == TNG_FLOAT_DATA &&
14463             tng_data->output_endianness_swap_func_32)
14464     {
14465         copy = malloc(n_values_per_frame * size);
14466         memcpy(copy, values, n_values_per_frame * size);
14467         for(i = 0; i < n_values_per_frame; i++)
14468         {
14469             if(tng_data->output_endianness_swap_func_32(tng_data,
14470                 (int32_t *)copy+i)
14471                 != TNG_SUCCESS)
14472             {
14473                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14474                         __FILE__, __LINE__);
14475             }
14476         }
14477         fwrite(copy, n_values_per_frame, size,
14478                tng_data->output_file);
14479         free(copy);
14480     }
14481
14482     else
14483     {
14484         fwrite(values, n_values_per_frame, size, tng_data->output_file);
14485     }
14486
14487     fflush(tng_data->output_file);
14488
14489     /* Update the number of written frames in the frame set. */
14490     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14491     {
14492         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14493     }
14494
14495     /* If the last frame has been written update the hash */
14496     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14497        data.first_frame_with_data) >=
14498        frame_set->n_frames)
14499     {
14500         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14501                             header_size);
14502     }
14503
14504     tng_block_destroy(&block);
14505
14506     return(TNG_SUCCESS);
14507 }
14508
14509 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
14510                 (tng_trajectory_t tng_data,
14511                  const int64_t frame_nr,
14512                  const int64_t block_id,
14513                  const int64_t val_first_particle,
14514                  const int64_t val_n_particles,
14515                  const void *values,
14516                  const char hash_mode)
14517 {
14518     int64_t header_pos, file_pos, tot_n_particles;
14519     int64_t output_file_len, n_values_per_frame, size, contents_size;
14520     int64_t header_size, temp_first, temp_last;
14521     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
14522     int64_t i, last_frame, temp_current;
14523     tng_gen_block_t block;
14524     tng_trajectory_frame_set_t frame_set;
14525     FILE *temp = tng_data->input_file;
14526     struct tng_particle_data data;
14527     tng_function_status stat;
14528     tng_particle_mapping_t mapping;
14529     char dependency, sparse_data, datatype;
14530     void *copy;
14531
14532     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14533     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14534     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14535     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
14536     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
14537
14538     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14539     {
14540         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14541                __FILE__, __LINE__);
14542         return(TNG_CRITICAL);
14543     }
14544
14545     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14546     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14547     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14548     tng_data->first_trajectory_frame_set_input_file_pos =
14549     tng_data->first_trajectory_frame_set_output_file_pos;
14550     tng_data->last_trajectory_frame_set_input_file_pos =
14551     tng_data->last_trajectory_frame_set_output_file_pos;
14552     tng_data->current_trajectory_frame_set_input_file_pos =
14553     tng_data->current_trajectory_frame_set_output_file_pos;
14554
14555     tng_data->input_file = tng_data->output_file;
14556
14557     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14558
14559     frame_set = &tng_data->current_trajectory_frame_set;
14560
14561     if(stat != TNG_SUCCESS)
14562     {
14563         last_frame = frame_set->first_frame +
14564                      frame_set->n_frames - 1;
14565 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
14566                   last_frame); */
14567         /* If the wanted frame would be in the frame set after the last
14568          * frame set create a new frame set. */
14569         if(stat == TNG_FAILURE &&
14570            (last_frame < frame_nr &&
14571             last_frame + tng_data->frame_set_n_frames >= frame_nr))
14572         {
14573             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14574             {
14575                 last_frame = frame_nr - 1;
14576             }
14577             tng_frame_set_new(tng_data,
14578                               last_frame+1,
14579                               tng_data->frame_set_n_frames);
14580
14581             file_pos = ftello(tng_data->output_file);
14582             fseeko(tng_data->output_file, 0, SEEK_END);
14583             output_file_len = ftello(tng_data->output_file);
14584             fseeko(tng_data->output_file, file_pos, SEEK_SET);
14585
14586             /* Read mapping blocks from the last frame set */
14587             tng_block_init(&block);
14588
14589             stat = tng_block_header_read(tng_data, block);
14590             while(file_pos < output_file_len &&
14591                   stat != TNG_CRITICAL &&
14592                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14593                   block->id != -1)
14594             {
14595                 if(block->id == TNG_PARTICLE_MAPPING)
14596                 {
14597                     tng_trajectory_mapping_block_read(tng_data, block,
14598                                                       hash_mode);
14599                 }
14600                 else
14601                 {
14602                     fseeko(tng_data->output_file, block->block_contents_size,
14603                         SEEK_CUR);
14604                 }
14605                 file_pos = ftello(tng_data->output_file);
14606                 if(file_pos < output_file_len)
14607                 {
14608                     stat = tng_block_header_read(tng_data, block);
14609                 }
14610             }
14611
14612             tng_block_destroy(&block);
14613             /* Write the frame set to disk */
14614             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14615             {
14616                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14617                 exit(1);
14618             }
14619         }
14620         else
14621         {
14622             tng_data->input_file = temp;
14623             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14624             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14625             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14626             return(stat);
14627         }
14628     }
14629
14630
14631     tng_block_init(&block);
14632
14633     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14634
14635     fseeko(tng_data->output_file, 0, SEEK_END);
14636     output_file_len = ftello(tng_data->output_file);
14637     fseeko(tng_data->output_file, file_pos, SEEK_SET);
14638
14639     /* Read past the frame set block first */
14640     stat = tng_block_header_read(tng_data, block);
14641     if(stat == TNG_CRITICAL)
14642     {
14643         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14644                file_pos, __FILE__, __LINE__);
14645         tng_block_destroy(&block);
14646         tng_data->input_file = temp;
14647
14648         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14649         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14650         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14651         return(stat);
14652     }
14653     fseeko(tng_data->output_file, block->block_contents_size,
14654             SEEK_CUR);
14655
14656     if(tng_data->var_num_atoms_flag)
14657     {
14658         tot_n_particles = frame_set->n_particles;
14659     }
14660     else
14661     {
14662         tot_n_particles = tng_data->n_particles;
14663     }
14664
14665     if(val_n_particles < tot_n_particles)
14666     {
14667         mapping_block_end_pos = -1;
14668         /* Read all mapping blocks to find the right place to put the data */
14669         stat = tng_block_header_read(tng_data, block);
14670         while(file_pos < output_file_len &&
14671                 stat != TNG_CRITICAL &&
14672                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14673                 block->id != -1)
14674         {
14675             if(block->id == TNG_PARTICLE_MAPPING)
14676             {
14677                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
14678             }
14679             else
14680             {
14681                 fseeko(tng_data->output_file, block->block_contents_size,
14682                       SEEK_CUR);
14683             }
14684             file_pos = ftello(tng_data->output_file);
14685             if(block->id == TNG_PARTICLE_MAPPING)
14686             {
14687                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
14688                 if(val_first_particle >= mapping->num_first_particle &&
14689                    val_first_particle < mapping->num_first_particle +
14690                    mapping->n_particles &&
14691                    val_first_particle + val_n_particles <=
14692                    mapping->num_first_particle + mapping->n_particles)
14693                 {
14694                     mapping_block_end_pos = file_pos;
14695                 }
14696             }
14697             if(file_pos < output_file_len)
14698             {
14699                 stat = tng_block_header_read(tng_data, block);
14700             }
14701         }
14702         if(stat == TNG_CRITICAL)
14703         {
14704             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14705                    file_pos, __FILE__, __LINE__);
14706             tng_block_destroy(&block);
14707             tng_data->input_file = temp;
14708
14709             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14710             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14711             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14712             return(stat);
14713         }
14714         if(mapping_block_end_pos < 0)
14715         {
14716             tng_block_destroy(&block);
14717             tng_data->input_file = temp;
14718
14719             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14720             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14721             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14722             return(TNG_FAILURE);
14723         }
14724         fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET);
14725     }
14726
14727     /* Read all block headers until next frame set block or
14728      * until the wanted block id is found */
14729     stat = tng_block_header_read(tng_data, block);
14730     while(file_pos < output_file_len &&
14731             stat != TNG_CRITICAL &&
14732             block->id != block_id &&
14733             block->id != TNG_PARTICLE_MAPPING &&
14734             block->id != TNG_TRAJECTORY_FRAME_SET &&
14735             block->id != -1)
14736     {
14737         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
14738         file_pos = ftello(tng_data->output_file);
14739         if(file_pos < output_file_len)
14740         {
14741             stat = tng_block_header_read(tng_data, block);
14742         }
14743     }
14744     if(stat == TNG_CRITICAL)
14745     {
14746         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14747                 file_pos, __FILE__, __LINE__);
14748         tng_block_destroy(&block);
14749         tng_data->input_file = temp;
14750
14751         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14752         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14753         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14754         return(stat);
14755     }
14756
14757     contents_size = block->block_contents_size;
14758     header_size = block->header_contents_size;
14759
14760     header_pos = ftello(tng_data->output_file) - header_size;
14761     frame_set = &tng_data->current_trajectory_frame_set;
14762
14763     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14764     {
14765         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14766         tng_block_destroy(&block);
14767         return(TNG_CRITICAL);
14768     }
14769
14770     data.datatype = datatype;
14771
14772     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14773     {
14774         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14775         tng_block_destroy(&block);
14776         return(TNG_CRITICAL);
14777     }
14778
14779     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14780        !(dependency & TNG_PARTICLE_DEPENDENT))
14781     {
14782         tng_block_destroy(&block);
14783         tng_data->input_file = temp;
14784
14785         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14786         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14787         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14788         return(TNG_FAILURE);
14789     }
14790
14791     if(fread(&sparse_data, sizeof(sparse_data), 1, tng_data->input_file) == 0)
14792     {
14793         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14794         tng_block_destroy(&block);
14795         return(TNG_CRITICAL);
14796     }
14797
14798     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14799              tng_data->input_file) == 0)
14800     {
14801         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14802         tng_block_destroy(&block);
14803         return(TNG_CRITICAL);
14804     }
14805     if(tng_data->output_endianness_swap_func_64)
14806     {
14807         if(tng_data->output_endianness_swap_func_64(tng_data,
14808             &data.n_values_per_frame)
14809             != TNG_SUCCESS)
14810         {
14811             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14812                     __FILE__, __LINE__);
14813         }
14814     }
14815
14816     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14817              tng_data->input_file) == 0)
14818     {
14819         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14820         tng_block_destroy(&block);
14821         return(TNG_CRITICAL);
14822     }
14823     if(tng_data->output_endianness_swap_func_64)
14824     {
14825         if(tng_data->output_endianness_swap_func_64(tng_data,
14826             &data.codec_id)
14827             != TNG_SUCCESS)
14828         {
14829             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14830                     __FILE__, __LINE__);
14831         }
14832     }
14833
14834     if(data.codec_id != TNG_UNCOMPRESSED)
14835     {
14836         if(fread(&data.compression_multiplier,
14837                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14838             == 0)
14839         {
14840             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14841             tng_block_destroy(&block);
14842             return(TNG_CRITICAL);
14843         }
14844
14845         if(tng_data->output_endianness_swap_func_64)
14846         {
14847             if(tng_data->output_endianness_swap_func_64(tng_data,
14848                (int64_t *)&data.compression_multiplier)
14849                 != TNG_SUCCESS)
14850             {
14851                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14852                         __FILE__, __LINE__);
14853             }
14854         }
14855     }
14856     else
14857     {
14858         data.compression_multiplier = 1;
14859     }
14860
14861     if(sparse_data)
14862     {
14863         if(fread(&data.first_frame_with_data,
14864                  sizeof(data.first_frame_with_data),
14865                  1, tng_data->input_file) == 0)
14866         {
14867             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14868             tng_block_destroy(&block);
14869             return(TNG_CRITICAL);
14870         }
14871         if(tng_data->output_endianness_swap_func_64)
14872         {
14873             if(tng_data->output_endianness_swap_func_64(tng_data,
14874                 &data.first_frame_with_data)
14875                 != TNG_SUCCESS)
14876             {
14877                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14878                         __FILE__, __LINE__);
14879             }
14880         }
14881
14882         if(fread(&data.stride_length, sizeof(data.stride_length),
14883                  1, tng_data->input_file) == 0)
14884         {
14885             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14886             tng_block_destroy(&block);
14887             return(TNG_CRITICAL);
14888         }
14889         if(tng_data->output_endianness_swap_func_64)
14890         {
14891             if(tng_data->output_endianness_swap_func_64(tng_data,
14892                 &data.stride_length)
14893                 != TNG_SUCCESS)
14894             {
14895                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14896                         __FILE__, __LINE__);
14897             }
14898         }
14899     }
14900     else
14901     {
14902         data.first_frame_with_data = 0;
14903         data.stride_length = 1;
14904     }
14905     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14906
14907     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14908              tng_data->input_file) == 0)
14909     {
14910         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14911         tng_block_destroy(&block);
14912         return(TNG_CRITICAL);
14913     }
14914     if(tng_data->output_endianness_swap_func_64)
14915     {
14916         if(tng_data->output_endianness_swap_func_64(tng_data,
14917             &num_first_particle)
14918             != TNG_SUCCESS)
14919         {
14920             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14921                     __FILE__, __LINE__);
14922         }
14923     }
14924
14925     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14926              tng_data->input_file) == 0)
14927     {
14928         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14929         tng_block_destroy(&block);
14930         return(TNG_CRITICAL);
14931     }
14932     if(tng_data->output_endianness_swap_func_64)
14933     {
14934         if(tng_data->output_endianness_swap_func_64(tng_data,
14935             &block_n_particles)
14936             != TNG_SUCCESS)
14937         {
14938             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14939                     __FILE__, __LINE__);
14940         }
14941     }
14942
14943
14944     tng_data->input_file = temp;
14945
14946     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14947     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14948     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14949
14950
14951     switch(data.datatype)
14952     {
14953         case(TNG_INT_DATA):
14954             size = sizeof(int64_t);
14955             break;
14956         case(TNG_FLOAT_DATA):
14957             size = sizeof(float);
14958             break;
14959         case(TNG_DOUBLE_DATA):
14960             size = sizeof(double);
14961             break;
14962         default:
14963             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14964                    __LINE__);
14965             tng_block_destroy(&block);
14966             return(TNG_FAILURE);
14967     }
14968
14969     n_values_per_frame = data.n_values_per_frame;
14970
14971     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14972                                data.first_frame_with_data)) /
14973                 data.stride_length;
14974     file_pos *= block_n_particles * size * n_values_per_frame;
14975
14976     if(file_pos > contents_size)
14977     {
14978         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14979                __LINE__);
14980         tng_block_destroy(&block);
14981         return(TNG_FAILURE);
14982     }
14983
14984     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
14985
14986     /* If the endianness is not big endian the data needs to be swapped */
14987     if((data.datatype == TNG_INT_DATA ||
14988         data.datatype == TNG_DOUBLE_DATA) &&
14989        tng_data->output_endianness_swap_func_64)
14990     {
14991         copy = malloc(val_n_particles * n_values_per_frame * size);
14992         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
14993         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
14994         {
14995             if(tng_data->output_endianness_swap_func_64(tng_data,
14996                 (int64_t *) copy+i)
14997                 != TNG_SUCCESS)
14998             {
14999                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
15000                         __FILE__, __LINE__);
15001             }
15002         }
15003         fwrite(copy, val_n_particles * n_values_per_frame, size,
15004                tng_data->output_file);
15005         free(copy);
15006     }
15007     else if(data.datatype == TNG_FLOAT_DATA &&
15008        tng_data->output_endianness_swap_func_32)
15009     {
15010         copy = malloc(val_n_particles * n_values_per_frame * size);
15011         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
15012         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
15013         {
15014             if(tng_data->output_endianness_swap_func_32(tng_data,
15015                 (int32_t *) copy+i)
15016                 != TNG_SUCCESS)
15017             {
15018                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
15019                         __FILE__, __LINE__);
15020             }
15021         }
15022         fwrite(copy, val_n_particles * n_values_per_frame, size,
15023                tng_data->output_file);
15024         free(copy);
15025     }
15026
15027     else
15028     {
15029         fwrite(values, val_n_particles * n_values_per_frame, size,
15030                tng_data->output_file);
15031     }
15032     fflush(tng_data->output_file);
15033
15034     /* Update the number of written frames in the frame set. */
15035     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
15036     {
15037         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
15038     }
15039
15040     /* If the last frame has been written update the hash */
15041     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
15042        data.first_frame_with_data) >=
15043        frame_set->n_frames)
15044     {
15045         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
15046                             header_size);
15047     }
15048
15049     tng_block_destroy(&block);
15050     return(TNG_SUCCESS);
15051 }
15052
15053 static tng_function_status tng_data_values_alloc
15054                 (const tng_trajectory_t tng_data,
15055                  union data_values ***values,
15056                  const int64_t n_frames,
15057                  const int64_t n_values_per_frame,
15058                  const char type)
15059 {
15060     int64_t i;
15061     tng_function_status stat;
15062
15063     if(n_frames <= 0 || n_values_per_frame <= 0)
15064     {
15065         return(TNG_FAILURE);
15066     }
15067
15068     if(*values)
15069     {
15070         stat = tng_data_values_free(tng_data, *values, n_frames,
15071                                     n_values_per_frame,
15072                                     type);
15073         if(stat != TNG_SUCCESS)
15074         {
15075             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15076                    __FILE__, __LINE__);
15077             return(stat);
15078         }
15079     }
15080     *values = malloc(sizeof(union data_values *) * n_frames);
15081     if(!*values)
15082     {
15083         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15084                sizeof(union data_values **) * n_frames,
15085                __FILE__, __LINE__);
15086         return(TNG_CRITICAL);
15087
15088     }
15089
15090     for(i = 0; i < n_frames; i++)
15091     {
15092         (*values)[i] = malloc(sizeof(union data_values) *
15093                            n_values_per_frame);
15094         if(!(*values)[i])
15095         {
15096             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15097                    sizeof(union data_values) * n_values_per_frame,
15098                    __FILE__, __LINE__);
15099             free(values);
15100             values = 0;
15101             return(TNG_CRITICAL);
15102         }
15103     }
15104     return(TNG_SUCCESS);
15105 }
15106
15107 /* FIXME: This needs ***values */
15108 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
15109                 (const tng_trajectory_t tng_data,
15110                  union data_values **values,
15111                  const int64_t n_frames,
15112                  const int64_t n_values_per_frame,
15113                  const char type)
15114 {
15115     int64_t i, j;
15116     (void)tng_data;
15117
15118     if(values)
15119     {
15120         for(i = 0; i < n_frames; i++)
15121         {
15122             if(values[i])
15123             {
15124                 if(type == TNG_CHAR_DATA)
15125                 {
15126                     for(j = 0; j < n_values_per_frame; j++)
15127                     {
15128                         if(values[i][j].c)
15129                         {
15130                             free(values[i][j].c);
15131                             values[i][j].c = 0;
15132                         }
15133                     }
15134                 }
15135                 free(values[i]);
15136                 values[i] = 0;
15137             }
15138         }
15139         free(values);
15140         values = 0;
15141     }
15142
15143     return(TNG_SUCCESS);
15144 }
15145
15146 static tng_function_status tng_particle_data_values_alloc
15147                 (const tng_trajectory_t tng_data,
15148                  union data_values ****values,
15149                  const int64_t n_frames,
15150                  const int64_t n_particles,
15151                  const int64_t n_values_per_frame,
15152                  const char type)
15153 {
15154     int64_t i, j;
15155     tng_function_status stat;
15156
15157     if(n_particles == 0 || n_values_per_frame == 0)
15158     {
15159         return(TNG_FAILURE);
15160     }
15161
15162     if(*values)
15163     {
15164         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
15165                                              n_particles, n_values_per_frame,
15166                                              type);
15167         if(stat != TNG_SUCCESS)
15168         {
15169             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15170                    __FILE__, __LINE__);
15171             return(stat);
15172         }
15173     }
15174     *values = malloc(sizeof(union data_values **) * n_frames);
15175     if(!*values)
15176     {
15177         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15178                sizeof(union data_values **) * n_frames,
15179                __FILE__, __LINE__);
15180         return(TNG_CRITICAL);
15181
15182     }
15183
15184     for(i = 0; i < n_frames; i++)
15185     {
15186         (*values)[i] = malloc(sizeof(union data_values *) *
15187                            n_particles);
15188         if(!(*values)[i])
15189         {
15190             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15191                    sizeof(union data_values *) * n_particles,
15192                    __FILE__, __LINE__);
15193             free(*values);
15194             *values = 0;
15195             return(TNG_CRITICAL);
15196         }
15197         for(j = 0; j < n_particles; j++)
15198         {
15199             (*values)[i][j] = malloc(sizeof(union data_values) *
15200                                   n_values_per_frame);
15201             if(!(*values)[i][j])
15202             {
15203                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15204                     sizeof(union data_values *) * n_particles,
15205                     __FILE__, __LINE__);
15206                 tng_particle_data_values_free(tng_data, *values, n_frames,
15207                                               n_particles, n_values_per_frame,
15208                                               type);
15209                 *values = 0;
15210                 return(TNG_CRITICAL);
15211             }
15212         }
15213     }
15214     return(TNG_SUCCESS);
15215 }
15216
15217 /* FIXME: This needs ****values */
15218 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
15219                 (const tng_trajectory_t tng_data,
15220                  union data_values ***values,
15221                  const int64_t n_frames,
15222                  const int64_t n_particles,
15223                  const int64_t n_values_per_frame,
15224                  const char type)
15225 {
15226     int64_t i, j, k;
15227     (void)tng_data;
15228
15229     if(values)
15230     {
15231         for(i = 0; i < n_frames; i++)
15232         {
15233             if(values[i])
15234             {
15235                 for(j = 0; j < n_particles; j++)
15236                 {
15237                     if(type == TNG_CHAR_DATA)
15238                     {
15239                         for(k = 0; k < n_values_per_frame; k++)
15240                         {
15241                             if(values[i][j][k].c)
15242                             {
15243                                 free(values[i][j][k].c);
15244                                 values[i][j][k].c = 0;
15245                             }
15246                         }
15247                     }
15248                     free(values[i][j]);
15249                     values[i][j] = 0;
15250                 }
15251                 free(values[i]);
15252                 values[i] = 0;
15253             }
15254         }
15255         free(values);
15256         values = 0;
15257     }
15258
15259     return(TNG_SUCCESS);
15260 }
15261
15262
15263 tng_function_status DECLSPECDLLEXPORT tng_data_get
15264                 (tng_trajectory_t tng_data,
15265                  const int64_t block_id,
15266                  union data_values ***values,
15267                  int64_t *n_frames,
15268                  int64_t *n_values_per_frame,
15269                  char *type)
15270 {
15271     int64_t i, j, file_pos, block_index;
15272     int size;
15273     size_t len;
15274     tng_non_particle_data_t data;
15275     tng_trajectory_frame_set_t frame_set;
15276     tng_gen_block_t block;
15277     tng_function_status stat;
15278
15279     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15280     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15281     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15282     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15283
15284     frame_set = &tng_data->current_trajectory_frame_set;
15285
15286     block_index = -1;
15287     data = 0;
15288
15289     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15290     {
15291         tng_block_init(&block);
15292         file_pos = ftello(tng_data->input_file);
15293         /* Read all blocks until next frame set block */
15294         stat = tng_block_header_read(tng_data, block);
15295         while(file_pos < tng_data->input_file_len &&
15296                 stat != TNG_CRITICAL &&
15297                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15298                 block->id != -1)
15299         {
15300             /* Use hash by default */
15301             stat = tng_block_read_next(tng_data, block,
15302                                     TNG_USE_HASH);
15303             if(stat != TNG_CRITICAL)
15304             {
15305                 file_pos = ftello(tng_data->input_file);
15306                 if(file_pos < tng_data->input_file_len)
15307                 {
15308                     stat = tng_block_header_read(tng_data, block);
15309                 }
15310             }
15311         }
15312         tng_block_destroy(&block);
15313         if(stat == TNG_CRITICAL)
15314         {
15315             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15316                     file_pos, __FILE__, __LINE__);
15317             return(stat);
15318         }
15319
15320         for(i = 0; i < frame_set->n_data_blocks; i++)
15321         {
15322             data = &frame_set->tr_data[i];
15323             if(data->block_id == block_id)
15324             {
15325                 block_index = i;
15326                 break;
15327             }
15328         }
15329         if(block_index < 0)
15330         {
15331             return(TNG_FAILURE);
15332         }
15333     }
15334
15335     *n_frames = tng_max_i64(1, data->n_frames);
15336     *n_values_per_frame = data->n_values_per_frame;
15337     *type = data->datatype;
15338
15339     if(*values == 0)
15340     {
15341         if(tng_data_values_alloc(tng_data, values, *n_frames,
15342                                  *n_values_per_frame,
15343                                  *type)
15344         != TNG_SUCCESS)
15345         {
15346             return(TNG_CRITICAL);
15347         }
15348     }
15349
15350     switch(*type)
15351     {
15352     case TNG_CHAR_DATA:
15353         for(i = 0; i < *n_frames; i++)
15354         {
15355             for(j = 0; j < *n_values_per_frame; j++)
15356             {
15357                 len = strlen(data->strings[i][j]) + 1;
15358                 (*values)[i][j].c = malloc(len);
15359                 strncpy((*values)[i][j].c, data->strings[i][j], len);
15360             }
15361         }
15362         break;
15363     case TNG_INT_DATA:
15364         size = sizeof(int);
15365         for(i = 0; i < *n_frames; i++)
15366         {
15367             for(j = 0; j < *n_values_per_frame; j++)
15368             {
15369                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15370                                              (i*(*n_values_per_frame) + j));
15371             }
15372         }
15373         break;
15374     case TNG_FLOAT_DATA:
15375         size = sizeof(float);
15376         for(i = 0; i < *n_frames; i++)
15377         {
15378             for(j = 0; j < *n_values_per_frame; j++)
15379             {
15380                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15381                                                (i*(*n_values_per_frame) + j));
15382             }
15383         }
15384         break;
15385     case TNG_DOUBLE_DATA:
15386     default:
15387         size = sizeof(double);
15388         for(i = 0; i < *n_frames; i++)
15389         {
15390             for(j = 0; j < *n_values_per_frame; j++)
15391             {
15392                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15393                                                 (i*(*n_values_per_frame) + j));
15394             }
15395         }
15396     }
15397
15398     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15399
15400     return(TNG_SUCCESS);
15401 }
15402
15403 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
15404                                         const int64_t block_id,
15405                                         void **values,
15406                                         int64_t *n_frames,
15407                                         int64_t *stride_length,
15408                                         int64_t *n_values_per_frame,
15409                                         char *type)
15410 {
15411     int64_t file_pos, data_size, n_frames_div, block_index;
15412     int i, size;
15413     tng_non_particle_data_t data;
15414     tng_trajectory_frame_set_t frame_set;
15415     tng_gen_block_t block;
15416     void *temp;
15417     tng_function_status stat;
15418
15419     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15420     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15421     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15422     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15423     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15424
15425     frame_set = &tng_data->current_trajectory_frame_set;
15426
15427     block_index = -1;
15428     data = 0;
15429
15430     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15431     {
15432         tng_block_init(&block);
15433         file_pos = ftello(tng_data->input_file);
15434         /* Read all blocks until next frame set block */
15435         stat = tng_block_header_read(tng_data, block);
15436         while(file_pos < tng_data->input_file_len &&
15437                 stat != TNG_CRITICAL &&
15438                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15439                 block->id != -1)
15440         {
15441             /* Use hash by default */
15442             stat = tng_block_read_next(tng_data, block,
15443                                     TNG_USE_HASH);
15444             if(stat != TNG_CRITICAL)
15445             {
15446                 file_pos = ftello(tng_data->input_file);
15447                 if(file_pos < tng_data->input_file_len)
15448                 {
15449                     stat = tng_block_header_read(tng_data, block);
15450                 }
15451             }
15452         }
15453         tng_block_destroy(&block);
15454         if(stat == TNG_CRITICAL)
15455         {
15456             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15457                     file_pos, __FILE__, __LINE__);
15458             return(stat);
15459         }
15460
15461         for(i = 0; i < frame_set->n_data_blocks; i++)
15462         {
15463             data = &frame_set->tr_data[i];
15464             if(data->block_id == block_id)
15465             {
15466                 block_index = i;
15467                 break;
15468             }
15469         }
15470         if(block_index < 0)
15471         {
15472             return(TNG_FAILURE);
15473         }
15474     }
15475
15476     *type = data->datatype;
15477
15478     switch(*type)
15479     {
15480     case TNG_CHAR_DATA:
15481         return(TNG_FAILURE);
15482     case TNG_INT_DATA:
15483         size = sizeof(int64_t);
15484         break;
15485     case TNG_FLOAT_DATA:
15486         size = sizeof(float);
15487         break;
15488     case TNG_DOUBLE_DATA:
15489     default:
15490         size = sizeof(double);
15491     }
15492
15493     *n_frames = data->n_frames;
15494     *n_values_per_frame = data->n_values_per_frame;
15495     *stride_length = data->stride_length;
15496     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
15497                    *n_frames / *stride_length;
15498
15499     data_size = n_frames_div * size *
15500                 *n_values_per_frame;
15501
15502     temp = realloc(*values, data_size);
15503     if(!temp)
15504     {
15505         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15506                data_size, __FILE__, __LINE__);
15507         free(*values);
15508         *values = 0;
15509         return(TNG_CRITICAL);
15510     }
15511
15512     *values = temp;
15513
15514     memcpy(*values, data->values, data_size);
15515
15516     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15517
15518     return(TNG_SUCCESS);
15519 }
15520
15521 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
15522                 (tng_trajectory_t tng_data,
15523                  const int64_t block_id,
15524                  const int64_t start_frame_nr,
15525                  const int64_t end_frame_nr,
15526                  const char hash_mode,
15527                  union data_values ***values,
15528                  int64_t *n_values_per_frame,
15529                  char *type)
15530 {
15531     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
15532     int64_t block_index;
15533     int size;
15534     size_t len;
15535     tng_non_particle_data_t data;
15536     tng_trajectory_frame_set_t frame_set;
15537     tng_gen_block_t block;
15538     tng_function_status stat;
15539
15540     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15541     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15542     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15543     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15544
15545     block_index = -1;
15546
15547     frame_set = &tng_data->current_trajectory_frame_set;
15548     first_frame = frame_set->first_frame;
15549
15550     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15551     if(stat != TNG_SUCCESS)
15552     {
15553         return(stat);
15554     }
15555
15556
15557     /* Do not re-read the frame set. */
15558     if(first_frame != frame_set->first_frame ||
15559        frame_set->n_data_blocks <= 0)
15560     {
15561         tng_block_init(&block);
15562         file_pos = ftello(tng_data->input_file);
15563         /* Read all blocks until next frame set block */
15564         stat = tng_block_header_read(tng_data, block);
15565         while(file_pos < tng_data->input_file_len &&
15566             stat != TNG_CRITICAL &&
15567             block->id != TNG_TRAJECTORY_FRAME_SET &&
15568             block->id != -1)
15569         {
15570             stat = tng_block_read_next(tng_data, block,
15571                                     hash_mode);
15572             if(stat != TNG_CRITICAL)
15573             {
15574                 file_pos = ftello(tng_data->input_file);
15575                 if(file_pos < tng_data->input_file_len)
15576                 {
15577                     stat = tng_block_header_read(tng_data, block);
15578                 }
15579             }
15580         }
15581         tng_block_destroy(&block);
15582         if(stat == TNG_CRITICAL)
15583         {
15584             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15585                     file_pos, __FILE__, __LINE__);
15586             return(stat);
15587         }
15588     }
15589
15590
15591     /* See if there is a data block of this ID.
15592      * Start checking the last read frame set */
15593     for(i = 0; i < frame_set->n_data_blocks; i++)
15594     {
15595         data = &frame_set->tr_data[i];
15596         if(data->block_id == block_id)
15597         {
15598             block_index = i;
15599             break;
15600         }
15601     }
15602
15603     if(block_index < 0)
15604     {
15605         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
15606                 block_id, __FILE__, __LINE__);
15607         return(TNG_FAILURE);
15608     }
15609
15610     n_frames = end_frame_nr - start_frame_nr + 1;
15611     *n_values_per_frame = data->n_values_per_frame;
15612     *type = data->datatype;
15613
15614     if(*values == 0)
15615     {
15616         if(tng_data_values_alloc(tng_data, values, n_frames,
15617                                  *n_values_per_frame,
15618                                  *type) != TNG_SUCCESS)
15619         {
15620             return(TNG_CRITICAL);
15621         }
15622     }
15623
15624     current_frame_pos = start_frame_nr - frame_set->first_frame;
15625     /* It's not very elegant to reuse so much of the code in the different case
15626      * statements, but it's unnecessarily slow to have the switch-case block
15627      * inside the for loops. */
15628     switch(*type)
15629     {
15630     case TNG_CHAR_DATA:
15631         for(i=0; i<n_frames; i++)
15632         {
15633             if(current_frame_pos == frame_set->n_frames)
15634             {
15635                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15636                 if(stat != TNG_SUCCESS)
15637                 {
15638                     return(stat);
15639                 }
15640                 current_frame_pos = 0;
15641             }
15642             for(j = 0; j < *n_values_per_frame; j++)
15643             {
15644                 len = strlen(data->strings[current_frame_pos][j]) + 1;
15645                 (*values)[i][j].c = malloc(len);
15646                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
15647             }
15648             current_frame_pos++;
15649         }
15650         break;
15651     case TNG_INT_DATA:
15652         size = sizeof(int);
15653         for(i=0; i<n_frames; i++)
15654         {
15655             if(current_frame_pos == frame_set->n_frames)
15656             {
15657                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15658                 if(stat != TNG_SUCCESS)
15659                 {
15660                     return(stat);
15661                 }
15662                 current_frame_pos = 0;
15663             }
15664             for(j = 0; j < *n_values_per_frame; j++)
15665             {
15666                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15667                                             (current_frame_pos *
15668                                              (*n_values_per_frame) + j));
15669             }
15670             current_frame_pos++;
15671         }
15672         break;
15673     case TNG_FLOAT_DATA:
15674         size = sizeof(float);
15675         for(i=0; i<n_frames; i++)
15676         {
15677             if(current_frame_pos == frame_set->n_frames)
15678             {
15679                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15680                 if(stat != TNG_SUCCESS)
15681                 {
15682                     return(stat);
15683                 }
15684                 current_frame_pos = 0;
15685             }
15686             for(j = 0; j < *n_values_per_frame; j++)
15687             {
15688                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15689                                                (current_frame_pos *
15690                                                 (*n_values_per_frame) + j));
15691             }
15692             current_frame_pos++;
15693         }
15694         break;
15695     case TNG_DOUBLE_DATA:
15696     default:
15697         size = sizeof(double);
15698         for(i=0; i<n_frames; i++)
15699         {
15700             if(current_frame_pos == frame_set->n_frames)
15701             {
15702                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15703                 if(stat != TNG_SUCCESS)
15704                 {
15705                     return(stat);
15706                 }
15707                 current_frame_pos = 0;
15708             }
15709             for(j = 0; j < *n_values_per_frame; j++)
15710             {
15711                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15712                                                 (current_frame_pos *
15713                                                  (*n_values_per_frame) + j));
15714             }
15715             current_frame_pos++;
15716         }
15717     }
15718
15719     data->last_retrieved_frame = end_frame_nr;
15720
15721     return(TNG_SUCCESS);
15722 }
15723
15724 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
15725                 (tng_trajectory_t tng_data,
15726                  const int64_t block_id,
15727                  const int64_t start_frame_nr,
15728                  const int64_t end_frame_nr,
15729                  const char hash_mode,
15730                  void **values,
15731                  int64_t *stride_length,
15732                  int64_t *n_values_per_frame,
15733                  char *type)
15734 {
15735     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15736     int64_t file_pos, current_frame_pos, data_size, frame_size;
15737     int64_t last_frame_pos;
15738     int size;
15739     tng_trajectory_frame_set_t frame_set;
15740     tng_non_particle_data_t np_data;
15741     tng_gen_block_t block;
15742     void *current_values = 0, *temp;
15743     tng_function_status stat;
15744
15745     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15746     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15747     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15748     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15749     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15750
15751     frame_set = &tng_data->current_trajectory_frame_set;
15752     first_frame = frame_set->first_frame;
15753
15754     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15755     if(stat != TNG_SUCCESS)
15756     {
15757         return(stat);
15758     }
15759
15760     /* Do not re-read the frame set and only need the requested block. */
15761     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
15762     stat = tng_data_find(tng_data, block_id, &np_data);
15763     if(first_frame != frame_set->first_frame ||
15764        stat != TNG_SUCCESS)
15765     {
15766         tng_block_init(&block);
15767         if(stat != TNG_SUCCESS)
15768         {
15769             fseeko(tng_data->input_file,
15770                    tng_data->current_trajectory_frame_set_input_file_pos,
15771                    SEEK_SET);
15772             stat = tng_block_header_read(tng_data, block);
15773             if(stat != TNG_SUCCESS)
15774             {
15775                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15776                         __FILE__, __LINE__);
15777                 return(stat);
15778             }
15779
15780             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
15781         }
15782         file_pos = ftello(tng_data->input_file);
15783         /* Read until next frame set block */
15784         stat = tng_block_header_read(tng_data, block);
15785         while(file_pos < tng_data->input_file_len &&
15786             stat != TNG_CRITICAL &&
15787             block->id != TNG_TRAJECTORY_FRAME_SET &&
15788             block->id != -1)
15789         {
15790             if(block->id == block_id)
15791             {
15792                 stat = tng_block_read_next(tng_data, block,
15793                                         hash_mode);
15794                 if(stat != TNG_CRITICAL)
15795                 {
15796                     file_pos = ftello(tng_data->input_file);
15797                     if(file_pos < tng_data->input_file_len)
15798                     {
15799                         stat = tng_block_header_read(tng_data, block);
15800                     }
15801                 }
15802             }
15803             else
15804             {
15805                 file_pos += block->block_contents_size + block->header_contents_size;
15806                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
15807                 if(file_pos < tng_data->input_file_len)
15808                 {
15809                     stat = tng_block_header_read(tng_data, block);
15810                 }
15811             }
15812         }
15813         tng_block_destroy(&block);
15814         if(stat == TNG_CRITICAL)
15815         {
15816             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15817                     file_pos, __FILE__, __LINE__);
15818             return(stat);
15819         }
15820     }
15821
15822     stat = tng_data_find(tng_data, block_id, &np_data);
15823     if(stat != TNG_SUCCESS)
15824     {
15825         return(stat);
15826     }
15827
15828     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15829                                &n_frames, stride_length,
15830                                n_values_per_frame, type);
15831
15832     if(stat != TNG_SUCCESS)
15833     {
15834         if(current_values)
15835         {
15836             free(current_values);
15837         }
15838         return(stat);
15839     }
15840
15841     if(n_frames == 1 && n_frames < frame_set->n_frames)
15842     {
15843         tot_n_frames = 1;
15844     }
15845     else
15846     {
15847         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15848     }
15849
15850     switch(*type)
15851     {
15852     case TNG_CHAR_DATA:
15853         return(TNG_FAILURE);
15854     case TNG_INT_DATA:
15855         size = sizeof(int64_t);
15856         break;
15857     case TNG_FLOAT_DATA:
15858         size = sizeof(float);
15859         break;
15860     case TNG_DOUBLE_DATA:
15861     default:
15862         size = sizeof(double);
15863     }
15864
15865     n_frames_div = (tot_n_frames % *stride_length) ?
15866                  tot_n_frames / *stride_length + 1:
15867                  tot_n_frames / *stride_length;
15868     data_size = n_frames_div * size * (*n_values_per_frame);
15869
15870 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15871               size, n_frames_div, data_size);
15872 */
15873     temp = realloc(*values, data_size);
15874     if(!temp)
15875     {
15876         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15877                data_size, __FILE__, __LINE__);
15878         free(*values);
15879         *values = 0;
15880         return(TNG_CRITICAL);
15881     }
15882
15883     *values = temp;
15884
15885     if( n_frames == 1 && n_frames < frame_set->n_frames)
15886     {
15887         memcpy(*values, current_values, size * (*n_values_per_frame));
15888     }
15889     else
15890     {
15891         current_frame_pos = start_frame_nr - frame_set->first_frame;
15892
15893         frame_size = size * (*n_values_per_frame);
15894
15895         last_frame_pos = tng_min_i64(n_frames,
15896                                      end_frame_nr - start_frame_nr);
15897
15898         n_frames_div = current_frame_pos / *stride_length;
15899         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15900                        last_frame_pos / *stride_length + 1:
15901                        last_frame_pos / *stride_length;
15902         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15903
15904         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15905                n_frames_div_2 * frame_size);
15906
15907         current_frame_pos += n_frames - current_frame_pos;
15908
15909         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15910         {
15911             stat = tng_frame_set_read_next(tng_data, hash_mode);
15912             if(stat != TNG_SUCCESS)
15913             {
15914                 if(current_values)
15915                 {
15916                     free(current_values);
15917                 }
15918                 free(*values);
15919                 *values = 0;
15920                 return(stat);
15921             }
15922
15923             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15924                                     &n_frames, stride_length,
15925                                     n_values_per_frame, type);
15926
15927             if(stat != TNG_SUCCESS)
15928             {
15929                 if(current_values)
15930                 {
15931                     free(current_values);
15932                 }
15933                 free(*values);
15934                 *values = 0;
15935                 return(stat);
15936             }
15937
15938             last_frame_pos = tng_min_i64(n_frames,
15939                                          end_frame_nr - current_frame_pos);
15940
15941             n_frames_div = current_frame_pos / *stride_length;
15942             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15943                            last_frame_pos / *stride_length + 1:
15944                            last_frame_pos / *stride_length;
15945             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15946
15947             memcpy(((char *)*values) + n_frames_div * frame_size,
15948                    current_values,
15949                    n_frames_div_2 * frame_size);
15950
15951             current_frame_pos += n_frames;
15952         }
15953     }
15954
15955     if(current_values)
15956     {
15957         free(current_values);
15958     }
15959
15960     np_data->last_retrieved_frame = end_frame_nr;
15961
15962     return(TNG_SUCCESS);
15963 }
15964
15965 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15966                 (tng_trajectory_t tng_data,
15967                  const int64_t block_id,
15968                  union data_values ****values,
15969                  int64_t *n_frames,
15970                  int64_t *n_particles,
15971                  int64_t *n_values_per_frame,
15972                  char *type)
15973 {
15974     int64_t i, j, k, mapping, file_pos, i_step, block_index;
15975     int size;
15976     size_t len;
15977     tng_particle_data_t data;
15978     tng_trajectory_frame_set_t frame_set;
15979     tng_gen_block_t block;
15980     char block_type_flag;
15981     tng_function_status stat;
15982
15983     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15984     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15985     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15986     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15987     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15988
15989     frame_set = &tng_data->current_trajectory_frame_set;
15990
15991     block_index = -1;
15992     data = 0;
15993
15994     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15995     {
15996         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
15997         {
15998             block_type_flag = TNG_TRAJECTORY_BLOCK;
15999         }
16000         else
16001         {
16002             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16003         }
16004
16005         tng_block_init(&block);
16006         file_pos = ftello(tng_data->input_file);
16007         /* Read all blocks until next frame set block */
16008         stat = tng_block_header_read(tng_data, block);
16009         while(file_pos < tng_data->input_file_len &&
16010                 stat != TNG_CRITICAL &&
16011                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16012                 block->id != -1)
16013         {
16014             /* Use hash by default */
16015             stat = tng_block_read_next(tng_data, block,
16016                                     TNG_USE_HASH);
16017             if(stat != TNG_CRITICAL)
16018             {
16019                 file_pos = ftello(tng_data->input_file);
16020                 if(file_pos < tng_data->input_file_len)
16021                 {
16022                     stat = tng_block_header_read(tng_data, block);
16023                 }
16024             }
16025         }
16026         tng_block_destroy(&block);
16027         if(stat == TNG_CRITICAL)
16028         {
16029             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16030                     file_pos, __FILE__, __LINE__);
16031             return(stat);
16032         }
16033
16034         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16035         {
16036             data = &frame_set->tr_particle_data[i];
16037             if(data->block_id == block_id)
16038             {
16039                 block_index = i;
16040                 block_type_flag = TNG_TRAJECTORY_BLOCK;
16041                 break;
16042             }
16043         }
16044         if(block_index < 0)
16045         {
16046             return(TNG_FAILURE);
16047         }
16048     }
16049     else
16050     {
16051         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16052         {
16053             block_type_flag = TNG_TRAJECTORY_BLOCK;
16054         }
16055         else
16056         {
16057             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16058         }
16059     }
16060
16061     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16062        tng_data->var_num_atoms_flag)
16063     {
16064         *n_particles = frame_set->n_particles;
16065     }
16066     else
16067     {
16068         *n_particles = tng_data->n_particles;
16069     }
16070
16071     *n_frames = tng_max_i64(1, data->n_frames);
16072     *n_values_per_frame = data->n_values_per_frame;
16073     *type = data->datatype;
16074
16075     if(*values == 0)
16076     {
16077         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
16078                                          *n_particles, *n_values_per_frame,
16079                                          *type)
16080             != TNG_SUCCESS)
16081         {
16082             return(TNG_CRITICAL);
16083         }
16084     }
16085
16086     /* It's not very elegant to reuse so much of the code in the different case
16087      * statements, but it's unnecessarily slow to have the switch-case block
16088      * inside the for loops. */
16089     switch(*type)
16090     {
16091     case TNG_CHAR_DATA:
16092         for(i = 0; i < *n_frames; i++)
16093         {
16094             for(j = 0; j < *n_particles; j++)
16095             {
16096                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16097                 for(k = 0; k < *n_values_per_frame; k++)
16098                 {
16099                     len = strlen(data->strings[i][j][k]) + 1;
16100                     (*values)[i][mapping][k].c = malloc(len);
16101                     strncpy((*values)[i][mapping][k].c,
16102                             data->strings[i][j][k], len);
16103                 }
16104             }
16105         }
16106         break;
16107     case TNG_INT_DATA:
16108         size = sizeof(int);
16109         i_step = (*n_particles) * (*n_values_per_frame);
16110         for(i = 0; i < *n_frames; i++)
16111         {
16112             for(j = 0; j < *n_particles; j++)
16113             {
16114                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16115                 for(k = 0; k < *n_values_per_frame; k++)
16116                 {
16117                     (*values)[i][mapping][k].i = *(int *)
16118                                                  ((char *)data->values + size *
16119                                                  (i * i_step + j *
16120                                                   (*n_values_per_frame) + k));
16121                 }
16122             }
16123         }
16124         break;
16125     case TNG_FLOAT_DATA:
16126         size = sizeof(float);
16127         i_step = (*n_particles) * (*n_values_per_frame);
16128         for(i = 0; i < *n_frames; i++)
16129         {
16130             for(j = 0; j < *n_particles; j++)
16131             {
16132                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16133                 for(k = 0; k < *n_values_per_frame; k++)
16134                 {
16135                     (*values)[i][mapping][k].f = *(float *)
16136                                                  ((char *)data->values + size *
16137                                                  (i * i_step + j *
16138                                                   (*n_values_per_frame) + k));
16139                 }
16140             }
16141         }
16142         break;
16143     case TNG_DOUBLE_DATA:
16144     default:
16145         size = sizeof(double);
16146         i_step = (*n_particles) * (*n_values_per_frame);
16147         for(i = 0; i < *n_frames; i++)
16148         {
16149             for(j = 0; j < *n_particles; j++)
16150             {
16151                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16152                 for(k = 0; k < *n_values_per_frame; k++)
16153                 {
16154                     (*values)[i][mapping][k].d = *(double *)
16155                                                  ((char *)data->values + size *
16156                                                  (i * i_step + j *
16157                                                   (*n_values_per_frame) + k));
16158                 }
16159             }
16160         }
16161     }
16162
16163     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16164
16165     return(TNG_SUCCESS);
16166 }
16167
16168 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
16169                 (tng_trajectory_t tng_data,
16170                  const int64_t block_id,
16171                  void **values,
16172                  int64_t *n_frames,
16173                  int64_t *stride_length,
16174                  int64_t *n_particles,
16175                  int64_t *n_values_per_frame,
16176                  char *type)
16177 {
16178     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
16179     int64_t block_index;
16180     int size;
16181     tng_particle_data_t data;
16182     tng_trajectory_frame_set_t frame_set;
16183     tng_gen_block_t block;
16184     void *temp;
16185     char block_type_flag;
16186     tng_function_status stat;
16187
16188     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16189     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16190     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16191     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16192     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16193
16194     frame_set = &tng_data->current_trajectory_frame_set;
16195
16196     block_index = -1;
16197     data = 0;
16198
16199     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16200     {
16201         tng_block_init(&block);
16202         file_pos = ftello(tng_data->input_file);
16203         /* Read all blocks until next frame set block */
16204         stat = tng_block_header_read(tng_data, block);
16205         while(file_pos < tng_data->input_file_len &&
16206                 stat != TNG_CRITICAL &&
16207                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16208                 block->id != -1)
16209         {
16210             /* Use hash by default */
16211             stat = tng_block_read_next(tng_data, block,
16212                                     TNG_USE_HASH);
16213             if(stat != TNG_CRITICAL)
16214             {
16215                 file_pos = ftello(tng_data->input_file);
16216                 if(file_pos < tng_data->input_file_len)
16217                 {
16218                     stat = tng_block_header_read(tng_data, block);
16219                 }
16220             }
16221         }
16222         tng_block_destroy(&block);
16223         if(stat == TNG_CRITICAL)
16224         {
16225             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16226                     file_pos, __FILE__, __LINE__);
16227             return(stat);
16228         }
16229
16230         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16231         {
16232             data = &frame_set->tr_particle_data[i];
16233             if(data->block_id == block_id)
16234             {
16235                 block_index = i;
16236                 break;
16237             }
16238         }
16239         if(block_index < 0)
16240         {
16241             return(TNG_FAILURE);
16242         }
16243     }
16244
16245     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16246     {
16247         block_type_flag = TNG_TRAJECTORY_BLOCK;
16248     }
16249     else
16250     {
16251         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16252     }
16253
16254    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16255       tng_data->var_num_atoms_flag)
16256     {
16257         *n_particles = frame_set->n_particles;
16258     }
16259     else
16260     {
16261         *n_particles = tng_data->n_particles;
16262     }
16263
16264     *type = data->datatype;
16265
16266     switch(*type)
16267     {
16268     case TNG_CHAR_DATA:
16269         return(TNG_FAILURE);
16270     case TNG_INT_DATA:
16271         size = sizeof(int64_t);
16272         break;
16273     case TNG_FLOAT_DATA:
16274         size = sizeof(float);
16275         break;
16276     case TNG_DOUBLE_DATA:
16277     default:
16278         size = sizeof(double);
16279     }
16280
16281     *n_frames = tng_max_i64(1, data->n_frames);
16282     *n_values_per_frame = data->n_values_per_frame;
16283     *stride_length = data->stride_length;
16284
16285     n_frames_div = (*n_frames % *stride_length) ?
16286                    *n_frames / *stride_length + 1:
16287                    *n_frames / *stride_length;
16288
16289     data_size = n_frames_div * size * (*n_particles) *
16290                 (*n_values_per_frame);
16291
16292     temp = realloc(*values, data_size);
16293     if(!temp)
16294     {
16295         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16296                data_size, __FILE__, __LINE__);
16297         free(*values);
16298         *values = 0;
16299         return(TNG_CRITICAL);
16300     }
16301
16302     *values = temp;
16303
16304     if(frame_set->n_mapping_blocks <= 0)
16305     {
16306         memcpy(*values, data->values, data_size);
16307     }
16308     else
16309     {
16310         i_step = (*n_particles) * (*n_values_per_frame);
16311         for(i = 0; i < *n_frames; i++)
16312         {
16313             for(j = 0; j < *n_particles; j++)
16314             {
16315                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16316                 memcpy(((char *)*values) + size * (i * i_step + mapping *
16317                        (*n_values_per_frame)),
16318                        (char *)data->values + size *
16319                        (i * i_step + j * (*n_values_per_frame)),
16320                        size * (*n_values_per_frame));
16321             }
16322         }
16323     }
16324
16325     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16326
16327     return(TNG_SUCCESS);
16328 }
16329
16330 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
16331                 (tng_trajectory_t tng_data,
16332                  const int64_t block_id,
16333                  const int64_t start_frame_nr,
16334                  const int64_t end_frame_nr,
16335                  const char hash_mode,
16336                  union data_values ****values,
16337                  int64_t *n_particles,
16338                  int64_t *n_values_per_frame,
16339                  char *type)
16340 {
16341     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
16342     int64_t first_frame, block_index;
16343     int size;
16344     size_t len;
16345     tng_particle_data_t data;
16346     tng_trajectory_frame_set_t frame_set;
16347     tng_gen_block_t block;
16348     char block_type_flag;
16349     tng_function_status stat;
16350
16351     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16352     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16353     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16354     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16355     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16356
16357     block_index = -1;
16358
16359     frame_set = &tng_data->current_trajectory_frame_set;
16360     first_frame = frame_set->first_frame;
16361
16362     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16363     if(stat != TNG_SUCCESS)
16364     {
16365         return(stat);
16366     }
16367
16368     /* Do not re-read the frame set. */
16369     if(first_frame != frame_set->first_frame ||
16370        frame_set->n_particle_data_blocks <= 0)
16371     {
16372         tng_block_init(&block);
16373         file_pos = ftello(tng_data->input_file);
16374         /* Read all blocks until next frame set block */
16375         stat = tng_block_header_read(tng_data, block);
16376         while(file_pos < tng_data->input_file_len &&
16377                 stat != TNG_CRITICAL &&
16378                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16379                 block->id != -1)
16380         {
16381             stat = tng_block_read_next(tng_data, block,
16382                                     hash_mode);
16383             if(stat != TNG_CRITICAL)
16384             {
16385                 file_pos = ftello(tng_data->input_file);
16386                 if(file_pos < tng_data->input_file_len)
16387                 {
16388                     stat = tng_block_header_read(tng_data, block);
16389                 }
16390             }
16391         }
16392         tng_block_destroy(&block);
16393         if(stat == TNG_CRITICAL)
16394         {
16395             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16396                     file_pos, __FILE__, __LINE__);
16397             return(stat);
16398         }
16399     }
16400
16401     /* See if there is already a data block of this ID.
16402      * Start checking the last read frame set */
16403     for(i = frame_set->n_particle_data_blocks; i-- ;)
16404     {
16405         data = &frame_set->tr_particle_data[i];
16406         if(data->block_id == block_id)
16407         {
16408             block_index = i;
16409             block_type_flag = TNG_TRAJECTORY_BLOCK;
16410             break;
16411         }
16412     }
16413
16414     if(block_index < 0)
16415     {
16416         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
16417                 block_id, __FILE__, __LINE__);
16418         return(TNG_FAILURE);
16419     }
16420
16421     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16422        tng_data->var_num_atoms_flag)
16423     {
16424         *n_particles = frame_set->n_particles;
16425     }
16426     else
16427     {
16428         *n_particles = tng_data->n_particles;
16429     }
16430
16431     n_frames = end_frame_nr - start_frame_nr + 1;
16432     *n_values_per_frame = data->n_values_per_frame;
16433     *type = data->datatype;
16434
16435     if(*values == 0)
16436     {
16437         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
16438                                          *n_particles, *n_values_per_frame,
16439                                          *type)
16440             != TNG_SUCCESS)
16441         {
16442             return(TNG_CRITICAL);
16443         }
16444     }
16445
16446     current_frame_pos = start_frame_nr - frame_set->first_frame;
16447     /* It's not very elegant to reuse so much of the code in the different case
16448      * statements, but it's unnecessarily slow to have the switch-case block
16449      * inside the for loops. */
16450     switch(*type)
16451     {
16452     case TNG_CHAR_DATA:
16453         for(i=0; i<n_frames; i++)
16454         {
16455             if(current_frame_pos == frame_set->n_frames)
16456             {
16457                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16458                 if(stat != TNG_SUCCESS)
16459                 {
16460                     return(stat);
16461                 }
16462                 current_frame_pos = 0;
16463             }
16464             for(j = 0; j < *n_particles; j++)
16465             {
16466                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16467                 for(k = 0; k < *n_values_per_frame; k++)
16468                 {
16469                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
16470                     (*values)[i][mapping][k].c = malloc(len);
16471                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
16472                 }
16473             }
16474             current_frame_pos++;
16475         }
16476         break;
16477     case TNG_INT_DATA:
16478         size = sizeof(int);
16479         i_step = (*n_particles) * (*n_values_per_frame);
16480         for(i=0; i<n_frames; i++)
16481         {
16482             if(current_frame_pos == frame_set->n_frames)
16483             {
16484                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16485                 if(stat != TNG_SUCCESS)
16486                 {
16487                     return(stat);
16488                 }
16489                 current_frame_pos = 0;
16490             }
16491             for(j = 0; j < *n_particles; j++)
16492             {
16493                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16494                 for(k = 0; k < *n_values_per_frame; k++)
16495                 {
16496                     (*values)[i][mapping][k].i = *(int *)
16497                                                  ((char *)data->values + size *
16498                                                   (current_frame_pos *
16499                                                    i_step + j *
16500                                                    (*n_values_per_frame) + k));
16501                 }
16502             }
16503             current_frame_pos++;
16504         }
16505         break;
16506     case TNG_FLOAT_DATA:
16507         size = sizeof(float);
16508         i_step = (*n_particles) * (*n_values_per_frame);
16509         for(i=0; i<n_frames; i++)
16510         {
16511             if(current_frame_pos == frame_set->n_frames)
16512             {
16513                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16514                 if(stat != TNG_SUCCESS)
16515                 {
16516                     return(stat);
16517                 }
16518                 current_frame_pos = 0;
16519             }
16520             for(j=0; j<*n_particles; j++)
16521             {
16522                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16523                 for(k=0; k<*n_values_per_frame; k++)
16524                 {
16525                     (*values)[i][mapping][k].f = *(float *)
16526                                                  ((char *)data->values + size *
16527                                                   (current_frame_pos *
16528                                                    i_step + j *
16529                                                    (*n_values_per_frame) + k));
16530                 }
16531             }
16532             current_frame_pos++;
16533         }
16534         break;
16535     case TNG_DOUBLE_DATA:
16536     default:
16537         size = sizeof(double);
16538         i_step = (*n_particles) * (*n_values_per_frame);
16539         for(i=0; i<n_frames; i++)
16540         {
16541             if(current_frame_pos == frame_set->n_frames)
16542             {
16543                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16544                 if(stat != TNG_SUCCESS)
16545                 {
16546                     return(stat);
16547                 }
16548                 current_frame_pos = 0;
16549             }
16550             for(j=0; j<*n_particles; j++)
16551             {
16552                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16553                 for(k=0; k<*n_values_per_frame; k++)
16554                 {
16555                     (*values)[i][mapping][k].d = *(double *)
16556                                                  ((char *)data->values + size *
16557                                                   (current_frame_pos *
16558                                                    i_step + j *
16559                                                    (*n_values_per_frame) + k));
16560                 }
16561             }
16562             current_frame_pos++;
16563         }
16564     }
16565
16566     data->last_retrieved_frame = end_frame_nr;
16567
16568     return(TNG_SUCCESS);
16569 }
16570
16571 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
16572                 (tng_trajectory_t tng_data,
16573                  const int64_t block_id,
16574                  const int64_t start_frame_nr,
16575                  const int64_t end_frame_nr,
16576                  const char hash_mode,
16577                  void **values,
16578                  int64_t *n_particles,
16579                  int64_t *stride_length,
16580                  int64_t *n_values_per_frame,
16581                  char *type)
16582 {
16583     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
16584     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
16585     int size;
16586     tng_trajectory_frame_set_t frame_set;
16587     tng_particle_data_t p_data;
16588     tng_gen_block_t block;
16589     void *current_values = 0, *temp;
16590     tng_function_status stat;
16591
16592     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16593     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16594     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16595     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16596     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16597     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16598
16599     frame_set = &tng_data->current_trajectory_frame_set;
16600     first_frame = frame_set->first_frame;
16601
16602     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16603     if(stat != TNG_SUCCESS)
16604     {
16605         return(stat);
16606     }
16607
16608     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
16609     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
16610     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16611     if(first_frame != frame_set->first_frame ||
16612        stat != TNG_SUCCESS)
16613     {
16614         tng_block_init(&block);
16615         if(stat != TNG_SUCCESS)
16616         {
16617             fseeko(tng_data->input_file,
16618                    tng_data->current_trajectory_frame_set_input_file_pos,
16619                    SEEK_SET);
16620             stat = tng_block_header_read(tng_data, block);
16621             if(stat != TNG_SUCCESS)
16622             {
16623                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
16624                         __FILE__, __LINE__);
16625                 return(stat);
16626             }
16627
16628             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
16629         }
16630         file_pos = ftello(tng_data->input_file);
16631         /* Read until next frame set block */
16632         stat = tng_block_header_read(tng_data, block);
16633         while(file_pos < tng_data->input_file_len &&
16634             stat != TNG_CRITICAL &&
16635             block->id != TNG_TRAJECTORY_FRAME_SET &&
16636             block->id != -1)
16637         {
16638             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
16639             {
16640                 stat = tng_block_read_next(tng_data, block,
16641                                         hash_mode);
16642                 if(stat != TNG_CRITICAL)
16643                 {
16644                     file_pos = ftello(tng_data->input_file);
16645                     if(file_pos < tng_data->input_file_len)
16646                     {
16647                         stat = tng_block_header_read(tng_data, block);
16648                     }
16649                 }
16650             }
16651             else
16652             {
16653                 file_pos += block->block_contents_size + block->header_contents_size;
16654                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
16655                 if(file_pos < tng_data->input_file_len)
16656                 {
16657                     stat = tng_block_header_read(tng_data, block);
16658                 }
16659             }
16660         }
16661         tng_block_destroy(&block);
16662         if(stat == TNG_CRITICAL)
16663         {
16664             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16665                     file_pos, __FILE__, __LINE__);
16666             return(stat);
16667         }
16668     }
16669     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16670     if(stat != TNG_SUCCESS)
16671     {
16672         return(stat);
16673     }
16674
16675     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16676                                         &n_frames, stride_length, n_particles,
16677                                         n_values_per_frame, type);
16678
16679     if(stat != TNG_SUCCESS || *n_particles == 0)
16680     {
16681         if(current_values)
16682         {
16683             free(current_values);
16684         }
16685         return(stat);
16686     }
16687
16688     if(n_frames == 1 && n_frames < frame_set->n_frames)
16689     {
16690         tot_n_frames = 1;
16691     }
16692     else
16693     {
16694         tot_n_frames = end_frame_nr - start_frame_nr + 1;
16695     }
16696
16697     switch(*type)
16698     {
16699     case TNG_CHAR_DATA:
16700         return(TNG_FAILURE);
16701     case TNG_INT_DATA:
16702         size = sizeof(int64_t);
16703         break;
16704     case TNG_FLOAT_DATA:
16705         size = sizeof(float);
16706         break;
16707     case TNG_DOUBLE_DATA:
16708     default:
16709         size = sizeof(double);
16710     }
16711
16712     n_frames_div = (tot_n_frames % *stride_length) ?
16713                  tot_n_frames / *stride_length + 1:
16714                  tot_n_frames / *stride_length;
16715
16716     data_size = n_frames_div * size * (*n_particles) *
16717                 (*n_values_per_frame);
16718
16719     temp = realloc(*values, data_size);
16720     if(!temp)
16721     {
16722         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16723                data_size, __FILE__, __LINE__);
16724         free(*values);
16725         *values = 0;
16726         return(TNG_CRITICAL);
16727     }
16728
16729     *values = temp;
16730
16731     if( n_frames == 1 && n_frames < frame_set->n_frames)
16732     {
16733         memcpy(*values, current_values, size * (*n_particles) *
16734                (*n_values_per_frame));
16735     }
16736     else
16737     {
16738         current_frame_pos = start_frame_nr - frame_set->first_frame;
16739
16740         frame_size = size * (*n_particles) * (*n_values_per_frame);
16741
16742         last_frame_pos = tng_min_i64(n_frames,
16743                                      end_frame_nr - start_frame_nr);
16744
16745         n_frames_div = current_frame_pos / *stride_length;
16746         n_frames_div_2 = (last_frame_pos % *stride_length) ?
16747                        last_frame_pos / *stride_length + 1:
16748                        last_frame_pos / *stride_length;
16749         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
16750
16751         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
16752                n_frames_div_2 * frame_size);
16753
16754         current_frame_pos += n_frames - current_frame_pos;
16755
16756         while(current_frame_pos <= end_frame_nr - start_frame_nr)
16757         {
16758             stat = tng_frame_set_read_next(tng_data, hash_mode);
16759             if(stat != TNG_SUCCESS)
16760             {
16761                 if(current_values)
16762                 {
16763                     free(current_values);
16764                 }
16765                 free(*values);
16766                 *values = 0;
16767                 return(stat);
16768             }
16769
16770             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16771                                                 &n_frames, stride_length, n_particles,
16772                                                 n_values_per_frame, type);
16773
16774             if(stat != TNG_SUCCESS)
16775             {
16776                 if(current_values)
16777                 {
16778                     free(current_values);
16779                 }
16780                 free(*values);
16781                 *values = 0;
16782                 return(stat);
16783             }
16784
16785             last_frame_pos = tng_min_i64(n_frames,
16786                                          end_frame_nr - current_frame_pos);
16787
16788             n_frames_div = current_frame_pos / *stride_length;
16789             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16790                            last_frame_pos / *stride_length + 1:
16791                            last_frame_pos / *stride_length;
16792             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16793
16794             memcpy(((char *)*values) + n_frames_div * frame_size,
16795                    current_values,
16796                    n_frames_div_2 * frame_size);
16797
16798             current_frame_pos += n_frames;
16799         }
16800     }
16801
16802     if(current_values)
16803     {
16804         free(current_values);
16805     }
16806
16807     p_data->last_retrieved_frame = end_frame_nr;
16808
16809     return(TNG_SUCCESS);
16810 }
16811
16812 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16813                 (const tng_trajectory_t tng_data,
16814                  const int64_t block_id,
16815                  int64_t frame,
16816                  int64_t *stride_length)
16817 {
16818     tng_function_status stat;
16819     tng_non_particle_data_t np_data;
16820     tng_particle_data_t p_data;
16821     int64_t orig_file_pos, file_pos;
16822     int is_particle_data;
16823
16824     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16825     {
16826         frame = 0;
16827     }
16828
16829     if(frame >= 0)
16830     {
16831         stat = tng_frame_set_of_frame_find(tng_data, frame);
16832         if(stat != TNG_SUCCESS)
16833         {
16834             return(stat);
16835         }
16836     }
16837     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16838     stat = tng_data_find(tng_data, block_id, &np_data);
16839     if(stat != TNG_SUCCESS)
16840     {
16841         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16842         if(stat != TNG_SUCCESS)
16843         {
16844             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16845             /* If no specific frame was required read until this data block is found */
16846             if(frame < 0)
16847             {
16848                 file_pos = ftello(tng_data->input_file);
16849                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16850                 {
16851                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16852                     file_pos = ftello(tng_data->input_file);
16853                 }
16854             }
16855             if(stat != TNG_SUCCESS)
16856             {
16857                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16858
16859                 return(stat);
16860             }
16861             stat = tng_data_find(tng_data, block_id, &np_data);
16862             if(stat != TNG_SUCCESS)
16863             {
16864                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16865                 if(stat != TNG_SUCCESS)
16866                 {
16867                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16868
16869                     return(stat);
16870                 }
16871                 else
16872                 {
16873                     is_particle_data = 1;
16874                 }
16875             }
16876             else
16877             {
16878                 is_particle_data = 0;
16879             }
16880         }
16881         else
16882         {
16883             is_particle_data = 1;
16884         }
16885     }
16886     else
16887     {
16888         is_particle_data = 0;
16889     }
16890     if(is_particle_data)
16891     {
16892         *stride_length = p_data->stride_length;
16893     }
16894     else
16895     {
16896         *stride_length = np_data->stride_length;
16897     }
16898     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16899
16900     return(TNG_SUCCESS);
16901 }
16902
16903 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16904                 (const tng_trajectory_t tng_data,
16905                  char *time)
16906 {
16907     struct tm *time_data;
16908     time_t secs;
16909
16910     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16911     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16912
16913     secs = tng_data->time;
16914
16915     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16916     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16917              "%4d-%02d-%02d %02d:%02d:%02d",
16918              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16919              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16920
16921     return(TNG_SUCCESS);
16922 }
16923
16924
16925 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16926                 (const char *filename,
16927                  const char mode,
16928                  tng_trajectory_t *tng_data_p)
16929 {
16930     tng_function_status stat;
16931
16932     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16933
16934     if(mode != 'r' && mode != 'w' && mode != 'a')
16935     {
16936         return(TNG_FAILURE);
16937     }
16938
16939     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16940     {
16941         tng_trajectory_destroy(tng_data_p);
16942         return(TNG_CRITICAL);
16943     }
16944
16945     if(mode == 'r' || mode == 'a')
16946     {
16947         tng_input_file_set(*tng_data_p, filename);
16948
16949         /* Read the file headers */
16950         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16951
16952         stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16953
16954         if(stat != TNG_SUCCESS)
16955         {
16956             return(stat);
16957         }
16958     }
16959
16960     if(mode == 'w')
16961     {
16962         tng_output_file_set(*tng_data_p, filename);
16963     }
16964     else if(mode == 'a')
16965     {
16966         if((*tng_data_p)->output_file)
16967         {
16968             fclose((*tng_data_p)->output_file);
16969         }
16970         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
16971         fseeko((*tng_data_p)->input_file,
16972                (*tng_data_p)->last_trajectory_frame_set_input_file_pos,
16973                SEEK_SET);
16974
16975         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
16976         if(stat != TNG_SUCCESS)
16977         {
16978             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
16979                    __FILE__, __LINE__);
16980         }
16981         (*tng_data_p)->output_file = 0;
16982
16983         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
16984         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
16985         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
16986         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
16987         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
16988         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
16989         if((*tng_data_p)->input_file)
16990         {
16991             fclose((*tng_data_p)->input_file);
16992             (*tng_data_p)->input_file = 0;
16993         }
16994         if((*tng_data_p)->input_file_path)
16995         {
16996             free((*tng_data_p)->input_file_path);
16997             (*tng_data_p)->input_file_path = 0;
16998         }
16999         tng_output_append_file_set(*tng_data_p, filename);
17000
17001         fseeko((*tng_data_p)->output_file, 0, SEEK_END);
17002     }
17003
17004     return(TNG_SUCCESS);
17005 }
17006
17007 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
17008                 (tng_trajectory_t *tng_data_p)
17009 {
17010     tng_trajectory_frame_set_t frame_set;
17011
17012     if(tng_data_p == 0)
17013     {
17014         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
17015                __FILE__, __LINE__);
17016         return(TNG_FAILURE);
17017     }
17018
17019     if(*tng_data_p == 0)
17020     {
17021         return(TNG_SUCCESS);
17022     }
17023
17024     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
17025
17026     if(frame_set->n_unwritten_frames > 0)
17027     {
17028         frame_set->n_frames = frame_set->n_unwritten_frames;
17029         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
17030     }
17031
17032     return(tng_trajectory_destroy(tng_data_p));
17033 }
17034
17035 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
17036                 (tng_trajectory_t tng_data,
17037                  const int64_t frame_nr,
17038                  double *time)
17039 {
17040     int64_t first_frame;
17041     tng_trajectory_frame_set_t frame_set;
17042     tng_function_status stat;
17043
17044     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17045     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
17046
17047     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
17048     if(stat != TNG_SUCCESS)
17049     {
17050         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
17051                frame_nr, __FILE__, __LINE__);
17052         return(stat);
17053     }
17054
17055     frame_set = &tng_data->current_trajectory_frame_set;
17056     first_frame = frame_set->first_frame;
17057
17058     if(tng_data->time_per_frame <= 0)
17059     {
17060         return(TNG_FAILURE);
17061     }
17062
17063     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
17064
17065     return(TNG_SUCCESS);
17066 }
17067
17068 /*
17069 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
17070                 (tng_trajectory_t tng_data,
17071                  int64_t *n_mols,
17072                  int64_t **molecule_cnt_list,
17073                  tng_molecule_t *mols)
17074 {
17075     tng_trajectory_frame_set_t frame_set;
17076
17077     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17078     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
17079
17080     *n_mols = tng_data->n_molecules;
17081
17082     frame_set = &tng_data->current_trajectory_frame_set;
17083     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
17084     {
17085         *molecule_cnt_list = frame_set->molecule_cnt_list;
17086     }
17087     else
17088     {
17089         *molecule_cnt_list = tng_data->molecule_cnt_list;
17090     }
17091
17092     *mols = tng_data->molecules;
17093
17094     return(TNG_SUCCESS);
17095 }
17096 */
17097 /*
17098 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
17099                 (tng_trajectory_t tng_data,
17100                  const char *name,
17101                  const int64_t cnt,
17102                  tng_molecule_t *mol)
17103 {
17104     tng_function_status stat;
17105
17106     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
17107     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
17108
17109     stat = tng_molecule_add(tng_data, name, mol);
17110     if(stat != TNG_SUCCESS)
17111     {
17112         return(stat);
17113     }
17114     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
17115
17116     return(stat);
17117 }
17118 */
17119 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
17120                 (tng_trajectory_t tng_data,
17121                  const tng_molecule_t mol,
17122                  int64_t *n_particles,
17123                  char ***names,
17124                  char ***types,
17125                  char ***res_names,
17126                  int64_t **res_ids,
17127                  char ***chain_names,
17128                  int64_t **chain_ids)
17129 {
17130     tng_atom_t atom;
17131     tng_residue_t res;
17132     tng_chain_t chain;
17133     int64_t i;
17134     (void)tng_data;
17135
17136     *n_particles = mol->n_atoms;
17137
17138     *names = malloc(sizeof(char *) * *n_particles);
17139     *types = malloc(sizeof(char *) * *n_particles);
17140     *res_names = malloc(sizeof(char *) * *n_particles);
17141     *chain_names = malloc(sizeof(char *) * *n_particles);
17142     *res_ids = malloc(sizeof(int64_t) * *n_particles);
17143     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
17144
17145     for(i = 0; i < *n_particles; i++)
17146     {
17147         atom = &mol->atoms[i];
17148         res = atom->residue;
17149         chain = res->chain;
17150         (*names)[i] = malloc(strlen(atom->name));
17151         strcpy(*names[i], atom->name);
17152         (*types)[i] = malloc(strlen(atom->atom_type));
17153         strcpy(*types[i], atom->atom_type);
17154         (*res_names)[i] = malloc(strlen(res->name));
17155         strcpy(*res_names[i], res->name);
17156         (*chain_names)[i] = malloc(strlen(chain->name));
17157         strcpy(*chain_names[i], chain->name);
17158         (*res_ids)[i] = res->id;
17159         (*chain_ids)[i] = chain->id;
17160     }
17161
17162     return(TNG_SUCCESS);
17163 }
17164
17165 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
17166                 (tng_trajectory_t tng_data,
17167                  tng_molecule_t mol,
17168                  const int64_t n_particles,
17169                  const char **names,
17170                  const char **types,
17171                  const char **res_names,
17172                  const int64_t *res_ids,
17173                  const char **chain_names,
17174                  const int64_t *chain_ids)
17175 {
17176     int64_t i;
17177     tng_chain_t chain;
17178     tng_residue_t residue;
17179     tng_atom_t atom;
17180     tng_function_status stat;
17181
17182     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17183     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
17184     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
17185     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
17186     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
17187     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
17188     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
17189
17190     for(i = 0; i < n_particles; i++)
17191     {
17192         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
17193            &chain) == TNG_FAILURE)
17194         {
17195             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
17196                                           &chain);
17197             if(stat != TNG_SUCCESS)
17198             {
17199                 return(stat);
17200             }
17201         }
17202         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
17203            &residue) == TNG_FAILURE)
17204         {
17205             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
17206                                          &residue);
17207             if(stat != TNG_SUCCESS)
17208             {
17209                 return(stat);
17210             }
17211         }
17212         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
17213         if(stat != TNG_SUCCESS)
17214         {
17215             return(stat);
17216         }
17217     }
17218     return(TNG_SUCCESS);
17219 }
17220
17221 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
17222                 (tng_trajectory_t tng_data,
17223                  float **positions, int64_t *stride_length)
17224 {
17225     int64_t n_frames, n_particles, n_values_per_frame;
17226     char type;
17227     tng_function_status stat;
17228
17229     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17230     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17231     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17232
17233     stat = tng_num_frames_get(tng_data, &n_frames);
17234     if(stat != TNG_SUCCESS)
17235     {
17236         return(stat);
17237     }
17238
17239     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17240                                                  0, n_frames - 1, TNG_USE_HASH,
17241                                                  (void **)positions,
17242                                                  &n_particles,
17243                                                  stride_length,
17244                                                  &n_values_per_frame,
17245                                                  &type);
17246
17247     return(stat);
17248 }
17249
17250 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
17251                 (tng_trajectory_t tng_data,
17252                  float **velocities, int64_t *stride_length)
17253 {
17254     int64_t n_frames, n_particles, n_values_per_frame;
17255     char type;
17256     tng_function_status stat;
17257
17258     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17259     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17260     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17261
17262     stat = tng_num_frames_get(tng_data, &n_frames);
17263     if(stat != TNG_SUCCESS)
17264     {
17265         return(stat);
17266     }
17267
17268     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17269                                                  0, n_frames - 1, TNG_USE_HASH,
17270                                                  (void **)velocities,
17271                                                  &n_particles,
17272                                                  stride_length,
17273                                                  &n_values_per_frame,
17274                                                  &type);
17275
17276     return(stat);
17277 }
17278
17279 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
17280                 (tng_trajectory_t tng_data,
17281                  float **forces, int64_t *stride_length)
17282 {
17283     int64_t n_frames, n_particles, n_values_per_frame;
17284     char type;
17285     tng_function_status stat;
17286
17287     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17288     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17289     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17290
17291     stat = tng_num_frames_get(tng_data, &n_frames);
17292     if(stat != TNG_SUCCESS)
17293     {
17294         return(stat);
17295     }
17296
17297     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17298                                                  0, n_frames - 1, TNG_USE_HASH,
17299                                                  (void **)forces,
17300                                                  &n_particles,
17301                                                  stride_length,
17302                                                  &n_values_per_frame,
17303                                                  &type);
17304
17305     return(stat);
17306 }
17307
17308 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
17309                 (tng_trajectory_t tng_data,
17310                  float **box_shape,
17311                  int64_t *stride_length)
17312 {
17313     int64_t n_frames, n_values_per_frame;
17314     char type;
17315     tng_function_status stat;
17316
17317     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17318     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17319     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17320
17321     stat = tng_num_frames_get(tng_data, &n_frames);
17322     if(stat != TNG_SUCCESS)
17323     {
17324         return(stat);
17325     }
17326
17327     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17328                                         0, n_frames - 1, TNG_USE_HASH,
17329                                         (void **)box_shape,
17330                                         stride_length,
17331                                         &n_values_per_frame,
17332                                         &type);
17333
17334     return(stat);
17335 }
17336
17337 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
17338                 (tng_trajectory_t tng_data,
17339                  const int64_t block_id,
17340                  void **values,
17341                  char *data_type,
17342                  int64_t *retrieved_frame_number,
17343                  double *retrieved_time)
17344 {
17345     tng_trajectory_frame_set_t frame_set;
17346     tng_particle_data_t data = 0;
17347     tng_function_status stat;
17348     int size;
17349     int64_t i, data_size, n_particles, file_pos;
17350     void *temp;
17351
17352     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17353     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17354     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17355     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17356     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17357
17358     frame_set = &tng_data->current_trajectory_frame_set;
17359
17360     stat = tng_particle_data_find(tng_data, block_id, &data);
17361     if(stat != TNG_SUCCESS)
17362     {
17363         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17364         file_pos = ftello(tng_data->input_file);
17365         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17366         {
17367             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17368             file_pos = ftello(tng_data->input_file);
17369         }
17370         if(stat != TNG_SUCCESS)
17371         {
17372             return(stat);
17373         }
17374         stat = tng_particle_data_find(tng_data, block_id, &data);
17375         if(stat != TNG_SUCCESS)
17376         {
17377             return(stat);
17378         }
17379     }
17380     if(data->last_retrieved_frame < 0)
17381     {
17382         fseeko(tng_data->input_file,
17383                tng_data->first_trajectory_frame_set_input_file_pos,
17384                SEEK_SET);
17385         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17386         if(stat != TNG_SUCCESS)
17387         {
17388             return(stat);
17389         }
17390         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17391         if(stat != TNG_SUCCESS)
17392         {
17393             return(stat);
17394         }
17395
17396         i = data->first_frame_with_data;
17397     }
17398     else
17399     {
17400         if(data->n_frames == 1)
17401         {
17402             i = data->last_retrieved_frame + 1;
17403         }
17404         else
17405         {
17406             i = data->last_retrieved_frame + data->stride_length;
17407         }
17408         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17409         {
17410             stat = tng_frame_set_of_frame_find(tng_data, i);
17411             if(stat != TNG_SUCCESS)
17412             {
17413                 /* If the frame set search found the frame set after the starting
17414                  * frame set there is a gap in the frame sets. So, even if the frame
17415                  * was not found the next frame with data is still in the found
17416                  * frame set. */
17417                 if(stat == TNG_CRITICAL)
17418                 {
17419                     return(stat);
17420                 }
17421                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17422                 {
17423                     return(TNG_FAILURE);
17424                 }
17425                 i = frame_set->first_frame;
17426             }
17427         }
17428         if(data->last_retrieved_frame < frame_set->first_frame)
17429         {
17430             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17431             if(stat != TNG_SUCCESS)
17432             {
17433                 return(stat);
17434             }
17435         }
17436     }
17437     data->last_retrieved_frame = i;
17438     *retrieved_frame_number = i;
17439     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17440     {
17441         *retrieved_time = frame_set->first_frame_time +
17442                         (i - frame_set->first_frame) *
17443                         tng_data->time_per_frame;
17444     }
17445     else
17446     {
17447         *retrieved_time = 0;
17448     }
17449
17450     if(data->stride_length > 1)
17451     {
17452         i = (i - data->first_frame_with_data) / data->stride_length;
17453     }
17454     else
17455     {
17456         i = (i - frame_set->first_frame);
17457     }
17458
17459     tng_num_particles_get(tng_data, &n_particles);
17460
17461     *data_type = data->datatype;
17462
17463     switch(*data_type)
17464     {
17465     case TNG_CHAR_DATA:
17466         return(TNG_FAILURE);
17467     case TNG_INT_DATA:
17468         size = sizeof(int64_t);
17469         break;
17470     case TNG_FLOAT_DATA:
17471         size = sizeof(float);
17472         break;
17473     case TNG_DOUBLE_DATA:
17474     default:
17475         size = sizeof(double);
17476     }
17477
17478     data_size = size * n_particles * data->n_values_per_frame;
17479
17480 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
17481 //            i, data_size, size, n_particles, data->n_values_per_frame);
17482
17483     temp = realloc(*values, data_size);
17484     if(!temp)
17485     {
17486         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17487                data_size, __FILE__, __LINE__);
17488         free(*values);
17489         *values = 0;
17490         return(TNG_CRITICAL);
17491     }
17492
17493     *values = temp;
17494
17495     memcpy(*values, (char *)data->values + i * data_size, data_size);
17496
17497     return(TNG_SUCCESS);
17498 }
17499
17500 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
17501                 (tng_trajectory_t tng_data,
17502                  const int64_t block_id,
17503                  void **values,
17504                  char *data_type,
17505                  int64_t *retrieved_frame_number,
17506                  double *retrieved_time)
17507 {
17508     tng_trajectory_frame_set_t frame_set;
17509     tng_non_particle_data_t data = 0;
17510     tng_function_status stat;
17511     int size;
17512     int64_t i, data_size, file_pos;
17513     void *temp;
17514
17515     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17516     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17517     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17518     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17519     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17520
17521     frame_set = &tng_data->current_trajectory_frame_set;
17522
17523     stat = tng_data_find(tng_data, block_id, &data);
17524     if(stat != TNG_SUCCESS)
17525     {
17526         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17527         file_pos = ftello(tng_data->input_file);
17528         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17529         {
17530             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17531             file_pos = ftello(tng_data->input_file);
17532         }
17533         if(stat != TNG_SUCCESS)
17534         {
17535             return(stat);
17536         }
17537         stat = tng_data_find(tng_data, block_id, &data);
17538         if(stat != TNG_SUCCESS)
17539         {
17540             return(stat);
17541         }
17542     }
17543     if(data->last_retrieved_frame < 0)
17544     {
17545         fseeko(tng_data->input_file,
17546                tng_data->first_trajectory_frame_set_input_file_pos,
17547                SEEK_SET);
17548         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17549         if(stat != TNG_SUCCESS)
17550         {
17551             return(stat);
17552         }
17553         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17554         if(stat != TNG_SUCCESS)
17555         {
17556             return(stat);
17557         }
17558
17559         i = data->first_frame_with_data;
17560     }
17561     else
17562     {
17563         if(data->n_frames == 1)
17564         {
17565             i = data->last_retrieved_frame + 1;
17566         }
17567         else
17568         {
17569             i = data->last_retrieved_frame + data->stride_length;
17570         }
17571         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17572         {
17573             stat = tng_frame_set_of_frame_find(tng_data, i);
17574             if(stat != TNG_SUCCESS)
17575             {
17576                 /* If the frame set search found the frame set after the starting
17577                  * frame set there is a gap in the frame sets. So, even if the frame
17578                  * was not found the next frame with data is still in the found
17579                  * frame set. */
17580                 if(stat == TNG_CRITICAL)
17581                 {
17582                     return(stat);
17583                 }
17584                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17585                 {
17586                     return(TNG_FAILURE);
17587                 }
17588                 i = frame_set->first_frame;
17589             }
17590         }
17591         if(data->last_retrieved_frame < frame_set->first_frame)
17592         {
17593             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17594             if(stat != TNG_SUCCESS)
17595             {
17596                 return(stat);
17597             }
17598         }
17599     }
17600     data->last_retrieved_frame = i;
17601     *retrieved_frame_number = i;
17602     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17603     {
17604         *retrieved_time = frame_set->first_frame_time +
17605                         (i - frame_set->first_frame) *
17606                         tng_data->time_per_frame;
17607     }
17608     else
17609     {
17610         *retrieved_time = 0;
17611     }
17612
17613     if(data->stride_length > 1)
17614     {
17615         i = (i - data->first_frame_with_data) / data->stride_length;
17616     }
17617     else
17618     {
17619         i = (i - frame_set->first_frame);
17620     }
17621
17622     *data_type = data->datatype;
17623
17624     switch(*data_type)
17625     {
17626     case TNG_CHAR_DATA:
17627         return(TNG_FAILURE);
17628     case TNG_INT_DATA:
17629         size = sizeof(int64_t);
17630         break;
17631     case TNG_FLOAT_DATA:
17632         size = sizeof(float);
17633         break;
17634     case TNG_DOUBLE_DATA:
17635     default:
17636         size = sizeof(double);
17637     }
17638
17639     data_size = size * data->n_values_per_frame;
17640
17641     temp = realloc(*values, data_size);
17642     if(!temp)
17643     {
17644         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17645                data_size, __FILE__, __LINE__);
17646         free(*values);
17647         *values = 0;
17648         return(TNG_CRITICAL);
17649     }
17650
17651     *values = temp;
17652
17653     memcpy(*values, (char *)data->values + i * data_size, data_size);
17654
17655     return(TNG_SUCCESS);
17656 }
17657
17658 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
17659                 (tng_trajectory_t tng_data,
17660                  const int64_t first_frame,
17661                  const int64_t last_frame,
17662                  float **positions,
17663                  int64_t *stride_length)
17664 {
17665     int64_t n_particles, n_values_per_frame;
17666     char type;
17667     tng_function_status stat;
17668
17669     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17670     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17671     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17672     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17673
17674     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17675                                                  first_frame, last_frame,
17676                                                  TNG_USE_HASH,
17677                                                  (void **)positions,
17678                                                  &n_particles,
17679                                                  stride_length,
17680                                                  &n_values_per_frame,
17681                                                  &type);
17682
17683     return(stat);
17684 }
17685
17686 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
17687                 (tng_trajectory_t tng_data,
17688                  const int64_t first_frame,
17689                  const int64_t last_frame,
17690                  float **velocities,
17691                  int64_t *stride_length)
17692 {
17693     int64_t n_particles, n_values_per_frame;
17694     char type;
17695     tng_function_status stat;
17696
17697     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17698     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17699     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17700     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17701
17702     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17703                                                  first_frame, last_frame,
17704                                                  TNG_USE_HASH,
17705                                                  (void **)velocities,
17706                                                  &n_particles,
17707                                                  stride_length,
17708                                                  &n_values_per_frame,
17709                                                  &type);
17710
17711     return(stat);
17712 }
17713
17714 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
17715                 (tng_trajectory_t tng_data,
17716                  const int64_t first_frame,
17717                  const int64_t last_frame,
17718                  float **forces,
17719                  int64_t *stride_length)
17720 {
17721     int64_t n_particles, n_values_per_frame;
17722     char type;
17723     tng_function_status stat;
17724
17725     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17726     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17727     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17728     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17729
17730     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17731                                                  first_frame, last_frame,
17732                                                  TNG_USE_HASH,
17733                                                  (void **)forces,
17734                                                  &n_particles,
17735                                                  stride_length,
17736                                                  &n_values_per_frame,
17737                                                  &type);
17738
17739     return(stat);
17740 }
17741
17742 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
17743                 (tng_trajectory_t tng_data,
17744                  const int64_t first_frame,
17745                  const int64_t last_frame,
17746                  float **box_shape,
17747                  int64_t *stride_length)
17748 {
17749     int64_t n_values_per_frame;
17750     char type;
17751     tng_function_status stat;
17752
17753     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17754     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17755     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17756     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17757
17758     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17759                                         first_frame, last_frame,
17760                                         TNG_USE_HASH,
17761                                         (void **)box_shape,
17762                                         stride_length,
17763                                         &n_values_per_frame,
17764                                         &type);
17765
17766     return(stat);
17767 }
17768
17769 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
17770                 (tng_trajectory_t tng_data,
17771                  const int64_t i,
17772                  const int64_t n_values_per_frame,
17773                  const int64_t block_id,
17774                  const char *block_name,
17775                  const char particle_dependency,
17776                  const char compression)
17777 {
17778     tng_trajectory_frame_set_t frame_set;
17779     tng_particle_data_t p_data;
17780     tng_non_particle_data_t np_data;
17781     int64_t n_particles, n_frames;
17782     tng_function_status stat;
17783
17784     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17785     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17786
17787     if(i <= 0)
17788     {
17789         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17790                i, __FILE__, __LINE__);
17791         return(TNG_FAILURE);
17792     }
17793
17794     frame_set = &tng_data->current_trajectory_frame_set;
17795
17796     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17797     {
17798         n_frames = tng_data->frame_set_n_frames;
17799
17800         stat = tng_frame_set_new(tng_data, 0, n_frames);
17801         if(stat != TNG_SUCCESS)
17802         {
17803             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17804                 __LINE__);
17805             return(stat);
17806         }
17807     }
17808     else
17809     {
17810         n_frames = frame_set->n_frames;
17811     }
17812
17813     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17814     {
17815         tng_num_particles_get(tng_data, &n_particles);
17816         if(n_particles <= 0)
17817         {
17818             return(TNG_FAILURE);
17819         }
17820
17821         if(tng_particle_data_find(tng_data, block_id, &p_data)
17822         != TNG_SUCCESS)
17823         {
17824             stat = tng_particle_data_block_add(tng_data, block_id,
17825                                                block_name,
17826                                                TNG_FLOAT_DATA,
17827                                                TNG_TRAJECTORY_BLOCK,
17828                                                n_frames, n_values_per_frame, i,
17829                                                0, n_particles,
17830                                                compression, 0);
17831             if(stat != TNG_SUCCESS)
17832             {
17833                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17834                        __FILE__, __LINE__);
17835                 return(stat);
17836             }
17837             p_data = &frame_set->tr_particle_data[frame_set->
17838                                                   n_particle_data_blocks - 1];
17839             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17840                                                   i, n_particles,
17841                                                   n_values_per_frame);
17842             if(stat != TNG_SUCCESS)
17843             {
17844                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17845                        __FILE__, __LINE__);
17846                 return(stat);
17847             }
17848         }
17849         else
17850         {
17851             if(p_data->stride_length != i)
17852             {
17853                 p_data->stride_length = i;
17854                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17855                                                       i, n_particles,
17856                                                       n_values_per_frame);
17857                 if(stat != TNG_SUCCESS)
17858                 {
17859                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17860                            __FILE__, __LINE__);
17861                     return(stat);
17862                 }
17863             }
17864         }
17865     }
17866     else
17867     {
17868         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17869         {
17870             stat = tng_data_block_add(tng_data, block_id, block_name,
17871                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17872                                       n_frames, n_values_per_frame,
17873                                       i, compression, 0);
17874             if(stat != TNG_SUCCESS)
17875             {
17876                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17877                        __FILE__, __LINE__);
17878                 return(stat);
17879             }
17880             np_data = &frame_set->tr_data[frame_set->
17881                                           n_data_blocks - 1];
17882             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17883                                          i, n_values_per_frame);
17884             if(stat != TNG_SUCCESS)
17885             {
17886                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17887                        __FILE__, __LINE__);
17888                 return(stat);
17889             }
17890         }
17891         else
17892         {
17893             if(np_data->stride_length != i)
17894             {
17895                 np_data->stride_length = i;
17896                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17897                                              i, n_values_per_frame);
17898                 if(stat != TNG_SUCCESS)
17899                 {
17900                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17901                            __FILE__, __LINE__);
17902                     return(stat);
17903                 }
17904             }
17905         }
17906     }
17907
17908     return(TNG_SUCCESS);
17909 }
17910
17911 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17912                 (tng_trajectory_t tng_data,
17913                  const int64_t i,
17914                  const int64_t n_values_per_frame,
17915                  const int64_t block_id,
17916                  const char *block_name,
17917                  const char particle_dependency,
17918                  const char compression)
17919 {
17920     tng_trajectory_frame_set_t frame_set;
17921     tng_particle_data_t p_data;
17922     tng_non_particle_data_t np_data;
17923     int64_t n_particles, n_frames;
17924     tng_function_status stat;
17925
17926     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17927     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17928
17929     if(i <= 0)
17930     {
17931         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17932                i, __FILE__, __LINE__);
17933         return(TNG_FAILURE);
17934     }
17935
17936     frame_set = &tng_data->current_trajectory_frame_set;
17937
17938     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17939     {
17940         n_frames = tng_data->frame_set_n_frames;
17941
17942         stat = tng_frame_set_new(tng_data, 0, n_frames);
17943         if(stat != TNG_SUCCESS)
17944         {
17945             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17946                 __LINE__);
17947             return(stat);
17948         }
17949     }
17950     else
17951     {
17952         n_frames = frame_set->n_frames;
17953     }
17954
17955     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17956     {
17957         tng_num_particles_get(tng_data, &n_particles);
17958
17959         if(n_particles <= 0)
17960         {
17961             return(TNG_FAILURE);
17962         }
17963
17964         if(tng_particle_data_find(tng_data, block_id, &p_data)
17965         != TNG_SUCCESS)
17966         {
17967             stat = tng_particle_data_block_add(tng_data, block_id,
17968                                             block_name,
17969                                             TNG_DOUBLE_DATA,
17970                                             TNG_TRAJECTORY_BLOCK,
17971                                             n_frames, n_values_per_frame, i,
17972                                             0, n_particles,
17973                                             compression, 0);
17974             if(stat != TNG_SUCCESS)
17975             {
17976                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17977                        __FILE__, __LINE__);
17978                 return(stat);
17979             }
17980             p_data = &frame_set->tr_particle_data[frame_set->
17981                                                   n_particle_data_blocks - 1];
17982             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17983                                                   i, n_particles,
17984                                                   n_values_per_frame);
17985             if(stat != TNG_SUCCESS)
17986             {
17987                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17988                        __FILE__, __LINE__);
17989                 return(stat);
17990             }
17991         }
17992         else
17993         {
17994             p_data->stride_length = i;
17995         }
17996     }
17997     else
17998     {
17999         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18000         {
18001             stat = tng_data_block_add(tng_data, block_id, block_name,
18002                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
18003                                       n_frames, n_values_per_frame,
18004                                       i, compression, 0);
18005             if(stat != TNG_SUCCESS)
18006             {
18007                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18008                        __FILE__, __LINE__);
18009                 return(stat);
18010             }
18011             np_data = &frame_set->tr_data[frame_set->
18012                                           n_data_blocks - 1];
18013             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18014                                          i, n_values_per_frame);
18015             if(stat != TNG_SUCCESS)
18016             {
18017                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18018                        __FILE__, __LINE__);
18019                 return(stat);
18020             }
18021         }
18022         else
18023         {
18024             np_data->stride_length = i;
18025         }
18026     }
18027
18028     return(TNG_SUCCESS);
18029 }
18030
18031 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
18032                 (tng_trajectory_t tng_data,
18033                  const int64_t i,
18034                  const int64_t n_values_per_frame,
18035                  const int64_t block_id,
18036                  const char *block_name,
18037                  const char particle_dependency,
18038                  const char compression)
18039 {
18040     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
18041            "See documentation. %s: %d", __FILE__, __LINE__);
18042     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
18043                                                block_id, block_name,
18044                                                particle_dependency,
18045                                                compression));
18046 }
18047 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
18048                 (tng_trajectory_t tng_data,
18049                  const int64_t i)
18050 {
18051     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18052     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18053
18054     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18055                                                TNG_TRAJ_POSITIONS,
18056                                                "POSITIONS",
18057                                                TNG_PARTICLE_BLOCK_DATA,
18058                                                TNG_TNG_COMPRESSION));
18059 }
18060
18061 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
18062                 (tng_trajectory_t tng_data,
18063                  const int64_t i)
18064 {
18065     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18066     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18067
18068     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18069                                                       TNG_TRAJ_POSITIONS,
18070                                                       "POSITIONS",
18071                                                       TNG_PARTICLE_BLOCK_DATA,
18072                                                       TNG_TNG_COMPRESSION));
18073 }
18074
18075 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
18076                 (tng_trajectory_t tng_data,
18077                  const int64_t i)
18078 {
18079     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
18080            "See documentation. %s: %d", __FILE__, __LINE__);
18081     return(tng_util_pos_write_interval_set(tng_data, i));
18082 }
18083
18084 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
18085                 (tng_trajectory_t tng_data,
18086                  const int64_t i)
18087 {
18088     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18089     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18090
18091     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18092                                                TNG_TRAJ_VELOCITIES,
18093                                                "VELOCITIES",
18094                                                TNG_PARTICLE_BLOCK_DATA,
18095                                                TNG_TNG_COMPRESSION));
18096 }
18097
18098 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
18099                 (tng_trajectory_t tng_data,
18100                  const int64_t i)
18101 {
18102     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18103     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18104
18105     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18106                                                       TNG_TRAJ_VELOCITIES,
18107                                                       "VELOCITIES",
18108                                                       TNG_PARTICLE_BLOCK_DATA,
18109                                                       TNG_TNG_COMPRESSION));
18110 }
18111
18112 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
18113                 (tng_trajectory_t tng_data,
18114                  const int64_t i)
18115 {
18116     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
18117            "See documentation. %s: %d", __FILE__, __LINE__);
18118     return(tng_util_vel_write_interval_set(tng_data, i));
18119 }
18120
18121 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
18122                 (tng_trajectory_t tng_data,
18123                  const int64_t i)
18124 {
18125     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18126     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18127
18128     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18129                                                TNG_TRAJ_FORCES,
18130                                                "FORCES",
18131                                                TNG_PARTICLE_BLOCK_DATA,
18132                                                TNG_GZIP_COMPRESSION));
18133 }
18134
18135 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
18136                 (tng_trajectory_t tng_data,
18137                  const int64_t i)
18138 {
18139     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18140     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18141
18142     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18143                                                       TNG_TRAJ_FORCES,
18144                                                       "FORCES",
18145                                                       TNG_PARTICLE_BLOCK_DATA,
18146                                                       TNG_GZIP_COMPRESSION));
18147 }
18148
18149 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
18150                 (tng_trajectory_t tng_data,
18151                  const int64_t i)
18152 {
18153     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
18154            "See documentation. %s: %d", __FILE__, __LINE__);
18155     return(tng_util_force_write_interval_set(tng_data, i));
18156 }
18157
18158 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
18159                 (tng_trajectory_t tng_data,
18160                  const int64_t i)
18161 {
18162     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18163     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18164
18165     return(tng_util_generic_write_interval_set(tng_data, i, 9,
18166                                                TNG_TRAJ_BOX_SHAPE,
18167                                                "BOX SHAPE",
18168                                                TNG_NON_PARTICLE_BLOCK_DATA,
18169                                                TNG_GZIP_COMPRESSION));
18170 }
18171
18172 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
18173                 (tng_trajectory_t tng_data,
18174                  const int64_t i)
18175 {
18176     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18177     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18178
18179     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
18180                                                       TNG_TRAJ_BOX_SHAPE,
18181                                                       "BOX SHAPE",
18182                                                       TNG_NON_PARTICLE_BLOCK_DATA,
18183                                                       TNG_GZIP_COMPRESSION));
18184 }
18185
18186 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
18187                 (tng_trajectory_t tng_data,
18188                  const int64_t i)
18189 {
18190     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
18191            "See documentation. %s: %d", __FILE__, __LINE__);
18192     return(tng_util_box_shape_write_interval_set(tng_data, i));
18193 }
18194
18195 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
18196                 (tng_trajectory_t tng_data,
18197                  const int64_t frame_nr,
18198                  const float *values,
18199                  const int64_t n_values_per_frame,
18200                  const int64_t block_id,
18201                  const char *block_name,
18202                  const char particle_dependency,
18203                  const char compression)
18204 {
18205     tng_trajectory_frame_set_t frame_set;
18206     tng_particle_data_t p_data;
18207     tng_non_particle_data_t np_data;
18208     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18209     int64_t last_frame;
18210     int is_first_frame_flag = 0;
18211     char block_type_flag;
18212     tng_function_status stat;
18213
18214     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18215     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18216     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18217
18218     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18219     {
18220         tng_num_particles_get(tng_data, &n_particles);
18221         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18222     }
18223
18224     if(values == 0)
18225     {
18226         return(TNG_FAILURE);
18227     }
18228
18229     frame_set = &tng_data->current_trajectory_frame_set;
18230
18231     if(frame_nr < 0)
18232     {
18233         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18234         n_frames = stride_length = 1;
18235     }
18236     else
18237     {
18238         block_type_flag = TNG_TRAJECTORY_BLOCK;
18239
18240         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18241         {
18242             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
18243             if(stat != TNG_SUCCESS)
18244             {
18245                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18246                     __LINE__);
18247                 return(stat);
18248             }
18249         }
18250         last_frame = frame_set->first_frame +
18251                      frame_set->n_frames - 1;
18252         if(frame_nr > last_frame)
18253         {
18254             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18255             if(stat != TNG_SUCCESS)
18256             {
18257                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18258                     __LINE__);
18259                 return(stat);
18260             }
18261             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18262             {
18263                 last_frame = frame_nr - 1;
18264             }
18265             stat = tng_frame_set_new(tng_data, last_frame + 1,
18266                                      tng_data->frame_set_n_frames);
18267             if(stat != TNG_SUCCESS)
18268             {
18269                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18270                     __LINE__);
18271                 return(stat);
18272             }
18273         }
18274         if(frame_set->n_unwritten_frames == 0)
18275         {
18276             is_first_frame_flag = 1;
18277         }
18278         frame_set->n_unwritten_frames = frame_nr -
18279                                         frame_set->first_frame + 1;
18280
18281         n_frames = frame_set->n_frames;
18282     }
18283
18284     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18285     {
18286         if(tng_particle_data_find(tng_data, block_id, &p_data)
18287         != TNG_SUCCESS)
18288         {
18289             stat = tng_particle_data_block_add(tng_data, block_id,
18290                                                block_name,
18291                                                TNG_FLOAT_DATA,
18292                                                block_type_flag,
18293                                                n_frames, n_values_per_frame,
18294                                                stride_length,
18295                                                0, n_particles,
18296                                                compression, 0);
18297             if(stat != TNG_SUCCESS)
18298             {
18299                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18300                        __FILE__, __LINE__);
18301                 return(stat);
18302             }
18303             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18304             {
18305                 p_data = &frame_set->tr_particle_data[frame_set->
18306                                                     n_particle_data_blocks - 1];
18307             }
18308             else
18309             {
18310                 p_data = &tng_data->non_tr_particle_data[tng_data->
18311                                                     n_particle_data_blocks - 1];
18312             }
18313             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18314                                                   stride_length, n_particles,
18315                                                   n_values_per_frame);
18316             if(stat != TNG_SUCCESS)
18317             {
18318                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18319                        __FILE__, __LINE__);
18320                 return(stat);
18321             }
18322         }
18323
18324         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18325         {
18326             stride_length = p_data->stride_length;
18327
18328             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
18329             {
18330                 p_data->first_frame_with_data = frame_nr;
18331                 frame_pos = 0;
18332             }
18333             else
18334             {
18335                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18336             }
18337
18338             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
18339                    n_values_per_frame, values, sizeof(float) *
18340                    n_particles * n_values_per_frame);
18341         }
18342         else
18343         {
18344             memcpy(p_data->values, values, sizeof(float) * n_particles *
18345                    n_values_per_frame);
18346         }
18347     }
18348     else
18349     {
18350         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18351         {
18352             stat = tng_data_block_add(tng_data, block_id, block_name,
18353                                       TNG_FLOAT_DATA, block_type_flag,
18354                                       n_frames, n_values_per_frame,
18355                                       stride_length, compression, 0);
18356             if(stat != TNG_SUCCESS)
18357             {
18358                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18359                        __FILE__, __LINE__);
18360                 return(stat);
18361             }
18362             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18363             {
18364                 np_data = &frame_set->tr_data[frame_set->
18365                                               n_data_blocks - 1];
18366             }
18367             else
18368             {
18369                 np_data = &tng_data->non_tr_data[tng_data->
18370                                                  n_data_blocks - 1];
18371             }
18372             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18373                                          stride_length, n_values_per_frame);
18374             if(stat != TNG_SUCCESS)
18375             {
18376                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18377                        __FILE__, __LINE__);
18378                 return(stat);
18379             }
18380         }
18381
18382         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18383         {
18384             stride_length = np_data->stride_length;
18385
18386             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
18387             {
18388                 np_data->first_frame_with_data = frame_nr;
18389                 frame_pos = 0;
18390             }
18391             else
18392             {
18393                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18394             }
18395
18396             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
18397                    n_values_per_frame, values, sizeof(float) *
18398                    n_values_per_frame);
18399         }
18400         else
18401         {
18402             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
18403         }
18404     }
18405
18406     return(TNG_SUCCESS);
18407 }
18408
18409 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
18410                 (tng_trajectory_t tng_data,
18411                  const int64_t frame_nr,
18412                  const double *values,
18413                  const int64_t n_values_per_frame,
18414                  const int64_t block_id,
18415                  const char *block_name,
18416                  const char particle_dependency,
18417                  const char compression)
18418 {
18419     tng_trajectory_frame_set_t frame_set;
18420     tng_particle_data_t p_data;
18421     tng_non_particle_data_t np_data;
18422     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18423     int64_t last_frame;
18424     int is_first_frame_flag = 0;
18425     char block_type_flag;
18426     tng_function_status stat;
18427
18428     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18429     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18430     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18431
18432     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18433     {
18434         tng_num_particles_get(tng_data, &n_particles);
18435         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18436     }
18437
18438     if(values == 0)
18439     {
18440         return(TNG_FAILURE);
18441     }
18442
18443     frame_set = &tng_data->current_trajectory_frame_set;
18444
18445     if(frame_nr < 0)
18446     {
18447         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18448         n_frames = stride_length = 1;
18449     }
18450     else
18451     {
18452         block_type_flag = TNG_TRAJECTORY_BLOCK;
18453
18454         n_frames = tng_data->frame_set_n_frames;
18455
18456         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18457         {
18458             stat = tng_frame_set_new(tng_data, 0, n_frames);
18459             if(stat != TNG_SUCCESS)
18460             {
18461                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18462                     __LINE__);
18463                 return(stat);
18464             }
18465         }
18466         else
18467         {
18468             n_frames = frame_set->n_frames;
18469         }
18470         last_frame = frame_set->first_frame +
18471                      frame_set->n_frames - 1;
18472         if(frame_nr > last_frame)
18473         {
18474             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18475             if(stat != TNG_SUCCESS)
18476             {
18477                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18478                     __LINE__);
18479                 return(stat);
18480             }
18481             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18482             {
18483                 last_frame = frame_nr - 1;
18484             }
18485             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
18486             if(stat != TNG_SUCCESS)
18487             {
18488                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18489                     __LINE__);
18490                 return(stat);
18491             }
18492         }
18493         if(frame_set->n_unwritten_frames == 0)
18494         {
18495             is_first_frame_flag = 1;
18496         }
18497         frame_set->n_unwritten_frames = frame_nr -
18498                                         frame_set->first_frame + 1;
18499     }
18500
18501     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18502     {
18503         if(tng_particle_data_find(tng_data, block_id, &p_data)
18504         != TNG_SUCCESS)
18505         {
18506             stat = tng_particle_data_block_add(tng_data, block_id,
18507                                             block_name,
18508                                             TNG_DOUBLE_DATA,
18509                                             block_type_flag,
18510                                             n_frames, n_values_per_frame,
18511                                             stride_length,
18512                                             0, n_particles,
18513                                             compression, 0);
18514             if(stat != TNG_SUCCESS)
18515             {
18516                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18517                        __FILE__, __LINE__);
18518                 return(stat);
18519             }
18520             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18521             {
18522                 p_data = &frame_set->tr_particle_data[frame_set->
18523                                                     n_particle_data_blocks - 1];
18524             }
18525             else
18526             {
18527                 p_data = &tng_data->non_tr_particle_data[tng_data->
18528                                                     n_particle_data_blocks - 1];
18529             }
18530             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18531                                                   stride_length, n_particles,
18532                                                   n_values_per_frame);
18533             if(stat != TNG_SUCCESS)
18534             {
18535                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18536                        __FILE__, __LINE__);
18537                 return(stat);
18538             }
18539         }
18540
18541         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18542         {
18543             stride_length = p_data->stride_length;
18544
18545             if(is_first_frame_flag)
18546             {
18547                 p_data->first_frame_with_data = frame_nr;
18548                 frame_pos = 0;
18549             }
18550             else
18551             {
18552                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18553             }
18554
18555             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
18556                    n_values_per_frame, values, sizeof(double) *
18557                    n_particles * n_values_per_frame);
18558         }
18559         else
18560         {
18561             memcpy(p_data->values, values, sizeof(double) * n_particles *
18562                    n_values_per_frame);
18563         }
18564     }
18565     else
18566     {
18567         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18568         {
18569             stat = tng_data_block_add(tng_data, block_id, block_name,
18570                                       TNG_DOUBLE_DATA, block_type_flag,
18571                                       n_frames, n_values_per_frame,
18572                                       stride_length, compression, 0);
18573             if(stat != TNG_SUCCESS)
18574             {
18575                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18576                        __FILE__, __LINE__);
18577                 return(stat);
18578             }
18579             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18580             {
18581                 np_data = &frame_set->tr_data[frame_set->
18582                                               n_data_blocks - 1];
18583             }
18584             else
18585             {
18586                 np_data = &tng_data->non_tr_data[tng_data->
18587                                                  n_data_blocks - 1];
18588             }
18589             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18590                                          stride_length, n_values_per_frame);
18591             if(stat != TNG_SUCCESS)
18592             {
18593                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18594                        __FILE__, __LINE__);
18595                 return(stat);
18596             }
18597         }
18598
18599         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18600         {
18601             stride_length = np_data->stride_length;
18602
18603             if(is_first_frame_flag)
18604             {
18605                 np_data->first_frame_with_data = frame_nr;
18606                 frame_pos = 0;
18607             }
18608             else
18609             {
18610                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18611             }
18612
18613             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
18614                    n_values_per_frame, values, sizeof(double) *
18615                    n_values_per_frame);
18616         }
18617         else
18618         {
18619             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
18620         }
18621     }
18622
18623     return(TNG_SUCCESS);
18624 }
18625
18626 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
18627                 (tng_trajectory_t tng_data,
18628                  const int64_t frame_nr,
18629                  const float *positions)
18630 {
18631     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18632     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18633     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18634
18635     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
18636                                   TNG_TRAJ_POSITIONS, "POSITIONS",
18637                                   TNG_PARTICLE_BLOCK_DATA,
18638                                   TNG_TNG_COMPRESSION));
18639 }
18640
18641 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
18642                 (tng_trajectory_t tng_data,
18643                  const int64_t frame_nr,
18644                  const double *positions)
18645 {
18646     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18647     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18648     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18649
18650     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
18651                                          TNG_TRAJ_POSITIONS, "POSITIONS",
18652                                          TNG_PARTICLE_BLOCK_DATA,
18653                                          TNG_TNG_COMPRESSION));
18654 }
18655
18656 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
18657                 (tng_trajectory_t tng_data,
18658                  const int64_t frame_nr,
18659                  const float *velocities)
18660 {
18661     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18662     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18663     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18664
18665     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
18666                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
18667                                   TNG_PARTICLE_BLOCK_DATA,
18668                                   TNG_TNG_COMPRESSION));
18669 }
18670
18671 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
18672                 (tng_trajectory_t tng_data,
18673                  const int64_t frame_nr,
18674                  const double *velocities)
18675 {
18676     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18677     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18678     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18679
18680     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
18681                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
18682                                          TNG_PARTICLE_BLOCK_DATA,
18683                                          TNG_TNG_COMPRESSION));
18684 }
18685
18686 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
18687                 (tng_trajectory_t tng_data,
18688                  const int64_t frame_nr,
18689                  const float *forces)
18690 {
18691     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18692     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18693     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18694
18695     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
18696                                   TNG_TRAJ_FORCES, "FORCES",
18697                                   TNG_PARTICLE_BLOCK_DATA,
18698                                   TNG_GZIP_COMPRESSION));
18699 }
18700
18701 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
18702                 (tng_trajectory_t tng_data,
18703                  const int64_t frame_nr,
18704                  const double *forces)
18705 {
18706     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18707     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18708     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18709
18710     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
18711                                          TNG_TRAJ_FORCES, "FORCES",
18712                                          TNG_PARTICLE_BLOCK_DATA,
18713                                          TNG_GZIP_COMPRESSION));
18714 }
18715
18716 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
18717                 (tng_trajectory_t tng_data,
18718                  const int64_t frame_nr,
18719                  const float *box_shape)
18720 {
18721     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18722     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18723     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18724
18725     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
18726                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18727                                   TNG_NON_PARTICLE_BLOCK_DATA,
18728                                   TNG_GZIP_COMPRESSION));
18729 }
18730
18731 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
18732                 (tng_trajectory_t tng_data,
18733                  const int64_t frame_nr,
18734                  const double *box_shape)
18735 {
18736     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18737     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18738     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18739
18740     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
18741                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18742                                          TNG_NON_PARTICLE_BLOCK_DATA,
18743                                          TNG_GZIP_COMPRESSION));
18744 }
18745
18746 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
18747                 (tng_trajectory_t tng_data,
18748                  const int64_t frame_nr,
18749                  const double time,
18750                  const float *values,
18751                  const int64_t n_values_per_frame,
18752                  const int64_t block_id,
18753                  const char *block_name,
18754                  const char particle_dependency,
18755                  const char compression)
18756 {
18757     tng_trajectory_frame_set_t frame_set;
18758     tng_function_status stat;
18759
18760     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18761     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18762     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18763     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18764
18765     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
18766                                   block_id, block_name,
18767                                   particle_dependency,
18768                                   compression);
18769
18770     if(stat != TNG_SUCCESS)
18771     {
18772         return(stat);
18773     }
18774
18775     frame_set = &tng_data->current_trajectory_frame_set;
18776
18777     /* first_frame_time is -1 when it is not yet set. */
18778     if(frame_set->first_frame_time < -0.1)
18779     {
18780         if(frame_nr > frame_set->first_frame)
18781         {
18782             stat = tng_frame_set_first_frame_time_set(tng_data,
18783                                                       time -
18784                                                       (frame_nr -
18785                                                        frame_set->first_frame) *
18786                                                       tng_data->time_per_frame);
18787         }
18788         else
18789         {
18790             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18791         }
18792     }
18793     return(stat);
18794 }
18795
18796 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18797                 (tng_trajectory_t tng_data,
18798                  const int64_t frame_nr,
18799                  const double time,
18800                  const double *values,
18801                  const int64_t n_values_per_frame,
18802                  const int64_t block_id,
18803                  const char *block_name,
18804                  const char particle_dependency,
18805                  const char compression)
18806 {
18807     tng_trajectory_frame_set_t frame_set;
18808     tng_function_status stat;
18809
18810     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18811     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18812     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18813     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18814
18815     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18816                                          block_id, block_name,
18817                                          particle_dependency,
18818                                          compression);
18819
18820     if(stat != TNG_SUCCESS)
18821     {
18822         return(stat);
18823     }
18824
18825     frame_set = &tng_data->current_trajectory_frame_set;
18826
18827     /* first_frame_time is -1 when it is not yet set. */
18828     if(frame_set->first_frame_time < -0.1)
18829     {
18830         if(frame_nr > frame_set->first_frame)
18831         {
18832             stat = tng_frame_set_first_frame_time_set(tng_data,
18833                                                       time -
18834                                                       (frame_nr -
18835                                                        frame_set->first_frame) *
18836                                                       tng_data->time_per_frame);
18837         }
18838         else
18839         {
18840             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18841         }
18842     }
18843     return(stat);
18844 }
18845
18846 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18847                 (tng_trajectory_t tng_data,
18848                  const int64_t frame_nr,
18849                  const double time,
18850                  const float *positions)
18851 {
18852     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18853     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18854     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18855     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18856
18857     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18858                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18859                                             TNG_PARTICLE_BLOCK_DATA,
18860                                             TNG_TNG_COMPRESSION));
18861 }
18862
18863 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18864                 (tng_trajectory_t tng_data,
18865                  const int64_t frame_nr,
18866                  const double time,
18867                  const double *positions)
18868 {
18869     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18870     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18871     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18872     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18873
18874     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18875                                                    positions, 3,
18876                                                    TNG_TRAJ_POSITIONS,
18877                                                    "POSITIONS",
18878                                                    TNG_PARTICLE_BLOCK_DATA,
18879                                                    TNG_TNG_COMPRESSION));
18880 }
18881
18882 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18883                 (tng_trajectory_t tng_data,
18884                  const int64_t frame_nr,
18885                  const double time,
18886                  const float *velocities)
18887 {
18888     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18889     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18890     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18891     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18892
18893     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18894                                             velocities, 3,
18895                                             TNG_TRAJ_VELOCITIES,
18896                                             "VELOCITIES",
18897                                             TNG_PARTICLE_BLOCK_DATA,
18898                                             TNG_TNG_COMPRESSION));
18899 }
18900
18901 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18902                 (tng_trajectory_t tng_data,
18903                  const int64_t frame_nr,
18904                  const double time,
18905                  const double *velocities)
18906 {
18907     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18908     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18909     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18910     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18911
18912     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18913                                                    velocities, 3,
18914                                                    TNG_TRAJ_VELOCITIES,
18915                                                    "VELOCITIES",
18916                                                    TNG_PARTICLE_BLOCK_DATA,
18917                                                    TNG_TNG_COMPRESSION));
18918 }
18919
18920 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18921                 (tng_trajectory_t tng_data,
18922                  const int64_t frame_nr,
18923                  const double time,
18924                  const float *forces)
18925 {
18926     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18927     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18928     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18929     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18930
18931     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18932                                             3, TNG_TRAJ_FORCES, "FORCES",
18933                                             TNG_PARTICLE_BLOCK_DATA,
18934                                             TNG_GZIP_COMPRESSION));
18935 }
18936
18937 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18938                 (tng_trajectory_t tng_data,
18939                  const int64_t frame_nr,
18940                  const double time,
18941                  const double *forces)
18942 {
18943     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18944     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18945     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18946     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18947
18948     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18949                                                    forces, 3,
18950                                                    TNG_TRAJ_FORCES, "FORCES",
18951                                                    TNG_PARTICLE_BLOCK_DATA,
18952                                                    TNG_GZIP_COMPRESSION));
18953 }
18954
18955 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18956                 (tng_trajectory_t tng_data,
18957                  const int64_t frame_nr,
18958                  const double time,
18959                  const float *box_shape)
18960 {
18961     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18962     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18963     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18964     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18965
18966     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
18967                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18968                                             TNG_NON_PARTICLE_BLOCK_DATA,
18969                                             TNG_GZIP_COMPRESSION));
18970 }
18971
18972 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
18973                 (tng_trajectory_t tng_data,
18974                  const int64_t frame_nr,
18975                  const double time,
18976                  const double *box_shape)
18977 {
18978     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18979     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18980     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18981     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18982
18983     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
18984                                                    time, box_shape, 9,
18985                                                    TNG_TRAJ_BOX_SHAPE,
18986                                                    "BOX SHAPE",
18987                                                    TNG_NON_PARTICLE_BLOCK_DATA,
18988                                                    TNG_GZIP_COMPRESSION));
18989 }
18990
18991 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
18992                 (tng_trajectory_t tng_data,
18993                  const int64_t block_id,
18994                  int64_t *codec_id,
18995                  double *factor)
18996 {
18997     tng_trajectory_frame_set_t frame_set;
18998     tng_particle_data_t p_data = 0;
18999     tng_non_particle_data_t np_data = 0;
19000     tng_function_status stat;
19001     int64_t i;
19002     int block_type = -1;
19003
19004     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19005     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
19006     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
19007
19008     frame_set = &tng_data->current_trajectory_frame_set;
19009
19010     stat = tng_particle_data_find(tng_data, block_id, &p_data);
19011     if(stat == TNG_SUCCESS)
19012     {
19013         block_type = TNG_PARTICLE_BLOCK_DATA;
19014     }
19015     else
19016     {
19017         stat = tng_data_find(tng_data, block_id, &np_data);
19018         if(stat == TNG_SUCCESS)
19019         {
19020             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19021         }
19022         else
19023         {
19024             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19025             if(stat != TNG_SUCCESS)
19026             {
19027                 return(stat);
19028             }
19029             stat = tng_particle_data_find(tng_data, block_id, &p_data);
19030             if(stat == TNG_SUCCESS)
19031             {
19032                 block_type = TNG_PARTICLE_BLOCK_DATA;
19033             }
19034             else
19035             {
19036                 stat = tng_data_find(tng_data, block_id, &np_data);
19037                 if(stat == TNG_SUCCESS)
19038                 {
19039                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19040                 }
19041                 else
19042                 {
19043                     return(stat);
19044                 }
19045             }
19046         }
19047     }
19048     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19049     {
19050         if(p_data->last_retrieved_frame < 0)
19051         {
19052             i = p_data->first_frame_with_data;
19053         }
19054         else
19055         {
19056             i = p_data->last_retrieved_frame;
19057         }
19058     }
19059     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19060     {
19061         if(np_data->last_retrieved_frame < 0)
19062         {
19063             i = np_data->first_frame_with_data;
19064         }
19065         else
19066         {
19067             i = np_data->last_retrieved_frame;
19068         }
19069     }
19070     else
19071     {
19072         return(TNG_FAILURE);
19073     }
19074     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
19075     {
19076         stat = tng_frame_set_of_frame_find(tng_data, i);
19077         if(stat != TNG_SUCCESS)
19078         {
19079             return(stat);
19080         }
19081         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19082         if(stat != TNG_SUCCESS)
19083         {
19084             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19085                 __FILE__, __LINE__);
19086             return(stat);
19087         }
19088     }
19089     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19090     {
19091         *codec_id = p_data->codec_id;
19092         *factor   = p_data->compression_multiplier;
19093     }
19094     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19095     {
19096         *codec_id = np_data->codec_id;
19097         *factor   = np_data->compression_multiplier;
19098     }
19099     return(TNG_SUCCESS);
19100 }
19101
19102 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
19103                 (tng_trajectory_t tng_data,
19104                  int64_t current_frame,
19105                  const int64_t n_requested_data_block_ids,
19106                  const int64_t *requested_data_block_ids,
19107                  int64_t *next_frame,
19108                  int64_t *n_data_blocks_in_next_frame,
19109                  int64_t **data_block_ids_in_next_frame)
19110 {
19111     tng_trajectory_frame_set_t frame_set;
19112     tng_function_status stat;
19113     tng_particle_data_t p_data;
19114     tng_non_particle_data_t np_data;
19115     tng_gen_block_t block;
19116     int64_t i, j, block_id, *temp;
19117     int64_t data_frame, frame_diff, min_diff;
19118     int64_t size, frame_set_file_pos, file_pos;
19119     int found, read_all = 0;
19120
19121     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19122     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
19123     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
19124     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19125
19126     if(n_requested_data_block_ids)
19127     {
19128         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.");
19129         size = sizeof(int64_t) * n_requested_data_block_ids;
19130         temp = realloc(*data_block_ids_in_next_frame, size);
19131         if(!temp)
19132         {
19133             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19134                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19135                     __FILE__, __LINE__);
19136             free(*data_block_ids_in_next_frame);
19137             *data_block_ids_in_next_frame = 0;
19138             return(TNG_CRITICAL);
19139         }
19140         *data_block_ids_in_next_frame = temp;
19141     }
19142
19143     frame_set = &tng_data->current_trajectory_frame_set;
19144
19145     current_frame += 1;
19146
19147     if(current_frame < frame_set->first_frame ||
19148        current_frame >= frame_set->first_frame + frame_set->n_frames)
19149     {
19150         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
19151         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
19152         if(stat != TNG_SUCCESS)
19153         {
19154             /* If the frame set search found the frame set after the starting
19155              * frame set there is a gap in the frame sets. So, even if the frame
19156              * was not found the next frame with data is still in the found
19157              * frame set. */
19158             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
19159                frame_set_file_pos)
19160             {
19161                 return(stat);
19162             }
19163             current_frame = frame_set->first_frame;
19164         }
19165     }
19166
19167     /* Check for data blocks only if they have not already been found. */
19168     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
19169     {
19170         file_pos = ftello(tng_data->input_file);
19171         if(file_pos < tng_data->input_file_len)
19172         {
19173             tng_block_init(&block);
19174             stat = tng_block_header_read(tng_data, block);
19175             while(file_pos < tng_data->input_file_len &&
19176                 stat != TNG_CRITICAL &&
19177                 block->id != TNG_TRAJECTORY_FRAME_SET &&
19178                 block->id != -1)
19179             {
19180                 stat = tng_block_read_next(tng_data, block,
19181                                         TNG_USE_HASH);
19182                 if(stat != TNG_CRITICAL)
19183                 {
19184                     file_pos = ftello(tng_data->input_file);
19185                     if(file_pos < tng_data->input_file_len)
19186                     {
19187                         stat = tng_block_header_read(tng_data, block);
19188                     }
19189                 }
19190             }
19191             tng_block_destroy(&block);
19192             if(stat == TNG_CRITICAL)
19193             {
19194                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
19195                         file_pos, __FILE__, __LINE__);
19196                 return(stat);
19197             }
19198         }
19199         read_all = 1;
19200     }
19201
19202     min_diff = -1;
19203
19204     *n_data_blocks_in_next_frame = 0;
19205
19206     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
19207     {
19208         p_data = &frame_set->tr_particle_data[i];
19209         block_id = p_data->block_id;
19210
19211         if(n_requested_data_block_ids > 0)
19212         {
19213             found = 0;
19214             for(j = 0; j < n_requested_data_block_ids; j++)
19215             {
19216                 if(block_id == requested_data_block_ids[j])
19217                 {
19218                     found = 1;
19219                     break;
19220                 }
19221             }
19222             if(!found)
19223             {
19224                 continue;
19225             }
19226         }
19227
19228         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
19229            p_data->last_retrieved_frame >=
19230            frame_set->first_frame + frame_set->n_frames))
19231         {
19232             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19233                                                                       TNG_USE_HASH, block_id);
19234             if(stat == TNG_CRITICAL)
19235             {
19236                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19237                     __FILE__, __LINE__);
19238                 return(stat);
19239             }
19240             if(stat == TNG_FAILURE)
19241             {
19242                 continue;
19243             }
19244         }
19245         if(frame_set->first_frame != current_frame &&
19246            p_data->last_retrieved_frame >= 0)
19247         {
19248             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
19249         }
19250         else
19251         {
19252             data_frame = p_data->first_frame_with_data;
19253         }
19254         frame_diff = data_frame - current_frame;
19255         if(frame_diff < 0)
19256         {
19257             continue;
19258         }
19259         if(min_diff == -1 || frame_diff <= min_diff)
19260         {
19261             if(frame_diff < min_diff)
19262             {
19263                 *n_data_blocks_in_next_frame = 1;
19264             }
19265             else
19266             {
19267                 *n_data_blocks_in_next_frame += 1;
19268             }
19269             if(n_requested_data_block_ids <= 0)
19270             {
19271                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19272                 temp = realloc(*data_block_ids_in_next_frame, size);
19273                 if(!temp)
19274                 {
19275                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19276                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19277                            __FILE__, __LINE__);
19278                     free(*data_block_ids_in_next_frame);
19279                     *data_block_ids_in_next_frame = 0;
19280                     return(TNG_CRITICAL);
19281                 }
19282                 *data_block_ids_in_next_frame = temp;
19283             }
19284             else
19285             {
19286                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19287             }
19288             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19289
19290             min_diff = frame_diff;
19291         }
19292     }
19293     for(i = 0; i < frame_set->n_data_blocks; i++)
19294     {
19295         np_data = &frame_set->tr_data[i];
19296         block_id = np_data->block_id;
19297
19298         if(n_requested_data_block_ids > 0)
19299         {
19300             found = 0;
19301             for(j = 0; j < n_requested_data_block_ids; j++)
19302             {
19303                 if(block_id == requested_data_block_ids[j])
19304                 {
19305                     found = 1;
19306                     break;
19307                 }
19308             }
19309             if(!found)
19310             {
19311                 continue;
19312             }
19313         }
19314
19315         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
19316            np_data->last_retrieved_frame >=
19317            frame_set->first_frame + frame_set->n_frames))
19318         {
19319             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19320                                                                       TNG_USE_HASH, block_id);
19321             if(stat == TNG_CRITICAL)
19322             {
19323                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19324                     __FILE__, __LINE__);
19325                 return(stat);
19326             }
19327             if(stat == TNG_FAILURE)
19328             {
19329                 continue;
19330             }
19331         }
19332         if(frame_set->first_frame != current_frame &&
19333            np_data->last_retrieved_frame >= 0)
19334         {
19335             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
19336         }
19337         else
19338         {
19339             data_frame = np_data->first_frame_with_data;
19340         }
19341         frame_diff = data_frame - current_frame;
19342         if(frame_diff < 0)
19343         {
19344             continue;
19345         }
19346         if(min_diff == -1 || frame_diff <= min_diff)
19347         {
19348             if(frame_diff < min_diff)
19349             {
19350                 *n_data_blocks_in_next_frame = 1;
19351             }
19352             else
19353             {
19354                 *n_data_blocks_in_next_frame += 1;
19355             }
19356             if(n_requested_data_block_ids <= 0)
19357             {
19358                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19359                 temp = realloc(*data_block_ids_in_next_frame, size);
19360                 if(!temp)
19361                 {
19362                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
19363                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19364                            __FILE__, __LINE__);
19365                     free(*data_block_ids_in_next_frame);
19366                     *data_block_ids_in_next_frame = 0;
19367                     return(TNG_CRITICAL);
19368                 }
19369                 *data_block_ids_in_next_frame = temp;
19370             }
19371             else
19372             {
19373                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19374             }
19375             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19376
19377             min_diff = frame_diff;
19378         }
19379     }
19380     if(min_diff < 0)
19381     {
19382         return(TNG_FAILURE);
19383     }
19384     *next_frame = current_frame + min_diff;
19385
19386     return(TNG_SUCCESS);
19387 }
19388
19389 /*
19390 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
19391                 (tng_trajectory_t tng_data,
19392                  int64_t *n_data_blocks,
19393                  int64_t **data_block_ids,
19394                  char ***data_block_names,
19395                  int64_t **stride_lengths,
19396                  int64_t **n_values_per_frame,
19397                  char **block_types,
19398                  char **dependencies,
19399                  char **compressions)
19400 {
19401     tng_gen_block_t block;
19402     int64_t orig_file_pos, file_pos;
19403
19404     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19405     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
19406     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19407     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
19408     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
19409
19410     orig_file_pos = ftello(tng_data->input_file);
19411
19412     if(!tng_data->input_file_len)
19413     {
19414         fseeko(tng_data->input_file, 0, SEEK_END);
19415         tng_data->input_file_len = ftello(tng_data->input_file);
19416     }
19417
19418     fseeko(tng_data->input_file, 0, SEEK_SET);
19419     file_pos = 0;
19420
19421     *n_data_blocks = 0;
19422
19423     tng_block_init(&block);
19424
19425     while(file_pos < tng_data->input_file_len &&
19426           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
19427     {
19428         if(block->id > TNG_TRAJECTORY_FRAME_SET)
19429         {
19430
19431         }
19432         file_pos += (block->block_contents_size + block->header_contents_size);
19433         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
19434     }
19435
19436     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
19437
19438     return(TNG_SUCCESS);
19439 }
19440 */
19441 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
19442                 (tng_trajectory_t tng_data,
19443                  const int64_t prev_frame)
19444 {
19445     tng_function_status stat;
19446     FILE *temp = tng_data->input_file;
19447
19448     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19449     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
19450
19451     tng_data->input_file = tng_data->output_file;
19452
19453     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
19454     if(stat != TNG_SUCCESS)
19455     {
19456         return(stat);
19457     }
19458
19459     tng_data->current_trajectory_frame_set_output_file_pos =
19460     tng_data->current_trajectory_frame_set_input_file_pos;
19461
19462     tng_data->input_file = temp;
19463
19464     return(TNG_SUCCESS);
19465 }