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