Fix ICC warnings
[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 #if defined( _WIN32 ) || defined( _WIN64 )
38     #ifndef fseeko
39         #define fseeko _fseeki64
40     #endif
41     #ifndef ftello
42         #ifdef __MINGW32__
43             #define ftello ftello64
44         #else
45             #define ftello _ftelli64
46         #endif
47     #endif
48 #endif
49
50 struct tng_bond {
51     /** One of the atoms of the bond */
52     int64_t from_atom_id;
53     /** The other atom of the bond */
54     int64_t to_atom_id;
55 };
56
57 struct tng_atom {
58     /** The residue containing this atom */
59     tng_residue_t residue;
60     /** A unique (per molecule) ID number of the atom */
61     int64_t id;
62     /** The atom_type (depending on the forcefield) */
63     char *atom_type;
64     /** The name of the atom */
65     char *name;
66 };
67
68 struct tng_residue {
69     /** The chain containing this residue */
70     tng_chain_t chain;
71     /** A unique (per chain) ID number of the residue */
72     int64_t id;
73     /** The name of the residue */
74     char *name;
75     /** The number of atoms in the residue */
76     int64_t n_atoms;
77     /** A list of atoms in the residue */
78     int64_t atoms_offset;
79 };
80
81 struct tng_chain {
82     /** The molecule containing this chain */
83     tng_molecule_t molecule;
84     /** A unique (per molecule) ID number of the chain */
85     int64_t id;
86     /** The name of the chain */
87     char *name;
88     /** The number of residues in the chain */
89     int64_t n_residues;
90     /** A list of residues in the chain */
91     tng_residue_t residues;
92 };
93
94 struct tng_molecule {
95     /** A unique ID number of the molecule */
96     int64_t id;
97     /** Quaternary structure of the molecule.
98      *  1 => monomeric
99      *  2 => dimeric
100      *  3 => trimeric
101      *  etc */
102     int64_t quaternary_str;
103     /** The number of chains in the molecule */
104     int64_t n_chains;
105     /** The number of residues in the molecule */
106     int64_t n_residues;
107     /** The number of atoms in the molecule */
108     int64_t n_atoms;
109     /** The number of bonds in the molecule. If the bonds are not specified this
110      * value can be 0. */
111     int64_t n_bonds;
112     /** The name of the molecule */
113     char *name;
114     /** A list of chains in the molecule */
115     tng_chain_t chains;
116     /** A list of residues in the molecule */
117     tng_residue_t residues;
118     /** A list of the atoms in the molecule */
119     tng_atom_t atoms;
120     /** A list of the bonds in the molecule */
121     tng_bond_t bonds;
122 };
123
124 struct tng_gen_block {
125     /** The size of the block header in bytes */
126     int64_t header_contents_size;
127     /** The size of the block contents in bytes */
128     int64_t block_contents_size;
129     /** The ID of the block to determine its type */
130     int64_t id;
131     /** The MD5 hash of the block to verify integrity */
132     char md5_hash[TNG_MD5_HASH_LEN];
133     /** The name of the block */
134     char *name;
135     /** The library version used to write the block */
136     int64_t block_version;
137     int64_t alt_hash_type;
138     int64_t alt_hash_len;
139     char *alt_hash;
140     int64_t signature_type;
141     int64_t signature_len;
142     char *signature;
143     /** The full block header contents */
144     char *header_contents;
145     /** The full block contents */
146     char *block_contents;
147 };
148
149 struct tng_particle_mapping {
150     /** The index number of the first particle in this mapping block */
151     int64_t num_first_particle;
152     /** The number of particles list in this mapping block */
153     int64_t n_particles;
154     /** the mapping of index numbers to the real particle numbers in the
155      * trajectory. real_particle_numbers[0] is the real particle number
156      * (as it is numbered in the molecular system) of the first particle
157      * in the data blocks covered by this particle mapping block */
158     int64_t *real_particle_numbers;
159 };
160
161 struct tng_trajectory_frame_set {
162     /** The number of different particle mapping blocks present. */
163     int64_t n_mapping_blocks;
164     /** The atom mappings of this frame set */
165     struct tng_particle_mapping *mappings;
166     /** The first frame of this frame set */
167     int64_t first_frame;
168     /** The number of frames in this frame set */
169     int64_t n_frames;
170     /** The number of written frames in this frame set (used when writing one
171      * frame at a time). */
172     int64_t n_written_frames;
173     /** The number of frames not yet written to file in this frame set
174      * (used from the utility functions to finish the writing properly. */
175     int64_t n_unwritten_frames;
176
177
178     /** A list of the number of each molecule type - only used when using
179      * variable number of atoms */
180     int64_t *molecule_cnt_list;
181     /** The number of particles/atoms - only used when using variable number
182      * of atoms */
183     int64_t n_particles;
184     /** The file position of the next frame set */
185     int64_t next_frame_set_file_pos;
186     /** The file position of the previous frame set */
187     int64_t prev_frame_set_file_pos;
188     /** The file position of the frame set one long stride step ahead */
189     int64_t medium_stride_next_frame_set_file_pos;
190     /** The file position of the frame set one long stride step behind */
191     int64_t medium_stride_prev_frame_set_file_pos;
192     /** The file position of the frame set one long stride step ahead */
193     int64_t long_stride_next_frame_set_file_pos;
194     /** The file position of the frame set one long stride step behind */
195     int64_t long_stride_prev_frame_set_file_pos;
196     /** Time stamp (in seconds) of first frame in frame set */
197     double first_frame_time;
198
199     /* The data blocks in a frame set are trajectory data blocks */
200     /** The number of trajectory data blocks of particle dependent data */
201     int n_particle_data_blocks;
202     /** A list of data blocks containing particle dependent data */
203     struct tng_particle_data *tr_particle_data;
204     /** The number of trajectory data blocks independent of particles */
205     int n_data_blocks;
206     /** A list of data blocks containing particle indepdendent data */
207     struct tng_non_particle_data *tr_data;
208 };
209
210 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
211 /* FIXME: Make only one data block struct */
212 struct tng_particle_data {
213     /** The block ID of the data block containing this particle data.
214      *  This is used to determine the kind of data that is stored */
215     int64_t block_id;
216     /** The name of the data block. This is used to determine the kind of
217      *  data that is stored */
218     char *block_name;
219     /** The type of data stored. */
220     char datatype;
221     /** The frame number of the first data value */
222     int64_t first_frame_with_data;
223     /** The number of frames in this frame set */
224     int64_t n_frames;
225     /** The number of values stored per frame */
226     int64_t n_values_per_frame;
227     /** The number of frames between each data point - e.g. when
228      *  storing sparse data. */
229     int64_t stride_length;
230     /** ID of the CODEC used for compression 0 == no compression. */
231     int64_t codec_id;
232     /** If reading one frame at a time this is the last read frame */
233     int64_t last_retrieved_frame;
234     /** The multiplier used for getting integer values for compression */
235     double compression_multiplier;
236     /** A 1-dimensional array of values of length
237      *  [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
238     void *values;
239     /** If storing character data store it in a 3-dimensional array */
240     char ****strings;
241 };
242
243 struct tng_non_particle_data {
244     /** The ID of the data block */
245     int64_t block_id;
246     /** The name of the data block. This is used to determine the kind of
247      *  data that is stored */
248     char *block_name;
249     /** The type of data stored. */
250     char datatype;
251     /** The first frame number of the first data value */
252     int64_t first_frame_with_data;
253     /** The number of frames in this data block */
254     int64_t n_frames;
255     /** The number of values stored per frame */
256     int64_t n_values_per_frame;
257     /** The number of frames between each data value, e.g. if storing data
258      *  that is not saved every frame. */
259     int64_t stride_length;
260     /** ID of the CODEC used for compression. 0 == no compression. */
261     int64_t codec_id;
262     /** If reading one frame at a time this is the last read frame */
263     int64_t last_retrieved_frame;
264     /** Compressed data is stored as integers. This compression multiplier is
265      *  the multiplication factor to convert from integer to float/double */
266     double compression_multiplier;
267     /** A 1-dimensional array of values of length
268      *  [sizeof (datatype)] * n_frames * n_values_per_frame */
269     void *values;
270     /** If storing character data store it in a 2-dimensional array */
271     char ***strings;
272 };
273
274
275
276 struct tng_trajectory {
277     /** The path of the input trajectory file */
278     char *input_file_path;
279     /** A handle to the input file */
280     FILE *input_file;
281     /** The length of the input file */
282     int64_t input_file_len;
283     /** The path of the output trajectory file */
284     char *output_file_path;
285     /** A handle to the output file */
286     FILE *output_file;
287     /** Function to swap 32 bit values to and from the endianness of the
288      * input file */
289     tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
290     /** Function to swap 64 bit values to and from the endianness of the
291      * input file */
292     tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
293     /** Function to swap 32 bit values to and from the endianness of the
294      * input file */
295     tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
296     /** Function to swap 64 bit values to and from the endianness of the
297      * input file */
298     tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
299     /** The endianness of 32 bit values of the current computer */
300     char endianness_32;
301     /** The endianness of 64 bit values of the current computer */
302     char endianness_64;
303
304     /** The name of the program producing this trajectory */
305     char *first_program_name;
306     /** The forcefield used in the simulations */
307     char *forcefield_name;
308     /** The name of the user running the simulations */
309     char *first_user_name;
310     /** The name of the computer on which the simulations were performed */
311     char *first_computer_name;
312     /** The PGP signature of the user creating the file. */
313     char *first_pgp_signature;
314     /** The name of the program used when making last modifications to the
315      *  file */
316     char *last_program_name;
317     /** The name of the user making the last modifications to the file */
318     char *last_user_name;
319     /** The name of the computer on which the last modifications were made */
320     char *last_computer_name;
321     /** The PGP signature of the user making the last modifications to the
322      *  file. */
323     char *last_pgp_signature;
324     /** The time (n seconds since 1970) when the file was created */
325     int64_t time;
326     /** The exponential of the value of the distance unit used. The default
327      * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
328      * the measurements are in Ã… the distance_unit_exponential = -10. */
329     int64_t distance_unit_exponential;
330
331     /** A flag indicating if the number of atoms can vary throughout the
332      *  simulation, e.g. using a grand canonical ensemble */
333     char var_num_atoms_flag;
334     /** The number of frames in a frame set. It is allowed to have frame sets
335      *  with fewer frames, but this will help searching for specific frames */
336     int64_t frame_set_n_frames;
337     /** The number of frame sets in a medium stride step */
338     int64_t medium_stride_length;
339     /** The number of frame sets in a long stride step */
340     int64_t long_stride_length;
341     /** The current (can change from one frame set to another) time length
342      *  (in seconds) of one frame */
343     double time_per_frame;
344
345     /** The number of different kinds of molecules in the trajectory */
346     int64_t n_molecules;
347     /** A list of molecules in the trajectory */
348     tng_molecule_t molecules;
349     /** A list of the count of each molecule - if using variable number of
350      *  particles this will be specified in each frame set */
351     int64_t *molecule_cnt_list;
352     /** The total number of particles/atoms. If using variable number of
353      *  particles this will be specified in each frame set */
354     int64_t n_particles;
355
356      /** The pos in the src file of the first frame set */
357     int64_t first_trajectory_frame_set_input_file_pos;
358     /** The pos in the dest file of the first frame set */
359     int64_t first_trajectory_frame_set_output_file_pos;
360     /** The pos in the src file of the last frame set */
361     int64_t last_trajectory_frame_set_input_file_pos;
362     /** The pos in the dest file of the last frame set */
363     int64_t last_trajectory_frame_set_output_file_pos;
364     /** The currently active frame set */
365     struct tng_trajectory_frame_set current_trajectory_frame_set;
366     /** The pos in the src file of the current frame set */
367     int64_t current_trajectory_frame_set_input_file_pos;
368     /** The pos in the dest file of the current frame set */
369     int64_t current_trajectory_frame_set_output_file_pos;
370     /** The number of frame sets in the trajectory N.B. Not saved in file and
371      *  cannot be trusted to be up-to-date */
372     int64_t n_trajectory_frame_sets;
373
374     /* These data blocks are non-trajectory data blocks */
375     /** The number of non-frame dependent particle dependent data blocks */
376     int n_particle_data_blocks;
377     /** A list of data blocks containing particle dependent data */
378     struct tng_particle_data *non_tr_particle_data;
379
380     /** The number of frame and particle independent data blocks */
381     int n_data_blocks;
382     /** A list of frame and particle indepdendent data blocks */
383     struct tng_non_particle_data *non_tr_data;
384
385     /** TNG compression algorithm for compressing positions */
386     int *compress_algo_pos;
387     /** TNG compression algorithm for compressing velocities */
388     int *compress_algo_vel;
389     /** The precision used for lossy compression */
390     double compression_precision;
391 };
392
393 #ifndef USE_WINDOWS
394 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
395 #define USE_WINDOWS
396 #endif /* win32... */
397 #endif /* not defined USE_WINDOWS */
398
399 #ifdef USE_WINDOWS
400 #define TNG_INLINE __inline
401 #define TNG_SNPRINTF _snprintf
402 #else
403 #define TNG_INLINE inline
404 #define TNG_SNPRINTF snprintf
405 #endif
406
407 static TNG_INLINE int tng_min_i(int a, int b)
408 {
409     return (a < b ? a : b);
410 }
411
412 /*
413 static TNG_INLINE int tng_max_i(int a, int b)
414 {
415     return (a > b ? a : b);
416 }
417 */
418 static TNG_INLINE int64_t tng_min_i64(int64_t a, int64_t b)
419 {
420     return (a < b ? a : b);
421 }
422
423 static TNG_INLINE int64_t tng_max_i64(int64_t a, int64_t b)
424 {
425     return (a > b ? a : b);
426 }
427
428 /*
429 static TNG_INLINE float tng_min_f(float a, float b)
430 {
431     return (a < b ? a : b);
432 }
433
434 static TNG_INLINE float tng_max_f(float a, float b)
435 {
436     return (a > b ? a : b);
437 }
438
439 static TNG_INLINE double tng_min_d(double a, double b)
440 {
441     return (a < b ? a : b);
442 }
443
444 static TNG_INLINE double tng_max_d(double a, double b)
445 {
446     return (a > b ? a : b);
447 }
448 */
449
450 /** This function swaps the byte order of a 32 bit numerical variable
451  * to big endian.
452  * It does not only work with integer, but e.g. floats need casting.
453  * If the byte order is already big endian no change is needed.
454  * @param tng_data is a trajectory data container.
455  * @param v is a pointer to a 32 bit numerical value (float or integer).
456  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
457  * byte order is not recognised.
458  */
459 static tng_function_status tng_swap_byte_order_big_endian_32
460                 (const tng_trajectory_t tng_data, int32_t *v)
461 {
462     switch(tng_data->endianness_32)
463     {
464     case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
465         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
466              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
467              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
468              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
469
470         return(TNG_SUCCESS);
471
472     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
473         *v = ((*v & 0xFFFF0000) >> 16) |
474              ((*v & 0x0000FFFF) << 16);
475
476         return(TNG_SUCCESS);
477
478     case TNG_BIG_ENDIAN_32: /* Already correct */
479         return(TNG_SUCCESS);
480
481     default:
482         return(TNG_FAILURE);
483     }
484 }
485
486 /** This function swaps the byte order of a 64 bit numerical variable
487  * to big endian.
488  * It does not only work with integer, but e.g. floats need casting.
489  * The byte order swapping routine can convert four different byte
490  * orders to big endian.
491  * If the byte order is already big endian no change is needed.
492  * @param tng_data is a trajectory data container.
493  * @param v is a pointer to a 64 bit numerical value (double or integer).
494  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
495  * byte order is not recognised.
496  */
497 static tng_function_status tng_swap_byte_order_big_endian_64
498                 (const tng_trajectory_t tng_data, int64_t *v)
499 {
500     switch(tng_data->endianness_64)
501     {
502     case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
503         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
504              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
505              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
506              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
507              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
508              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
509              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
510              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
511
512         return(TNG_SUCCESS);
513
514     case TNG_QUAD_SWAP_64: /* Byte quad swap */
515         *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
516              ((*v & 0x00000000FFFFFFFFLL) << 32);
517
518         return(TNG_SUCCESS);
519
520     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
521         *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
522              ((*v & 0x0000FFFF0000FFFFLL) << 16);
523
524         return(TNG_SUCCESS);
525
526     case TNG_BYTE_SWAP_64: /* Byte swap */
527         *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
528              ((*v & 0x00FF00FF00FF00FFLL) << 8);
529
530         return(TNG_SUCCESS);
531
532     case TNG_BIG_ENDIAN_64: /* Already correct */
533         return(TNG_SUCCESS);
534
535     default:
536         return(TNG_FAILURE);
537     }
538 }
539
540 /** This function swaps the byte order of a 32 bit numerical variable
541  * to little endian.
542  * It does not only work with integer, but e.g. floats need casting.
543  * If the byte order is already little endian no change is needed.
544  * @param tng_data is a trajectory data container.
545  * @param v is a pointer to a 32 bit numerical value (float or integer).
546  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
547  * byte order is not recognised.
548  */
549 static tng_function_status tng_swap_byte_order_little_endian_32
550                 (const tng_trajectory_t tng_data, int32_t *v)
551 {
552     switch(tng_data->endianness_32)
553     {
554     case TNG_LITTLE_ENDIAN_32: /* Already correct */
555         return(TNG_SUCCESS);
556
557     case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
558         *v = ((*v & 0xFF00FF00) >> 8) |
559              ((*v & 0x00FF00FF) << 8);
560
561         return(TNG_SUCCESS);
562
563     case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
564         *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
565              ((*v & 0x00FF0000) >> 8) |  /* Move 2nd byte to pos 3 */
566              ((*v & 0x0000FF00) << 8) |  /* Move 3rd byte to pos 2 */
567              ((*v & 0x000000FF) << 24);  /* Move last byte to first */
568
569         return(TNG_SUCCESS);
570
571     default:
572         return(TNG_FAILURE);
573     }
574 }
575
576 /** This function swaps the byte order of a 64 bit numerical variable
577  * to little endian.
578  * It does not only work with integer, but e.g. floats need casting.
579  * The byte order swapping routine can convert four different byte
580  * orders to little endian.
581  * If the byte order is already little endian no change is needed.
582  * @param tng_data is a trajectory data container.
583  * @param v is a pointer to a 64 bit numerical value (double or integer).
584  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
585  * byte order is not recognised.
586  */
587 static tng_function_status tng_swap_byte_order_little_endian_64
588                 (const tng_trajectory_t tng_data, int64_t *v)
589 {
590     switch(tng_data->endianness_64)
591     {
592     case TNG_LITTLE_ENDIAN_64: /* Already correct */
593         return(TNG_SUCCESS);
594
595     case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
596         *v = ((*v & 0xFF000000FF000000LL) >> 24) |
597              ((*v & 0x00FF000000FF0000LL) >> 8) |
598              ((*v & 0x0000FF000000FF00LL) << 8) |
599              ((*v & 0x000000FF000000FFLL) << 24);
600
601         return(TNG_SUCCESS);
602
603     case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
604         *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
605              ((*v & 0x00FF00FF00000000LL) >> 24) |
606              ((*v & 0x00000000FF00FF00LL) << 24) |
607              ((*v & 0x0000000000FF00FFLL) << 40);
608
609         return(TNG_SUCCESS);
610
611     case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
612         *v = ((*v & 0xFFFF000000000000LL) >> 48) |
613              ((*v & 0x0000FFFF00000000LL) >> 16) |
614              ((*v & 0x00000000FFFF0000LL) << 16) |
615              ((*v & 0x000000000000FFFFLL) << 48);
616
617         return(TNG_SUCCESS);
618
619     case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
620         *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
621              ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
622              ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
623              ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
624              ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
625              ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
626              ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
627              ((*v & 0x00000000000000FFLL) << 56);  /* Move last byte to first */
628
629         return(TNG_SUCCESS);
630
631     default:
632         return(TNG_FAILURE);
633     }
634 }
635 /** Generate the md5 hash of a block.
636  * The hash is created based on the actual block contents.
637  * @param block is a general block container.
638  * @return TNG_SUCCESS (0) if successful.
639  */
640 static tng_function_status tng_block_md5_hash_generate(tng_gen_block_t block)
641 {
642     md5_state_t md5_state;
643
644     md5_init(&md5_state);
645     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
646                (int)block->block_contents_size);
647     md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
648
649     return(TNG_SUCCESS);
650 }
651
652 /** Compare the current block md5 hash (e.g. read from file) with the md5 hash
653  * calculated from the current contents.
654  * If the current md5 hash is not set skip the comparison.
655  * @param block is a general block container.
656  * @param results If the hashes match results is set to TNG_TRUE, otherwise it is
657  * set to TNG_FALSE. If the hash was not set results is set to TNG_TRUE.
658  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the hash was not
659  * set.
660  */
661 static tng_function_status tng_md5_hash_match_verify(tng_gen_block_t block,
662                                                      tng_bool *results)
663 {
664     md5_state_t md5_state;
665     char hash[TNG_MD5_HASH_LEN];
666
667     TNG_ASSERT(block->block_contents_size > 0, "The block contents size must be > 0");
668
669     *results = TNG_TRUE;
670     if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0)
671     {
672         return(TNG_FAILURE);
673     }
674     md5_init(&md5_state);
675     md5_append(&md5_state, (md5_byte_t *)block->block_contents,
676                (int)block->block_contents_size);
677     md5_finish(&md5_state, (md5_byte_t *)hash);
678
679     if(strncmp(block->md5_hash, hash, 16) != 0)
680     {
681         *results = TNG_FALSE;
682     }
683
684     return(TNG_SUCCESS);
685 }
686
687 /** Open the input file if it is not already opened.
688  * @param tng_data is a trajectory data container.
689  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
690  * error has occured.
691  */
692 static tng_function_status tng_input_file_init(tng_trajectory_t tng_data)
693 {
694     if(!tng_data->input_file)
695     {
696         if(!tng_data->input_file_path)
697         {
698             fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
699                    __FILE__, __LINE__);
700             return(TNG_CRITICAL);
701         }
702         tng_data->input_file = fopen(tng_data->input_file_path, "rb");
703         if(!tng_data->input_file)
704         {
705             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
706                    tng_data->input_file_path, __FILE__, __LINE__);
707             return(TNG_CRITICAL);
708         }
709     }
710     return(TNG_SUCCESS);
711 }
712
713 /** Open the output file if it is not already opened
714  * @param tng_data is a trajectory data container.
715  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
716  * error has occured.
717  */
718 static tng_function_status tng_output_file_init(tng_trajectory_t tng_data)
719 {
720     if(!tng_data->output_file)
721     {
722         if(!tng_data->output_file_path)
723         {
724             fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
725                    __FILE__, __LINE__);
726             return(TNG_CRITICAL);
727         }
728
729         tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
730
731         if(!tng_data->output_file)
732         {
733             fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
734                    tng_data->output_file_path, __FILE__, __LINE__);
735             return(TNG_CRITICAL);
736         }
737     }
738     return(TNG_SUCCESS);
739 }
740
741 /** Setup a file block container.
742  * @param block_p a pointer to memory to initialise as a file block container.
743  * @details Memory is allocated during initialisation.
744  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
745  * error has occured.
746  */
747 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
748 {
749     tng_gen_block_t block;
750
751     *block_p = malloc(sizeof(struct tng_gen_block));
752     if(!*block_p)
753     {
754         fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
755                sizeof(struct tng_gen_block), __FILE__, __LINE__);
756         return(TNG_CRITICAL);
757     }
758
759     block = *block_p;
760
761     block->id = -1;
762     /* Reset the md5_hash */
763     memcpy(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN);
764     block->name = 0;
765     block->block_version = TNG_API_VERSION;
766     block->header_contents = 0;
767     block->header_contents_size = 0;
768     block->block_contents = 0;
769     block->block_contents_size = 0;
770
771     return(TNG_SUCCESS);
772 }
773
774 /**
775  * @brief Clean up a file block container.
776  * @param block_p a pointer to the file block container to destroy.
777  * @details All allocated memory in the data structure is freed, as well as
778  * block_p itself.
779  * @return TNG_SUCCESS (0) if successful.
780  */
781 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
782 {
783     tng_gen_block_t block = *block_p;
784
785     if(!*block_p)
786     {
787         return(TNG_SUCCESS);
788     }
789
790 /*     fprintf(stderr, "TNG library: Destroying block\n"); */
791     if(block->name)
792     {
793         free(block->name);
794         block->name = 0;
795     }
796     if(block->header_contents)
797     {
798         free(block->header_contents);
799         block->header_contents = 0;
800     }
801     if(block->block_contents)
802     {
803         free(block->block_contents);
804         block->block_contents = 0;
805     }
806
807     free(*block_p);
808     *block_p = 0;
809
810     return(TNG_SUCCESS);
811 }
812
813 /** Read the header of a data block, regardless of its type
814  * @param tng_data is a trajectory data container.
815  * @param block is a general block container.
816  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
817  * error has occured (not able to read the header size, thus skipping
818  * the block) or TNG_CRITICAL (2) if a major error has occured.
819  */
820 static tng_function_status tng_block_header_read
821                 (tng_trajectory_t tng_data, tng_gen_block_t block)
822 {
823     int len;
824     int64_t offset = 0;
825
826     TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
827
828     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
829     {
830         return(TNG_CRITICAL);
831     }
832
833     /* First read the header size to be able to read the whole header. */
834     if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
835         1, tng_data->input_file) == 0)
836     {
837         fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
838                __FILE__, __LINE__);
839         return(TNG_CRITICAL);
840     }
841
842     if(block->header_contents_size == 0)
843     {
844         block->id = -1;
845         return(TNG_FAILURE);
846     }
847
848     /* If this was the size of the general info block check the endianness */
849     if(ftello(tng_data->input_file) < 9)
850     {
851         /* File is little endian */
852         if ( *((const char*)&block->header_contents_size) != 0x00 &&
853              *((const char*)(&block->header_contents_size) + 7) == 0x00)
854         {
855             /* If the architecture endianness is little endian no byte swap
856              * will be needed. Otherwise use the functions to swap to little
857              * endian */
858             if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
859             {
860                 tng_data->input_endianness_swap_func_32 = 0;
861             }
862             else
863             {
864                 tng_data->input_endianness_swap_func_32 =
865                 &tng_swap_byte_order_little_endian_32;
866             }
867             if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
868             {
869                 tng_data->input_endianness_swap_func_64 = 0;
870             }
871             else
872             {
873                 tng_data->input_endianness_swap_func_64 =
874                 &tng_swap_byte_order_little_endian_64;
875             }
876         }
877         /* File is big endian */
878         else
879         {
880             /* If the architecture endianness is big endian no byte swap
881              * will be needed. Otherwise use the functions to swap to big
882              * endian */
883             if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
884             {
885                 tng_data->input_endianness_swap_func_32 = 0;
886             }
887             else
888             {
889                 tng_data->input_endianness_swap_func_32 =
890                 &tng_swap_byte_order_big_endian_32;
891             }
892             if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
893             {
894                 tng_data->input_endianness_swap_func_64 = 0;
895             }
896             else
897             {
898                 tng_data->input_endianness_swap_func_64 =
899                 &tng_swap_byte_order_big_endian_64;
900             }
901         }
902     }
903
904     if(tng_data->input_endianness_swap_func_64)
905     {
906         if(tng_data->input_endianness_swap_func_64(tng_data,
907                                                    &block->header_contents_size)
908             != TNG_SUCCESS)
909         {
910             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
911                     __FILE__, __LINE__);
912         }
913     }
914
915     /* Move the reading position to the beginning of the header. */
916     fseeko(tng_data->input_file, -(int64_t)sizeof(block->header_contents_size),
917            SEEK_CUR);
918
919     /* If there is already memory allocated for the contents free it (we do not
920      * know if the size is correct). */
921     if(block->header_contents)
922     {
923         free(block->header_contents);
924     }
925
926     block->header_contents = malloc(block->header_contents_size);
927     if(!block->header_contents)
928     {
929         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
930                block->header_contents_size, __FILE__, __LINE__);
931         return(TNG_CRITICAL);
932     }
933
934     /* Read the whole header into header_contents. This way it can be saved
935      * even if it cannot be interpreted
936      * for one reason or another. */
937     if(fread(block->header_contents, block->header_contents_size, 1,
938         tng_data->input_file) == 0)
939     {
940         fprintf(stderr, "TNG library: Cannot read header. %s: %d\n", __FILE__, __LINE__);
941         return(TNG_CRITICAL);
942     }
943
944     /* The header contents size has already been read. Skip ahead. */
945     offset = sizeof(block->header_contents_size);
946
947
948     /* Copy the respective parameters from the header contents block */
949     memcpy(&block->block_contents_size, block->header_contents+offset,
950            sizeof(block->block_contents_size));
951     if(tng_data->input_endianness_swap_func_64)
952     {
953         if(tng_data->input_endianness_swap_func_64(tng_data,
954                                                    &block->block_contents_size)
955             != TNG_SUCCESS)
956         {
957             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
958                     __FILE__, __LINE__);
959         }
960     }
961
962     offset += sizeof(block->block_contents_size);
963
964     memcpy(&block->id, block->header_contents+offset, sizeof(block->id));
965     if(tng_data->input_endianness_swap_func_64)
966     {
967         if(tng_data->input_endianness_swap_func_64(tng_data,
968                                                    &block->id)
969             != TNG_SUCCESS)
970         {
971             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
972                     __FILE__, __LINE__);
973         }
974     }
975
976     offset += sizeof(block->id);
977
978     memcpy(block->md5_hash, block->header_contents+offset, TNG_MD5_HASH_LEN);
979     offset += TNG_MD5_HASH_LEN;
980
981     if(block->name && strcmp(block->name, block->header_contents+offset) != 0)
982     {
983         free(block->name);
984         block->name = 0;
985     }
986     len = tng_min_i((int)strlen(block->header_contents+offset) + 1, TNG_MAX_STR_LEN);
987     if(!block->name)
988     {
989         block->name = malloc(len);
990         if(!block->name)
991         {
992             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
993                     __FILE__, __LINE__);
994             return(TNG_CRITICAL);
995         }
996         strncpy(block->name, block->header_contents+offset, len);
997     }
998     offset += len;
999
1000     memcpy(&block->block_version, block->header_contents+offset,
1001            sizeof(block->block_version));
1002     if(tng_data->input_endianness_swap_func_64)
1003     {
1004         if(tng_data->input_endianness_swap_func_64(tng_data,
1005                                                    &block->block_version)
1006             != TNG_SUCCESS)
1007         {
1008             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1009                     __FILE__, __LINE__);
1010         }
1011     }
1012
1013     return(TNG_SUCCESS);
1014 }
1015
1016 /** Write a whole block, both header and contents, regardless of it type
1017  * @param tng_data is a trajectory data container.
1018  * @param block is a general block container.
1019  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1020  * has occurred or TNG_CRITICAL (2) if a major error has occured.
1021  */
1022 /* Disabled until it is used.*/
1023 /*
1024 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1025 //                                                     tng_gen_block_t block)
1026 // {
1027 //     if(!block->header_contents)
1028 //     {
1029 //         fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1030 //         return(TNG_FAILURE);
1031 //     }
1032 //     if(fwrite(block->header_contents, block->header_contents_size, 1,
1033 //                 tng_data->output_file) != 1)
1034 //     {
1035 //         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1036 //                 __FILE__, __LINE__);
1037 //         return(TNG_CRITICAL);
1038 //     }
1039 //
1040 //     if(!block->block_contents)
1041 //     {
1042 //         fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1043 //                 __FILE__, __LINE__);
1044 //         return(TNG_FAILURE);
1045 //     }
1046 //     if(fwrite(block->block_contents, block->block_contents_size, 1,
1047 //                 tng_data->output_file) != 1)
1048 //     {
1049 //         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1050 //                 __FILE__, __LINE__);
1051 //         return(TNG_CRITICAL);
1052 //     }
1053 //     return(TNG_SUCCESS);
1054 // }
1055 */
1056
1057 /** Update the md5 hash of a block already written to the file
1058  * @param tng_data is a trajectory data container.
1059  * @param block is the block, of which to update the md5 hash.
1060  * @param header_start_pos is the file position where the block header starts.
1061  * @param contents_start_pos is the file position where the block contents
1062  * start.
1063  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1064  * error has occured.
1065  */
1066 static tng_function_status tng_md5_hash_update(tng_trajectory_t tng_data,
1067                                                tng_gen_block_t block,
1068                                                const int64_t header_start_pos,
1069                                                const int64_t contents_start_pos)
1070 {
1071     if(block->block_contents)
1072     {
1073         free(block->block_contents);
1074     }
1075
1076     block->block_contents = malloc(block->block_contents_size);
1077     if(!block->block_contents)
1078     {
1079         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1080                block->block_contents_size, __FILE__, __LINE__);
1081         return(TNG_CRITICAL);
1082     }
1083
1084     fseeko(tng_data->output_file, contents_start_pos, SEEK_SET);
1085     if(fread(block->block_contents, block->block_contents_size, 1,
1086             tng_data->output_file) == 0)
1087     {
1088         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1089         return(TNG_CRITICAL);
1090     }
1091
1092     tng_block_md5_hash_generate(block);
1093
1094     fseeko(tng_data->output_file, header_start_pos + 3 * sizeof(int64_t),
1095           SEEK_SET);
1096     fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1097
1098     return(TNG_SUCCESS);
1099 }
1100
1101 /** Update the frame set pointers in the file header (general info block),
1102  * already written to disk
1103  * @param tng_data is a trajectory data container.
1104  * @param hash_mode specifies whether to update the block md5 hash when
1105  * updating the pointers.
1106  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1107  * error has occured.
1108  */
1109 static tng_function_status tng_header_pointers_update
1110                 (tng_trajectory_t tng_data, const char hash_mode)
1111 {
1112     tng_gen_block_t block;
1113     FILE *temp = tng_data->input_file;
1114     int64_t output_file_pos, pos, contents_start_pos;
1115
1116     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1117     {
1118         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1119                __FILE__, __LINE__);
1120         return(TNG_CRITICAL);
1121     }
1122
1123     tng_data->input_file = tng_data->output_file;
1124
1125     tng_block_init(&block);
1126
1127     output_file_pos = ftello(tng_data->output_file);
1128     fseeko(tng_data->output_file, 0, SEEK_SET);
1129
1130     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1131     {
1132         fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1133                __FILE__, __LINE__);
1134         tng_data->input_file = temp;
1135         tng_block_destroy(&block);
1136         return(TNG_CRITICAL);
1137     }
1138
1139     contents_start_pos = ftello(tng_data->output_file);
1140
1141     fseeko(tng_data->output_file, block->block_contents_size - 5 *
1142           sizeof(int64_t), SEEK_CUR);
1143
1144     tng_data->input_file = temp;
1145
1146     pos = tng_data->first_trajectory_frame_set_output_file_pos;
1147
1148     if(tng_data->input_endianness_swap_func_64)
1149     {
1150         if(tng_data->input_endianness_swap_func_64(tng_data,
1151                                                     &pos)
1152             != TNG_SUCCESS)
1153         {
1154             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1155                     __FILE__, __LINE__);
1156         }
1157     }
1158
1159     if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1160     {
1161         tng_block_destroy(&block);
1162         return(TNG_CRITICAL);
1163     }
1164
1165     pos = tng_data->last_trajectory_frame_set_output_file_pos;
1166
1167     if(tng_data->input_endianness_swap_func_64)
1168     {
1169         if(tng_data->input_endianness_swap_func_64(tng_data,
1170                                                     &pos)
1171             != TNG_SUCCESS)
1172         {
1173             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1174                     __FILE__, __LINE__);
1175         }
1176     }
1177
1178     if(fwrite(&pos,
1179         sizeof(int64_t), 1, tng_data->output_file) != 1)
1180     {
1181         tng_block_destroy(&block);
1182         return(TNG_CRITICAL);
1183     }
1184
1185     if(hash_mode == TNG_USE_HASH)
1186     {
1187         tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1188     }
1189
1190     tng_block_destroy(&block);
1191
1192     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1193
1194     return(TNG_SUCCESS);
1195 }
1196
1197 /** Update the frame set pointers in the current frame set block, already
1198  * written to disk. It also updates the pointers of the blocks pointing to
1199  * the current frame set block.
1200  * @param tng_data is a trajectory data container.
1201  * @param hash_mode specifies whether to update the block md5 hash when
1202  * updating the pointers.
1203  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1204  * error has occured.
1205  */
1206 static tng_function_status tng_frame_set_pointers_update
1207                 (tng_trajectory_t tng_data, const char hash_mode)
1208 {
1209     tng_gen_block_t block;
1210     tng_trajectory_frame_set_t frame_set;
1211     FILE *temp = tng_data->input_file;
1212     int64_t pos, output_file_pos, contents_start_pos;
1213
1214     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1215     {
1216         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1217                __FILE__, __LINE__);
1218         return(TNG_CRITICAL);
1219     }
1220
1221     tng_block_init(&block);
1222     output_file_pos = ftello(tng_data->output_file);
1223
1224     tng_data->input_file = tng_data->output_file;
1225
1226     frame_set = &tng_data->current_trajectory_frame_set;
1227
1228     pos = tng_data->current_trajectory_frame_set_output_file_pos;
1229
1230     /* Update next frame set */
1231     if(frame_set->next_frame_set_file_pos > 0)
1232     {
1233         fseeko(tng_data->output_file, frame_set->next_frame_set_file_pos,
1234               SEEK_SET);
1235
1236         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1237         {
1238             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1239                 __FILE__, __LINE__);
1240             tng_data->input_file = temp;
1241             tng_block_destroy(&block);
1242             return(TNG_CRITICAL);
1243         }
1244
1245         contents_start_pos = ftello(tng_data->output_file);
1246
1247         fseeko(tng_data->output_file, block->block_contents_size - (5 *
1248             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1249
1250         if(tng_data->input_endianness_swap_func_64)
1251         {
1252             if(tng_data->input_endianness_swap_func_64(tng_data,
1253                                                         &pos)
1254                 != TNG_SUCCESS)
1255             {
1256                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1257                         __FILE__, __LINE__);
1258             }
1259         }
1260
1261         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1262         {
1263             tng_data->input_file = temp;
1264             tng_block_destroy(&block);
1265             return(TNG_CRITICAL);
1266         }
1267
1268         if(hash_mode == TNG_USE_HASH)
1269         {
1270             tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1271                                 contents_start_pos);
1272         }
1273         fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1274     }
1275     /* Update previous frame set */
1276     if(frame_set->prev_frame_set_file_pos > 0)
1277     {
1278         fseeko(tng_data->output_file, frame_set->prev_frame_set_file_pos,
1279               SEEK_SET);
1280
1281         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1282         {
1283             fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1284                 __FILE__, __LINE__);
1285             tng_data->input_file = temp;
1286             tng_block_destroy(&block);
1287             return(TNG_CRITICAL);
1288         }
1289
1290         contents_start_pos = ftello(tng_data->output_file);
1291
1292         fseeko(tng_data->output_file, block->block_contents_size - (6 *
1293             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1294
1295         if(tng_data->input_endianness_swap_func_64)
1296         {
1297             if(tng_data->input_endianness_swap_func_64(tng_data,
1298                                                         &pos)
1299                 != TNG_SUCCESS)
1300             {
1301                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1302                         __FILE__, __LINE__);
1303             }
1304         }
1305
1306         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1307         {
1308             tng_data->input_file = temp;
1309             tng_block_destroy(&block);
1310             return(TNG_CRITICAL);
1311         }
1312
1313         if(hash_mode == TNG_USE_HASH)
1314         {
1315             tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1316                                 contents_start_pos);
1317         }
1318         fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1319     }
1320
1321     /* Update the frame set one medium stride step after */
1322     if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1323     {
1324         fseeko(tng_data->output_file,
1325                frame_set->medium_stride_next_frame_set_file_pos,
1326                SEEK_SET);
1327
1328         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1329         {
1330             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1331                 __FILE__, __LINE__);
1332             tng_data->input_file = temp;
1333             tng_block_destroy(&block);
1334             return(TNG_CRITICAL);
1335         }
1336
1337         contents_start_pos = ftello(tng_data->output_file);
1338
1339         fseeko(tng_data->output_file, block->block_contents_size - (3 *
1340             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1341
1342         if(tng_data->input_endianness_swap_func_64)
1343         {
1344             if(tng_data->input_endianness_swap_func_64(tng_data,
1345                                                         &pos)
1346                 != TNG_SUCCESS)
1347             {
1348                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1349                         __FILE__, __LINE__);
1350             }
1351         }
1352
1353         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1354         {
1355             tng_data->input_file = temp;
1356             tng_block_destroy(&block);
1357             return(TNG_CRITICAL);
1358         }
1359
1360         if(hash_mode == TNG_USE_HASH)
1361         {
1362             tng_md5_hash_update(tng_data, block,
1363                                 frame_set->medium_stride_next_frame_set_file_pos,
1364                                 contents_start_pos);
1365         }
1366     }
1367     /* Update the frame set one medium stride step before */
1368     if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1369     {
1370         fseeko(tng_data->output_file,
1371                frame_set->medium_stride_prev_frame_set_file_pos,
1372                SEEK_SET);
1373
1374         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1375         {
1376             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1377                 __FILE__, __LINE__);
1378             tng_data->input_file = temp;
1379             tng_block_destroy(&block);
1380             return(TNG_CRITICAL);
1381         }
1382
1383         contents_start_pos = ftello(tng_data->output_file);
1384
1385         fseeko(tng_data->output_file, block->block_contents_size - (4 *
1386             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1387
1388         if(tng_data->input_endianness_swap_func_64)
1389         {
1390             if(tng_data->input_endianness_swap_func_64(tng_data,
1391                                                         &pos)
1392                 != TNG_SUCCESS)
1393             {
1394                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1395                         __FILE__, __LINE__);
1396             }
1397         }
1398
1399         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1400         {
1401             tng_data->input_file = temp;
1402             tng_block_destroy(&block);
1403             return(TNG_CRITICAL);
1404         }
1405
1406         if(hash_mode == TNG_USE_HASH)
1407         {
1408             tng_md5_hash_update(tng_data, block,
1409                                 frame_set->medium_stride_prev_frame_set_file_pos,
1410                                 contents_start_pos);
1411         }
1412     }
1413
1414     /* Update the frame set one long stride step after */
1415     if(frame_set->long_stride_next_frame_set_file_pos > 0)
1416     {
1417         fseeko(tng_data->output_file,
1418                frame_set->long_stride_next_frame_set_file_pos,
1419                SEEK_SET);
1420
1421         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1422         {
1423             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1424                 __FILE__, __LINE__);
1425             tng_data->input_file = temp;
1426             tng_block_destroy(&block);
1427             return(TNG_CRITICAL);
1428         }
1429
1430         contents_start_pos = ftello(tng_data->output_file);
1431
1432         fseeko(tng_data->output_file, block->block_contents_size - (1 *
1433                sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1434
1435         if(tng_data->input_endianness_swap_func_64)
1436         {
1437             if(tng_data->input_endianness_swap_func_64(tng_data,
1438                                                         &pos)
1439                 != TNG_SUCCESS)
1440             {
1441                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1442                         __FILE__, __LINE__);
1443             }
1444         }
1445
1446         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1447         {
1448             tng_data->input_file = temp;
1449             tng_block_destroy(&block);
1450             return(TNG_CRITICAL);
1451         }
1452
1453         if(hash_mode == TNG_USE_HASH)
1454         {
1455             tng_md5_hash_update(tng_data, block,
1456                                 frame_set->long_stride_next_frame_set_file_pos,
1457                                 contents_start_pos);
1458         }
1459     }
1460     /* Update the frame set one long stride step before */
1461     if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1462     {
1463         fseeko(tng_data->output_file,
1464                frame_set->long_stride_prev_frame_set_file_pos,
1465                SEEK_SET);
1466
1467         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1468         {
1469             fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1470                 __FILE__, __LINE__);
1471             tng_data->input_file = temp;
1472             tng_block_destroy(&block);
1473             return(TNG_CRITICAL);
1474         }
1475
1476         contents_start_pos = ftello(tng_data->output_file);
1477
1478         fseeko(tng_data->output_file, block->block_contents_size - (2 *
1479             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1480
1481         if(tng_data->input_endianness_swap_func_64)
1482         {
1483             if(tng_data->input_endianness_swap_func_64(tng_data,
1484                                                         &pos)
1485                 != TNG_SUCCESS)
1486             {
1487                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1488                         __FILE__, __LINE__);
1489             }
1490         }
1491
1492         if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1493         {
1494             tng_data->input_file = temp;
1495             tng_block_destroy(&block);
1496             return(TNG_CRITICAL);
1497         }
1498
1499         if(hash_mode == TNG_USE_HASH)
1500         {
1501             tng_md5_hash_update(tng_data, block,
1502                                 frame_set->long_stride_prev_frame_set_file_pos,
1503                                 contents_start_pos);
1504         }
1505     }
1506
1507     fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1508
1509     tng_data->input_file = temp;
1510
1511     tng_block_destroy(&block);
1512
1513     return(TNG_SUCCESS);
1514 }
1515
1516 static tng_function_status tng_reread_frame_set_at_file_pos
1517                 (tng_trajectory_t tng_data,
1518                  const int64_t pos)
1519 {
1520     tng_gen_block_t block;
1521     tng_function_status stat;
1522
1523     tng_block_init(&block);
1524
1525     fseeko(tng_data->input_file, pos, SEEK_SET);
1526     if(pos > 0)
1527     {
1528         stat = tng_block_header_read(tng_data, block);
1529         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1530         {
1531             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
1532                     __FILE__, __LINE__);
1533             tng_block_destroy(&block);
1534             return(TNG_FAILURE);
1535         }
1536
1537         if(tng_block_read_next(tng_data, block,
1538                                TNG_SKIP_HASH) != TNG_SUCCESS)
1539         {
1540             tng_block_destroy(&block);
1541             return(TNG_CRITICAL);
1542         }
1543     }
1544
1545     tng_block_destroy(&block);
1546
1547     return(TNG_SUCCESS);
1548 }
1549
1550 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1551                 (tng_trajectory_t tng_data,
1552                  int64_t *pos)
1553 {
1554     int64_t orig_pos, curr_frame_set_pos;
1555     tng_gen_block_t block;
1556     tng_function_status stat;
1557     tng_trajectory_frame_set_t frame_set =
1558     &tng_data->current_trajectory_frame_set;
1559
1560     orig_pos = ftello(tng_data->input_file);
1561     curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1562
1563     *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1564
1565     if(*pos <= 0)
1566     {
1567         return(TNG_SUCCESS);
1568     }
1569
1570     fseeko(tng_data->input_file, *pos, SEEK_SET);
1571
1572     tng_block_init(&block);
1573     /* Read block headers first to see that a frame set block is found. */
1574     stat = tng_block_header_read(tng_data, block);
1575     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1576     {
1577         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1578                 __FILE__, __LINE__);
1579         tng_block_destroy(&block);
1580         return(TNG_FAILURE);
1581     }
1582
1583     if(tng_block_read_next(tng_data, block,
1584                            TNG_SKIP_HASH) != TNG_SUCCESS)
1585     {
1586         tng_block_destroy(&block);
1587         return(TNG_CRITICAL);
1588     }
1589
1590     /* Read all frame set blocks (not the blocks between them) */
1591     while(frame_set->next_frame_set_file_pos > 0)
1592     {
1593         fseeko(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1594         stat = tng_block_header_read(tng_data, block);
1595         if(stat == TNG_CRITICAL)
1596         {
1597             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
1598                     __FILE__, __LINE__);
1599             tng_block_destroy(&block);
1600             return(TNG_CRITICAL);
1601         }
1602         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1603         {
1604             return(TNG_FAILURE);
1605         }
1606
1607         stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1608         if(stat != TNG_SUCCESS)
1609         {
1610             tng_block_destroy(&block);
1611             return(stat);
1612         }
1613         /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1614         if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1615            tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1616         {
1617             *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1618         }
1619     }
1620
1621     /* Re-read the frame set that used to be the current one */
1622     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1623
1624     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1625
1626     tng_block_destroy(&block);
1627
1628     return(TNG_SUCCESS);
1629 }
1630
1631 static tng_function_status tng_frame_set_complete_migrate
1632                 (tng_trajectory_t tng_data,
1633                  int64_t block_start_pos,
1634                  int64_t block_len,
1635                  int64_t new_pos)
1636 {
1637     int64_t i;
1638     tng_bool updated = TNG_FALSE;
1639
1640     char *contents;
1641
1642     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1643     {
1644         return(TNG_CRITICAL);
1645     }
1646
1647     fseeko(tng_data->input_file, block_start_pos, SEEK_SET);
1648
1649     contents = malloc(block_len);
1650     if(!contents)
1651     {
1652         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1653                 block_len, __FILE__, __LINE__);
1654         return(TNG_CRITICAL);
1655     }
1656
1657     if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1658     {
1659         fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1660                __FILE__, __LINE__);
1661         free(contents);
1662         return(TNG_CRITICAL);
1663     }
1664     fseeko(tng_data->output_file, new_pos, SEEK_SET);
1665
1666     if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1667     {
1668         fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1669                 __FILE__, __LINE__);
1670         free(contents);
1671         return(TNG_CRITICAL);
1672     }
1673
1674     tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1675
1676     tng_frame_set_pointers_update(tng_data, TNG_USE_HASH);
1677
1678     /* Update the general info block if needed */
1679     if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1680     {
1681         tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1682         updated = TNG_TRUE;
1683     }
1684     if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1685     {
1686         tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1687         updated = TNG_TRUE;
1688     }
1689     if(updated)
1690     {
1691         tng_header_pointers_update(tng_data, TNG_USE_HASH);
1692     }
1693
1694     /* Fill the block with NULL to avoid confusion. */
1695     for(i = 0; i < block_len; i++)
1696     {
1697         contents[i] = '\0';
1698     }
1699     fseeko(tng_data->output_file, block_start_pos, SEEK_SET);
1700
1701     /* FIXME: casting block_len to size_t is dangerous */
1702     fwrite(contents, 1, block_len, tng_data->output_file);
1703
1704     free(contents);
1705
1706     return(TNG_SUCCESS);
1707 }
1708
1709 static tng_function_status tng_length_of_current_frame_set_contents_get
1710                 (tng_trajectory_t tng_data,
1711                  int64_t *len)
1712 {
1713     int64_t orig_pos, pos, curr_frame_set_pos;
1714     tng_gen_block_t block;
1715     tng_function_status stat;
1716
1717     orig_pos = ftello(tng_data->input_file);
1718     curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1719
1720     *len = 0;
1721
1722     fseeko(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1723
1724     tng_block_init(&block);
1725     /* Read block headers first to see that a frame set block is found. */
1726     stat = tng_block_header_read(tng_data, block);
1727     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1728     {
1729         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
1730                 curr_frame_set_pos, __FILE__, __LINE__);
1731         tng_block_destroy(&block);
1732         return(TNG_FAILURE);
1733     }
1734
1735     /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1736     while(stat == TNG_SUCCESS)
1737     {
1738         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1739         *len += block->header_contents_size + block->block_contents_size;
1740         pos += block->header_contents_size + block->block_contents_size;
1741         if(pos >= tng_data->input_file_len)
1742         {
1743             break;
1744         }
1745         stat = tng_block_header_read(tng_data, block);
1746         if(block->id == TNG_TRAJECTORY_FRAME_SET)
1747         {
1748             break;
1749         }
1750     }
1751
1752     /* Re-read the frame set that used to be the current one */
1753     tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1754
1755     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1756
1757     tng_block_destroy(&block);
1758
1759     return(TNG_SUCCESS);
1760 }
1761
1762 /** Migrate blocks in the file to make room for new data in a block. This
1763  * is required e.g. when adding data to a block or extending strings in a
1764  * block.
1765  * @param tng_data is a trajectory data container.
1766  * @param start_pos is the position from which to start moving data, usually
1767  * the byte after the end of the block to which data was added.
1768  * @param offset is the number of bytes that were inserted.
1769  * @details Trajectory blocks (frame sets and their related blocks) are moved
1770  * to the end of the file (if needed) in order to make room for non-trajectory
1771  * data.
1772  */
1773 static tng_function_status tng_migrate_data_in_file
1774                 (tng_trajectory_t tng_data,
1775                  int64_t start_pos,
1776                  int64_t offset)
1777 {
1778     int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1779     tng_gen_block_t block;
1780     tng_function_status stat;
1781     FILE *temp;
1782
1783     if(offset <= 0)
1784     {
1785         return(TNG_SUCCESS);
1786     }
1787
1788     temp = tng_data->input_file;
1789
1790     stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1791     if(stat != TNG_SUCCESS)
1792     {
1793         tng_data->input_file = temp;
1794         return(stat);
1795     }
1796
1797     tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1798
1799     empty_space = traj_start_pos - (start_pos - 1);
1800
1801     if(empty_space >= offset)
1802     {
1803         return(TNG_SUCCESS);
1804     }
1805
1806     orig_file_pos = ftello(tng_data->input_file);
1807     tng_block_init(&block);
1808
1809     while(empty_space < offset)
1810     {
1811         fseeko(tng_data->input_file, traj_start_pos, SEEK_SET);
1812         stat = tng_block_header_read(tng_data, block);
1813         if(stat == TNG_CRITICAL)
1814         {
1815             fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1816                     __FILE__, __LINE__);
1817             tng_block_destroy(&block);
1818             tng_data->input_file = temp;
1819             return(TNG_CRITICAL);
1820         }
1821         if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1822         {
1823             tng_data->input_file = temp;
1824             tng_block_destroy(&block);
1825             return(TNG_FAILURE);
1826         }
1827         stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1828         if(stat != TNG_SUCCESS)
1829         {
1830             tng_data->input_file = temp;
1831             tng_block_destroy(&block);
1832             return(stat);
1833         }
1834         stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1835                                               frame_set_length, tng_data->input_file_len);
1836         if(stat != TNG_SUCCESS)
1837         {
1838             tng_data->input_file = temp;
1839             tng_block_destroy(&block);
1840             return(stat);
1841         }
1842
1843         empty_space += frame_set_length;
1844     }
1845     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
1846     tng_block_destroy(&block);
1847
1848     return(TNG_SUCCESS);
1849 }
1850
1851 static tng_function_status tng_block_header_len_calculate
1852                 (const tng_trajectory_t tng_data,
1853                  tng_gen_block_t block,
1854                  int64_t *len)
1855 {
1856     int name_len;
1857     (void)tng_data;
1858
1859     /* If the string is unallocated allocate memory for just string
1860      * termination */
1861     if(!block->name)
1862     {
1863         block->name = malloc(1);
1864         if(!block->name)
1865         {
1866             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
1867                    __FILE__, __LINE__);
1868             return(TNG_CRITICAL);
1869         }
1870         block->name[0] = 0;
1871     }
1872
1873     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1874
1875     /* Calculate the size of the header to write */
1876     *len = sizeof(block->header_contents_size) +
1877                   sizeof(block->block_contents_size) +
1878                   sizeof(block->id) +
1879                   sizeof(block->block_version) +
1880                   TNG_MD5_HASH_LEN +
1881                   name_len;
1882
1883     return (TNG_SUCCESS);
1884 }
1885
1886 /** Write the header of a data block, regardless of its type
1887  * @param tng_data is a trajectory data container.
1888  * @param block is a general block container.
1889  * @param hash_mode is an option to decide whether to use the md5 hash or not.
1890  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
1891  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1892  * error has occured.
1893  */
1894 static tng_function_status tng_block_header_write
1895                 (tng_trajectory_t tng_data,
1896                  tng_gen_block_t block,
1897                  const char hash_mode)
1898 {
1899     int name_len, offset = 0;
1900
1901     TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
1902
1903     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1904     {
1905         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1906                __FILE__, __LINE__);
1907         return(TNG_CRITICAL);
1908     }
1909
1910     if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
1911         TNG_SUCCESS)
1912     {
1913         fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
1914                 __FILE__, __LINE__);
1915         return(TNG_CRITICAL);
1916     }
1917
1918     if(hash_mode == TNG_USE_HASH)
1919     {
1920         tng_block_md5_hash_generate(block);
1921     }
1922
1923     if(block->header_contents)
1924     {
1925         free(block->header_contents);
1926     }
1927
1928     block->header_contents = malloc(block->header_contents_size);
1929     if(!block->header_contents)
1930     {
1931         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
1932                block->header_contents_size, __FILE__, __LINE__);
1933         return(TNG_CRITICAL);
1934     }
1935
1936     name_len = tng_min_i((int)strlen(block->name) + 1, TNG_MAX_STR_LEN);
1937
1938     /* First copy all data into the header_contents block and finally write
1939      * the whole block at once. */
1940     memcpy(block->header_contents, &block->header_contents_size,
1941            sizeof(block->header_contents_size));
1942     if(tng_data->output_endianness_swap_func_64)
1943     {
1944         if(tng_data->output_endianness_swap_func_64(tng_data,
1945                                       (int64_t *)block->header_contents+offset)
1946             != TNG_SUCCESS)
1947         {
1948             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1949                     __FILE__, __LINE__);
1950         }
1951     }
1952     offset += sizeof(block->header_contents_size);
1953
1954     memcpy(block->header_contents+offset, &block->block_contents_size,
1955            sizeof(block->block_contents_size));
1956     if(tng_data->output_endianness_swap_func_64)
1957     {
1958         if(tng_data->output_endianness_swap_func_64(tng_data,
1959                                       (int64_t *)block->header_contents+offset)
1960             != TNG_SUCCESS)
1961         {
1962             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1963                     __FILE__, __LINE__);
1964         }
1965     }
1966     offset += sizeof(block->block_contents_size);
1967
1968     memcpy(block->header_contents+offset, &block->id, sizeof(block->id));
1969     if(tng_data->output_endianness_swap_func_64)
1970     {
1971         if(tng_data->output_endianness_swap_func_64(tng_data,
1972                                       (int64_t *)block->header_contents+offset)
1973             != TNG_SUCCESS)
1974         {
1975             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1976                     __FILE__, __LINE__);
1977         }
1978     }
1979     offset += sizeof(block->id);
1980
1981     memcpy(block->header_contents+offset, block->md5_hash, TNG_MD5_HASH_LEN);
1982     offset += TNG_MD5_HASH_LEN;
1983
1984     strncpy(block->header_contents+offset, block->name, name_len);
1985     offset += name_len;
1986
1987     memcpy(block->header_contents+offset, &block->block_version,
1988            sizeof(block->block_version));
1989     if(tng_data->output_endianness_swap_func_64)
1990     {
1991         if(tng_data->output_endianness_swap_func_64(tng_data,
1992                                       (int64_t *)block->header_contents+offset)
1993             != TNG_SUCCESS)
1994         {
1995             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1996                     __FILE__, __LINE__);
1997         }
1998     }
1999
2000     if(fwrite(block->header_contents, block->header_contents_size,
2001        1, tng_data->output_file) != 1)
2002     {
2003         fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", __FILE__, __LINE__);
2004         return(TNG_CRITICAL);
2005     }
2006     return(TNG_SUCCESS);
2007 }
2008
2009 static tng_function_status tng_general_info_block_len_calculate
2010                 (tng_trajectory_t tng_data,
2011                  int64_t *len)
2012 {
2013     int first_program_name_len, first_user_name_len;
2014     int first_computer_name_len, first_pgp_signature_len;
2015     int last_program_name_len, last_user_name_len;
2016     int last_computer_name_len, last_pgp_signature_len;
2017     int forcefield_name_len;
2018
2019     /* If the strings are unallocated allocate memory for just string
2020      * termination */
2021     if(!tng_data->first_program_name)
2022     {
2023         tng_data->first_program_name = malloc(1);
2024         if(!tng_data->first_program_name)
2025         {
2026             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2027                    __FILE__, __LINE__);
2028             return(TNG_CRITICAL);
2029         }
2030         tng_data->first_program_name[0] = 0;
2031     }
2032     if(!tng_data->last_program_name)
2033     {
2034         tng_data->last_program_name = malloc(1);
2035         if(!tng_data->last_program_name)
2036         {
2037             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2038                    __FILE__, __LINE__);
2039             return(TNG_CRITICAL);
2040         }
2041         tng_data->last_program_name[0] = 0;
2042     }
2043     if(!tng_data->first_user_name)
2044     {
2045         tng_data->first_user_name = malloc(1);
2046         if(!tng_data->first_user_name)
2047         {
2048             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2049                    __FILE__, __LINE__);
2050             return(TNG_CRITICAL);
2051         }
2052         tng_data->first_user_name[0] = 0;
2053     }
2054     if(!tng_data->last_user_name)
2055     {
2056         tng_data->last_user_name = malloc(1);
2057         if(!tng_data->last_user_name)
2058         {
2059             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2060                    __FILE__, __LINE__);
2061             return(TNG_CRITICAL);
2062         }
2063         tng_data->last_user_name[0] = 0;
2064     }
2065     if(!tng_data->first_computer_name)
2066     {
2067         tng_data->first_computer_name = malloc(1);
2068         if(!tng_data->first_computer_name)
2069         {
2070             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2071                    __FILE__, __LINE__);
2072             return(TNG_CRITICAL);
2073         }
2074         tng_data->first_computer_name[0] = 0;
2075     }
2076     if(!tng_data->last_computer_name)
2077     {
2078         tng_data->last_computer_name = malloc(1);
2079         if(!tng_data->last_computer_name)
2080         {
2081             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2082                    __FILE__, __LINE__);
2083             return(TNG_CRITICAL);
2084         }
2085         tng_data->last_computer_name[0] = 0;
2086     }
2087     if(!tng_data->first_pgp_signature)
2088     {
2089         tng_data->first_pgp_signature = malloc(1);
2090         if(!tng_data->first_pgp_signature)
2091         {
2092             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2093                    __FILE__, __LINE__);
2094             return(TNG_CRITICAL);
2095         }
2096         tng_data->first_pgp_signature[0] = 0;
2097     }
2098     if(!tng_data->last_pgp_signature)
2099     {
2100         tng_data->last_pgp_signature = malloc(1);
2101         if(!tng_data->last_pgp_signature)
2102         {
2103             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2104                    __FILE__, __LINE__);
2105             return(TNG_CRITICAL);
2106         }
2107         tng_data->last_pgp_signature[0] = 0;
2108     }
2109     if(!tng_data->forcefield_name)
2110     {
2111         tng_data->forcefield_name = malloc(1);
2112         if(!tng_data->forcefield_name)
2113         {
2114             fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
2115                    __FILE__, __LINE__);
2116             return(TNG_CRITICAL);
2117         }
2118         tng_data->forcefield_name[0] = 0;
2119     }
2120
2121     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2122                            TNG_MAX_STR_LEN);
2123     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2124                            TNG_MAX_STR_LEN);
2125     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2126                         TNG_MAX_STR_LEN);
2127     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2128                         TNG_MAX_STR_LEN);
2129     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2130                             TNG_MAX_STR_LEN);
2131     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2132                             TNG_MAX_STR_LEN);
2133     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2134                             TNG_MAX_STR_LEN);
2135     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2136                             TNG_MAX_STR_LEN);
2137     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2138                               TNG_MAX_STR_LEN);
2139
2140     *len = sizeof(tng_data->time) +
2141                   sizeof(tng_data->var_num_atoms_flag) +
2142                   sizeof(tng_data->frame_set_n_frames) +
2143                   sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2144                   sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2145                   sizeof(tng_data->medium_stride_length) +
2146                   sizeof(tng_data->long_stride_length) +
2147                   sizeof(tng_data->distance_unit_exponential) +
2148                   first_program_name_len +
2149                   last_program_name_len +
2150                   first_user_name_len +
2151                   last_user_name_len +
2152                   first_computer_name_len +
2153                   last_computer_name_len +
2154                   first_pgp_signature_len +
2155                   last_pgp_signature_len +
2156                   forcefield_name_len;
2157
2158     return(TNG_SUCCESS);
2159 }
2160
2161 /** Read a general info block. This is the first block of a TNG file.
2162  *  Populate the fields in tng_data.
2163  * @param tng_data is a trajectory data container.
2164  * @param block is a general block container.
2165  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2166  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2167  * compared to the md5 hash of the read contents to ensure valid data.
2168  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2169  * error has occured.
2170  */
2171 static tng_function_status tng_general_info_block_read
2172                 (tng_trajectory_t tng_data, tng_gen_block_t block,
2173                  const char hash_mode)
2174 {
2175     int len, offset = 0;
2176     tng_bool same_hash;
2177
2178     void *temp;
2179
2180     TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2181
2182     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2183     {
2184         return(TNG_CRITICAL);
2185     }
2186
2187     temp = realloc(block->block_contents, block->block_contents_size);
2188     if(!temp)
2189     {
2190         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2191                block->block_contents_size, __FILE__, __LINE__);
2192         free(block->block_contents);
2193         block->block_contents = 0;
2194         return(TNG_CRITICAL);
2195     }
2196     block->block_contents = temp;
2197
2198     /* Read the whole block into block_contents to be able to write it to disk
2199      * even if it cannot be interpreted. */
2200     if(fread(block->block_contents, block->block_contents_size, 1,
2201              tng_data->input_file) == 0)
2202     {
2203         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
2204         return(TNG_CRITICAL);
2205     }
2206
2207     /* FIXME: Does not check if the size of the contents matches the expected
2208      * size or if the contents can be read. */
2209
2210     if(hash_mode == TNG_USE_HASH)
2211     {
2212         tng_md5_hash_match_verify(block, &same_hash);
2213         if(same_hash != TNG_TRUE)
2214         {
2215             fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2216                 "%s: %d\n",
2217                 __FILE__, __LINE__);
2218     /*         return(TNG_FAILURE); */
2219         }
2220     }
2221
2222     len = tng_min_i((int)strlen(block->block_contents) + 1, TNG_MAX_STR_LEN);
2223     temp = realloc(tng_data->first_program_name, len);
2224     if(!temp)
2225     {
2226         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2227                __FILE__, __LINE__);
2228         free(tng_data->first_program_name);
2229         tng_data->first_program_name = 0;
2230         return(TNG_CRITICAL);
2231     }
2232     tng_data->first_program_name = temp;
2233     strncpy(tng_data->first_program_name, block->block_contents, len);
2234     offset += len;
2235
2236     len = tng_min_i((int)strlen(block->block_contents + offset) + 1, TNG_MAX_STR_LEN);
2237     temp = realloc(tng_data->last_program_name, len);
2238     if(!temp)
2239     {
2240         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2241                __FILE__, __LINE__);
2242         free(tng_data->last_program_name);
2243         tng_data->last_program_name = 0;
2244         return(TNG_CRITICAL);
2245     }
2246     tng_data->last_program_name = temp;
2247     strncpy(tng_data->last_program_name, block->block_contents + offset, len);
2248     offset += len;
2249
2250     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2251     temp = realloc(tng_data->first_user_name, len);
2252     if(!temp)
2253     {
2254         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2255                __FILE__, __LINE__);
2256         free(tng_data->first_user_name);
2257         tng_data->first_user_name = 0;
2258         return(TNG_CRITICAL);
2259     }
2260     tng_data->first_user_name = temp;
2261     strncpy(tng_data->first_user_name, block->block_contents+offset, len);
2262     offset += len;
2263
2264     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2265     temp = realloc(tng_data->last_user_name, len);
2266     if(!temp)
2267     {
2268         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2269                __FILE__, __LINE__);
2270         free(tng_data->last_user_name);
2271         tng_data->last_user_name = 0;
2272         return(TNG_CRITICAL);
2273     }
2274     tng_data->last_user_name = temp;
2275     strncpy(tng_data->last_user_name, block->block_contents+offset, len);
2276     offset += len;
2277
2278     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2279     temp = realloc(tng_data->first_computer_name, len);
2280     if(!temp)
2281     {
2282         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2283                __FILE__, __LINE__);
2284         free(tng_data->first_computer_name);
2285         tng_data->first_computer_name = 0;
2286         return(TNG_CRITICAL);
2287     }
2288     tng_data->first_computer_name = temp;
2289     strncpy(tng_data->first_computer_name, block->block_contents+offset, len);
2290     offset += len;
2291
2292     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2293     temp = realloc(tng_data->last_computer_name, len);
2294     if(!temp)
2295     {
2296         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2297                __FILE__, __LINE__);
2298         free(tng_data->last_computer_name);
2299         tng_data->last_computer_name = 0;
2300         return(TNG_CRITICAL);
2301     }
2302     tng_data->last_computer_name = temp;
2303     strncpy(tng_data->last_computer_name, block->block_contents+offset, len);
2304     offset += len;
2305
2306     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2307     temp = realloc(tng_data->first_pgp_signature, len);
2308     if(!temp)
2309     {
2310         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2311                __FILE__, __LINE__);
2312         free(tng_data->first_pgp_signature);
2313         tng_data->first_pgp_signature = 0;
2314         return(TNG_CRITICAL);
2315     }
2316     tng_data->first_pgp_signature = temp;
2317     strncpy(tng_data->first_pgp_signature, block->block_contents+offset, len);
2318     offset += len;
2319
2320     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2321     temp = realloc(tng_data->last_pgp_signature, len);
2322     if(!temp)
2323     {
2324         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2325                __FILE__, __LINE__);
2326         free(tng_data->last_pgp_signature);
2327         tng_data->last_pgp_signature = 0;
2328         return(TNG_CRITICAL);
2329     }
2330     tng_data->last_pgp_signature = temp;
2331     strncpy(tng_data->last_pgp_signature, block->block_contents+offset, len);
2332     offset += len;
2333
2334     len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
2335     temp = realloc(tng_data->forcefield_name, len);
2336     if(!temp)
2337     {
2338         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
2339                __FILE__, __LINE__);
2340         free(tng_data->forcefield_name);
2341         tng_data->forcefield_name = 0;
2342         return(TNG_CRITICAL);
2343     }
2344     tng_data->forcefield_name = temp;
2345     strncpy(tng_data->forcefield_name, block->block_contents+offset, len);
2346     offset += len;
2347
2348     memcpy(&tng_data->time, block->block_contents+offset,
2349            sizeof(tng_data->time));
2350     if(tng_data->input_endianness_swap_func_64)
2351     {
2352         if(tng_data->input_endianness_swap_func_64(tng_data,
2353                                                    &tng_data->time)
2354             != TNG_SUCCESS)
2355         {
2356             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2357                     __FILE__, __LINE__);
2358         }
2359     }
2360     offset += sizeof(tng_data->time);
2361
2362     memcpy(&tng_data->var_num_atoms_flag, block->block_contents+offset,
2363            sizeof(tng_data->var_num_atoms_flag));
2364     offset += sizeof(tng_data->var_num_atoms_flag);
2365
2366     memcpy(&tng_data->frame_set_n_frames, block->block_contents+offset,
2367            sizeof(tng_data->frame_set_n_frames));
2368     if(tng_data->input_endianness_swap_func_64)
2369     {
2370         if(tng_data->input_endianness_swap_func_64(tng_data,
2371                                                  &tng_data->frame_set_n_frames)
2372             != TNG_SUCCESS)
2373         {
2374             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2375                     __FILE__, __LINE__);
2376         }
2377     }
2378     offset += sizeof(tng_data->frame_set_n_frames);
2379
2380     memcpy(&tng_data->first_trajectory_frame_set_input_file_pos,
2381            block->block_contents+offset,
2382            sizeof(tng_data->first_trajectory_frame_set_input_file_pos));
2383     if(tng_data->input_endianness_swap_func_64)
2384     {
2385         if(tng_data->input_endianness_swap_func_64(tng_data,
2386                           &tng_data->first_trajectory_frame_set_input_file_pos)
2387             != TNG_SUCCESS)
2388         {
2389             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2390                     __FILE__, __LINE__);
2391         }
2392     }
2393     offset += sizeof(tng_data->first_trajectory_frame_set_input_file_pos);
2394
2395     tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2396     tng_data->first_trajectory_frame_set_input_file_pos;
2397
2398
2399     memcpy(&tng_data->last_trajectory_frame_set_input_file_pos,
2400            block->block_contents+offset,
2401            sizeof(tng_data->last_trajectory_frame_set_input_file_pos));
2402     if(tng_data->input_endianness_swap_func_64)
2403     {
2404         if(tng_data->input_endianness_swap_func_64(tng_data,
2405                           &tng_data->last_trajectory_frame_set_input_file_pos)
2406             != TNG_SUCCESS)
2407         {
2408             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2409                     __FILE__, __LINE__);
2410         }
2411     }
2412     offset += sizeof(tng_data->last_trajectory_frame_set_input_file_pos);
2413
2414     memcpy(&tng_data->medium_stride_length, block->block_contents+offset,
2415            sizeof(tng_data->medium_stride_length));
2416     if(tng_data->input_endianness_swap_func_64)
2417     {
2418         if(tng_data->input_endianness_swap_func_64(tng_data,
2419                                                &tng_data->medium_stride_length)
2420             != TNG_SUCCESS)
2421         {
2422             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2423                     __FILE__, __LINE__);
2424         }
2425     }
2426     offset += sizeof(tng_data->medium_stride_length);
2427
2428     memcpy(&tng_data->long_stride_length, block->block_contents+offset,
2429            sizeof(tng_data->long_stride_length));
2430     if(tng_data->input_endianness_swap_func_64)
2431     {
2432         if(tng_data->input_endianness_swap_func_64(tng_data,
2433                                                    &tng_data->long_stride_length)
2434             != TNG_SUCCESS)
2435         {
2436             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2437                     __FILE__, __LINE__);
2438         }
2439     }
2440     offset += sizeof(tng_data->long_stride_length);
2441
2442     if(block->block_version >= 3)
2443     {
2444         memcpy(&tng_data->distance_unit_exponential, block->block_contents+offset,
2445             sizeof(tng_data->distance_unit_exponential));
2446         if(tng_data->input_endianness_swap_func_64)
2447         {
2448             if(tng_data->input_endianness_swap_func_64(tng_data,
2449                                           &tng_data->distance_unit_exponential)
2450                 != TNG_SUCCESS)
2451             {
2452                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2453                         __FILE__, __LINE__);
2454             }
2455         }
2456     }
2457
2458     return(TNG_SUCCESS);
2459 }
2460
2461 /** Write a general info block. This is the first block of a TNG file.
2462  * @param tng_data is a trajectory data container.
2463  * @param hash_mode is an option to decide whether to use the md5 hash or not.
2464  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2465  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2466  * error has occured.
2467  */
2468 static tng_function_status tng_general_info_block_write
2469                 (tng_trajectory_t tng_data,
2470                  const char hash_mode)
2471 {
2472     int first_program_name_len, first_user_name_len;
2473     int first_computer_name_len, first_pgp_signature_len;
2474     int last_program_name_len, last_user_name_len;
2475     int last_computer_name_len, last_pgp_signature_len;
2476     int forcefield_name_len, name_len;
2477     int offset = 0;
2478     tng_gen_block_t block;
2479
2480     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2481     {
2482         return(TNG_CRITICAL);
2483     }
2484
2485     fseeko(tng_data->output_file, 0, SEEK_SET);
2486
2487     tng_block_init(&block);
2488
2489     name_len = (int)strlen("GENERAL INFO");
2490
2491     block->name = malloc(name_len + 1);
2492     if(!block->name)
2493     {
2494         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
2495                 name_len+1, __FILE__, __LINE__);
2496         tng_block_destroy(&block);
2497         return(TNG_CRITICAL);
2498     }
2499
2500     strcpy(block->name, "GENERAL INFO");
2501     block->id = TNG_GENERAL_INFO;
2502
2503     if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2504         TNG_SUCCESS)
2505     {
2506         fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2507                 __FILE__, __LINE__);
2508         tng_block_destroy(&block);
2509         return(TNG_CRITICAL);
2510     }
2511
2512     first_program_name_len = tng_min_i((int)strlen(tng_data->first_program_name) + 1,
2513                            TNG_MAX_STR_LEN);
2514     last_program_name_len = tng_min_i((int)strlen(tng_data->last_program_name) + 1,
2515                            TNG_MAX_STR_LEN);
2516     first_user_name_len = tng_min_i((int)strlen(tng_data->first_user_name) + 1,
2517                         TNG_MAX_STR_LEN);
2518     last_user_name_len = tng_min_i((int)strlen(tng_data->last_user_name) + 1,
2519                         TNG_MAX_STR_LEN);
2520     first_computer_name_len = tng_min_i((int)strlen(tng_data->first_computer_name) + 1,
2521                             TNG_MAX_STR_LEN);
2522     last_computer_name_len = tng_min_i((int)strlen(tng_data->last_computer_name) + 1,
2523                             TNG_MAX_STR_LEN);
2524     first_pgp_signature_len = tng_min_i((int)strlen(tng_data->first_pgp_signature) + 1,
2525                             TNG_MAX_STR_LEN);
2526     last_pgp_signature_len = tng_min_i((int)strlen(tng_data->last_pgp_signature) + 1,
2527                             TNG_MAX_STR_LEN);
2528     forcefield_name_len = tng_min_i((int)strlen(tng_data->forcefield_name) + 1,
2529                               TNG_MAX_STR_LEN);
2530
2531     if(block->block_contents)
2532     {
2533         free(block->block_contents);
2534     }
2535     block->block_contents = malloc(block->block_contents_size);
2536     if(!block->block_contents)
2537     {
2538         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
2539                block->block_contents_size, __FILE__, __LINE__);
2540         tng_block_destroy(&block);
2541         return(TNG_CRITICAL);
2542     }
2543
2544     strncpy(block->block_contents, tng_data->first_program_name, first_program_name_len);
2545     offset += first_program_name_len;
2546
2547     strncpy(block->block_contents+offset, tng_data->last_program_name, last_program_name_len);
2548     offset += last_program_name_len;
2549
2550     strncpy(block->block_contents+offset, tng_data->first_user_name, first_user_name_len);
2551     offset += first_user_name_len;
2552
2553     strncpy(block->block_contents+offset, tng_data->last_user_name, last_user_name_len);
2554     offset += last_user_name_len;
2555
2556     strncpy(block->block_contents+offset, tng_data->first_computer_name,
2557             first_computer_name_len);
2558     offset += first_computer_name_len;
2559
2560     strncpy(block->block_contents+offset, tng_data->last_computer_name,
2561             last_computer_name_len);
2562     offset += last_computer_name_len;
2563
2564     strncpy(block->block_contents+offset, tng_data->first_pgp_signature,
2565             first_pgp_signature_len);
2566     offset += first_pgp_signature_len;
2567
2568     strncpy(block->block_contents+offset, tng_data->last_pgp_signature,
2569             last_pgp_signature_len);
2570     offset += last_pgp_signature_len;
2571
2572     strncpy(block->block_contents+offset, tng_data->forcefield_name,
2573             forcefield_name_len);
2574     offset += forcefield_name_len;
2575
2576     memcpy(block->block_contents+offset, &tng_data->time,
2577            sizeof(tng_data->time));
2578     if(tng_data->output_endianness_swap_func_64)
2579     {
2580         if(tng_data->output_endianness_swap_func_64(tng_data,
2581                                       (int64_t *)block->header_contents+offset)
2582             != TNG_SUCCESS)
2583         {
2584             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2585                     __FILE__, __LINE__);
2586         }
2587     }
2588     offset += sizeof(tng_data->time);
2589
2590     memcpy(block->block_contents+offset, &tng_data->var_num_atoms_flag,
2591            sizeof(tng_data->var_num_atoms_flag));
2592     offset += sizeof(tng_data->var_num_atoms_flag);
2593
2594     memcpy(block->block_contents+offset, &tng_data->frame_set_n_frames,
2595            sizeof(tng_data->frame_set_n_frames));
2596     if(tng_data->output_endianness_swap_func_64)
2597     {
2598         if(tng_data->output_endianness_swap_func_64(tng_data,
2599                                       (int64_t *)block->header_contents+offset)
2600             != TNG_SUCCESS)
2601         {
2602             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2603                     __FILE__, __LINE__);
2604         }
2605     }
2606     offset += sizeof(tng_data->frame_set_n_frames);
2607
2608     memcpy(block->block_contents+offset,
2609            &tng_data->first_trajectory_frame_set_output_file_pos,
2610            sizeof(tng_data->first_trajectory_frame_set_output_file_pos));
2611     if(tng_data->output_endianness_swap_func_64)
2612     {
2613         if(tng_data->output_endianness_swap_func_64(tng_data,
2614                                       (int64_t *)block->header_contents+offset)
2615             != TNG_SUCCESS)
2616         {
2617             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2618                     __FILE__, __LINE__);
2619         }
2620     }
2621     offset += sizeof(tng_data->first_trajectory_frame_set_output_file_pos);
2622
2623     memcpy(block->block_contents+offset,
2624            &tng_data->last_trajectory_frame_set_output_file_pos,
2625            sizeof(tng_data->last_trajectory_frame_set_output_file_pos));
2626     if(tng_data->output_endianness_swap_func_64)
2627     {
2628         if(tng_data->output_endianness_swap_func_64(tng_data,
2629                                       (int64_t *)block->header_contents+offset)
2630             != TNG_SUCCESS)
2631         {
2632             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2633                     __FILE__, __LINE__);
2634         }
2635     }
2636     offset += sizeof(tng_data->last_trajectory_frame_set_output_file_pos);
2637
2638     memcpy(block->block_contents+offset, &tng_data->medium_stride_length,
2639            sizeof(tng_data->medium_stride_length));
2640     if(tng_data->output_endianness_swap_func_64)
2641     {
2642         if(tng_data->output_endianness_swap_func_64(tng_data,
2643                                       (int64_t *)block->header_contents+offset)
2644             != TNG_SUCCESS)
2645         {
2646             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2647                     __FILE__, __LINE__);
2648         }
2649     }
2650     offset += sizeof(tng_data->medium_stride_length);
2651
2652     memcpy(block->block_contents+offset, &tng_data->long_stride_length,
2653            sizeof(tng_data->long_stride_length));
2654     if(tng_data->output_endianness_swap_func_64)
2655     {
2656         if(tng_data->output_endianness_swap_func_64(tng_data,
2657                                       (int64_t *)block->header_contents+offset)
2658             != TNG_SUCCESS)
2659         {
2660             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2661                     __FILE__, __LINE__);
2662         }
2663     }
2664     offset += sizeof(tng_data->long_stride_length);
2665
2666     memcpy(block->block_contents+offset, &tng_data->distance_unit_exponential,
2667            sizeof(tng_data->distance_unit_exponential));
2668     if(tng_data->output_endianness_swap_func_64)
2669     {
2670         if(tng_data->output_endianness_swap_func_64(tng_data,
2671                                       (int64_t *)block->header_contents+offset)
2672             != TNG_SUCCESS)
2673         {
2674             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2675                     __FILE__, __LINE__);
2676         }
2677     }
2678
2679     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
2680     {
2681         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2682                tng_data->output_file_path, __FILE__, __LINE__);
2683         tng_block_destroy(&block);
2684         return(TNG_CRITICAL);
2685     }
2686
2687     if(fwrite(block->block_contents, block->block_contents_size, 1,
2688         tng_data->output_file) != 1)
2689     {
2690         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
2691         tng_block_destroy(&block);
2692         return(TNG_CRITICAL);
2693     }
2694
2695     tng_block_destroy(&block);
2696
2697     return(TNG_SUCCESS);
2698 }
2699
2700 /** Read the chain data of a molecules block.
2701  * @param tng_data is a trajectory data container.
2702  * @param block is a general block container.
2703  * @param chain is the chain data container.
2704  * @param offset is the offset of the block input and is updated when reading.
2705  * @return TNG_SUCCESS(0) is successful.
2706  */
2707 static tng_function_status tng_chain_data_read(tng_trajectory_t tng_data,
2708                                                tng_gen_block_t block,
2709                                                tng_chain_t chain,
2710                                                int *offset)
2711 {
2712     int len;
2713
2714     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2715
2716     memcpy(&chain->id, block->block_contents+*offset,
2717             sizeof(chain->id));
2718     if(tng_data->input_endianness_swap_func_64)
2719     {
2720         if(tng_data->input_endianness_swap_func_64(tng_data,
2721                                                    &chain->id)
2722             != TNG_SUCCESS)
2723         {
2724             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2725                     __FILE__, __LINE__);
2726         }
2727     }
2728     *offset += sizeof(chain->id);
2729
2730     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2731             TNG_MAX_STR_LEN);
2732     chain->name = malloc(len);
2733     strncpy(chain->name,
2734             block->block_contents+*offset, len);
2735     *offset += len;
2736
2737     memcpy(&chain->n_residues, block->block_contents+*offset,
2738         sizeof(chain->n_residues));
2739     if(tng_data->input_endianness_swap_func_64)
2740     {
2741         if(tng_data->input_endianness_swap_func_64(tng_data,
2742                                                    &chain->n_residues)
2743             != TNG_SUCCESS)
2744         {
2745             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2746                     __FILE__, __LINE__);
2747         }
2748     }
2749     *offset += sizeof(chain->n_residues);
2750
2751     return(TNG_SUCCESS);
2752 }
2753
2754 /** Write the chain data of a molecules block.
2755  * @param tng_data is a trajectory data container.
2756  * @param block is a general block container.
2757  * @param chain is the chain data container.
2758  * @param offset is the offset of the block output and is updated when writing.
2759  * @return TNG_SUCCESS(0) is successful.
2760  */
2761 static tng_function_status tng_chain_data_write(tng_trajectory_t tng_data,
2762                                                 tng_gen_block_t block,
2763                                                 tng_chain_t chain,
2764                                                 int *offset)
2765 {
2766     int len;
2767
2768     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2769
2770     memcpy(block->block_contents+*offset, &chain->id, sizeof(chain->id));
2771     if(tng_data->output_endianness_swap_func_64)
2772     {
2773         if(tng_data->output_endianness_swap_func_64(tng_data,
2774                                     (int64_t *)block->header_contents+*offset)
2775             != TNG_SUCCESS)
2776         {
2777             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2778                     __FILE__, __LINE__);
2779         }
2780     }
2781     *offset += sizeof(chain->id);
2782
2783     len = tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2784     strncpy(block->block_contents + *offset, chain->name, len);
2785     *offset += len;
2786
2787     memcpy(block->block_contents+*offset, &chain->n_residues,
2788         sizeof(chain->n_residues));
2789     if(tng_data->output_endianness_swap_func_64)
2790     {
2791         if(tng_data->output_endianness_swap_func_64(tng_data,
2792                                     (int64_t *)block->header_contents+*offset)
2793             != TNG_SUCCESS)
2794         {
2795             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2796                     __FILE__, __LINE__);
2797         }
2798     }
2799     *offset += sizeof(chain->n_residues);
2800
2801     return(TNG_SUCCESS);
2802 }
2803
2804 /** Read the residue data of a molecules block.
2805  * @param tng_data is a trajectory data container.
2806  * @param block is a general block container.
2807  * @param residue is the residue data container.
2808  * @param offset is the offset of the block input and is updated when reading.
2809  * @return TNG_SUCCESS(0) is successful.
2810  */
2811 static tng_function_status tng_residue_data_read(tng_trajectory_t tng_data,
2812                                                  tng_gen_block_t block,
2813                                                  tng_residue_t residue,
2814                                                  int *offset)
2815 {
2816     int len;
2817
2818     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2819
2820     memcpy(&residue->id, block->block_contents+*offset,
2821         sizeof(residue->id));
2822     if(tng_data->input_endianness_swap_func_64)
2823     {
2824         if(tng_data->input_endianness_swap_func_64(tng_data,
2825                                                    &residue->id)
2826             != TNG_SUCCESS)
2827         {
2828             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2829                     __FILE__, __LINE__);
2830         }
2831     }
2832     *offset += sizeof(residue->id);
2833
2834     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2835             TNG_MAX_STR_LEN);
2836     residue->name = malloc(len);
2837     strncpy(residue->name,
2838             block->block_contents+*offset, len);
2839     *offset += len;
2840
2841     memcpy(&residue->n_atoms, block->block_contents+*offset,
2842             sizeof(residue->n_atoms));
2843     if(tng_data->input_endianness_swap_func_64)
2844     {
2845         if(tng_data->input_endianness_swap_func_64(tng_data,
2846                                                    &residue->n_atoms)
2847             != TNG_SUCCESS)
2848         {
2849             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2850                     __FILE__, __LINE__);
2851         }
2852     }
2853     *offset += sizeof(residue->n_atoms);
2854
2855     return(TNG_SUCCESS);
2856 }
2857
2858 /** Write the residue data of a molecules block.
2859  * @param tng_data is a trajectory data container.
2860  * @param block is a general block container.
2861  * @param residue is the residue data container.
2862  * @param offset is the offset of the block output and is updated when writing.
2863  * @return TNG_SUCCESS(0) is successful.
2864  */
2865 static tng_function_status tng_residue_data_write(tng_trajectory_t tng_data,
2866                                                   tng_gen_block_t block,
2867                                                   tng_residue_t residue,
2868                                                   int *offset)
2869 {
2870     int len;
2871
2872     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2873
2874     memcpy(block->block_contents+*offset, &residue->id, sizeof(residue->id));
2875     if(tng_data->output_endianness_swap_func_64)
2876     {
2877         if(tng_data->output_endianness_swap_func_64(tng_data,
2878                                     (int64_t *)block->header_contents+*offset)
2879             != TNG_SUCCESS)
2880         {
2881             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2882                     __FILE__, __LINE__);
2883         }
2884     }
2885     *offset += sizeof(residue->id);
2886
2887     len = tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2888     strncpy(block->block_contents + *offset, residue->name, len);
2889     *offset += len;
2890
2891     memcpy(block->block_contents+*offset, &residue->n_atoms,
2892         sizeof(residue->n_atoms));
2893     if(tng_data->output_endianness_swap_func_64)
2894     {
2895         if(tng_data->output_endianness_swap_func_64(tng_data,
2896                                     (int64_t *)block->header_contents+*offset)
2897             != TNG_SUCCESS)
2898         {
2899             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2900                     __FILE__, __LINE__);
2901         }
2902     }
2903     *offset += sizeof(residue->n_atoms);
2904
2905     return(TNG_SUCCESS);
2906 }
2907
2908 /** Read the atom data of a molecules block.
2909  * @param tng_data is a trajectory data container.
2910  * @param block is a general block container.
2911  * @param atom is the atom data container.
2912  * @param offset is the offset of the block input and is updated when reading.
2913  * @return TNG_SUCCESS(0) is successful.
2914  */
2915 static tng_function_status tng_atom_data_read(tng_trajectory_t tng_data,
2916                                               tng_gen_block_t block,
2917                                               tng_atom_t atom,
2918                                               int *offset)
2919 {
2920     int len;
2921
2922     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2923
2924     memcpy(&atom->id, block->block_contents+*offset,
2925         sizeof(atom->id));
2926     if(tng_data->input_endianness_swap_func_64)
2927     {
2928         if(tng_data->input_endianness_swap_func_64(tng_data,
2929                                                     &atom->id)
2930             != TNG_SUCCESS)
2931         {
2932             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2933                     __FILE__, __LINE__);
2934         }
2935     }
2936     *offset += sizeof(atom->id);
2937
2938     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2939             TNG_MAX_STR_LEN);
2940     atom->name = malloc(len);
2941     strncpy(atom->name,
2942             block->block_contents+*offset, len);
2943     *offset += len;
2944
2945     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
2946             TNG_MAX_STR_LEN);
2947     atom->atom_type = malloc(len);
2948     strncpy(atom->atom_type,
2949             block->block_contents+*offset, len);
2950     *offset += len;
2951
2952     return(TNG_SUCCESS);
2953 }
2954
2955 /** Write the atom data of a molecules block.
2956  * @param tng_data is a trajectory data container.
2957  * @param block is a general block container.
2958  * @param atom is the atom data container.
2959  * @param offset is the offset of the block output and is updated when writing.
2960  * @return TNG_SUCCESS(0) is successful.
2961  */
2962 static tng_function_status tng_atom_data_write(tng_trajectory_t tng_data,
2963                                                tng_gen_block_t block,
2964                                                tng_atom_t atom,
2965                                                int *offset)
2966 {
2967     int len;
2968
2969     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
2970
2971     memcpy(block->block_contents+*offset, &atom->id,
2972             sizeof(atom->id));
2973     if(tng_data->output_endianness_swap_func_64)
2974     {
2975         if(tng_data->output_endianness_swap_func_64(tng_data,
2976                                     (int64_t *)block->header_contents+*offset)
2977             != TNG_SUCCESS)
2978         {
2979             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
2980                     __FILE__, __LINE__);
2981         }
2982     }
2983     *offset += sizeof(atom->id);
2984
2985     len = tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2986     strncpy(block->block_contents + *offset, atom->name, len);
2987     *offset += len;
2988
2989     len = tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2990     strncpy(block->block_contents + *offset, atom->atom_type, len);
2991     *offset += len;
2992
2993     return(TNG_SUCCESS);
2994 }
2995
2996 static tng_function_status tng_molecules_block_len_calculate
2997                 (const tng_trajectory_t tng_data,
2998                  int64_t *len)
2999 {
3000     int64_t i, j;
3001     tng_molecule_t molecule;
3002     tng_chain_t chain;
3003     tng_residue_t residue;
3004     tng_atom_t atom;
3005     tng_bond_t bond;
3006
3007     *len = 0;
3008
3009     for(i = 0; i < tng_data->n_molecules; i++)
3010     {
3011         molecule = &tng_data->molecules[i];
3012         if(!molecule->name)
3013         {
3014             molecule->name = malloc(1);
3015             if(!molecule->name)
3016             {
3017                 fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3018                        __FILE__, __LINE__);
3019                 return(TNG_CRITICAL);
3020             }
3021             molecule->name[0] = 0;
3022         }
3023         *len += tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3024
3025         chain = molecule->chains;
3026         for(j = 0; j < molecule->n_chains; j++)
3027         {
3028             *len += sizeof(chain->id);
3029
3030             if(!chain->name)
3031             {
3032                 chain->name = malloc(1);
3033                 if(!chain->name)
3034                 {
3035                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3036                            __FILE__, __LINE__);
3037                     return(TNG_CRITICAL);
3038                 }
3039                 chain->name[0] = 0;
3040             }
3041             *len += tng_min_i((int)strlen(chain->name) + 1, TNG_MAX_STR_LEN);
3042
3043             *len += sizeof(chain->n_residues);
3044
3045             chain++;
3046         }
3047
3048         residue = molecule->residues;
3049         for(j = 0; j < molecule->n_residues; j++)
3050         {
3051             *len += sizeof(residue->id);
3052
3053             if(!residue->name)
3054             {
3055                 residue->name = malloc(1);
3056                 if(!residue->name)
3057                 {
3058                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3059                            __FILE__, __LINE__);
3060                     return(TNG_CRITICAL);
3061                 }
3062                 residue->name[0] = 0;
3063             }
3064             *len += tng_min_i((int)strlen(residue->name) + 1, TNG_MAX_STR_LEN);
3065
3066             *len += sizeof(residue->n_atoms);
3067
3068             residue++;
3069         }
3070
3071         atom = molecule->atoms;
3072         for(j = 0; j < molecule->n_atoms; j++)
3073         {
3074             *len += sizeof(atom->id);
3075             if(!atom->name)
3076             {
3077                 atom->name = malloc(1);
3078                 if(!atom->name)
3079                 {
3080                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3081                            __FILE__, __LINE__);
3082                     return(TNG_CRITICAL);
3083                 }
3084                 atom->name[0] = 0;
3085             }
3086             *len += tng_min_i((int)strlen(atom->name) + 1, TNG_MAX_STR_LEN);
3087
3088             if(!atom->atom_type)
3089             {
3090                 atom->atom_type = malloc(1);
3091                 if(!atom->atom_type)
3092                 {
3093                     fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
3094                            __FILE__, __LINE__);
3095                     return(TNG_CRITICAL);
3096                 }
3097                 atom->atom_type[0] = 0;
3098             }
3099             *len += tng_min_i((int)strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
3100
3101             atom++;
3102         }
3103
3104         for(j = 0; j < molecule->n_bonds; j++)
3105         {
3106             *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
3107         }
3108     }
3109     *len += sizeof(tng_data->n_molecules) +
3110             (sizeof(molecule->id) +
3111             sizeof(molecule->quaternary_str) +
3112             sizeof(molecule->n_chains) +
3113             sizeof(molecule->n_residues) +
3114             sizeof(molecule->n_atoms) +
3115             sizeof(molecule->n_bonds)) *
3116             tng_data->n_molecules;
3117
3118     if(!tng_data->var_num_atoms_flag)
3119     {
3120         *len += tng_data->n_molecules * sizeof(int64_t);
3121     }
3122
3123     return(TNG_SUCCESS);
3124 }
3125
3126 /** Read a molecules block. Contains chain, residue and atom data
3127  * @param tng_data is a trajectory data container.
3128  * @param block is a general block container.
3129  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3130  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3131  * compared to the md5 hash of the read contents to ensure valid data.
3132  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3133  * error has occured.
3134  */
3135 static tng_function_status tng_molecules_block_read
3136                 (tng_trajectory_t tng_data,
3137                  tng_gen_block_t block,
3138                  const char hash_mode)
3139 {
3140     int64_t i, j, k, l;
3141     int len, offset = 0;
3142     tng_molecule_t molecule;
3143     tng_chain_t chain;
3144     tng_residue_t residue;
3145     tng_atom_t atom;
3146     tng_bond_t bond;
3147     tng_bool same_hash;
3148
3149     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3150     {
3151         return(TNG_CRITICAL);
3152     }
3153
3154     if(block->block_contents)
3155     {
3156         free(block->block_contents);
3157     }
3158
3159     block->block_contents = malloc(block->block_contents_size);
3160     if(!block->block_contents)
3161     {
3162         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3163                block->block_contents_size, __FILE__, __LINE__);
3164         return(TNG_CRITICAL);
3165     }
3166
3167     /* Read the whole block into block_contents to be able to write it to disk
3168      * even if it cannot be interpreted. */
3169     if(fread(block->block_contents, block->block_contents_size, 1,
3170              tng_data->input_file) == 0)
3171     {
3172         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3173     }
3174
3175     /* FIXME: Does not check if the size of the contents matches the expected
3176      * size or if the contents can be read. */
3177
3178     if(hash_mode == TNG_USE_HASH)
3179     {
3180         tng_md5_hash_match_verify(block, &same_hash);
3181         if(same_hash != TNG_TRUE)
3182         {
3183             fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3184                 "%s: %d\n",
3185                 __FILE__, __LINE__);
3186         }
3187     }
3188
3189     if(tng_data->molecules)
3190     {
3191         for(i=0; i<tng_data->n_molecules; i++)
3192         {
3193             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
3194         }
3195         free(tng_data->molecules);
3196         tng_data->molecules = 0;
3197         tng_data->n_molecules = 0;
3198     }
3199
3200     memcpy(&tng_data->n_molecules, block->block_contents,
3201            sizeof(tng_data->n_molecules));
3202     if(tng_data->input_endianness_swap_func_64)
3203     {
3204         if(tng_data->input_endianness_swap_func_64(tng_data,
3205                                                    &tng_data->n_molecules)
3206             != TNG_SUCCESS)
3207         {
3208             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3209                     __FILE__, __LINE__);
3210         }
3211     }
3212     offset += sizeof(tng_data->n_molecules);
3213
3214     if(tng_data->molecules)
3215     {
3216         free(tng_data->molecules);
3217     }
3218
3219     tng_data->n_particles = 0;
3220
3221     tng_data->molecules = malloc(tng_data->n_molecules *
3222                           sizeof(struct tng_molecule));
3223     if(!tng_data->molecules)
3224     {
3225         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3226                tng_data->n_molecules * sizeof(struct tng_molecule),
3227                __FILE__, __LINE__);
3228         return(TNG_CRITICAL);
3229     }
3230
3231     if(!tng_data->var_num_atoms_flag)
3232     {
3233         if(tng_data->molecule_cnt_list)
3234         {
3235             free(tng_data->molecule_cnt_list);
3236         }
3237         tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
3238                                       tng_data->n_molecules);
3239         if(!tng_data->molecule_cnt_list)
3240         {
3241             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3242                    tng_data->n_molecules * sizeof(struct tng_molecule),
3243                    __FILE__, __LINE__);
3244             return(TNG_CRITICAL);
3245         }
3246     }
3247
3248     /* Read each molecule from file */
3249     for(i=0; i < tng_data->n_molecules; i++)
3250     {
3251         molecule = &tng_data->molecules[i];
3252
3253         memcpy(&molecule->id, block->block_contents+offset,
3254                sizeof(molecule->id));
3255         if(tng_data->input_endianness_swap_func_64)
3256         {
3257             if(tng_data->input_endianness_swap_func_64(tng_data,
3258                                                        &molecule->id)
3259                 != TNG_SUCCESS)
3260             {
3261                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3262                         __FILE__, __LINE__);
3263             }
3264         }
3265         offset += sizeof(molecule->id);
3266
3267 /*         fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
3268         len = tng_min_i((int)strlen(block->block_contents+offset) + 1, TNG_MAX_STR_LEN);
3269         molecule->name = malloc(len);
3270         strncpy(molecule->name, block->block_contents+offset, len);
3271         offset += len;
3272
3273         memcpy(&molecule->quaternary_str, block->block_contents+offset,
3274                sizeof(molecule->quaternary_str));
3275         if(tng_data->input_endianness_swap_func_64)
3276         {
3277             if(tng_data->input_endianness_swap_func_64(tng_data,
3278                                                      &molecule->quaternary_str)
3279                 != TNG_SUCCESS)
3280             {
3281                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3282                         __FILE__, __LINE__);
3283             }
3284         }
3285         offset += sizeof(molecule->quaternary_str);
3286
3287         if(!tng_data->var_num_atoms_flag)
3288         {
3289             memcpy(&tng_data->molecule_cnt_list[i],
3290                    block->block_contents+offset,
3291                    sizeof(int64_t));
3292             if(tng_data->input_endianness_swap_func_64)
3293             {
3294                 if(tng_data->input_endianness_swap_func_64(tng_data,
3295                                                &tng_data->molecule_cnt_list[i])
3296                     != TNG_SUCCESS)
3297                 {
3298                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3299                             __FILE__, __LINE__);
3300                 }
3301             }
3302             offset += sizeof(int64_t);
3303         }
3304
3305
3306         memcpy(&molecule->n_chains, block->block_contents+offset,
3307                sizeof(molecule->n_chains));
3308         if(tng_data->input_endianness_swap_func_64)
3309         {
3310             if(tng_data->input_endianness_swap_func_64(tng_data,
3311                                                        &molecule->n_chains)
3312                 != TNG_SUCCESS)
3313             {
3314                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3315                         __FILE__, __LINE__);
3316             }
3317         }
3318         offset += sizeof(molecule->n_chains);
3319
3320         memcpy(&molecule->n_residues, block->block_contents+offset,
3321                sizeof(molecule->n_residues));
3322         if(tng_data->input_endianness_swap_func_64)
3323         {
3324             if(tng_data->input_endianness_swap_func_64(tng_data,
3325                                                        &molecule->n_residues)
3326                 != TNG_SUCCESS)
3327             {
3328                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3329                         __FILE__, __LINE__);
3330             }
3331         }
3332         offset += sizeof(molecule->n_residues);
3333
3334         memcpy(&molecule->n_atoms, block->block_contents+offset,
3335                sizeof(molecule->n_atoms));
3336         if(tng_data->input_endianness_swap_func_64)
3337         {
3338             if(tng_data->input_endianness_swap_func_64(tng_data,
3339                                                        &molecule->n_atoms)
3340                 != TNG_SUCCESS)
3341             {
3342                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3343                         __FILE__, __LINE__);
3344             }
3345         }
3346         offset += sizeof(molecule->n_atoms);
3347
3348         tng_data->n_particles += molecule->n_atoms *
3349                                  tng_data->molecule_cnt_list[i];
3350
3351         if(molecule->n_chains > 0)
3352         {
3353             molecule->chains = malloc(molecule->n_chains *
3354                                     sizeof(struct tng_chain));
3355             if(!molecule->chains)
3356             {
3357                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3358                     molecule->n_chains * sizeof(struct tng_chain),
3359                     __FILE__, __LINE__);
3360                 return(TNG_CRITICAL);
3361             }
3362
3363             chain = molecule->chains;
3364         }
3365         else
3366         {
3367             chain = 0;
3368         }
3369
3370         if(molecule->n_residues > 0)
3371         {
3372             molecule->residues = malloc(molecule->n_residues *
3373                                 sizeof(struct tng_residue));
3374             if(!molecule->residues)
3375             {
3376                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3377                     molecule->n_residues * sizeof(struct tng_residue),
3378                     __FILE__, __LINE__);
3379                 if(molecule->chains)
3380                 {
3381                     free(molecule->chains);
3382                     molecule->chains = 0;
3383                 }
3384                 return(TNG_CRITICAL);
3385             }
3386
3387             residue = molecule->residues;
3388         }
3389         else
3390         {
3391             residue = 0;
3392         }
3393
3394         molecule->atoms = malloc(molecule->n_atoms *
3395                                  sizeof(struct tng_atom));
3396         if(!molecule->atoms)
3397         {
3398             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3399                    molecule->n_atoms * sizeof(struct tng_atom),
3400                    __FILE__, __LINE__);
3401             if(molecule->chains)
3402             {
3403                 free(molecule->chains);
3404                 molecule->chains = 0;
3405             }
3406             if(molecule->residues)
3407             {
3408                 free(molecule->residues);
3409                 molecule->residues = 0;
3410             }
3411             return(TNG_CRITICAL);
3412         }
3413
3414         atom = molecule->atoms;
3415
3416         if(molecule->n_chains > 0)
3417         {
3418             /* Read the chains of the molecule */
3419             for(j=0; j<molecule->n_chains; j++)
3420             {
3421                 chain->molecule = molecule;
3422
3423                 tng_chain_data_read(tng_data, block, chain, &offset);
3424
3425                 chain->residues = molecule->residues;
3426                 residue = chain->residues;
3427
3428                 /* Read the residues of the chain */
3429                 for(k=0; k<chain->n_residues; k++)
3430                 {
3431                     residue->chain = chain;
3432
3433                     tng_residue_data_read(tng_data, block, residue, &offset);
3434
3435                     residue->atoms_offset = atom - molecule->atoms;
3436                     /* Read the atoms of the residue */
3437                     for(l=0; l<residue->n_atoms; l++)
3438                     {
3439                         atom->residue = residue;
3440
3441                         tng_atom_data_read(tng_data, block, atom, &offset);
3442
3443                         atom++;
3444                     }
3445                     residue++;
3446                 }
3447                 chain++;
3448             }
3449         }
3450         else
3451         {
3452             if(molecule->n_residues > 0)
3453             {
3454                 for(k=0; k<molecule->n_residues; k++)
3455                 {
3456                     residue->chain = 0;
3457
3458                     tng_residue_data_read(tng_data, block, residue, &offset);
3459
3460                     residue->atoms_offset = atom - molecule->atoms;
3461                     /* Read the atoms of the residue */
3462                     for(l=0; l<residue->n_atoms; l++)
3463                     {
3464                         atom->residue = residue;
3465
3466                         tng_atom_data_read(tng_data, block, atom, &offset);
3467
3468                         atom++;
3469                     }
3470                     residue++;
3471                 }
3472             }
3473             else
3474             {
3475                 for(l=0; l<molecule->n_atoms; l++)
3476                 {
3477                     atom->residue = 0;
3478
3479                     tng_atom_data_read(tng_data, block, atom, &offset);
3480
3481                     atom++;
3482                 }
3483             }
3484         }
3485
3486         memcpy(&molecule->n_bonds, block->block_contents+offset,
3487                sizeof(molecule->n_bonds));
3488         if(tng_data->input_endianness_swap_func_64)
3489         {
3490             if(tng_data->input_endianness_swap_func_64(tng_data,
3491                                                        &molecule->n_bonds)
3492                 != TNG_SUCCESS)
3493             {
3494                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3495                         __FILE__, __LINE__);
3496             }
3497         }
3498         offset += sizeof(molecule->n_bonds);
3499
3500         if(molecule->n_bonds > 0)
3501         {
3502             tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
3503                                            sizeof(struct tng_bond));
3504             if(!molecule->bonds)
3505             {
3506                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
3507                        molecule->n_bonds * sizeof(struct tng_bond),
3508                        __FILE__, __LINE__);
3509                 if(molecule->chains)
3510                 {
3511                     free(molecule->chains);
3512                     molecule->chains = 0;
3513                 }
3514                 if(molecule->residues)
3515                 {
3516                     free(molecule->residues);
3517                     molecule->residues = 0;
3518                 }
3519                 if(molecule->atoms)
3520                 {
3521                     free(molecule->atoms);
3522                     molecule->atoms = 0;
3523                 }
3524                 return(TNG_CRITICAL);
3525             }
3526
3527             bond = molecule->bonds;
3528
3529             for(j=0; j<molecule->n_bonds; j++)
3530             {
3531                 memcpy(&bond->from_atom_id, block->block_contents+offset,
3532                     sizeof(bond->from_atom_id));
3533                 if(tng_data->input_endianness_swap_func_64)
3534                 {
3535                     if(tng_data->input_endianness_swap_func_64(tng_data,
3536                                                                &bond->from_atom_id)
3537                         != TNG_SUCCESS)
3538                     {
3539                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3540                                 __FILE__, __LINE__);
3541                     }
3542                 }
3543                 offset += sizeof(bond->from_atom_id);
3544
3545                 memcpy(&bond->to_atom_id, block->block_contents+offset,
3546                     sizeof(bond->to_atom_id));
3547                 if(tng_data->input_endianness_swap_func_64)
3548                 {
3549                     if(tng_data->input_endianness_swap_func_64(tng_data,
3550                                                                &bond->to_atom_id)
3551                         != TNG_SUCCESS)
3552                     {
3553                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3554                                 __FILE__, __LINE__);
3555                     }
3556                 }
3557                 offset += sizeof(bond->to_atom_id);
3558
3559                 bond++;
3560             }
3561         }
3562         else
3563         {
3564             molecule->bonds = 0;
3565         }
3566     }
3567
3568     return(TNG_SUCCESS);
3569 }
3570
3571 /** Write a molecules block.
3572  * @param tng_data is a trajectory data container.
3573  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3574  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3575  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3576  * error has occured.
3577  */
3578 static tng_function_status tng_molecules_block_write
3579                 (tng_trajectory_t tng_data,
3580                  const char hash_mode)
3581 {
3582     int len = 0, name_len, offset = 0;
3583     int64_t i, j, k, l;
3584     tng_molecule_t molecule;
3585     tng_chain_t chain;
3586     tng_residue_t residue;
3587     tng_atom_t atom;
3588     tng_bond_t bond;
3589     tng_gen_block_t block;
3590
3591     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3592     {
3593         return(TNG_CRITICAL);
3594     }
3595
3596     tng_block_init(&block);
3597
3598     name_len = (int)strlen("MOLECULES");
3599
3600     block->name = malloc(name_len + 1);
3601     if(!block->name)
3602     {
3603         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
3604                 name_len+1, __FILE__, __LINE__);
3605         tng_block_destroy(&block);
3606         return(TNG_CRITICAL);
3607     }
3608
3609     strcpy(block->name, "MOLECULES");
3610     block->id = TNG_MOLECULES;
3611
3612     if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3613         TNG_SUCCESS)
3614     {
3615         fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3616                 __FILE__, __LINE__);
3617         tng_block_destroy(&block);
3618         return(TNG_CRITICAL);
3619     }
3620
3621     block->block_contents = malloc(block->block_contents_size);
3622     if(!block->block_contents)
3623     {
3624         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3625                block->block_contents_size, __FILE__, __LINE__);
3626         tng_block_destroy(&block);
3627         return(TNG_CRITICAL);
3628     }
3629
3630     memcpy(block->block_contents+offset, &tng_data->n_molecules,
3631            sizeof(tng_data->n_molecules));
3632     if(tng_data->output_endianness_swap_func_64)
3633     {
3634         if(tng_data->output_endianness_swap_func_64(tng_data,
3635                                       (int64_t *)block->header_contents+offset)
3636             != TNG_SUCCESS)
3637         {
3638             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3639                     __FILE__, __LINE__);
3640         }
3641     }
3642     offset += sizeof(tng_data->n_molecules);
3643
3644     for(i = 0; i < tng_data->n_molecules; i++)
3645     {
3646         molecule = &tng_data->molecules[i];
3647         memcpy(block->block_contents+offset, &molecule->id,
3648                sizeof(molecule->id));
3649         if(tng_data->output_endianness_swap_func_64)
3650         {
3651             if(tng_data->output_endianness_swap_func_64(tng_data,
3652                                         (int64_t *)block->header_contents+offset)
3653                 != TNG_SUCCESS)
3654             {
3655                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3656                         __FILE__, __LINE__);
3657             }
3658         }
3659         offset += sizeof(molecule->id);
3660
3661 /*         fprintf(stderr, "TNG library: Wrote id: %"PRId64" offset: %d\n", molecule->id, offset); */
3662         len = tng_min_i((int)strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
3663         strncpy(block->block_contents + offset, molecule->name, len);
3664         offset += len;
3665
3666         memcpy(block->block_contents+offset, &molecule->quaternary_str,
3667                sizeof(molecule->quaternary_str));
3668         if(tng_data->output_endianness_swap_func_64)
3669         {
3670             if(tng_data->output_endianness_swap_func_64(tng_data,
3671                                         (int64_t *)block->header_contents+offset)
3672                 != TNG_SUCCESS)
3673             {
3674                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3675                         __FILE__, __LINE__);
3676             }
3677         }
3678         offset += sizeof(molecule->quaternary_str);
3679
3680         if(!tng_data->var_num_atoms_flag)
3681         {
3682             memcpy(block->block_contents+offset,
3683                    &tng_data->molecule_cnt_list[i], sizeof(int64_t));
3684             if(tng_data->output_endianness_swap_func_64)
3685             {
3686                 if(tng_data->output_endianness_swap_func_64(tng_data,
3687                                             (int64_t *)block->header_contents+offset)
3688                     != TNG_SUCCESS)
3689                 {
3690                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3691                             __FILE__, __LINE__);
3692                 }
3693             }
3694             offset += sizeof(int64_t);
3695         }
3696
3697         memcpy(block->block_contents+offset, &molecule->n_chains,
3698                sizeof(molecule->n_chains));
3699         if(tng_data->output_endianness_swap_func_64)
3700         {
3701             if(tng_data->output_endianness_swap_func_64(tng_data,
3702                                         (int64_t *)block->header_contents+offset)
3703                 != TNG_SUCCESS)
3704             {
3705                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3706                         __FILE__, __LINE__);
3707             }
3708         }
3709         offset += sizeof(molecule->n_chains);
3710
3711         memcpy(block->block_contents+offset, &molecule->n_residues,
3712                sizeof(molecule->n_residues));
3713         if(tng_data->output_endianness_swap_func_64)
3714         {
3715             if(tng_data->output_endianness_swap_func_64(tng_data,
3716                                         (int64_t *)block->header_contents+offset)
3717                 != TNG_SUCCESS)
3718             {
3719                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3720                         __FILE__, __LINE__);
3721             }
3722         }
3723         offset += sizeof(molecule->n_residues);
3724
3725         memcpy(block->block_contents+offset, &molecule->n_atoms,
3726                sizeof(molecule->n_atoms));
3727         if(tng_data->output_endianness_swap_func_64)
3728         {
3729             if(tng_data->output_endianness_swap_func_64(tng_data,
3730                                         (int64_t *)block->header_contents+offset)
3731                 != TNG_SUCCESS)
3732             {
3733                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3734                         __FILE__, __LINE__);
3735             }
3736         }
3737         offset += sizeof(molecule->n_atoms);
3738
3739         if(molecule->n_chains > 0)
3740         {
3741             chain = molecule->chains;
3742             for(j = 0; j < molecule->n_chains; j++)
3743             {
3744                 tng_chain_data_write(tng_data, block, chain, &offset);
3745
3746                 residue = chain->residues;
3747                 for(k = 0; k < chain->n_residues; k++)
3748                 {
3749                     tng_residue_data_write(tng_data, block, residue, &offset);
3750
3751                     atom = molecule->atoms + residue->atoms_offset;
3752                     for(l = 0; l < residue->n_atoms; l++)
3753                     {
3754                         tng_atom_data_write(tng_data, block, atom, &offset);
3755
3756                         atom++;
3757                     }
3758                     residue++;
3759                 }
3760                 chain++;
3761             }
3762         }
3763         else
3764         {
3765             if(molecule->n_residues > 0)
3766             {
3767                 residue = molecule->residues;
3768                 for(k = 0; k < molecule->n_residues; k++)
3769                 {
3770                     tng_residue_data_write(tng_data, block, residue, &offset);
3771
3772                     atom = molecule->atoms + residue->atoms_offset;
3773                     for(l = 0; l < residue->n_atoms; l++)
3774                     {
3775                         tng_atom_data_write(tng_data, block, atom, &offset);
3776
3777                         atom++;
3778                     }
3779                     residue++;
3780                 }
3781             }
3782             else
3783             {
3784                 atom = molecule->atoms;
3785                 for(l = 0; l < molecule->n_atoms; l++)
3786                 {
3787                     tng_atom_data_write(tng_data, block, atom, &offset);
3788
3789                     atom++;
3790                 }
3791             }
3792         }
3793
3794         memcpy(block->block_contents+offset, &molecule->n_bonds,
3795                sizeof(molecule->n_bonds));
3796         if(tng_data->output_endianness_swap_func_64)
3797         {
3798             if(tng_data->output_endianness_swap_func_64(tng_data,
3799                                         (int64_t *)block->header_contents+offset)
3800                 != TNG_SUCCESS)
3801             {
3802                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3803                         __FILE__, __LINE__);
3804             }
3805         }
3806         offset += sizeof(molecule->n_bonds);
3807
3808         bond = molecule->bonds;
3809         for(j = 0; j < molecule->n_bonds; j++)
3810         {
3811             memcpy(block->block_contents+offset, &bond->from_atom_id,
3812                    sizeof(bond->from_atom_id));
3813             if(tng_data->output_endianness_swap_func_64)
3814             {
3815                 if(tng_data->output_endianness_swap_func_64(tng_data,
3816                                             (int64_t *)block->header_contents+offset)
3817                     != TNG_SUCCESS)
3818                 {
3819                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3820                             __FILE__, __LINE__);
3821                 }
3822             }
3823             offset += sizeof(bond->from_atom_id);
3824
3825             memcpy(block->block_contents+offset, &bond->to_atom_id,
3826                    sizeof(bond->to_atom_id));
3827             if(tng_data->output_endianness_swap_func_64)
3828             {
3829                 if(tng_data->output_endianness_swap_func_64(tng_data,
3830                                             (int64_t *)block->header_contents+offset)
3831                     != TNG_SUCCESS)
3832                 {
3833                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3834                             __FILE__, __LINE__);
3835                 }
3836             }
3837             offset += sizeof(bond->to_atom_id);
3838
3839             bond++;
3840         }
3841     }
3842
3843     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
3844     {
3845         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3846                tng_data->output_file_path, __FILE__, __LINE__);
3847         tng_block_destroy(&block);
3848         return(TNG_CRITICAL);
3849     }
3850
3851     if(fwrite(block->block_contents, block->block_contents_size, 1,
3852               tng_data->output_file) != 1)
3853     {
3854         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
3855                __FILE__, __LINE__);
3856         tng_block_destroy(&block);
3857         return(TNG_CRITICAL);
3858     }
3859
3860     tng_block_destroy(&block);
3861
3862     return(TNG_SUCCESS);
3863 }
3864
3865 static tng_function_status tng_frame_set_block_len_calculate
3866                 (const tng_trajectory_t tng_data,
3867                  int64_t *len)
3868 {
3869     *len = sizeof(int64_t) * 8;
3870     *len += sizeof(double) * 2;
3871
3872     if(tng_data->var_num_atoms_flag)
3873     {
3874         *len += sizeof(int64_t) * tng_data->n_molecules;
3875     }
3876     return(TNG_SUCCESS);
3877 }
3878
3879 /** Read a frame set block. Update tng_data->current_trajectory_frame_set
3880  * @param tng_data is a trajectory data container.
3881  * @param block is a general block container.
3882  * @param hash_mode is an option to decide whether to use the md5 hash or not.
3883  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3884  * compared to the md5 hash of the read contents to ensure valid data.
3885  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3886  * error has occured.
3887  */
3888 static tng_function_status tng_frame_set_block_read
3889                 (tng_trajectory_t tng_data,
3890                  tng_gen_block_t block,
3891                  const char hash_mode)
3892 {
3893     int offset = 0;
3894     int64_t file_pos, i, prev_n_particles;
3895     tng_bool same_hash;
3896     tng_trajectory_frame_set_t frame_set =
3897     &tng_data->current_trajectory_frame_set;
3898
3899     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3900     {
3901         return(TNG_CRITICAL);
3902     }
3903
3904     if(block->block_contents)
3905     {
3906         free(block->block_contents);
3907     }
3908
3909     block->block_contents = malloc(block->block_contents_size);
3910     if(!block->block_contents)
3911     {
3912         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
3913                block->block_contents_size, __FILE__, __LINE__);
3914         return(TNG_CRITICAL);
3915     }
3916
3917     /* Read the whole block into block_contents to be able to write it to
3918      * disk even if it cannot be interpreted. */
3919     if(fread(block->block_contents, block->block_contents_size, 1,
3920              tng_data->input_file) == 0)
3921     {
3922         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3923         return(TNG_CRITICAL);
3924     }
3925
3926     /* FIXME: Does not check if the size of the contents matches the expected
3927      * size or if the contents can be read. */
3928
3929     file_pos = (int64_t)ftello(tng_data->input_file) -
3930                (block->block_contents_size + block->header_contents_size);
3931
3932     if(hash_mode == TNG_USE_HASH)
3933     {
3934         tng_md5_hash_match_verify(block, &same_hash);
3935         if(same_hash != TNG_TRUE)
3936         {
3937             fprintf(stderr, "TNG library: Frame set block contents corrupt. File pos %"PRId64" Hashes do not match. "
3938                 "%s: %d\n",
3939                 file_pos, __FILE__, __LINE__);
3940     /*         return(TNG_FAILURE); */
3941         }
3942     }
3943
3944     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3945
3946     tng_frame_set_particle_mapping_free(tng_data);
3947
3948     if(tng_data->first_trajectory_frame_set_input_file_pos <= 0)
3949     {
3950         tng_data->first_trajectory_frame_set_input_file_pos = file_pos;
3951     }
3952     /* FIXME: Should check the frame number instead of the file_pos, in case
3953      * frame sets are not in order */
3954     if(tng_data->last_trajectory_frame_set_input_file_pos < file_pos)
3955     {
3956         tng_data->last_trajectory_frame_set_input_file_pos = file_pos;
3957     }
3958
3959     memcpy(&frame_set->first_frame, block->block_contents,
3960            sizeof(frame_set->first_frame));
3961     if(tng_data->input_endianness_swap_func_64)
3962     {
3963         if(tng_data->input_endianness_swap_func_64(tng_data,
3964                                                    &frame_set->first_frame)
3965             != TNG_SUCCESS)
3966         {
3967             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3968                     __FILE__, __LINE__);
3969         }
3970     }
3971     offset += sizeof(frame_set->first_frame);
3972
3973     memcpy(&frame_set->n_frames, block->block_contents + offset,
3974            sizeof(frame_set->n_frames));
3975     if(tng_data->input_endianness_swap_func_64)
3976     {
3977         if(tng_data->input_endianness_swap_func_64(tng_data,
3978                                                    &frame_set->n_frames)
3979             != TNG_SUCCESS)
3980         {
3981             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
3982                     __FILE__, __LINE__);
3983         }
3984     }
3985     offset += sizeof(frame_set->n_frames);
3986
3987     if(tng_data->var_num_atoms_flag)
3988     {
3989         prev_n_particles = frame_set->n_particles;
3990         frame_set->n_particles = 0;
3991         /* If the list of molecule counts has already been created assume that
3992          * it is of correct size. */
3993         if(!frame_set->molecule_cnt_list)
3994         {
3995                 frame_set->molecule_cnt_list =
3996                 malloc(sizeof(int64_t) * tng_data->n_molecules);
3997
3998                 if(!frame_set->molecule_cnt_list)
3999                 {
4000                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
4001                            sizeof(int64_t) * tng_data->n_molecules,
4002                            __FILE__, __LINE__);
4003                     return(TNG_CRITICAL);
4004                 }
4005         }
4006         for(i = 0; i < tng_data->n_molecules; i++)
4007         {
4008             memcpy(&frame_set->molecule_cnt_list[i],
4009                    block->block_contents + offset,
4010                    sizeof(int64_t));
4011             if(tng_data->input_endianness_swap_func_64)
4012             {
4013                 if(tng_data->input_endianness_swap_func_64(tng_data,
4014                                               &frame_set->molecule_cnt_list[i])
4015                     != TNG_SUCCESS)
4016                 {
4017                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4018                             __FILE__, __LINE__);
4019                 }
4020             }
4021             offset += sizeof(int64_t);
4022             frame_set->n_particles += tng_data->molecules[i].n_atoms *
4023                                       frame_set->molecule_cnt_list[i];
4024         }
4025         if(prev_n_particles && frame_set->n_particles != prev_n_particles)
4026         {
4027             /* FIXME: Particle dependent data memory management */
4028         }
4029     }
4030
4031     memcpy(&frame_set->next_frame_set_file_pos,
4032            block->block_contents + offset,
4033            sizeof(frame_set->next_frame_set_file_pos));
4034     if(tng_data->input_endianness_swap_func_64)
4035     {
4036         if(tng_data->input_endianness_swap_func_64(tng_data,
4037                                            &frame_set->next_frame_set_file_pos)
4038             != TNG_SUCCESS)
4039         {
4040             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4041                     __FILE__, __LINE__);
4042         }
4043     }
4044     offset += sizeof(frame_set->next_frame_set_file_pos);
4045
4046     memcpy(&frame_set->prev_frame_set_file_pos,
4047            block->block_contents + offset,
4048            sizeof(frame_set->prev_frame_set_file_pos));
4049     if(tng_data->input_endianness_swap_func_64)
4050     {
4051         if(tng_data->input_endianness_swap_func_64(tng_data,
4052                                            &frame_set->prev_frame_set_file_pos)
4053             != TNG_SUCCESS)
4054         {
4055             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4056                     __FILE__, __LINE__);
4057         }
4058     }
4059     offset += sizeof(frame_set->prev_frame_set_file_pos);
4060
4061     memcpy(&frame_set->medium_stride_next_frame_set_file_pos,
4062            block->block_contents + offset,
4063            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4064     if(tng_data->input_endianness_swap_func_64)
4065     {
4066         if(tng_data->input_endianness_swap_func_64(tng_data,
4067                              &frame_set->medium_stride_next_frame_set_file_pos)
4068             != TNG_SUCCESS)
4069         {
4070             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4071                     __FILE__, __LINE__);
4072         }
4073     }
4074     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4075
4076     memcpy(&frame_set->medium_stride_prev_frame_set_file_pos,
4077            block->block_contents + offset,
4078            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4079     if(tng_data->input_endianness_swap_func_64)
4080     {
4081         if(tng_data->input_endianness_swap_func_64(tng_data,
4082                              &frame_set->medium_stride_prev_frame_set_file_pos)
4083             != TNG_SUCCESS)
4084         {
4085             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4086                     __FILE__, __LINE__);
4087         }
4088     }
4089     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4090
4091     memcpy(&frame_set->long_stride_next_frame_set_file_pos,
4092            block->block_contents + offset,
4093            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4094     if(tng_data->input_endianness_swap_func_64)
4095     {
4096         if(tng_data->input_endianness_swap_func_64(tng_data,
4097                                &frame_set->long_stride_next_frame_set_file_pos)
4098             != TNG_SUCCESS)
4099         {
4100             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4101                     __FILE__, __LINE__);
4102         }
4103     }
4104     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4105
4106     memcpy(&frame_set->long_stride_prev_frame_set_file_pos,
4107            block->block_contents + offset,
4108            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4109     if(tng_data->input_endianness_swap_func_64)
4110     {
4111         if(tng_data->input_endianness_swap_func_64(tng_data,
4112                                &frame_set->long_stride_prev_frame_set_file_pos)
4113             != TNG_SUCCESS)
4114         {
4115             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4116                     __FILE__, __LINE__);
4117         }
4118     }
4119     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4120
4121     if(block->block_version >= 3)
4122     {
4123         memcpy(&frame_set->first_frame_time,
4124             block->block_contents + offset,
4125             sizeof(frame_set->first_frame_time));
4126         if(tng_data->input_endianness_swap_func_64)
4127         {
4128             if(tng_data->input_endianness_swap_func_64(tng_data,
4129                                 (int64_t *)&frame_set->first_frame_time)
4130                 != TNG_SUCCESS)
4131             {
4132                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4133                         __FILE__, __LINE__);
4134             }
4135         }
4136         offset += sizeof(frame_set->first_frame_time);
4137
4138         memcpy(&tng_data->time_per_frame,
4139             block->block_contents + offset,
4140             sizeof(tng_data->time_per_frame));
4141         if(tng_data->input_endianness_swap_func_64)
4142         {
4143             if(tng_data->input_endianness_swap_func_64(tng_data,
4144                                 (int64_t *)&tng_data->time_per_frame)
4145                 != TNG_SUCCESS)
4146             {
4147                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4148                         __FILE__, __LINE__);
4149             }
4150         }
4151     }
4152     else
4153     {
4154         frame_set->first_frame_time = -1;
4155         tng_data->time_per_frame = -1;
4156     }
4157
4158     /* If the output file and the input files are the same the number of
4159      * frames in the file are the same number as has just been read.
4160      * This is updated here to later on see if there have been new frames
4161      * added and thereby the frame set needs to be rewritten. */
4162     if(tng_data->output_file == tng_data->input_file)
4163     {
4164         frame_set->n_written_frames = frame_set->n_frames;
4165     }
4166
4167     return(TNG_SUCCESS);
4168 }
4169
4170 /** Write tng_data->current_trajectory_frame_set to file
4171  * @param tng_data is a trajectory data container.
4172  * @param block is a general block container.
4173  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4174  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4175  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4176  * error has occured.
4177  */
4178 static tng_function_status tng_frame_set_block_write
4179                 (tng_trajectory_t tng_data,
4180                  tng_gen_block_t block,
4181                  const char hash_mode)
4182 {
4183     char *temp_name;
4184     int64_t i;
4185     int offset = 0;
4186     unsigned int name_len;
4187     tng_trajectory_frame_set_t frame_set =
4188     &tng_data->current_trajectory_frame_set;
4189
4190     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4191     {
4192         return(TNG_CRITICAL);
4193     }
4194
4195     name_len = (int)strlen("TRAJECTORY FRAME SET");
4196
4197     if(!block->name || strlen(block->name) < name_len)
4198     {
4199         temp_name = realloc(block->name, name_len + 1);
4200         if(!temp_name)
4201         {
4202             fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
4203                    name_len+1, __FILE__, __LINE__);
4204             free(block->name);
4205             block->name = 0;
4206             return(TNG_CRITICAL);
4207         }
4208         block->name = temp_name;
4209     }
4210     strcpy(block->name, "TRAJECTORY FRAME SET");
4211     block->id = TNG_TRAJECTORY_FRAME_SET;
4212
4213     if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
4214         TNG_SUCCESS)
4215     {
4216         fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
4217                 __FILE__, __LINE__);
4218         return(TNG_CRITICAL);
4219     }
4220
4221     if(block->block_contents)
4222     {
4223         free(block->block_contents);
4224     }
4225     block->block_contents = malloc(block->block_contents_size);
4226     if(!block->block_contents)
4227     {
4228         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4229                block->block_contents_size, __FILE__, __LINE__);
4230         return(TNG_CRITICAL);
4231     }
4232
4233     memcpy(block->block_contents, &frame_set->first_frame,
4234            sizeof(frame_set->first_frame));
4235     if(tng_data->output_endianness_swap_func_64)
4236     {
4237         if(tng_data->output_endianness_swap_func_64(tng_data,
4238                                       (int64_t *)block->header_contents+offset)
4239             != TNG_SUCCESS)
4240         {
4241             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4242                     __FILE__, __LINE__);
4243         }
4244     }
4245     offset += sizeof(frame_set->first_frame);
4246
4247     memcpy(block->block_contents+offset, &frame_set->n_frames,
4248            sizeof(frame_set->n_frames));
4249     if(tng_data->output_endianness_swap_func_64)
4250     {
4251         if(tng_data->output_endianness_swap_func_64(tng_data,
4252                                       (int64_t *)block->header_contents+offset)
4253             != TNG_SUCCESS)
4254         {
4255             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4256                     __FILE__, __LINE__);
4257         }
4258     }
4259     offset += sizeof(frame_set->n_frames);
4260
4261     if(tng_data->var_num_atoms_flag)
4262     {
4263         for(i = 0; i < tng_data->n_molecules; i++)
4264         {
4265             memcpy(block->block_contents+offset,
4266                    &frame_set->molecule_cnt_list[i],
4267                    sizeof(int64_t));
4268             if(tng_data->output_endianness_swap_func_64)
4269             {
4270                 if(tng_data->output_endianness_swap_func_64(tng_data,
4271                                             (int64_t *)block->header_contents+offset)
4272                     != TNG_SUCCESS)
4273                 {
4274                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4275                             __FILE__, __LINE__);
4276                 }
4277             }
4278             offset += sizeof(int64_t);
4279         }
4280     }
4281
4282
4283     memcpy(block->block_contents+offset, &frame_set->next_frame_set_file_pos,
4284            sizeof(frame_set->next_frame_set_file_pos));
4285     if(tng_data->output_endianness_swap_func_64)
4286     {
4287         if(tng_data->output_endianness_swap_func_64(tng_data,
4288                                       (int64_t *)block->header_contents+offset)
4289             != TNG_SUCCESS)
4290         {
4291             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4292                     __FILE__, __LINE__);
4293         }
4294     }
4295     offset += sizeof(frame_set->next_frame_set_file_pos);
4296
4297     memcpy(block->block_contents+offset, &frame_set->prev_frame_set_file_pos,
4298            sizeof(frame_set->prev_frame_set_file_pos));
4299     if(tng_data->output_endianness_swap_func_64)
4300     {
4301         if(tng_data->output_endianness_swap_func_64(tng_data,
4302                                       (int64_t *)block->header_contents+offset)
4303             != TNG_SUCCESS)
4304         {
4305             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4306                     __FILE__, __LINE__);
4307         }
4308     }
4309     offset += sizeof(frame_set->prev_frame_set_file_pos);
4310
4311     memcpy(block->block_contents+offset,
4312            &frame_set->medium_stride_next_frame_set_file_pos,
4313            sizeof(frame_set->medium_stride_next_frame_set_file_pos));
4314     if(tng_data->output_endianness_swap_func_64)
4315     {
4316         if(tng_data->output_endianness_swap_func_64(tng_data,
4317                                       (int64_t *)block->header_contents+offset)
4318             != TNG_SUCCESS)
4319         {
4320             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4321                     __FILE__, __LINE__);
4322         }
4323     }
4324     offset += sizeof(frame_set->medium_stride_next_frame_set_file_pos);
4325
4326     memcpy(block->block_contents+offset,
4327            &frame_set->medium_stride_prev_frame_set_file_pos,
4328            sizeof(frame_set->medium_stride_prev_frame_set_file_pos));
4329     if(tng_data->output_endianness_swap_func_64)
4330     {
4331         if(tng_data->output_endianness_swap_func_64(tng_data,
4332                                       (int64_t *)block->header_contents+offset)
4333             != TNG_SUCCESS)
4334         {
4335             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4336                     __FILE__, __LINE__);
4337         }
4338     }
4339     offset += sizeof(frame_set->medium_stride_prev_frame_set_file_pos);
4340
4341     memcpy(block->block_contents+offset,
4342            &frame_set->long_stride_next_frame_set_file_pos,
4343            sizeof(frame_set->long_stride_next_frame_set_file_pos));
4344     if(tng_data->output_endianness_swap_func_64)
4345     {
4346         if(tng_data->output_endianness_swap_func_64(tng_data,
4347                                       (int64_t *)block->header_contents+offset)
4348             != TNG_SUCCESS)
4349         {
4350             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4351                     __FILE__, __LINE__);
4352         }
4353     }
4354     offset += sizeof(frame_set->long_stride_next_frame_set_file_pos);
4355
4356     memcpy(block->block_contents+offset,
4357            &frame_set->long_stride_prev_frame_set_file_pos,
4358            sizeof(frame_set->long_stride_prev_frame_set_file_pos));
4359     if(tng_data->output_endianness_swap_func_64)
4360     {
4361         if(tng_data->output_endianness_swap_func_64(tng_data,
4362                                       (int64_t *)block->header_contents+offset)
4363             != TNG_SUCCESS)
4364         {
4365             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4366                     __FILE__, __LINE__);
4367         }
4368     }
4369     offset += sizeof(frame_set->long_stride_prev_frame_set_file_pos);
4370
4371     memcpy(block->block_contents+offset,
4372            &frame_set->first_frame_time,
4373            sizeof(frame_set->first_frame_time));
4374     if(tng_data->output_endianness_swap_func_64)
4375     {
4376         if(tng_data->output_endianness_swap_func_64(tng_data,
4377                                       (int64_t *)block->header_contents+offset)
4378             != TNG_SUCCESS)
4379         {
4380             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4381                     __FILE__, __LINE__);
4382         }
4383     }
4384     offset += sizeof(frame_set->first_frame_time);
4385
4386     memcpy(block->block_contents+offset,
4387            &tng_data->time_per_frame,
4388            sizeof(tng_data->time_per_frame));
4389     if(tng_data->output_endianness_swap_func_64)
4390     {
4391         if(tng_data->output_endianness_swap_func_64(tng_data,
4392                                       (int64_t *)block->header_contents+offset)
4393             != TNG_SUCCESS)
4394         {
4395             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4396                     __FILE__, __LINE__);
4397         }
4398     }
4399
4400     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4401     {
4402         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4403                tng_data->output_file_path, __FILE__, __LINE__);
4404         return(TNG_CRITICAL);
4405     }
4406
4407     if(fwrite(block->block_contents, block->block_contents_size, 1,
4408               tng_data->output_file) != 1)
4409     {
4410         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4411         return(TNG_CRITICAL);
4412     }
4413
4414     return(TNG_SUCCESS);
4415 }
4416
4417 static tng_function_status tng_trajectory_mapping_block_len_calculate
4418                 (const tng_trajectory_t tng_data,
4419                  const int64_t n_particles,
4420                  int64_t *len)
4421 {
4422     (void)tng_data;
4423     *len = sizeof(int64_t) * (2 + n_particles);
4424
4425     return(TNG_SUCCESS);
4426 }
4427
4428 /** Read an atom mappings block (translating between real atom indexes and how
4429  *  the atom info is written in this frame set).
4430  * @param tng_data is a trajectory data container.
4431  * @param block is a general block container.
4432  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4433  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
4434  * compared to the md5 hash of the read contents to ensure valid data.
4435  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4436  * error has occured.
4437  */
4438 static tng_function_status tng_trajectory_mapping_block_read
4439                 (tng_trajectory_t tng_data,
4440                  tng_gen_block_t block,
4441                  const char hash_mode)
4442 {
4443     int64_t i;
4444     int offset = 0;
4445     tng_bool same_hash;
4446     tng_trajectory_frame_set_t frame_set =
4447     &tng_data->current_trajectory_frame_set;
4448
4449     tng_particle_mapping_t mapping, mappings;
4450
4451     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
4452     {
4453         return(TNG_CRITICAL);
4454     }
4455
4456     if(block->block_contents)
4457     {
4458         free(block->block_contents);
4459     }
4460
4461     block->block_contents = malloc(block->block_contents_size);
4462     if(!block->block_contents)
4463     {
4464         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4465                block->block_contents_size, __FILE__, __LINE__);
4466         return(TNG_CRITICAL);
4467     }
4468
4469     /* Read the whole block into block_contents to be able to write it to disk
4470      *  even if it cannot be interpreted. */
4471     if(fread(block->block_contents, block->block_contents_size, 1,
4472         tng_data->input_file) == 0)
4473     {
4474         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
4475         return(TNG_CRITICAL);
4476     }
4477
4478     /* FIXME: Does not check if the size of the contents matches the expected
4479      * size or if the contents can be read. */
4480
4481     if(hash_mode == TNG_USE_HASH)
4482     {
4483         tng_md5_hash_match_verify(block, &same_hash);
4484         if(same_hash != TNG_TRUE)
4485         {
4486             fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4487                 "%s: %d\n",
4488                 __FILE__, __LINE__);
4489     /*         return(TNG_FAILURE); */
4490         }
4491     }
4492
4493     frame_set->n_mapping_blocks++;
4494     mappings = realloc(frame_set->mappings,
4495                        sizeof(struct tng_particle_mapping) *
4496                        frame_set->n_mapping_blocks);
4497     if(!mappings)
4498     {
4499         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4500                block->block_contents_size, __FILE__, __LINE__);
4501         free(frame_set->mappings);
4502         frame_set->mappings = 0;
4503         return(TNG_CRITICAL);
4504     }
4505     frame_set->mappings = mappings;
4506     mapping = &mappings[frame_set->n_mapping_blocks - 1];
4507
4508
4509     memcpy(&mapping->num_first_particle, block->block_contents+offset,
4510            sizeof(mapping->num_first_particle));
4511     if(tng_data->input_endianness_swap_func_64)
4512     {
4513         if(tng_data->input_endianness_swap_func_64(tng_data,
4514                                                    &mapping->num_first_particle)
4515             != TNG_SUCCESS)
4516         {
4517             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4518                     __FILE__, __LINE__);
4519         }
4520     }
4521     offset += sizeof(mapping->num_first_particle);
4522
4523     memcpy(&mapping->n_particles, block->block_contents+offset,
4524            sizeof(mapping->n_particles));
4525     if(tng_data->input_endianness_swap_func_64)
4526     {
4527         if(tng_data->input_endianness_swap_func_64(tng_data,
4528                                                    &mapping->n_particles)
4529             != TNG_SUCCESS)
4530         {
4531             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4532                     __FILE__, __LINE__);
4533         }
4534     }
4535     offset += sizeof(mapping->n_particles);
4536
4537     mapping->real_particle_numbers = malloc(mapping->n_particles *
4538                                             sizeof(int64_t));
4539     if(!mapping->real_particle_numbers)
4540     {
4541         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
4542                 mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
4543         return(TNG_CRITICAL);
4544     }
4545
4546     /* If the byte order needs to be swapped the data must be read one value at
4547      * a time and swapped */
4548     if(tng_data->input_endianness_swap_func_64)
4549     {
4550         for(i = 0; i < mapping->n_particles; i++)
4551         {
4552             memcpy(&mapping->real_particle_numbers[i],
4553                     block->block_contents + offset,
4554                     sizeof(int64_t));
4555             if(tng_data->input_endianness_swap_func_64(tng_data,
4556                                             &mapping->real_particle_numbers[i])
4557                 != TNG_SUCCESS)
4558             {
4559                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4560                         __FILE__, __LINE__);
4561             }
4562             offset += sizeof(int64_t);
4563         }
4564     }
4565     /* Otherwise the data can be read all at once */
4566     else
4567     {
4568         memcpy(mapping->real_particle_numbers, block->block_contents + offset,
4569                mapping->n_particles * sizeof(int64_t));
4570     }
4571
4572
4573     return(TNG_SUCCESS);
4574 }
4575
4576 /** Write the atom mappings of the current trajectory frame set
4577  * @param tng_data is a trajectory data container.
4578  * @param block is a general block container.
4579  * @param mapping_block_nr is the index of the mapping block to write.
4580  * @param hash_mode is an option to decide whether to use the md5 hash or not.
4581  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4582  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4583  * has occurred or TNG_CRITICAL (2) if a major error has occured.
4584  */
4585 static tng_function_status tng_trajectory_mapping_block_write
4586                 (tng_trajectory_t tng_data,
4587                  tng_gen_block_t block,
4588                  int mapping_block_nr,
4589                  const char hash_mode)
4590 {
4591     char *temp_name;
4592     int i, offset = 0;
4593     unsigned int name_len;
4594     tng_particle_mapping_t mapping =
4595     &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4596
4597     if(mapping_block_nr >=
4598        tng_data->current_trajectory_frame_set.n_mapping_blocks)
4599     {
4600         fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4601                __FILE__, __LINE__);
4602         return(TNG_FAILURE);
4603     }
4604
4605     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4606     {
4607         return(TNG_CRITICAL);
4608     }
4609
4610     name_len = (int)strlen("PARTICLE MAPPING");
4611
4612     if(!block->name || strlen(block->name) < name_len)
4613     {
4614         temp_name = realloc(block->name, name_len + 1);
4615         if(!temp_name)
4616         {
4617             fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
4618                    name_len+1, __FILE__, __LINE__);
4619             free(block->name);
4620             block->name = 0;
4621             return(TNG_CRITICAL);
4622         }
4623         block->name = temp_name;
4624     }
4625     strcpy(block->name, "PARTICLE MAPPING");
4626     block->id = TNG_PARTICLE_MAPPING;
4627
4628     if(tng_trajectory_mapping_block_len_calculate(tng_data,
4629                                                   mapping->n_particles,
4630                                                   &block->block_contents_size) !=
4631         TNG_SUCCESS)
4632     {
4633         fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4634                 __FILE__, __LINE__);
4635         return(TNG_CRITICAL);
4636     }
4637
4638     if(block->block_contents)
4639     {
4640         free(block->block_contents);
4641     }
4642     block->block_contents = malloc(block->block_contents_size);
4643     if(!block->block_contents)
4644     {
4645         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4646                block->block_contents_size, __FILE__, __LINE__);
4647         return(TNG_CRITICAL);
4648     }
4649
4650     memcpy(block->block_contents, &mapping->num_first_particle,
4651            sizeof(mapping->num_first_particle));
4652     if(tng_data->output_endianness_swap_func_64)
4653     {
4654         if(tng_data->output_endianness_swap_func_64(tng_data,
4655                                       (int64_t *)block->header_contents+offset)
4656             != TNG_SUCCESS)
4657         {
4658             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4659                     __FILE__, __LINE__);
4660         }
4661     }
4662     offset += sizeof(mapping->num_first_particle);
4663
4664     memcpy(block->block_contents+offset, &mapping->n_particles,
4665            sizeof(mapping->n_particles));
4666     if(tng_data->output_endianness_swap_func_64)
4667     {
4668         if(tng_data->output_endianness_swap_func_64(tng_data,
4669                                       (int64_t *)block->header_contents+offset)
4670             != TNG_SUCCESS)
4671         {
4672             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4673                     __FILE__, __LINE__);
4674         }
4675     }
4676     offset += sizeof(mapping->n_particles);
4677
4678     if(tng_data->output_endianness_swap_func_64)
4679     {
4680         for(i = 0; i < mapping->n_particles; i++)
4681         {
4682             memcpy(block->block_contents+offset, &mapping->real_particle_numbers[i],
4683                 sizeof(int64_t));
4684             if(tng_data->output_endianness_swap_func_64(tng_data,
4685                                         (int64_t *)block->header_contents+offset)
4686                 != TNG_SUCCESS)
4687             {
4688                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
4689                         __FILE__, __LINE__);
4690             }
4691             offset += sizeof(int64_t);
4692         }
4693     }
4694     else
4695     {
4696         memcpy(block->block_contents+offset, mapping->real_particle_numbers,
4697                mapping->n_particles * sizeof(int64_t));
4698     }
4699
4700
4701     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
4702     {
4703         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4704                tng_data->output_file_path, __FILE__, __LINE__);
4705         return(TNG_CRITICAL);
4706     }
4707
4708     if(fwrite(block->block_contents, block->block_contents_size, 1,
4709               tng_data->output_file) != 1)
4710     {
4711         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, __LINE__);
4712         return(TNG_CRITICAL);
4713     }
4714
4715     return(TNG_SUCCESS);
4716 }
4717
4718 /** Prepare a block for storing particle data
4719  * @param tng_data is a trajectory data container.
4720  * @param block_type_flag specifies if this is a trajectory block or a
4721  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4722  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4723  * error has occured.
4724  */
4725 static tng_function_status tng_particle_data_block_create
4726                 (tng_trajectory_t tng_data,
4727                  const char block_type_flag)
4728 {
4729     tng_trajectory_frame_set_t frame_set =
4730     &tng_data->current_trajectory_frame_set;
4731
4732     tng_particle_data_t data;
4733
4734     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4735     {
4736         frame_set->n_particle_data_blocks++;
4737         data = realloc(frame_set->tr_particle_data,
4738                     sizeof(struct tng_particle_data) *
4739                     frame_set->n_particle_data_blocks);
4740         if(!data)
4741         {
4742             fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
4743                 sizeof(struct tng_particle_data) *
4744                 frame_set->n_particle_data_blocks,
4745                 __FILE__, __LINE__);
4746             free(frame_set->tr_particle_data);
4747             frame_set->tr_particle_data = 0;
4748             return(TNG_CRITICAL);
4749         }
4750         frame_set->tr_particle_data = data;
4751     }
4752     else
4753     {
4754         tng_data->n_particle_data_blocks++;
4755         data = realloc(tng_data->non_tr_particle_data,
4756                         sizeof(struct tng_particle_data) *
4757                         tng_data->n_particle_data_blocks);
4758         if(!data)
4759         {
4760             fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
4761                     sizeof(struct tng_particle_data) *
4762                     tng_data->n_particle_data_blocks,
4763                     __FILE__, __LINE__);
4764             free(tng_data->non_tr_particle_data);
4765             tng_data->non_tr_particle_data = 0;
4766             return(TNG_CRITICAL);
4767         }
4768         tng_data->non_tr_particle_data = data;
4769     }
4770
4771     return(TNG_SUCCESS);
4772 }
4773
4774 static tng_function_status tng_compress(tng_trajectory_t tng_data,
4775                                         tng_gen_block_t block,
4776                                         const int64_t n_frames,
4777                                         const int64_t n_particles,
4778                                         const char type,
4779                                         void *start_pos)
4780 {
4781     int nalgo;
4782     int new_len;
4783     int *alt_algo = 0;
4784     char *dest, *temp, *temp_data_contents;
4785     int64_t algo_find_n_frames, compressed_len, offset;
4786     float f_precision;
4787     double d_precision;
4788
4789     if(block->id != TNG_TRAJ_POSITIONS &&
4790        block->id != TNG_TRAJ_VELOCITIES)
4791     {
4792         fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4793                "TNG method. %s: %d\n", __FILE__, __LINE__);
4794         return(TNG_FAILURE);
4795     }
4796     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4797     {
4798         fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4799         return(TNG_FAILURE);
4800     }
4801
4802     if(n_frames <= 0 || n_particles <= 0)
4803     {
4804         fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4805                "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4806         return(TNG_FAILURE);
4807     }
4808
4809     f_precision = 1/(float)tng_data->compression_precision;
4810     d_precision = 1/tng_data->compression_precision;
4811
4812     compressed_len = block->block_contents_size - (int64_t)((char *)start_pos - (char *)block->block_contents);
4813     temp_data_contents = malloc(compressed_len);
4814     if(!temp_data_contents)
4815     {
4816         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
4817                 compressed_len, __FILE__, __LINE__);
4818         return(TNG_CRITICAL);
4819     }
4820
4821     memcpy(temp_data_contents, (char *)start_pos, compressed_len);
4822
4823     if(block->id == TNG_TRAJ_POSITIONS)
4824     {
4825         /* If there is only one frame in this frame set and there might be more
4826          * do not store the algorithm as the compression algorithm, but find
4827          * the best one without storing it */
4828         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4829         {
4830             nalgo = tng_compress_nalgo();
4831             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4832             if(type == TNG_FLOAT_DATA)
4833             {
4834                 dest = tng_compress_pos_float_find_algo((float *)temp_data_contents, (int)n_particles,
4835                                                         (int)n_frames,
4836                                                         f_precision,
4837                                                         0, alt_algo,
4838                                                         &new_len);
4839
4840             }
4841             else
4842             {
4843                 dest = tng_compress_pos_find_algo((double *)temp_data_contents, (int)n_particles,
4844                                            (int)n_frames,
4845                                            d_precision,
4846                                            0, alt_algo,
4847                                            &new_len);
4848             }
4849         }
4850         else if(!tng_data->compress_algo_pos)
4851         {
4852             if(n_frames > 10)
4853             {
4854                 algo_find_n_frames = 5;
4855             }
4856             else
4857             {
4858                 algo_find_n_frames = n_frames;
4859             }
4860
4861             nalgo = tng_compress_nalgo();
4862             tng_data->compress_algo_pos=malloc(nalgo *
4863                                            sizeof *tng_data->compress_algo_pos);
4864             if(type == TNG_FLOAT_DATA)
4865             {
4866                 dest = tng_compress_pos_float_find_algo((float *)temp_data_contents, (int)n_particles,
4867                                                         (int)algo_find_n_frames,
4868                                                         f_precision,
4869                                                         0, tng_data->
4870                                                         compress_algo_pos,
4871                                                         &new_len);
4872
4873                 if(algo_find_n_frames < n_frames)
4874                 {
4875                     dest = tng_compress_pos_float((float *)temp_data_contents, (int)n_particles,
4876                                                   (int)n_frames,
4877                                                   f_precision,
4878                                                   0, tng_data->compress_algo_pos,
4879                                                   &new_len);
4880                 }
4881             }
4882             else
4883             {
4884                 dest = tng_compress_pos_find_algo((double *)temp_data_contents, (int)n_particles,
4885                                            (int)algo_find_n_frames,
4886                                            d_precision,
4887                                            0, tng_data->
4888                                            compress_algo_pos,
4889                                            &new_len);
4890
4891                 if(algo_find_n_frames < n_frames)
4892                 {
4893                     dest = tng_compress_pos((double *)temp_data_contents, (int)n_particles,
4894                                             (int)n_frames,
4895                                             d_precision, 0,
4896                                             tng_data->compress_algo_pos,
4897                                             &new_len);
4898                 }
4899             }
4900         }
4901         else
4902         {
4903             if(type == TNG_FLOAT_DATA)
4904             {
4905                 dest = tng_compress_pos_float((float *)temp_data_contents, (int)n_particles,
4906                                               (int)n_frames,
4907                                               f_precision, 0,
4908                                               tng_data->compress_algo_pos, &new_len);
4909             }
4910             else
4911             {
4912                 dest = tng_compress_pos((double *)temp_data_contents, (int)n_particles,
4913                                         (int)n_frames,
4914                                         d_precision, 0,
4915                                         tng_data->compress_algo_pos,
4916                                         &new_len);
4917             }
4918         }
4919     }
4920     else if(block->id == TNG_TRAJ_VELOCITIES)
4921     {
4922         /* If there is only one frame in this frame set and there might be more
4923          * do not store the algorithm as the compression algorithm, but find
4924          * the best one without storing it */
4925         if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4926         {
4927             nalgo = tng_compress_nalgo();
4928             alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_vel);
4929             if(type == TNG_FLOAT_DATA)
4930             {
4931                 dest = tng_compress_vel_float_find_algo((float *)temp_data_contents, (int)n_particles,
4932                                                         (int)n_frames,
4933                                                         f_precision,
4934                                                         0, alt_algo,
4935                                                         &new_len);
4936
4937             }
4938             else
4939             {
4940                 dest = tng_compress_vel_find_algo((double *)temp_data_contents, (int)n_particles,
4941                                                   (int)n_frames,
4942                                                   d_precision,
4943                                                   0, alt_algo,
4944                                                   &new_len);
4945             }
4946         }
4947         else if(!tng_data->compress_algo_vel)
4948         {
4949             if(n_frames > 10)
4950             {
4951                 algo_find_n_frames = 5;
4952             }
4953             else
4954             {
4955                 algo_find_n_frames = n_frames;
4956             }
4957
4958             nalgo = tng_compress_nalgo();
4959             tng_data->compress_algo_vel=malloc(nalgo *
4960                                            sizeof *tng_data->compress_algo_vel);
4961
4962             if(type == TNG_FLOAT_DATA)
4963             {
4964                 dest = tng_compress_vel_float_find_algo((float *)temp_data_contents, (int)n_particles,
4965                                                         (int)algo_find_n_frames,
4966                                                         f_precision,
4967                                                         0, tng_data->
4968                                                         compress_algo_vel,
4969                                                         &new_len);
4970                 if(algo_find_n_frames < n_frames)
4971                 {
4972                     dest = tng_compress_vel_float((float *)temp_data_contents, (int)n_particles,
4973                                                   (int)n_frames,
4974                                                   f_precision,
4975                                                   0, tng_data->compress_algo_vel,
4976                                                   &new_len);
4977                 }
4978             }
4979             else
4980             {
4981                 dest = tng_compress_vel_find_algo((double *)temp_data_contents, (int)n_particles,
4982                                                   (int)algo_find_n_frames,
4983                                                   d_precision,
4984                                                   0, tng_data->
4985                                                   compress_algo_vel,
4986                                                   &new_len);
4987                 if(algo_find_n_frames < n_frames)
4988                 {
4989                     dest = tng_compress_vel((double *)temp_data_contents, (int)n_particles,
4990                                             (int)n_frames,
4991                                             d_precision,
4992                                             0, tng_data->compress_algo_vel,
4993                                             &new_len);
4994                 }
4995             }
4996         }
4997         else
4998         {
4999             if(type == TNG_FLOAT_DATA)
5000             {
5001                 dest = tng_compress_vel_float((float *)temp_data_contents, (int)n_particles,
5002                                               (int)n_frames,
5003                                               f_precision,
5004                                               0, tng_data->
5005                                               compress_algo_vel,
5006                                               &new_len);
5007             }
5008             else
5009             {
5010                 dest = tng_compress_vel((double *)temp_data_contents, (int)n_particles,
5011                                         (int)n_frames,
5012                                         d_precision,
5013                                         0, tng_data->
5014                                         compress_algo_vel,
5015                                         &new_len);
5016             }
5017         }
5018     }
5019     else
5020     {
5021         fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
5022         free(temp_data_contents);
5023         return(TNG_FAILURE);
5024     }
5025
5026     offset = (unsigned long)((char *)start_pos - block->block_contents);
5027
5028     if(alt_algo)
5029     {
5030         free(alt_algo);
5031     }
5032
5033     block->block_contents_size = new_len + offset;
5034
5035     free(temp_data_contents);
5036
5037     temp = realloc(block->block_contents, block->block_contents_size);
5038     if(!temp)
5039     {
5040         free(block->block_contents);
5041         block->block_contents = 0;
5042         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5043                block->block_contents_size, __FILE__, __LINE__);
5044         return(TNG_CRITICAL);
5045     }
5046     block->block_contents = temp;
5047     if(dest)
5048     {
5049         memcpy(temp + offset, dest, new_len);
5050         free(dest);
5051     }
5052     else
5053     {
5054         fprintf(stderr, "TNG library: Error during TNG compression. %s: %d\n", __FILE__, __LINE__);
5055         return(TNG_FAILURE);
5056     }
5057
5058     return(TNG_SUCCESS);
5059 }
5060
5061 static tng_function_status tng_uncompress(tng_trajectory_t tng_data,
5062                                           tng_gen_block_t block,
5063                                           const char type,
5064                                           void *start_pos,
5065                                           const int64_t uncompressed_len)
5066 {
5067     char *temp, *temp_data_contents;
5068     int64_t compressed_len;
5069     double *d_dest = 0;
5070     float *f_dest = 0;
5071     int64_t offset;
5072     int result;
5073     (void)tng_data;
5074
5075     TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
5076
5077     if(block->id != TNG_TRAJ_POSITIONS &&
5078        block->id != TNG_TRAJ_VELOCITIES)
5079     {
5080         fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
5081                "TNG method.\n");
5082         return(TNG_FAILURE);
5083     }
5084     if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
5085     {
5086         fprintf(stderr, "TNG library: Data type not supported.\n");
5087         return(TNG_FAILURE);
5088     }
5089
5090     compressed_len = block->block_contents_size - (int64_t)((char *)start_pos - (char *)block->block_contents);
5091     temp_data_contents = malloc(compressed_len);
5092     if(!temp_data_contents)
5093     {
5094         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5095                 uncompressed_len, __FILE__, __LINE__);
5096         return(TNG_CRITICAL);
5097     }
5098
5099     memcpy(temp_data_contents, (char *)start_pos, compressed_len);
5100
5101     if(type == TNG_FLOAT_DATA)
5102     {
5103         f_dest = malloc(uncompressed_len);
5104         if(!f_dest)
5105         {
5106             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5107                 uncompressed_len, __FILE__, __LINE__);
5108             free(temp_data_contents);
5109             return(TNG_CRITICAL);
5110         }
5111         result = tng_compress_uncompress_float(temp_data_contents, f_dest);
5112     }
5113     else
5114     {
5115         d_dest = malloc(uncompressed_len);
5116         if(!d_dest)
5117         {
5118             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5119                 uncompressed_len, __FILE__, __LINE__);
5120             free(temp_data_contents);
5121             return(TNG_CRITICAL);
5122         }
5123         result = tng_compress_uncompress(temp_data_contents, d_dest);
5124     }
5125
5126     if(result == 1)
5127     {
5128         fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
5129         free(temp_data_contents);
5130         return(TNG_FAILURE);
5131     }
5132
5133     offset = (unsigned long)((char *)start_pos - (char *)block->block_contents);
5134
5135     block->block_contents_size = (int64_t)(uncompressed_len + offset);
5136
5137     temp = realloc(block->block_contents, uncompressed_len + offset);
5138     if(!temp)
5139     {
5140         free(block->block_contents);
5141         block->block_contents = 0;
5142         if(d_dest)
5143         {
5144             free(d_dest);
5145         }
5146         if(f_dest)
5147         {
5148             free(f_dest);
5149         }
5150         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5151                block->block_contents_size, __FILE__, __LINE__);
5152         free(temp_data_contents);
5153         return(TNG_CRITICAL);
5154     }
5155
5156     if(type == TNG_FLOAT_DATA)
5157     {
5158         memcpy(temp + offset, f_dest, uncompressed_len);
5159     }
5160     else
5161     {
5162         memcpy(temp + offset, d_dest, uncompressed_len);
5163     }
5164
5165     block->block_contents = temp;
5166
5167     free(temp_data_contents);
5168     if(d_dest)
5169     {
5170         free(d_dest);
5171     }
5172     if(f_dest)
5173     {
5174         free(f_dest);
5175     }
5176     return(TNG_SUCCESS);
5177 }
5178
5179 #ifdef USE_ZLIB
5180 static tng_function_status tng_gzip_compress(tng_trajectory_t tng_data,
5181                                              tng_gen_block_t block,
5182                                              void *start_pos, const int len)
5183 {
5184     Bytef *dest;
5185     char *temp;
5186     unsigned long max_len, stat, offset;
5187     (void)tng_data;
5188
5189     max_len = compressBound(len);
5190     dest = malloc(max_len);
5191     if(!dest)
5192     {
5193         fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
5194                max_len, __FILE__, __LINE__);
5195         return(TNG_CRITICAL);
5196     }
5197
5198     stat = compress(dest, &max_len, start_pos, len);
5199     if(stat != (unsigned long)Z_OK)
5200     {
5201         free(dest);
5202         if(stat == (unsigned long)Z_MEM_ERROR)
5203         {
5204             fprintf(stderr, "TNG library: Not enough memory. ");
5205         }
5206         else if(stat == (unsigned long)Z_BUF_ERROR)
5207         {
5208             fprintf(stderr, "TNG library: Destination buffer too small. ");
5209         }
5210         fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
5211         return(TNG_FAILURE);
5212     }
5213
5214     offset = (char *)start_pos - block->block_contents;
5215
5216     block->block_contents_size = max_len + offset;
5217
5218     temp = realloc(block->block_contents, block->block_contents_size);
5219     if(!temp)
5220     {
5221         free(block->block_contents);
5222         free(dest);
5223         block->block_contents = 0;
5224         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5225                block->block_contents_size, __FILE__, __LINE__);
5226         return(TNG_CRITICAL);
5227     }
5228
5229     block->block_contents = temp;
5230
5231     memcpy(temp + offset, dest, max_len);
5232
5233     free(dest);
5234
5235     return(TNG_SUCCESS);
5236 }
5237
5238 static tng_function_status tng_gzip_uncompress(tng_trajectory_t tng_data,
5239                                                tng_gen_block_t block,
5240                                                void *start_pos,
5241                                                unsigned long uncompressed_len)
5242 {
5243     Bytef *dest;
5244     char *temp;
5245     unsigned long stat;
5246     int offset;
5247     (void)tng_data;
5248
5249     offset = (char *)start_pos - (char *)block->block_contents;
5250
5251     dest = malloc(uncompressed_len);
5252     if(!dest)
5253     {
5254         fprintf(stderr, "TNG library: Cannot allocate memory (%lud bytes). %s: %d\n",
5255                uncompressed_len, __FILE__, __LINE__);
5256         return(TNG_CRITICAL);
5257     }
5258
5259     stat = uncompress(dest, &uncompressed_len, (Bytef *) start_pos,
5260                       block->block_contents_size - offset);
5261
5262     if(stat != Z_OK)
5263     {
5264         free(dest);
5265         if(stat == (unsigned long)Z_MEM_ERROR)
5266         {
5267             fprintf(stderr, "TNG library: Not enough memory. ");
5268         }
5269         else if(stat == (unsigned long)Z_BUF_ERROR)
5270         {
5271             fprintf(stderr, "TNG library: Destination buffer too small. ");
5272         }
5273         else if(stat == (unsigned long)Z_DATA_ERROR)
5274         {
5275             fprintf(stderr, "TNG library: Data corrupt. ");
5276         }
5277         fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
5278                __LINE__);
5279         return(TNG_FAILURE);
5280     }
5281
5282
5283     block->block_contents_size = uncompressed_len + offset;
5284
5285     temp = realloc(block->block_contents, uncompressed_len + offset);
5286     if(!temp)
5287     {
5288         free(block->block_contents);
5289         block->block_contents = 0;
5290         free(dest);
5291         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5292                block->block_contents_size, __FILE__, __LINE__);
5293         return(TNG_CRITICAL);
5294     }
5295
5296     memcpy(temp + offset, dest, uncompressed_len);
5297
5298     block->block_contents = temp;
5299
5300     free(dest);
5301     return(TNG_SUCCESS);
5302 }
5303 #endif
5304
5305 /** Allocate memory for storing particle data.
5306  * The allocated block will be refered to by data->values.
5307  * @param tng_data is a trajectory data container.
5308  * @param data is the data struct, which will contain the allocated memory in
5309  * data->values.
5310  * @param n_frames is the number of frames of data to store.
5311  * @param n_particles is the number of particles with data.
5312  * @param n_values_per_frame is the number of data values per particle and
5313  * frame.
5314  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5315  * error has occured.
5316  */
5317 static tng_function_status tng_allocate_particle_data_mem
5318                 (tng_trajectory_t tng_data,
5319                  tng_particle_data_t data,
5320                  int64_t n_frames,
5321                  int64_t stride_length,
5322                  const int64_t n_particles,
5323                  const int64_t n_values_per_frame)
5324 {
5325     void ***values;
5326     int64_t i, j, k, size, frame_alloc;
5327     (void)tng_data;
5328
5329     if(n_particles == 0 || n_values_per_frame == 0)
5330     {
5331         return(TNG_FAILURE);
5332     }
5333
5334     if(data->strings && data->datatype == TNG_CHAR_DATA)
5335     {
5336         for(i = 0; i < data->n_frames; i++)
5337         {
5338             for(j = 0; j < n_particles; j++)
5339             {
5340                 for(k = 0; k < data->n_values_per_frame; k++)
5341                 {
5342                     if(data->strings[i][j][k])
5343                     {
5344                         free(data->strings[i][j][k]);
5345                     }
5346                 }
5347                 free(data->strings[i][j]);
5348             }
5349             free(data->strings[i]);
5350         }
5351         free(data->strings);
5352     }
5353     data->n_frames = n_frames;
5354     n_frames = tng_max_i64(1, n_frames);
5355     data->stride_length = tng_max_i64(1, stride_length);
5356     data->n_values_per_frame = n_values_per_frame;
5357     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5358
5359     if(data->datatype == TNG_CHAR_DATA)
5360     {
5361         data->strings = malloc(sizeof(char ***) * frame_alloc);
5362         for(i = 0; i < frame_alloc; i++)
5363         {
5364             data->strings[i] = malloc(sizeof(char **) *
5365                                     n_particles);
5366             if(!data->strings[i])
5367             {
5368                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
5369                     sizeof(union data_values *) * n_particles,
5370                     __FILE__, __LINE__);
5371                 return(TNG_CRITICAL);
5372             }
5373             for(j = 0; j < n_particles; j++)
5374             {
5375                 data->strings[i][j] = malloc(sizeof(char *) *
5376                                             n_values_per_frame);
5377                 if(!data->strings[i][j])
5378                 {
5379                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
5380                         sizeof(union data_values) * n_values_per_frame,
5381                         __FILE__, __LINE__);
5382                     return(TNG_CRITICAL);
5383                 }
5384                 for(k = 0; k < n_values_per_frame; k++)
5385                 {
5386                     data->strings[i][j][k] = 0;
5387                 }
5388             }
5389         }
5390     }
5391     else
5392     {
5393         switch(data->datatype)
5394         {
5395         case TNG_INT_DATA:
5396             size = sizeof(int64_t);
5397             break;
5398         case TNG_FLOAT_DATA:
5399             size = sizeof(float);
5400             break;
5401         case TNG_DOUBLE_DATA:
5402         default:
5403             size = sizeof(double);
5404         }
5405
5406         values = realloc(data->values,
5407                          size * frame_alloc *
5408                          n_particles * n_values_per_frame);
5409         if(!values)
5410         {
5411             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
5412                    size * frame_alloc *
5413                    n_particles * n_values_per_frame,
5414                    __FILE__, __LINE__);
5415             free(data->values);
5416             data->values = 0;
5417             return(TNG_CRITICAL);
5418         }
5419         data->values = values;
5420     }
5421     return(TNG_SUCCESS);
5422 }
5423
5424 static tng_function_status tng_particle_data_find
5425                 (tng_trajectory_t tng_data,
5426                  const int64_t id,
5427                  tng_particle_data_t *data)
5428 {
5429     int64_t block_index, i;
5430     tng_trajectory_frame_set_t frame_set = &tng_data->
5431                                            current_trajectory_frame_set;
5432     char block_type_flag;
5433
5434     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5435        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5436     {
5437         block_type_flag = TNG_TRAJECTORY_BLOCK;
5438     }
5439     else
5440     {
5441         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5442     }
5443
5444     block_index = -1;
5445     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5446     {
5447         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
5448         {
5449             *data = &frame_set->tr_particle_data[i];
5450             if((*data)->block_id == id)
5451             {
5452                 block_index = i;
5453                 break;
5454             }
5455         }
5456     }
5457     else
5458     {
5459         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
5460         {
5461             *data = &tng_data->non_tr_particle_data[i];
5462             if((*data)->block_id == id)
5463             {
5464                 block_index = i;
5465                 break;
5466             }
5467         }
5468     }
5469     if(block_index == -1)
5470     {
5471         return(TNG_FAILURE);
5472     }
5473     return(TNG_SUCCESS);
5474 }
5475
5476 static tng_function_status tng_data_find
5477                 (tng_trajectory_t tng_data,
5478                  const int64_t id,
5479                  tng_non_particle_data_t *data)
5480 {
5481     int64_t block_index, i;
5482     tng_trajectory_frame_set_t frame_set = &tng_data->
5483                                            current_trajectory_frame_set;
5484     char block_type_flag;
5485
5486     if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
5487        tng_data->current_trajectory_frame_set_output_file_pos > 0)
5488     {
5489         block_type_flag = TNG_TRAJECTORY_BLOCK;
5490     }
5491     else
5492     {
5493         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5494     }
5495
5496     block_index = -1;
5497     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5498     {
5499         for(i = 0; i < frame_set->n_data_blocks; i++)
5500         {
5501             *data = &frame_set->tr_data[i];
5502             if((*data)->block_id == id)
5503             {
5504                 block_index = i;
5505                 break;
5506             }
5507         }
5508         if(block_index == -1)
5509         {
5510             for(i = 0; i < tng_data->n_data_blocks; i++)
5511             {
5512                 *data = &tng_data->non_tr_data[i];
5513                 if((*data)->block_id == id)
5514                 {
5515                     block_index = i;
5516                     break;
5517                 }
5518             }
5519         }
5520     }
5521     else
5522     {
5523         for(i = 0; i < tng_data->n_data_blocks; i++)
5524         {
5525             *data = &tng_data->non_tr_data[i];
5526             if((*data)->block_id == id)
5527             {
5528                 block_index = i;
5529                 break;
5530             }
5531         }
5532     }
5533     if(block_index == -1)
5534     {
5535         return(TNG_FAILURE);
5536     }
5537     return(TNG_SUCCESS);
5538 }
5539
5540 static tng_function_status tng_data_block_len_calculate
5541                 (const tng_trajectory_t tng_data,
5542                  const tng_particle_data_t data,
5543                  const tng_bool is_particle_data,
5544                  const int64_t n_frames,
5545                  const int64_t frame_step,
5546                  const int64_t stride_length,
5547                  const int64_t num_first_particle,
5548                  const int64_t n_particles,
5549                  const char dependency,
5550                  int64_t *data_start_pos,
5551                  int64_t *len)
5552 {
5553     int size;
5554     int64_t i, j, k;
5555     char ***first_dim_values, **second_dim_values;
5556     (void)tng_data;
5557
5558     if(data == 0)
5559     {
5560         return(TNG_SUCCESS);
5561     }
5562
5563     switch(data->datatype)
5564     {
5565     case TNG_CHAR_DATA:
5566         size = 1;
5567         break;
5568     case TNG_INT_DATA:
5569         size = sizeof(int64_t);
5570         break;
5571     case TNG_FLOAT_DATA:
5572         size = sizeof(float);
5573         break;
5574     case TNG_DOUBLE_DATA:
5575     default:
5576         size = sizeof(double);
5577     }
5578
5579     *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
5580            sizeof(data->codec_id);
5581     if(is_particle_data)
5582     {
5583         *len += sizeof(num_first_particle) + sizeof(n_particles);
5584     }
5585
5586     if(stride_length > 1)
5587     {
5588         *len += sizeof(data->first_frame_with_data) +
5589                 sizeof(data->stride_length);
5590     }
5591
5592     if(data->codec_id != TNG_UNCOMPRESSED)
5593     {
5594         *len += sizeof(data->compression_multiplier);
5595     }
5596
5597     if(dependency & TNG_FRAME_DEPENDENT)
5598     {
5599         *len += sizeof(char);
5600     }
5601
5602     *data_start_pos = *len;
5603
5604     if(data->datatype == TNG_CHAR_DATA)
5605     {
5606         if(is_particle_data)
5607         {
5608             for(i = 0; i < n_frames; i++)
5609             {
5610                 first_dim_values = data->strings[i];
5611                 for(j = num_first_particle; j < num_first_particle + n_particles;
5612                     j++)
5613                 {
5614                     second_dim_values = first_dim_values[j];
5615                     for(k = 0; k < data->n_values_per_frame; k++)
5616                     {
5617                         *len += strlen(second_dim_values[k]) + 1;
5618                     }
5619                 }
5620             }
5621         }
5622         else
5623         {
5624             for(i = 0; i < n_frames; i++)
5625             {
5626                 second_dim_values = ((tng_non_particle_data_t)data)->strings[i];
5627                 for(j = 0; j < data->n_values_per_frame; j++)
5628                 {
5629                     *len += strlen(second_dim_values[j]) + 1;
5630                 }
5631             }
5632         }
5633     }
5634     else
5635     {
5636         *len += size * frame_step * n_particles * data->n_values_per_frame;
5637     }
5638
5639     return(TNG_SUCCESS);
5640 }
5641
5642 /** Read the values of a particle data block
5643  * @param tng_data is a trajectory data container.
5644  * @param block is the block to store the data (should already contain
5645  * the block headers and the block contents).
5646  * @param offset is the reading offset to point at the place where the actual
5647  * values are stored, starting from the beginning of the block_contents. The
5648  * offset is changed during the reading.
5649  * @param datatype is the type of data of the data block (char, int, float or
5650  * double).
5651  * @param num_first_particle is the number of the first particle in the data
5652  * block. This should be the same as in the corresponding particle mapping
5653  * block.
5654  * @param n_particles is the number of particles in the data block. This should
5655  * be the same as in the corresponding particle mapping block.
5656  * @param first_frame_with_data is the frame number of the first frame with data
5657  * in this data block.
5658  * @param stride_length is the number of frames between each data entry.
5659  * @param n_frames is the number of frames in this data block.
5660  * @param n_values is the number of values per particle and frame stored in this
5661  * data block.
5662  * @param codec_id is the ID of the codec to compress the data.
5663  * @param multiplier is the multiplication factor applied to each data value
5664  * before compression. This factor is applied since some compression algorithms
5665  * work only on integers.
5666  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5667  * error has occured.
5668  */
5669 static tng_function_status tng_particle_data_read
5670                 (tng_trajectory_t tng_data,
5671                  tng_gen_block_t block,
5672                  int *offset,
5673                  const char datatype,
5674                  const int64_t num_first_particle,
5675                  const int64_t n_particles,
5676                  const int64_t first_frame_with_data,
5677                  const int64_t stride_length,
5678                  int64_t n_frames,
5679                  const int64_t n_values,
5680                  const int64_t codec_id,
5681                  const double multiplier)
5682 {
5683     int64_t i, j, k, tot_n_particles, n_frames_div;
5684     int size, len;
5685     int64_t data_size;
5686     char ***first_dim_values, **second_dim_values;
5687     tng_particle_data_t data;
5688     tng_trajectory_frame_set_t frame_set =
5689     &tng_data->current_trajectory_frame_set;
5690     char block_type_flag;
5691
5692     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
5693
5694     /* This must be caught early to avoid creating a data block if not necessary. */
5695 #ifndef USE_ZLIB
5696     if(codec_id == TNG_GZIP_COMPRESSION)
5697     {
5698         fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
5699                 __LINE__);
5700         return(TNG_FAILURE);
5701     }
5702 #endif
5703
5704     switch(datatype)
5705     {
5706     case TNG_CHAR_DATA:
5707         size = 1;
5708         break;
5709     case TNG_INT_DATA:
5710         size = sizeof(int64_t);
5711         break;
5712     case TNG_FLOAT_DATA:
5713         size = sizeof(float);
5714         break;
5715     case TNG_DOUBLE_DATA:
5716     default:
5717         size = sizeof(double);
5718     }
5719
5720     /* If the block does not exist, create it */
5721     if(tng_particle_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
5722     {
5723         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5724         {
5725             block_type_flag = TNG_TRAJECTORY_BLOCK;
5726         }
5727         else
5728         {
5729             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5730         }
5731
5732         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
5733            TNG_SUCCESS)
5734         {
5735             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
5736                    __FILE__, __LINE__);
5737             return(TNG_CRITICAL);
5738         }
5739         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5740         {
5741             data = &frame_set->tr_particle_data[frame_set->
5742                                                 n_particle_data_blocks - 1];
5743         }
5744         else
5745         {
5746             data = &tng_data->non_tr_particle_data[tng_data->
5747                                                    n_particle_data_blocks - 1];
5748         }
5749         data->block_id = block->id;
5750
5751         data->block_name = malloc(strlen(block->name) + 1);
5752         if(!data->block_name)
5753         {
5754             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5755                    (int)strlen(block->name)+1, __FILE__, __LINE__);
5756             return(TNG_CRITICAL);
5757         }
5758         strcpy(data->block_name, block->name);
5759
5760         data->datatype = datatype;
5761
5762         data->values = 0;
5763         /* FIXME: Memory leak from strings. */
5764         data->strings = 0;
5765         data->n_frames = 0;
5766         data->codec_id = codec_id;
5767         data->compression_multiplier = multiplier;
5768         data->last_retrieved_frame = -1;
5769     }
5770
5771     if(/*block_type_flag == TNG_TRAJECTORY_BLOCK &&*/
5772        tng_data->current_trajectory_frame_set_input_file_pos > 0 &&
5773        tng_data->var_num_atoms_flag)
5774     {
5775         tot_n_particles = frame_set->n_particles;
5776     }
5777     else
5778     {
5779         tot_n_particles = tng_data->n_particles;
5780     }
5781
5782     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5783
5784     if(codec_id != TNG_UNCOMPRESSED)
5785     {
5786         data_size = (unsigned long)(n_frames_div * size * n_particles * n_values);
5787         switch(codec_id)
5788         {
5789         case TNG_XTC_COMPRESSION:
5790             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5791             break;
5792         case TNG_TNG_COMPRESSION:
5793 /*            fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5794             if(tng_uncompress(tng_data, block, datatype,
5795                               block->block_contents + *offset,
5796                               data_size) != TNG_SUCCESS)
5797             {
5798                 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5799                        __FILE__, __LINE__);
5800                 return(TNG_CRITICAL);
5801             }
5802 /*            fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
5803             break;
5804 #ifdef USE_ZLIB
5805         case TNG_GZIP_COMPRESSION:
5806 /*            fprintf(stderr, "TNG library: Before GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5807             if(tng_gzip_uncompress(tng_data, block,
5808                                    block->block_contents + *offset,
5809                                    data_size) != TNG_SUCCESS)
5810             {
5811                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5812                     __LINE__);
5813                 return(TNG_CRITICAL);
5814             }
5815 /*            fprintf(stderr, "TNG library: After GZIP uncompression: %"PRId64"\n", block->block_contents_size);*/
5816             break;
5817 #endif
5818         }
5819     }
5820     /* Allocate memory */
5821     if(!data->values || data->n_frames != n_frames ||
5822        data->n_values_per_frame != n_values)
5823     {
5824         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
5825                                           stride_length,
5826                                           tot_n_particles, n_values) !=
5827            TNG_SUCCESS)
5828         {
5829             fprintf(stderr, "TNG library: Cannot allocate memory for particle data. %s: %d\n",
5830                    __FILE__, __LINE__);
5831             return(TNG_CRITICAL);
5832         }
5833     }
5834
5835     data->first_frame_with_data = first_frame_with_data;
5836
5837     if(datatype == TNG_CHAR_DATA)
5838     {
5839         for(i = 0; i < n_frames_div; i++)
5840         {
5841             first_dim_values = data->strings[i];
5842             for(j = num_first_particle; j < num_first_particle + n_particles;
5843                 j++)
5844             {
5845                 second_dim_values = first_dim_values[j];
5846                 for(k = 0; k < n_values; k++)
5847                 {
5848                     len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
5849                               TNG_MAX_STR_LEN);
5850                     if(second_dim_values[k])
5851                     {
5852                         free(second_dim_values[k]);
5853                     }
5854                     second_dim_values[k] = malloc(len);
5855                     if(!second_dim_values[k])
5856                     {
5857                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
5858                             len, __FILE__, __LINE__);
5859                         return(TNG_CRITICAL);
5860                     }
5861                     strncpy(second_dim_values[k],
5862                             block->block_contents+*offset, len);
5863                     *offset += len;
5864                 }
5865             }
5866         }
5867     }
5868     else
5869     {
5870         memcpy((char *)data->values + n_frames_div * size * n_values *
5871                num_first_particle,
5872                block->block_contents + *offset,
5873                block->block_contents_size - *offset);
5874         switch(datatype)
5875         {
5876         case TNG_FLOAT_DATA:
5877             if(tng_data->input_endianness_swap_func_32)
5878             {
5879                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5880                 {
5881                     if(tng_data->input_endianness_swap_func_32(tng_data,
5882                         (int32_t *)((char *)data->values + i))
5883                         != TNG_SUCCESS)
5884                     {
5885                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5886                                 __FILE__, __LINE__);
5887                     }
5888                 }
5889             }
5890             break;
5891         case TNG_INT_DATA:
5892         case TNG_DOUBLE_DATA:
5893             if(tng_data->input_endianness_swap_func_64)
5894             {
5895                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
5896                 {
5897                     if(tng_data->input_endianness_swap_func_64(tng_data,
5898                         (int64_t *)((char *)data->values + i))
5899                         != TNG_SUCCESS)
5900                     {
5901                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5902                                 __FILE__, __LINE__);
5903                     }
5904                 }
5905             }
5906             break;
5907         case TNG_CHAR_DATA:
5908             break;
5909         }
5910     }
5911     return(TNG_SUCCESS);
5912 }
5913
5914 /** Write a particle data block
5915  * @param tng_data is a trajectory data container.
5916  * @param block is the block to store the data (should already contain
5917  * the block headers and the block contents).
5918  * @param block_index is the index number of the data block in the frame set.
5919  * @param mapping is the particle mapping that is relevant for the data block.
5920  * @param hash_mode is an option to decide whether to use the md5 hash or not.
5921  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5922  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5923  * error has occured.
5924  */
5925 static tng_function_status tng_particle_data_block_write
5926                 (tng_trajectory_t tng_data,
5927                  tng_gen_block_t block,
5928                  const int64_t block_index,
5929                  const tng_particle_mapping_t mapping,
5930                  const char hash_mode)
5931 {
5932     int64_t n_particles, num_first_particle, n_frames, stride_length;
5933     int64_t frame_step, data_start_pos;
5934     int64_t i, j, k;
5935     int size;
5936     size_t len, offset = 0;
5937     char dependency, temp, *temp_name;
5938     double multiplier;
5939     char ***first_dim_values, **second_dim_values;
5940     tng_trajectory_frame_set_t frame_set;
5941     tng_function_status stat;
5942
5943     tng_particle_data_t data;
5944     char block_type_flag;
5945
5946     frame_set = &tng_data->current_trajectory_frame_set;
5947
5948     /* If we have already started writing frame sets it is too late to write
5949      * non-trajectory data blocks */
5950     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5951     {
5952         block_type_flag = TNG_TRAJECTORY_BLOCK;
5953     }
5954     else
5955     {
5956         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5957     }
5958
5959     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5960     {
5961         return(TNG_CRITICAL);
5962     }
5963
5964     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5965     {
5966         data = &frame_set->tr_particle_data[block_index];
5967
5968         /* If this data block has not had any data added in this frame set
5969          * do not write it. */
5970         if(data->first_frame_with_data < frame_set->first_frame)
5971         {
5972             return(TNG_SUCCESS);
5973         }
5974
5975         stride_length = tng_max_i64(1, data->stride_length);
5976     }
5977     else
5978     {
5979         data = &tng_data->non_tr_particle_data[block_index];
5980         stride_length = 1;
5981     }
5982
5983     switch(data->datatype)
5984     {
5985     case TNG_CHAR_DATA:
5986         size = 1;
5987         break;
5988     case TNG_INT_DATA:
5989         size = sizeof(int64_t);
5990         break;
5991     case TNG_FLOAT_DATA:
5992         size = sizeof(float);
5993         break;
5994     case TNG_DOUBLE_DATA:
5995     default:
5996         size = sizeof(double);
5997     }
5998
5999     len = strlen(data->block_name) + 1;
6000
6001     if(!block->name || strlen(block->name) < len)
6002     {
6003         temp_name = realloc(block->name, len);
6004         if(!temp_name)
6005         {
6006             fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n", len,
6007                    __FILE__, __LINE__);
6008             free(block->name);
6009             block->name = 0;
6010             return(TNG_CRITICAL);
6011         }
6012         block->name = temp_name;
6013     }
6014     strncpy(block->name, data->block_name, len);
6015     block->id = data->block_id;
6016
6017     /* If writing frame independent data data->n_frames is 0, but n_frames
6018        is used for the loop writing the data (and reserving memory) and needs
6019        to be at least 1 */
6020     n_frames = tng_max_i64(1, data->n_frames);
6021
6022     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6023     {
6024         /* If the frame set is finished before writing the full number of frames
6025            make sure the data block is not longer than the frame set. */
6026         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6027
6028         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6029     }
6030
6031     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6032                  n_frames / stride_length;
6033
6034     /* TNG compression will use compression precision to get integers from
6035      * floating point data. The compression multiplier stores that information
6036      * to be able to return the precision of the compressed data. */
6037     if(data->codec_id == TNG_TNG_COMPRESSION)
6038     {
6039         data->compression_multiplier = tng_data->compression_precision;
6040     }
6041     /* Uncompressed data blocks do not use compression multipliers at all.
6042      * GZip compression does not need it either. */
6043     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6044     {
6045         data->compression_multiplier = 1.0;
6046     }
6047
6048     if(mapping && mapping->n_particles != 0)
6049     {
6050         n_particles = mapping->n_particles;
6051         num_first_particle = mapping->num_first_particle;
6052     }
6053     else
6054     {
6055         num_first_particle = 0;
6056         if(tng_data->var_num_atoms_flag)
6057         {
6058             n_particles = frame_set->n_particles;
6059         }
6060         else
6061         {
6062             n_particles = tng_data->n_particles;
6063         }
6064     }
6065
6066     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6067     {
6068         dependency = TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT;
6069     }
6070     else
6071     {
6072         dependency = TNG_PARTICLE_DEPENDENT;
6073     }
6074
6075     if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
6076                                     frame_step, stride_length, num_first_particle,
6077                                     n_particles, dependency, &data_start_pos,
6078                                     &block->block_contents_size) != TNG_SUCCESS)
6079     {
6080         fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
6081                 __FILE__, __LINE__);
6082         return(TNG_CRITICAL);
6083     }
6084
6085     if(block->block_contents)
6086     {
6087         free(block->block_contents);
6088     }
6089     block->block_contents = malloc(block->block_contents_size);
6090     if(!block->block_contents)
6091     {
6092         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6093                block->block_contents_size, __FILE__, __LINE__);
6094         return(TNG_CRITICAL);
6095     }
6096
6097
6098     memcpy(block->block_contents, &data->datatype, sizeof(char));
6099     offset += sizeof(char);
6100
6101     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6102     offset += sizeof(char);
6103
6104     if(dependency & TNG_FRAME_DEPENDENT)
6105     {
6106         if(stride_length > 1)
6107         {
6108             temp = 1;
6109         }
6110         else
6111         {
6112             temp = 0;
6113         }
6114         memcpy(block->block_contents+offset, &temp, sizeof(char));
6115         offset += sizeof(char);
6116     }
6117
6118     memcpy(block->block_contents+offset, &data->n_values_per_frame,
6119            sizeof(data->n_values_per_frame));
6120     if(tng_data->output_endianness_swap_func_64)
6121     {
6122         if(tng_data->output_endianness_swap_func_64(tng_data,
6123            (int64_t *)block->header_contents+offset)
6124             != TNG_SUCCESS)
6125         {
6126             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6127                     __FILE__, __LINE__);
6128         }
6129     }
6130     offset += sizeof(data->n_values_per_frame);
6131
6132     memcpy(block->block_contents+offset, &data->codec_id,
6133            sizeof(data->codec_id));
6134     if(tng_data->output_endianness_swap_func_64)
6135     {
6136         if(tng_data->output_endianness_swap_func_64(tng_data,
6137            (int64_t *)block->header_contents+offset)
6138             != TNG_SUCCESS)
6139         {
6140             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6141                     __FILE__, __LINE__);
6142         }
6143     }
6144     offset += sizeof(data->codec_id);
6145
6146     if(data->codec_id != TNG_UNCOMPRESSED)
6147     {
6148         memcpy(block->block_contents+offset, &data->compression_multiplier,
6149                sizeof(data->compression_multiplier));
6150         if(tng_data->output_endianness_swap_func_64)
6151         {
6152             if(tng_data->output_endianness_swap_func_64(tng_data,
6153                (int64_t *)block->header_contents+offset)
6154                 != TNG_SUCCESS)
6155             {
6156                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6157                         __FILE__, __LINE__);
6158             }
6159         }
6160         offset += sizeof(data->compression_multiplier);
6161     }
6162
6163     if(data->n_frames > 0 && stride_length > 1)
6164     {
6165         /* FIXME: first_frame_with_data is not reliably set */
6166         if(data->first_frame_with_data == 0)
6167         {
6168             data->first_frame_with_data = frame_set->first_frame;
6169         }
6170         memcpy(block->block_contents+offset, &data->first_frame_with_data,
6171                sizeof(data->first_frame_with_data));
6172         if(tng_data->output_endianness_swap_func_64)
6173         {
6174             if(tng_data->output_endianness_swap_func_64(tng_data,
6175                (int64_t *)block->header_contents+offset)
6176                 != TNG_SUCCESS)
6177             {
6178                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6179                         __FILE__, __LINE__);
6180             }
6181         }
6182         offset += sizeof(data->first_frame_with_data);
6183
6184         memcpy(block->block_contents+offset, &stride_length,
6185                sizeof(stride_length));
6186         if(tng_data->output_endianness_swap_func_64)
6187         {
6188             if(tng_data->output_endianness_swap_func_64(tng_data,
6189                (int64_t *)block->header_contents+offset)
6190                 != TNG_SUCCESS)
6191             {
6192                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6193                         __FILE__, __LINE__);
6194             }
6195         }
6196         offset += sizeof(stride_length);
6197     }
6198
6199
6200     memcpy(block->block_contents+offset, &num_first_particle,
6201            sizeof(num_first_particle));
6202     if(tng_data->output_endianness_swap_func_64)
6203     {
6204         if(tng_data->output_endianness_swap_func_64(tng_data,
6205            (int64_t *)block->header_contents+offset)
6206             != TNG_SUCCESS)
6207         {
6208             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6209                     __FILE__, __LINE__);
6210         }
6211     }
6212     offset += sizeof(num_first_particle);
6213
6214     memcpy(block->block_contents+offset, &n_particles, sizeof(n_particles));
6215     if(tng_data->output_endianness_swap_func_64)
6216     {
6217         if(tng_data->output_endianness_swap_func_64(tng_data,
6218            (int64_t *)block->header_contents+offset)
6219             != TNG_SUCCESS)
6220         {
6221             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6222                     __FILE__, __LINE__);
6223         }
6224     }
6225     offset += sizeof(n_particles);
6226
6227     if(data->datatype == TNG_CHAR_DATA)
6228     {
6229         if(data->strings)
6230         {
6231             for(i = 0; i < frame_step; i++)
6232             {
6233                 first_dim_values = data->strings[i];
6234                 for(j = num_first_particle; j < num_first_particle + n_particles;
6235                     j++)
6236                 {
6237                     second_dim_values = first_dim_values[j];
6238                     for(k = 0; k < data->n_values_per_frame; k++)
6239                     {
6240                         len = (unsigned int)strlen(second_dim_values[k]) + 1;
6241                         strncpy(block->block_contents+offset,
6242                                 second_dim_values[k], len);
6243                         offset += len;
6244                     }
6245                 }
6246             }
6247         }
6248     }
6249     else if(data->values)
6250     {
6251         memcpy(block->block_contents + offset, data->values,
6252                block->block_contents_size - offset);
6253
6254         switch(data->datatype)
6255         {
6256         case TNG_FLOAT_DATA:
6257             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6258                data->codec_id == TNG_TNG_COMPRESSION)
6259             {
6260                 if(tng_data->input_endianness_swap_func_32)
6261                 {
6262                     for(i = offset; i < block->block_contents_size; i+=size)
6263                     {
6264                         if(tng_data->input_endianness_swap_func_32(tng_data,
6265                            (int32_t *)(block->block_contents + i))
6266                            != TNG_SUCCESS)
6267                         {
6268                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6269                                     __FILE__, __LINE__);
6270                         }
6271                     }
6272                 }
6273             }
6274             else
6275             {
6276                 multiplier = data->compression_multiplier;
6277                 if(fabs(multiplier - 1.0) > 0.00001 ||
6278                    tng_data->input_endianness_swap_func_32)
6279                 {
6280                     for(i = offset; i < block->block_contents_size; i+=size)
6281                     {
6282                         *(float *)(block->block_contents + i) *= (float)multiplier;
6283                         if(tng_data->input_endianness_swap_func_32 &&
6284                         tng_data->input_endianness_swap_func_32(tng_data,
6285                         (int32_t *)(block->block_contents + i))
6286                         != TNG_SUCCESS)
6287                         {
6288                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6289                                     __FILE__, __LINE__);
6290                         }
6291                     }
6292                 }
6293             }
6294             break;
6295         case TNG_INT_DATA:
6296             if(tng_data->input_endianness_swap_func_64)
6297             {
6298                 for(i = offset; i < block->block_contents_size; i+=size)
6299                 {
6300                     if(tng_data->input_endianness_swap_func_64(tng_data,
6301                        (int64_t *)(block->block_contents + i))
6302                        != TNG_SUCCESS)
6303                     {
6304                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6305                                 __FILE__, __LINE__);
6306                     }
6307                 }
6308             }
6309             break;
6310         case TNG_DOUBLE_DATA:
6311             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
6312                data->codec_id == TNG_TNG_COMPRESSION)
6313             {
6314                 if(tng_data->input_endianness_swap_func_64)
6315                 {
6316                     for(i = offset; i < block->block_contents_size; i+=size)
6317                     {
6318                         if(tng_data->input_endianness_swap_func_64(tng_data,
6319                            (int64_t *)(block->block_contents + i))
6320                            != TNG_SUCCESS)
6321                         {
6322                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6323                                     __FILE__, __LINE__);
6324                         }
6325                     }
6326                 }
6327             }
6328             else
6329             {
6330                 multiplier = data->compression_multiplier;
6331                 if(fabs(multiplier - 1.0) > 0.00001 ||
6332                    tng_data->input_endianness_swap_func_64)
6333                 {
6334                     for(i = offset; i < block->block_contents_size; i+=size)
6335                     {
6336                         *(double *)(block->block_contents + i) *= multiplier;
6337                         if(tng_data->input_endianness_swap_func_64 &&
6338                         tng_data->input_endianness_swap_func_64(tng_data,
6339                         (int64_t *)(block->block_contents + i))
6340                         != TNG_SUCCESS)
6341                         {
6342                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6343                                     __FILE__, __LINE__);
6344                         }
6345                     }
6346                 }
6347             }
6348             break;
6349         case TNG_CHAR_DATA:
6350             break;
6351         }
6352     }
6353     else
6354     {
6355         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
6356     }
6357
6358     frame_set->n_written_frames += frame_set->n_unwritten_frames;
6359     frame_set->n_unwritten_frames = 0;
6360
6361     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
6362     {
6363         switch(data->codec_id)
6364         {
6365         case TNG_XTC_COMPRESSION:
6366             fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6367             data->codec_id = TNG_UNCOMPRESSED;
6368             break;
6369         case TNG_TNG_COMPRESSION:
6370             stat = tng_compress(tng_data, block, frame_step,
6371                                 n_particles, data->datatype,
6372                                 block->block_contents + data_start_pos);
6373             if(stat != TNG_SUCCESS)
6374             {
6375                 fprintf(stderr, "TNG library: Could not write tng compressed block data. %s: %d\n",
6376                     __FILE__, __LINE__);
6377                 if(stat == TNG_CRITICAL)
6378                 {
6379                     return(TNG_CRITICAL);
6380                 }
6381                 /* Set the data again, but with no compression (to write only
6382                  * the relevant data) */
6383                 data->codec_id = TNG_UNCOMPRESSED;
6384                 stat = tng_particle_data_block_write(tng_data, block,
6385                                                      block_index, mapping,
6386                                                      hash_mode);
6387                 return(stat);
6388             }
6389             break;
6390 #ifdef USE_ZLIB
6391         case TNG_GZIP_COMPRESSION:
6392     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size);*/
6393             stat = tng_gzip_compress(tng_data, block,
6394                                      block->block_contents + data_start_pos,
6395                                      block->block_contents_size - data_start_pos);
6396             if(stat != TNG_SUCCESS)
6397             {
6398                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6399                     __LINE__);
6400                 if(stat == TNG_CRITICAL)
6401                 {
6402                     return(TNG_CRITICAL);
6403                 }
6404                 /* Set the data again, but with no compression (to write only
6405                  * the relevant data) */
6406                 data->codec_id = TNG_UNCOMPRESSED;
6407                 stat = tng_particle_data_block_write(tng_data, block,
6408                                                      block_index, mapping,
6409                                                      hash_mode);
6410                 return(stat);
6411             }
6412     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size);*/
6413             break;
6414 #endif
6415         }
6416     }
6417
6418     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
6419     {
6420         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
6421                tng_data->output_file_path, __FILE__, __LINE__);
6422         return(TNG_CRITICAL);
6423     }
6424
6425     if(fwrite(block->block_contents, block->block_contents_size, 1,
6426         tng_data->output_file) != 1)
6427     {
6428         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6429                 __LINE__);
6430         return(TNG_CRITICAL);
6431     }
6432
6433     return(TNG_SUCCESS);
6434 }
6435
6436 /* TEST: */
6437 /** Create a non-particle data block
6438  * @param tng_data is a trajectory data container.
6439  * @param block_type_flag specifies if this is a trajectory block or a
6440  * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
6441  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6442  * error has occured.
6443  */
6444 static tng_function_status tng_data_block_create
6445                 (tng_trajectory_t tng_data,
6446                  const char block_type_flag)
6447 {
6448     tng_trajectory_frame_set_t frame_set =
6449     &tng_data->current_trajectory_frame_set;
6450
6451     tng_non_particle_data_t data;
6452
6453     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6454     {
6455         frame_set->n_data_blocks++;
6456         data = realloc(frame_set->tr_data, sizeof(struct tng_non_particle_data) *
6457                        frame_set->n_data_blocks);
6458         if(!data)
6459         {
6460             fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
6461                 sizeof(struct tng_non_particle_data) * frame_set->n_data_blocks,
6462                 __FILE__, __LINE__);
6463             free(frame_set->tr_data);
6464             frame_set->tr_data = 0;
6465             return(TNG_CRITICAL);
6466         }
6467         frame_set->tr_data = data;
6468     }
6469     else
6470     {
6471         tng_data->n_data_blocks++;
6472         data = realloc(tng_data->non_tr_data, sizeof(struct tng_non_particle_data) *
6473                         tng_data->n_data_blocks);
6474         if(!data)
6475         {
6476             fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
6477                 sizeof(struct tng_non_particle_data) * tng_data->n_data_blocks,
6478                 __FILE__, __LINE__);
6479             free(tng_data->non_tr_data);
6480             tng_data->non_tr_data = 0;
6481             return(TNG_CRITICAL);
6482         }
6483         tng_data->non_tr_data = data;
6484     }
6485
6486     return(TNG_SUCCESS);
6487 }
6488
6489 /* TEST: */
6490 /** Allocate memory for storing non-particle data.
6491  * The allocated block will be refered to by data->values.
6492  * @param tng_data is a trajectory data container.
6493  * @param data is the data struct, which will contain the allocated memory in
6494  * data->values.
6495  * @param n_frames is the number of frames of data to store.
6496  * @param n_values_per_frame is the number of data values per frame.
6497  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6498  * error has occured.
6499  */
6500 static tng_function_status tng_allocate_data_mem
6501                 (tng_trajectory_t tng_data,
6502                  tng_non_particle_data_t data,
6503                  int64_t n_frames,
6504                  int64_t stride_length,
6505                  const int64_t n_values_per_frame)
6506 {
6507     void **values;
6508     int64_t i, j, size, frame_alloc;
6509     (void)tng_data;
6510
6511     if(n_values_per_frame == 0)
6512     {
6513         return(TNG_FAILURE);
6514     }
6515
6516     if(data->strings && data->datatype == TNG_CHAR_DATA)
6517     {
6518         for(i = 0; i < data->n_frames; i++)
6519         {
6520             for(j = 0; j < data->n_values_per_frame; j++)
6521             {
6522                 if(data->strings[i][j])
6523                 {
6524                     free(data->strings[i][j]);
6525                     data->strings[i][j] = 0;
6526                 }
6527             }
6528             free(data->strings[i]);
6529             data->strings[i] = 0;
6530         }
6531         free(data->strings);
6532     }
6533     data->n_frames = n_frames;
6534     data->stride_length = tng_max_i64(1, stride_length);
6535     n_frames = tng_max_i64(1, n_frames);
6536     data->n_values_per_frame = n_values_per_frame;
6537     frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6538
6539     if(data->datatype == TNG_CHAR_DATA)
6540     {
6541         data->strings = malloc(sizeof(char **) * frame_alloc);
6542         for(i = 0; i < frame_alloc; i++)
6543         {
6544             data->strings[i] = malloc(sizeof(char *) * n_values_per_frame);
6545             if(!data->strings[i])
6546             {
6547                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6548                        n_values_per_frame,
6549                        __FILE__, __LINE__);
6550                 return(TNG_CRITICAL);
6551             }
6552             for(j = 0; j < n_values_per_frame; j++)
6553             {
6554                 data->strings[i][j] = 0;
6555             }
6556         }
6557     }
6558     else
6559     {
6560         switch(data->datatype)
6561         {
6562         case TNG_INT_DATA:
6563             size = sizeof(int64_t);
6564             break;
6565         case TNG_FLOAT_DATA:
6566             size = sizeof(float);
6567             break;
6568         case TNG_DOUBLE_DATA:
6569         default:
6570             size = sizeof(double);
6571         }
6572
6573         values = realloc(data->values,
6574                          size * frame_alloc *
6575                          n_values_per_frame);
6576         if(!values)
6577         {
6578             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6579                    size * frame_alloc *
6580                    n_values_per_frame,
6581                    __FILE__, __LINE__);
6582             free(data->values);
6583             data->values = 0;
6584             return(TNG_CRITICAL);
6585         }
6586         data->values = values;
6587     }
6588
6589     return(TNG_SUCCESS);
6590 }
6591
6592 /** Read the values of a non-particle data block
6593  * @param tng_data is a trajectory data container.
6594  * @param block is the block to store the data (should already contain
6595  * the block headers and the block contents).
6596  * @param offset is the reading offset to point at the place where the actual
6597  * values are stored, starting from the beginning of the block_contents. The
6598  * offset is changed during the reading.
6599  * @param datatype is the type of data of the data block (char, int, float or
6600  * double).
6601  * @param first_frame_with_data is the frame number of the first frame with data
6602  * in this data block.
6603  * @param stride_length is the number of frames between each data entry.
6604  * @param n_frames is the number of frames in this data block.
6605  * @param n_values is the number of values per frame stored in this data block.
6606  * @param codec_id is the ID of the codec to compress the data.
6607  * @param multiplier is the multiplication factor applied to each data value
6608  * before compression. This factor is applied since some compression algorithms
6609  * work only on integers.
6610  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6611  * error has occured.
6612  */
6613 static tng_function_status tng_data_read(tng_trajectory_t tng_data,
6614                                          tng_gen_block_t block,
6615                                          int *offset,
6616                                          const char datatype,
6617                                          const int64_t first_frame_with_data,
6618                                          const int64_t stride_length,
6619                                          int64_t n_frames,
6620                                          const int64_t n_values,
6621                                          const int64_t codec_id,
6622                                          const double multiplier)
6623 {
6624     int64_t i, j, n_frames_div;
6625     int size, len;
6626 #ifdef USE_ZLIB
6627     int64_t data_size;
6628 #endif
6629     tng_non_particle_data_t data;
6630     tng_trajectory_frame_set_t frame_set =
6631     &tng_data->current_trajectory_frame_set;
6632     char block_type_flag;
6633
6634     TNG_ASSERT(offset != 0, "TNG library: offset must not be a NULL pointer.");
6635
6636 /*     fprintf(stderr, "TNG library: %s\n", block->name);*/
6637
6638     /* This must be caught early to avoid creating a data block if not necessary. */
6639 #ifndef USE_ZLIB
6640     if(codec_id == TNG_GZIP_COMPRESSION)
6641     {
6642         fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
6643                 __LINE__);
6644         return(TNG_FAILURE);
6645     }
6646 #endif
6647
6648     switch(datatype)
6649     {
6650     case TNG_CHAR_DATA:
6651         size = 1;
6652         break;
6653     case TNG_INT_DATA:
6654         size = sizeof(int64_t);
6655         break;
6656     case TNG_FLOAT_DATA:
6657         size = sizeof(float);
6658         break;
6659     case TNG_DOUBLE_DATA:
6660     default:
6661         size = sizeof(double);
6662     }
6663
6664     /* If the block does not exist, create it */
6665     if(tng_data_find(tng_data, block->id, &data) != TNG_SUCCESS)
6666     {
6667         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
6668         {
6669             block_type_flag = TNG_TRAJECTORY_BLOCK;
6670         }
6671         else
6672         {
6673             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6674         }
6675
6676         if(tng_data_block_create(tng_data, block_type_flag) !=
6677             TNG_SUCCESS)
6678         {
6679             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
6680                    __FILE__, __LINE__);
6681             return(TNG_CRITICAL);
6682         }
6683         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6684         {
6685             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
6686         }
6687         else
6688         {
6689             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
6690         }
6691         data->block_id = block->id;
6692
6693         data->block_name = malloc(strlen(block->name) + 1);
6694         if(!data->block_name)
6695         {
6696             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6697                    (int)strlen(block->name)+1, __FILE__, __LINE__);
6698             return(TNG_CRITICAL);
6699         }
6700         strcpy(data->block_name, block->name);
6701
6702         data->datatype = datatype;
6703
6704         data->values = 0;
6705         /* FIXME: Memory leak from strings. */
6706         data->strings = 0;
6707         data->n_frames = 0;
6708         data->codec_id = codec_id;
6709         data->compression_multiplier = multiplier;
6710         data->last_retrieved_frame = -1;
6711     }
6712
6713     n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
6714
6715     if(codec_id != TNG_UNCOMPRESSED)
6716     {
6717         switch(codec_id)
6718         {
6719 #ifdef USE_ZLIB
6720         case TNG_GZIP_COMPRESSION:
6721             data_size = n_frames_div * size * n_values;
6722     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
6723             if(tng_gzip_uncompress(tng_data, block,
6724                                    block->block_contents + *offset,
6725                                    data_size) != TNG_SUCCESS)
6726             {
6727                 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
6728                     __LINE__);
6729                 return(TNG_CRITICAL);
6730             }
6731     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
6732             break;
6733 #endif
6734         }
6735     }
6736
6737     /* Allocate memory */
6738     if(!data->values || data->n_frames != n_frames ||
6739        data->n_values_per_frame != n_values)
6740     {
6741         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
6742                                  n_values) !=
6743            TNG_SUCCESS)
6744         {
6745             fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
6746                    __FILE__, __LINE__);
6747             return(TNG_CRITICAL);
6748         }
6749     }
6750
6751     data->first_frame_with_data = first_frame_with_data;
6752
6753     if(datatype == TNG_CHAR_DATA)
6754     {
6755         for(i = 0; i < n_frames_div; i++)
6756         {
6757             for(j = 0; j < n_values; j++)
6758             {
6759                 len = tng_min_i((int)strlen(block->block_contents+*offset) + 1,
6760                               TNG_MAX_STR_LEN);
6761                 if(data->strings[i][j])
6762                 {
6763                     free(data->strings[i][j]);
6764                 }
6765                 data->strings[i][j] = malloc(len);
6766                 if(!data->strings[i][j])
6767                 {
6768                     fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
6769                            len, __FILE__, __LINE__);
6770                     return(TNG_CRITICAL);
6771                 }
6772                 strncpy(data->strings[i][j], block->block_contents+*offset,
6773                         len);
6774                 *offset += len;
6775             }
6776         }
6777     }
6778     else
6779     {
6780         memcpy(data->values, block->block_contents + *offset,
6781                block->block_contents_size - *offset);
6782         switch(datatype)
6783         {
6784         case TNG_FLOAT_DATA:
6785             if(tng_data->input_endianness_swap_func_32)
6786             {
6787                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6788                 {
6789                     if(tng_data->input_endianness_swap_func_32(tng_data,
6790                         (int32_t *)((char *)data->values + i))
6791                         != TNG_SUCCESS)
6792                     {
6793                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6794                                 __FILE__, __LINE__);
6795                     }
6796                 }
6797             }
6798             break;
6799         case TNG_INT_DATA:
6800         case TNG_DOUBLE_DATA:
6801             if(tng_data->input_endianness_swap_func_64)
6802             {
6803                 for(i = 0; i < (block->block_contents_size - *offset); i+=size)
6804                 {
6805                     if(tng_data->input_endianness_swap_func_64(tng_data,
6806                         (int64_t *)((char *)data->values + i))
6807                         != TNG_SUCCESS)
6808                     {
6809                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6810                                 __FILE__, __LINE__);
6811                     }
6812                 }
6813             }
6814             break;
6815         case TNG_CHAR_DATA:
6816             break;
6817         }
6818     }
6819     return(TNG_SUCCESS);
6820 }
6821
6822 /** Write a non-particle data block
6823  * @param tng_data is a trajectory data container.
6824  * @param block is the block to store the data (should already contain
6825  * the block headers and the block contents).
6826  * @param block_index is the index number of the data block in the frame set.
6827  * @param hash_mode is an option to decide whether to use the md5 hash or not.
6828  * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
6829  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6830  * error has occured.
6831  */
6832 static tng_function_status tng_data_block_write(tng_trajectory_t tng_data,
6833                                                 tng_gen_block_t block,
6834                                                 const int64_t block_index,
6835                                                 const char hash_mode)
6836 {
6837     int64_t n_frames, stride_length, frame_step, data_start_pos;
6838     int64_t i, j;
6839     int offset = 0, size;
6840     unsigned int len;
6841 #ifdef USE_ZLIB
6842     tng_function_status stat;
6843 #endif
6844     char temp, dependency, *temp_name;
6845     double multiplier;
6846     tng_trajectory_frame_set_t frame_set =
6847     &tng_data->current_trajectory_frame_set;
6848
6849     tng_non_particle_data_t data;
6850     char block_type_flag;
6851
6852     /* If we have already started writing frame sets it is too late to write
6853      * non-trajectory data blocks */
6854     if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
6855     {
6856         block_type_flag = TNG_TRAJECTORY_BLOCK;
6857     }
6858     else
6859     {
6860         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
6861     }
6862
6863     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6864     {
6865         return(TNG_CRITICAL);
6866     }
6867
6868     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6869     {
6870         data = &frame_set->tr_data[block_index];
6871
6872         /* If this data block has not had any data added in this frame set
6873          * do not write it. */
6874         if(data->first_frame_with_data < frame_set->first_frame)
6875         {
6876             return(TNG_SUCCESS);
6877         }
6878
6879         stride_length = tng_max_i64(1, data->stride_length);
6880     }
6881     else
6882     {
6883         data = &tng_data->non_tr_data[block_index];
6884         stride_length = 1;
6885     }
6886
6887     switch(data->datatype)
6888     {
6889     case TNG_CHAR_DATA:
6890         size = 1;
6891         break;
6892     case TNG_INT_DATA:
6893         size = sizeof(int64_t);
6894         break;
6895     case TNG_FLOAT_DATA:
6896         size = sizeof(float);
6897         break;
6898     case TNG_DOUBLE_DATA:
6899     default:
6900         size = sizeof(double);
6901     }
6902
6903     len = (unsigned int)strlen(data->block_name) + 1;
6904
6905     if(!block->name || strlen(block->name) < len)
6906     {
6907         temp_name = realloc(block->name, len);
6908         if(!temp_name)
6909         {
6910             fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n", len+1,
6911                    __FILE__, __LINE__);
6912             free(block->name);
6913             block->name = 0;
6914             return(TNG_CRITICAL);
6915         }
6916         block->name = temp_name;
6917     }
6918     strncpy(block->name, data->block_name, len);
6919     block->id = data->block_id;
6920
6921     /* If writing frame independent data data->n_frames is 0, but n_frames
6922        is used for the loop writing the data (and reserving memory) and needs
6923        to be at least 1 */
6924     n_frames = tng_max_i64(1, data->n_frames);
6925
6926     if(block_type_flag == TNG_TRAJECTORY_BLOCK)
6927     {
6928         /* If the frame set is finished before writing the full number of frames
6929            make sure the data block is not longer than the frame set. */
6930         n_frames = tng_min_i64(n_frames, frame_set->n_frames);
6931
6932         n_frames -= (data->first_frame_with_data - frame_set->first_frame);
6933     }
6934
6935     frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
6936                  n_frames / stride_length;
6937
6938     /* TNG compression will use compression precision to get integers from
6939      * floating point data. The compression multiplier stores that information
6940      * to be able to return the precision of the compressed data. */
6941     if(data->codec_id == TNG_TNG_COMPRESSION)
6942     {
6943         data->compression_multiplier = tng_data->compression_precision;
6944     }
6945     /* Uncompressed data blocks do not use compression multipliers at all.
6946      * GZip compression does not need it either. */
6947     else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6948     {
6949         data->compression_multiplier = 1.0;
6950     }
6951
6952     if(block_type_flag == TNG_TRAJECTORY_BLOCK && data->n_frames > 0)
6953     {
6954         dependency = TNG_FRAME_DEPENDENT;
6955     }
6956     else
6957     {
6958         dependency = 0;
6959     }
6960
6961     if(tng_data_block_len_calculate(tng_data, (tng_particle_data_t)data, TNG_FALSE, n_frames,
6962                                     frame_step, stride_length, 0,
6963                                     1, dependency, &data_start_pos,
6964                                     &block->block_contents_size) != TNG_SUCCESS)
6965     {
6966         fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
6967                 __FILE__, __LINE__);
6968         return(TNG_CRITICAL);
6969     }
6970
6971     if(block->block_contents)
6972     {
6973         free(block->block_contents);
6974     }
6975     block->block_contents = malloc(block->block_contents_size);
6976     if(!block->block_contents)
6977     {
6978         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
6979                block->block_contents_size, __FILE__, __LINE__);
6980         return(TNG_CRITICAL);
6981     }
6982
6983
6984     memcpy(block->block_contents, &data->datatype, sizeof(char));
6985     offset += sizeof(char);
6986
6987     memcpy(block->block_contents+offset, &dependency, sizeof(char));
6988     offset += sizeof(char);
6989
6990     if(dependency & TNG_FRAME_DEPENDENT)
6991     {
6992         if(stride_length > 1)
6993         {
6994             temp = 1;
6995         }
6996         else
6997         {
6998             temp = 0;
6999         }
7000         memcpy(block->block_contents+offset, &temp, sizeof(char));
7001         offset += sizeof(char);
7002     }
7003
7004     memcpy(block->block_contents+offset, &data->n_values_per_frame,
7005            sizeof(data->n_values_per_frame));
7006     if(tng_data->output_endianness_swap_func_64)
7007     {
7008         if(tng_data->output_endianness_swap_func_64(tng_data,
7009            (int64_t *)block->header_contents+offset)
7010             != TNG_SUCCESS)
7011         {
7012             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7013                     __FILE__, __LINE__);
7014         }
7015     }
7016     offset += sizeof(data->n_values_per_frame);
7017
7018     memcpy(block->block_contents+offset, &data->codec_id,
7019            sizeof(data->codec_id));
7020     if(tng_data->output_endianness_swap_func_64)
7021     {
7022         if(tng_data->output_endianness_swap_func_64(tng_data,
7023            (int64_t *)block->header_contents+offset)
7024             != TNG_SUCCESS)
7025         {
7026             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7027                     __FILE__, __LINE__);
7028         }
7029     }
7030     offset += sizeof(data->codec_id);
7031
7032     if(data->codec_id != TNG_UNCOMPRESSED)
7033     {
7034         memcpy(block->block_contents+offset, &data->compression_multiplier,
7035                sizeof(data->compression_multiplier));
7036         if(tng_data->output_endianness_swap_func_64)
7037         {
7038             if(tng_data->output_endianness_swap_func_64(tng_data,
7039             (int64_t *)block->header_contents+offset)
7040                 != TNG_SUCCESS)
7041             {
7042                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7043                         __FILE__, __LINE__);
7044             }
7045         }
7046         offset += sizeof(data->compression_multiplier);
7047     }
7048
7049     if(data->n_frames > 0 && stride_length > 1)
7050     {
7051         /* FIXME: first_frame_with_data is not reliably set */
7052         if(data->first_frame_with_data == 0)
7053         {
7054             data->first_frame_with_data = frame_set->first_frame;
7055         }
7056         memcpy(block->block_contents+offset, &data->first_frame_with_data,
7057                sizeof(data->first_frame_with_data));
7058         if(tng_data->output_endianness_swap_func_64)
7059         {
7060             if(tng_data->output_endianness_swap_func_64(tng_data,
7061             (int64_t *)block->header_contents+offset)
7062                 != TNG_SUCCESS)
7063             {
7064                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7065                         __FILE__, __LINE__);
7066             }
7067         }
7068         offset += sizeof(data->first_frame_with_data);
7069
7070         memcpy(block->block_contents+offset, &stride_length,
7071                sizeof(data->stride_length));
7072         if(tng_data->output_endianness_swap_func_64)
7073         {
7074             if(tng_data->output_endianness_swap_func_64(tng_data,
7075             (int64_t *)block->header_contents+offset)
7076                 != TNG_SUCCESS)
7077             {
7078                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7079                         __FILE__, __LINE__);
7080             }
7081         }
7082         offset += sizeof(data->stride_length);
7083     }
7084
7085     if(data->datatype == TNG_CHAR_DATA)
7086     {
7087         if(data->strings)
7088         {
7089             for(i = 0; i < frame_step; i++)
7090             {
7091                 for(j = 0; j < data->n_values_per_frame; j++)
7092                 {
7093                     len = (unsigned int)strlen(data->strings[i][j]) + 1;
7094                     strncpy(block->block_contents+offset, data->strings[i][j],
7095                             len);
7096                     offset += len;
7097                 }
7098             }
7099         }
7100     }
7101     else if(data->values)
7102     {
7103         memcpy(block->block_contents + offset, data->values,
7104                block->block_contents_size - offset);
7105         switch(data->datatype)
7106         {
7107         case TNG_FLOAT_DATA:
7108             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7109                data->codec_id == TNG_TNG_COMPRESSION)
7110             {
7111                 if(tng_data->input_endianness_swap_func_32)
7112                 {
7113                     for(i = offset; i < block->block_contents_size; i+=size)
7114                     {
7115                         if(tng_data->input_endianness_swap_func_32(tng_data,
7116                            (int32_t *)(block->block_contents + i))
7117                            != TNG_SUCCESS)
7118                         {
7119                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7120                                     __FILE__, __LINE__);
7121                         }
7122                     }
7123                 }
7124             }
7125             else
7126             {
7127                 multiplier = data->compression_multiplier;
7128                 if(fabs(multiplier - 1.0) > 0.00001 ||
7129                    tng_data->input_endianness_swap_func_32)
7130                 {
7131                     for(i = offset; block->block_contents_size; i+=size)
7132                     {
7133                         *(float *)(block->block_contents + i) *= (float)multiplier;
7134                         if(tng_data->input_endianness_swap_func_32 &&
7135                         tng_data->input_endianness_swap_func_32(tng_data,
7136                         (int32_t *)(block->block_contents + i))
7137                         != TNG_SUCCESS)
7138                         {
7139                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7140                                     __FILE__, __LINE__);
7141                         }
7142                     }
7143                 }
7144             }
7145             break;
7146         case TNG_INT_DATA:
7147             if(tng_data->input_endianness_swap_func_64)
7148             {
7149                 for(i = offset; i < block->block_contents_size; i+=size)
7150                 {
7151                     if(tng_data->input_endianness_swap_func_64(tng_data,
7152                        (int64_t *)(block->block_contents + i))
7153                        != TNG_SUCCESS)
7154                     {
7155                         fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7156                                 __FILE__, __LINE__);
7157                     }
7158                 }
7159             }
7160             break;
7161         case TNG_DOUBLE_DATA:
7162             if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION ||
7163                data->codec_id == TNG_TNG_COMPRESSION)
7164             {
7165                 if(tng_data->input_endianness_swap_func_64)
7166                 {
7167                     for(i = offset; i < block->block_contents_size; i+=size)
7168                     {
7169                         if(tng_data->input_endianness_swap_func_64(tng_data,
7170                            (int64_t *)(block->block_contents + i))
7171                            != TNG_SUCCESS)
7172                         {
7173                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7174                                     __FILE__, __LINE__);
7175                         }
7176                     }
7177                 }
7178             }
7179             else
7180             {
7181                 multiplier = data->compression_multiplier;
7182                 if(fabs(multiplier - 1.0) > 0.00001 ||
7183                    tng_data->input_endianness_swap_func_64)
7184                 {
7185                     for(i = offset; i < block->block_contents_size; i+=size)
7186                     {
7187                         *(double *)(block->block_contents + i) *= multiplier;
7188                         if(tng_data->input_endianness_swap_func_64 &&
7189                         tng_data->input_endianness_swap_func_64(tng_data,
7190                         (int64_t *)(block->block_contents + i))
7191                         != TNG_SUCCESS)
7192                         {
7193                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7194                                     __FILE__, __LINE__);
7195                         }
7196                     }
7197                 }
7198             }
7199             break;
7200         case TNG_CHAR_DATA:
7201             break;
7202         }
7203     }
7204     else
7205     {
7206         memset(block->block_contents+offset, 0, block->block_contents_size - offset);
7207     }
7208
7209     frame_set->n_written_frames += frame_set->n_unwritten_frames;
7210     frame_set->n_unwritten_frames = 0;
7211
7212     if(block_type_flag == TNG_NON_TRAJECTORY_BLOCK || frame_set->n_written_frames > 0)
7213     {
7214         switch(data->codec_id)
7215         {
7216 #ifdef USE_ZLIB
7217         case TNG_GZIP_COMPRESSION:
7218     /*         fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
7219             stat = tng_gzip_compress(tng_data, block,
7220                                      block->block_contents + data_start_pos,
7221                                      block->block_contents_size - data_start_pos);
7222             if(stat != TNG_SUCCESS)
7223             {
7224                 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
7225                     __LINE__);
7226                 if(stat == TNG_CRITICAL)
7227                 {
7228                     return(TNG_CRITICAL);
7229                 }
7230                 data->codec_id = TNG_UNCOMPRESSED;
7231             }
7232     /*         fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
7233             break;
7234 #endif
7235         }
7236     }
7237
7238     if(tng_block_header_write(tng_data, block, hash_mode) != TNG_SUCCESS)
7239     {
7240         fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
7241                tng_data->output_file_path, __FILE__, __LINE__);
7242         return(TNG_CRITICAL);
7243     }
7244
7245     if(fwrite(block->block_contents, block->block_contents_size, 1,
7246               tng_data->output_file) != 1)
7247     {
7248         fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
7249                __FILE__, __LINE__);
7250         return(TNG_CRITICAL);
7251     }
7252
7253     return(TNG_SUCCESS);
7254 }
7255
7256 /** Read the meta information of a data block (particle or non-particle data).
7257  * @param tng_data is a trajectory data container.
7258  * @param block is the block to store the data (should already contain
7259  * the block headers).
7260  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7261  * error has occured.
7262  */
7263 static tng_function_status tng_data_block_meta_information_read
7264                 (tng_trajectory_t tng_data,
7265                  tng_gen_block_t block,
7266                  int *offset,
7267                  char *datatype,
7268                  char *dependency,
7269                  char *sparse_data,
7270                  int64_t *n_values,
7271                  int64_t *codec_id,
7272                  int64_t *first_frame_with_data,
7273                  int64_t *stride_length,
7274                  int64_t *n_frames,
7275                  int64_t *num_first_particle,
7276                  int64_t *block_n_particles,
7277                  double *multiplier)
7278 {
7279     int meta_size;
7280     char *contents;
7281
7282     if(block->block_contents)
7283     {
7284         contents = block->block_contents;
7285     }
7286     else
7287     {
7288         meta_size = 3 * sizeof(char) + sizeof(double) + 6 * sizeof(int64_t);
7289         contents = malloc(meta_size);
7290         if(!contents)
7291         {
7292             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
7293                meta_size, __FILE__, __LINE__);
7294         }
7295
7296         if(fread(contents, meta_size, 1, tng_data->input_file) == 0)
7297         {
7298             fprintf(stderr, "TNG library: Cannot read data block meta information. %s: %d\n", __FILE__, __LINE__);
7299             free(contents);
7300             return(TNG_CRITICAL);
7301         }
7302     }
7303
7304     memcpy(datatype, contents+*offset,
7305            sizeof(*datatype));
7306     *offset += sizeof(*datatype);
7307
7308     memcpy(dependency, contents+*offset,
7309            sizeof(*dependency));
7310     *offset += sizeof(*dependency);
7311
7312     if(*dependency & TNG_FRAME_DEPENDENT)
7313     {
7314         memcpy(sparse_data, contents+*offset,
7315                sizeof(*sparse_data));
7316         *offset += sizeof(*sparse_data);
7317     }
7318
7319     memcpy(n_values, contents+*offset,
7320         sizeof(*n_values));
7321     if(tng_data->input_endianness_swap_func_64)
7322     {
7323         if(tng_data->input_endianness_swap_func_64(tng_data,
7324                                                    n_values)
7325             != TNG_SUCCESS)
7326         {
7327             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7328                     __FILE__, __LINE__);
7329         }
7330     }
7331     *offset += sizeof(*n_values);
7332
7333     memcpy(codec_id, contents+*offset,
7334         sizeof(*codec_id));
7335     if(tng_data->input_endianness_swap_func_64)
7336     {
7337         if(tng_data->input_endianness_swap_func_64(tng_data,
7338                                                    codec_id)
7339             != TNG_SUCCESS)
7340         {
7341             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7342                     __FILE__, __LINE__);
7343         }
7344     }
7345     *offset += sizeof(*codec_id);
7346
7347     if(*codec_id != TNG_UNCOMPRESSED)
7348     {
7349         memcpy(multiplier, contents+*offset,
7350             sizeof(*multiplier));
7351         if(tng_data->input_endianness_swap_func_64)
7352         {
7353             if(tng_data->input_endianness_swap_func_64(tng_data,
7354                                                        (int64_t *) multiplier)
7355                 != TNG_SUCCESS)
7356             {
7357                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7358                         __FILE__, __LINE__);
7359             }
7360         }
7361         *offset += sizeof(*multiplier);
7362     }
7363     else
7364     {
7365         *multiplier = 1;
7366     }
7367
7368     if(*dependency & TNG_FRAME_DEPENDENT)
7369     {
7370         if(*sparse_data)
7371         {
7372             memcpy(first_frame_with_data, contents+*offset,
7373                 sizeof(*first_frame_with_data));
7374             if(tng_data->input_endianness_swap_func_64)
7375             {
7376                 if(tng_data->input_endianness_swap_func_64(tng_data,
7377                                                            first_frame_with_data)
7378                     != TNG_SUCCESS)
7379                 {
7380                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7381                             __FILE__, __LINE__);
7382                 }
7383             }
7384             *offset += sizeof(*first_frame_with_data);
7385
7386             memcpy(stride_length, contents+*offset,
7387                 sizeof(*stride_length));
7388             if(tng_data->input_endianness_swap_func_64)
7389             {
7390                 if(tng_data->input_endianness_swap_func_64(tng_data,
7391                                                            stride_length)
7392                     != TNG_SUCCESS)
7393                 {
7394                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7395                             __FILE__, __LINE__);
7396                 }
7397             }
7398             *offset += sizeof(*stride_length);
7399             *n_frames = tng_data->current_trajectory_frame_set.n_frames -
7400                         (*first_frame_with_data -
7401                         tng_data->current_trajectory_frame_set.first_frame);
7402         }
7403         else
7404         {
7405             *first_frame_with_data = 0;
7406             *stride_length = 1;
7407             *n_frames = tng_data->current_trajectory_frame_set.n_frames;
7408         }
7409     }
7410     else
7411     {
7412         *first_frame_with_data = 0;
7413         *stride_length = 1;
7414         *n_frames = 1;
7415     }
7416
7417     if (*dependency & TNG_PARTICLE_DEPENDENT)
7418     {
7419         memcpy(num_first_particle, contents+*offset,
7420                sizeof(*num_first_particle));
7421         if(tng_data->input_endianness_swap_func_64)
7422         {
7423             if(tng_data->input_endianness_swap_func_64(tng_data,
7424                                                        num_first_particle)
7425                 != TNG_SUCCESS)
7426             {
7427                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7428                         __FILE__, __LINE__);
7429             }
7430         }
7431         *offset += sizeof(*num_first_particle);
7432
7433         memcpy(block_n_particles, contents+*offset,
7434             sizeof(*block_n_particles));
7435         if(tng_data->input_endianness_swap_func_64)
7436         {
7437             if(tng_data->input_endianness_swap_func_64(tng_data,
7438                                                        block_n_particles)
7439                 != TNG_SUCCESS)
7440             {
7441                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
7442                         __FILE__, __LINE__);
7443             }
7444         }
7445         *offset += sizeof(*block_n_particles);
7446     }
7447
7448     if(!block->block_contents)
7449     {
7450         free(contents);
7451     }
7452     return(TNG_SUCCESS);
7453 }
7454
7455 /** Read the contents of a data block (particle or non-particle data).
7456  * @param tng_data is a trajectory data container.
7457  * @param block is the block to store the data (should already contain
7458  * the block headers).
7459  * @param hash_mode is an option to decide whether to use the md5 hash or not.
7460  * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
7461  * compared to the md5 hash of the read contents to ensure valid data.
7462  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7463  * error has occured.
7464  */
7465 static tng_function_status tng_data_block_contents_read
7466                 (tng_trajectory_t tng_data,
7467                  tng_gen_block_t block,
7468                  const char hash_mode)
7469 {
7470     int64_t n_values, codec_id, n_frames, first_frame_with_data;
7471     int64_t stride_length, block_n_particles, num_first_particle;
7472     double multiplier;
7473     char datatype, dependency, sparse_data;
7474     int offset = 0;
7475     tng_bool same_hash;
7476
7477     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
7478     {
7479         return(TNG_CRITICAL);
7480     }
7481
7482     if(block->block_contents)
7483     {
7484         free(block->block_contents);
7485     }
7486
7487     block->block_contents = malloc(block->block_contents_size);
7488     if(!block->block_contents)
7489     {
7490         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
7491                block->block_contents_size, __FILE__, __LINE__);
7492         return(TNG_CRITICAL);
7493     }
7494
7495     /* Read the whole block into block_contents to be able to write it to
7496      * disk even if it cannot be interpreted. */
7497     if(fread(block->block_contents, block->block_contents_size, 1,
7498              tng_data->input_file) == 0)
7499     {
7500         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
7501         return(TNG_CRITICAL);
7502     }
7503
7504     /* FIXME: Does not check if the size of the contents matches the expected
7505      * size or if the contents can be read. */
7506
7507     if(hash_mode == TNG_USE_HASH)
7508     {
7509         tng_md5_hash_match_verify(block, &same_hash);
7510         if(same_hash != TNG_TRUE)
7511         {
7512             fprintf(stderr, "TNG library: '%s' data block contents corrupt. Hashes do not match. %s: %d\n",
7513                 block->name, __FILE__, __LINE__);
7514     /*         return(TNG_FAILURE); */
7515         }
7516     }
7517
7518     if(tng_data_block_meta_information_read(tng_data, block,
7519                                             &offset, &datatype,
7520                                             &dependency, &sparse_data,
7521                                             &n_values, &codec_id,
7522                                             &first_frame_with_data,
7523                                             &stride_length, &n_frames,
7524                                             &num_first_particle,
7525                                             &block_n_particles,
7526                                             &multiplier) == TNG_CRITICAL)
7527     {
7528         fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
7529             block->name, __FILE__, __LINE__);
7530         return(TNG_CRITICAL);
7531     }
7532
7533     if (dependency & TNG_PARTICLE_DEPENDENT)
7534     {
7535         return(tng_particle_data_read(tng_data, block,
7536                                       &offset, datatype,
7537                                       num_first_particle,
7538                                       block_n_particles,
7539                                       first_frame_with_data,
7540                                       stride_length,
7541                                       n_frames, n_values,
7542                                       codec_id, multiplier));
7543     }
7544     else
7545     {
7546         return(tng_data_read(tng_data, block,
7547                              &offset, datatype,
7548                              first_frame_with_data,
7549                              stride_length,
7550                              n_frames, n_values,
7551                              codec_id, multiplier));
7552     }
7553 }
7554
7555 /*
7556 // ** Move the blocks in a frame set so that there is no unused space between
7557 //  * them. This can only be done on the last frame set in the file and should
7558 //  * be done e.g. if the last frame set in the file has fewer frames than
7559 //  * default or after compressing data blocks in a frame set.
7560 //  * @param tng_data is a trajectory data container.
7561 //  * @details the current_trajectory_frame_set is the one that will be modified.
7562 //  * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
7563 //  * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
7564 //  * FIXME: This function is not finished!!!
7565 //  *
7566 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
7567 // {
7568 //     tng_gen_block_t block;
7569 //     tng_trajectory_frame_set_t frame_set;
7570 //     FILE *temp = tng_data->input_file;
7571 //     int64_t pos, contents_start_pos, output_file_len;
7572 //
7573 //     frame_set = &tng_data->current_trajectory_frame_set;
7574 //
7575 //     if(frame_set->n_written_frames == frame_set->n_frames)
7576 //     {
7577 //         return(TNG_SUCCESS);
7578 //     }
7579 //
7580 //     if(tng_data->current_trajectory_frame_set_output_file_pos !=
7581 //        tng_data->last_trajectory_frame_set_output_file_pos)
7582 //     {
7583 //     }
7584 //
7585 //     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7586 //     {
7587 //         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7588 //                __FILE__, __LINE__);
7589 //         return(TNG_CRITICAL);
7590 //     }
7591 //
7592 //     tng_block_init(&block);
7593 // //     output_file_pos = ftello(tng_data->output_file);
7594 //
7595 //     tng_data->input_file = tng_data->output_file;
7596 //
7597 //     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7598 //
7599 //     fseeko(tng_data->output_file, pos, SEEK_SET);
7600 //     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7601 //     {
7602 //         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7603 //             __FILE__, __LINE__);
7604 //         tng_data->input_file = temp;
7605 //         tng_block_destroy(&block);
7606 //         return(TNG_CRITICAL);
7607 //     }
7608 //
7609 //     contents_start_pos = ftello(tng_data->output_file);
7610 //
7611 //     fseeko(tng_data->output_file, 0, SEEK_END);
7612 //     output_file_len = ftello(tng_data->output_file);
7613 //     pos = contents_start_pos + block->block_contents_size;
7614 //     fseeko(tng_data->output_file, pos,
7615 //           SEEK_SET);
7616 //
7617 //     while(pos < output_file_len)
7618 //     {
7619 //         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7620 //         {
7621 //             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7622 //                    __FILE__, __LINE__);
7623 //             tng_data->input_file = temp;
7624 //             tng_block_destroy(&block);
7625 //             return(TNG_CRITICAL);
7626 //         }
7627 //         pos += block->header_contents_size + block->block_contents_size;
7628 //         fseeko(tng_data->output_file, pos, SEEK_SET);
7629 //     }
7630 //
7631 //     return(TNG_SUCCESS);
7632 // }
7633 */
7634 /** Finish writing the current frame set. Update the number of frames
7635  * and the hashes of the frame set and all its data blocks (if hash_mode
7636  * == TNG_USE_HASH).
7637  * @param tng_data is a trajectory data container.
7638  * @param hash_mode specifies whether to update the block md5 hash when
7639  * updating the pointers.
7640  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7641  * error has occured.
7642  */
7643 static tng_function_status tng_frame_set_finalize
7644                 (tng_trajectory_t tng_data, const char hash_mode)
7645 {
7646     tng_gen_block_t block;
7647     tng_trajectory_frame_set_t frame_set;
7648     FILE *temp = tng_data->input_file;
7649     int64_t pos, contents_start_pos, output_file_len;
7650
7651     frame_set = &tng_data->current_trajectory_frame_set;
7652
7653     if(frame_set->n_written_frames == frame_set->n_frames)
7654     {
7655         return(TNG_SUCCESS);
7656     }
7657
7658     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
7659     {
7660         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
7661                __FILE__, __LINE__);
7662         return(TNG_CRITICAL);
7663     }
7664
7665     tng_block_init(&block);
7666 /*     output_file_pos = ftello(tng_data->output_file); */
7667
7668     tng_data->input_file = tng_data->output_file;
7669
7670     pos = tng_data->current_trajectory_frame_set_output_file_pos;
7671
7672     fseeko(tng_data->output_file, pos, SEEK_SET);
7673
7674     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7675     {
7676         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
7677             __FILE__, __LINE__);
7678         tng_data->input_file = temp;
7679         tng_block_destroy(&block);
7680         return(TNG_CRITICAL);
7681     }
7682
7683     contents_start_pos = ftello(tng_data->output_file);
7684
7685     fseeko(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
7686     if(fwrite(&frame_set->n_written_frames, sizeof(frame_set->n_frames),
7687               1, tng_data->output_file) != 1)
7688     {
7689         tng_data->input_file = temp;
7690         tng_block_destroy(&block);
7691         return(TNG_CRITICAL);
7692     }
7693
7694
7695     if(hash_mode == TNG_USE_HASH)
7696     {
7697         tng_md5_hash_update(tng_data, block, pos,
7698                             pos + block->header_contents_size);
7699     }
7700
7701     fseeko(tng_data->output_file, 0, SEEK_END);
7702     output_file_len = ftello(tng_data->output_file);
7703     pos = contents_start_pos + block->block_contents_size;
7704     fseeko(tng_data->output_file, pos, SEEK_SET);
7705
7706     while(pos < output_file_len)
7707     {
7708         if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
7709         {
7710             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
7711                    __FILE__, __LINE__);
7712             tng_data->input_file = temp;
7713             tng_block_destroy(&block);
7714             return(TNG_CRITICAL);
7715         }
7716
7717         if(hash_mode == TNG_USE_HASH)
7718         {
7719             tng_md5_hash_update(tng_data, block, pos,
7720                                 pos + block->header_contents_size);
7721         }
7722         pos += block->header_contents_size + block->block_contents_size;
7723         fseeko(tng_data->output_file, pos, SEEK_SET);
7724     }
7725
7726     tng_data->input_file = temp;
7727     tng_block_destroy(&block);
7728     return(TNG_SUCCESS);
7729 }
7730
7731 /*
7732 // ** Sets the name of a file contents block
7733 //  * @param tng_data is a trajectory data container.
7734 //  * @param block is the block, of which to change names.
7735 //  * @param new_name is the new name of the block.
7736 //  * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
7737 //  * error has occured.
7738 //
7739 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
7740 //                                               tng_gen_block_t block,
7741 //                                               const char *new_name)
7742 // {
7743 //     int len;
7744 //
7745 //     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7746 //
7747 //      * If the currently stored string length is not enough to store the new
7748 //      * string it is freed and reallocated. *
7749 //     if(block->name && strlen(block->name) < len)
7750 //     {
7751 //         free(block->name);
7752 //         block->name = 0;
7753 //     }
7754 //     if(!block->name)
7755 //     {
7756 //         block->name = malloc(len);
7757 //         if(!block->name)
7758 //         {
7759 //             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
7760 //                    __FILE__, __LINE__);
7761 //             return(TNG_CRITICAL);
7762 //         }
7763 //     }
7764 //
7765 //     strncpy(block->name, new_name, len);
7766 //
7767 //     return(TNG_SUCCESS);
7768 // }
7769 */
7770
7771 tng_function_status tng_atom_residue_get(const tng_trajectory_t tng_data,
7772                                          const tng_atom_t atom,
7773                                          tng_residue_t *residue)
7774 {
7775     (void) tng_data;
7776
7777     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7778
7779     *residue = atom->residue;
7780
7781     return(TNG_SUCCESS);
7782 }
7783
7784 tng_function_status tng_atom_name_get(const tng_trajectory_t tng_data,
7785                                       const tng_atom_t atom,
7786                                       char *name,
7787                                       const int max_len)
7788 {
7789     (void) tng_data;
7790     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7791     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7792
7793     strncpy(name, atom->name, max_len - 1);
7794     name[max_len - 1] = 0;
7795
7796     if(strlen(atom->name) > (unsigned int)max_len - 1)
7797     {
7798         return(TNG_FAILURE);
7799     }
7800     return(TNG_SUCCESS);
7801 }
7802
7803 tng_function_status tng_atom_name_set(tng_trajectory_t tng_data,
7804                                       tng_atom_t atom,
7805                                       const char *new_name)
7806 {
7807     unsigned int len;
7808     (void)tng_data;
7809
7810     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7811     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7812
7813     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
7814
7815     /* If the currently stored string length is not enough to store the new
7816      * string it is freed and reallocated. */
7817     if(atom->name && strlen(atom->name) < len)
7818     {
7819         free(atom->name);
7820         atom->name = 0;
7821     }
7822     if(!atom->name)
7823     {
7824         atom->name = malloc(len);
7825         if(!atom->name)
7826         {
7827             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7828                    __FILE__, __LINE__);
7829             return(TNG_CRITICAL);
7830         }
7831     }
7832
7833     strncpy(atom->name, new_name, len);
7834
7835     return(TNG_SUCCESS);
7836 }
7837
7838 tng_function_status tng_atom_type_get(const tng_trajectory_t tng_data,
7839                                       const tng_atom_t atom,
7840                                       char *type,
7841                                       const int max_len)
7842 {
7843     (void) tng_data;
7844     TNG_ASSERT(atom, "TNG library: atom must not be NULL");
7845     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
7846
7847     strncpy(type, atom->atom_type, max_len - 1);
7848     type[max_len - 1] = 0;
7849
7850     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
7851     {
7852         return(TNG_FAILURE);
7853     }
7854     return(TNG_SUCCESS);
7855 }
7856
7857 tng_function_status tng_atom_type_set(tng_trajectory_t tng_data,
7858                                       tng_atom_t atom,
7859                                       const char *new_type)
7860 {
7861     unsigned int len;
7862     (void)tng_data;
7863
7864     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7865     TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
7866
7867     len = tng_min_i((int)strlen(new_type) + 1, TNG_MAX_STR_LEN);
7868
7869     /* If the currently stored string length is not enough to store the new
7870      * string it is freed and reallocated. */
7871     if(atom->atom_type && strlen(atom->atom_type) < len)
7872     {
7873         free(atom->atom_type);
7874         atom->atom_type = 0;
7875     }
7876     if(!atom->atom_type)
7877     {
7878         atom->atom_type = malloc(len);
7879         if(!atom->atom_type)
7880         {
7881             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
7882                    __FILE__, __LINE__);
7883             return(TNG_CRITICAL);
7884         }
7885     }
7886
7887     strncpy(atom->atom_type, new_type, len);
7888
7889     return(TNG_SUCCESS);
7890 }
7891
7892 /** Initialise an atom struct
7893  * @param atom is the atom to initialise.
7894  * @return TNG_SUCCESS (0) if successful.
7895  */
7896 static tng_function_status tng_atom_init(tng_atom_t atom)
7897 {
7898     atom->name = 0;
7899     atom->atom_type = 0;
7900
7901     return(TNG_SUCCESS);
7902 }
7903
7904 /** Free the memory in an atom struct
7905  * @param atom is the atom to destroy.
7906  * @return TNG_SUCCESS (0) if successful.
7907  */
7908 static tng_function_status tng_atom_destroy(tng_atom_t atom)
7909 {
7910     if(atom->name)
7911     {
7912         free(atom->name);
7913         atom->name = 0;
7914     }
7915     if(atom->atom_type)
7916     {
7917         free(atom->atom_type);
7918         atom->atom_type = 0;
7919     }
7920
7921     return(TNG_SUCCESS);
7922 }
7923
7924 tng_function_status DECLSPECDLLEXPORT tng_version_major
7925                 (const tng_trajectory_t tng_data,
7926                  int *version)
7927 {
7928     (void)tng_data;
7929
7930     *version = TNG_VERSION_MAJOR;
7931
7932     return(TNG_SUCCESS);
7933 }
7934
7935 tng_function_status DECLSPECDLLEXPORT tng_version_minor
7936                 (const tng_trajectory_t tng_data,
7937                  int *version)
7938 {
7939     (void)tng_data;
7940
7941     *version = TNG_VERSION_MINOR;
7942
7943     return(TNG_SUCCESS);
7944 }
7945
7946 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
7947                 (const tng_trajectory_t tng_data,
7948                  int *patch_level)
7949 {
7950     (void)tng_data;
7951
7952     *patch_level = TNG_VERSION_PATCHLEVEL;
7953
7954     return(TNG_SUCCESS);
7955 }
7956
7957 tng_function_status DECLSPECDLLEXPORT tng_version
7958                 (const tng_trajectory_t tng_data,
7959                  char *version,
7960                  const int max_len)
7961 {
7962     (void)tng_data;
7963     TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
7964
7965     TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
7966
7967     return(TNG_SUCCESS);
7968 }
7969
7970 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
7971                 (tng_trajectory_t tng_data,
7972                  const char *name,
7973                  tng_molecule_t *molecule)
7974 {
7975     int64_t id;
7976
7977     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7978     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7979
7980     /* Set ID to the ID of the last molecule + 1 */
7981     if(tng_data->n_molecules)
7982     {
7983         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7984     }
7985     else
7986     {
7987         id = 1;
7988     }
7989
7990     return(tng_molecule_w_id_add(tng_data, name, id, molecule));
7991 }
7992
7993 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
7994                 (tng_trajectory_t tng_data,
7995                  const char *name,
7996                  const int64_t id,
7997                  tng_molecule_t *molecule)
7998 {
7999     tng_molecule_t new_molecules;
8000     int64_t *new_molecule_cnt_list;
8001     tng_function_status stat = TNG_SUCCESS;
8002
8003     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8004     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8005
8006     new_molecules = realloc(tng_data->molecules,
8007                             sizeof(struct tng_molecule) *
8008                             (tng_data->n_molecules + 1));
8009
8010     if(!new_molecules)
8011     {
8012         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8013                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
8014                __FILE__, __LINE__);
8015         free(tng_data->molecules);
8016         tng_data->molecules = 0;
8017         return(TNG_CRITICAL);
8018     }
8019
8020     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
8021                                     sizeof(int64_t) *
8022                                     (tng_data->n_molecules + 1));
8023
8024     if(!new_molecule_cnt_list)
8025     {
8026         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8027                sizeof(int64_t) * (tng_data->n_molecules + 1),
8028                __FILE__, __LINE__);
8029         free(tng_data->molecule_cnt_list);
8030         tng_data->molecule_cnt_list = 0;
8031         free(new_molecules);
8032         return(TNG_CRITICAL);
8033     }
8034
8035     tng_data->molecules = new_molecules;
8036     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8037
8038     *molecule = &new_molecules[tng_data->n_molecules];
8039
8040     tng_molecule_init(tng_data, *molecule);
8041     tng_molecule_name_set(tng_data, *molecule, name);
8042
8043     /* FIXME: Should this be a function argument instead? */
8044     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8045
8046     (*molecule)->id = id;
8047
8048     tng_data->n_molecules++;
8049
8050     return(stat);
8051 }
8052
8053 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
8054                 (tng_trajectory_t tng_data,
8055                  tng_molecule_t *molecule_p)
8056 {
8057     int64_t *new_molecule_cnt_list, id;
8058     tng_molecule_t new_molecules, molecule;
8059
8060     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8061
8062     /* Set ID to the ID of the last molecule + 1 */
8063     if(tng_data->n_molecules)
8064     {
8065         id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
8066     }
8067     else
8068     {
8069         id = 1;
8070     }
8071
8072     new_molecules = realloc(tng_data->molecules,
8073                             sizeof(struct tng_molecule) *
8074                             (tng_data->n_molecules + 1));
8075
8076     if(!new_molecules)
8077     {
8078         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8079                sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
8080                __FILE__, __LINE__);
8081         free(tng_data->molecules);
8082         tng_data->molecules = 0;
8083         return(TNG_CRITICAL);
8084     }
8085
8086     new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
8087                                     sizeof(int64_t) *
8088                                     (tng_data->n_molecules + 1));
8089
8090     if(!new_molecule_cnt_list)
8091     {
8092         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8093                sizeof(int64_t) * (tng_data->n_molecules + 1),
8094                __FILE__, __LINE__);
8095         free(tng_data->molecule_cnt_list);
8096         tng_data->molecule_cnt_list = 0;
8097         free(new_molecules);
8098         return(TNG_CRITICAL);
8099     }
8100
8101     molecule = *molecule_p;
8102
8103     tng_data->molecules = new_molecules;
8104     tng_data->molecule_cnt_list = new_molecule_cnt_list;
8105
8106     new_molecules[tng_data->n_molecules] = *molecule;
8107
8108     tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
8109
8110     free(*molecule_p);
8111
8112     molecule = &new_molecules[tng_data->n_molecules];
8113
8114     *molecule_p = molecule;
8115
8116     molecule->id = id;
8117
8118     tng_data->n_molecules++;
8119
8120     return(TNG_SUCCESS);
8121 }
8122
8123 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
8124                                           const tng_molecule_t molecule,
8125                                           char *name,
8126                                           const int max_len)
8127 {
8128     (void) tng_data;
8129     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8130     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8131
8132     strncpy(name, molecule->name, max_len - 1);
8133     name[max_len - 1] = 0;
8134
8135     if(strlen(molecule->name) > (unsigned int)max_len - 1)
8136     {
8137         return(TNG_FAILURE);
8138     }
8139     return(TNG_SUCCESS);
8140 }
8141
8142 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
8143                 (tng_trajectory_t tng_data,
8144                  tng_molecule_t molecule,
8145                  const char *new_name)
8146 {
8147     unsigned int len;
8148     (void)tng_data;
8149
8150     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8151     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8152
8153     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8154
8155     /* If the currently stored string length is not enough to store the new
8156      * string it is freed and reallocated. */
8157     if(molecule->name && strlen(molecule->name) < len)
8158     {
8159         free(molecule->name);
8160         molecule->name = 0;
8161     }
8162     if(!molecule->name)
8163     {
8164         molecule->name = malloc(len);
8165         if(!molecule->name)
8166         {
8167             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8168                    __FILE__, __LINE__);
8169             return(TNG_CRITICAL);
8170         }
8171     }
8172
8173     strncpy(molecule->name, new_name, len);
8174
8175     return(TNG_SUCCESS);
8176 }
8177
8178 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
8179                 (const tng_trajectory_t tng_data,
8180                  const tng_molecule_t molecule,
8181                  int64_t *cnt)
8182 {
8183     int64_t i, index = -1;
8184
8185     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8186     TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
8187
8188     for(i = 0; i < tng_data->n_molecules; i++)
8189     {
8190         if(&tng_data->molecules[i] == molecule)
8191         {
8192             index = i;
8193             break;
8194         }
8195     }
8196     if(index == -1)
8197     {
8198         return(TNG_FAILURE);
8199     }
8200     *cnt = tng_data->molecule_cnt_list[index];
8201
8202     return(TNG_SUCCESS);
8203 }
8204
8205 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
8206                 (tng_trajectory_t tng_data,
8207                  tng_molecule_t molecule,
8208                  const int64_t cnt)
8209 {
8210     int64_t i, old_cnt, index = -1;
8211
8212     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8213
8214     for(i = 0; i < tng_data->n_molecules; i++)
8215     {
8216         if(&tng_data->molecules[i] == molecule)
8217         {
8218             index = i;
8219             break;
8220         }
8221     }
8222     if(index == -1)
8223     {
8224         fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
8225                __FILE__, __LINE__);
8226         return(TNG_FAILURE);
8227     }
8228     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
8229     {
8230         old_cnt = tng_data->molecule_cnt_list[index];
8231         tng_data->molecule_cnt_list[index] = cnt;
8232
8233         tng_data->n_particles += (cnt-old_cnt) *
8234                                  tng_data->molecules[index].n_atoms;
8235     }
8236     else
8237     {
8238         old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
8239         tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
8240
8241         tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
8242                 tng_data->molecules[index].n_atoms;
8243     }
8244
8245     return(TNG_SUCCESS);
8246 }
8247
8248 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
8249                 (tng_trajectory_t tng_data,
8250                  const char *name,
8251                  int64_t nr,
8252                  tng_molecule_t *molecule)
8253 {
8254     int64_t i, n_molecules;
8255
8256     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8257     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8258     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8259
8260     n_molecules = tng_data->n_molecules;
8261
8262     for(i = n_molecules - 1; i >= 0; i--)
8263     {
8264         *molecule = &tng_data->molecules[i];
8265         if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
8266         {
8267             if(nr == -1 || nr == (*molecule)->id)
8268             {
8269                 return(TNG_SUCCESS);
8270             }
8271         }
8272     }
8273
8274     *molecule = 0;
8275
8276     return(TNG_FAILURE);
8277 }
8278
8279 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
8280                 (tng_trajectory_t tng_data,
8281                  int64_t index,
8282                  tng_molecule_t *molecule)
8283 {
8284     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8285     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8286
8287     if(index >= tng_data->n_molecules)
8288     {
8289         *molecule = 0;
8290         return(TNG_FAILURE);
8291     }
8292     *molecule = &tng_data->molecules[index];
8293     return(TNG_SUCCESS);
8294 }
8295
8296 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(tng_trajectory_t tng_data_src,
8297                                                                tng_trajectory_t tng_data_dest)
8298 {
8299     tng_molecule_t molecule, molecule_temp;
8300     tng_chain_t chain, chain_temp;
8301     tng_residue_t residue, residue_temp;
8302     tng_atom_t atom, atom_temp;
8303     tng_bond_t bond_temp;
8304     tng_function_status stat;
8305     int64_t i, j, k, l, *list_temp;
8306
8307     TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
8308     TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
8309
8310     for(i = 0; i < tng_data_dest->n_molecules; i++)
8311     {
8312         molecule = &tng_data_dest->molecules[i];
8313         tng_molecule_destroy(tng_data_dest, molecule);
8314     }
8315
8316     tng_data_dest->n_molecules = 0;
8317     tng_data_dest->n_particles = 0;
8318
8319     molecule_temp = realloc(tng_data_dest->molecules,
8320                     sizeof(struct tng_molecule) * tng_data_src->n_molecules);
8321     if(!molecule_temp)
8322     {
8323         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8324                sizeof(struct tng_molecule) * tng_data_src->n_molecules,
8325                __FILE__, __LINE__);
8326         free(tng_data_dest->molecules);
8327         tng_data_dest->molecules = 0;
8328         return(TNG_CRITICAL);
8329     }
8330     list_temp = realloc(tng_data_dest->molecule_cnt_list,
8331                                      sizeof(int64_t) * tng_data_src->n_molecules);
8332     if(!list_temp)
8333     {
8334         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8335                sizeof(int64_t) * tng_data_src->n_molecules,
8336                __FILE__, __LINE__);
8337         free(tng_data_dest->molecule_cnt_list);
8338         tng_data_dest->molecule_cnt_list = 0;
8339         free(molecule_temp);
8340         return(TNG_CRITICAL);
8341     }
8342
8343     tng_data_dest->molecules = molecule_temp;
8344     tng_data_dest->molecule_cnt_list = list_temp;
8345
8346     for(i = 0; i < tng_data_src->n_molecules; i++)
8347     {
8348         molecule = &tng_data_src->molecules[i];
8349         stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
8350                                      &molecule_temp);
8351         if(stat != TNG_SUCCESS)
8352         {
8353             fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
8354                    __FILE__, __LINE__);
8355             return(stat);
8356         }
8357         molecule_temp->quaternary_str = molecule->quaternary_str;
8358         for(j = 0; j < molecule->n_chains; j++)
8359         {
8360             chain = &molecule->chains[j];
8361             stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
8362                                                chain->name, chain->id,
8363                                                &chain_temp);
8364             if(stat != TNG_SUCCESS)
8365             {
8366                 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
8367                        __FILE__, __LINE__);
8368                 return(stat);
8369             }
8370             for(k = 0; k < chain->n_residues; k++)
8371             {
8372                 residue = &chain->residues[k];
8373                 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
8374                                                   residue->name, residue->id,
8375                                                   &residue_temp);
8376                 if(stat != TNG_SUCCESS)
8377                 {
8378                     fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
8379                            __FILE__, __LINE__);
8380                     return(stat);
8381                 }
8382                 for(l = 0; l < residue->n_atoms; l++)
8383                 {
8384                     atom = &molecule->atoms[residue->atoms_offset + l];
8385                     stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
8386                                                      atom->name, atom->atom_type,
8387                                                      atom->id, &atom_temp);
8388                     if(stat != TNG_SUCCESS)
8389                     {
8390                     fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
8391                            __FILE__, __LINE__);
8392                         return(stat);
8393                     }
8394                 }
8395             }
8396         }
8397         molecule_temp->n_bonds = molecule->n_bonds;
8398         if(molecule->n_bonds > 0)
8399         {
8400             bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
8401                                 molecule->n_bonds);
8402             if(!bond_temp)
8403             {
8404                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8405                        sizeof(struct tng_bond) * molecule->n_bonds,
8406                        __FILE__, __LINE__);
8407                 free(molecule_temp->bonds);
8408                 molecule_temp->n_bonds = 0;
8409                 return(TNG_CRITICAL);
8410             }
8411             molecule_temp->bonds = bond_temp;
8412             for(j = 0; j < molecule->n_bonds; j++)
8413             {
8414                 molecule_temp->bonds[j] = molecule->bonds[j];
8415             }
8416         }
8417         stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
8418                                     tng_data_src->molecule_cnt_list[i]);
8419         if(stat != TNG_SUCCESS)
8420         {
8421             fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
8422                    __FILE__, __LINE__);
8423             return(stat);
8424         }
8425     }
8426     return(TNG_SUCCESS);
8427 }
8428
8429 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
8430                 (const tng_trajectory_t tng_data,
8431                  const tng_molecule_t molecule,
8432                  int64_t *n)
8433 {
8434     (void) tng_data;
8435     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8436     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8437
8438     *n = molecule->n_chains;
8439
8440     return(TNG_SUCCESS);
8441 }
8442
8443 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
8444                 (tng_trajectory_t tng_data,
8445                  tng_molecule_t molecule,
8446                  int64_t index,
8447                  tng_chain_t *chain)
8448 {
8449     (void) tng_data;
8450     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8451     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8452
8453     if(index >= molecule->n_chains)
8454     {
8455         *chain = 0;
8456         return(TNG_FAILURE);
8457     }
8458     *chain = &molecule->chains[index];
8459     return(TNG_SUCCESS);
8460 }
8461
8462 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
8463                 (const tng_trajectory_t tng_data,
8464                  const tng_molecule_t molecule,
8465                  int64_t *n)
8466 {
8467     (void) tng_data;
8468     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8469     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8470
8471     *n = molecule->n_residues;
8472
8473     return(TNG_SUCCESS);
8474 }
8475
8476 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
8477                 (const tng_trajectory_t tng_data,
8478                  const tng_molecule_t molecule,
8479                  const int64_t index,
8480                  tng_residue_t *residue)
8481 {
8482     (void) tng_data;
8483     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8484     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8485
8486     if(index >= molecule->n_residues)
8487     {
8488         *residue = 0;
8489         return(TNG_FAILURE);
8490     }
8491     *residue = &molecule->residues[index];
8492     return(TNG_SUCCESS);
8493 }
8494
8495 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
8496                 (const tng_trajectory_t tng_data,
8497                  const tng_molecule_t molecule,
8498                  int64_t *n)
8499 {
8500     (void) tng_data;
8501     TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
8502     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8503
8504     *n = molecule->n_atoms;
8505
8506     return(TNG_SUCCESS);
8507 }
8508
8509 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
8510                 (const tng_trajectory_t tng_data,
8511                  const tng_molecule_t molecule,
8512                  const int64_t index,
8513                  tng_atom_t *atom)
8514 {
8515     (void) tng_data;
8516     TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
8517     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
8518
8519     if(index >= molecule->n_atoms)
8520     {
8521         *atom = 0;
8522         return(TNG_FAILURE);
8523     }
8524     *atom = &molecule->atoms[index];
8525     return(TNG_SUCCESS);
8526 }
8527
8528 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
8529                 (tng_trajectory_t tng_data,
8530                  tng_molecule_t molecule,
8531                  const char *name,
8532                  int64_t nr,
8533                  tng_chain_t *chain)
8534 {
8535     int64_t i, n_chains;
8536     (void)tng_data;
8537
8538     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8539     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8540
8541     n_chains = molecule->n_chains;
8542
8543     for(i = n_chains - 1; i >= 0; i--)
8544     {
8545         *chain = &molecule->chains[i];
8546         if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
8547         {
8548             if(nr == -1 || nr == (*chain)->id)
8549             {
8550                 return(TNG_SUCCESS);
8551             }
8552         }
8553     }
8554
8555     *chain = 0;
8556
8557     return(TNG_FAILURE);
8558 }
8559
8560 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
8561                 (tng_trajectory_t tng_data,
8562                  tng_molecule_t molecule,
8563                  const char *name,
8564                  tng_chain_t *chain)
8565 {
8566     int64_t id;
8567
8568     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8569     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8570
8571     /* Set ID to the ID of the last chain + 1 */
8572     if(molecule->n_chains)
8573     {
8574         id = molecule->chains[molecule->n_chains-1].id + 1;
8575     }
8576     else
8577     {
8578         id = 1;
8579     }
8580
8581     return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
8582                                        id, chain));
8583 }
8584
8585 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
8586                 (tng_trajectory_t tng_data,
8587                  tng_molecule_t molecule,
8588                  const char *name,
8589                  const int64_t id,
8590                  tng_chain_t *chain)
8591 {
8592     tng_chain_t new_chains;
8593     tng_function_status stat = TNG_SUCCESS;
8594
8595     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8596     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8597
8598     new_chains = realloc(molecule->chains,
8599                          sizeof(struct tng_chain) *
8600                          (molecule->n_chains + 1));
8601
8602     if(!new_chains)
8603     {
8604         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8605                sizeof(struct tng_chain) * (molecule->n_chains + 1),
8606                __FILE__, __LINE__);
8607         free(molecule->chains);
8608         molecule->chains = 0;
8609         return(TNG_CRITICAL);
8610     }
8611
8612     molecule->chains = new_chains;
8613
8614     *chain = &new_chains[molecule->n_chains];
8615     (*chain)->name = 0;
8616
8617     tng_chain_name_set(tng_data, *chain, name);
8618
8619     (*chain)->molecule = molecule;
8620     (*chain)->n_residues = 0;
8621
8622     molecule->n_chains++;
8623
8624     (*chain)->id = id;
8625
8626     return(stat);
8627 }
8628
8629 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
8630                 (const tng_trajectory_t tng_data,
8631                  tng_molecule_t molecule,
8632                  const int64_t from_atom_id,
8633                  const int64_t to_atom_id,
8634                  tng_bond_t *bond)
8635 {
8636     tng_bond_t new_bonds;
8637     (void)tng_data;
8638
8639     new_bonds = realloc(molecule->bonds,
8640                         sizeof(struct tng_bond) *
8641                         (molecule->n_bonds + 1));
8642
8643     if(!new_bonds)
8644     {
8645         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8646                sizeof(struct tng_bond) * (molecule->n_bonds + 1),
8647                __FILE__, __LINE__);
8648         *bond = 0;
8649         free(molecule->bonds);
8650         molecule->bonds = 0;
8651         return(TNG_CRITICAL);
8652     }
8653
8654     molecule->bonds = new_bonds;
8655
8656     *bond = &new_bonds[molecule->n_bonds];
8657
8658     (*bond)->from_atom_id = from_atom_id;
8659     (*bond)->to_atom_id = to_atom_id;
8660
8661     molecule->n_bonds++;
8662
8663     return(TNG_SUCCESS);
8664 }
8665
8666 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
8667                 (tng_trajectory_t tng_data,
8668                  tng_molecule_t molecule,
8669                  const char *name,
8670                  int64_t id,
8671                  tng_atom_t *atom)
8672 {
8673     int64_t i, n_atoms;
8674     (void)tng_data;
8675
8676     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8677
8678     n_atoms = molecule->n_atoms;
8679
8680     for(i = n_atoms - 1; i >= 0; i--)
8681     {
8682         *atom = &molecule->atoms[i];
8683         if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
8684         {
8685             if(id == -1 || id == (*atom)->id)
8686             {
8687                 return(TNG_SUCCESS);
8688             }
8689         }
8690     }
8691
8692     *atom = 0;
8693
8694     return(TNG_FAILURE);
8695 }
8696
8697 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
8698                                        const tng_chain_t chain,
8699                                        char *name,
8700                                        const int max_len)
8701 {
8702     (void) tng_data;
8703     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8704     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8705
8706     strncpy(name, chain->name, max_len - 1);
8707     name[max_len - 1] = 0;
8708
8709     if(strlen(chain->name) > (unsigned int)max_len - 1)
8710     {
8711         return(TNG_FAILURE);
8712     }
8713     return(TNG_SUCCESS);
8714 }
8715
8716 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
8717                 (tng_trajectory_t tng_data,
8718                  tng_chain_t chain,
8719                  const char *new_name)
8720 {
8721     unsigned int len;
8722     (void)tng_data;
8723
8724     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
8725
8726     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8727
8728     /* If the currently stored string length is not enough to store the new
8729      * string it is freed and reallocated. */
8730     if(chain->name && strlen(chain->name) < len)
8731     {
8732         free(chain->name);
8733         chain->name = 0;
8734     }
8735     if(!chain->name)
8736     {
8737         chain->name = malloc(len);
8738         if(!chain->name)
8739         {
8740             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8741                    __FILE__, __LINE__);
8742             return(TNG_CRITICAL);
8743         }
8744     }
8745
8746     strncpy(chain->name, new_name, len);
8747
8748     return(TNG_SUCCESS);
8749 }
8750
8751 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
8752                 (const tng_trajectory_t tng_data,
8753                  const tng_chain_t chain,
8754                  int64_t *n)
8755 {
8756     (void) tng_data;
8757     TNG_ASSERT(chain, "TNG library: chain must not be NULL");
8758     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8759
8760     *n = chain->n_residues;
8761
8762     return(TNG_SUCCESS);
8763 }
8764
8765 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
8766                 (const tng_trajectory_t tng_data,
8767                  const tng_chain_t chain,
8768                  const int64_t index,
8769                  tng_residue_t *residue)
8770 {
8771     (void) tng_data;
8772     TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
8773     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
8774
8775     if(index >= chain->n_residues)
8776     {
8777         *residue = 0;
8778         return(TNG_FAILURE);
8779     }
8780     *residue = &chain->residues[index];
8781     return(TNG_SUCCESS);
8782 }
8783
8784 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
8785                 (tng_trajectory_t tng_data,
8786                  tng_chain_t chain,
8787                  const char *name,
8788                  int64_t id,
8789                  tng_residue_t *residue)
8790 {
8791     int64_t i, n_residues;
8792     (void)tng_data;
8793
8794     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8795
8796     n_residues = chain->n_residues;
8797
8798     for(i = n_residues - 1; i >= 0; i--)
8799     {
8800         *residue = &chain->residues[i];
8801         if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
8802         {
8803             if(id == -1 || id == (*residue)->id)
8804             {
8805                 return(TNG_SUCCESS);
8806             }
8807         }
8808     }
8809
8810     *residue = 0;
8811
8812     return(TNG_FAILURE);
8813 }
8814
8815 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
8816                 (tng_trajectory_t tng_data,
8817                  tng_chain_t chain,
8818                  const char *name,
8819                  tng_residue_t *residue)
8820 {
8821     int64_t id;
8822
8823     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8824     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8825
8826     /* Set ID to the ID of the last residue + 1 */
8827     if(chain->n_residues)
8828     {
8829         id = chain->residues[chain->n_residues-1].id + 1;
8830     }
8831     else
8832     {
8833         id = 0;
8834     }
8835
8836     return(tng_chain_residue_w_id_add(tng_data, chain, name,
8837                                       id, residue));
8838 }
8839
8840 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
8841                 (tng_trajectory_t tng_data,
8842                  tng_chain_t chain,
8843                  const char *name,
8844                  const int64_t id,
8845                  tng_residue_t *residue)
8846 {
8847     int64_t curr_index;
8848     tng_residue_t new_residues, temp_residue, last_residue;
8849     tng_molecule_t molecule = chain->molecule;
8850     tng_function_status stat = TNG_SUCCESS;
8851
8852     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8853     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8854
8855     if(chain->n_residues)
8856     {
8857         curr_index = chain->residues - molecule->residues;
8858     }
8859     else
8860     {
8861         curr_index = -1;
8862     }
8863
8864     new_residues = realloc(molecule->residues,
8865                            sizeof(struct tng_residue) *
8866                            (molecule->n_residues + 1));
8867
8868     if(!new_residues)
8869     {
8870         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
8871                sizeof(struct tng_residue) * (molecule->n_residues + 1),
8872                __FILE__, __LINE__);
8873         free(molecule->residues);
8874         molecule->residues = 0;
8875         return(TNG_CRITICAL);
8876     }
8877
8878     molecule->residues = new_residues;
8879
8880     if(curr_index != -1)
8881     {
8882         chain->residues = new_residues + curr_index;
8883         if(molecule->n_residues)
8884         {
8885             last_residue = &new_residues[molecule->n_residues - 1];
8886
8887             temp_residue = chain->residues + (chain->n_residues - 1);
8888             /* Make space in list of residues to add the new residues together with the other
8889             * residues of this chain */
8890             if(temp_residue != last_residue)
8891             {
8892                 ++temp_residue;
8893                 memmove(temp_residue + 1, temp_residue,
8894                         last_residue - temp_residue);
8895             }
8896         }
8897     }
8898     else
8899     {
8900         curr_index = molecule->n_residues;
8901     }
8902
8903     *residue = &molecule->residues[curr_index + chain->n_residues];
8904
8905     if(!chain->n_residues)
8906     {
8907         chain->residues = *residue;
8908     }
8909     else
8910     {
8911         chain->residues = &molecule->residues[curr_index];
8912     }
8913
8914     (*residue)->name = 0;
8915     tng_residue_name_set(tng_data, *residue, name);
8916
8917     (*residue)->chain = chain;
8918     (*residue)->n_atoms = 0;
8919     (*residue)->atoms_offset = 0;
8920
8921     chain->n_residues++;
8922     molecule->n_residues++;
8923
8924     (*residue)->id = id;
8925
8926     return(stat);
8927 }
8928
8929 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
8930                                          const tng_residue_t residue,
8931                                          char *name,
8932                                          const int max_len)
8933 {
8934     (void) tng_data;
8935     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8936     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
8937
8938     strncpy(name, residue->name, max_len - 1);
8939     name[max_len - 1] = 0;
8940
8941     if(strlen(residue->name) > (unsigned int)max_len - 1)
8942     {
8943         return(TNG_FAILURE);
8944     }
8945     return(TNG_SUCCESS);
8946 }
8947
8948 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(tng_trajectory_t tng_data,
8949                                                            tng_residue_t residue,
8950                                                            const char *new_name)
8951 {
8952     unsigned int len;
8953     (void)tng_data;
8954
8955     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8956     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
8957
8958     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
8959
8960     /* If the currently stored string length is not enough to store the new
8961      * string it is freed and reallocated. */
8962     if(residue->name && strlen(residue->name) < len)
8963     {
8964         free(residue->name);
8965         residue->name = 0;
8966     }
8967     if(!residue->name)
8968     {
8969         residue->name = malloc(len);
8970         if(!residue->name)
8971         {
8972             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
8973                    __FILE__, __LINE__);
8974             return(TNG_CRITICAL);
8975         }
8976     }
8977
8978     strncpy(residue->name, new_name, len);
8979
8980     return(TNG_SUCCESS);
8981 }
8982
8983 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
8984                 (const tng_trajectory_t tng_data,
8985                  const tng_residue_t residue,
8986                  int64_t *n)
8987 {
8988     (void) tng_data;
8989     TNG_ASSERT(residue, "TNG library: residue must not be NULL");
8990     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
8991
8992     *n = residue->n_atoms;
8993
8994     return(TNG_SUCCESS);
8995 }
8996
8997 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
8998                 (const tng_trajectory_t tng_data,
8999                  const tng_residue_t residue,
9000                  const int64_t index,
9001                  tng_atom_t *atom)
9002 {
9003     tng_chain_t chain;
9004     tng_molecule_t molecule;
9005
9006     (void) tng_data;
9007     TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
9008     TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
9009
9010     if(index >= residue->n_atoms)
9011     {
9012         *atom = 0;
9013         return(TNG_FAILURE);
9014     }
9015     chain = residue->chain;
9016     molecule = chain->molecule;
9017
9018     if(index + residue->atoms_offset >= molecule->n_atoms)
9019     {
9020         *atom = 0;
9021         return(TNG_FAILURE);
9022     }
9023
9024     *atom = &molecule->atoms[residue->atoms_offset + index];
9025     return(TNG_SUCCESS);
9026 }
9027
9028 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
9029                 (tng_trajectory_t tng_data,
9030                  tng_residue_t residue,
9031                  const char *atom_name,
9032                  const char *atom_type,
9033                  tng_atom_t *atom)
9034 {
9035     int64_t id;
9036
9037     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9038     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
9039     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
9040
9041     /* Set ID to the ID of the last atom + 1 */
9042     if(residue->chain->molecule->n_atoms)
9043     {
9044         id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
9045     }
9046     else
9047     {
9048         id = 0;
9049     }
9050
9051     return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
9052                                      id, atom));
9053 }
9054
9055 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
9056                 (tng_trajectory_t tng_data,
9057                  tng_residue_t residue,
9058                  const char *atom_name,
9059                  const char *atom_type,
9060                  const int64_t id,
9061                  tng_atom_t *atom)
9062 {
9063     tng_atom_t new_atoms;
9064     tng_molecule_t molecule = residue->chain->molecule;
9065     tng_function_status stat = TNG_SUCCESS;
9066
9067     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9068     TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
9069     TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
9070
9071     if(!residue->n_atoms)
9072     {
9073         residue->atoms_offset = molecule->n_atoms;
9074     }
9075
9076     new_atoms = realloc(molecule->atoms,
9077                         sizeof(struct tng_atom) *
9078                         (molecule->n_atoms + 1));
9079
9080     if(!new_atoms)
9081     {
9082         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
9083                sizeof(struct tng_atom) * (molecule->n_atoms + 1),
9084                __FILE__, __LINE__);
9085         free(molecule->atoms);
9086         molecule->atoms = 0;
9087         return(TNG_CRITICAL);
9088     }
9089
9090     molecule->atoms = new_atoms;
9091
9092     *atom = &new_atoms[molecule->n_atoms];
9093
9094     tng_atom_init(*atom);
9095     tng_atom_name_set(tng_data, *atom, atom_name);
9096     tng_atom_type_set(tng_data, *atom, atom_type);
9097
9098     (*atom)->residue = residue;
9099
9100     residue->n_atoms++;
9101     molecule->n_atoms++;
9102
9103     (*atom)->id = id;
9104
9105     return(stat);
9106 }
9107
9108 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
9109                                                          tng_molecule_t *molecule_p)
9110 {
9111     *molecule_p = malloc(sizeof(struct tng_molecule));
9112     if(!*molecule_p)
9113     {
9114         fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
9115                sizeof(struct tng_molecule), __FILE__, __LINE__);
9116         return(TNG_CRITICAL);
9117     }
9118
9119     tng_molecule_init(tng_data, *molecule_p);
9120
9121     return(TNG_SUCCESS);
9122 }
9123
9124 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
9125                                                         tng_molecule_t *molecule_p)
9126 {
9127     if(!*molecule_p)
9128     {
9129         return(TNG_SUCCESS);
9130     }
9131
9132     tng_molecule_destroy(tng_data, *molecule_p);
9133
9134     free(*molecule_p);
9135     *molecule_p = 0;
9136
9137     return(TNG_SUCCESS);
9138 }
9139
9140 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
9141                                                         tng_molecule_t molecule)
9142 {
9143     (void)tng_data;
9144     molecule->quaternary_str = 1;
9145     molecule->name = 0;
9146     molecule->n_chains = 0;
9147     molecule->chains = 0;
9148     molecule->n_residues = 0;
9149     molecule->residues = 0;
9150     molecule->n_atoms = 0;
9151     molecule->atoms = 0;
9152     molecule->n_bonds = 0;
9153     molecule->bonds = 0;
9154
9155     return(TNG_SUCCESS);
9156 }
9157
9158 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
9159                                                            tng_molecule_t molecule)
9160 {
9161     int64_t i;
9162     (void)tng_data;
9163
9164     if(molecule->name)
9165     {
9166         free(molecule->name);
9167         molecule->name = 0;
9168     }
9169
9170     if(molecule->chains)
9171     {
9172         for(i = 0; i < molecule->n_chains; i++)
9173         {
9174             if(molecule->chains[i].name)
9175             {
9176                 free(molecule->chains[i].name);
9177                 molecule->chains[i].name = 0;
9178             }
9179         }
9180         free(molecule->chains);
9181         molecule->chains = 0;
9182     }
9183     molecule->n_chains = 0;
9184
9185     if(molecule->residues)
9186     {
9187         for(i = 0; i < molecule->n_residues; i++)
9188         {
9189             if(molecule->residues[i].name)
9190             {
9191                 free(molecule->residues[i].name);
9192                 molecule->residues[i].name = 0;
9193             }
9194         }
9195         free(molecule->residues);
9196         molecule->residues = 0;
9197     }
9198     molecule->n_residues = 0;
9199
9200     if(molecule->atoms)
9201     {
9202         for(i = 0; i < molecule->n_atoms; i++)
9203         {
9204             tng_atom_destroy(&molecule->atoms[i]);
9205         }
9206         free(molecule->atoms);
9207         molecule->atoms = 0;
9208     }
9209     molecule->n_atoms = 0;
9210
9211     if(molecule->bonds)
9212     {
9213         free(molecule->bonds);
9214         molecule->bonds = 0;
9215     }
9216     molecule->n_bonds = 0;
9217
9218     return(TNG_SUCCESS);
9219 }
9220
9221 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
9222                 (const tng_trajectory_t tng_data,
9223                  const int64_t nr,
9224                  char *name,
9225                  int max_len)
9226 {
9227     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9228     tng_molecule_t mol;
9229     tng_bool found = TNG_FALSE;
9230
9231     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9232     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9233
9234     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9235
9236     if(!molecule_cnt_list)
9237     {
9238         return(TNG_FAILURE);
9239     }
9240
9241     for(i = 0; i < tng_data->n_molecules; i++)
9242     {
9243         mol = &tng_data->molecules[i];
9244         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9245         {
9246             cnt += mol->n_atoms * molecule_cnt_list[i];
9247             continue;
9248         }
9249         found = TNG_TRUE;
9250         break;
9251     }
9252     if(!found)
9253     {
9254         return(TNG_FAILURE);
9255     }
9256
9257     strncpy(name, mol->name, max_len - 1);
9258     name[max_len - 1] = 0;
9259
9260     if(strlen(mol->name) > (unsigned int)max_len - 1)
9261     {
9262         return(TNG_FAILURE);
9263     }
9264     return(TNG_SUCCESS);
9265 }
9266
9267 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
9268                 (const tng_trajectory_t tng_data,
9269                  const int64_t nr,
9270                  int64_t *id)
9271 {
9272     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9273     tng_molecule_t mol;
9274     tng_bool found = TNG_FALSE;
9275
9276     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9277     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9278
9279     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9280
9281     if(!molecule_cnt_list)
9282     {
9283         return(TNG_FAILURE);
9284     }
9285
9286     for(i = 0; i < tng_data->n_molecules; i++)
9287     {
9288         mol = &tng_data->molecules[i];
9289         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9290         {
9291             cnt += mol->n_atoms * molecule_cnt_list[i];
9292             continue;
9293         }
9294         found = TNG_TRUE;
9295         break;
9296     }
9297     if(!found)
9298     {
9299         return(TNG_FAILURE);
9300     }
9301
9302     *id = mol->id;
9303
9304     return(TNG_SUCCESS);
9305 }
9306
9307 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
9308                 (const tng_trajectory_t tng_data,
9309                  int64_t *n_bonds,
9310                  int64_t **from_atoms,
9311                  int64_t **to_atoms)
9312 {
9313     int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
9314     int64_t from_atom, to_atom, *molecule_cnt_list = 0;
9315     tng_molecule_t mol;
9316     tng_bond_t bond;
9317
9318     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9319     TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
9320     TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
9321     TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
9322
9323     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9324
9325     if(!molecule_cnt_list)
9326     {
9327         return(TNG_FAILURE);
9328     }
9329
9330     *n_bonds = 0;
9331     /* First count the total number of bonds to allocate memory */
9332     for(i = 0; i < tng_data->n_molecules; i++)
9333     {
9334         mol = &tng_data->molecules[i];
9335         mol_cnt = molecule_cnt_list[i];
9336         *n_bonds += mol_cnt * mol->n_bonds;
9337     }
9338     if(*n_bonds == 0)
9339     {
9340         return(TNG_SUCCESS);
9341     }
9342
9343     *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9344     if(!*from_atoms)
9345     {
9346         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
9347                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9348         return(TNG_CRITICAL);
9349     }
9350     *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
9351     if(!*to_atoms)
9352     {
9353         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
9354                sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
9355         free(*from_atoms);
9356         *from_atoms = 0;
9357         return(TNG_CRITICAL);
9358     }
9359
9360     cnt = 0;
9361     for(i = 0; i < tng_data->n_molecules; i++)
9362     {
9363         mol = &tng_data->molecules[i];
9364         mol_cnt = molecule_cnt_list[i];
9365         for(j = 0; j < mol_cnt; j++)
9366         {
9367             for(k = 0; k < mol->n_bonds; k++)
9368             {
9369                 bond = &mol->bonds[k];
9370                 from_atom = atom_cnt + bond->from_atom_id;
9371                 to_atom = atom_cnt + bond->to_atom_id;
9372                 (*from_atoms)[cnt] = from_atom;
9373                 (*to_atoms)[cnt++] = to_atom;
9374             }
9375             atom_cnt += mol->n_atoms;
9376         }
9377     }
9378
9379     return(TNG_SUCCESS);
9380 }
9381
9382 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
9383                 (const tng_trajectory_t tng_data,
9384                  const int64_t nr,
9385                  char *name,
9386                  int max_len)
9387 {
9388     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9389     tng_molecule_t mol;
9390     tng_atom_t atom;
9391     tng_bool found = TNG_FALSE;
9392
9393     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9394     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9395
9396     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9397
9398     if(!molecule_cnt_list)
9399     {
9400         return(TNG_FAILURE);
9401     }
9402
9403     for(i = 0; i < tng_data->n_molecules; i++)
9404     {
9405         mol = &tng_data->molecules[i];
9406         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9407         {
9408             cnt += mol->n_atoms * molecule_cnt_list[i];
9409             continue;
9410         }
9411         atom = &mol->atoms[nr % mol->n_atoms];
9412         found = TNG_TRUE;
9413         break;
9414     }
9415     if(!found)
9416     {
9417         return(TNG_FAILURE);
9418     }
9419     if(!atom->residue || !atom->residue->chain)
9420     {
9421         return(TNG_FAILURE);
9422     }
9423
9424     strncpy(name, atom->residue->chain->name, max_len - 1);
9425     name[max_len - 1] = 0;
9426
9427     if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
9428     {
9429         return(TNG_FAILURE);
9430     }
9431     return(TNG_SUCCESS);
9432 }
9433
9434 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
9435                 (const tng_trajectory_t tng_data,
9436                  const int64_t nr,
9437                  char *name,
9438                  int max_len)
9439 {
9440     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9441     tng_molecule_t mol;
9442     tng_atom_t atom;
9443     tng_bool found = TNG_FALSE;
9444
9445     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9446     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9447
9448     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9449
9450     if(!molecule_cnt_list)
9451     {
9452         return(TNG_FAILURE);
9453     }
9454
9455     for(i = 0; i < tng_data->n_molecules; i++)
9456     {
9457         mol = &tng_data->molecules[i];
9458         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9459         {
9460             cnt += mol->n_atoms * molecule_cnt_list[i];
9461             continue;
9462         }
9463         atom = &mol->atoms[nr % mol->n_atoms];
9464         found = TNG_TRUE;
9465         break;
9466     }
9467     if(!found)
9468     {
9469         return(TNG_FAILURE);
9470     }
9471     if(!atom->residue)
9472     {
9473         return(TNG_FAILURE);
9474     }
9475
9476     strncpy(name, atom->residue->name, max_len - 1);
9477     name[max_len - 1] = 0;
9478
9479     if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
9480     {
9481         return(TNG_FAILURE);
9482     }
9483     return(TNG_SUCCESS);
9484 }
9485
9486 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
9487                 (const tng_trajectory_t tng_data,
9488                  const int64_t nr,
9489                  int64_t *id)
9490 {
9491     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9492     tng_molecule_t mol;
9493     tng_atom_t atom;
9494     tng_bool found = TNG_FALSE;
9495
9496     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9497     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9498
9499     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9500
9501     if(!molecule_cnt_list)
9502     {
9503         return(TNG_FAILURE);
9504     }
9505
9506     for(i = 0; i < tng_data->n_molecules; i++)
9507     {
9508         mol = &tng_data->molecules[i];
9509         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9510         {
9511             cnt += mol->n_atoms * molecule_cnt_list[i];
9512             continue;
9513         }
9514         atom = &mol->atoms[nr % mol->n_atoms];
9515         found = TNG_TRUE;
9516         break;
9517     }
9518     if(!found)
9519     {
9520         return(TNG_FAILURE);
9521     }
9522     if(!atom->residue)
9523     {
9524         return(TNG_FAILURE);
9525     }
9526
9527     *id = atom->residue->id;
9528
9529     return(TNG_SUCCESS);
9530 }
9531
9532 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
9533                 (const tng_trajectory_t tng_data,
9534                  const int64_t nr,
9535                  int64_t *id)
9536 {
9537     int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
9538     tng_molecule_t mol;
9539     tng_atom_t atom;
9540     tng_bool found = TNG_FALSE;
9541
9542     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9543     TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
9544
9545     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9546
9547     if(!molecule_cnt_list)
9548     {
9549         return(TNG_FAILURE);
9550     }
9551
9552     for(i = 0; i < tng_data->n_molecules; i++)
9553     {
9554         mol = &tng_data->molecules[i];
9555         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9556         {
9557             cnt += mol->n_atoms * molecule_cnt_list[i];
9558             offset += mol->n_residues * molecule_cnt_list[i];
9559             continue;
9560         }
9561         atom = &mol->atoms[nr % mol->n_atoms];
9562         found = TNG_TRUE;
9563         break;
9564     }
9565     if(!found)
9566     {
9567         return(TNG_FAILURE);
9568     }
9569     if(!atom->residue)
9570     {
9571         return(TNG_FAILURE);
9572     }
9573
9574     offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
9575
9576     *id = atom->residue->id + offset;
9577
9578     return(TNG_SUCCESS);
9579 }
9580
9581 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
9582                 (const tng_trajectory_t tng_data,
9583                  const int64_t nr,
9584                  char *name,
9585                  int max_len)
9586 {
9587     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9588     tng_molecule_t mol;
9589     tng_atom_t atom;
9590     tng_bool found = TNG_FALSE;
9591
9592     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9593     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
9594
9595     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9596
9597     if(!molecule_cnt_list)
9598     {
9599         return(TNG_FAILURE);
9600     }
9601
9602     for(i = 0; i < tng_data->n_molecules; i++)
9603     {
9604         mol = &tng_data->molecules[i];
9605         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9606         {
9607             cnt += mol->n_atoms * molecule_cnt_list[i];
9608             continue;
9609         }
9610         atom = &mol->atoms[nr % mol->n_atoms];
9611         found = TNG_TRUE;
9612         break;
9613     }
9614     if(!found)
9615     {
9616         return(TNG_FAILURE);
9617     }
9618
9619     strncpy(name, atom->name, max_len - 1);
9620     name[max_len - 1] = 0;
9621
9622     if(strlen(atom->name) > (unsigned int)max_len - 1)
9623     {
9624         return(TNG_FAILURE);
9625     }
9626     return(TNG_SUCCESS);
9627 }
9628
9629 tng_function_status tng_atom_type_of_particle_nr_get
9630                 (const tng_trajectory_t tng_data,
9631                  const int64_t nr,
9632                  char *type,
9633                  int max_len)
9634 {
9635     int64_t cnt = 0, i, *molecule_cnt_list = 0;
9636     tng_molecule_t mol;
9637     tng_atom_t atom;
9638     tng_bool found = TNG_FALSE;
9639
9640     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9641     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
9642
9643     tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
9644
9645     if(!molecule_cnt_list)
9646     {
9647         return(TNG_FAILURE);
9648     }
9649
9650     for(i = 0; i < tng_data->n_molecules; i++)
9651     {
9652         mol = &tng_data->molecules[i];
9653         if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
9654         {
9655             cnt += mol->n_atoms * molecule_cnt_list[i];
9656             continue;
9657         }
9658         atom = &mol->atoms[nr % mol->n_atoms];
9659         found = TNG_TRUE;
9660         break;
9661     }
9662     if(!found)
9663     {
9664         return(TNG_FAILURE);
9665     }
9666
9667     strncpy(type, atom->atom_type, max_len - 1);
9668     type[max_len - 1] = 0;
9669
9670     if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
9671     {
9672         return(TNG_FAILURE);
9673     }
9674     return(TNG_SUCCESS);
9675 }
9676
9677 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
9678                 (tng_trajectory_t tng_data,
9679                  const int64_t num_first_particle,
9680                  const int64_t n_particles,
9681                  const int64_t *mapping_table)
9682 {
9683     int64_t i;
9684     tng_particle_mapping_t mapping;
9685     tng_trajectory_frame_set_t frame_set;
9686
9687     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9688
9689     frame_set = &tng_data->current_trajectory_frame_set;
9690
9691     /* Sanity check of the particle ranges. Split into multiple if
9692      * statements for improved readability */
9693     for(i = 0; i < frame_set->n_mapping_blocks; i++)
9694     {
9695         mapping = &frame_set->mappings[i];
9696         if(num_first_particle >= mapping->num_first_particle &&
9697            num_first_particle < mapping->num_first_particle +
9698                                    mapping->n_particles)
9699         {
9700             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9701             return(TNG_FAILURE);
9702         }
9703         if(num_first_particle + n_particles >=
9704            mapping->num_first_particle &&
9705            num_first_particle + n_particles <
9706            mapping->num_first_particle + mapping->n_particles)
9707         {
9708             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9709             return(TNG_FAILURE);
9710         }
9711         if(mapping->num_first_particle >= num_first_particle &&
9712            mapping->num_first_particle < num_first_particle +
9713                                             n_particles)
9714         {
9715             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9716             return(TNG_FAILURE);
9717         }
9718         if(mapping->num_first_particle + mapping->n_particles >
9719            num_first_particle &&
9720            mapping->num_first_particle + mapping->n_particles <
9721            num_first_particle + n_particles)
9722         {
9723             fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
9724             return(TNG_FAILURE);
9725         }
9726     }
9727
9728     frame_set->n_mapping_blocks++;
9729
9730     mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
9731                       frame_set->n_mapping_blocks);
9732
9733     if(!mapping)
9734     {
9735         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
9736                sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
9737                __FILE__, __LINE__);
9738         free(frame_set->mappings);
9739         frame_set->mappings = 0;
9740         return(TNG_CRITICAL);
9741     }
9742     frame_set->mappings = mapping;
9743
9744     frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
9745     frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
9746
9747     frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
9748     if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
9749     {
9750         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
9751                sizeof(int64_t) * n_particles, __FILE__, __LINE__);
9752         return(TNG_CRITICAL);
9753     }
9754
9755     for(i=0; i<n_particles; i++)
9756     {
9757         frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
9758     }
9759
9760     return(TNG_SUCCESS);
9761 }
9762
9763 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(tng_trajectory_t tng_data)
9764 {
9765     tng_trajectory_frame_set_t frame_set;
9766     tng_particle_mapping_t mapping;
9767     int64_t i;
9768
9769     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9770
9771     frame_set = &tng_data->current_trajectory_frame_set;
9772
9773     if(frame_set->n_mapping_blocks && frame_set->mappings)
9774     {
9775         for(i = 0; i < frame_set->n_mapping_blocks; i++)
9776         {
9777             mapping = &frame_set->mappings[i];
9778             if(mapping->real_particle_numbers)
9779             {
9780                 free(mapping->real_particle_numbers);
9781                 mapping->real_particle_numbers = 0;
9782             }
9783         }
9784         free(frame_set->mappings);
9785         frame_set->mappings = 0;
9786         frame_set->n_mapping_blocks = 0;
9787     }
9788
9789     return(TNG_SUCCESS);
9790 }
9791
9792 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
9793 {
9794     time_t seconds;
9795     tng_trajectory_frame_set_t frame_set;
9796     tng_trajectory_t tng_data;
9797
9798     *tng_data_p = malloc(sizeof(struct tng_trajectory));
9799     if(!*tng_data_p)
9800     {
9801         fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
9802                sizeof(struct tng_trajectory), __FILE__, __LINE__);
9803         return(TNG_CRITICAL);
9804     }
9805
9806     tng_data = *tng_data_p;
9807
9808     frame_set = &tng_data->current_trajectory_frame_set;
9809
9810     tng_data->input_file_path = 0;
9811     tng_data->input_file = 0;
9812     tng_data->input_file_len = 0;
9813     tng_data->output_file_path = 0;
9814     tng_data->output_file = 0;
9815
9816     tng_data->first_program_name = 0;
9817     tng_data->first_user_name = 0;
9818     tng_data->first_computer_name = 0;
9819     tng_data->first_pgp_signature = 0;
9820     tng_data->last_program_name = 0;
9821     tng_data->last_user_name = 0;
9822     tng_data->last_computer_name = 0;
9823     tng_data->last_pgp_signature = 0;
9824     tng_data->forcefield_name = 0;
9825
9826     seconds = time(0);
9827     if ( seconds == -1)
9828     {
9829         fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
9830     }
9831     else
9832     {
9833         tng_data->time = seconds;
9834     }
9835
9836     tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
9837     tng_data->first_trajectory_frame_set_input_file_pos = -1;
9838     tng_data->last_trajectory_frame_set_input_file_pos = -1;
9839     tng_data->current_trajectory_frame_set_input_file_pos = -1;
9840     tng_data->first_trajectory_frame_set_output_file_pos = -1;
9841     tng_data->last_trajectory_frame_set_output_file_pos = -1;
9842     tng_data->current_trajectory_frame_set_output_file_pos = -1;
9843     tng_data->frame_set_n_frames = 100;
9844     tng_data->n_trajectory_frame_sets = 0;
9845     tng_data->medium_stride_length = 100;
9846     tng_data->long_stride_length = 10000;
9847
9848     tng_data->time_per_frame = -1;
9849
9850     tng_data->n_particle_data_blocks = 0;
9851     tng_data->n_data_blocks = 0;
9852
9853     tng_data->non_tr_particle_data = 0;
9854     tng_data->non_tr_data = 0;
9855
9856     tng_data->compress_algo_pos = 0;
9857     tng_data->compress_algo_vel = 0;
9858     tng_data->compression_precision = 1000;
9859     tng_data->distance_unit_exponential = -9;
9860
9861     frame_set->first_frame = -1;
9862     frame_set->n_mapping_blocks = 0;
9863     frame_set->mappings = 0;
9864     frame_set->molecule_cnt_list = 0;
9865
9866     frame_set->n_particle_data_blocks = 0;
9867     frame_set->n_data_blocks = 0;
9868
9869     frame_set->tr_particle_data = 0;
9870     frame_set->tr_data = 0;
9871
9872     frame_set->n_written_frames = 0;
9873     frame_set->n_unwritten_frames = 0;
9874
9875     frame_set->next_frame_set_file_pos = -1;
9876     frame_set->prev_frame_set_file_pos = -1;
9877     frame_set->medium_stride_next_frame_set_file_pos = -1;
9878     frame_set->medium_stride_prev_frame_set_file_pos = -1;
9879     frame_set->long_stride_next_frame_set_file_pos = -1;
9880     frame_set->long_stride_prev_frame_set_file_pos = -1;
9881
9882     frame_set->first_frame_time = -1;
9883
9884     tng_data->n_molecules = 0;
9885     tng_data->molecules = 0;
9886     tng_data->molecule_cnt_list = 0;
9887     tng_data->n_particles = 0;
9888
9889     {
9890       /* Check the endianness of the computer */
9891       static int32_t endianness_32 = 0x01234567;
9892       /* 0x01234567 */
9893       if ( *(const unsigned char*)&endianness_32 == 0x01 )
9894         {
9895           tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
9896         }
9897
9898       /* 0x67452301 */
9899       else if( *(const unsigned char*)&endianness_32 == 0x67 )
9900         {
9901           tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
9902
9903         }
9904
9905       /* 0x45670123 */
9906       else if ( *(const unsigned char*)&endianness_32 == 0x45 )
9907         {
9908           tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
9909         }
9910     }
9911     {
9912       static int64_t endianness_64 = 0x0123456789ABCDEFLL;
9913       /* 0x0123456789ABCDEF */
9914       if ( *(const unsigned char*)&endianness_64 == 0x01 )
9915         {
9916           tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
9917         }
9918
9919       /* 0xEFCDAB8967452301 */
9920       else if ( *(const unsigned char*)&endianness_64 == 0xEF )
9921         {
9922           tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
9923         }
9924
9925       /* 0x89ABCDEF01234567 */
9926       else if ( *(const unsigned char*)&endianness_64 == 0x89 )
9927         {
9928           tng_data->endianness_64 = TNG_QUAD_SWAP_64;
9929         }
9930
9931       /* 0x45670123CDEF89AB */
9932       else if ( *(const unsigned char*)&endianness_64 == 0x45 )
9933         {
9934           tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
9935         }
9936
9937       /* 0x23016745AB89EFCD */
9938       else if ( *(const unsigned char*)&endianness_64 == 0x23 )
9939         {
9940           tng_data->endianness_64 = TNG_BYTE_SWAP_64;
9941         }
9942     }
9943
9944     /* By default do not swap the byte order, i.e. keep the byte order of the
9945      * architecture. The input file endianness will be set when reading the
9946      * header. The output endianness can be changed - before the file is
9947      * written. */
9948     tng_data->input_endianness_swap_func_32 = 0;
9949     tng_data->input_endianness_swap_func_64 = 0;
9950     tng_data->output_endianness_swap_func_32 = 0;
9951     tng_data->output_endianness_swap_func_64 = 0;
9952
9953     tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9954     tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9955     tng_data->current_trajectory_frame_set.n_frames = 0;
9956
9957     return(TNG_SUCCESS);
9958 }
9959
9960 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
9961 {
9962     int64_t i, j, k, l;
9963     int64_t n_particles, n_values_per_frame;
9964     tng_trajectory_t tng_data = *tng_data_p;
9965     tng_trajectory_frame_set_t frame_set;
9966
9967     if(!*tng_data_p)
9968     {
9969         return(TNG_SUCCESS);
9970     }
9971
9972     frame_set = &tng_data->current_trajectory_frame_set;
9973
9974     if(tng_data->input_file_path)
9975     {
9976         free(tng_data->input_file_path);
9977         tng_data->input_file_path = 0;
9978     }
9979
9980     if(tng_data->input_file)
9981     {
9982         if(tng_data->output_file == tng_data->input_file)
9983         {
9984             tng_frame_set_finalize(tng_data, TNG_USE_HASH);
9985             tng_data->output_file = 0;
9986         }
9987         fclose(tng_data->input_file);
9988         tng_data->input_file = 0;
9989     }
9990
9991     if(tng_data->output_file_path)
9992     {
9993         free(tng_data->output_file_path);
9994         tng_data->output_file_path = 0;
9995     }
9996
9997     if(tng_data->output_file)
9998     {
9999         /* FIXME: Do not always write the hash */
10000         tng_frame_set_finalize(tng_data, TNG_USE_HASH);
10001         fclose(tng_data->output_file);
10002         tng_data->output_file = 0;
10003     }
10004
10005     if(tng_data->first_program_name)
10006     {
10007         free(tng_data->first_program_name);
10008         tng_data->first_program_name = 0;
10009     }
10010
10011     if(tng_data->last_program_name)
10012     {
10013         free(tng_data->last_program_name);
10014         tng_data->last_program_name = 0;
10015     }
10016
10017     if(tng_data->first_user_name)
10018     {
10019         free(tng_data->first_user_name);
10020         tng_data->first_user_name = 0;
10021     }
10022
10023     if(tng_data->last_user_name)
10024     {
10025         free(tng_data->last_user_name);
10026         tng_data->last_user_name = 0;
10027     }
10028
10029     if(tng_data->first_computer_name)
10030     {
10031         free(tng_data->first_computer_name);
10032         tng_data->first_computer_name = 0;
10033     }
10034
10035     if(tng_data->last_computer_name)
10036     {
10037         free(tng_data->last_computer_name);
10038         tng_data->last_computer_name = 0;
10039     }
10040
10041     if(tng_data->first_pgp_signature)
10042     {
10043         free(tng_data->first_pgp_signature);
10044         tng_data->first_pgp_signature = 0;
10045     }
10046
10047     if(tng_data->last_pgp_signature)
10048     {
10049         free(tng_data->last_pgp_signature);
10050         tng_data->last_pgp_signature = 0;
10051     }
10052
10053     if(tng_data->forcefield_name)
10054     {
10055         free(tng_data->forcefield_name);
10056         tng_data->forcefield_name = 0;
10057     }
10058
10059     tng_frame_set_particle_mapping_free(tng_data);
10060
10061     if(frame_set->molecule_cnt_list)
10062     {
10063         free(frame_set->molecule_cnt_list);
10064         frame_set->molecule_cnt_list = 0;
10065     }
10066
10067     if(tng_data->var_num_atoms_flag)
10068     {
10069         n_particles = frame_set->n_particles;
10070     }
10071     else
10072     {
10073         n_particles = tng_data->n_particles;
10074     }
10075
10076     if(tng_data->non_tr_particle_data)
10077     {
10078         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
10079         {
10080             if(tng_data->non_tr_particle_data[i].values)
10081             {
10082                 free(tng_data->non_tr_particle_data[i].values);
10083                 tng_data->non_tr_particle_data[i].values = 0;
10084             }
10085
10086             if(tng_data->non_tr_particle_data[i].strings)
10087             {
10088                 n_values_per_frame = tng_data->non_tr_particle_data[i].
10089                                      n_values_per_frame;
10090                 if(tng_data->non_tr_particle_data[i].strings[0])
10091                 {
10092                     for(j = 0; j < n_particles; j++)
10093                     {
10094                         if(tng_data->non_tr_particle_data[i].strings[0][j])
10095                         {
10096                             for(k = 0; k < n_values_per_frame; k++)
10097                             {
10098                                 if(tng_data->non_tr_particle_data[i].
10099                                    strings[0][j][k])
10100                                 {
10101                                     free(tng_data->non_tr_particle_data[i].
10102                                          strings[0][j][k]);
10103                                     tng_data->non_tr_particle_data[i].
10104                                     strings[0][j][k] = 0;
10105                                 }
10106                             }
10107                             free(tng_data->non_tr_particle_data[i].
10108                                  strings[0][j]);
10109                             tng_data->non_tr_particle_data[i].strings[0][j] = 0;
10110                         }
10111                     }
10112                     free(tng_data->non_tr_particle_data[i].strings[0]);
10113                     tng_data->non_tr_particle_data[i].strings[0] = 0;
10114                 }
10115                 free(tng_data->non_tr_particle_data[i].strings);
10116                 tng_data->non_tr_particle_data[i].strings = 0;
10117             }
10118
10119             if(tng_data->non_tr_particle_data[i].block_name)
10120             {
10121                 free(tng_data->non_tr_particle_data[i].block_name);
10122                 tng_data->non_tr_particle_data[i].block_name = 0;
10123             }
10124         }
10125         free(tng_data->non_tr_particle_data);
10126         tng_data->non_tr_particle_data = 0;
10127     }
10128
10129     if(tng_data->non_tr_data)
10130     {
10131         for(i = 0; i < tng_data->n_data_blocks; i++)
10132         {
10133             if(tng_data->non_tr_data[i].values)
10134             {
10135                 free(tng_data->non_tr_data[i].values);
10136                 tng_data->non_tr_data[i].values = 0;
10137             }
10138
10139             if(tng_data->non_tr_data[i].strings)
10140             {
10141                 n_values_per_frame = tng_data->non_tr_data[i].
10142                                      n_values_per_frame;
10143                 if(tng_data->non_tr_data[i].strings[0])
10144                 {
10145                     for(j = 0; j < n_values_per_frame; j++)
10146                     {
10147                         if(tng_data->non_tr_data[i].strings[0][j])
10148                         {
10149                             free(tng_data->non_tr_data[i].strings[0][j]);
10150                             tng_data->non_tr_data[i].strings[0][j] = 0;
10151                         }
10152                     }
10153                     free(tng_data->non_tr_data[i].strings[0]);
10154                     tng_data->non_tr_data[i].strings[0] = 0;
10155                 }
10156                 free(tng_data->non_tr_data[i].strings);
10157                 tng_data->non_tr_data[i].strings = 0;
10158             }
10159
10160             if(tng_data->non_tr_data[i].block_name)
10161             {
10162                 free(tng_data->non_tr_data[i].block_name);
10163                 tng_data->non_tr_data[i].block_name = 0;
10164             }
10165         }
10166         free(tng_data->non_tr_data);
10167         tng_data->non_tr_data = 0;
10168     }
10169
10170     tng_data->n_particle_data_blocks = 0;
10171     tng_data->n_data_blocks = 0;
10172
10173     if(tng_data->compress_algo_pos)
10174     {
10175         free(tng_data->compress_algo_pos);
10176         tng_data->compress_algo_pos = 0;
10177     }
10178     if(tng_data->compress_algo_vel)
10179     {
10180         free(tng_data->compress_algo_vel);
10181         tng_data->compress_algo_vel = 0;
10182     }
10183
10184     if(frame_set->tr_particle_data)
10185     {
10186         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
10187         {
10188             if(frame_set->tr_particle_data[i].values)
10189             {
10190                 free(frame_set->tr_particle_data[i].values);
10191                 frame_set->tr_particle_data[i].values = 0;
10192             }
10193
10194             if(frame_set->tr_particle_data[i].strings)
10195             {
10196                 n_values_per_frame = frame_set->tr_particle_data[i].
10197                                      n_values_per_frame;
10198                 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
10199                 {
10200                     if(frame_set->tr_particle_data[i].strings[j])
10201                     {
10202                         for(k = 0; k < n_particles; k++)
10203                         {
10204                             if(frame_set->tr_particle_data[i].
10205                                 strings[j][k])
10206                             {
10207                                 for(l = 0; l < n_values_per_frame; l++)
10208                                 {
10209                                     if(frame_set->tr_particle_data[i].
10210                                         strings[j][k][l])
10211                                     {
10212                                         free(frame_set->tr_particle_data[i].
10213                                                 strings[j][k][l]);
10214                                         frame_set->tr_particle_data[i].
10215                                         strings[j][k][l] = 0;
10216                                     }
10217                                 }
10218                                 free(frame_set->tr_particle_data[i].
10219                                         strings[j][k]);
10220                                 frame_set->tr_particle_data[i].
10221                                 strings[j][k] = 0;
10222                             }
10223                         }
10224                         free(frame_set->tr_particle_data[i].strings[j]);
10225                         frame_set->tr_particle_data[i].strings[j] = 0;
10226                     }
10227                 }
10228                 free(frame_set->tr_particle_data[i].strings);
10229                 frame_set->tr_particle_data[i].strings = 0;
10230             }
10231
10232             if(frame_set->tr_particle_data[i].block_name)
10233             {
10234                 free(frame_set->tr_particle_data[i].block_name);
10235                 frame_set->tr_particle_data[i].block_name = 0;
10236             }
10237         }
10238         free(frame_set->tr_particle_data);
10239         frame_set->tr_particle_data = 0;
10240     }
10241
10242     if(frame_set->tr_data)
10243     {
10244         for(i = 0; i < frame_set->n_data_blocks; i++)
10245         {
10246             if(frame_set->tr_data[i].values)
10247             {
10248                 free(frame_set->tr_data[i].values);
10249                 frame_set->tr_data[i].values = 0;
10250             }
10251
10252             if(frame_set->tr_data[i].strings)
10253             {
10254                 n_values_per_frame = frame_set->tr_data[i].
10255                                      n_values_per_frame;
10256                 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
10257                 {
10258                     if(frame_set->tr_data[i].strings[j])
10259                     {
10260                         for(k = 0; k < n_values_per_frame; k++)
10261                         {
10262                             if(frame_set->tr_data[i].strings[j][k])
10263                             {
10264                                 free(frame_set->tr_data[i].strings[j][k]);
10265                                 frame_set->tr_data[i].strings[j][k] = 0;
10266                             }
10267                         }
10268                         free(frame_set->tr_data[i].strings[j]);
10269                         frame_set->tr_data[i].strings[j] = 0;
10270                     }
10271                 }
10272                 free(frame_set->tr_data[i].strings);
10273                 frame_set->tr_data[i].strings = 0;
10274             }
10275
10276             if(frame_set->tr_data[i].block_name)
10277             {
10278                 free(frame_set->tr_data[i].block_name);
10279                 frame_set->tr_data[i].block_name = 0;
10280             }
10281         }
10282         free(frame_set->tr_data);
10283         frame_set->tr_data = 0;
10284     }
10285
10286     frame_set->n_particle_data_blocks = 0;
10287     frame_set->n_data_blocks = 0;
10288
10289     if(tng_data->molecules)
10290     {
10291         for(i = 0; i < tng_data->n_molecules; i++)
10292         {
10293             tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
10294         }
10295         free(tng_data->molecules);
10296         tng_data->molecules = 0;
10297         tng_data->n_molecules = 0;
10298     }
10299     if(tng_data->molecule_cnt_list)
10300     {
10301         free(tng_data->molecule_cnt_list);
10302         tng_data->molecule_cnt_list = 0;
10303     }
10304
10305     free(*tng_data_p);
10306     *tng_data_p = 0;
10307
10308     return(TNG_SUCCESS);
10309 }
10310
10311 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src(tng_trajectory_t src,
10312                                                  tng_trajectory_t *dest_p)
10313 {
10314     tng_trajectory_frame_set_t frame_set;
10315     tng_trajectory_t dest;
10316
10317     TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
10318
10319     *dest_p = malloc(sizeof(struct tng_trajectory));
10320     if(!*dest_p)
10321     {
10322         fprintf(stderr, "TNG library: Cannot allocate memory (%"TNG_PRIsize" bytes). %s: %d\n",
10323                sizeof(struct tng_trajectory), __FILE__, __LINE__);
10324         return(TNG_CRITICAL);
10325     }
10326
10327     dest = *dest_p;
10328
10329     frame_set = &dest->current_trajectory_frame_set;
10330
10331     dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
10332     if(!dest->input_file_path)
10333     {
10334         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10335                (int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
10336         return(TNG_CRITICAL);
10337     }
10338     strcpy(dest->input_file_path, src->input_file_path);
10339     dest->input_file = 0;
10340     dest->input_file_len = src->input_file_len;
10341     dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
10342     if(!dest->output_file_path)
10343     {
10344         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
10345                (int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
10346         return(TNG_CRITICAL);
10347     }
10348     strcpy(dest->output_file_path, src->output_file_path);
10349     dest->output_file = 0;
10350
10351     dest->first_program_name = 0;
10352     dest->first_user_name = 0;
10353     dest->first_computer_name = 0;
10354     dest->first_pgp_signature = 0;
10355     dest->last_program_name = 0;
10356     dest->last_user_name = 0;
10357     dest->last_computer_name = 0;
10358     dest->last_pgp_signature = 0;
10359     dest->forcefield_name = 0;
10360
10361     dest->var_num_atoms_flag = src->var_num_atoms_flag;
10362     dest->first_trajectory_frame_set_input_file_pos =
10363     src->first_trajectory_frame_set_input_file_pos;
10364     dest->last_trajectory_frame_set_input_file_pos =
10365     src->last_trajectory_frame_set_input_file_pos;
10366     dest->current_trajectory_frame_set_input_file_pos =
10367     src->current_trajectory_frame_set_input_file_pos;
10368     dest->first_trajectory_frame_set_output_file_pos =
10369     src->first_trajectory_frame_set_output_file_pos;
10370     dest->last_trajectory_frame_set_output_file_pos =
10371     src->last_trajectory_frame_set_output_file_pos;
10372     dest->current_trajectory_frame_set_output_file_pos =
10373     src->current_trajectory_frame_set_output_file_pos;
10374     dest->frame_set_n_frames = src->frame_set_n_frames;
10375     dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
10376     dest->medium_stride_length = src->medium_stride_length;
10377     dest->long_stride_length = src->long_stride_length;
10378
10379     dest->time_per_frame = src->time_per_frame;
10380
10381     /* Currently the non trajectory data blocks are not copied since it
10382      * can lead to problems when freeing memory in a parallel block. */
10383     dest->n_particle_data_blocks = 0;
10384     dest->n_data_blocks = 0;
10385     dest->non_tr_particle_data = 0;
10386     dest->non_tr_data = 0;
10387
10388     dest->compress_algo_pos = 0;
10389     dest->compress_algo_vel = 0;
10390     dest->distance_unit_exponential = -9;
10391     dest->compression_precision = 1000;
10392
10393     frame_set->n_mapping_blocks = 0;
10394     frame_set->mappings = 0;
10395     frame_set->molecule_cnt_list = 0;
10396
10397     frame_set->n_particle_data_blocks = 0;
10398     frame_set->n_data_blocks = 0;
10399
10400     frame_set->tr_particle_data = 0;
10401     frame_set->tr_data = 0;
10402
10403     frame_set->next_frame_set_file_pos = -1;
10404     frame_set->prev_frame_set_file_pos = -1;
10405     frame_set->medium_stride_next_frame_set_file_pos = -1;
10406     frame_set->medium_stride_prev_frame_set_file_pos = -1;
10407     frame_set->long_stride_next_frame_set_file_pos = -1;
10408     frame_set->long_stride_prev_frame_set_file_pos = -1;
10409     frame_set->first_frame = -1;
10410
10411     dest->n_molecules = 0;
10412     dest->molecules = 0;
10413     dest->molecule_cnt_list = 0;
10414     dest->n_particles = src->n_particles;
10415
10416     dest->endianness_32 = src->endianness_32;
10417     dest->endianness_64 = src->endianness_64;
10418     dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
10419     dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
10420     dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
10421     dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
10422
10423     dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
10424     dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
10425     dest->current_trajectory_frame_set.n_frames = 0;
10426
10427     return(TNG_SUCCESS);
10428 }
10429
10430 tng_function_status DECLSPECDLLEXPORT tng_input_file_get(const tng_trajectory_t tng_data,
10431                                        char *file_name, const int max_len)
10432 {
10433     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10434     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10435
10436     strncpy(file_name, tng_data->input_file_path, max_len - 1);
10437     file_name[max_len - 1] = 0;
10438
10439     if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
10440     {
10441         return(TNG_FAILURE);
10442     }
10443     return(TNG_SUCCESS);
10444 }
10445
10446 tng_function_status DECLSPECDLLEXPORT tng_input_file_set(tng_trajectory_t tng_data,
10447                                                          const char *file_name)
10448 {
10449     unsigned int len;
10450     char *temp;
10451
10452     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10453     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10454
10455
10456     if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
10457                                            file_name) == 0)
10458     {
10459         return(TNG_SUCCESS);
10460     }
10461
10462     if(tng_data->input_file)
10463     {
10464         fclose(tng_data->input_file);
10465     }
10466
10467     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10468     temp = realloc(tng_data->input_file_path, len);
10469     if(!temp)
10470     {
10471         fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10472                __FILE__, __LINE__);
10473         free(tng_data->input_file_path);
10474         tng_data->input_file_path = 0;
10475         return(TNG_CRITICAL);
10476     }
10477     tng_data->input_file_path = temp;
10478
10479     strncpy(tng_data->input_file_path, file_name, len);
10480
10481     return(tng_input_file_init(tng_data));
10482 }
10483
10484 tng_function_status tng_output_file_get(const tng_trajectory_t tng_data,
10485                                        char *file_name, const int max_len)
10486 {
10487     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10488     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10489
10490     strncpy(file_name, tng_data->output_file_path, max_len - 1);
10491     file_name[max_len - 1] = 0;
10492
10493     if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
10494     {
10495         return(TNG_FAILURE);
10496     }
10497     return(TNG_SUCCESS);
10498 }
10499
10500 tng_function_status DECLSPECDLLEXPORT tng_output_file_set(tng_trajectory_t tng_data,
10501                                                           const char *file_name)
10502 {
10503     int len;
10504     char *temp;
10505
10506     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10507     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10508
10509     if(tng_data->output_file_path &&
10510        strcmp(tng_data->output_file_path, file_name) == 0)
10511     {
10512         return(TNG_SUCCESS);
10513     }
10514
10515     if(tng_data->output_file)
10516     {
10517         fclose(tng_data->output_file);
10518     }
10519
10520     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10521     temp = realloc(tng_data->output_file_path, len);
10522     if(!temp)
10523     {
10524         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10525                __FILE__, __LINE__);
10526         free(tng_data->output_file_path);
10527         tng_data->output_file_path = 0;
10528         return(TNG_CRITICAL);
10529     }
10530     tng_data->output_file_path = temp;
10531
10532     strncpy(tng_data->output_file_path, file_name, len);
10533
10534     return(tng_output_file_init(tng_data));
10535 }
10536
10537 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
10538                 (tng_trajectory_t tng_data,
10539                  const char *file_name)
10540 {
10541     int len;
10542     char *temp;
10543
10544     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10545     TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
10546
10547     if(tng_data->output_file_path &&
10548        strcmp(tng_data->output_file_path, file_name) == 0)
10549     {
10550         return(TNG_SUCCESS);
10551     }
10552
10553     if(tng_data->output_file)
10554     {
10555         fclose(tng_data->output_file);
10556     }
10557
10558     len = tng_min_i((int)strlen(file_name) + 1, TNG_MAX_STR_LEN);
10559     temp = realloc(tng_data->output_file_path, len);
10560     if(!temp)
10561     {
10562         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
10563                __FILE__, __LINE__);
10564         free(tng_data->output_file_path);
10565         tng_data->output_file_path = 0;
10566         return(TNG_CRITICAL);
10567     }
10568     tng_data->output_file_path = temp;
10569
10570     strncpy(tng_data->output_file_path, file_name, len);
10571
10572     tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
10573     if(!tng_data->output_file)
10574     {
10575         fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
10576                 tng_data->output_file_path, __FILE__, __LINE__);
10577         return(TNG_CRITICAL);
10578     }
10579     tng_data->input_file = tng_data->output_file;
10580
10581     return(TNG_SUCCESS);
10582 }
10583
10584 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
10585                 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
10586 {
10587     tng_endianness_32 end_32;
10588     tng_endianness_64 end_64;
10589
10590     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10591     TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
10592
10593     if(tng_data->output_endianness_swap_func_32)
10594     {
10595         /* If other endianness variants are added they must be added here as well */
10596         if(tng_data->output_endianness_swap_func_32 ==
10597            &tng_swap_byte_order_big_endian_32)
10598         {
10599             end_32 = TNG_BIG_ENDIAN_32;
10600         }
10601         else if(tng_data->output_endianness_swap_func_32 ==
10602                 &tng_swap_byte_order_little_endian_32)
10603         {
10604             end_32 = TNG_LITTLE_ENDIAN_32;
10605         }
10606         else
10607         {
10608             return(TNG_FAILURE);
10609         }
10610     }
10611     else
10612     {
10613         end_32 = (tng_endianness_32)tng_data->endianness_32;
10614     }
10615
10616     if(tng_data->output_endianness_swap_func_64)
10617     {
10618         /* If other endianness variants are added they must be added here as well */
10619         if(tng_data->output_endianness_swap_func_64 ==
10620            &tng_swap_byte_order_big_endian_64)
10621         {
10622             end_64 = TNG_BIG_ENDIAN_64;
10623         }
10624         else if(tng_data->output_endianness_swap_func_64 ==
10625                 &tng_swap_byte_order_little_endian_64)
10626         {
10627             end_64 = TNG_LITTLE_ENDIAN_64;
10628         }
10629         else
10630         {
10631             return(TNG_FAILURE);
10632         }
10633     }
10634     else
10635     {
10636         end_64 = (tng_endianness_64)tng_data->endianness_64;
10637     }
10638
10639     if((int)end_32 != (int)end_64)
10640     {
10641         return(TNG_FAILURE);
10642     }
10643
10644     if(end_32 == TNG_LITTLE_ENDIAN_32)
10645     {
10646         *endianness = TNG_LITTLE_ENDIAN;
10647     }
10648
10649     else if(end_32 == TNG_BIG_ENDIAN_32)
10650     {
10651         *endianness = TNG_BIG_ENDIAN;
10652     }
10653     else
10654     {
10655         return(TNG_FAILURE);
10656     }
10657
10658     return(TNG_SUCCESS);
10659 }
10660
10661 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
10662                 (tng_trajectory_t tng_data,
10663                  const tng_file_endianness endianness)
10664 {
10665     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10666
10667     /* Tne endianness cannot be changed if the data has already been written
10668      * to the output file. */
10669     if(ftello(tng_data->output_file) > 0)
10670     {
10671         return(TNG_FAILURE);
10672     }
10673
10674     if(endianness == TNG_BIG_ENDIAN)
10675     {
10676         if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
10677         {
10678             tng_data->output_endianness_swap_func_32 = 0;
10679         }
10680         else
10681         {
10682             tng_data->output_endianness_swap_func_32 =
10683             &tng_swap_byte_order_big_endian_32;
10684         }
10685         if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
10686         {
10687             tng_data->output_endianness_swap_func_64 = 0;
10688         }
10689         else
10690         {
10691             tng_data->output_endianness_swap_func_64 =
10692             &tng_swap_byte_order_big_endian_64;
10693         }
10694         return(TNG_SUCCESS);
10695     }
10696     else if(endianness == TNG_LITTLE_ENDIAN)
10697     {
10698         if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
10699         {
10700             tng_data->output_endianness_swap_func_32 = 0;
10701         }
10702         else
10703         {
10704             tng_data->output_endianness_swap_func_32 =
10705             &tng_swap_byte_order_little_endian_32;
10706         }
10707         if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
10708         {
10709             tng_data->output_endianness_swap_func_64 = 0;
10710         }
10711         else
10712         {
10713             tng_data->output_endianness_swap_func_64 =
10714             &tng_swap_byte_order_little_endian_64;
10715         }
10716         return(TNG_SUCCESS);
10717     }
10718
10719     /* If the specified endianness is neither big nor little endian return a
10720      * failure. */
10721     return(TNG_FAILURE);
10722 }
10723
10724 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
10725                     (const tng_trajectory_t tng_data,
10726                      char *name, const int max_len)
10727 {
10728     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10729     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10730
10731     strncpy(name, tng_data->first_program_name, max_len - 1);
10732     name[max_len - 1] = 0;
10733
10734     if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
10735     {
10736         return(TNG_FAILURE);
10737     }
10738     return(TNG_SUCCESS);
10739 }
10740
10741 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set(tng_trajectory_t tng_data,
10742                                                                  const char *new_name)
10743 {
10744     unsigned int len;
10745
10746     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10747     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10748
10749     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10750
10751     if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
10752     {
10753         free(tng_data->first_program_name);
10754         tng_data->first_program_name = 0;
10755     }
10756     if(!tng_data->first_program_name)
10757     {
10758         tng_data->first_program_name = malloc(len);
10759         if(!tng_data->first_program_name)
10760         {
10761             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10762                    __FILE__, __LINE__);
10763             return(TNG_CRITICAL);
10764         }
10765     }
10766
10767     strncpy(tng_data->first_program_name, new_name, len);
10768
10769     return(TNG_SUCCESS);
10770 }
10771
10772 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
10773                     (const tng_trajectory_t tng_data,
10774                      char *name, const int max_len)
10775 {
10776     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10777     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10778
10779     strncpy(name, tng_data->last_program_name, max_len - 1);
10780     name[max_len - 1] = 0;
10781
10782     if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
10783     {
10784         return(TNG_FAILURE);
10785     }
10786     return(TNG_SUCCESS);
10787 }
10788
10789 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
10790                     (tng_trajectory_t tng_data,
10791                      const char *new_name)
10792 {
10793     unsigned int len;
10794
10795     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10796     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10797
10798     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10799
10800     if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
10801     {
10802         free(tng_data->last_program_name);
10803         tng_data->last_program_name = 0;
10804     }
10805     if(!tng_data->last_program_name)
10806     {
10807         tng_data->last_program_name = malloc(len);
10808         if(!tng_data->last_program_name)
10809         {
10810             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10811                    __FILE__, __LINE__);
10812             return(TNG_CRITICAL);
10813         }
10814     }
10815
10816     strncpy(tng_data->last_program_name, new_name, len);
10817
10818     return(TNG_SUCCESS);
10819 }
10820
10821 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
10822                     (const tng_trajectory_t tng_data,
10823                      char *name, const int max_len)
10824 {
10825     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10826     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10827
10828     strncpy(name, tng_data->first_user_name, max_len - 1);
10829     name[max_len - 1] = 0;
10830
10831     if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
10832     {
10833         return(TNG_FAILURE);
10834     }
10835     return(TNG_SUCCESS);
10836 }
10837
10838 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
10839                     (tng_trajectory_t tng_data,
10840                      const char *new_name)
10841 {
10842     unsigned int len;
10843
10844     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10845     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10846
10847     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10848
10849     /* If the currently stored string length is not enough to store the new
10850      * string it is freed and reallocated. */
10851     if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
10852     {
10853         free(tng_data->first_user_name);
10854         tng_data->first_user_name = 0;
10855     }
10856     if(!tng_data->first_user_name)
10857     {
10858         tng_data->first_user_name = malloc(len);
10859         if(!tng_data->first_user_name)
10860         {
10861             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10862                    __FILE__, __LINE__);
10863             return(TNG_CRITICAL);
10864         }
10865     }
10866
10867     strncpy(tng_data->first_user_name, new_name, len);
10868
10869     return(TNG_SUCCESS);
10870 }
10871
10872 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
10873                     (const tng_trajectory_t tng_data,
10874                      char *name, const int max_len)
10875 {
10876     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10877     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10878
10879     strncpy(name, tng_data->last_user_name, max_len - 1);
10880     name[max_len - 1] = 0;
10881
10882     if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
10883     {
10884         return(TNG_FAILURE);
10885     }
10886     return(TNG_SUCCESS);
10887 }
10888
10889 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
10890                     (tng_trajectory_t tng_data,
10891                      const char *new_name)
10892 {
10893     unsigned int len;
10894
10895     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10896     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10897
10898     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10899
10900     /* If the currently stored string length is not enough to store the new
10901      * string it is freed and reallocated. */
10902     if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
10903     {
10904         free(tng_data->last_user_name);
10905         tng_data->last_user_name = 0;
10906     }
10907     if(!tng_data->last_user_name)
10908     {
10909         tng_data->last_user_name = malloc(len);
10910         if(!tng_data->last_user_name)
10911         {
10912             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10913                    __FILE__, __LINE__);
10914             return(TNG_CRITICAL);
10915         }
10916     }
10917
10918     strncpy(tng_data->last_user_name, new_name, len);
10919
10920     return(TNG_SUCCESS);
10921 }
10922
10923 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
10924                     (const tng_trajectory_t tng_data,
10925                      char *name, const int max_len)
10926 {
10927     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10928     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10929
10930     strncpy(name, tng_data->first_computer_name, max_len - 1);
10931     name[max_len - 1] = 0;
10932
10933     if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
10934     {
10935         return(TNG_FAILURE);
10936     }
10937     return(TNG_SUCCESS);
10938 }
10939
10940 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
10941                     (tng_trajectory_t tng_data,
10942                      const char *new_name)
10943 {
10944     unsigned int len;
10945
10946     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10947     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10948
10949     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
10950
10951     /* If the currently stored string length is not enough to store the new
10952      * string it is freed and reallocated. */
10953     if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
10954     {
10955         free(tng_data->first_computer_name);
10956         tng_data->first_computer_name = 0;
10957     }
10958     if(!tng_data->first_computer_name)
10959     {
10960         tng_data->first_computer_name = malloc(len);
10961         if(!tng_data->first_computer_name)
10962         {
10963             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
10964                    __FILE__, __LINE__);
10965             return(TNG_CRITICAL);
10966         }
10967     }
10968
10969     strncpy(tng_data->first_computer_name, new_name, len);
10970
10971     return(TNG_SUCCESS);
10972 }
10973
10974 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
10975                     (const tng_trajectory_t tng_data,
10976                      char *name, const int max_len)
10977 {
10978     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10979     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10980
10981     strncpy(name, tng_data->last_computer_name, max_len - 1);
10982     name[max_len - 1] = 0;
10983
10984     if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
10985     {
10986         return(TNG_FAILURE);
10987     }
10988     return(TNG_SUCCESS);
10989 }
10990
10991 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
10992                     (tng_trajectory_t tng_data,
10993                      const char *new_name)
10994 {
10995     unsigned int len;
10996
10997     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10998     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10999
11000     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11001
11002     /* If the currently stored string length is not enough to store the new
11003      * string it is freed and reallocated. */
11004     if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
11005         len)
11006     {
11007         free(tng_data->last_computer_name);
11008         tng_data->last_computer_name = 0;
11009     }
11010     if(!tng_data->last_computer_name)
11011     {
11012         tng_data->last_computer_name = malloc(len);
11013         if(!tng_data->last_computer_name)
11014         {
11015             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11016                    __FILE__, __LINE__);
11017             return(TNG_CRITICAL);
11018         }
11019     }
11020
11021     strncpy(tng_data->last_computer_name, new_name, len);
11022
11023     return(TNG_SUCCESS);
11024 }
11025
11026 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
11027                     (const tng_trajectory_t tng_data,
11028                      char *signature, const int max_len)
11029 {
11030     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11031     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11032
11033     strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
11034     signature[max_len - 1] = 0;
11035
11036     if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
11037     {
11038         return(TNG_FAILURE);
11039     }
11040     return(TNG_SUCCESS);
11041 }
11042
11043 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
11044                     (tng_trajectory_t tng_data,
11045                      const char *signature)
11046 {
11047     unsigned int len;
11048
11049     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11050     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11051
11052     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11053
11054     /* If the currently stored string length is not enough to store the new
11055      * string it is freed and reallocated. */
11056     if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
11057         len)
11058     {
11059         free(tng_data->first_pgp_signature);
11060         tng_data->first_pgp_signature = 0;
11061     }
11062     if(!tng_data->first_pgp_signature)
11063     {
11064         tng_data->first_pgp_signature = malloc(len);
11065         if(!tng_data->first_pgp_signature)
11066         {
11067             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11068                    __FILE__, __LINE__);
11069             return(TNG_CRITICAL);
11070         }
11071     }
11072
11073     strncpy(tng_data->first_pgp_signature, signature, len);
11074
11075     return(TNG_SUCCESS);
11076 }
11077
11078 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
11079                     (const tng_trajectory_t tng_data,
11080                      char *signature, const int max_len)
11081 {
11082     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11083     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11084
11085     strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
11086     signature[max_len - 1] = 0;
11087
11088     if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
11089     {
11090         return(TNG_FAILURE);
11091     }
11092     return(TNG_SUCCESS);
11093 }
11094
11095 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
11096                     (tng_trajectory_t tng_data,
11097                      const char *signature)
11098 {
11099     unsigned int len;
11100
11101     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11102     TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
11103
11104     len = tng_min_i((int)strlen(signature) + 1, TNG_MAX_STR_LEN);
11105
11106     /* If the currently stored string length is not enough to store the new
11107      * string it is freed and reallocated. */
11108     if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
11109         len)
11110     {
11111         free(tng_data->last_pgp_signature);
11112         tng_data->last_pgp_signature = 0;
11113     }
11114     if(!tng_data->last_pgp_signature)
11115     {
11116         tng_data->last_pgp_signature = malloc(len);
11117         if(!tng_data->last_pgp_signature)
11118         {
11119             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11120                    __FILE__, __LINE__);
11121             return(TNG_CRITICAL);
11122         }
11123     }
11124
11125     strncpy(tng_data->last_pgp_signature, signature, len);
11126
11127     return(TNG_SUCCESS);
11128 }
11129
11130 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
11131                     (const tng_trajectory_t tng_data,
11132                      char *name, const int max_len)
11133 {
11134     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11135     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
11136
11137     strncpy(name, tng_data->forcefield_name, max_len - 1);
11138     name[max_len - 1] = 0;
11139
11140     if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
11141     {
11142         return(TNG_FAILURE);
11143     }
11144     return(TNG_SUCCESS);
11145 }
11146
11147 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
11148                     (tng_trajectory_t tng_data,
11149                      const char *new_name)
11150 {
11151     unsigned int len;
11152
11153     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11154     TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
11155
11156     len = tng_min_i((int)strlen(new_name) + 1, TNG_MAX_STR_LEN);
11157
11158     /* If the currently stored string length is not enough to store the new
11159      * string it is freed and reallocated. */
11160     if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
11161     {
11162         free(tng_data->forcefield_name);
11163         tng_data->forcefield_name = 0;
11164     }
11165     if(!tng_data->forcefield_name)
11166     {
11167         tng_data->forcefield_name = malloc(len);
11168         if(!tng_data->forcefield_name)
11169         {
11170             fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
11171                    __FILE__, __LINE__);
11172             return(TNG_CRITICAL);
11173         }
11174     }
11175
11176     strncpy(tng_data->forcefield_name, new_name, len);
11177
11178     return(TNG_SUCCESS);
11179 }
11180
11181 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
11182                     (const tng_trajectory_t tng_data,
11183                      int64_t *len)
11184 {
11185     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11186     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11187
11188     *len = tng_data->medium_stride_length;
11189
11190     return(TNG_SUCCESS);
11191 }
11192
11193 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
11194                     (tng_trajectory_t tng_data,
11195                      const int64_t len)
11196 {
11197     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11198
11199     if(len >= tng_data->long_stride_length)
11200     {
11201         return(TNG_FAILURE);
11202     }
11203     tng_data->medium_stride_length = len;
11204
11205     return(TNG_SUCCESS);
11206 }
11207
11208 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
11209                 (const tng_trajectory_t tng_data,
11210                  int64_t *len)
11211 {
11212     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11213     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11214
11215     *len = tng_data->long_stride_length;
11216
11217     return(TNG_SUCCESS);
11218 }
11219
11220 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
11221                 (tng_trajectory_t tng_data,
11222                  const int64_t len)
11223 {
11224     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11225
11226     if(len <= tng_data->medium_stride_length)
11227     {
11228         return(TNG_FAILURE);
11229     }
11230     tng_data->long_stride_length = len;
11231
11232     return(TNG_SUCCESS);
11233 }
11234
11235 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
11236                 (const tng_trajectory_t tng_data,
11237                  double *time)
11238 {
11239     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11240     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
11241
11242     *time = tng_data->time_per_frame;
11243
11244     return(TNG_SUCCESS);
11245 }
11246
11247 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
11248                 (tng_trajectory_t tng_data,
11249                  const double time)
11250 {
11251     tng_trajectory_frame_set_t frame_set;
11252
11253     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11254     TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
11255
11256     if(fabs(time - tng_data->time_per_frame) < 0.00001)
11257     {
11258         return(TNG_SUCCESS);
11259     }
11260
11261     frame_set = &tng_data->current_trajectory_frame_set;
11262
11263     /* If the current frame set is not finished write it to disk before
11264        changing time per frame. */
11265     if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
11266     {
11267         frame_set->n_frames = frame_set->n_unwritten_frames;
11268         tng_frame_set_write(tng_data, TNG_USE_HASH);
11269     }
11270     tng_data->time_per_frame = time;
11271
11272     return(TNG_SUCCESS);
11273 }
11274
11275 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
11276                     (const tng_trajectory_t tng_data,
11277                      int64_t *len)
11278 {
11279     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11280     TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
11281
11282     *len = tng_data->input_file_len;
11283
11284     return(TNG_SUCCESS);
11285 }
11286
11287 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
11288                     (const tng_trajectory_t tng_data,
11289                      int64_t *n)
11290 {
11291     tng_gen_block_t block;
11292     tng_function_status stat;
11293     int64_t file_pos, last_file_pos, first_frame, n_frames;
11294
11295     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11296     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
11297     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11298
11299     file_pos = ftello(tng_data->input_file);
11300     last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11301
11302     if(last_file_pos <= 0)
11303     {
11304         return(TNG_FAILURE);
11305     }
11306
11307     tng_block_init(&block);
11308     fseeko(tng_data->input_file,
11309            last_file_pos,
11310            SEEK_SET);
11311     /* Read block headers first to see that a frame set block is found. */
11312     stat = tng_block_header_read(tng_data, block);
11313     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11314     {
11315         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
11316                 __FILE__, __LINE__);
11317         tng_block_destroy(&block);
11318         return(TNG_FAILURE);
11319     }
11320     tng_block_destroy(&block);
11321
11322     if(fread(&first_frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
11323     {
11324         fprintf(stderr, "TNG library: Cannot read first frame of frame set. %s: %d\n",
11325                __FILE__, __LINE__);
11326         return(TNG_CRITICAL);
11327     }
11328     if(fread(&n_frames, sizeof(int64_t), 1, tng_data->input_file) == 0)
11329     {
11330         fprintf(stderr, "TNG library: Cannot read n frames of frame set. %s: %d\n",
11331                __FILE__, __LINE__);
11332         return(TNG_CRITICAL);
11333     }
11334     fseeko(tng_data->input_file, file_pos, SEEK_SET);
11335
11336     *n = first_frame + n_frames;
11337
11338     return(TNG_SUCCESS);
11339 }
11340
11341 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
11342                 (const tng_trajectory_t tng_data,
11343                  double *precision)
11344 {
11345     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11346
11347     *precision = tng_data->compression_precision;
11348
11349     return(TNG_SUCCESS);
11350 }
11351
11352 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
11353                 (tng_trajectory_t tng_data,
11354                  const double precision)
11355 {
11356     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11357
11358     tng_data->compression_precision = precision;
11359
11360     return(TNG_SUCCESS);
11361 }
11362
11363 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
11364                 (tng_trajectory_t tng_data,
11365                  const int64_t n)
11366 {
11367     tng_molecule_t mol;
11368     tng_chain_t chain;
11369     tng_residue_t res;
11370     tng_atom_t atom;
11371     tng_function_status stat;
11372     int64_t diff, n_mod, n_impl;
11373
11374     TNG_ASSERT(n >= 0, "TNG library: The number of molecules must be >= 0");
11375
11376     diff = n - tng_data->n_particles;
11377
11378     stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
11379     if(stat == TNG_SUCCESS)
11380     {
11381         if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
11382         {
11383             fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
11384                     __FILE__, __LINE__);
11385             return(TNG_FAILURE);
11386         }
11387         diff -= n_impl * mol->n_atoms;
11388     }
11389
11390     if(diff == 0)
11391     {
11392         if(stat == TNG_SUCCESS)
11393         {
11394             stat = tng_molecule_cnt_set(tng_data, mol, 0);
11395             return(stat);
11396         }
11397         return(TNG_SUCCESS);
11398     }
11399     else if(diff < 0)
11400     {
11401         fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
11402         fprintf(stderr, "particle count.\n");
11403         fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11404                 __FILE__, __LINE__);
11405         /* FIXME: Should we set the count of all other molecules to 0 and add
11406          * implicit molecules? */
11407         return(TNG_FAILURE);
11408     }
11409     if(stat != TNG_SUCCESS)
11410     {
11411         stat = tng_molecule_add(tng_data,
11412                                 "TNG_IMPLICIT_MOL",
11413                                 &mol);
11414         if(stat != TNG_SUCCESS)
11415         {
11416             return(stat);
11417         }
11418         stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
11419         if(stat != TNG_SUCCESS)
11420         {
11421             return(stat);
11422         }
11423         stat = tng_chain_residue_add(tng_data, chain, "", &res);
11424         if(stat != TNG_SUCCESS)
11425         {
11426             return(stat);
11427         }
11428         stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
11429         if(stat != TNG_SUCCESS)
11430         {
11431             return(stat);
11432         }
11433     }
11434     else
11435     {
11436         if(mol->n_atoms > 1)
11437         {
11438             n_mod = diff % mol->n_atoms;
11439             if(n_mod != 0)
11440             {
11441                 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
11442                 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
11443                 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
11444                         __FILE__, __LINE__);
11445                 return(TNG_FAILURE);
11446             }
11447             diff /= mol->n_atoms;
11448         }
11449     }
11450     stat = tng_molecule_cnt_set(tng_data, mol, diff);
11451
11452     return(stat);
11453 }
11454
11455 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
11456                 (const tng_trajectory_t tng_data,
11457                  int64_t *n)
11458 {
11459     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11460     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11461
11462     if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
11463     {
11464         *n = tng_data->n_particles;
11465     }
11466     else
11467     {
11468         *n = tng_data->current_trajectory_frame_set.n_particles;
11469     }
11470
11471     return(TNG_SUCCESS);
11472 }
11473
11474 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
11475                 (const tng_trajectory_t tng_data,
11476                  char *variable)
11477 {
11478     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11479     TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
11480
11481     *variable = tng_data->var_num_atoms_flag;
11482
11483     return(TNG_SUCCESS);
11484 }
11485
11486 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
11487                     (const tng_trajectory_t tng_data,
11488                      int64_t *n)
11489 {
11490     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11491     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11492
11493     *n = tng_data->n_molecules;
11494
11495     return(TNG_SUCCESS);
11496 }
11497
11498 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
11499                     (const tng_trajectory_t tng_data,
11500                      int64_t *n)
11501 {
11502     int64_t *cnt_list = 0, cnt = 0, i;
11503
11504     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11505     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11506
11507     tng_molecule_cnt_list_get(tng_data, &cnt_list);
11508
11509     if(!cnt_list)
11510     {
11511         return(TNG_FAILURE);
11512     }
11513
11514     for(i = 0; i < tng_data->n_molecules; i++)
11515     {
11516         cnt += cnt_list[i];
11517     }
11518
11519     *n = cnt;
11520
11521     return(TNG_SUCCESS);
11522 }
11523
11524 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
11525                 (const tng_trajectory_t tng_data,
11526                  int64_t **mol_cnt_list)
11527 {
11528     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11529
11530     if(tng_data->var_num_atoms_flag)
11531     {
11532         *mol_cnt_list = tng_data->current_trajectory_frame_set.
11533                        molecule_cnt_list;
11534     }
11535     else
11536     {
11537         *mol_cnt_list = tng_data->molecule_cnt_list;
11538     }
11539     if(*mol_cnt_list == 0)
11540     {
11541         return(TNG_FAILURE);
11542     }
11543     return(TNG_SUCCESS);
11544 }
11545
11546 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
11547                 (const tng_trajectory_t tng_data,
11548                  int64_t *exp)
11549 {
11550     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11551     TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
11552
11553     *exp = tng_data->distance_unit_exponential;
11554
11555     return(TNG_SUCCESS);
11556 }
11557
11558 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
11559                 (const tng_trajectory_t tng_data,
11560                  const int64_t exp)
11561 {
11562     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11563
11564     tng_data->distance_unit_exponential = exp;
11565
11566     return(TNG_SUCCESS);
11567 }
11568
11569 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
11570                 (const tng_trajectory_t tng_data,
11571                  int64_t *n)
11572 {
11573     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11574     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11575
11576     *n = tng_data->frame_set_n_frames;
11577
11578     return(TNG_SUCCESS);
11579 }
11580
11581 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
11582                 (const tng_trajectory_t tng_data,
11583                  const int64_t n)
11584 {
11585     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11586
11587     tng_data->frame_set_n_frames = n;
11588
11589     return(TNG_SUCCESS);
11590 }
11591
11592 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
11593                 (const tng_trajectory_t tng_data,
11594                  int64_t *n)
11595 {
11596     int64_t long_stride_length, medium_stride_length;
11597     int64_t file_pos, orig_frame_set_file_pos;
11598     tng_trajectory_frame_set_t frame_set;
11599     struct tng_trajectory_frame_set orig_frame_set;
11600     tng_gen_block_t block;
11601     tng_function_status stat;
11602     int64_t cnt = 0;
11603
11604     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11605     TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
11606
11607     orig_frame_set = tng_data->current_trajectory_frame_set;
11608
11609     frame_set = &tng_data->current_trajectory_frame_set;
11610
11611     orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11612     file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11613
11614     if(file_pos < 0)
11615     {
11616         *n = tng_data->n_trajectory_frame_sets = cnt;
11617         return(TNG_SUCCESS);
11618     }
11619
11620     tng_block_init(&block);
11621     fseeko(tng_data->input_file,
11622           file_pos,
11623           SEEK_SET);
11624     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11625     /* Read block headers first to see what block is found. */
11626     stat = tng_block_header_read(tng_data, block);
11627     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11628     {
11629         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11630                 __FILE__, __LINE__);
11631         tng_block_destroy(&block);
11632         return(TNG_CRITICAL);
11633     }
11634
11635     if(tng_block_read_next(tng_data, block,
11636                         TNG_SKIP_HASH) != TNG_SUCCESS)
11637     {
11638         tng_block_destroy(&block);
11639         return(TNG_CRITICAL);
11640     }
11641
11642     ++cnt;
11643
11644     long_stride_length = tng_data->long_stride_length;
11645     medium_stride_length = tng_data->medium_stride_length;
11646
11647     /* Take long steps forward until a long step forward would be too long or
11648      * the last frame set is found */
11649     file_pos = frame_set->long_stride_next_frame_set_file_pos;
11650     while(file_pos > 0)
11651     {
11652         if(file_pos > 0)
11653         {
11654             cnt += long_stride_length;
11655             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11656             /* Read block headers first to see what block is found. */
11657             stat = tng_block_header_read(tng_data, block);
11658             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11659             {
11660                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11661                        file_pos, __FILE__, __LINE__);
11662                 tng_block_destroy(&block);
11663                 return(TNG_CRITICAL);
11664             }
11665
11666             if(tng_block_read_next(tng_data, block,
11667                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11668             {
11669                 tng_block_destroy(&block);
11670                 return(TNG_CRITICAL);
11671             }
11672         }
11673         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11674     }
11675
11676     /* Take medium steps forward until a medium step forward would be too long
11677      * or the last frame set is found */
11678     file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11679     while(file_pos > 0)
11680     {
11681         if(file_pos > 0)
11682         {
11683             cnt += medium_stride_length;
11684             fseeko(tng_data->input_file,
11685                   file_pos,
11686                   SEEK_SET);
11687             /* Read block headers first to see what block is found. */
11688             stat = tng_block_header_read(tng_data, block);
11689             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11690             {
11691                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11692                        file_pos, __FILE__, __LINE__);
11693                 tng_block_destroy(&block);
11694                 return(TNG_CRITICAL);
11695             }
11696
11697             if(tng_block_read_next(tng_data, block,
11698                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11699             {
11700                 tng_block_destroy(&block);
11701                 return(TNG_CRITICAL);
11702             }
11703         }
11704         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11705     }
11706
11707     /* Take one step forward until the last frame set is found */
11708     file_pos = frame_set->next_frame_set_file_pos;
11709     while(file_pos > 0)
11710     {
11711         if(file_pos > 0)
11712         {
11713             ++cnt;
11714             fseeko(tng_data->input_file,
11715                   file_pos,
11716                   SEEK_SET);
11717             /* Read block headers first to see what block is found. */
11718             stat = tng_block_header_read(tng_data, block);
11719             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11720             {
11721                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11722                        file_pos, __FILE__, __LINE__);
11723                 tng_block_destroy(&block);
11724                 return(TNG_CRITICAL);
11725             }
11726
11727             if(tng_block_read_next(tng_data, block,
11728                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11729             {
11730                 tng_block_destroy(&block);
11731                 return(TNG_CRITICAL);
11732             }
11733         }
11734         file_pos = frame_set->next_frame_set_file_pos;
11735     }
11736
11737     tng_block_destroy(&block);
11738
11739     *n = tng_data->n_trajectory_frame_sets = cnt;
11740
11741     *frame_set = orig_frame_set;
11742     /* The mapping block in the original frame set has been freed when reading
11743      * other frame sets. */
11744     frame_set->mappings = 0;
11745     frame_set->n_mapping_blocks = 0;
11746
11747     fseeko(tng_data->input_file,
11748            tng_data->first_trajectory_frame_set_input_file_pos,
11749            SEEK_SET);
11750
11751     tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
11752
11753     return(TNG_SUCCESS);
11754 }
11755
11756 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
11757                 (const tng_trajectory_t tng_data,
11758                  tng_trajectory_frame_set_t *frame_set_p)
11759 {
11760     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11761
11762     *frame_set_p = &tng_data->current_trajectory_frame_set;
11763
11764     return(TNG_SUCCESS);
11765 }
11766
11767 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
11768                 (tng_trajectory_t tng_data,
11769                  const int64_t nr)
11770 {
11771     int64_t long_stride_length, medium_stride_length;
11772     int64_t file_pos, curr_nr = 0, n_frame_sets;
11773     tng_trajectory_frame_set_t frame_set;
11774     tng_gen_block_t block;
11775     tng_function_status stat;
11776
11777     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11778     TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
11779
11780     frame_set = &tng_data->current_trajectory_frame_set;
11781
11782     stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
11783
11784     if(stat != TNG_SUCCESS)
11785     {
11786         return(stat);
11787     }
11788
11789     if(nr >= n_frame_sets)
11790     {
11791         return(TNG_FAILURE);
11792     }
11793
11794     long_stride_length = tng_data->long_stride_length;
11795     medium_stride_length = tng_data->medium_stride_length;
11796
11797     /* FIXME: The frame set number of the current frame set is not stored */
11798
11799     if(nr < n_frame_sets - 1 - nr)
11800     {
11801         /* Start from the beginning */
11802         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11803     }
11804     else
11805     {
11806         /* Start from the end */
11807         file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11808         curr_nr = n_frame_sets - 1;
11809     }
11810     if(file_pos <= 0)
11811     {
11812         return(TNG_FAILURE);
11813     }
11814
11815     tng_block_init(&block);
11816     fseeko(tng_data->input_file,
11817            file_pos,
11818            SEEK_SET);
11819     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11820     /* Read block headers first to see what block is found. */
11821     stat = tng_block_header_read(tng_data, block);
11822     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11823     {
11824         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
11825                 __FILE__, __LINE__);
11826         tng_block_destroy(&block);
11827         return(TNG_CRITICAL);
11828     }
11829
11830     if(tng_block_read_next(tng_data, block,
11831                         TNG_SKIP_HASH) != TNG_SUCCESS)
11832     {
11833         tng_block_destroy(&block);
11834         return(TNG_CRITICAL);
11835     }
11836
11837     if(curr_nr == nr)
11838     {
11839         tng_block_destroy(&block);
11840         return(TNG_SUCCESS);
11841     }
11842
11843     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11844
11845     /* Take long steps forward until a long step forward would be too long or
11846      * the right frame set is found */
11847     while(file_pos > 0 && curr_nr + long_stride_length <= nr)
11848     {
11849         file_pos = frame_set->long_stride_next_frame_set_file_pos;
11850         if(file_pos > 0)
11851         {
11852             curr_nr += long_stride_length;
11853             fseeko(tng_data->input_file, file_pos, SEEK_SET);
11854             /* Read block headers first to see what block is found. */
11855             stat = tng_block_header_read(tng_data, block);
11856             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11857             {
11858                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11859                        file_pos,  __FILE__, __LINE__);
11860                 tng_block_destroy(&block);
11861                 return(TNG_CRITICAL);
11862             }
11863
11864             if(tng_block_read_next(tng_data, block,
11865                                    TNG_SKIP_HASH) != TNG_SUCCESS)
11866             {
11867                 tng_block_destroy(&block);
11868                 return(TNG_CRITICAL);
11869             }
11870             if(curr_nr == nr)
11871             {
11872                 tng_block_destroy(&block);
11873                 return(TNG_SUCCESS);
11874             }
11875         }
11876     }
11877
11878     /* Take medium steps forward until a medium step forward would be too long
11879      * or the right frame set is found */
11880     while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
11881     {
11882         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11883         if(file_pos > 0)
11884         {
11885             curr_nr += medium_stride_length;
11886             fseeko(tng_data->input_file,
11887                    file_pos,
11888                    SEEK_SET);
11889             /* Read block headers first to see what block is found. */
11890             stat = tng_block_header_read(tng_data, block);
11891             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11892             {
11893                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11894                        file_pos, __FILE__, __LINE__);
11895                 tng_block_destroy(&block);
11896                 return(TNG_CRITICAL);
11897             }
11898
11899             if(tng_block_read_next(tng_data, block,
11900                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11901             {
11902                 tng_block_destroy(&block);
11903                 return(TNG_CRITICAL);
11904             }
11905             if(curr_nr == nr)
11906             {
11907                 tng_block_destroy(&block);
11908                 return(TNG_SUCCESS);
11909             }
11910         }
11911     }
11912
11913     /* Take one step forward until the right frame set is found */
11914     while(file_pos > 0 && curr_nr < nr)
11915     {
11916         file_pos = frame_set->next_frame_set_file_pos;
11917
11918         if(file_pos > 0)
11919         {
11920             ++curr_nr;
11921             fseeko(tng_data->input_file,
11922                    file_pos,
11923                    SEEK_SET);
11924             /* Read block headers first to see what block is found. */
11925             stat = tng_block_header_read(tng_data, block);
11926             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11927             {
11928                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11929                        file_pos, __FILE__, __LINE__);
11930                 tng_block_destroy(&block);
11931                 return(TNG_CRITICAL);
11932             }
11933
11934             if(tng_block_read_next(tng_data, block,
11935                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11936             {
11937                 tng_block_destroy(&block);
11938                 return(TNG_CRITICAL);
11939             }
11940             if(curr_nr == nr)
11941             {
11942                 tng_block_destroy(&block);
11943                 return(TNG_SUCCESS);
11944             }
11945         }
11946     }
11947
11948     /* Take long steps backward until a long step backward would be too long
11949      * or the right frame set is found */
11950     while(file_pos > 0 && curr_nr - long_stride_length >= nr)
11951     {
11952         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11953         if(file_pos > 0)
11954         {
11955             curr_nr -= long_stride_length;
11956             fseeko(tng_data->input_file,
11957                    file_pos,
11958                    SEEK_SET);
11959             /* Read block headers first to see what block is found. */
11960             stat = tng_block_header_read(tng_data, block);
11961             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11962             {
11963                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11964                        file_pos, __FILE__, __LINE__);
11965                 tng_block_destroy(&block);
11966                 return(TNG_CRITICAL);
11967             }
11968
11969             if(tng_block_read_next(tng_data, block,
11970                                 TNG_SKIP_HASH) != TNG_SUCCESS)
11971             {
11972                 tng_block_destroy(&block);
11973                 return(TNG_CRITICAL);
11974             }
11975             if(curr_nr == nr)
11976             {
11977                 tng_block_destroy(&block);
11978                 return(TNG_SUCCESS);
11979             }
11980         }
11981     }
11982
11983     /* Take medium steps backward until a medium step backward would be too long
11984      * or the right frame set is found */
11985     while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
11986     {
11987         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11988         if(file_pos > 0)
11989         {
11990             curr_nr -= medium_stride_length;
11991             fseeko(tng_data->input_file,
11992                    file_pos,
11993                    SEEK_SET);
11994             /* Read block headers first to see what block is found. */
11995             stat = tng_block_header_read(tng_data, block);
11996             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11997             {
11998                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
11999                        file_pos, __FILE__, __LINE__);
12000                 tng_block_destroy(&block);
12001                 return(TNG_CRITICAL);
12002             }
12003
12004             if(tng_block_read_next(tng_data, block,
12005                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12006             {
12007                 tng_block_destroy(&block);
12008                 return(TNG_CRITICAL);
12009             }
12010             if(curr_nr == nr)
12011             {
12012                 tng_block_destroy(&block);
12013                 return(TNG_SUCCESS);
12014             }
12015         }
12016     }
12017
12018     /* Take one step backward until the right frame set is found */
12019     while(file_pos > 0 && curr_nr > nr)
12020     {
12021         file_pos = frame_set->prev_frame_set_file_pos;
12022         if(file_pos > 0)
12023         {
12024             --curr_nr;
12025             fseeko(tng_data->input_file,
12026                    file_pos,
12027                    SEEK_SET);
12028             /* Read block headers first to see what block is found. */
12029             stat = tng_block_header_read(tng_data, block);
12030             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12031             {
12032                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12033                        file_pos, __FILE__, __LINE__);
12034                 tng_block_destroy(&block);
12035                 return(TNG_CRITICAL);
12036             }
12037
12038             if(tng_block_read_next(tng_data, block,
12039                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12040             {
12041                 tng_block_destroy(&block);
12042                 return(TNG_CRITICAL);
12043             }
12044             if(curr_nr == nr)
12045             {
12046                 tng_block_destroy(&block);
12047                 return(TNG_SUCCESS);
12048             }
12049         }
12050     }
12051
12052     /* If for some reason the current frame set is not yet found,
12053      * take one step forward until the right frame set is found */
12054     while(file_pos > 0 && curr_nr < nr)
12055     {
12056         file_pos = frame_set->next_frame_set_file_pos;
12057         if(file_pos > 0)
12058         {
12059             ++curr_nr;
12060             fseeko(tng_data->input_file,
12061                    file_pos,
12062                    SEEK_SET);
12063             /* Read block headers first to see what block is found. */
12064             stat = tng_block_header_read(tng_data, block);
12065             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12066             {
12067                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12068                        file_pos, __FILE__, __LINE__);
12069                 tng_block_destroy(&block);
12070                 return(TNG_CRITICAL);
12071             }
12072
12073             if(tng_block_read_next(tng_data, block,
12074                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12075             {
12076                 tng_block_destroy(&block);
12077                 return(TNG_CRITICAL);
12078             }
12079             if(curr_nr == nr)
12080             {
12081                 tng_block_destroy(&block);
12082                 return(TNG_SUCCESS);
12083             }
12084         }
12085     }
12086
12087     tng_block_destroy(&block);
12088     return(TNG_FAILURE);
12089 }
12090
12091 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
12092                 (tng_trajectory_t tng_data,
12093                  const int64_t frame)
12094 {
12095     int64_t first_frame, last_frame, n_frames_per_frame_set;
12096     int64_t long_stride_length, medium_stride_length;
12097     int64_t file_pos, temp_frame, n_frames;
12098     tng_trajectory_frame_set_t frame_set;
12099     tng_gen_block_t block;
12100     tng_function_status stat;
12101
12102     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12103     TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
12104
12105     frame_set = &tng_data->current_trajectory_frame_set;
12106
12107     tng_block_init(&block);
12108
12109     if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
12110     {
12111         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12112         fseeko(tng_data->input_file,
12113                file_pos,
12114                SEEK_SET);
12115         tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12116         /* Read block headers first to see what block is found. */
12117         stat = tng_block_header_read(tng_data, block);
12118         if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12119         {
12120             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12121                     file_pos, __FILE__, __LINE__);
12122             tng_block_destroy(&block);
12123             return(TNG_CRITICAL);
12124         }
12125
12126         if(tng_block_read_next(tng_data, block,
12127                             TNG_SKIP_HASH) != TNG_SUCCESS)
12128         {
12129             tng_block_destroy(&block);
12130             return(TNG_CRITICAL);
12131         }
12132     }
12133
12134     first_frame = tng_max_i64(frame_set->first_frame, 0);
12135     last_frame = first_frame + frame_set->n_frames - 1;
12136     /* Is this the right frame set? */
12137     if(first_frame <= frame && frame <= last_frame)
12138     {
12139         tng_block_destroy(&block);
12140         return(TNG_SUCCESS);
12141     }
12142
12143     n_frames_per_frame_set = tng_data->frame_set_n_frames;
12144     long_stride_length = tng_data->long_stride_length;
12145     medium_stride_length = tng_data->medium_stride_length;
12146
12147     if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
12148        TNG_SUCCESS)
12149     {
12150         if(temp_frame - first_frame > n_frames_per_frame_set)
12151         {
12152             n_frames_per_frame_set = temp_frame - first_frame;
12153         }
12154     }
12155
12156     tng_num_frames_get(tng_data, &n_frames);
12157
12158     if(frame >= n_frames)
12159     {
12160         tng_block_destroy(&block);
12161         return(TNG_FAILURE);
12162     }
12163
12164     if(first_frame - frame >= frame ||
12165        frame - last_frame >
12166        tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
12167     {
12168         /* Start from the beginning */
12169         if(first_frame - frame >= frame)
12170         {
12171             file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12172
12173             if(file_pos <= 0)
12174             {
12175                 tng_block_destroy(&block);
12176                 return(TNG_FAILURE);
12177             }
12178         }
12179         /* Start from the end */
12180         else if(frame - first_frame > (n_frames - 1) - frame)
12181         {
12182             file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
12183
12184             /* If the last frame set position is not set start from the current
12185              * frame set, since it will be closer than the first frame set. */
12186         }
12187         /* Start from current */
12188         else
12189         {
12190             file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12191         }
12192
12193         if(file_pos > 0)
12194         {
12195             fseeko(tng_data->input_file,
12196                    file_pos,
12197                    SEEK_SET);
12198             tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12199             /* Read block headers first to see what block is found. */
12200             stat = tng_block_header_read(tng_data, block);
12201             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12202             {
12203                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12204                        file_pos, __FILE__, __LINE__);
12205                 tng_block_destroy(&block);
12206                 return(TNG_CRITICAL);
12207             }
12208
12209             if(tng_block_read_next(tng_data, block,
12210                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12211             {
12212                 tng_block_destroy(&block);
12213                 return(TNG_CRITICAL);
12214             }
12215         }
12216     }
12217
12218     first_frame = tng_max_i64(frame_set->first_frame, 0);
12219     last_frame = first_frame + frame_set->n_frames - 1;
12220
12221     if(frame >= first_frame && frame <= last_frame)
12222     {
12223         tng_block_destroy(&block);
12224         return(TNG_SUCCESS);
12225     }
12226
12227     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12228
12229     /* Take long steps forward until a long step forward would be too long or
12230      * the right frame set is found */
12231     while(file_pos > 0 && first_frame + long_stride_length *
12232           n_frames_per_frame_set <= frame)
12233     {
12234         file_pos = frame_set->long_stride_next_frame_set_file_pos;
12235         if(file_pos > 0)
12236         {
12237             fseeko(tng_data->input_file, file_pos, SEEK_SET);
12238             /* Read block headers first to see what block is found. */
12239             stat = tng_block_header_read(tng_data, block);
12240             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12241             {
12242                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12243                        file_pos, __FILE__, __LINE__);
12244                 tng_block_destroy(&block);
12245                 return(TNG_CRITICAL);
12246             }
12247
12248             if(tng_block_read_next(tng_data, block,
12249                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12250             {
12251                 tng_block_destroy(&block);
12252                 return(TNG_CRITICAL);
12253             }
12254         }
12255         first_frame = tng_max_i64(frame_set->first_frame, 0);
12256         last_frame = first_frame + frame_set->n_frames - 1;
12257         if(frame >= first_frame && frame <= last_frame)
12258         {
12259             tng_block_destroy(&block);
12260             return(TNG_SUCCESS);
12261         }
12262     }
12263
12264     /* Take medium steps forward until a medium step forward would be too long
12265      * or the right frame set is found */
12266     while(file_pos > 0 && first_frame + medium_stride_length *
12267           n_frames_per_frame_set <= frame)
12268     {
12269         file_pos = frame_set->medium_stride_next_frame_set_file_pos;
12270         if(file_pos > 0)
12271         {
12272             fseeko(tng_data->input_file,
12273                    file_pos,
12274                    SEEK_SET);
12275             /* Read block headers first to see what block is found. */
12276             stat = tng_block_header_read(tng_data, block);
12277             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12278             {
12279                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12280                        file_pos, __FILE__, __LINE__);
12281                 tng_block_destroy(&block);
12282                 return(TNG_CRITICAL);
12283             }
12284
12285             if(tng_block_read_next(tng_data, block,
12286                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12287             {
12288                 tng_block_destroy(&block);
12289                 return(TNG_CRITICAL);
12290             }
12291         }
12292         first_frame = tng_max_i64(frame_set->first_frame, 0);
12293         last_frame = first_frame + frame_set->n_frames - 1;
12294         if(frame >= first_frame && frame <= last_frame)
12295         {
12296             tng_block_destroy(&block);
12297             return(TNG_SUCCESS);
12298         }
12299     }
12300
12301     /* Take one step forward until the right frame set is found */
12302     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12303     {
12304         file_pos = frame_set->next_frame_set_file_pos;
12305         if(file_pos > 0)
12306         {
12307             fseeko(tng_data->input_file,
12308                    file_pos,
12309                    SEEK_SET);
12310             /* Read block headers first to see what block is found. */
12311             stat = tng_block_header_read(tng_data, block);
12312             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12313             {
12314                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12315                        file_pos, __FILE__, __LINE__);
12316                 tng_block_destroy(&block);
12317                 return(TNG_CRITICAL);
12318             }
12319
12320             if(tng_block_read_next(tng_data, block,
12321                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12322             {
12323                 tng_block_destroy(&block);
12324                 return(TNG_CRITICAL);
12325             }
12326         }
12327         first_frame = tng_max_i64(frame_set->first_frame, 0);
12328         last_frame = first_frame + frame_set->n_frames - 1;
12329         if(frame >= first_frame && frame <= last_frame)
12330         {
12331             tng_block_destroy(&block);
12332             return(TNG_SUCCESS);
12333         }
12334     }
12335
12336     /* Take long steps backward until a long step backward would be too long
12337      * or the right frame set is found */
12338     while(file_pos > 0 && first_frame - long_stride_length *
12339           n_frames_per_frame_set >= frame)
12340     {
12341         file_pos = frame_set->long_stride_prev_frame_set_file_pos;
12342         if(file_pos > 0)
12343         {
12344             fseeko(tng_data->input_file,
12345                    file_pos,
12346                    SEEK_SET);
12347             /* Read block headers first to see what block is found. */
12348             stat = tng_block_header_read(tng_data, block);
12349             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12350             {
12351                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12352                        file_pos, __FILE__, __LINE__);
12353                 tng_block_destroy(&block);
12354                 return(TNG_CRITICAL);
12355             }
12356
12357             if(tng_block_read_next(tng_data, block,
12358                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12359             {
12360                 tng_block_destroy(&block);
12361                 return(TNG_CRITICAL);
12362             }
12363         }
12364         first_frame = tng_max_i64(frame_set->first_frame, 0);
12365         last_frame = first_frame + frame_set->n_frames - 1;
12366         if(frame >= first_frame && frame <= last_frame)
12367         {
12368             tng_block_destroy(&block);
12369             return(TNG_SUCCESS);
12370         }
12371     }
12372
12373     /* Take medium steps backward until a medium step backward would be too long
12374      * or the right frame set is found */
12375     while(file_pos > 0 && first_frame - medium_stride_length *
12376           n_frames_per_frame_set >= frame)
12377     {
12378         file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
12379         if(file_pos > 0)
12380         {
12381             fseeko(tng_data->input_file,
12382                    file_pos,
12383                    SEEK_SET);
12384             /* Read block headers first to see what block is found. */
12385             stat = tng_block_header_read(tng_data, block);
12386             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12387             {
12388                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12389                        file_pos, __FILE__, __LINE__);
12390                 tng_block_destroy(&block);
12391                 return(TNG_CRITICAL);
12392             }
12393
12394             if(tng_block_read_next(tng_data, block,
12395                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12396             {
12397                 tng_block_destroy(&block);
12398                 return(TNG_CRITICAL);
12399             }
12400         }
12401         first_frame = tng_max_i64(frame_set->first_frame, 0);
12402         last_frame = first_frame + frame_set->n_frames - 1;
12403         if(frame >= first_frame && frame <= last_frame)
12404         {
12405             tng_block_destroy(&block);
12406             return(TNG_SUCCESS);
12407         }
12408     }
12409
12410     /* Take one step backward until the right frame set is found */
12411     while(file_pos > 0 && first_frame > frame && last_frame > frame)
12412     {
12413         file_pos = frame_set->prev_frame_set_file_pos;
12414         if(file_pos > 0)
12415         {
12416             fseeko(tng_data->input_file,
12417                    file_pos,
12418                    SEEK_SET);
12419             /* Read block headers first to see what block is found. */
12420             stat = tng_block_header_read(tng_data, block);
12421             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12422             {
12423                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12424                        file_pos, __FILE__, __LINE__);
12425                 tng_block_destroy(&block);
12426                 return(TNG_CRITICAL);
12427             }
12428
12429             if(tng_block_read_next(tng_data, block,
12430                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12431             {
12432                 tng_block_destroy(&block);
12433                 return(TNG_CRITICAL);
12434             }
12435         }
12436         first_frame = tng_max_i64(frame_set->first_frame, 0);
12437         last_frame = first_frame + frame_set->n_frames - 1;
12438         if(frame >= first_frame && frame <= last_frame)
12439         {
12440             tng_block_destroy(&block);
12441             return(TNG_SUCCESS);
12442         }
12443     }
12444
12445     /* If for some reason the current frame set is not yet found,
12446      * take one step forward until the right frame set is found */
12447     while(file_pos > 0 && first_frame < frame && last_frame < frame)
12448     {
12449         file_pos = frame_set->next_frame_set_file_pos;
12450         if(file_pos > 0)
12451         {
12452             fseeko(tng_data->input_file,
12453                    file_pos,
12454                    SEEK_SET);
12455             /* Read block headers first to see what block is found. */
12456             stat = tng_block_header_read(tng_data, block);
12457             if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12458             {
12459                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12460                        file_pos, __FILE__, __LINE__);
12461                 tng_block_destroy(&block);
12462                 return(TNG_CRITICAL);
12463             }
12464
12465             if(tng_block_read_next(tng_data, block,
12466                                 TNG_SKIP_HASH) != TNG_SUCCESS)
12467             {
12468                 tng_block_destroy(&block);
12469                 return(TNG_CRITICAL);
12470             }
12471         }
12472         first_frame = tng_max_i64(frame_set->first_frame, 0);
12473         last_frame = first_frame + frame_set->n_frames - 1;
12474         if(frame >= first_frame && frame <= last_frame)
12475         {
12476             tng_block_destroy(&block);
12477             return(TNG_SUCCESS);
12478         }
12479     }
12480
12481     tng_block_destroy(&block);
12482     return(TNG_FAILURE);
12483 }
12484
12485 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
12486                 (const tng_trajectory_t tng_data,
12487                  const tng_trajectory_frame_set_t frame_set,
12488                  int64_t *pos)
12489 {
12490     (void)tng_data;
12491
12492     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12493     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12494
12495     *pos = frame_set->next_frame_set_file_pos;
12496
12497     return(TNG_SUCCESS);
12498 }
12499
12500 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
12501                 (const tng_trajectory_t tng_data,
12502                  const tng_trajectory_frame_set_t frame_set,
12503                  int64_t *pos)
12504 {
12505     (void)tng_data;
12506
12507     TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
12508     TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
12509
12510     *pos = frame_set->prev_frame_set_file_pos;
12511
12512     return(TNG_SUCCESS);
12513 }
12514
12515 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
12516                 (const tng_trajectory_t tng_data,
12517                  const tng_trajectory_frame_set_t frame_set,
12518                  int64_t *first_frame,
12519                  int64_t *last_frame)
12520 {
12521     (void)tng_data;
12522
12523     TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
12524     TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
12525     TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
12526
12527     *first_frame = frame_set->first_frame;
12528     *last_frame = *first_frame + frame_set->n_frames - 1;
12529
12530     return(TNG_SUCCESS);
12531 }
12532
12533 /** Translate from the particle numbering used in a frame set to the real
12534  *  particle numbering - used in the molecule description.
12535  * @param frame_set is the frame_set containing the mappings to use.
12536  * @param local is the index number of the atom in this frame set
12537  * @param real is set to the index of the atom in the molecular system.
12538  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12539  * cannot be found.
12540  */
12541 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
12542                 (const tng_trajectory_frame_set_t frame_set,
12543                  const int64_t local,
12544                  int64_t *real)
12545 {
12546     int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
12547     tng_particle_mapping_t mapping;
12548     if(n_blocks <= 0)
12549     {
12550         *real = local;
12551         return(TNG_SUCCESS);
12552     }
12553     for(i = 0; i < n_blocks; i++)
12554     {
12555         mapping = &frame_set->mappings[i];
12556         first = mapping->num_first_particle;
12557         if(local < first ||
12558            local >= first + mapping->n_particles)
12559         {
12560             continue;
12561         }
12562         *real = mapping->real_particle_numbers[local-first];
12563         return(TNG_SUCCESS);
12564     }
12565     *real = local;
12566     return(TNG_FAILURE);
12567 }
12568
12569 /** Translate from the real particle numbering to the particle numbering
12570  *  used in a frame set.
12571  * @param frame_set is the frame_set containing the mappings to use.
12572  * @param real is the index number of the atom in the molecular system.
12573  * @param local is set to the index of the atom in this frame set.
12574  * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
12575  * cannot be found.
12576  */
12577 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
12578                 (const tng_trajectory_frame_set_t frame_set,
12579                  const int64_t real,
12580                  int64_t *local)
12581 {
12582     int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
12583     tng_particle_mapping_t mapping;
12584     if(n_blocks <= 0)
12585     {
12586         *local = real;
12587         return(TNG_SUCCESS);
12588     }
12589     for(i = 0; i < n_blocks; i++)
12590     {
12591         mapping = &frame_set->mappings[i];
12592         for(j = mapping->n_particles; j--;)
12593         {
12594             if(mapping->real_particle_numbers[j] == real)
12595             {
12596                 *local = j;
12597                 return(TNG_SUCCESS);
12598             }
12599         }
12600     }
12601     return(TNG_FAILURE);
12602 }
12603 */
12604
12605 static tng_function_status tng_file_headers_len_get
12606                 (tng_trajectory_t tng_data,
12607                  int64_t *len)
12608 {
12609     int64_t orig_pos;
12610     tng_gen_block_t block;
12611
12612     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12613
12614     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12615     {
12616         return(TNG_CRITICAL);
12617     }
12618
12619     *len = 0;
12620
12621     orig_pos = ftello(tng_data->input_file);
12622
12623     if(!tng_data->input_file_len)
12624     {
12625         fseeko(tng_data->input_file, 0, SEEK_END);
12626         tng_data->input_file_len = ftello(tng_data->input_file);
12627     }
12628     fseeko(tng_data->input_file, 0, SEEK_SET);
12629
12630     tng_block_init(&block);
12631     /* Read through the headers of non-trajectory blocks (they come before the
12632      * trajectory blocks in the file) */
12633     while (*len < tng_data->input_file_len &&
12634            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12635            block->id != -1 &&
12636            block->id != TNG_TRAJECTORY_FRAME_SET)
12637     {
12638         *len += block->header_contents_size + block->block_contents_size;
12639         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12640     }
12641
12642     fseeko(tng_data->input_file, orig_pos, SEEK_SET);
12643
12644     tng_block_destroy(&block);
12645
12646     return(TNG_SUCCESS);
12647 }
12648
12649 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
12650                 (tng_trajectory_t tng_data,
12651                  const char hash_mode)
12652 {
12653     int64_t prev_pos = 0;
12654     tng_gen_block_t block;
12655
12656     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12657
12658     tng_data->n_trajectory_frame_sets = 0;
12659
12660     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12661     {
12662         return(TNG_CRITICAL);
12663     }
12664
12665     if(!tng_data->input_file_len)
12666     {
12667         fseeko(tng_data->input_file, 0, SEEK_END);
12668         tng_data->input_file_len = ftello(tng_data->input_file);
12669     }
12670     fseeko(tng_data->input_file, 0, SEEK_SET);
12671
12672     tng_block_init(&block);
12673     /* Non trajectory blocks (they come before the trajectory
12674      * blocks in the file) */
12675     while (prev_pos < tng_data->input_file_len &&
12676            tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
12677            block->id != -1 &&
12678            block->id != TNG_TRAJECTORY_FRAME_SET)
12679     {
12680         tng_block_read_next(tng_data, block, hash_mode);
12681         prev_pos = ftello(tng_data->input_file);
12682     }
12683
12684     /* Go back if a trajectory block was encountered */
12685     if(block->id == TNG_TRAJECTORY_FRAME_SET)
12686     {
12687         fseeko(tng_data->input_file, prev_pos, SEEK_SET);
12688     }
12689
12690     tng_block_destroy(&block);
12691
12692     return(TNG_SUCCESS);
12693 }
12694
12695 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
12696                 (tng_trajectory_t tng_data,
12697                  const char hash_mode)
12698 {
12699     int i;
12700     int64_t len, orig_len, tot_len = 0, data_start_pos;
12701     tng_function_status stat;
12702     tng_gen_block_t block;
12703
12704     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12705
12706     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
12707     {
12708         return(TNG_CRITICAL);
12709     }
12710
12711     if(tng_data->n_trajectory_frame_sets > 0)
12712     {
12713         stat = tng_file_headers_len_get(tng_data, &orig_len);
12714         if(stat != TNG_SUCCESS)
12715         {
12716             return(stat);
12717         }
12718
12719         tng_block_init(&block);
12720         block->name = malloc(TNG_MAX_STR_LEN);
12721         if(!block->name)
12722         {
12723             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
12724                     TNG_MAX_STR_LEN, __FILE__, __LINE__);
12725             tng_block_destroy(&block);
12726             return(TNG_CRITICAL);
12727         }
12728         strcpy(block->name, "GENERAL INFO");
12729         tng_block_header_len_calculate(tng_data, block, &len);
12730         tot_len += len;
12731         tng_general_info_block_len_calculate(tng_data, &len);
12732         tot_len += len;
12733         strcpy(block->name, "MOLECULES");
12734         tng_block_header_len_calculate(tng_data, block, &len);
12735         tot_len += len;
12736         tng_molecules_block_len_calculate(tng_data, &len);
12737         tot_len += len;
12738
12739         for(i = 0; i < tng_data->n_data_blocks; i++)
12740         {
12741             strcpy(block->name, tng_data->non_tr_data[i].block_name);
12742             tng_block_header_len_calculate(tng_data, block, &len);
12743             tot_len += len;
12744             tng_data_block_len_calculate(tng_data,
12745                                         (tng_particle_data_t)&tng_data->non_tr_data[i],
12746                                         TNG_FALSE, 1, 1, 1, 0,
12747                                         1, 0, &data_start_pos,
12748                                         &len);
12749             tot_len += len;
12750         }
12751         for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12752         {
12753             strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
12754             tng_block_header_len_calculate(tng_data, block, &len);
12755             tot_len += len;
12756             tng_data_block_len_calculate(tng_data,
12757                                         &tng_data->non_tr_particle_data[i],
12758                                         TNG_TRUE, 1, 1, 1, 0,
12759                                         tng_data->n_particles, TNG_PARTICLE_DEPENDENT,
12760                                         &data_start_pos,
12761                                         &len);
12762             tot_len += len;
12763         }
12764         tng_block_destroy(&block);
12765
12766         if(tot_len > orig_len)
12767         {
12768             tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len);
12769         }
12770
12771         tng_data->current_trajectory_frame_set_output_file_pos = -1;
12772     }
12773
12774     /* TODO: If there is already frame set data written to this file (e.g. when
12775      * appending to an already existing file we might need to move frame sets to
12776      * the end of the file. */
12777
12778     if(tng_general_info_block_write(tng_data, hash_mode)
12779        != TNG_SUCCESS)
12780     {
12781         fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
12782                 tng_data->input_file_path, __FILE__, __LINE__);
12783         return(TNG_CRITICAL);
12784     }
12785
12786     if(tng_molecules_block_write(tng_data, hash_mode)
12787         != TNG_SUCCESS)
12788     {
12789         fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
12790                 tng_data->input_file_path, __FILE__, __LINE__);
12791         return(TNG_CRITICAL);
12792     }
12793
12794     /* FIXME: Currently writing non-trajectory data blocks here.
12795      * Should perhaps be moved. */
12796     tng_block_init(&block);
12797     for(i = 0; i < tng_data->n_data_blocks; i++)
12798     {
12799         block->id = tng_data->non_tr_data[i].block_id;
12800         tng_data_block_write(tng_data, block,
12801                              i, hash_mode);
12802     }
12803
12804     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12805     {
12806         block->id = tng_data->non_tr_particle_data[i].block_id;
12807         tng_particle_data_block_write(tng_data, block,
12808                                       i, 0, hash_mode);
12809     }
12810
12811     tng_block_destroy(&block);
12812
12813     return(TNG_SUCCESS);
12814 }
12815
12816 tng_function_status DECLSPECDLLEXPORT tng_block_read_next(tng_trajectory_t tng_data,
12817                                         tng_gen_block_t block,
12818                                         const char hash_mode)
12819 {
12820     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12821     TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
12822
12823     switch(block->id)
12824     {
12825     case TNG_TRAJECTORY_FRAME_SET:
12826         return(tng_frame_set_block_read(tng_data, block, hash_mode));
12827     case TNG_PARTICLE_MAPPING:
12828         return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
12829     case TNG_GENERAL_INFO:
12830         return(tng_general_info_block_read(tng_data, block, hash_mode));
12831     case TNG_MOLECULES:
12832         return(tng_molecules_block_read(tng_data, block, hash_mode));
12833     default:
12834         if(block->id >= TNG_TRAJ_BOX_SHAPE)
12835         {
12836             return(tng_data_block_contents_read(tng_data, block, hash_mode));
12837         }
12838         else
12839         {
12840             /* Skip to the next block */
12841             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12842             return(TNG_FAILURE);
12843         }
12844     }
12845 }
12846
12847 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
12848                 (tng_trajectory_t tng_data,
12849                  const char hash_mode)
12850 {
12851     int64_t file_pos;
12852     tng_gen_block_t block;
12853     tng_function_status stat;
12854
12855     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12856
12857     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12858     {
12859         return(TNG_CRITICAL);
12860     }
12861
12862     file_pos = ftello(tng_data->input_file);
12863
12864     tng_block_init(&block);
12865
12866     if(!tng_data->input_file_len)
12867     {
12868         fseeko(tng_data->input_file, 0, SEEK_END);
12869         tng_data->input_file_len = ftello(tng_data->input_file);
12870         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12871     }
12872
12873     /* Read block headers first to see what block is found. */
12874     stat = tng_block_header_read(tng_data, block);
12875     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
12876        block->id == -1)
12877     {
12878         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12879                file_pos, __FILE__, __LINE__);
12880         tng_block_destroy(&block);
12881         return(TNG_CRITICAL);
12882     }
12883
12884     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12885
12886     if(tng_block_read_next(tng_data, block,
12887                            hash_mode) == TNG_SUCCESS)
12888     {
12889         tng_data->n_trajectory_frame_sets++;
12890         file_pos = ftello(tng_data->input_file);
12891         /* Read all blocks until next frame set block */
12892         stat = tng_block_header_read(tng_data, block);
12893         while(file_pos < tng_data->input_file_len &&
12894               stat != TNG_CRITICAL &&
12895               block->id != TNG_TRAJECTORY_FRAME_SET &&
12896               block->id != -1)
12897         {
12898             stat = tng_block_read_next(tng_data, block,
12899                                        hash_mode);
12900             if(stat != TNG_CRITICAL)
12901             {
12902                 file_pos = ftello(tng_data->input_file);
12903                 if(file_pos < tng_data->input_file_len)
12904                 {
12905                     stat = tng_block_header_read(tng_data, block);
12906                 }
12907             }
12908         }
12909         if(stat == TNG_CRITICAL)
12910         {
12911             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12912                    file_pos, __FILE__, __LINE__);
12913             tng_block_destroy(&block);
12914             return(stat);
12915         }
12916
12917         if(block->id == TNG_TRAJECTORY_FRAME_SET)
12918         {
12919             fseeko(tng_data->input_file, file_pos, SEEK_SET);
12920         }
12921     }
12922
12923     tng_block_destroy(&block);
12924
12925     return(TNG_SUCCESS);
12926 }
12927
12928
12929 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
12930                 (tng_trajectory_t tng_data,
12931                  const char hash_mode,
12932                  const int64_t block_id)
12933 {
12934     int64_t file_pos;
12935     tng_gen_block_t block;
12936     tng_function_status stat;
12937     int found_flag = 1;
12938
12939     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12940
12941     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12942     {
12943         return(TNG_CRITICAL);
12944     }
12945
12946     file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
12947
12948     if(file_pos < 0)
12949     {
12950         /* No current frame set. This means that the first frame set must be
12951          * read */
12952         found_flag = 0;
12953         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12954     }
12955
12956     if(file_pos > 0)
12957     {
12958         fseeko(tng_data->input_file,
12959               file_pos,
12960               SEEK_SET);
12961     }
12962     else
12963     {
12964         return(TNG_FAILURE);
12965     }
12966
12967     tng_block_init(&block);
12968
12969     if(!tng_data->input_file_len)
12970     {
12971         fseeko(tng_data->input_file, 0, SEEK_END);
12972         tng_data->input_file_len = ftello(tng_data->input_file);
12973         fseeko(tng_data->input_file, file_pos, SEEK_SET);
12974     }
12975
12976     /* Read block headers first to see what block is found. */
12977     stat = tng_block_header_read(tng_data, block);
12978     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12979     {
12980         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
12981                file_pos, __FILE__, __LINE__);
12982         tng_block_destroy(&block);
12983         return(TNG_CRITICAL);
12984     }
12985     /* If the current frame set had already been read skip its block contents */
12986     if(found_flag)
12987     {
12988         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
12989     }
12990     /* Otherwiese read the frame set block */
12991     else
12992     {
12993         stat = tng_block_read_next(tng_data, block,
12994                                    hash_mode);
12995         if(stat != TNG_SUCCESS)
12996         {
12997             fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
12998             tng_block_destroy(&block);
12999             return(stat);
13000         }
13001     }
13002     file_pos = ftello(tng_data->input_file);
13003
13004     found_flag = 0;
13005
13006     /* Read only blocks of the requested ID
13007         * until next frame set block */
13008     stat = tng_block_header_read(tng_data, block);
13009     while(file_pos < tng_data->input_file_len &&
13010             stat != TNG_CRITICAL &&
13011             block->id != TNG_TRAJECTORY_FRAME_SET &&
13012             block->id != -1)
13013     {
13014         if(block->id == block_id)
13015         {
13016             stat = tng_block_read_next(tng_data, block,
13017                                        hash_mode);
13018             if(stat != TNG_CRITICAL)
13019             {
13020                 file_pos = ftello(tng_data->input_file);
13021                 found_flag = 1;
13022                 if(file_pos < tng_data->input_file_len)
13023                 {
13024                     stat = tng_block_header_read(tng_data, block);
13025                 }
13026             }
13027         }
13028         else
13029         {
13030             file_pos += (block->block_contents_size + block->header_contents_size);
13031             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
13032             if(file_pos < tng_data->input_file_len)
13033             {
13034                 stat = tng_block_header_read(tng_data, block);
13035             }
13036         }
13037     }
13038     if(stat == TNG_CRITICAL)
13039     {
13040         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13041                 file_pos, __FILE__, __LINE__);
13042         tng_block_destroy(&block);
13043         return(stat);
13044     }
13045
13046     if(block->id == TNG_TRAJECTORY_FRAME_SET)
13047     {
13048         fseeko(tng_data->input_file, file_pos, SEEK_SET);
13049     }
13050
13051     tng_block_destroy(&block);
13052
13053     if(found_flag)
13054     {
13055         return(TNG_SUCCESS);
13056     }
13057     else
13058     {
13059         return(TNG_FAILURE);
13060     }
13061 }
13062
13063 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
13064                 (tng_trajectory_t tng_data,
13065                  const char hash_mode)
13066 {
13067     int64_t file_pos;
13068
13069     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13070
13071     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13072     {
13073         return(TNG_CRITICAL);
13074     }
13075
13076     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13077
13078     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13079     {
13080         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13081     }
13082
13083     if(file_pos > 0)
13084     {
13085         fseeko(tng_data->input_file,
13086               file_pos,
13087               SEEK_SET);
13088     }
13089     else
13090     {
13091         return(TNG_FAILURE);
13092     }
13093
13094     return(tng_frame_set_read(tng_data, hash_mode));
13095 }
13096
13097 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
13098                 (tng_trajectory_t tng_data,
13099                  const char hash_mode,
13100                  const int64_t block_id)
13101 {
13102     int64_t file_pos;
13103     tng_gen_block_t block;
13104     tng_function_status stat;
13105
13106     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13107
13108     if(tng_input_file_init(tng_data) != TNG_SUCCESS)
13109     {
13110         return(TNG_CRITICAL);
13111     }
13112
13113     file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
13114
13115     if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13116     {
13117         file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13118     }
13119
13120     if(file_pos > 0)
13121     {
13122         fseeko(tng_data->input_file,
13123               file_pos,
13124               SEEK_SET);
13125     }
13126     else
13127     {
13128         return(TNG_FAILURE);
13129     }
13130
13131     tng_block_init(&block);
13132
13133     if(!tng_data->input_file_len)
13134     {
13135         fseeko(tng_data->input_file, 0, SEEK_END);
13136         tng_data->input_file_len = ftello(tng_data->input_file);
13137         fseeko(tng_data->input_file, file_pos, SEEK_SET);
13138     }
13139
13140     /* Read block headers first to see what block is found. */
13141     stat = tng_block_header_read(tng_data, block);
13142     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13143     {
13144         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13145                file_pos, __FILE__, __LINE__);
13146         tng_block_destroy(&block);
13147         return(TNG_CRITICAL);
13148     }
13149
13150     tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
13151
13152     if(tng_block_read_next(tng_data, block,
13153                            hash_mode) == TNG_SUCCESS)
13154     {
13155         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
13156     }
13157
13158     tng_block_destroy(&block);
13159
13160     return(stat);
13161 }
13162
13163 tng_function_status tng_frame_set_write(tng_trajectory_t tng_data,
13164                                         const char hash_mode)
13165 {
13166     int i, j;
13167     tng_gen_block_t block;
13168     tng_trajectory_frame_set_t frame_set;
13169     tng_function_status stat;
13170
13171     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13172
13173     frame_set = &tng_data->current_trajectory_frame_set;
13174
13175     if(frame_set->n_written_frames == frame_set->n_frames)
13176     {
13177         return(TNG_SUCCESS);
13178     }
13179
13180     tng_data->current_trajectory_frame_set_output_file_pos =
13181     ftello(tng_data->output_file);
13182     tng_data->last_trajectory_frame_set_output_file_pos =
13183     tng_data->current_trajectory_frame_set_output_file_pos;
13184
13185     if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
13186     {
13187         return(TNG_FAILURE);
13188     }
13189
13190     if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
13191     {
13192         tng_data->first_trajectory_frame_set_output_file_pos =
13193         tng_data->current_trajectory_frame_set_output_file_pos;
13194     }
13195
13196     tng_block_init(&block);
13197
13198     if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
13199     {
13200         tng_block_destroy(&block);
13201         return(TNG_FAILURE);
13202     }
13203
13204     /* Write non-particle data blocks */
13205     for(i = 0; i<frame_set->n_data_blocks; i++)
13206     {
13207         block->id = frame_set->tr_data[i].block_id;
13208         tng_data_block_write(tng_data, block, i, hash_mode);
13209     }
13210     /* Write the mapping blocks and particle data blocks*/
13211     if(frame_set->n_mapping_blocks)
13212     {
13213         for(i = 0; i < frame_set->n_mapping_blocks; i++)
13214         {
13215             block->id = TNG_PARTICLE_MAPPING;
13216             if(frame_set->mappings[i].n_particles > 0)
13217             {
13218                 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
13219                 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
13220                 {
13221                     block->id = frame_set->tr_particle_data[j].block_id;
13222                     tng_particle_data_block_write(tng_data, block,
13223                                                   j, &frame_set->mappings[i],
13224                                                   hash_mode);
13225                 }
13226             }
13227         }
13228     }
13229     else
13230     {
13231         for(i = 0; i<frame_set->n_particle_data_blocks; i++)
13232         {
13233             block->id = frame_set->tr_particle_data[i].block_id;
13234             tng_particle_data_block_write(tng_data, block,
13235                                           i, 0, hash_mode);
13236         }
13237     }
13238
13239
13240     /* Update pointers in the general info block */
13241     stat = tng_header_pointers_update(tng_data, hash_mode);
13242
13243     if(stat == TNG_SUCCESS)
13244     {
13245         stat = tng_frame_set_pointers_update(tng_data, hash_mode);
13246     }
13247
13248     tng_block_destroy(&block);
13249
13250     frame_set->n_unwritten_frames = 0;
13251
13252     fflush(tng_data->output_file);
13253
13254     return(stat);
13255 }
13256
13257 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
13258                 (tng_trajectory_t tng_data,
13259                  const char hash_mode)
13260 {
13261     tng_trajectory_frame_set_t frame_set;
13262
13263     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13264
13265     frame_set = &tng_data->current_trajectory_frame_set;
13266
13267     if(frame_set->n_unwritten_frames == 0)
13268     {
13269         return(TNG_SUCCESS);
13270     }
13271     frame_set->n_frames = frame_set->n_unwritten_frames;
13272
13273     return(tng_frame_set_write(tng_data, hash_mode));
13274 }
13275
13276 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
13277                 (tng_trajectory_t tng_data,
13278                  const int64_t first_frame,
13279                  const int64_t n_frames)
13280 {
13281     tng_gen_block_t block;
13282     tng_trajectory_frame_set_t frame_set;
13283     FILE *temp = tng_data->input_file;
13284     int64_t curr_pos;
13285
13286     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13287     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13288     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13289
13290     frame_set = &tng_data->current_trajectory_frame_set;
13291
13292     curr_pos = ftello(tng_data->output_file);
13293
13294     if(curr_pos <= 10)
13295     {
13296         tng_file_headers_write(tng_data, TNG_USE_HASH);
13297     }
13298
13299     /* Set pointer to previous frame set to the one that was loaded
13300      * before.
13301      * FIXME: This is a bit risky. If they are not added in order
13302      * it will be wrong. */
13303     if(tng_data->n_trajectory_frame_sets)
13304     {
13305         frame_set->prev_frame_set_file_pos =
13306         tng_data->current_trajectory_frame_set_output_file_pos;
13307     }
13308
13309     tng_data->current_trajectory_frame_set_output_file_pos =
13310     ftello(tng_data->output_file);
13311
13312     tng_data->n_trajectory_frame_sets++;
13313
13314     /* Set the medium range pointers */
13315     if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
13316     {
13317         frame_set->medium_stride_prev_frame_set_file_pos =
13318         tng_data->first_trajectory_frame_set_output_file_pos;
13319     }
13320     else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13321     {
13322         /* FIXME: Currently only working if the previous frame set has its
13323          * medium stride pointer already set. This might need some fixing. */
13324         if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
13325            frame_set->medium_stride_prev_frame_set_file_pos != 0)
13326         {
13327             tng_block_init(&block);
13328             tng_data->input_file = tng_data->output_file;
13329
13330             curr_pos = ftello(tng_data->output_file);
13331             fseeko(tng_data->output_file,
13332                    frame_set->medium_stride_prev_frame_set_file_pos,
13333                    SEEK_SET);
13334
13335             if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13336             {
13337                 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13338                     __FILE__, __LINE__);
13339                 tng_data->input_file = temp;
13340                 tng_block_destroy(&block);
13341                 return(TNG_CRITICAL);
13342             }
13343
13344             /* Read the next frame set from the previous frame set and one
13345              * medium stride step back */
13346             fseeko(tng_data->output_file, block->block_contents_size - (6 *
13347             sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13348             if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
13349                sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
13350                1, tng_data->output_file) == 0)
13351             {
13352                 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13353                 tng_data->input_file = temp;
13354                 tng_block_destroy(&block);
13355                 return(TNG_CRITICAL);
13356             }
13357
13358             if(tng_data->input_endianness_swap_func_64)
13359             {
13360                 if(tng_data->input_endianness_swap_func_64(tng_data,
13361                    &frame_set->medium_stride_prev_frame_set_file_pos)
13362                     != TNG_SUCCESS)
13363                 {
13364                     fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13365                             __FILE__, __LINE__);
13366                 }
13367             }
13368
13369             tng_block_destroy(&block);
13370
13371             /* Set the long range pointers */
13372             if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
13373             {
13374                 frame_set->long_stride_prev_frame_set_file_pos =
13375                 tng_data->first_trajectory_frame_set_output_file_pos;
13376             }
13377             else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
13378             {
13379                 /* FIXME: Currently only working if the previous frame set has its
13380                 * long stride pointer already set. This might need some fixing. */
13381                 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
13382                 frame_set->long_stride_prev_frame_set_file_pos != 0)
13383                 {
13384                     tng_block_init(&block);
13385                     tng_data->input_file = tng_data->output_file;
13386
13387                     fseeko(tng_data->output_file,
13388                            frame_set->long_stride_prev_frame_set_file_pos,
13389                            SEEK_SET);
13390
13391                     if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
13392                     {
13393                         fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
13394                             __FILE__, __LINE__);
13395                         tng_data->input_file = temp;
13396                         tng_block_destroy(&block);
13397                         return(TNG_CRITICAL);
13398                     }
13399
13400                     /* Read the next frame set from the previous frame set and one
13401                     * long stride step back */
13402                     fseeko(tng_data->output_file, block->block_contents_size - (6 *
13403                           sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
13404
13405                     tng_block_destroy(&block);
13406
13407                     if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
13408                     sizeof(frame_set->long_stride_prev_frame_set_file_pos),
13409                     1, tng_data->output_file) == 0)
13410                     {
13411                         fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
13412                         tng_data->input_file = temp;
13413                         return(TNG_CRITICAL);
13414                     }
13415
13416                     if(tng_data->input_endianness_swap_func_64)
13417                     {
13418                         if(tng_data->input_endianness_swap_func_64(tng_data,
13419                            &frame_set->long_stride_prev_frame_set_file_pos)
13420                             != TNG_SUCCESS)
13421                         {
13422                             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13423                                     __FILE__, __LINE__);
13424                         }
13425                     }
13426
13427                 }
13428             }
13429
13430             tng_data->input_file = temp;
13431             fseeko(tng_data->output_file, curr_pos, SEEK_SET);
13432         }
13433     }
13434
13435     frame_set->first_frame = first_frame;
13436     frame_set->n_frames = n_frames;
13437     frame_set->n_written_frames = 0;
13438     frame_set->n_unwritten_frames = 0;
13439     frame_set->first_frame_time = -1;
13440
13441     if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
13442        tng_data->first_trajectory_frame_set_output_file_pos == 0)
13443     {
13444         tng_data->first_trajectory_frame_set_output_file_pos =
13445         tng_data->current_trajectory_frame_set_output_file_pos;
13446     }
13447     /* FIXME: Should check the frame number instead of the file_pos,
13448      * in case frame sets are not in order */
13449     if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
13450        tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
13451        tng_data->last_trajectory_frame_set_output_file_pos <
13452        tng_data->current_trajectory_frame_set_output_file_pos)
13453     {
13454         tng_data->last_trajectory_frame_set_output_file_pos =
13455         tng_data->current_trajectory_frame_set_output_file_pos;
13456     }
13457
13458     return(TNG_SUCCESS);
13459 }
13460
13461 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
13462                 (tng_trajectory_t tng_data,
13463                  const int64_t first_frame,
13464                  const int64_t n_frames,
13465                  const double first_frame_time)
13466 {
13467     tng_function_status stat;
13468
13469     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13470     TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
13471     TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
13472     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13473
13474
13475     stat = tng_frame_set_new(tng_data, first_frame, n_frames);
13476     if(stat != TNG_SUCCESS)
13477     {
13478         return(stat);
13479     }
13480     stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
13481
13482     return(stat);
13483 }
13484
13485 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
13486                 (tng_trajectory_t tng_data,
13487                  const double first_frame_time)
13488 {
13489     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13490     TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
13491
13492     tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
13493
13494     return(TNG_SUCCESS);
13495 }
13496
13497 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
13498                 (const tng_trajectory_t tng_data,
13499                  int64_t *frame)
13500 {
13501     int64_t file_pos, next_frame_set_file_pos;
13502     tng_gen_block_t block;
13503     tng_function_status stat;
13504
13505     tng_trajectory_frame_set_t frame_set;
13506
13507     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13508     TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
13509     TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
13510
13511     file_pos = ftello(tng_data->input_file);
13512
13513     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13514     {
13515         next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
13516     }
13517     else
13518     {
13519         frame_set = &tng_data->current_trajectory_frame_set;
13520         next_frame_set_file_pos = frame_set->next_frame_set_file_pos;
13521     }
13522
13523     if(next_frame_set_file_pos <= 0)
13524     {
13525         return(TNG_FAILURE);
13526     }
13527
13528     fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET);
13529     /* Read block headers first to see that a frame set block is found. */
13530     tng_block_init(&block);
13531     stat = tng_block_header_read(tng_data, block);
13532     if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
13533     {
13534         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
13535                file_pos, __FILE__, __LINE__);
13536         return(TNG_CRITICAL);
13537     }
13538 /*    if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
13539     {
13540         tng_block_read_next(tng_data, block, TNG_USE_HASH);
13541     }*/
13542     tng_block_destroy(&block);
13543
13544     if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
13545     {
13546         fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
13547                __FILE__, __LINE__);
13548         return(TNG_CRITICAL);
13549     }
13550     fseeko(tng_data->input_file, file_pos, SEEK_SET);
13551
13552     return(TNG_SUCCESS);
13553 }
13554
13555 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
13556                 (tng_trajectory_t tng_data,
13557                  const int64_t id,
13558                  const char *block_name,
13559                  const char datatype,
13560                  const char block_type_flag,
13561                  int64_t n_frames,
13562                  const int64_t n_values_per_frame,
13563                  int64_t stride_length,
13564                  const int64_t codec_id,
13565                  void *new_data)
13566 {
13567     int i, j, size, len;
13568     tng_trajectory_frame_set_t frame_set;
13569     tng_non_particle_data_t data;
13570     char **first_dim_values;
13571     char *new_data_c=new_data;
13572     int64_t n_frames_div;
13573
13574     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13575     TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
13576     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13577
13578     frame_set = &tng_data->current_trajectory_frame_set;
13579
13580     if(stride_length <= 0)
13581     {
13582         stride_length = 1;
13583     }
13584
13585     /* If the block does not exist, create it */
13586     if(tng_data_find(tng_data, id, &data) != TNG_SUCCESS)
13587     {
13588         if(tng_data_block_create(tng_data, block_type_flag) !=
13589             TNG_SUCCESS)
13590         {
13591             fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
13592                    __FILE__, __LINE__);
13593             return(TNG_CRITICAL);
13594         }
13595         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13596         {
13597             data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
13598         }
13599         else
13600         {
13601             data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
13602         }
13603         data->block_id = id;
13604
13605         data->block_name = malloc(strlen(block_name) + 1);
13606         if(!data->block_name)
13607         {
13608             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13609                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13610             return(TNG_CRITICAL);
13611         }
13612         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13613
13614         data->values = 0;
13615         /* FIXME: Memory leak from strings. */
13616         data->strings = 0;
13617         data->last_retrieved_frame = -1;
13618     }
13619
13620     data->datatype = datatype;
13621     data->stride_length = tng_max_i64(stride_length, 1);
13622     data->n_values_per_frame = n_values_per_frame;
13623     data->n_frames = n_frames;
13624     data->codec_id = codec_id;
13625     data->compression_multiplier = 1.0;
13626     /* FIXME: This can cause problems. */
13627     data->first_frame_with_data = frame_set->first_frame;
13628
13629     switch(datatype)
13630     {
13631     case TNG_FLOAT_DATA:
13632         size = sizeof(float);
13633         break;
13634     case TNG_INT_DATA:
13635         size = sizeof(int64_t);
13636         break;
13637     case TNG_DOUBLE_DATA:
13638     default:
13639         size = sizeof(double);
13640         break;
13641     }
13642
13643     if(new_data_c)
13644     {
13645         /* Allocate memory */
13646         if(tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
13647                                  n_values_per_frame) !=
13648         TNG_SUCCESS)
13649         {
13650             fprintf(stderr, "TNG library: Cannot allocate data memory. %s: %d\n",
13651                 __FILE__, __LINE__);
13652             return(TNG_CRITICAL);
13653         }
13654
13655         if(n_frames > frame_set->n_unwritten_frames)
13656         {
13657             frame_set->n_unwritten_frames = n_frames;
13658         }
13659
13660         n_frames_div = (n_frames % stride_length) ?
13661                      n_frames / stride_length + 1:
13662                      n_frames / stride_length;
13663
13664         if(datatype == TNG_CHAR_DATA)
13665         {
13666             for(i = 0; i < n_frames_div; i++)
13667             {
13668                 first_dim_values = data->strings[i];
13669                 for(j = 0; j < n_values_per_frame; j++)
13670                 {
13671                     len = tng_min_i((int)strlen(new_data_c) + 1,
13672                                 TNG_MAX_STR_LEN);
13673                     if(first_dim_values[j])
13674                     {
13675                         free(first_dim_values[j]);
13676                     }
13677                     first_dim_values[j] = malloc(len);
13678                     if(!first_dim_values[j])
13679                     {
13680                         fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13681                             len, __FILE__, __LINE__);
13682                         return(TNG_CRITICAL);
13683                     }
13684                     strncpy(first_dim_values[j],
13685                             new_data_c, len);
13686                     new_data_c += len;
13687                 }
13688             }
13689         }
13690         else
13691         {
13692             memcpy(data->values, new_data, size * n_frames_div *
13693                    n_values_per_frame);
13694         }
13695     }
13696
13697     return(TNG_SUCCESS);
13698 }
13699
13700 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
13701                 (tng_trajectory_t tng_data,
13702                  const int64_t id,
13703                  const char *block_name,
13704                  const char datatype,
13705                  const char block_type_flag,
13706                  int64_t n_frames,
13707                  const int64_t n_values_per_frame,
13708                  int64_t stride_length,
13709                  const int64_t num_first_particle,
13710                  const int64_t n_particles,
13711                  const int64_t codec_id,
13712                  void *new_data)
13713 {
13714     int i, size, len;
13715     int64_t j, k;
13716     int64_t tot_n_particles, n_frames_div;
13717     char ***first_dim_values, **second_dim_values;
13718     tng_trajectory_frame_set_t frame_set;
13719     tng_particle_data_t data;
13720     char *new_data_c=new_data;
13721
13722     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13723     TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
13724     TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
13725     TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
13726     TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
13727
13728
13729     frame_set = &tng_data->current_trajectory_frame_set;
13730
13731     if(stride_length <= 0)
13732     {
13733         stride_length = 1;
13734     }
13735
13736     /* If the block does not exist, create it */
13737     if(tng_particle_data_find(tng_data, id, &data) != TNG_SUCCESS)
13738     {
13739         if(tng_particle_data_block_create(tng_data, block_type_flag) !=
13740             TNG_SUCCESS)
13741         {
13742             fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
13743                    __FILE__, __LINE__);
13744             return(TNG_CRITICAL);
13745         }
13746         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
13747         {
13748             data = &frame_set->tr_particle_data[frame_set->
13749                                                 n_particle_data_blocks - 1];
13750         }
13751         else
13752         {
13753             data = &tng_data->non_tr_particle_data[tng_data->
13754                                                    n_particle_data_blocks - 1];
13755         }
13756         data->block_id = id;
13757
13758         data->block_name = malloc(strlen(block_name) + 1);
13759         if(!data->block_name)
13760         {
13761             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13762                    (int)strlen(block_name)+1, __FILE__, __LINE__);
13763             return(TNG_CRITICAL);
13764         }
13765         strncpy(data->block_name, block_name, strlen(block_name) + 1);
13766
13767         data->datatype = datatype;
13768
13769         data->values = 0;
13770         /* FIXME: Memory leak from strings. */
13771         data->strings = 0;
13772         data->last_retrieved_frame = -1;
13773     }
13774
13775     data->stride_length = tng_max_i64(stride_length, 1);
13776     data->n_values_per_frame = n_values_per_frame;
13777     data->n_frames = n_frames;
13778     data->codec_id = codec_id;
13779     data->compression_multiplier = 1.0;
13780     /* FIXME: This can cause problems. */
13781     data->first_frame_with_data = frame_set->first_frame;
13782
13783     if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
13784     {
13785         tot_n_particles = frame_set->n_particles;
13786     }
13787     else
13788     {
13789         tot_n_particles = tng_data->n_particles;
13790     }
13791
13792     /* If data values are supplied add that data to the data block. */
13793     if(new_data_c)
13794     {
13795         /* Allocate memory */
13796         if(tng_allocate_particle_data_mem(tng_data, data, n_frames,
13797                                           stride_length, tot_n_particles,
13798                                           n_values_per_frame) !=
13799         TNG_SUCCESS)
13800         {
13801             fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
13802                 __FILE__, __LINE__);
13803             return(TNG_CRITICAL);
13804         }
13805
13806         if(n_frames > frame_set->n_unwritten_frames)
13807         {
13808             frame_set->n_unwritten_frames = n_frames;
13809         }
13810
13811         n_frames_div = (n_frames % stride_length) ?
13812                      n_frames / stride_length + 1:
13813                      n_frames / stride_length;
13814
13815         if(datatype == TNG_CHAR_DATA)
13816         {
13817             for(i = 0; i < n_frames_div; i++)
13818             {
13819                 first_dim_values = data->strings[i];
13820                 for(j = num_first_particle; j < num_first_particle + n_particles;
13821                     j++)
13822                 {
13823                     second_dim_values = first_dim_values[j];
13824                     for(k = 0; k < n_values_per_frame; k++)
13825                     {
13826                         len = tng_min_i((int)strlen(new_data_c) + 1,
13827                                 TNG_MAX_STR_LEN);
13828                         if(second_dim_values[k])
13829                         {
13830                             free(second_dim_values[k]);
13831                         }
13832                         second_dim_values[k] = malloc(len);
13833                         if(!second_dim_values[k])
13834                         {
13835                             fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
13836                                 len, __FILE__, __LINE__);
13837                             return(TNG_CRITICAL);
13838                         }
13839                         strncpy(second_dim_values[k],
13840                                 new_data_c, len);
13841                         new_data_c += len;
13842                     }
13843                 }
13844             }
13845         }
13846         else
13847         {
13848             switch(datatype)
13849             {
13850             case TNG_INT_DATA:
13851                 size = sizeof(int64_t);
13852                 break;
13853             case TNG_FLOAT_DATA:
13854                 size = sizeof(float);
13855                 break;
13856             case TNG_DOUBLE_DATA:
13857             default:
13858                 size = sizeof(double);
13859             }
13860
13861             memcpy(data->values, new_data, size * n_frames_div *
13862                    n_particles * n_values_per_frame);
13863         }
13864     }
13865
13866     return(TNG_SUCCESS);
13867 }
13868
13869 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
13870                 (tng_trajectory_t tng_data,
13871                  int64_t block_id,
13872                  char *name,
13873                  int max_len)
13874 {
13875     int64_t i;
13876     tng_trajectory_frame_set_t frame_set;
13877     tng_function_status stat;
13878     tng_particle_data_t p_data;
13879     tng_non_particle_data_t np_data;
13880     int block_type = -1;
13881
13882     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13883     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
13884
13885     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13886     {
13887         p_data = &tng_data->non_tr_particle_data[i];
13888         if(p_data->block_id == block_id)
13889         {
13890             strncpy(name, p_data->block_name, max_len);
13891             name[max_len - 1] = '\0';
13892             return(TNG_SUCCESS);
13893         }
13894     }
13895     for(i = 0; i < tng_data->n_data_blocks; i++)
13896     {
13897         np_data = &tng_data->non_tr_data[i];
13898         if(np_data->block_id == block_id)
13899         {
13900             strncpy(name, np_data->block_name, max_len);
13901             name[max_len - 1] = '\0';
13902             return(TNG_SUCCESS);
13903         }
13904     }
13905
13906     frame_set = &tng_data->current_trajectory_frame_set;
13907
13908     stat = tng_particle_data_find(tng_data, block_id, &p_data);
13909     if(stat == TNG_SUCCESS)
13910     {
13911         block_type = TNG_PARTICLE_BLOCK_DATA;
13912     }
13913     else
13914     {
13915         stat = tng_data_find(tng_data, block_id, &np_data);
13916         if(stat == TNG_SUCCESS)
13917         {
13918             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13919         }
13920         else
13921         {
13922             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13923             if(stat != TNG_SUCCESS)
13924             {
13925                 return(stat);
13926             }
13927             stat = tng_particle_data_find(tng_data, block_id, &p_data);
13928             if(stat == TNG_SUCCESS)
13929             {
13930                 block_type = TNG_PARTICLE_BLOCK_DATA;
13931             }
13932             else
13933             {
13934                 stat = tng_data_find(tng_data, block_id, &np_data);
13935                 if(stat == TNG_SUCCESS)
13936                 {
13937                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
13938                 }
13939             }
13940         }
13941     }
13942     if(block_type == TNG_PARTICLE_BLOCK_DATA)
13943     {
13944         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13945         {
13946             p_data = &frame_set->tr_particle_data[i];
13947             if(p_data->block_id == block_id)
13948             {
13949                 strncpy(name, p_data->block_name, max_len);
13950                 name[max_len - 1] = '\0';
13951                 return(TNG_SUCCESS);
13952             }
13953         }
13954     }
13955     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
13956     {
13957         for(i = 0; i < frame_set->n_data_blocks; i++)
13958         {
13959             np_data = &frame_set->tr_data[i];
13960             if(np_data->block_id == block_id)
13961             {
13962                 strncpy(name, np_data->block_name, max_len);
13963                 name[max_len - 1] = '\0';
13964                 return(TNG_SUCCESS);
13965             }
13966         }
13967     }
13968
13969     return(TNG_FAILURE);
13970 }
13971
13972 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
13973                 (const tng_trajectory_t tng_data,
13974                  int64_t block_id,
13975                  int *block_dependency)
13976 {
13977     int64_t i;
13978     tng_function_status stat;
13979     tng_particle_data_t p_data;
13980     tng_non_particle_data_t np_data;
13981
13982     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13983     TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
13984
13985     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13986     {
13987         p_data = &tng_data->non_tr_particle_data[i];
13988         if(p_data->block_id == block_id)
13989         {
13990             *block_dependency = TNG_PARTICLE_DEPENDENT;
13991             return(TNG_SUCCESS);
13992         }
13993     }
13994     for(i = 0; i < tng_data->n_data_blocks; i++)
13995     {
13996         np_data = &tng_data->non_tr_data[i];
13997         if(np_data->block_id == block_id)
13998         {
13999             *block_dependency = 0;
14000             return(TNG_SUCCESS);
14001         }
14002     }
14003
14004     stat = tng_particle_data_find(tng_data, block_id, &p_data);
14005     if(stat == TNG_SUCCESS)
14006     {
14007         *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
14008         return(TNG_SUCCESS);
14009     }
14010     else
14011     {
14012         stat = tng_data_find(tng_data, block_id, &np_data);
14013         if(stat == TNG_SUCCESS)
14014         {
14015             *block_dependency = TNG_FRAME_DEPENDENT;
14016             return(TNG_SUCCESS);
14017         }
14018         else
14019         {
14020             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
14021             if(stat != TNG_SUCCESS)
14022             {
14023                 return(stat);
14024             }
14025             stat = tng_particle_data_find(tng_data, block_id, &p_data);
14026             if(stat == TNG_SUCCESS)
14027             {
14028                 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
14029                 return(TNG_SUCCESS);
14030             }
14031             else
14032             {
14033                 stat = tng_data_find(tng_data, block_id, &np_data);
14034                 if(stat == TNG_SUCCESS)
14035                 {
14036                     *block_dependency = TNG_FRAME_DEPENDENT;
14037                     return(TNG_SUCCESS);
14038                 }
14039             }
14040         }
14041     }
14042
14043     return(TNG_FAILURE);
14044 }
14045
14046 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
14047                 (const tng_trajectory_t tng_data,
14048                  int64_t block_id,
14049                  int64_t *n_values_per_frame)
14050 {
14051     int64_t i;
14052     tng_function_status stat;
14053     tng_particle_data_t p_data;
14054     tng_non_particle_data_t np_data;
14055
14056     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14057     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14058
14059     for(i = 0; i < tng_data->n_particle_data_blocks; i++)
14060     {
14061         p_data = &tng_data->non_tr_particle_data[i];
14062         if(p_data->block_id == block_id)
14063         {
14064             *n_values_per_frame = p_data->n_values_per_frame;
14065             return(TNG_SUCCESS);
14066         }
14067     }
14068     for(i = 0; i < tng_data->n_data_blocks; i++)
14069     {
14070         np_data = &tng_data->non_tr_data[i];
14071         if(np_data->block_id == block_id)
14072         {
14073             *n_values_per_frame = np_data->n_values_per_frame;
14074             return(TNG_SUCCESS);
14075         }
14076     }
14077
14078     stat = tng_particle_data_find(tng_data, block_id, &p_data);
14079     if(stat == TNG_SUCCESS)
14080     {
14081         *n_values_per_frame = p_data->n_values_per_frame;
14082         return(TNG_SUCCESS);
14083     }
14084     else
14085     {
14086         stat = tng_data_find(tng_data, block_id, &np_data);
14087         if(stat == TNG_SUCCESS)
14088         {
14089             *n_values_per_frame = np_data->n_values_per_frame;
14090             return(TNG_SUCCESS);
14091         }
14092         else
14093         {
14094             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
14095             if(stat != TNG_SUCCESS)
14096             {
14097                 return(stat);
14098             }
14099             stat = tng_particle_data_find(tng_data, block_id, &p_data);
14100             if(stat == TNG_SUCCESS)
14101             {
14102                 *n_values_per_frame = p_data->n_values_per_frame;
14103                 return(TNG_SUCCESS);
14104             }
14105             else
14106             {
14107                 stat = tng_data_find(tng_data, block_id, &np_data);
14108                 if(stat == TNG_SUCCESS)
14109                 {
14110                     *n_values_per_frame = np_data->n_values_per_frame;
14111                     return(TNG_SUCCESS);
14112                 }
14113             }
14114         }
14115     }
14116
14117     return(TNG_FAILURE);
14118 }
14119
14120 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
14121                 (tng_trajectory_t tng_data,
14122                  const int64_t frame_nr,
14123                  const int64_t block_id,
14124                  const void *values,
14125                  const char hash_mode)
14126 {
14127     int64_t header_pos, file_pos;
14128     int64_t output_file_len, n_values_per_frame, size, contents_size;
14129     int64_t header_size, temp_first, temp_last;
14130     int64_t i, last_frame, temp_current;
14131     tng_gen_block_t block;
14132     tng_trajectory_frame_set_t frame_set;
14133     FILE *temp = tng_data->input_file;
14134     struct tng_non_particle_data data;
14135     tng_function_status stat;
14136     char dependency, sparse_data, datatype;
14137     void *copy;
14138
14139     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14140     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14141     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14142
14143     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14144     {
14145         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14146                __FILE__, __LINE__);
14147         return(TNG_CRITICAL);
14148     }
14149
14150     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14151     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14152     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14153     tng_data->first_trajectory_frame_set_input_file_pos =
14154     tng_data->first_trajectory_frame_set_output_file_pos;
14155     tng_data->last_trajectory_frame_set_input_file_pos =
14156     tng_data->last_trajectory_frame_set_output_file_pos;
14157     tng_data->current_trajectory_frame_set_input_file_pos =
14158     tng_data->current_trajectory_frame_set_output_file_pos;
14159
14160     tng_data->input_file = tng_data->output_file;
14161
14162     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14163
14164     frame_set = &tng_data->current_trajectory_frame_set;
14165
14166     if(stat != TNG_SUCCESS)
14167     {
14168         last_frame = frame_set->first_frame +
14169                      frame_set->n_frames - 1;
14170         /* If the wanted frame would be in the frame set after the last
14171             * frame set create a new frame set. */
14172         if(stat == TNG_FAILURE &&
14173             last_frame < frame_nr)
14174 /*           (last_frame < frame_nr &&
14175             tng_data->current_trajectory_frame_set.first_frame +
14176             tng_data->frame_set_n_frames >= frame_nr))*/
14177         {
14178             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14179             {
14180                 last_frame = frame_nr - 1;
14181             }
14182             tng_frame_set_new(tng_data,
14183                               last_frame+1,
14184                               tng_data->frame_set_n_frames);
14185             file_pos = ftello(tng_data->output_file);
14186             fseeko(tng_data->output_file, 0, SEEK_END);
14187             output_file_len = ftello(tng_data->output_file);
14188             fseeko(tng_data->output_file, file_pos, SEEK_SET);
14189
14190             /* Read mapping blocks from the last frame set */
14191             tng_block_init(&block);
14192
14193             stat = tng_block_header_read(tng_data, block);
14194             while(file_pos < output_file_len &&
14195                   stat != TNG_CRITICAL &&
14196                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14197                   block->id != -1)
14198             {
14199                 if(block->id == TNG_PARTICLE_MAPPING)
14200                 {
14201                     tng_trajectory_mapping_block_read(tng_data, block,
14202                                                       hash_mode);
14203                 }
14204                 else
14205                 {
14206                     fseeko(tng_data->output_file, block->block_contents_size,
14207                            SEEK_CUR);
14208                 }
14209                 file_pos = ftello(tng_data->output_file);
14210                 if(file_pos < output_file_len)
14211                 {
14212                     stat = tng_block_header_read(tng_data, block);
14213                 }
14214             }
14215
14216             tng_block_destroy(&block);
14217             /* Write the frame set to disk */
14218             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14219             {
14220                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14221                 return(TNG_CRITICAL);
14222             }
14223         }
14224         else
14225         {
14226             tng_data->input_file = temp;
14227             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14228             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14229             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14230             return(stat);
14231         }
14232     }
14233
14234     tng_block_init(&block);
14235
14236     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14237
14238     fseeko(tng_data->output_file, 0, SEEK_END);
14239     output_file_len = ftello(tng_data->output_file);
14240     fseeko(tng_data->output_file, file_pos, SEEK_SET);
14241
14242     /* Read past the frame set block first */
14243     stat = tng_block_header_read(tng_data, block);
14244     if(stat == TNG_CRITICAL)
14245     {
14246         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14247                file_pos, __FILE__, __LINE__);
14248         tng_block_destroy(&block);
14249         tng_data->input_file = temp;
14250
14251         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14252         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14253         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14254         return(stat);
14255     }
14256     fseeko(tng_data->output_file, block->block_contents_size,
14257            SEEK_CUR);
14258
14259     /* Read all block headers until next frame set block or
14260      * until the wanted block id is found */
14261     stat = tng_block_header_read(tng_data, block);
14262     while(file_pos < output_file_len &&
14263             stat != TNG_CRITICAL &&
14264             block->id != block_id &&
14265             block->id != TNG_TRAJECTORY_FRAME_SET &&
14266             block->id != -1)
14267     {
14268         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
14269         file_pos = ftello(tng_data->output_file);
14270         if(file_pos < output_file_len)
14271         {
14272             stat = tng_block_header_read(tng_data, block);
14273         }
14274     }
14275     if(stat == TNG_CRITICAL)
14276     {
14277         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14278                file_pos, __FILE__, __LINE__);
14279         tng_block_destroy(&block);
14280         tng_data->input_file = temp;
14281         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14282         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14283         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14284         return(stat);
14285     }
14286
14287     contents_size = block->block_contents_size;
14288     header_size = block->header_contents_size;
14289
14290     header_pos = ftello(tng_data->output_file) - header_size;
14291     frame_set = &tng_data->current_trajectory_frame_set;
14292
14293     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14294     {
14295         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14296         tng_block_destroy(&block);
14297         return(TNG_CRITICAL);
14298     }
14299     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14300     {
14301         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14302         tng_block_destroy(&block);
14303         return(TNG_CRITICAL);
14304     }
14305     data.datatype = datatype;
14306
14307     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14308        (dependency & TNG_PARTICLE_DEPENDENT))
14309     {
14310         tng_block_destroy(&block);
14311         tng_data->input_file = temp;
14312
14313         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14314         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14315         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14316         return(TNG_FAILURE);
14317     }
14318
14319     if(fread(&sparse_data, sizeof(sparse_data), 1, 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
14326     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14327              tng_data->input_file) == 0)
14328     {
14329         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14330         tng_block_destroy(&block);
14331         return(TNG_CRITICAL);
14332     }
14333     if(tng_data->output_endianness_swap_func_64)
14334     {
14335         if(tng_data->output_endianness_swap_func_64(tng_data,
14336             &data.n_values_per_frame)
14337             != TNG_SUCCESS)
14338         {
14339             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14340                     __FILE__, __LINE__);
14341         }
14342     }
14343
14344     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14345              tng_data->input_file) == 0)
14346     {
14347         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14348         tng_block_destroy(&block);
14349         return(TNG_CRITICAL);
14350     }
14351     if(tng_data->output_endianness_swap_func_64)
14352     {
14353         if(tng_data->output_endianness_swap_func_64(tng_data,
14354             &data.codec_id)
14355             != TNG_SUCCESS)
14356         {
14357             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14358                     __FILE__, __LINE__);
14359         }
14360     }
14361
14362     if(data.codec_id != TNG_UNCOMPRESSED)
14363     {
14364         if(fread(&data.compression_multiplier,
14365                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14366             == 0)
14367         {
14368             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14369             tng_block_destroy(&block);
14370             return(TNG_CRITICAL);
14371         }
14372         if(tng_data->output_endianness_swap_func_64)
14373         {
14374             if(tng_data->output_endianness_swap_func_64(tng_data,
14375                 (int64_t *)&data.compression_multiplier)
14376                 != TNG_SUCCESS)
14377             {
14378                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14379                         __FILE__, __LINE__);
14380             }
14381         }
14382     }
14383     else
14384     {
14385         data.compression_multiplier = 1;
14386     }
14387
14388     if(sparse_data)
14389     {
14390         if(fread(&data.first_frame_with_data, sizeof(data.first_frame_with_data),
14391                  1, tng_data->input_file) == 0)
14392         {
14393             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14394             tng_block_destroy(&block);
14395             return(TNG_CRITICAL);
14396         }
14397         if(tng_data->output_endianness_swap_func_64)
14398         {
14399             if(tng_data->output_endianness_swap_func_64(tng_data,
14400                 &data.first_frame_with_data)
14401                 != TNG_SUCCESS)
14402             {
14403                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14404                         __FILE__, __LINE__);
14405             }
14406         }
14407
14408         if(fread(&data.stride_length, sizeof(data.stride_length),
14409                  1, tng_data->input_file) == 0)
14410         {
14411             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14412             tng_block_destroy(&block);
14413             return(TNG_CRITICAL);
14414         }
14415         if(tng_data->output_endianness_swap_func_64)
14416         {
14417             if(tng_data->output_endianness_swap_func_64(tng_data,
14418                 &data.stride_length)
14419                 != TNG_SUCCESS)
14420             {
14421                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14422                         __FILE__, __LINE__);
14423             }
14424         }
14425     }
14426     else
14427     {
14428         data.first_frame_with_data = 0;
14429         data.stride_length = 1;
14430     }
14431     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14432
14433     tng_data->input_file = temp;
14434
14435     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14436     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14437     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14438
14439     switch(data.datatype)
14440     {
14441         case(TNG_INT_DATA):
14442             size = sizeof(int64_t);
14443             break;
14444         case(TNG_FLOAT_DATA):
14445             size = sizeof(float);
14446             break;
14447         case(TNG_DOUBLE_DATA):
14448             size = sizeof(double);
14449             break;
14450         default:
14451             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14452                    __LINE__);
14453             tng_block_destroy(&block);
14454             return(TNG_FAILURE);
14455     }
14456
14457     n_values_per_frame = data.n_values_per_frame;
14458
14459     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
14460                                data.first_frame_with_data)) /
14461                 data.stride_length;
14462     file_pos *= size * n_values_per_frame;
14463
14464     if(file_pos > contents_size)
14465     {
14466         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
14467                __LINE__);
14468         tng_block_destroy(&block);
14469         return(TNG_FAILURE);
14470     }
14471
14472     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
14473
14474     /* If the endianness is not big endian the data needs to be swapped */
14475     if((data.datatype == TNG_INT_DATA ||
14476         data.datatype == TNG_DOUBLE_DATA) &&
14477        tng_data->output_endianness_swap_func_64)
14478     {
14479         copy = malloc(n_values_per_frame * size);
14480         memcpy(copy, values, n_values_per_frame * size);
14481         for(i = 0; i < n_values_per_frame; i++)
14482         {
14483             if(tng_data->output_endianness_swap_func_64(tng_data,
14484                 (int64_t *)copy+i)
14485                 != TNG_SUCCESS)
14486             {
14487                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14488                         __FILE__, __LINE__);
14489             }
14490         }
14491         fwrite(copy, n_values_per_frame, size,
14492                tng_data->output_file);
14493         free(copy);
14494     }
14495     else if(data.datatype == TNG_FLOAT_DATA &&
14496             tng_data->output_endianness_swap_func_32)
14497     {
14498         copy = malloc(n_values_per_frame * size);
14499         memcpy(copy, values, n_values_per_frame * size);
14500         for(i = 0; i < n_values_per_frame; i++)
14501         {
14502             if(tng_data->output_endianness_swap_func_32(tng_data,
14503                 (int32_t *)copy+i)
14504                 != TNG_SUCCESS)
14505             {
14506                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14507                         __FILE__, __LINE__);
14508             }
14509         }
14510         fwrite(copy, n_values_per_frame, size,
14511                tng_data->output_file);
14512         free(copy);
14513     }
14514
14515     else
14516     {
14517         fwrite(values, n_values_per_frame, size, tng_data->output_file);
14518     }
14519
14520     fflush(tng_data->output_file);
14521
14522     /* Update the number of written frames in the frame set. */
14523     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
14524     {
14525         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
14526     }
14527
14528     /* If the last frame has been written update the hash */
14529     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
14530        data.first_frame_with_data) >=
14531        frame_set->n_frames)
14532     {
14533         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
14534                             header_size);
14535     }
14536
14537     tng_block_destroy(&block);
14538
14539     return(TNG_SUCCESS);
14540 }
14541
14542 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
14543                 (tng_trajectory_t tng_data,
14544                  const int64_t frame_nr,
14545                  const int64_t block_id,
14546                  const int64_t val_first_particle,
14547                  const int64_t val_n_particles,
14548                  const void *values,
14549                  const char hash_mode)
14550 {
14551     int64_t header_pos, file_pos, tot_n_particles;
14552     int64_t output_file_len, n_values_per_frame, size, contents_size;
14553     int64_t header_size, temp_first, temp_last;
14554     int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
14555     int64_t i, last_frame, temp_current;
14556     tng_gen_block_t block;
14557     tng_trajectory_frame_set_t frame_set;
14558     FILE *temp = tng_data->input_file;
14559     struct tng_particle_data data;
14560     tng_function_status stat;
14561     tng_particle_mapping_t mapping;
14562     char dependency, sparse_data, datatype;
14563     void *copy;
14564
14565     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14566     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
14567     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
14568     TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
14569     TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
14570
14571     if(tng_output_file_init(tng_data) != TNG_SUCCESS)
14572     {
14573         fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
14574                __FILE__, __LINE__);
14575         return(TNG_CRITICAL);
14576     }
14577
14578     temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
14579     temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
14580     temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
14581     tng_data->first_trajectory_frame_set_input_file_pos =
14582     tng_data->first_trajectory_frame_set_output_file_pos;
14583     tng_data->last_trajectory_frame_set_input_file_pos =
14584     tng_data->last_trajectory_frame_set_output_file_pos;
14585     tng_data->current_trajectory_frame_set_input_file_pos =
14586     tng_data->current_trajectory_frame_set_output_file_pos;
14587
14588     tng_data->input_file = tng_data->output_file;
14589
14590     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
14591
14592     frame_set = &tng_data->current_trajectory_frame_set;
14593
14594     if(stat != TNG_SUCCESS)
14595     {
14596         last_frame = frame_set->first_frame +
14597                      frame_set->n_frames - 1;
14598 /*         fprintf(stderr, "TNG library: Frame %"PRId64" not found. Last frame: %"PRId64"\n", frame_nr,
14599                   last_frame); */
14600         /* If the wanted frame would be in the frame set after the last
14601          * frame set create a new frame set. */
14602         if(stat == TNG_FAILURE &&
14603            (last_frame < frame_nr &&
14604             last_frame + tng_data->frame_set_n_frames >= frame_nr))
14605         {
14606             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
14607             {
14608                 last_frame = frame_nr - 1;
14609             }
14610             tng_frame_set_new(tng_data,
14611                               last_frame+1,
14612                               tng_data->frame_set_n_frames);
14613
14614             file_pos = ftello(tng_data->output_file);
14615             fseeko(tng_data->output_file, 0, SEEK_END);
14616             output_file_len = ftello(tng_data->output_file);
14617             fseeko(tng_data->output_file, file_pos, SEEK_SET);
14618
14619             /* Read mapping blocks from the last frame set */
14620             tng_block_init(&block);
14621
14622             stat = tng_block_header_read(tng_data, block);
14623             while(file_pos < output_file_len &&
14624                   stat != TNG_CRITICAL &&
14625                   block->id != TNG_TRAJECTORY_FRAME_SET &&
14626                   block->id != -1)
14627             {
14628                 if(block->id == TNG_PARTICLE_MAPPING)
14629                 {
14630                     tng_trajectory_mapping_block_read(tng_data, block,
14631                                                       hash_mode);
14632                 }
14633                 else
14634                 {
14635                     fseeko(tng_data->output_file, block->block_contents_size,
14636                         SEEK_CUR);
14637                 }
14638                 file_pos = ftello(tng_data->output_file);
14639                 if(file_pos < output_file_len)
14640                 {
14641                     stat = tng_block_header_read(tng_data, block);
14642                 }
14643             }
14644
14645             tng_block_destroy(&block);
14646             /* Write the frame set to disk */
14647             if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
14648             {
14649                 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
14650                 exit(1);
14651             }
14652         }
14653         else
14654         {
14655             tng_data->input_file = temp;
14656             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14657             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14658             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14659             return(stat);
14660         }
14661     }
14662
14663
14664     tng_block_init(&block);
14665
14666     file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
14667
14668     fseeko(tng_data->output_file, 0, SEEK_END);
14669     output_file_len = ftello(tng_data->output_file);
14670     fseeko(tng_data->output_file, file_pos, SEEK_SET);
14671
14672     /* Read past the frame set block first */
14673     stat = tng_block_header_read(tng_data, block);
14674     if(stat == TNG_CRITICAL)
14675     {
14676         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14677                file_pos, __FILE__, __LINE__);
14678         tng_block_destroy(&block);
14679         tng_data->input_file = temp;
14680
14681         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14682         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14683         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14684         return(stat);
14685     }
14686     fseeko(tng_data->output_file, block->block_contents_size,
14687             SEEK_CUR);
14688
14689     if(tng_data->var_num_atoms_flag)
14690     {
14691         tot_n_particles = frame_set->n_particles;
14692     }
14693     else
14694     {
14695         tot_n_particles = tng_data->n_particles;
14696     }
14697
14698     if(val_n_particles < tot_n_particles)
14699     {
14700         mapping_block_end_pos = -1;
14701         /* Read all mapping blocks to find the right place to put the data */
14702         stat = tng_block_header_read(tng_data, block);
14703         while(file_pos < output_file_len &&
14704                 stat != TNG_CRITICAL &&
14705                 block->id != TNG_TRAJECTORY_FRAME_SET &&
14706                 block->id != -1)
14707         {
14708             if(block->id == TNG_PARTICLE_MAPPING)
14709             {
14710                 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
14711             }
14712             else
14713             {
14714                 fseeko(tng_data->output_file, block->block_contents_size,
14715                       SEEK_CUR);
14716             }
14717             file_pos = ftello(tng_data->output_file);
14718             if(block->id == TNG_PARTICLE_MAPPING)
14719             {
14720                 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
14721                 if(val_first_particle >= mapping->num_first_particle &&
14722                    val_first_particle < mapping->num_first_particle +
14723                    mapping->n_particles &&
14724                    val_first_particle + val_n_particles <=
14725                    mapping->num_first_particle + mapping->n_particles)
14726                 {
14727                     mapping_block_end_pos = file_pos;
14728                 }
14729             }
14730             if(file_pos < output_file_len)
14731             {
14732                 stat = tng_block_header_read(tng_data, block);
14733             }
14734         }
14735         if(stat == TNG_CRITICAL)
14736         {
14737             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14738                    file_pos, __FILE__, __LINE__);
14739             tng_block_destroy(&block);
14740             tng_data->input_file = temp;
14741
14742             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14743             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14744             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14745             return(stat);
14746         }
14747         if(mapping_block_end_pos < 0)
14748         {
14749             tng_block_destroy(&block);
14750             tng_data->input_file = temp;
14751
14752             tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14753             tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14754             tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14755             return(TNG_FAILURE);
14756         }
14757         fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET);
14758     }
14759
14760     /* Read all block headers until next frame set block or
14761      * until the wanted block id is found */
14762     stat = tng_block_header_read(tng_data, block);
14763     while(file_pos < output_file_len &&
14764             stat != TNG_CRITICAL &&
14765             block->id != block_id &&
14766             block->id != TNG_PARTICLE_MAPPING &&
14767             block->id != TNG_TRAJECTORY_FRAME_SET &&
14768             block->id != -1)
14769     {
14770         fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
14771         file_pos = ftello(tng_data->output_file);
14772         if(file_pos < output_file_len)
14773         {
14774             stat = tng_block_header_read(tng_data, block);
14775         }
14776     }
14777     if(stat == TNG_CRITICAL)
14778     {
14779         fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
14780                 file_pos, __FILE__, __LINE__);
14781         tng_block_destroy(&block);
14782         tng_data->input_file = temp;
14783
14784         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14785         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14786         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14787         return(stat);
14788     }
14789
14790     contents_size = block->block_contents_size;
14791     header_size = block->header_contents_size;
14792
14793     header_pos = ftello(tng_data->output_file) - header_size;
14794     frame_set = &tng_data->current_trajectory_frame_set;
14795
14796     if(fread(&datatype, sizeof(datatype), 1, tng_data->input_file) == 0)
14797     {
14798         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14799         tng_block_destroy(&block);
14800         return(TNG_CRITICAL);
14801     }
14802
14803     data.datatype = datatype;
14804
14805     if(fread(&dependency, sizeof(dependency), 1, tng_data->input_file) == 0)
14806     {
14807         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14808         tng_block_destroy(&block);
14809         return(TNG_CRITICAL);
14810     }
14811
14812     if(!(dependency & TNG_FRAME_DEPENDENT) ||
14813        !(dependency & TNG_PARTICLE_DEPENDENT))
14814     {
14815         tng_block_destroy(&block);
14816         tng_data->input_file = temp;
14817
14818         tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14819         tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14820         tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14821         return(TNG_FAILURE);
14822     }
14823
14824     if(fread(&sparse_data, sizeof(sparse_data), 1, 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
14831     if(fread(&data.n_values_per_frame, sizeof(data.n_values_per_frame), 1,
14832              tng_data->input_file) == 0)
14833     {
14834         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14835         tng_block_destroy(&block);
14836         return(TNG_CRITICAL);
14837     }
14838     if(tng_data->output_endianness_swap_func_64)
14839     {
14840         if(tng_data->output_endianness_swap_func_64(tng_data,
14841             &data.n_values_per_frame)
14842             != TNG_SUCCESS)
14843         {
14844             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14845                     __FILE__, __LINE__);
14846         }
14847     }
14848
14849     if(fread(&data.codec_id, sizeof(data.codec_id), 1,
14850              tng_data->input_file) == 0)
14851     {
14852         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14853         tng_block_destroy(&block);
14854         return(TNG_CRITICAL);
14855     }
14856     if(tng_data->output_endianness_swap_func_64)
14857     {
14858         if(tng_data->output_endianness_swap_func_64(tng_data,
14859             &data.codec_id)
14860             != TNG_SUCCESS)
14861         {
14862             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14863                     __FILE__, __LINE__);
14864         }
14865     }
14866
14867     if(data.codec_id != TNG_UNCOMPRESSED)
14868     {
14869         if(fread(&data.compression_multiplier,
14870                  sizeof(data.compression_multiplier), 1, tng_data->input_file)
14871             == 0)
14872         {
14873             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14874             tng_block_destroy(&block);
14875             return(TNG_CRITICAL);
14876         }
14877
14878         if(tng_data->output_endianness_swap_func_64)
14879         {
14880             if(tng_data->output_endianness_swap_func_64(tng_data,
14881                (int64_t *)&data.compression_multiplier)
14882                 != TNG_SUCCESS)
14883             {
14884                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14885                         __FILE__, __LINE__);
14886             }
14887         }
14888     }
14889     else
14890     {
14891         data.compression_multiplier = 1;
14892     }
14893
14894     if(sparse_data)
14895     {
14896         if(fread(&data.first_frame_with_data,
14897                  sizeof(data.first_frame_with_data),
14898                  1, tng_data->input_file) == 0)
14899         {
14900             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14901             tng_block_destroy(&block);
14902             return(TNG_CRITICAL);
14903         }
14904         if(tng_data->output_endianness_swap_func_64)
14905         {
14906             if(tng_data->output_endianness_swap_func_64(tng_data,
14907                 &data.first_frame_with_data)
14908                 != TNG_SUCCESS)
14909             {
14910                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14911                         __FILE__, __LINE__);
14912             }
14913         }
14914
14915         if(fread(&data.stride_length, sizeof(data.stride_length),
14916                  1, tng_data->input_file) == 0)
14917         {
14918             fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14919             tng_block_destroy(&block);
14920             return(TNG_CRITICAL);
14921         }
14922         if(tng_data->output_endianness_swap_func_64)
14923         {
14924             if(tng_data->output_endianness_swap_func_64(tng_data,
14925                 &data.stride_length)
14926                 != TNG_SUCCESS)
14927             {
14928                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14929                         __FILE__, __LINE__);
14930             }
14931         }
14932     }
14933     else
14934     {
14935         data.first_frame_with_data = 0;
14936         data.stride_length = 1;
14937     }
14938     data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
14939
14940     if(fread(&num_first_particle, sizeof(num_first_particle), 1,
14941              tng_data->input_file) == 0)
14942     {
14943         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14944         tng_block_destroy(&block);
14945         return(TNG_CRITICAL);
14946     }
14947     if(tng_data->output_endianness_swap_func_64)
14948     {
14949         if(tng_data->output_endianness_swap_func_64(tng_data,
14950             &num_first_particle)
14951             != TNG_SUCCESS)
14952         {
14953             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14954                     __FILE__, __LINE__);
14955         }
14956     }
14957
14958     if(fread(&block_n_particles, sizeof(block_n_particles), 1,
14959              tng_data->input_file) == 0)
14960     {
14961         fprintf(stderr, "TNG library: Error reading file. %s: %d\n", __FILE__, __LINE__);
14962         tng_block_destroy(&block);
14963         return(TNG_CRITICAL);
14964     }
14965     if(tng_data->output_endianness_swap_func_64)
14966     {
14967         if(tng_data->output_endianness_swap_func_64(tng_data,
14968             &block_n_particles)
14969             != TNG_SUCCESS)
14970         {
14971             fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
14972                     __FILE__, __LINE__);
14973         }
14974     }
14975
14976
14977     tng_data->input_file = temp;
14978
14979     tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
14980     tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
14981     tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
14982
14983
14984     switch(data.datatype)
14985     {
14986         case(TNG_INT_DATA):
14987             size = sizeof(int64_t);
14988             break;
14989         case(TNG_FLOAT_DATA):
14990             size = sizeof(float);
14991             break;
14992         case(TNG_DOUBLE_DATA):
14993             size = sizeof(double);
14994             break;
14995         default:
14996             fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
14997                    __LINE__);
14998             tng_block_destroy(&block);
14999             return(TNG_FAILURE);
15000     }
15001
15002     n_values_per_frame = data.n_values_per_frame;
15003
15004     file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
15005                                data.first_frame_with_data)) /
15006                 data.stride_length;
15007     file_pos *= block_n_particles * size * n_values_per_frame;
15008
15009     if(file_pos > contents_size)
15010     {
15011         fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
15012                __LINE__);
15013         tng_block_destroy(&block);
15014         return(TNG_FAILURE);
15015     }
15016
15017     fseeko(tng_data->output_file, file_pos, SEEK_CUR);
15018
15019     /* If the endianness is not big endian the data needs to be swapped */
15020     if((data.datatype == TNG_INT_DATA ||
15021         data.datatype == TNG_DOUBLE_DATA) &&
15022        tng_data->output_endianness_swap_func_64)
15023     {
15024         copy = malloc(val_n_particles * n_values_per_frame * size);
15025         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
15026         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
15027         {
15028             if(tng_data->output_endianness_swap_func_64(tng_data,
15029                 (int64_t *) copy+i)
15030                 != TNG_SUCCESS)
15031             {
15032                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
15033                         __FILE__, __LINE__);
15034             }
15035         }
15036         fwrite(copy, val_n_particles * n_values_per_frame, size,
15037                tng_data->output_file);
15038         free(copy);
15039     }
15040     else if(data.datatype == TNG_FLOAT_DATA &&
15041        tng_data->output_endianness_swap_func_32)
15042     {
15043         copy = malloc(val_n_particles * n_values_per_frame * size);
15044         memcpy(copy, values, val_n_particles * n_values_per_frame * size);
15045         for(i = 0; i < val_n_particles * n_values_per_frame; i++)
15046         {
15047             if(tng_data->output_endianness_swap_func_32(tng_data,
15048                 (int32_t *) copy+i)
15049                 != TNG_SUCCESS)
15050             {
15051                 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
15052                         __FILE__, __LINE__);
15053             }
15054         }
15055         fwrite(copy, val_n_particles * n_values_per_frame, size,
15056                tng_data->output_file);
15057         free(copy);
15058     }
15059
15060     else
15061     {
15062         fwrite(values, val_n_particles * n_values_per_frame, size,
15063                tng_data->output_file);
15064     }
15065     fflush(tng_data->output_file);
15066
15067     /* Update the number of written frames in the frame set. */
15068     if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
15069     {
15070         frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
15071     }
15072
15073     /* If the last frame has been written update the hash */
15074     if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
15075        data.first_frame_with_data) >=
15076        frame_set->n_frames)
15077     {
15078         tng_md5_hash_update(tng_data, block, header_pos, header_pos +
15079                             header_size);
15080     }
15081
15082     tng_block_destroy(&block);
15083     return(TNG_SUCCESS);
15084 }
15085
15086 static tng_function_status tng_data_values_alloc
15087                 (const tng_trajectory_t tng_data,
15088                  union data_values ***values,
15089                  const int64_t n_frames,
15090                  const int64_t n_values_per_frame,
15091                  const char type)
15092 {
15093     int64_t i;
15094     tng_function_status stat;
15095
15096     if(n_frames <= 0 || n_values_per_frame <= 0)
15097     {
15098         return(TNG_FAILURE);
15099     }
15100
15101     if(*values)
15102     {
15103         stat = tng_data_values_free(tng_data, *values, n_frames,
15104                                     n_values_per_frame,
15105                                     type);
15106         if(stat != TNG_SUCCESS)
15107         {
15108             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15109                    __FILE__, __LINE__);
15110             return(stat);
15111         }
15112     }
15113     *values = malloc(sizeof(union data_values *) * n_frames);
15114     if(!*values)
15115     {
15116         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
15117                sizeof(union data_values **) * n_frames,
15118                __FILE__, __LINE__);
15119         return(TNG_CRITICAL);
15120
15121     }
15122
15123     for(i = 0; i < n_frames; i++)
15124     {
15125         (*values)[i] = malloc(sizeof(union data_values) *
15126                            n_values_per_frame);
15127         if(!(*values)[i])
15128         {
15129             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
15130                    sizeof(union data_values) * n_values_per_frame,
15131                    __FILE__, __LINE__);
15132             free(values);
15133             values = 0;
15134             return(TNG_CRITICAL);
15135         }
15136     }
15137     return(TNG_SUCCESS);
15138 }
15139
15140 /* FIXME: This needs ***values */
15141 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
15142                 (const tng_trajectory_t tng_data,
15143                  union data_values **values,
15144                  const int64_t n_frames,
15145                  const int64_t n_values_per_frame,
15146                  const char type)
15147 {
15148     int64_t i, j;
15149     (void)tng_data;
15150
15151     if(values)
15152     {
15153         for(i = 0; i < n_frames; i++)
15154         {
15155             if(values[i])
15156             {
15157                 if(type == TNG_CHAR_DATA)
15158                 {
15159                     for(j = 0; j < n_values_per_frame; j++)
15160                     {
15161                         if(values[i][j].c)
15162                         {
15163                             free(values[i][j].c);
15164                             values[i][j].c = 0;
15165                         }
15166                     }
15167                 }
15168                 free(values[i]);
15169                 values[i] = 0;
15170             }
15171         }
15172         free(values);
15173         values = 0;
15174     }
15175
15176     return(TNG_SUCCESS);
15177 }
15178
15179 static tng_function_status tng_particle_data_values_alloc
15180                 (const tng_trajectory_t tng_data,
15181                  union data_values ****values,
15182                  const int64_t n_frames,
15183                  const int64_t n_particles,
15184                  const int64_t n_values_per_frame,
15185                  const char type)
15186 {
15187     int64_t i, j;
15188     tng_function_status stat;
15189
15190     if(n_particles == 0 || n_values_per_frame == 0)
15191     {
15192         return(TNG_FAILURE);
15193     }
15194
15195     if(*values)
15196     {
15197         stat = tng_particle_data_values_free(tng_data, *values, n_frames,
15198                                              n_particles, n_values_per_frame,
15199                                              type);
15200         if(stat != TNG_SUCCESS)
15201         {
15202             fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
15203                    __FILE__, __LINE__);
15204             return(stat);
15205         }
15206     }
15207     *values = malloc(sizeof(union data_values **) * n_frames);
15208     if(!*values)
15209     {
15210         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
15211                sizeof(union data_values **) * n_frames,
15212                __FILE__, __LINE__);
15213         return(TNG_CRITICAL);
15214
15215     }
15216
15217     for(i = 0; i < n_frames; i++)
15218     {
15219         (*values)[i] = malloc(sizeof(union data_values *) *
15220                            n_particles);
15221         if(!(*values)[i])
15222         {
15223             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
15224                    sizeof(union data_values *) * n_particles,
15225                    __FILE__, __LINE__);
15226             free(*values);
15227             *values = 0;
15228             return(TNG_CRITICAL);
15229         }
15230         for(j = 0; j < n_particles; j++)
15231         {
15232             (*values)[i][j] = malloc(sizeof(union data_values) *
15233                                   n_values_per_frame);
15234             if(!(*values)[i][j])
15235             {
15236                 fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
15237                     sizeof(union data_values *) * n_particles,
15238                     __FILE__, __LINE__);
15239                 tng_particle_data_values_free(tng_data, *values, n_frames,
15240                                               n_particles, n_values_per_frame,
15241                                               type);
15242                 *values = 0;
15243                 return(TNG_CRITICAL);
15244             }
15245         }
15246     }
15247     return(TNG_SUCCESS);
15248 }
15249
15250 /* FIXME: This needs ****values */
15251 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
15252                 (const tng_trajectory_t tng_data,
15253                  union data_values ***values,
15254                  const int64_t n_frames,
15255                  const int64_t n_particles,
15256                  const int64_t n_values_per_frame,
15257                  const char type)
15258 {
15259     int64_t i, j, k;
15260     (void)tng_data;
15261
15262     if(values)
15263     {
15264         for(i = 0; i < n_frames; i++)
15265         {
15266             if(values[i])
15267             {
15268                 for(j = 0; j < n_particles; j++)
15269                 {
15270                     if(type == TNG_CHAR_DATA)
15271                     {
15272                         for(k = 0; k < n_values_per_frame; k++)
15273                         {
15274                             if(values[i][j][k].c)
15275                             {
15276                                 free(values[i][j][k].c);
15277                                 values[i][j][k].c = 0;
15278                             }
15279                         }
15280                     }
15281                     free(values[i][j]);
15282                     values[i][j] = 0;
15283                 }
15284                 free(values[i]);
15285                 values[i] = 0;
15286             }
15287         }
15288         free(values);
15289         values = 0;
15290     }
15291
15292     return(TNG_SUCCESS);
15293 }
15294
15295
15296 tng_function_status DECLSPECDLLEXPORT tng_data_get
15297                 (tng_trajectory_t tng_data,
15298                  const int64_t block_id,
15299                  union data_values ***values,
15300                  int64_t *n_frames,
15301                  int64_t *n_values_per_frame,
15302                  char *type)
15303 {
15304     int64_t i, j, file_pos, block_index;
15305     int size;
15306     size_t len;
15307     tng_non_particle_data_t data;
15308     tng_trajectory_frame_set_t frame_set;
15309     tng_gen_block_t block;
15310     tng_function_status stat;
15311
15312     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15313     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15314     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15315     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15316
15317     frame_set = &tng_data->current_trajectory_frame_set;
15318
15319     block_index = -1;
15320     data = 0;
15321
15322     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15323     {
15324         tng_block_init(&block);
15325         file_pos = ftello(tng_data->input_file);
15326         /* Read all blocks until next frame set block */
15327         stat = tng_block_header_read(tng_data, block);
15328         while(file_pos < tng_data->input_file_len &&
15329                 stat != TNG_CRITICAL &&
15330                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15331                 block->id != -1)
15332         {
15333             /* Use hash by default */
15334             stat = tng_block_read_next(tng_data, block,
15335                                     TNG_USE_HASH);
15336             if(stat != TNG_CRITICAL)
15337             {
15338                 file_pos = ftello(tng_data->input_file);
15339                 if(file_pos < tng_data->input_file_len)
15340                 {
15341                     stat = tng_block_header_read(tng_data, block);
15342                 }
15343             }
15344         }
15345         tng_block_destroy(&block);
15346         if(stat == TNG_CRITICAL)
15347         {
15348             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15349                     file_pos, __FILE__, __LINE__);
15350             return(stat);
15351         }
15352
15353         for(i = 0; i < frame_set->n_data_blocks; i++)
15354         {
15355             data = &frame_set->tr_data[i];
15356             if(data->block_id == block_id)
15357             {
15358                 block_index = i;
15359                 break;
15360             }
15361         }
15362         if(block_index < 0)
15363         {
15364             return(TNG_FAILURE);
15365         }
15366     }
15367
15368     *n_frames = tng_max_i64(1, data->n_frames);
15369     *n_values_per_frame = data->n_values_per_frame;
15370     *type = data->datatype;
15371
15372     if(*values == 0)
15373     {
15374         if(tng_data_values_alloc(tng_data, values, *n_frames,
15375                                  *n_values_per_frame,
15376                                  *type)
15377         != TNG_SUCCESS)
15378         {
15379             return(TNG_CRITICAL);
15380         }
15381     }
15382
15383     switch(*type)
15384     {
15385     case TNG_CHAR_DATA:
15386         for(i = 0; i < *n_frames; i++)
15387         {
15388             for(j = 0; j < *n_values_per_frame; j++)
15389             {
15390                 len = strlen(data->strings[i][j]) + 1;
15391                 (*values)[i][j].c = malloc(len);
15392                 strncpy((*values)[i][j].c, data->strings[i][j], len);
15393             }
15394         }
15395         break;
15396     case TNG_INT_DATA:
15397         size = sizeof(int);
15398         for(i = 0; i < *n_frames; i++)
15399         {
15400             for(j = 0; j < *n_values_per_frame; j++)
15401             {
15402                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15403                                              (i*(*n_values_per_frame) + j));
15404             }
15405         }
15406         break;
15407     case TNG_FLOAT_DATA:
15408         size = sizeof(float);
15409         for(i = 0; i < *n_frames; i++)
15410         {
15411             for(j = 0; j < *n_values_per_frame; j++)
15412             {
15413                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15414                                                (i*(*n_values_per_frame) + j));
15415             }
15416         }
15417         break;
15418     case TNG_DOUBLE_DATA:
15419     default:
15420         size = sizeof(double);
15421         for(i = 0; i < *n_frames; i++)
15422         {
15423             for(j = 0; j < *n_values_per_frame; j++)
15424             {
15425                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15426                                                 (i*(*n_values_per_frame) + j));
15427             }
15428         }
15429     }
15430
15431     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15432
15433     return(TNG_SUCCESS);
15434 }
15435
15436 tng_function_status tng_data_vector_get(tng_trajectory_t tng_data,
15437                                         const int64_t block_id,
15438                                         void **values,
15439                                         int64_t *n_frames,
15440                                         int64_t *stride_length,
15441                                         int64_t *n_values_per_frame,
15442                                         char *type)
15443 {
15444     int64_t file_pos, data_size, n_frames_div, block_index;
15445     int i, size;
15446     tng_non_particle_data_t data;
15447     tng_trajectory_frame_set_t frame_set;
15448     tng_gen_block_t block;
15449     void *temp;
15450     tng_function_status stat;
15451
15452     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15453     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15454     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15455     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15456     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15457
15458     frame_set = &tng_data->current_trajectory_frame_set;
15459
15460     block_index = -1;
15461     data = 0;
15462
15463     if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
15464     {
15465         tng_block_init(&block);
15466         file_pos = ftello(tng_data->input_file);
15467         /* Read all blocks until next frame set block */
15468         stat = tng_block_header_read(tng_data, block);
15469         while(file_pos < tng_data->input_file_len &&
15470                 stat != TNG_CRITICAL &&
15471                 block->id != TNG_TRAJECTORY_FRAME_SET &&
15472                 block->id != -1)
15473         {
15474             /* Use hash by default */
15475             stat = tng_block_read_next(tng_data, block,
15476                                     TNG_USE_HASH);
15477             if(stat != TNG_CRITICAL)
15478             {
15479                 file_pos = ftello(tng_data->input_file);
15480                 if(file_pos < tng_data->input_file_len)
15481                 {
15482                     stat = tng_block_header_read(tng_data, block);
15483                 }
15484             }
15485         }
15486         tng_block_destroy(&block);
15487         if(stat == TNG_CRITICAL)
15488         {
15489             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15490                     file_pos, __FILE__, __LINE__);
15491             return(stat);
15492         }
15493
15494         for(i = 0; i < frame_set->n_data_blocks; i++)
15495         {
15496             data = &frame_set->tr_data[i];
15497             if(data->block_id == block_id)
15498             {
15499                 block_index = i;
15500                 break;
15501             }
15502         }
15503         if(block_index < 0)
15504         {
15505             return(TNG_FAILURE);
15506         }
15507     }
15508
15509     *type = data->datatype;
15510
15511     switch(*type)
15512     {
15513     case TNG_CHAR_DATA:
15514         return(TNG_FAILURE);
15515     case TNG_INT_DATA:
15516         size = sizeof(int64_t);
15517         break;
15518     case TNG_FLOAT_DATA:
15519         size = sizeof(float);
15520         break;
15521     case TNG_DOUBLE_DATA:
15522     default:
15523         size = sizeof(double);
15524     }
15525
15526     *n_frames = data->n_frames;
15527     *n_values_per_frame = data->n_values_per_frame;
15528     *stride_length = data->stride_length;
15529     n_frames_div = (*n_frames % *stride_length) ? *n_frames / *stride_length + 1:
15530                    *n_frames / *stride_length;
15531
15532     data_size = n_frames_div * size *
15533                 *n_values_per_frame;
15534
15535     temp = realloc(*values, data_size);
15536     if(!temp)
15537     {
15538         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15539                data_size, __FILE__, __LINE__);
15540         free(*values);
15541         *values = 0;
15542         return(TNG_CRITICAL);
15543     }
15544
15545     *values = temp;
15546
15547     memcpy(*values, data->values, data_size);
15548
15549     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
15550
15551     return(TNG_SUCCESS);
15552 }
15553
15554 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
15555                 (tng_trajectory_t tng_data,
15556                  const int64_t block_id,
15557                  const int64_t start_frame_nr,
15558                  const int64_t end_frame_nr,
15559                  const char hash_mode,
15560                  union data_values ***values,
15561                  int64_t *n_values_per_frame,
15562                  char *type)
15563 {
15564     int64_t i, j, n_frames, file_pos, current_frame_pos, first_frame;
15565     int64_t block_index;
15566     int size;
15567     size_t len;
15568     tng_non_particle_data_t data;
15569     tng_trajectory_frame_set_t frame_set;
15570     tng_gen_block_t block;
15571     tng_function_status stat;
15572
15573     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15574     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15575     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15576     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15577
15578     block_index = -1;
15579
15580     frame_set = &tng_data->current_trajectory_frame_set;
15581     first_frame = frame_set->first_frame;
15582
15583     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15584     if(stat != TNG_SUCCESS)
15585     {
15586         return(stat);
15587     }
15588
15589
15590     /* Do not re-read the frame set. */
15591     if(first_frame != frame_set->first_frame ||
15592        frame_set->n_data_blocks <= 0)
15593     {
15594         tng_block_init(&block);
15595         file_pos = ftello(tng_data->input_file);
15596         /* Read all blocks until next frame set block */
15597         stat = tng_block_header_read(tng_data, block);
15598         while(file_pos < tng_data->input_file_len &&
15599             stat != TNG_CRITICAL &&
15600             block->id != TNG_TRAJECTORY_FRAME_SET &&
15601             block->id != -1)
15602         {
15603             stat = tng_block_read_next(tng_data, block,
15604                                     hash_mode);
15605             if(stat != TNG_CRITICAL)
15606             {
15607                 file_pos = ftello(tng_data->input_file);
15608                 if(file_pos < tng_data->input_file_len)
15609                 {
15610                     stat = tng_block_header_read(tng_data, block);
15611                 }
15612             }
15613         }
15614         tng_block_destroy(&block);
15615         if(stat == TNG_CRITICAL)
15616         {
15617             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15618                     file_pos, __FILE__, __LINE__);
15619             return(stat);
15620         }
15621     }
15622
15623
15624     /* See if there is a data block of this ID.
15625      * Start checking the last read frame set */
15626     for(i = 0; i < frame_set->n_data_blocks; i++)
15627     {
15628         data = &frame_set->tr_data[i];
15629         if(data->block_id == block_id)
15630         {
15631             block_index = i;
15632             break;
15633         }
15634     }
15635
15636     if(block_index < 0)
15637     {
15638         fprintf(stderr, "TNG library: Could not find non-particle data block with id %"PRId64". %s: %d\n",
15639                 block_id, __FILE__, __LINE__);
15640         return(TNG_FAILURE);
15641     }
15642
15643     n_frames = end_frame_nr - start_frame_nr + 1;
15644     *n_values_per_frame = data->n_values_per_frame;
15645     *type = data->datatype;
15646
15647     if(*values == 0)
15648     {
15649         if(tng_data_values_alloc(tng_data, values, n_frames,
15650                                  *n_values_per_frame,
15651                                  *type) != TNG_SUCCESS)
15652         {
15653             return(TNG_CRITICAL);
15654         }
15655     }
15656
15657     current_frame_pos = start_frame_nr - frame_set->first_frame;
15658     /* It's not very elegant to reuse so much of the code in the different case
15659      * statements, but it's unnecessarily slow to have the switch-case block
15660      * inside the for loops. */
15661     switch(*type)
15662     {
15663     case TNG_CHAR_DATA:
15664         for(i=0; i<n_frames; i++)
15665         {
15666             if(current_frame_pos == frame_set->n_frames)
15667             {
15668                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15669                 if(stat != TNG_SUCCESS)
15670                 {
15671                     return(stat);
15672                 }
15673                 current_frame_pos = 0;
15674             }
15675             for(j = 0; j < *n_values_per_frame; j++)
15676             {
15677                 len = strlen(data->strings[current_frame_pos][j]) + 1;
15678                 (*values)[i][j].c = malloc(len);
15679                 strncpy((*values)[i][j].c, data->strings[current_frame_pos][j], len);
15680             }
15681             current_frame_pos++;
15682         }
15683         break;
15684     case TNG_INT_DATA:
15685         size = sizeof(int);
15686         for(i=0; i<n_frames; i++)
15687         {
15688             if(current_frame_pos == frame_set->n_frames)
15689             {
15690                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15691                 if(stat != TNG_SUCCESS)
15692                 {
15693                     return(stat);
15694                 }
15695                 current_frame_pos = 0;
15696             }
15697             for(j = 0; j < *n_values_per_frame; j++)
15698             {
15699                 (*values)[i][j].i = *(int *)((char *)data->values + size *
15700                                             (current_frame_pos *
15701                                              (*n_values_per_frame) + j));
15702             }
15703             current_frame_pos++;
15704         }
15705         break;
15706     case TNG_FLOAT_DATA:
15707         size = sizeof(float);
15708         for(i=0; i<n_frames; i++)
15709         {
15710             if(current_frame_pos == frame_set->n_frames)
15711             {
15712                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15713                 if(stat != TNG_SUCCESS)
15714                 {
15715                     return(stat);
15716                 }
15717                 current_frame_pos = 0;
15718             }
15719             for(j = 0; j < *n_values_per_frame; j++)
15720             {
15721                 (*values)[i][j].f = *(float *)((char *)data->values + size *
15722                                                (current_frame_pos *
15723                                                 (*n_values_per_frame) + j));
15724             }
15725             current_frame_pos++;
15726         }
15727         break;
15728     case TNG_DOUBLE_DATA:
15729     default:
15730         size = sizeof(double);
15731         for(i=0; i<n_frames; i++)
15732         {
15733             if(current_frame_pos == frame_set->n_frames)
15734             {
15735                 stat = tng_frame_set_read_next(tng_data, hash_mode);
15736                 if(stat != TNG_SUCCESS)
15737                 {
15738                     return(stat);
15739                 }
15740                 current_frame_pos = 0;
15741             }
15742             for(j = 0; j < *n_values_per_frame; j++)
15743             {
15744                 (*values)[i][j].d = *(double *)((char *)data->values + size *
15745                                                 (current_frame_pos *
15746                                                  (*n_values_per_frame) + j));
15747             }
15748             current_frame_pos++;
15749         }
15750     }
15751
15752     data->last_retrieved_frame = end_frame_nr;
15753
15754     return(TNG_SUCCESS);
15755 }
15756
15757 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
15758                 (tng_trajectory_t tng_data,
15759                  const int64_t block_id,
15760                  const int64_t start_frame_nr,
15761                  const int64_t end_frame_nr,
15762                  const char hash_mode,
15763                  void **values,
15764                  int64_t *stride_length,
15765                  int64_t *n_values_per_frame,
15766                  char *type)
15767 {
15768     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
15769     int64_t file_pos, current_frame_pos, data_size, frame_size;
15770     int64_t last_frame_pos;
15771     int size;
15772     tng_trajectory_frame_set_t frame_set;
15773     tng_non_particle_data_t np_data;
15774     tng_gen_block_t block;
15775     void *current_values = 0, *temp;
15776     tng_function_status stat;
15777
15778     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15779     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
15780     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15781     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15782     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15783
15784     frame_set = &tng_data->current_trajectory_frame_set;
15785     first_frame = frame_set->first_frame;
15786
15787     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
15788     if(stat != TNG_SUCCESS)
15789     {
15790         return(stat);
15791     }
15792
15793     /* Do not re-read the frame set and only need the requested block. */
15794     /* TODO: Test that blocks are read correctly now that not all of them are read at the same time. */
15795     stat = tng_data_find(tng_data, block_id, &np_data);
15796     if(first_frame != frame_set->first_frame ||
15797        stat != TNG_SUCCESS)
15798     {
15799         tng_block_init(&block);
15800         if(stat != TNG_SUCCESS)
15801         {
15802             fseeko(tng_data->input_file,
15803                    tng_data->current_trajectory_frame_set_input_file_pos,
15804                    SEEK_SET);
15805             stat = tng_block_header_read(tng_data, block);
15806             if(stat != TNG_SUCCESS)
15807             {
15808                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
15809                         __FILE__, __LINE__);
15810                 return(stat);
15811             }
15812
15813             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
15814         }
15815         file_pos = ftello(tng_data->input_file);
15816         /* Read until next frame set block */
15817         stat = tng_block_header_read(tng_data, block);
15818         while(file_pos < tng_data->input_file_len &&
15819             stat != TNG_CRITICAL &&
15820             block->id != TNG_TRAJECTORY_FRAME_SET &&
15821             block->id != -1)
15822         {
15823             if(block->id == block_id)
15824             {
15825                 stat = tng_block_read_next(tng_data, block,
15826                                         hash_mode);
15827                 if(stat != TNG_CRITICAL)
15828                 {
15829                     file_pos = ftello(tng_data->input_file);
15830                     if(file_pos < tng_data->input_file_len)
15831                     {
15832                         stat = tng_block_header_read(tng_data, block);
15833                     }
15834                 }
15835             }
15836             else
15837             {
15838                 file_pos += block->block_contents_size + block->header_contents_size;
15839                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
15840                 if(file_pos < tng_data->input_file_len)
15841                 {
15842                     stat = tng_block_header_read(tng_data, block);
15843                 }
15844             }
15845         }
15846         tng_block_destroy(&block);
15847         if(stat == TNG_CRITICAL)
15848         {
15849             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
15850                     file_pos, __FILE__, __LINE__);
15851             return(stat);
15852         }
15853     }
15854
15855     stat = tng_data_find(tng_data, block_id, &np_data);
15856     if(stat != TNG_SUCCESS)
15857     {
15858         return(stat);
15859     }
15860
15861     stat = tng_data_vector_get(tng_data, block_id, &current_values,
15862                                &n_frames, stride_length,
15863                                n_values_per_frame, type);
15864
15865     if(stat != TNG_SUCCESS)
15866     {
15867         if(current_values)
15868         {
15869             free(current_values);
15870         }
15871         return(stat);
15872     }
15873
15874     if(n_frames == 1 && n_frames < frame_set->n_frames)
15875     {
15876         tot_n_frames = 1;
15877     }
15878     else
15879     {
15880         tot_n_frames = end_frame_nr - start_frame_nr + 1;
15881     }
15882
15883     switch(*type)
15884     {
15885     case TNG_CHAR_DATA:
15886         return(TNG_FAILURE);
15887     case TNG_INT_DATA:
15888         size = sizeof(int64_t);
15889         break;
15890     case TNG_FLOAT_DATA:
15891         size = sizeof(float);
15892         break;
15893     case TNG_DOUBLE_DATA:
15894     default:
15895         size = sizeof(double);
15896     }
15897
15898     n_frames_div = (tot_n_frames % *stride_length) ?
15899                  tot_n_frames / *stride_length + 1:
15900                  tot_n_frames / *stride_length;
15901     data_size = n_frames_div * size * (*n_values_per_frame);
15902
15903 /*     fprintf(stderr, "TNG library: size: %d, n_frames_div: %"PRId64", data_size: %"PRId64"\n",
15904               size, n_frames_div, data_size);
15905 */
15906     temp = realloc(*values, data_size);
15907     if(!temp)
15908     {
15909         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
15910                data_size, __FILE__, __LINE__);
15911         free(*values);
15912         *values = 0;
15913         return(TNG_CRITICAL);
15914     }
15915
15916     *values = temp;
15917
15918     if( n_frames == 1 && n_frames < frame_set->n_frames)
15919     {
15920         memcpy(*values, current_values, size * (*n_values_per_frame));
15921     }
15922     else
15923     {
15924         current_frame_pos = start_frame_nr - frame_set->first_frame;
15925
15926         frame_size = size * (*n_values_per_frame);
15927
15928         last_frame_pos = tng_min_i64(n_frames,
15929                                      end_frame_nr - start_frame_nr);
15930
15931         n_frames_div = current_frame_pos / *stride_length;
15932         n_frames_div_2 = (last_frame_pos % *stride_length) ?
15933                        last_frame_pos / *stride_length + 1:
15934                        last_frame_pos / *stride_length;
15935         n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15936
15937         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
15938                n_frames_div_2 * frame_size);
15939
15940         current_frame_pos += n_frames - current_frame_pos;
15941
15942         while(current_frame_pos <= end_frame_nr - start_frame_nr)
15943         {
15944             stat = tng_frame_set_read_next(tng_data, hash_mode);
15945             if(stat != TNG_SUCCESS)
15946             {
15947                 if(current_values)
15948                 {
15949                     free(current_values);
15950                 }
15951                 free(*values);
15952                 *values = 0;
15953                 return(stat);
15954             }
15955
15956             stat = tng_data_vector_get(tng_data, block_id, &current_values,
15957                                     &n_frames, stride_length,
15958                                     n_values_per_frame, type);
15959
15960             if(stat != TNG_SUCCESS)
15961             {
15962                 if(current_values)
15963                 {
15964                     free(current_values);
15965                 }
15966                 free(*values);
15967                 *values = 0;
15968                 return(stat);
15969             }
15970
15971             last_frame_pos = tng_min_i64(n_frames,
15972                                          end_frame_nr - current_frame_pos);
15973
15974             n_frames_div = current_frame_pos / *stride_length;
15975             n_frames_div_2 = (last_frame_pos % *stride_length) ?
15976                            last_frame_pos / *stride_length + 1:
15977                            last_frame_pos / *stride_length;
15978             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
15979
15980             memcpy(((char *)*values) + n_frames_div * frame_size,
15981                    current_values,
15982                    n_frames_div_2 * frame_size);
15983
15984             current_frame_pos += n_frames;
15985         }
15986     }
15987
15988     if(current_values)
15989     {
15990         free(current_values);
15991     }
15992
15993     np_data->last_retrieved_frame = end_frame_nr;
15994
15995     return(TNG_SUCCESS);
15996 }
15997
15998 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
15999                 (tng_trajectory_t tng_data,
16000                  const int64_t block_id,
16001                  union data_values ****values,
16002                  int64_t *n_frames,
16003                  int64_t *n_particles,
16004                  int64_t *n_values_per_frame,
16005                  char *type)
16006 {
16007     int64_t i, j, k, mapping, file_pos, i_step, block_index;
16008     int size;
16009     size_t len;
16010     tng_particle_data_t data;
16011     tng_trajectory_frame_set_t frame_set;
16012     tng_gen_block_t block;
16013     char block_type_flag;
16014     tng_function_status stat;
16015
16016     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16017     TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
16018     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16019     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16020     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16021
16022     frame_set = &tng_data->current_trajectory_frame_set;
16023
16024     block_index = -1;
16025     data = 0;
16026
16027     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16028     {
16029         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16030         {
16031             block_type_flag = TNG_TRAJECTORY_BLOCK;
16032         }
16033         else
16034         {
16035             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16036         }
16037
16038         tng_block_init(&block);
16039         file_pos = ftello(tng_data->input_file);
16040         /* Read all blocks until next frame set block */
16041         stat = tng_block_header_read(tng_data, block);
16042         while(file_pos < tng_data->input_file_len &&
16043                 stat != TNG_CRITICAL &&
16044                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16045                 block->id != -1)
16046         {
16047             /* Use hash by default */
16048             stat = tng_block_read_next(tng_data, block,
16049                                     TNG_USE_HASH);
16050             if(stat != TNG_CRITICAL)
16051             {
16052                 file_pos = ftello(tng_data->input_file);
16053                 if(file_pos < tng_data->input_file_len)
16054                 {
16055                     stat = tng_block_header_read(tng_data, block);
16056                 }
16057             }
16058         }
16059         tng_block_destroy(&block);
16060         if(stat == TNG_CRITICAL)
16061         {
16062             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16063                     file_pos, __FILE__, __LINE__);
16064             return(stat);
16065         }
16066
16067         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16068         {
16069             data = &frame_set->tr_particle_data[i];
16070             if(data->block_id == block_id)
16071             {
16072                 block_index = i;
16073                 block_type_flag = TNG_TRAJECTORY_BLOCK;
16074                 break;
16075             }
16076         }
16077         if(block_index < 0)
16078         {
16079             return(TNG_FAILURE);
16080         }
16081     }
16082     else
16083     {
16084         if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16085         {
16086             block_type_flag = TNG_TRAJECTORY_BLOCK;
16087         }
16088         else
16089         {
16090             block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16091         }
16092     }
16093
16094     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16095        tng_data->var_num_atoms_flag)
16096     {
16097         *n_particles = frame_set->n_particles;
16098     }
16099     else
16100     {
16101         *n_particles = tng_data->n_particles;
16102     }
16103
16104     *n_frames = tng_max_i64(1, data->n_frames);
16105     *n_values_per_frame = data->n_values_per_frame;
16106     *type = data->datatype;
16107
16108     if(*values == 0)
16109     {
16110         if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
16111                                          *n_particles, *n_values_per_frame,
16112                                          *type)
16113             != TNG_SUCCESS)
16114         {
16115             return(TNG_CRITICAL);
16116         }
16117     }
16118
16119     /* It's not very elegant to reuse so much of the code in the different case
16120      * statements, but it's unnecessarily slow to have the switch-case block
16121      * inside the for loops. */
16122     switch(*type)
16123     {
16124     case TNG_CHAR_DATA:
16125         for(i = 0; i < *n_frames; i++)
16126         {
16127             for(j = 0; j < *n_particles; j++)
16128             {
16129                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16130                 for(k = 0; k < *n_values_per_frame; k++)
16131                 {
16132                     len = strlen(data->strings[i][j][k]) + 1;
16133                     (*values)[i][mapping][k].c = malloc(len);
16134                     strncpy((*values)[i][mapping][k].c,
16135                             data->strings[i][j][k], len);
16136                 }
16137             }
16138         }
16139         break;
16140     case TNG_INT_DATA:
16141         size = sizeof(int);
16142         i_step = (*n_particles) * (*n_values_per_frame);
16143         for(i = 0; i < *n_frames; i++)
16144         {
16145             for(j = 0; j < *n_particles; j++)
16146             {
16147                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16148                 for(k = 0; k < *n_values_per_frame; k++)
16149                 {
16150                     (*values)[i][mapping][k].i = *(int *)
16151                                                  ((char *)data->values + size *
16152                                                  (i * i_step + j *
16153                                                   (*n_values_per_frame) + k));
16154                 }
16155             }
16156         }
16157         break;
16158     case TNG_FLOAT_DATA:
16159         size = sizeof(float);
16160         i_step = (*n_particles) * (*n_values_per_frame);
16161         for(i = 0; i < *n_frames; i++)
16162         {
16163             for(j = 0; j < *n_particles; j++)
16164             {
16165                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16166                 for(k = 0; k < *n_values_per_frame; k++)
16167                 {
16168                     (*values)[i][mapping][k].f = *(float *)
16169                                                  ((char *)data->values + size *
16170                                                  (i * i_step + j *
16171                                                   (*n_values_per_frame) + k));
16172                 }
16173             }
16174         }
16175         break;
16176     case TNG_DOUBLE_DATA:
16177     default:
16178         size = sizeof(double);
16179         i_step = (*n_particles) * (*n_values_per_frame);
16180         for(i = 0; i < *n_frames; i++)
16181         {
16182             for(j = 0; j < *n_particles; j++)
16183             {
16184                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16185                 for(k = 0; k < *n_values_per_frame; k++)
16186                 {
16187                     (*values)[i][mapping][k].d = *(double *)
16188                                                  ((char *)data->values + size *
16189                                                  (i * i_step + j *
16190                                                   (*n_values_per_frame) + k));
16191                 }
16192             }
16193         }
16194     }
16195
16196     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16197
16198     return(TNG_SUCCESS);
16199 }
16200
16201 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
16202                 (tng_trajectory_t tng_data,
16203                  const int64_t block_id,
16204                  void **values,
16205                  int64_t *n_frames,
16206                  int64_t *stride_length,
16207                  int64_t *n_particles,
16208                  int64_t *n_values_per_frame,
16209                  char *type)
16210 {
16211     int64_t i, j, mapping, file_pos, i_step, data_size, n_frames_div;
16212     int64_t block_index;
16213     int size;
16214     tng_particle_data_t data;
16215     tng_trajectory_frame_set_t frame_set;
16216     tng_gen_block_t block;
16217     void *temp;
16218     char block_type_flag;
16219     tng_function_status stat;
16220
16221     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16222     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16223     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16224     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16225     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16226
16227     frame_set = &tng_data->current_trajectory_frame_set;
16228
16229     block_index = -1;
16230     data = 0;
16231
16232     if(tng_particle_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16233     {
16234         tng_block_init(&block);
16235         file_pos = ftello(tng_data->input_file);
16236         /* Read all blocks until next frame set block */
16237         stat = tng_block_header_read(tng_data, block);
16238         while(file_pos < tng_data->input_file_len &&
16239                 stat != TNG_CRITICAL &&
16240                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16241                 block->id != -1)
16242         {
16243             /* Use hash by default */
16244             stat = tng_block_read_next(tng_data, block,
16245                                     TNG_USE_HASH);
16246             if(stat != TNG_CRITICAL)
16247             {
16248                 file_pos = ftello(tng_data->input_file);
16249                 if(file_pos < tng_data->input_file_len)
16250                 {
16251                     stat = tng_block_header_read(tng_data, block);
16252                 }
16253             }
16254         }
16255         tng_block_destroy(&block);
16256         if(stat == TNG_CRITICAL)
16257         {
16258             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16259                     file_pos, __FILE__, __LINE__);
16260             return(stat);
16261         }
16262
16263         for(i = 0; i < frame_set->n_particle_data_blocks; i++)
16264         {
16265             data = &frame_set->tr_particle_data[i];
16266             if(data->block_id == block_id)
16267             {
16268                 block_index = i;
16269                 break;
16270             }
16271         }
16272         if(block_index < 0)
16273         {
16274             return(TNG_FAILURE);
16275         }
16276     }
16277
16278     if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
16279     {
16280         block_type_flag = TNG_TRAJECTORY_BLOCK;
16281     }
16282     else
16283     {
16284         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16285     }
16286
16287    if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16288       tng_data->var_num_atoms_flag)
16289     {
16290         *n_particles = frame_set->n_particles;
16291     }
16292     else
16293     {
16294         *n_particles = tng_data->n_particles;
16295     }
16296
16297     *type = data->datatype;
16298
16299     switch(*type)
16300     {
16301     case TNG_CHAR_DATA:
16302         return(TNG_FAILURE);
16303     case TNG_INT_DATA:
16304         size = sizeof(int64_t);
16305         break;
16306     case TNG_FLOAT_DATA:
16307         size = sizeof(float);
16308         break;
16309     case TNG_DOUBLE_DATA:
16310     default:
16311         size = sizeof(double);
16312     }
16313
16314     *n_frames = tng_max_i64(1, data->n_frames);
16315     *n_values_per_frame = data->n_values_per_frame;
16316     *stride_length = data->stride_length;
16317
16318     n_frames_div = (*n_frames % *stride_length) ?
16319                    *n_frames / *stride_length + 1:
16320                    *n_frames / *stride_length;
16321
16322     data_size = n_frames_div * size * (*n_particles) *
16323                 (*n_values_per_frame);
16324
16325     temp = realloc(*values, data_size);
16326     if(!temp)
16327     {
16328         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16329                data_size, __FILE__, __LINE__);
16330         free(*values);
16331         *values = 0;
16332         return(TNG_CRITICAL);
16333     }
16334
16335     *values = temp;
16336
16337     if(frame_set->n_mapping_blocks <= 0)
16338     {
16339         memcpy(*values, data->values, data_size);
16340     }
16341     else
16342     {
16343         i_step = (*n_particles) * (*n_values_per_frame);
16344         for(i = 0; i < *n_frames; i++)
16345         {
16346             for(j = 0; j < *n_particles; j++)
16347             {
16348                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16349                 memcpy(((char *)*values) + size * (i * i_step + mapping *
16350                        (*n_values_per_frame)),
16351                        (char *)data->values + size *
16352                        (i * i_step + j * (*n_values_per_frame)),
16353                        size * (*n_values_per_frame));
16354             }
16355         }
16356     }
16357
16358     data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
16359
16360     return(TNG_SUCCESS);
16361 }
16362
16363 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
16364                 (tng_trajectory_t tng_data,
16365                  const int64_t block_id,
16366                  const int64_t start_frame_nr,
16367                  const int64_t end_frame_nr,
16368                  const char hash_mode,
16369                  union data_values ****values,
16370                  int64_t *n_particles,
16371                  int64_t *n_values_per_frame,
16372                  char *type)
16373 {
16374     int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
16375     int64_t first_frame, block_index;
16376     int size;
16377     size_t len;
16378     tng_particle_data_t data;
16379     tng_trajectory_frame_set_t frame_set;
16380     tng_gen_block_t block;
16381     char block_type_flag;
16382     tng_function_status stat;
16383
16384     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16385     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16386     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16387     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16388     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16389
16390     block_index = -1;
16391
16392     frame_set = &tng_data->current_trajectory_frame_set;
16393     first_frame = frame_set->first_frame;
16394
16395     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16396     if(stat != TNG_SUCCESS)
16397     {
16398         return(stat);
16399     }
16400
16401     /* Do not re-read the frame set. */
16402     if(first_frame != frame_set->first_frame ||
16403        frame_set->n_particle_data_blocks <= 0)
16404     {
16405         tng_block_init(&block);
16406         file_pos = ftello(tng_data->input_file);
16407         /* Read all blocks until next frame set block */
16408         stat = tng_block_header_read(tng_data, block);
16409         while(file_pos < tng_data->input_file_len &&
16410                 stat != TNG_CRITICAL &&
16411                 block->id != TNG_TRAJECTORY_FRAME_SET &&
16412                 block->id != -1)
16413         {
16414             stat = tng_block_read_next(tng_data, block,
16415                                     hash_mode);
16416             if(stat != TNG_CRITICAL)
16417             {
16418                 file_pos = ftello(tng_data->input_file);
16419                 if(file_pos < tng_data->input_file_len)
16420                 {
16421                     stat = tng_block_header_read(tng_data, block);
16422                 }
16423             }
16424         }
16425         tng_block_destroy(&block);
16426         if(stat == TNG_CRITICAL)
16427         {
16428             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16429                     file_pos, __FILE__, __LINE__);
16430             return(stat);
16431         }
16432     }
16433
16434     /* See if there is already a data block of this ID.
16435      * Start checking the last read frame set */
16436     for(i = frame_set->n_particle_data_blocks; i-- ;)
16437     {
16438         data = &frame_set->tr_particle_data[i];
16439         if(data->block_id == block_id)
16440         {
16441             block_index = i;
16442             block_type_flag = TNG_TRAJECTORY_BLOCK;
16443             break;
16444         }
16445     }
16446
16447     if(block_index < 0)
16448     {
16449         fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
16450                 block_id, __FILE__, __LINE__);
16451         return(TNG_FAILURE);
16452     }
16453
16454     if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
16455        tng_data->var_num_atoms_flag)
16456     {
16457         *n_particles = frame_set->n_particles;
16458     }
16459     else
16460     {
16461         *n_particles = tng_data->n_particles;
16462     }
16463
16464     n_frames = end_frame_nr - start_frame_nr + 1;
16465     *n_values_per_frame = data->n_values_per_frame;
16466     *type = data->datatype;
16467
16468     if(*values == 0)
16469     {
16470         if(tng_particle_data_values_alloc(tng_data, values, n_frames,
16471                                          *n_particles, *n_values_per_frame,
16472                                          *type)
16473             != TNG_SUCCESS)
16474         {
16475             return(TNG_CRITICAL);
16476         }
16477     }
16478
16479     current_frame_pos = start_frame_nr - frame_set->first_frame;
16480     /* It's not very elegant to reuse so much of the code in the different case
16481      * statements, but it's unnecessarily slow to have the switch-case block
16482      * inside the for loops. */
16483     switch(*type)
16484     {
16485     case TNG_CHAR_DATA:
16486         for(i=0; i<n_frames; i++)
16487         {
16488             if(current_frame_pos == frame_set->n_frames)
16489             {
16490                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16491                 if(stat != TNG_SUCCESS)
16492                 {
16493                     return(stat);
16494                 }
16495                 current_frame_pos = 0;
16496             }
16497             for(j = 0; j < *n_particles; j++)
16498             {
16499                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16500                 for(k = 0; k < *n_values_per_frame; k++)
16501                 {
16502                     len = strlen(data->strings[current_frame_pos][j][k]) + 1;
16503                     (*values)[i][mapping][k].c = malloc(len);
16504                     strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
16505                 }
16506             }
16507             current_frame_pos++;
16508         }
16509         break;
16510     case TNG_INT_DATA:
16511         size = sizeof(int);
16512         i_step = (*n_particles) * (*n_values_per_frame);
16513         for(i=0; i<n_frames; i++)
16514         {
16515             if(current_frame_pos == frame_set->n_frames)
16516             {
16517                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16518                 if(stat != TNG_SUCCESS)
16519                 {
16520                     return(stat);
16521                 }
16522                 current_frame_pos = 0;
16523             }
16524             for(j = 0; j < *n_particles; j++)
16525             {
16526                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16527                 for(k = 0; k < *n_values_per_frame; k++)
16528                 {
16529                     (*values)[i][mapping][k].i = *(int *)
16530                                                  ((char *)data->values + size *
16531                                                   (current_frame_pos *
16532                                                    i_step + j *
16533                                                    (*n_values_per_frame) + k));
16534                 }
16535             }
16536             current_frame_pos++;
16537         }
16538         break;
16539     case TNG_FLOAT_DATA:
16540         size = sizeof(float);
16541         i_step = (*n_particles) * (*n_values_per_frame);
16542         for(i=0; i<n_frames; i++)
16543         {
16544             if(current_frame_pos == frame_set->n_frames)
16545             {
16546                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16547                 if(stat != TNG_SUCCESS)
16548                 {
16549                     return(stat);
16550                 }
16551                 current_frame_pos = 0;
16552             }
16553             for(j=0; j<*n_particles; j++)
16554             {
16555                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16556                 for(k=0; k<*n_values_per_frame; k++)
16557                 {
16558                     (*values)[i][mapping][k].f = *(float *)
16559                                                  ((char *)data->values + size *
16560                                                   (current_frame_pos *
16561                                                    i_step + j *
16562                                                    (*n_values_per_frame) + k));
16563                 }
16564             }
16565             current_frame_pos++;
16566         }
16567         break;
16568     case TNG_DOUBLE_DATA:
16569     default:
16570         size = sizeof(double);
16571         i_step = (*n_particles) * (*n_values_per_frame);
16572         for(i=0; i<n_frames; i++)
16573         {
16574             if(current_frame_pos == frame_set->n_frames)
16575             {
16576                 stat = tng_frame_set_read_next(tng_data, hash_mode);
16577                 if(stat != TNG_SUCCESS)
16578                 {
16579                     return(stat);
16580                 }
16581                 current_frame_pos = 0;
16582             }
16583             for(j=0; j<*n_particles; j++)
16584             {
16585                 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
16586                 for(k=0; k<*n_values_per_frame; k++)
16587                 {
16588                     (*values)[i][mapping][k].d = *(double *)
16589                                                  ((char *)data->values + size *
16590                                                   (current_frame_pos *
16591                                                    i_step + j *
16592                                                    (*n_values_per_frame) + k));
16593                 }
16594             }
16595             current_frame_pos++;
16596         }
16597     }
16598
16599     data->last_retrieved_frame = end_frame_nr;
16600
16601     return(TNG_SUCCESS);
16602 }
16603
16604 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
16605                 (tng_trajectory_t tng_data,
16606                  const int64_t block_id,
16607                  const int64_t start_frame_nr,
16608                  const int64_t end_frame_nr,
16609                  const char hash_mode,
16610                  void **values,
16611                  int64_t *n_particles,
16612                  int64_t *stride_length,
16613                  int64_t *n_values_per_frame,
16614                  char *type)
16615 {
16616     int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
16617     int64_t file_pos, current_frame_pos, last_frame_pos, data_size, frame_size;
16618     int size;
16619     tng_trajectory_frame_set_t frame_set;
16620     tng_particle_data_t p_data;
16621     tng_gen_block_t block;
16622     void *current_values = 0, *temp;
16623     tng_function_status stat;
16624
16625     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16626     TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
16627     TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
16628     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
16629     TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
16630     TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
16631
16632     frame_set = &tng_data->current_trajectory_frame_set;
16633     first_frame = frame_set->first_frame;
16634
16635     stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
16636     if(stat != TNG_SUCCESS)
16637     {
16638         return(stat);
16639     }
16640
16641     /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
16642     /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
16643     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16644     if(first_frame != frame_set->first_frame ||
16645        stat != TNG_SUCCESS)
16646     {
16647         tng_block_init(&block);
16648         if(stat != TNG_SUCCESS)
16649         {
16650             fseeko(tng_data->input_file,
16651                    tng_data->current_trajectory_frame_set_input_file_pos,
16652                    SEEK_SET);
16653             stat = tng_block_header_read(tng_data, block);
16654             if(stat != TNG_SUCCESS)
16655             {
16656                 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
16657                         __FILE__, __LINE__);
16658                 return(stat);
16659             }
16660
16661             fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
16662         }
16663         file_pos = ftello(tng_data->input_file);
16664         /* Read until next frame set block */
16665         stat = tng_block_header_read(tng_data, block);
16666         while(file_pos < tng_data->input_file_len &&
16667             stat != TNG_CRITICAL &&
16668             block->id != TNG_TRAJECTORY_FRAME_SET &&
16669             block->id != -1)
16670         {
16671             if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
16672             {
16673                 stat = tng_block_read_next(tng_data, block,
16674                                         hash_mode);
16675                 if(stat != TNG_CRITICAL)
16676                 {
16677                     file_pos = ftello(tng_data->input_file);
16678                     if(file_pos < tng_data->input_file_len)
16679                     {
16680                         stat = tng_block_header_read(tng_data, block);
16681                     }
16682                 }
16683             }
16684             else
16685             {
16686                 file_pos += block->block_contents_size + block->header_contents_size;
16687                 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
16688                 if(file_pos < tng_data->input_file_len)
16689                 {
16690                     stat = tng_block_header_read(tng_data, block);
16691                 }
16692             }
16693         }
16694         tng_block_destroy(&block);
16695         if(stat == TNG_CRITICAL)
16696         {
16697             fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
16698                     file_pos, __FILE__, __LINE__);
16699             return(stat);
16700         }
16701     }
16702     stat = tng_particle_data_find(tng_data, block_id, &p_data);
16703     if(stat != TNG_SUCCESS)
16704     {
16705         return(stat);
16706     }
16707
16708     stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16709                                         &n_frames, stride_length, n_particles,
16710                                         n_values_per_frame, type);
16711
16712     if(stat != TNG_SUCCESS || *n_particles == 0)
16713     {
16714         if(current_values)
16715         {
16716             free(current_values);
16717         }
16718         return(stat);
16719     }
16720
16721     if(n_frames == 1 && n_frames < frame_set->n_frames)
16722     {
16723         tot_n_frames = 1;
16724     }
16725     else
16726     {
16727         tot_n_frames = end_frame_nr - start_frame_nr + 1;
16728     }
16729
16730     switch(*type)
16731     {
16732     case TNG_CHAR_DATA:
16733         return(TNG_FAILURE);
16734     case TNG_INT_DATA:
16735         size = sizeof(int64_t);
16736         break;
16737     case TNG_FLOAT_DATA:
16738         size = sizeof(float);
16739         break;
16740     case TNG_DOUBLE_DATA:
16741     default:
16742         size = sizeof(double);
16743     }
16744
16745     n_frames_div = (tot_n_frames % *stride_length) ?
16746                  tot_n_frames / *stride_length + 1:
16747                  tot_n_frames / *stride_length;
16748
16749     data_size = n_frames_div * size * (*n_particles) *
16750                 (*n_values_per_frame);
16751
16752     temp = realloc(*values, data_size);
16753     if(!temp)
16754     {
16755         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
16756                data_size, __FILE__, __LINE__);
16757         free(*values);
16758         *values = 0;
16759         return(TNG_CRITICAL);
16760     }
16761
16762     *values = temp;
16763
16764     if( n_frames == 1 && n_frames < frame_set->n_frames)
16765     {
16766         memcpy(*values, current_values, size * (*n_particles) *
16767                (*n_values_per_frame));
16768     }
16769     else
16770     {
16771         current_frame_pos = start_frame_nr - frame_set->first_frame;
16772
16773         frame_size = size * (*n_particles) * (*n_values_per_frame);
16774
16775         last_frame_pos = tng_min_i64(n_frames,
16776                                      end_frame_nr - start_frame_nr);
16777
16778         n_frames_div = current_frame_pos / *stride_length;
16779         n_frames_div_2 = (last_frame_pos % *stride_length) ?
16780                        last_frame_pos / *stride_length + 1:
16781                        last_frame_pos / *stride_length;
16782         n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
16783
16784         memcpy(*values, (char *)current_values + n_frames_div * frame_size,
16785                n_frames_div_2 * frame_size);
16786
16787         current_frame_pos += n_frames - current_frame_pos;
16788
16789         while(current_frame_pos <= end_frame_nr - start_frame_nr)
16790         {
16791             stat = tng_frame_set_read_next(tng_data, hash_mode);
16792             if(stat != TNG_SUCCESS)
16793             {
16794                 if(current_values)
16795                 {
16796                     free(current_values);
16797                 }
16798                 free(*values);
16799                 *values = 0;
16800                 return(stat);
16801             }
16802
16803             stat = tng_particle_data_vector_get(tng_data, block_id, &current_values,
16804                                                 &n_frames, stride_length, n_particles,
16805                                                 n_values_per_frame, type);
16806
16807             if(stat != TNG_SUCCESS)
16808             {
16809                 if(current_values)
16810                 {
16811                     free(current_values);
16812                 }
16813                 free(*values);
16814                 *values = 0;
16815                 return(stat);
16816             }
16817
16818             last_frame_pos = tng_min_i64(n_frames,
16819                                          end_frame_nr - current_frame_pos);
16820
16821             n_frames_div = current_frame_pos / *stride_length;
16822             n_frames_div_2 = (last_frame_pos % *stride_length) ?
16823                            last_frame_pos / *stride_length + 1:
16824                            last_frame_pos / *stride_length;
16825             n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
16826
16827             memcpy(((char *)*values) + n_frames_div * frame_size,
16828                    current_values,
16829                    n_frames_div_2 * frame_size);
16830
16831             current_frame_pos += n_frames;
16832         }
16833     }
16834
16835     if(current_values)
16836     {
16837         free(current_values);
16838     }
16839
16840     p_data->last_retrieved_frame = end_frame_nr;
16841
16842     return(TNG_SUCCESS);
16843 }
16844
16845 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
16846                 (const tng_trajectory_t tng_data,
16847                  const int64_t block_id,
16848                  int64_t frame,
16849                  int64_t *stride_length)
16850 {
16851     tng_function_status stat;
16852     tng_non_particle_data_t np_data;
16853     tng_particle_data_t p_data;
16854     int64_t orig_file_pos, file_pos;
16855     int is_particle_data;
16856
16857     if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
16858     {
16859         frame = 0;
16860     }
16861
16862     if(frame >= 0)
16863     {
16864         stat = tng_frame_set_of_frame_find(tng_data, frame);
16865         if(stat != TNG_SUCCESS)
16866         {
16867             return(stat);
16868         }
16869     }
16870     orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
16871     stat = tng_data_find(tng_data, block_id, &np_data);
16872     if(stat != TNG_SUCCESS)
16873     {
16874         stat = tng_particle_data_find(tng_data, block_id, &p_data);
16875         if(stat != TNG_SUCCESS)
16876         {
16877             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16878             /* If no specific frame was required read until this data block is found */
16879             if(frame < 0)
16880             {
16881                 file_pos = ftello(tng_data->input_file);
16882                 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
16883                 {
16884                     stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
16885                     file_pos = ftello(tng_data->input_file);
16886                 }
16887             }
16888             if(stat != TNG_SUCCESS)
16889             {
16890                 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16891
16892                 return(stat);
16893             }
16894             stat = tng_data_find(tng_data, block_id, &np_data);
16895             if(stat != TNG_SUCCESS)
16896             {
16897                 stat = tng_particle_data_find(tng_data, block_id, &p_data);
16898                 if(stat != TNG_SUCCESS)
16899                 {
16900                     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16901
16902                     return(stat);
16903                 }
16904                 else
16905                 {
16906                     is_particle_data = 1;
16907                 }
16908             }
16909             else
16910             {
16911                 is_particle_data = 0;
16912             }
16913         }
16914         else
16915         {
16916             is_particle_data = 1;
16917         }
16918     }
16919     else
16920     {
16921         is_particle_data = 0;
16922     }
16923     if(is_particle_data)
16924     {
16925         *stride_length = p_data->stride_length;
16926     }
16927     else
16928     {
16929         *stride_length = np_data->stride_length;
16930     }
16931     tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
16932
16933     return(TNG_SUCCESS);
16934 }
16935
16936 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
16937                 (const tng_trajectory_t tng_data,
16938                  char *time)
16939 {
16940     struct tm *time_data;
16941     time_t secs;
16942
16943     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16944     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
16945
16946     secs = tng_data->time;
16947
16948     time_data = localtime(&secs); /* Returns a statically allocated variable. */
16949     TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
16950              "%4d-%02d-%02d %02d:%02d:%02d",
16951              time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
16952              time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
16953
16954     return(TNG_SUCCESS);
16955 }
16956
16957
16958 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
16959                 (const char *filename,
16960                  const char mode,
16961                  tng_trajectory_t *tng_data_p)
16962 {
16963     tng_function_status stat;
16964
16965     TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
16966
16967     if(mode != 'r' && mode != 'w' && mode != 'a')
16968     {
16969         return(TNG_FAILURE);
16970     }
16971
16972     if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
16973     {
16974         tng_trajectory_destroy(tng_data_p);
16975         return(TNG_CRITICAL);
16976     }
16977
16978     if(mode == 'r' || mode == 'a')
16979     {
16980         tng_input_file_set(*tng_data_p, filename);
16981
16982         /* Read the file headers */
16983         tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
16984
16985         stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
16986
16987         if(stat != TNG_SUCCESS)
16988         {
16989             return(stat);
16990         }
16991     }
16992
16993     if(mode == 'w')
16994     {
16995         tng_output_file_set(*tng_data_p, filename);
16996     }
16997     else if(mode == 'a')
16998     {
16999         if((*tng_data_p)->output_file)
17000         {
17001             fclose((*tng_data_p)->output_file);
17002         }
17003         (*tng_data_p)->output_file = (*tng_data_p)->input_file;
17004         fseeko((*tng_data_p)->input_file,
17005                (*tng_data_p)->last_trajectory_frame_set_input_file_pos,
17006                SEEK_SET);
17007
17008         stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
17009         if(stat != TNG_SUCCESS)
17010         {
17011             fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
17012                    __FILE__, __LINE__);
17013         }
17014         (*tng_data_p)->output_file = 0;
17015
17016         (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
17017         (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
17018         (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
17019         (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
17020         (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
17021         (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
17022         if((*tng_data_p)->input_file)
17023         {
17024             fclose((*tng_data_p)->input_file);
17025             (*tng_data_p)->input_file = 0;
17026         }
17027         if((*tng_data_p)->input_file_path)
17028         {
17029             free((*tng_data_p)->input_file_path);
17030             (*tng_data_p)->input_file_path = 0;
17031         }
17032         tng_output_append_file_set(*tng_data_p, filename);
17033
17034         fseeko((*tng_data_p)->output_file, 0, SEEK_END);
17035     }
17036
17037     return(TNG_SUCCESS);
17038 }
17039
17040 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
17041                 (tng_trajectory_t *tng_data_p)
17042 {
17043     tng_trajectory_frame_set_t frame_set;
17044
17045     if(tng_data_p == 0)
17046     {
17047         fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
17048                __FILE__, __LINE__);
17049         return(TNG_FAILURE);
17050     }
17051
17052     if(*tng_data_p == 0)
17053     {
17054         return(TNG_SUCCESS);
17055     }
17056
17057     frame_set = &(*tng_data_p)->current_trajectory_frame_set;
17058
17059     if(frame_set->n_unwritten_frames > 0)
17060     {
17061         frame_set->n_frames = frame_set->n_unwritten_frames;
17062         tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
17063     }
17064
17065     return(tng_trajectory_destroy(tng_data_p));
17066 }
17067
17068 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
17069                 (tng_trajectory_t tng_data,
17070                  const int64_t frame_nr,
17071                  double *time)
17072 {
17073     int64_t first_frame;
17074     tng_trajectory_frame_set_t frame_set;
17075     tng_function_status stat;
17076
17077     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17078     TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
17079
17080     stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
17081     if(stat != TNG_SUCCESS)
17082     {
17083         fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
17084                frame_nr, __FILE__, __LINE__);
17085         return(stat);
17086     }
17087
17088     frame_set = &tng_data->current_trajectory_frame_set;
17089     first_frame = frame_set->first_frame;
17090
17091     if(tng_data->time_per_frame <= 0)
17092     {
17093         return(TNG_FAILURE);
17094     }
17095
17096     *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
17097
17098     return(TNG_SUCCESS);
17099 }
17100
17101 /*
17102 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
17103                 (tng_trajectory_t tng_data,
17104                  int64_t *n_mols,
17105                  int64_t **molecule_cnt_list,
17106                  tng_molecule_t *mols)
17107 {
17108     tng_trajectory_frame_set_t frame_set;
17109
17110     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17111     TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
17112
17113     *n_mols = tng_data->n_molecules;
17114
17115     frame_set = &tng_data->current_trajectory_frame_set;
17116     if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
17117     {
17118         *molecule_cnt_list = frame_set->molecule_cnt_list;
17119     }
17120     else
17121     {
17122         *molecule_cnt_list = tng_data->molecule_cnt_list;
17123     }
17124
17125     *mols = tng_data->molecules;
17126
17127     return(TNG_SUCCESS);
17128 }
17129 */
17130 /*
17131 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
17132                 (tng_trajectory_t tng_data,
17133                  const char *name,
17134                  const int64_t cnt,
17135                  tng_molecule_t *mol)
17136 {
17137     tng_function_status stat;
17138
17139     TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
17140     TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
17141
17142     stat = tng_molecule_add(tng_data, name, mol);
17143     if(stat != TNG_SUCCESS)
17144     {
17145         return(stat);
17146     }
17147     stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
17148
17149     return(stat);
17150 }
17151 */
17152 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
17153                 (tng_trajectory_t tng_data,
17154                  const tng_molecule_t mol,
17155                  int64_t *n_particles,
17156                  char ***names,
17157                  char ***types,
17158                  char ***res_names,
17159                  int64_t **res_ids,
17160                  char ***chain_names,
17161                  int64_t **chain_ids)
17162 {
17163     tng_atom_t atom;
17164     tng_residue_t res;
17165     tng_chain_t chain;
17166     int64_t i;
17167     (void)tng_data;
17168
17169     *n_particles = mol->n_atoms;
17170
17171     *names = malloc(sizeof(char *) * *n_particles);
17172     *types = malloc(sizeof(char *) * *n_particles);
17173     *res_names = malloc(sizeof(char *) * *n_particles);
17174     *chain_names = malloc(sizeof(char *) * *n_particles);
17175     *res_ids = malloc(sizeof(int64_t) * *n_particles);
17176     *chain_ids = malloc(sizeof(int64_t) * *n_particles);
17177
17178     for(i = 0; i < *n_particles; i++)
17179     {
17180         atom = &mol->atoms[i];
17181         res = atom->residue;
17182         chain = res->chain;
17183         (*names)[i] = malloc(strlen(atom->name));
17184         strcpy(*names[i], atom->name);
17185         (*types)[i] = malloc(strlen(atom->atom_type));
17186         strcpy(*types[i], atom->atom_type);
17187         (*res_names)[i] = malloc(strlen(res->name));
17188         strcpy(*res_names[i], res->name);
17189         (*chain_names)[i] = malloc(strlen(chain->name));
17190         strcpy(*chain_names[i], chain->name);
17191         (*res_ids)[i] = res->id;
17192         (*chain_ids)[i] = chain->id;
17193     }
17194
17195     return(TNG_SUCCESS);
17196 }
17197
17198 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
17199                 (tng_trajectory_t tng_data,
17200                  tng_molecule_t mol,
17201                  const int64_t n_particles,
17202                  const char **names,
17203                  const char **types,
17204                  const char **res_names,
17205                  const int64_t *res_ids,
17206                  const char **chain_names,
17207                  const int64_t *chain_ids)
17208 {
17209     int64_t i;
17210     tng_chain_t chain;
17211     tng_residue_t residue;
17212     tng_atom_t atom;
17213     tng_function_status stat;
17214
17215     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17216     TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
17217     TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
17218     TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
17219     TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
17220     TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
17221     TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
17222
17223     for(i = 0; i < n_particles; i++)
17224     {
17225         if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
17226            &chain) == TNG_FAILURE)
17227         {
17228             stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
17229                                           &chain);
17230             if(stat != TNG_SUCCESS)
17231             {
17232                 return(stat);
17233             }
17234         }
17235         if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
17236            &residue) == TNG_FAILURE)
17237         {
17238             stat = tng_chain_residue_add(tng_data, chain, res_names[i],
17239                                          &residue);
17240             if(stat != TNG_SUCCESS)
17241             {
17242                 return(stat);
17243             }
17244         }
17245         stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
17246         if(stat != TNG_SUCCESS)
17247         {
17248             return(stat);
17249         }
17250     }
17251     return(TNG_SUCCESS);
17252 }
17253
17254 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
17255                 (tng_trajectory_t tng_data,
17256                  float **positions, int64_t *stride_length)
17257 {
17258     int64_t n_frames, n_particles, n_values_per_frame;
17259     char type;
17260     tng_function_status stat;
17261
17262     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17263     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17264     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17265
17266     stat = tng_num_frames_get(tng_data, &n_frames);
17267     if(stat != TNG_SUCCESS)
17268     {
17269         return(stat);
17270     }
17271
17272     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17273                                                  0, n_frames - 1, TNG_USE_HASH,
17274                                                  (void **)positions,
17275                                                  &n_particles,
17276                                                  stride_length,
17277                                                  &n_values_per_frame,
17278                                                  &type);
17279
17280     return(stat);
17281 }
17282
17283 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
17284                 (tng_trajectory_t tng_data,
17285                  float **velocities, int64_t *stride_length)
17286 {
17287     int64_t n_frames, n_particles, n_values_per_frame;
17288     char type;
17289     tng_function_status stat;
17290
17291     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17292     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17293     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17294
17295     stat = tng_num_frames_get(tng_data, &n_frames);
17296     if(stat != TNG_SUCCESS)
17297     {
17298         return(stat);
17299     }
17300
17301     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17302                                                  0, n_frames - 1, TNG_USE_HASH,
17303                                                  (void **)velocities,
17304                                                  &n_particles,
17305                                                  stride_length,
17306                                                  &n_values_per_frame,
17307                                                  &type);
17308
17309     return(stat);
17310 }
17311
17312 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
17313                 (tng_trajectory_t tng_data,
17314                  float **forces, int64_t *stride_length)
17315 {
17316     int64_t n_frames, n_particles, n_values_per_frame;
17317     char type;
17318     tng_function_status stat;
17319
17320     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17321     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17322     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17323
17324     stat = tng_num_frames_get(tng_data, &n_frames);
17325     if(stat != TNG_SUCCESS)
17326     {
17327         return(stat);
17328     }
17329
17330     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17331                                                  0, n_frames - 1, TNG_USE_HASH,
17332                                                  (void **)forces,
17333                                                  &n_particles,
17334                                                  stride_length,
17335                                                  &n_values_per_frame,
17336                                                  &type);
17337
17338     return(stat);
17339 }
17340
17341 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
17342                 (tng_trajectory_t tng_data,
17343                  float **box_shape,
17344                  int64_t *stride_length)
17345 {
17346     int64_t n_frames, n_values_per_frame;
17347     char type;
17348     tng_function_status stat;
17349
17350     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17351     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17352     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17353
17354     stat = tng_num_frames_get(tng_data, &n_frames);
17355     if(stat != TNG_SUCCESS)
17356     {
17357         return(stat);
17358     }
17359
17360     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17361                                         0, n_frames - 1, TNG_USE_HASH,
17362                                         (void **)box_shape,
17363                                         stride_length,
17364                                         &n_values_per_frame,
17365                                         &type);
17366
17367     return(stat);
17368 }
17369
17370 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
17371                 (tng_trajectory_t tng_data,
17372                  const int64_t block_id,
17373                  void **values,
17374                  char *data_type,
17375                  int64_t *retrieved_frame_number,
17376                  double *retrieved_time)
17377 {
17378     tng_trajectory_frame_set_t frame_set;
17379     tng_particle_data_t data = 0;
17380     tng_function_status stat;
17381     int size;
17382     int64_t i, data_size, n_particles, file_pos;
17383     void *temp;
17384
17385     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17386     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17387     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17388     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17389     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17390
17391     frame_set = &tng_data->current_trajectory_frame_set;
17392
17393     stat = tng_particle_data_find(tng_data, block_id, &data);
17394     if(stat != TNG_SUCCESS)
17395     {
17396         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17397         file_pos = ftello(tng_data->input_file);
17398         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17399         {
17400             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17401             file_pos = ftello(tng_data->input_file);
17402         }
17403         if(stat != TNG_SUCCESS)
17404         {
17405             return(stat);
17406         }
17407         stat = tng_particle_data_find(tng_data, block_id, &data);
17408         if(stat != TNG_SUCCESS)
17409         {
17410             return(stat);
17411         }
17412     }
17413     if(data->last_retrieved_frame < 0)
17414     {
17415         fseeko(tng_data->input_file,
17416                tng_data->first_trajectory_frame_set_input_file_pos,
17417                SEEK_SET);
17418         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17419         if(stat != TNG_SUCCESS)
17420         {
17421             return(stat);
17422         }
17423         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17424         if(stat != TNG_SUCCESS)
17425         {
17426             return(stat);
17427         }
17428
17429         i = data->first_frame_with_data;
17430     }
17431     else
17432     {
17433         if(data->n_frames == 1)
17434         {
17435             i = data->last_retrieved_frame + 1;
17436         }
17437         else
17438         {
17439             i = data->last_retrieved_frame + data->stride_length;
17440         }
17441         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17442         {
17443             stat = tng_frame_set_of_frame_find(tng_data, i);
17444             if(stat != TNG_SUCCESS)
17445             {
17446                 /* If the frame set search found the frame set after the starting
17447                  * frame set there is a gap in the frame sets. So, even if the frame
17448                  * was not found the next frame with data is still in the found
17449                  * frame set. */
17450                 if(stat == TNG_CRITICAL)
17451                 {
17452                     return(stat);
17453                 }
17454                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17455                 {
17456                     return(TNG_FAILURE);
17457                 }
17458                 i = frame_set->first_frame;
17459             }
17460         }
17461         if(data->last_retrieved_frame < frame_set->first_frame)
17462         {
17463             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17464             if(stat != TNG_SUCCESS)
17465             {
17466                 return(stat);
17467             }
17468         }
17469     }
17470     data->last_retrieved_frame = i;
17471     *retrieved_frame_number = i;
17472     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17473     {
17474         *retrieved_time = frame_set->first_frame_time +
17475                         (i - frame_set->first_frame) *
17476                         tng_data->time_per_frame;
17477     }
17478     else
17479     {
17480         *retrieved_time = 0;
17481     }
17482
17483     if(data->stride_length > 1)
17484     {
17485         i = (i - data->first_frame_with_data) / data->stride_length;
17486     }
17487     else
17488     {
17489         i = (i - frame_set->first_frame);
17490     }
17491
17492     tng_num_particles_get(tng_data, &n_particles);
17493
17494     *data_type = data->datatype;
17495
17496     switch(*data_type)
17497     {
17498     case TNG_CHAR_DATA:
17499         return(TNG_FAILURE);
17500     case TNG_INT_DATA:
17501         size = sizeof(int64_t);
17502         break;
17503     case TNG_FLOAT_DATA:
17504         size = sizeof(float);
17505         break;
17506     case TNG_DOUBLE_DATA:
17507     default:
17508         size = sizeof(double);
17509     }
17510
17511     data_size = size * n_particles * data->n_values_per_frame;
17512
17513 //     fprintf(stderr, "TNG library: TEMP: i = %"PRId64", data_size = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
17514 //            i, data_size, size, n_particles, data->n_values_per_frame);
17515
17516     temp = realloc(*values, data_size);
17517     if(!temp)
17518     {
17519         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17520                data_size, __FILE__, __LINE__);
17521         free(*values);
17522         *values = 0;
17523         return(TNG_CRITICAL);
17524     }
17525
17526     *values = temp;
17527
17528     memcpy(*values, (char *)data->values + i * data_size, data_size);
17529
17530     return(TNG_SUCCESS);
17531 }
17532
17533 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
17534                 (tng_trajectory_t tng_data,
17535                  const int64_t block_id,
17536                  void **values,
17537                  char *data_type,
17538                  int64_t *retrieved_frame_number,
17539                  double *retrieved_time)
17540 {
17541     tng_trajectory_frame_set_t frame_set;
17542     tng_non_particle_data_t data = 0;
17543     tng_function_status stat;
17544     int size;
17545     int64_t i, data_size, file_pos;
17546     void *temp;
17547
17548     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17549     TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
17550     TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
17551     TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
17552     TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
17553
17554     frame_set = &tng_data->current_trajectory_frame_set;
17555
17556     stat = tng_data_find(tng_data, block_id, &data);
17557     if(stat != TNG_SUCCESS)
17558     {
17559         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17560         file_pos = ftello(tng_data->input_file);
17561         while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
17562         {
17563             stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17564             file_pos = ftello(tng_data->input_file);
17565         }
17566         if(stat != TNG_SUCCESS)
17567         {
17568             return(stat);
17569         }
17570         stat = tng_data_find(tng_data, block_id, &data);
17571         if(stat != TNG_SUCCESS)
17572         {
17573             return(stat);
17574         }
17575     }
17576     if(data->last_retrieved_frame < 0)
17577     {
17578         fseeko(tng_data->input_file,
17579                tng_data->first_trajectory_frame_set_input_file_pos,
17580                SEEK_SET);
17581         stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
17582         if(stat != TNG_SUCCESS)
17583         {
17584             return(stat);
17585         }
17586         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17587         if(stat != TNG_SUCCESS)
17588         {
17589             return(stat);
17590         }
17591
17592         i = data->first_frame_with_data;
17593     }
17594     else
17595     {
17596         if(data->n_frames == 1)
17597         {
17598             i = data->last_retrieved_frame + 1;
17599         }
17600         else
17601         {
17602             i = data->last_retrieved_frame + data->stride_length;
17603         }
17604         if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17605         {
17606             stat = tng_frame_set_of_frame_find(tng_data, i);
17607             if(stat != TNG_SUCCESS)
17608             {
17609                 /* If the frame set search found the frame set after the starting
17610                  * frame set there is a gap in the frame sets. So, even if the frame
17611                  * was not found the next frame with data is still in the found
17612                  * frame set. */
17613                 if(stat == TNG_CRITICAL)
17614                 {
17615                     return(stat);
17616                 }
17617                 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
17618                 {
17619                     return(TNG_FAILURE);
17620                 }
17621                 i = frame_set->first_frame;
17622             }
17623         }
17624         if(data->last_retrieved_frame < frame_set->first_frame)
17625         {
17626             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17627             if(stat != TNG_SUCCESS)
17628             {
17629                 return(stat);
17630             }
17631         }
17632     }
17633     data->last_retrieved_frame = i;
17634     *retrieved_frame_number = i;
17635     if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
17636     {
17637         *retrieved_time = frame_set->first_frame_time +
17638                         (i - frame_set->first_frame) *
17639                         tng_data->time_per_frame;
17640     }
17641     else
17642     {
17643         *retrieved_time = 0;
17644     }
17645
17646     if(data->stride_length > 1)
17647     {
17648         i = (i - data->first_frame_with_data) / data->stride_length;
17649     }
17650     else
17651     {
17652         i = (i - frame_set->first_frame);
17653     }
17654
17655     *data_type = data->datatype;
17656
17657     switch(*data_type)
17658     {
17659     case TNG_CHAR_DATA:
17660         return(TNG_FAILURE);
17661     case TNG_INT_DATA:
17662         size = sizeof(int64_t);
17663         break;
17664     case TNG_FLOAT_DATA:
17665         size = sizeof(float);
17666         break;
17667     case TNG_DOUBLE_DATA:
17668     default:
17669         size = sizeof(double);
17670     }
17671
17672     data_size = size * data->n_values_per_frame;
17673
17674     temp = realloc(*values, data_size);
17675     if(!temp)
17676     {
17677         fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
17678                data_size, __FILE__, __LINE__);
17679         free(*values);
17680         *values = 0;
17681         return(TNG_CRITICAL);
17682     }
17683
17684     *values = temp;
17685
17686     memcpy(*values, (char *)data->values + i * data_size, data_size);
17687
17688     return(TNG_SUCCESS);
17689 }
17690
17691 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
17692                 (tng_trajectory_t tng_data,
17693                  const int64_t first_frame,
17694                  const int64_t last_frame,
17695                  float **positions,
17696                  int64_t *stride_length)
17697 {
17698     int64_t n_particles, n_values_per_frame;
17699     char type;
17700     tng_function_status stat;
17701
17702     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17703     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17704     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17705     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17706
17707     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
17708                                                  first_frame, last_frame,
17709                                                  TNG_USE_HASH,
17710                                                  (void **)positions,
17711                                                  &n_particles,
17712                                                  stride_length,
17713                                                  &n_values_per_frame,
17714                                                  &type);
17715
17716     return(stat);
17717 }
17718
17719 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
17720                 (tng_trajectory_t tng_data,
17721                  const int64_t first_frame,
17722                  const int64_t last_frame,
17723                  float **velocities,
17724                  int64_t *stride_length)
17725 {
17726     int64_t n_particles, n_values_per_frame;
17727     char type;
17728     tng_function_status stat;
17729
17730     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17731     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17732     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17733     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17734
17735     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
17736                                                  first_frame, last_frame,
17737                                                  TNG_USE_HASH,
17738                                                  (void **)velocities,
17739                                                  &n_particles,
17740                                                  stride_length,
17741                                                  &n_values_per_frame,
17742                                                  &type);
17743
17744     return(stat);
17745 }
17746
17747 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
17748                 (tng_trajectory_t tng_data,
17749                  const int64_t first_frame,
17750                  const int64_t last_frame,
17751                  float **forces,
17752                  int64_t *stride_length)
17753 {
17754     int64_t n_particles, n_values_per_frame;
17755     char type;
17756     tng_function_status stat;
17757
17758     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17759     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17760     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17761     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17762
17763     stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
17764                                                  first_frame, last_frame,
17765                                                  TNG_USE_HASH,
17766                                                  (void **)forces,
17767                                                  &n_particles,
17768                                                  stride_length,
17769                                                  &n_values_per_frame,
17770                                                  &type);
17771
17772     return(stat);
17773 }
17774
17775 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
17776                 (tng_trajectory_t tng_data,
17777                  const int64_t first_frame,
17778                  const int64_t last_frame,
17779                  float **box_shape,
17780                  int64_t *stride_length)
17781 {
17782     int64_t n_values_per_frame;
17783     char type;
17784     tng_function_status stat;
17785
17786     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17787     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17788     TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
17789     TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
17790
17791     stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
17792                                         first_frame, last_frame,
17793                                         TNG_USE_HASH,
17794                                         (void **)box_shape,
17795                                         stride_length,
17796                                         &n_values_per_frame,
17797                                         &type);
17798
17799     return(stat);
17800 }
17801
17802 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
17803                 (tng_trajectory_t tng_data,
17804                  const int64_t i,
17805                  const int64_t n_values_per_frame,
17806                  const int64_t block_id,
17807                  const char *block_name,
17808                  const char particle_dependency,
17809                  const char compression)
17810 {
17811     tng_trajectory_frame_set_t frame_set;
17812     tng_particle_data_t p_data;
17813     tng_non_particle_data_t np_data;
17814     int64_t n_particles, n_frames;
17815     tng_function_status stat;
17816
17817     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17818     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17819
17820     if(i <= 0)
17821     {
17822         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17823                i, __FILE__, __LINE__);
17824         return(TNG_FAILURE);
17825     }
17826
17827     frame_set = &tng_data->current_trajectory_frame_set;
17828
17829     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17830     {
17831         n_frames = tng_data->frame_set_n_frames;
17832
17833         stat = tng_frame_set_new(tng_data, 0, n_frames);
17834         if(stat != TNG_SUCCESS)
17835         {
17836             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17837                 __LINE__);
17838             return(stat);
17839         }
17840     }
17841     else
17842     {
17843         n_frames = frame_set->n_frames;
17844     }
17845
17846     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17847     {
17848         tng_num_particles_get(tng_data, &n_particles);
17849         if(n_particles <= 0)
17850         {
17851             return(TNG_FAILURE);
17852         }
17853
17854         if(tng_particle_data_find(tng_data, block_id, &p_data)
17855         != TNG_SUCCESS)
17856         {
17857             stat = tng_particle_data_block_add(tng_data, block_id,
17858                                                block_name,
17859                                                TNG_FLOAT_DATA,
17860                                                TNG_TRAJECTORY_BLOCK,
17861                                                n_frames, n_values_per_frame, i,
17862                                                0, n_particles,
17863                                                compression, 0);
17864             if(stat != TNG_SUCCESS)
17865             {
17866                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17867                        __FILE__, __LINE__);
17868                 return(stat);
17869             }
17870             p_data = &frame_set->tr_particle_data[frame_set->
17871                                                   n_particle_data_blocks - 1];
17872             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17873                                                   i, n_particles,
17874                                                   n_values_per_frame);
17875             if(stat != TNG_SUCCESS)
17876             {
17877                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17878                        __FILE__, __LINE__);
17879                 return(stat);
17880             }
17881         }
17882         else
17883         {
17884             if(p_data->stride_length != i)
17885             {
17886                 p_data->stride_length = i;
17887                 stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
17888                                                       i, n_particles,
17889                                                       n_values_per_frame);
17890                 if(stat != TNG_SUCCESS)
17891                 {
17892                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17893                            __FILE__, __LINE__);
17894                     return(stat);
17895                 }
17896             }
17897         }
17898     }
17899     else
17900     {
17901         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
17902         {
17903             stat = tng_data_block_add(tng_data, block_id, block_name,
17904                                       TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
17905                                       n_frames, n_values_per_frame,
17906                                       i, compression, 0);
17907             if(stat != TNG_SUCCESS)
17908             {
17909                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
17910                        __FILE__, __LINE__);
17911                 return(stat);
17912             }
17913             np_data = &frame_set->tr_data[frame_set->
17914                                           n_data_blocks - 1];
17915             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17916                                          i, n_values_per_frame);
17917             if(stat != TNG_SUCCESS)
17918             {
17919                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17920                        __FILE__, __LINE__);
17921                 return(stat);
17922             }
17923         }
17924         else
17925         {
17926             if(np_data->stride_length != i)
17927             {
17928                 np_data->stride_length = i;
17929                 stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
17930                                              i, n_values_per_frame);
17931                 if(stat != TNG_SUCCESS)
17932                 {
17933                     fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
17934                            __FILE__, __LINE__);
17935                     return(stat);
17936                 }
17937             }
17938         }
17939     }
17940
17941     return(TNG_SUCCESS);
17942 }
17943
17944 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
17945                 (tng_trajectory_t tng_data,
17946                  const int64_t i,
17947                  const int64_t n_values_per_frame,
17948                  const int64_t block_id,
17949                  const char *block_name,
17950                  const char particle_dependency,
17951                  const char compression)
17952 {
17953     tng_trajectory_frame_set_t frame_set;
17954     tng_particle_data_t p_data;
17955     tng_non_particle_data_t np_data;
17956     int64_t n_particles, n_frames;
17957     tng_function_status stat;
17958
17959     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17960     TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
17961
17962     if(i <= 0)
17963     {
17964         fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
17965                i, __FILE__, __LINE__);
17966         return(TNG_FAILURE);
17967     }
17968
17969     frame_set = &tng_data->current_trajectory_frame_set;
17970
17971     if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
17972     {
17973         n_frames = tng_data->frame_set_n_frames;
17974
17975         stat = tng_frame_set_new(tng_data, 0, n_frames);
17976         if(stat != TNG_SUCCESS)
17977         {
17978             fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
17979                 __LINE__);
17980             return(stat);
17981         }
17982     }
17983     else
17984     {
17985         n_frames = frame_set->n_frames;
17986     }
17987
17988     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
17989     {
17990         tng_num_particles_get(tng_data, &n_particles);
17991
17992         if(n_particles <= 0)
17993         {
17994             return(TNG_FAILURE);
17995         }
17996
17997         if(tng_particle_data_find(tng_data, block_id, &p_data)
17998         != TNG_SUCCESS)
17999         {
18000             stat = tng_particle_data_block_add(tng_data, block_id,
18001                                             block_name,
18002                                             TNG_DOUBLE_DATA,
18003                                             TNG_TRAJECTORY_BLOCK,
18004                                             n_frames, n_values_per_frame, i,
18005                                             0, n_particles,
18006                                             compression, 0);
18007             if(stat != TNG_SUCCESS)
18008             {
18009                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18010                        __FILE__, __LINE__);
18011                 return(stat);
18012             }
18013             p_data = &frame_set->tr_particle_data[frame_set->
18014                                                   n_particle_data_blocks - 1];
18015             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18016                                                   i, n_particles,
18017                                                   n_values_per_frame);
18018             if(stat != TNG_SUCCESS)
18019             {
18020                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18021                        __FILE__, __LINE__);
18022                 return(stat);
18023             }
18024         }
18025         else
18026         {
18027             p_data->stride_length = i;
18028         }
18029     }
18030     else
18031     {
18032         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18033         {
18034             stat = tng_data_block_add(tng_data, block_id, block_name,
18035                                       TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
18036                                       n_frames, n_values_per_frame,
18037                                       i, compression, 0);
18038             if(stat != TNG_SUCCESS)
18039             {
18040                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18041                        __FILE__, __LINE__);
18042                 return(stat);
18043             }
18044             np_data = &frame_set->tr_data[frame_set->
18045                                           n_data_blocks - 1];
18046             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18047                                          i, n_values_per_frame);
18048             if(stat != TNG_SUCCESS)
18049             {
18050                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18051                        __FILE__, __LINE__);
18052                 return(stat);
18053             }
18054         }
18055         else
18056         {
18057             np_data->stride_length = i;
18058         }
18059     }
18060
18061     return(TNG_SUCCESS);
18062 }
18063
18064 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
18065                 (tng_trajectory_t tng_data,
18066                  const int64_t i,
18067                  const int64_t n_values_per_frame,
18068                  const int64_t block_id,
18069                  const char *block_name,
18070                  const char particle_dependency,
18071                  const char compression)
18072 {
18073     fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
18074            "See documentation. %s: %d", __FILE__, __LINE__);
18075     return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
18076                                                block_id, block_name,
18077                                                particle_dependency,
18078                                                compression));
18079 }
18080 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
18081                 (tng_trajectory_t tng_data,
18082                  const int64_t i)
18083 {
18084     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18085     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18086
18087     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18088                                                TNG_TRAJ_POSITIONS,
18089                                                "POSITIONS",
18090                                                TNG_PARTICLE_BLOCK_DATA,
18091                                                TNG_TNG_COMPRESSION));
18092 }
18093
18094 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
18095                 (tng_trajectory_t tng_data,
18096                  const int64_t i)
18097 {
18098     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18099     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18100
18101     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18102                                                       TNG_TRAJ_POSITIONS,
18103                                                       "POSITIONS",
18104                                                       TNG_PARTICLE_BLOCK_DATA,
18105                                                       TNG_TNG_COMPRESSION));
18106 }
18107
18108 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
18109                 (tng_trajectory_t tng_data,
18110                  const int64_t i)
18111 {
18112     fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
18113            "See documentation. %s: %d", __FILE__, __LINE__);
18114     return(tng_util_pos_write_interval_set(tng_data, i));
18115 }
18116
18117 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
18118                 (tng_trajectory_t tng_data,
18119                  const int64_t i)
18120 {
18121     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18122     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18123
18124     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18125                                                TNG_TRAJ_VELOCITIES,
18126                                                "VELOCITIES",
18127                                                TNG_PARTICLE_BLOCK_DATA,
18128                                                TNG_TNG_COMPRESSION));
18129 }
18130
18131 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
18132                 (tng_trajectory_t tng_data,
18133                  const int64_t i)
18134 {
18135     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18136     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18137
18138     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18139                                                       TNG_TRAJ_VELOCITIES,
18140                                                       "VELOCITIES",
18141                                                       TNG_PARTICLE_BLOCK_DATA,
18142                                                       TNG_TNG_COMPRESSION));
18143 }
18144
18145 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
18146                 (tng_trajectory_t tng_data,
18147                  const int64_t i)
18148 {
18149     fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
18150            "See documentation. %s: %d", __FILE__, __LINE__);
18151     return(tng_util_vel_write_interval_set(tng_data, i));
18152 }
18153
18154 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
18155                 (tng_trajectory_t tng_data,
18156                  const int64_t i)
18157 {
18158     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18159     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18160
18161     return(tng_util_generic_write_interval_set(tng_data, i, 3,
18162                                                TNG_TRAJ_FORCES,
18163                                                "FORCES",
18164                                                TNG_PARTICLE_BLOCK_DATA,
18165                                                TNG_GZIP_COMPRESSION));
18166 }
18167
18168 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
18169                 (tng_trajectory_t tng_data,
18170                  const int64_t i)
18171 {
18172     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18173     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18174
18175     return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
18176                                                       TNG_TRAJ_FORCES,
18177                                                       "FORCES",
18178                                                       TNG_PARTICLE_BLOCK_DATA,
18179                                                       TNG_GZIP_COMPRESSION));
18180 }
18181
18182 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
18183                 (tng_trajectory_t tng_data,
18184                  const int64_t i)
18185 {
18186     fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
18187            "See documentation. %s: %d", __FILE__, __LINE__);
18188     return(tng_util_force_write_interval_set(tng_data, i));
18189 }
18190
18191 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
18192                 (tng_trajectory_t tng_data,
18193                  const int64_t i)
18194 {
18195     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18196     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18197
18198     return(tng_util_generic_write_interval_set(tng_data, i, 9,
18199                                                TNG_TRAJ_BOX_SHAPE,
18200                                                "BOX SHAPE",
18201                                                TNG_NON_PARTICLE_BLOCK_DATA,
18202                                                TNG_GZIP_COMPRESSION));
18203 }
18204
18205 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
18206                 (tng_trajectory_t tng_data,
18207                  const int64_t i)
18208 {
18209     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18210     TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
18211
18212     return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
18213                                                       TNG_TRAJ_BOX_SHAPE,
18214                                                       "BOX SHAPE",
18215                                                       TNG_NON_PARTICLE_BLOCK_DATA,
18216                                                       TNG_GZIP_COMPRESSION));
18217 }
18218
18219 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
18220                 (tng_trajectory_t tng_data,
18221                  const int64_t i)
18222 {
18223     fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
18224            "See documentation. %s: %d", __FILE__, __LINE__);
18225     return(tng_util_box_shape_write_interval_set(tng_data, i));
18226 }
18227
18228 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
18229                 (tng_trajectory_t tng_data,
18230                  const int64_t frame_nr,
18231                  const float *values,
18232                  const int64_t n_values_per_frame,
18233                  const int64_t block_id,
18234                  const char *block_name,
18235                  const char particle_dependency,
18236                  const char compression)
18237 {
18238     tng_trajectory_frame_set_t frame_set;
18239     tng_particle_data_t p_data;
18240     tng_non_particle_data_t np_data;
18241     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18242     int64_t last_frame;
18243     int is_first_frame_flag = 0;
18244     char block_type_flag;
18245     tng_function_status stat;
18246
18247     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18248     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18249     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18250
18251     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18252     {
18253         tng_num_particles_get(tng_data, &n_particles);
18254         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18255     }
18256
18257     if(values == 0)
18258     {
18259         return(TNG_FAILURE);
18260     }
18261
18262     frame_set = &tng_data->current_trajectory_frame_set;
18263
18264     if(frame_nr < 0)
18265     {
18266         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18267         n_frames = stride_length = 1;
18268     }
18269     else
18270     {
18271         block_type_flag = TNG_TRAJECTORY_BLOCK;
18272
18273         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18274         {
18275             stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
18276             if(stat != TNG_SUCCESS)
18277             {
18278                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18279                     __LINE__);
18280                 return(stat);
18281             }
18282         }
18283         last_frame = frame_set->first_frame +
18284                      frame_set->n_frames - 1;
18285         if(frame_nr > last_frame)
18286         {
18287             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18288             if(stat != TNG_SUCCESS)
18289             {
18290                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18291                     __LINE__);
18292                 return(stat);
18293             }
18294             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18295             {
18296                 last_frame = frame_nr - 1;
18297             }
18298             stat = tng_frame_set_new(tng_data, last_frame + 1,
18299                                      tng_data->frame_set_n_frames);
18300             if(stat != TNG_SUCCESS)
18301             {
18302                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18303                     __LINE__);
18304                 return(stat);
18305             }
18306         }
18307         if(frame_set->n_unwritten_frames == 0)
18308         {
18309             is_first_frame_flag = 1;
18310         }
18311         frame_set->n_unwritten_frames = frame_nr -
18312                                         frame_set->first_frame + 1;
18313
18314         n_frames = frame_set->n_frames;
18315     }
18316
18317     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18318     {
18319         if(tng_particle_data_find(tng_data, block_id, &p_data)
18320         != TNG_SUCCESS)
18321         {
18322             stat = tng_particle_data_block_add(tng_data, block_id,
18323                                                block_name,
18324                                                TNG_FLOAT_DATA,
18325                                                block_type_flag,
18326                                                n_frames, n_values_per_frame,
18327                                                stride_length,
18328                                                0, n_particles,
18329                                                compression, 0);
18330             if(stat != TNG_SUCCESS)
18331             {
18332                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18333                        __FILE__, __LINE__);
18334                 return(stat);
18335             }
18336             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18337             {
18338                 p_data = &frame_set->tr_particle_data[frame_set->
18339                                                     n_particle_data_blocks - 1];
18340             }
18341             else
18342             {
18343                 p_data = &tng_data->non_tr_particle_data[tng_data->
18344                                                     n_particle_data_blocks - 1];
18345             }
18346             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18347                                                   stride_length, n_particles,
18348                                                   n_values_per_frame);
18349             if(stat != TNG_SUCCESS)
18350             {
18351                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18352                        __FILE__, __LINE__);
18353                 return(stat);
18354             }
18355         }
18356
18357         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18358         {
18359             stride_length = p_data->stride_length;
18360
18361             if(is_first_frame_flag || p_data->first_frame_with_data < frame_set->first_frame)
18362             {
18363                 p_data->first_frame_with_data = frame_nr;
18364                 frame_pos = 0;
18365             }
18366             else
18367             {
18368                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18369             }
18370
18371             memcpy((char *)p_data->values + sizeof(float) * frame_pos * n_particles *
18372                    n_values_per_frame, values, sizeof(float) *
18373                    n_particles * n_values_per_frame);
18374         }
18375         else
18376         {
18377             memcpy(p_data->values, values, sizeof(float) * n_particles *
18378                    n_values_per_frame);
18379         }
18380     }
18381     else
18382     {
18383         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18384         {
18385             stat = tng_data_block_add(tng_data, block_id, block_name,
18386                                       TNG_FLOAT_DATA, block_type_flag,
18387                                       n_frames, n_values_per_frame,
18388                                       stride_length, compression, 0);
18389             if(stat != TNG_SUCCESS)
18390             {
18391                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18392                        __FILE__, __LINE__);
18393                 return(stat);
18394             }
18395             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18396             {
18397                 np_data = &frame_set->tr_data[frame_set->
18398                                               n_data_blocks - 1];
18399             }
18400             else
18401             {
18402                 np_data = &tng_data->non_tr_data[tng_data->
18403                                                  n_data_blocks - 1];
18404             }
18405             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18406                                          stride_length, n_values_per_frame);
18407             if(stat != TNG_SUCCESS)
18408             {
18409                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18410                        __FILE__, __LINE__);
18411                 return(stat);
18412             }
18413         }
18414
18415         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18416         {
18417             stride_length = np_data->stride_length;
18418
18419             if(is_first_frame_flag || np_data->first_frame_with_data < frame_set->first_frame)
18420             {
18421                 np_data->first_frame_with_data = frame_nr;
18422                 frame_pos = 0;
18423             }
18424             else
18425             {
18426                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18427             }
18428
18429             memcpy((char *)np_data->values + sizeof(float) * frame_pos *
18430                    n_values_per_frame, values, sizeof(float) *
18431                    n_values_per_frame);
18432         }
18433         else
18434         {
18435             memcpy(np_data->values, values, sizeof(float) * n_values_per_frame);
18436         }
18437     }
18438
18439     return(TNG_SUCCESS);
18440 }
18441
18442 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
18443                 (tng_trajectory_t tng_data,
18444                  const int64_t frame_nr,
18445                  const double *values,
18446                  const int64_t n_values_per_frame,
18447                  const int64_t block_id,
18448                  const char *block_name,
18449                  const char particle_dependency,
18450                  const char compression)
18451 {
18452     tng_trajectory_frame_set_t frame_set;
18453     tng_particle_data_t p_data;
18454     tng_non_particle_data_t np_data;
18455     int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
18456     int64_t last_frame;
18457     int is_first_frame_flag = 0;
18458     char block_type_flag;
18459     tng_function_status stat;
18460
18461     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18462     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18463     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18464
18465     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18466     {
18467         tng_num_particles_get(tng_data, &n_particles);
18468         TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
18469     }
18470
18471     if(values == 0)
18472     {
18473         return(TNG_FAILURE);
18474     }
18475
18476     frame_set = &tng_data->current_trajectory_frame_set;
18477
18478     if(frame_nr < 0)
18479     {
18480         block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
18481         n_frames = stride_length = 1;
18482     }
18483     else
18484     {
18485         block_type_flag = TNG_TRAJECTORY_BLOCK;
18486
18487         n_frames = tng_data->frame_set_n_frames;
18488
18489         if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
18490         {
18491             stat = tng_frame_set_new(tng_data, 0, n_frames);
18492             if(stat != TNG_SUCCESS)
18493             {
18494                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18495                     __LINE__);
18496                 return(stat);
18497             }
18498         }
18499         else
18500         {
18501             n_frames = frame_set->n_frames;
18502         }
18503         last_frame = frame_set->first_frame +
18504                      frame_set->n_frames - 1;
18505         if(frame_nr > last_frame)
18506         {
18507             stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
18508             if(stat != TNG_SUCCESS)
18509             {
18510                 fprintf(stderr, "TNG library: Cannot write frame set.  %s: %d\n", __FILE__,
18511                     __LINE__);
18512                 return(stat);
18513             }
18514             if(last_frame + tng_data->frame_set_n_frames < frame_nr)
18515             {
18516                 last_frame = frame_nr - 1;
18517             }
18518             stat = tng_frame_set_new(tng_data, last_frame + 1, n_frames);
18519             if(stat != TNG_SUCCESS)
18520             {
18521                 fprintf(stderr, "TNG library: Cannot create frame set.  %s: %d\n", __FILE__,
18522                     __LINE__);
18523                 return(stat);
18524             }
18525         }
18526         if(frame_set->n_unwritten_frames == 0)
18527         {
18528             is_first_frame_flag = 1;
18529         }
18530         frame_set->n_unwritten_frames = frame_nr -
18531                                         frame_set->first_frame + 1;
18532     }
18533
18534     if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
18535     {
18536         if(tng_particle_data_find(tng_data, block_id, &p_data)
18537         != TNG_SUCCESS)
18538         {
18539             stat = tng_particle_data_block_add(tng_data, block_id,
18540                                             block_name,
18541                                             TNG_DOUBLE_DATA,
18542                                             block_type_flag,
18543                                             n_frames, n_values_per_frame,
18544                                             stride_length,
18545                                             0, n_particles,
18546                                             compression, 0);
18547             if(stat != TNG_SUCCESS)
18548             {
18549                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18550                        __FILE__, __LINE__);
18551                 return(stat);
18552             }
18553             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18554             {
18555                 p_data = &frame_set->tr_particle_data[frame_set->
18556                                                     n_particle_data_blocks - 1];
18557             }
18558             else
18559             {
18560                 p_data = &tng_data->non_tr_particle_data[tng_data->
18561                                                     n_particle_data_blocks - 1];
18562             }
18563             stat = tng_allocate_particle_data_mem(tng_data, p_data, n_frames,
18564                                                   stride_length, n_particles,
18565                                                   n_values_per_frame);
18566             if(stat != TNG_SUCCESS)
18567             {
18568                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18569                        __FILE__, __LINE__);
18570                 return(stat);
18571             }
18572         }
18573
18574         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18575         {
18576             stride_length = p_data->stride_length;
18577
18578             if(is_first_frame_flag)
18579             {
18580                 p_data->first_frame_with_data = frame_nr;
18581                 frame_pos = 0;
18582             }
18583             else
18584             {
18585                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18586             }
18587
18588             memcpy((char *)p_data->values + sizeof(double) * frame_pos * n_particles *
18589                    n_values_per_frame, values, sizeof(double) *
18590                    n_particles * n_values_per_frame);
18591         }
18592         else
18593         {
18594             memcpy(p_data->values, values, sizeof(double) * n_particles *
18595                    n_values_per_frame);
18596         }
18597     }
18598     else
18599     {
18600         if(tng_data_find(tng_data, block_id, &np_data) != TNG_SUCCESS)
18601         {
18602             stat = tng_data_block_add(tng_data, block_id, block_name,
18603                                       TNG_DOUBLE_DATA, block_type_flag,
18604                                       n_frames, n_values_per_frame,
18605                                       stride_length, compression, 0);
18606             if(stat != TNG_SUCCESS)
18607             {
18608                 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
18609                        __FILE__, __LINE__);
18610                 return(stat);
18611             }
18612             if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18613             {
18614                 np_data = &frame_set->tr_data[frame_set->
18615                                               n_data_blocks - 1];
18616             }
18617             else
18618             {
18619                 np_data = &tng_data->non_tr_data[tng_data->
18620                                                  n_data_blocks - 1];
18621             }
18622             stat = tng_allocate_data_mem(tng_data, np_data, n_frames,
18623                                          stride_length, n_values_per_frame);
18624             if(stat != TNG_SUCCESS)
18625             {
18626                 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
18627                        __FILE__, __LINE__);
18628                 return(stat);
18629             }
18630         }
18631
18632         if(block_type_flag == TNG_TRAJECTORY_BLOCK)
18633         {
18634             stride_length = np_data->stride_length;
18635
18636             if(is_first_frame_flag)
18637             {
18638                 np_data->first_frame_with_data = frame_nr;
18639                 frame_pos = 0;
18640             }
18641             else
18642             {
18643                 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
18644             }
18645
18646             memcpy((char *)np_data->values + sizeof(double) * frame_pos *
18647                    n_values_per_frame, values, sizeof(double) *
18648                    n_values_per_frame);
18649         }
18650         else
18651         {
18652             memcpy(np_data->values, values, sizeof(double) * n_values_per_frame);
18653         }
18654     }
18655
18656     return(TNG_SUCCESS);
18657 }
18658
18659 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
18660                 (tng_trajectory_t tng_data,
18661                  const int64_t frame_nr,
18662                  const float *positions)
18663 {
18664     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18665     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18666     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18667
18668     return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
18669                                   TNG_TRAJ_POSITIONS, "POSITIONS",
18670                                   TNG_PARTICLE_BLOCK_DATA,
18671                                   TNG_TNG_COMPRESSION));
18672 }
18673
18674 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
18675                 (tng_trajectory_t tng_data,
18676                  const int64_t frame_nr,
18677                  const double *positions)
18678 {
18679     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18680     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18681     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18682
18683     return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
18684                                          TNG_TRAJ_POSITIONS, "POSITIONS",
18685                                          TNG_PARTICLE_BLOCK_DATA,
18686                                          TNG_TNG_COMPRESSION));
18687 }
18688
18689 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
18690                 (tng_trajectory_t tng_data,
18691                  const int64_t frame_nr,
18692                  const float *velocities)
18693 {
18694     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18695     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18696     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18697
18698     return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
18699                                   TNG_TRAJ_VELOCITIES, "VELOCITIES",
18700                                   TNG_PARTICLE_BLOCK_DATA,
18701                                   TNG_TNG_COMPRESSION));
18702 }
18703
18704 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
18705                 (tng_trajectory_t tng_data,
18706                  const int64_t frame_nr,
18707                  const double *velocities)
18708 {
18709     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18710     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18711     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18712
18713     return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
18714                                          TNG_TRAJ_VELOCITIES, "VELOCITIES",
18715                                          TNG_PARTICLE_BLOCK_DATA,
18716                                          TNG_TNG_COMPRESSION));
18717 }
18718
18719 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
18720                 (tng_trajectory_t tng_data,
18721                  const int64_t frame_nr,
18722                  const float *forces)
18723 {
18724     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18725     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18726     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18727
18728     return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
18729                                   TNG_TRAJ_FORCES, "FORCES",
18730                                   TNG_PARTICLE_BLOCK_DATA,
18731                                   TNG_GZIP_COMPRESSION));
18732 }
18733
18734 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
18735                 (tng_trajectory_t tng_data,
18736                  const int64_t frame_nr,
18737                  const double *forces)
18738 {
18739     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18740     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18741     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18742
18743     return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
18744                                          TNG_TRAJ_FORCES, "FORCES",
18745                                          TNG_PARTICLE_BLOCK_DATA,
18746                                          TNG_GZIP_COMPRESSION));
18747 }
18748
18749 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
18750                 (tng_trajectory_t tng_data,
18751                  const int64_t frame_nr,
18752                  const float *box_shape)
18753 {
18754     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18755     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18756     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18757
18758     return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
18759                                   TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18760                                   TNG_NON_PARTICLE_BLOCK_DATA,
18761                                   TNG_GZIP_COMPRESSION));
18762 }
18763
18764 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
18765                 (tng_trajectory_t tng_data,
18766                  const int64_t frame_nr,
18767                  const double *box_shape)
18768 {
18769     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18770     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18771     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18772
18773     return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
18774                                          TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
18775                                          TNG_NON_PARTICLE_BLOCK_DATA,
18776                                          TNG_GZIP_COMPRESSION));
18777 }
18778
18779 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
18780                 (tng_trajectory_t tng_data,
18781                  const int64_t frame_nr,
18782                  const double time,
18783                  const float *values,
18784                  const int64_t n_values_per_frame,
18785                  const int64_t block_id,
18786                  const char *block_name,
18787                  const char particle_dependency,
18788                  const char compression)
18789 {
18790     tng_trajectory_frame_set_t frame_set;
18791     tng_function_status stat;
18792
18793     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18794     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18795     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18796     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18797
18798     stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
18799                                   block_id, block_name,
18800                                   particle_dependency,
18801                                   compression);
18802
18803     if(stat != TNG_SUCCESS)
18804     {
18805         return(stat);
18806     }
18807
18808     frame_set = &tng_data->current_trajectory_frame_set;
18809
18810     /* first_frame_time is -1 when it is not yet set. */
18811     if(frame_set->first_frame_time < -0.1)
18812     {
18813         if(frame_nr > frame_set->first_frame)
18814         {
18815             stat = tng_frame_set_first_frame_time_set(tng_data,
18816                                                       time -
18817                                                       (frame_nr -
18818                                                        frame_set->first_frame) *
18819                                                       tng_data->time_per_frame);
18820         }
18821         else
18822         {
18823             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18824         }
18825     }
18826     return(stat);
18827 }
18828
18829 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
18830                 (tng_trajectory_t tng_data,
18831                  const int64_t frame_nr,
18832                  const double time,
18833                  const double *values,
18834                  const int64_t n_values_per_frame,
18835                  const int64_t block_id,
18836                  const char *block_name,
18837                  const char particle_dependency,
18838                  const char compression)
18839 {
18840     tng_trajectory_frame_set_t frame_set;
18841     tng_function_status stat;
18842
18843     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18844     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18845     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18846     TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
18847
18848     stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
18849                                          block_id, block_name,
18850                                          particle_dependency,
18851                                          compression);
18852
18853     if(stat != TNG_SUCCESS)
18854     {
18855         return(stat);
18856     }
18857
18858     frame_set = &tng_data->current_trajectory_frame_set;
18859
18860     /* first_frame_time is -1 when it is not yet set. */
18861     if(frame_set->first_frame_time < -0.1)
18862     {
18863         if(frame_nr > frame_set->first_frame)
18864         {
18865             stat = tng_frame_set_first_frame_time_set(tng_data,
18866                                                       time -
18867                                                       (frame_nr -
18868                                                        frame_set->first_frame) *
18869                                                       tng_data->time_per_frame);
18870         }
18871         else
18872         {
18873             stat = tng_frame_set_first_frame_time_set(tng_data, time);
18874         }
18875     }
18876     return(stat);
18877 }
18878
18879 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
18880                 (tng_trajectory_t tng_data,
18881                  const int64_t frame_nr,
18882                  const double time,
18883                  const float *positions)
18884 {
18885     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18886     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18887     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18888     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18889
18890     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
18891                                             3, TNG_TRAJ_POSITIONS, "POSITIONS",
18892                                             TNG_PARTICLE_BLOCK_DATA,
18893                                             TNG_TNG_COMPRESSION));
18894 }
18895
18896 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
18897                 (tng_trajectory_t tng_data,
18898                  const int64_t frame_nr,
18899                  const double time,
18900                  const double *positions)
18901 {
18902     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18903     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18904     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18905     TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
18906
18907     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18908                                                    positions, 3,
18909                                                    TNG_TRAJ_POSITIONS,
18910                                                    "POSITIONS",
18911                                                    TNG_PARTICLE_BLOCK_DATA,
18912                                                    TNG_TNG_COMPRESSION));
18913 }
18914
18915 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
18916                 (tng_trajectory_t tng_data,
18917                  const int64_t frame_nr,
18918                  const double time,
18919                  const float *velocities)
18920 {
18921     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18922     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18923     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18924     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18925
18926     return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
18927                                             velocities, 3,
18928                                             TNG_TRAJ_VELOCITIES,
18929                                             "VELOCITIES",
18930                                             TNG_PARTICLE_BLOCK_DATA,
18931                                             TNG_TNG_COMPRESSION));
18932 }
18933
18934 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
18935                 (tng_trajectory_t tng_data,
18936                  const int64_t frame_nr,
18937                  const double time,
18938                  const double *velocities)
18939 {
18940     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18941     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18942     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18943     TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
18944
18945     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18946                                                    velocities, 3,
18947                                                    TNG_TRAJ_VELOCITIES,
18948                                                    "VELOCITIES",
18949                                                    TNG_PARTICLE_BLOCK_DATA,
18950                                                    TNG_TNG_COMPRESSION));
18951 }
18952
18953 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
18954                 (tng_trajectory_t tng_data,
18955                  const int64_t frame_nr,
18956                  const double time,
18957                  const float *forces)
18958 {
18959     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18960     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18961     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18962     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18963
18964     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
18965                                             3, TNG_TRAJ_FORCES, "FORCES",
18966                                             TNG_PARTICLE_BLOCK_DATA,
18967                                             TNG_GZIP_COMPRESSION));
18968 }
18969
18970 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
18971                 (tng_trajectory_t tng_data,
18972                  const int64_t frame_nr,
18973                  const double time,
18974                  const double *forces)
18975 {
18976     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18977     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18978     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18979     TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
18980
18981     return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
18982                                                    forces, 3,
18983                                                    TNG_TRAJ_FORCES, "FORCES",
18984                                                    TNG_PARTICLE_BLOCK_DATA,
18985                                                    TNG_GZIP_COMPRESSION));
18986 }
18987
18988 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
18989                 (tng_trajectory_t tng_data,
18990                  const int64_t frame_nr,
18991                  const double time,
18992                  const float *box_shape)
18993 {
18994     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
18995     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
18996     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
18997     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
18998
18999     return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
19000                                             9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
19001                                             TNG_NON_PARTICLE_BLOCK_DATA,
19002                                             TNG_GZIP_COMPRESSION));
19003 }
19004
19005 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
19006                 (tng_trajectory_t tng_data,
19007                  const int64_t frame_nr,
19008                  const double time,
19009                  const double *box_shape)
19010 {
19011     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19012     TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
19013     TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
19014     TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
19015
19016     return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
19017                                                    time, box_shape, 9,
19018                                                    TNG_TRAJ_BOX_SHAPE,
19019                                                    "BOX SHAPE",
19020                                                    TNG_NON_PARTICLE_BLOCK_DATA,
19021                                                    TNG_GZIP_COMPRESSION));
19022 }
19023
19024 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
19025                 (tng_trajectory_t tng_data,
19026                  const int64_t block_id,
19027                  int64_t *codec_id,
19028                  double *factor)
19029 {
19030     tng_trajectory_frame_set_t frame_set;
19031     tng_particle_data_t p_data = 0;
19032     tng_non_particle_data_t np_data = 0;
19033     tng_function_status stat;
19034     int64_t i;
19035     int block_type = -1;
19036
19037     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19038     TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
19039     TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
19040
19041     frame_set = &tng_data->current_trajectory_frame_set;
19042
19043     stat = tng_particle_data_find(tng_data, block_id, &p_data);
19044     if(stat == TNG_SUCCESS)
19045     {
19046         block_type = TNG_PARTICLE_BLOCK_DATA;
19047     }
19048     else
19049     {
19050         stat = tng_data_find(tng_data, block_id, &np_data);
19051         if(stat == TNG_SUCCESS)
19052         {
19053             block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19054         }
19055         else
19056         {
19057             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19058             if(stat != TNG_SUCCESS)
19059             {
19060                 return(stat);
19061             }
19062             stat = tng_particle_data_find(tng_data, block_id, &p_data);
19063             if(stat == TNG_SUCCESS)
19064             {
19065                 block_type = TNG_PARTICLE_BLOCK_DATA;
19066             }
19067             else
19068             {
19069                 stat = tng_data_find(tng_data, block_id, &np_data);
19070                 if(stat == TNG_SUCCESS)
19071                 {
19072                     block_type = TNG_NON_PARTICLE_BLOCK_DATA;
19073                 }
19074                 else
19075                 {
19076                     return(stat);
19077                 }
19078             }
19079         }
19080     }
19081     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19082     {
19083         if(p_data->last_retrieved_frame < 0)
19084         {
19085             i = p_data->first_frame_with_data;
19086         }
19087         else
19088         {
19089             i = p_data->last_retrieved_frame;
19090         }
19091     }
19092     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19093     {
19094         if(np_data->last_retrieved_frame < 0)
19095         {
19096             i = np_data->first_frame_with_data;
19097         }
19098         else
19099         {
19100             i = np_data->last_retrieved_frame;
19101         }
19102     }
19103     else
19104     {
19105         return(TNG_FAILURE);
19106     }
19107     if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
19108     {
19109         stat = tng_frame_set_of_frame_find(tng_data, i);
19110         if(stat != TNG_SUCCESS)
19111         {
19112             return(stat);
19113         }
19114         stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
19115         if(stat != TNG_SUCCESS)
19116         {
19117             fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19118                 __FILE__, __LINE__);
19119             return(stat);
19120         }
19121     }
19122     if(block_type == TNG_PARTICLE_BLOCK_DATA)
19123     {
19124         *codec_id = p_data->codec_id;
19125         *factor   = p_data->compression_multiplier;
19126     }
19127     else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
19128     {
19129         *codec_id = np_data->codec_id;
19130         *factor   = np_data->compression_multiplier;
19131     }
19132     return(TNG_SUCCESS);
19133 }
19134
19135 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
19136                 (tng_trajectory_t tng_data,
19137                  int64_t current_frame,
19138                  const int64_t n_requested_data_block_ids,
19139                  const int64_t *requested_data_block_ids,
19140                  int64_t *next_frame,
19141                  int64_t *n_data_blocks_in_next_frame,
19142                  int64_t **data_block_ids_in_next_frame)
19143 {
19144     tng_trajectory_frame_set_t frame_set;
19145     tng_function_status stat;
19146     tng_particle_data_t p_data;
19147     tng_non_particle_data_t np_data;
19148     tng_gen_block_t block;
19149     int64_t i, j, block_id, *temp;
19150     int64_t data_frame, frame_diff, min_diff;
19151     int64_t size, frame_set_file_pos, file_pos;
19152     int found, read_all = 0;
19153
19154     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19155     TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
19156     TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
19157     TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19158
19159     if(n_requested_data_block_ids)
19160     {
19161         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.");
19162         size = sizeof(int64_t) * n_requested_data_block_ids;
19163         temp = realloc(*data_block_ids_in_next_frame, size);
19164         if(!temp)
19165         {
19166             fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
19167                     sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19168                     __FILE__, __LINE__);
19169             free(*data_block_ids_in_next_frame);
19170             *data_block_ids_in_next_frame = 0;
19171             return(TNG_CRITICAL);
19172         }
19173         *data_block_ids_in_next_frame = temp;
19174     }
19175
19176     frame_set = &tng_data->current_trajectory_frame_set;
19177
19178     current_frame += 1;
19179
19180     if(current_frame < frame_set->first_frame ||
19181        current_frame >= frame_set->first_frame + frame_set->n_frames)
19182     {
19183         frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
19184         stat = tng_frame_set_of_frame_find(tng_data, current_frame);
19185         if(stat != TNG_SUCCESS)
19186         {
19187             /* If the frame set search found the frame set after the starting
19188              * frame set there is a gap in the frame sets. So, even if the frame
19189              * was not found the next frame with data is still in the found
19190              * frame set. */
19191             if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
19192                frame_set_file_pos)
19193             {
19194                 return(stat);
19195             }
19196             current_frame = frame_set->first_frame;
19197         }
19198     }
19199
19200     /* Check for data blocks only if they have not already been found. */
19201     if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
19202     {
19203         file_pos = ftello(tng_data->input_file);
19204         if(file_pos < tng_data->input_file_len)
19205         {
19206             tng_block_init(&block);
19207             stat = tng_block_header_read(tng_data, block);
19208             while(file_pos < tng_data->input_file_len &&
19209                 stat != TNG_CRITICAL &&
19210                 block->id != TNG_TRAJECTORY_FRAME_SET &&
19211                 block->id != -1)
19212             {
19213                 stat = tng_block_read_next(tng_data, block,
19214                                         TNG_USE_HASH);
19215                 if(stat != TNG_CRITICAL)
19216                 {
19217                     file_pos = ftello(tng_data->input_file);
19218                     if(file_pos < tng_data->input_file_len)
19219                     {
19220                         stat = tng_block_header_read(tng_data, block);
19221                     }
19222                 }
19223             }
19224             tng_block_destroy(&block);
19225             if(stat == TNG_CRITICAL)
19226             {
19227                 fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
19228                         file_pos, __FILE__, __LINE__);
19229                 return(stat);
19230             }
19231         }
19232         read_all = 1;
19233     }
19234
19235     min_diff = -1;
19236
19237     *n_data_blocks_in_next_frame = 0;
19238
19239     for(i = 0; i < frame_set->n_particle_data_blocks; i++)
19240     {
19241         p_data = &frame_set->tr_particle_data[i];
19242         block_id = p_data->block_id;
19243
19244         if(n_requested_data_block_ids > 0)
19245         {
19246             found = 0;
19247             for(j = 0; j < n_requested_data_block_ids; j++)
19248             {
19249                 if(block_id == requested_data_block_ids[j])
19250                 {
19251                     found = 1;
19252                     break;
19253                 }
19254             }
19255             if(!found)
19256             {
19257                 continue;
19258             }
19259         }
19260
19261         if(!read_all && (p_data->last_retrieved_frame < frame_set->first_frame ||
19262            p_data->last_retrieved_frame >=
19263            frame_set->first_frame + frame_set->n_frames))
19264         {
19265             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19266                                                                       TNG_USE_HASH, block_id);
19267             if(stat == TNG_CRITICAL)
19268             {
19269                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19270                     __FILE__, __LINE__);
19271                 return(stat);
19272             }
19273             if(stat == TNG_FAILURE)
19274             {
19275                 continue;
19276             }
19277         }
19278         if(frame_set->first_frame != current_frame &&
19279            p_data->last_retrieved_frame >= 0)
19280         {
19281             data_frame = p_data->last_retrieved_frame + p_data->stride_length;
19282         }
19283         else
19284         {
19285             data_frame = p_data->first_frame_with_data;
19286         }
19287         frame_diff = data_frame - current_frame;
19288         if(frame_diff < 0)
19289         {
19290             continue;
19291         }
19292         if(min_diff == -1 || frame_diff <= min_diff)
19293         {
19294             if(frame_diff < min_diff)
19295             {
19296                 *n_data_blocks_in_next_frame = 1;
19297             }
19298             else
19299             {
19300                 *n_data_blocks_in_next_frame += 1;
19301             }
19302             if(n_requested_data_block_ids <= 0)
19303             {
19304                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19305                 temp = realloc(*data_block_ids_in_next_frame, size);
19306                 if(!temp)
19307                 {
19308                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
19309                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19310                            __FILE__, __LINE__);
19311                     free(*data_block_ids_in_next_frame);
19312                     *data_block_ids_in_next_frame = 0;
19313                     return(TNG_CRITICAL);
19314                 }
19315                 *data_block_ids_in_next_frame = temp;
19316             }
19317             else
19318             {
19319                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19320             }
19321             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19322
19323             min_diff = frame_diff;
19324         }
19325     }
19326     for(i = 0; i < frame_set->n_data_blocks; i++)
19327     {
19328         np_data = &frame_set->tr_data[i];
19329         block_id = np_data->block_id;
19330
19331         if(n_requested_data_block_ids > 0)
19332         {
19333             found = 0;
19334             for(j = 0; j < n_requested_data_block_ids; j++)
19335             {
19336                 if(block_id == requested_data_block_ids[j])
19337                 {
19338                     found = 1;
19339                     break;
19340                 }
19341             }
19342             if(!found)
19343             {
19344                 continue;
19345             }
19346         }
19347
19348         if(!read_all && (np_data->last_retrieved_frame < frame_set->first_frame ||
19349            np_data->last_retrieved_frame >=
19350            frame_set->first_frame + frame_set->n_frames))
19351         {
19352             stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
19353                                                                       TNG_USE_HASH, block_id);
19354             if(stat == TNG_CRITICAL)
19355             {
19356                 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
19357                     __FILE__, __LINE__);
19358                 return(stat);
19359             }
19360             if(stat == TNG_FAILURE)
19361             {
19362                 continue;
19363             }
19364         }
19365         if(frame_set->first_frame != current_frame &&
19366            np_data->last_retrieved_frame >= 0)
19367         {
19368             data_frame = np_data->last_retrieved_frame + np_data->stride_length;
19369         }
19370         else
19371         {
19372             data_frame = np_data->first_frame_with_data;
19373         }
19374         frame_diff = data_frame - current_frame;
19375         if(frame_diff < 0)
19376         {
19377             continue;
19378         }
19379         if(min_diff == -1 || frame_diff <= min_diff)
19380         {
19381             if(frame_diff < min_diff)
19382             {
19383                 *n_data_blocks_in_next_frame = 1;
19384             }
19385             else
19386             {
19387                 *n_data_blocks_in_next_frame += 1;
19388             }
19389             if(n_requested_data_block_ids <= 0)
19390             {
19391                 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
19392                 temp = realloc(*data_block_ids_in_next_frame, size);
19393                 if(!temp)
19394                 {
19395                     fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
19396                            sizeof(int64_t) * (*n_data_blocks_in_next_frame),
19397                            __FILE__, __LINE__);
19398                     free(*data_block_ids_in_next_frame);
19399                     *data_block_ids_in_next_frame = 0;
19400                     return(TNG_CRITICAL);
19401                 }
19402                 *data_block_ids_in_next_frame = temp;
19403             }
19404             else
19405             {
19406                 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
19407             }
19408             (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
19409
19410             min_diff = frame_diff;
19411         }
19412     }
19413     if(min_diff < 0)
19414     {
19415         return(TNG_FAILURE);
19416     }
19417     *next_frame = current_frame + min_diff;
19418
19419     return(TNG_SUCCESS);
19420 }
19421
19422 /*
19423 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
19424                 (tng_trajectory_t tng_data,
19425                  int64_t *n_data_blocks,
19426                  int64_t **data_block_ids,
19427                  char ***data_block_names,
19428                  int64_t **stride_lengths,
19429                  int64_t **n_values_per_frame,
19430                  char **block_types,
19431                  char **dependencies,
19432                  char **compressions)
19433 {
19434     tng_gen_block_t block;
19435     int64_t orig_file_pos, file_pos;
19436
19437     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19438     TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
19439     TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
19440     TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
19441     TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
19442
19443     orig_file_pos = ftello(tng_data->input_file);
19444
19445     if(!tng_data->input_file_len)
19446     {
19447         fseeko(tng_data->input_file, 0, SEEK_END);
19448         tng_data->input_file_len = ftello(tng_data->input_file);
19449     }
19450
19451     fseeko(tng_data->input_file, 0, SEEK_SET);
19452     file_pos = 0;
19453
19454     *n_data_blocks = 0;
19455
19456     tng_block_init(&block);
19457
19458     while(file_pos < tng_data->input_file_len &&
19459           tng_block_header_read(tng_data, block) != TNG_CRITICAL)
19460     {
19461         if(block->id > TNG_TRAJECTORY_FRAME_SET)
19462         {
19463
19464         }
19465         file_pos += (block->block_contents_size + block->header_contents_size);
19466         fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
19467     }
19468
19469     fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
19470
19471     return(TNG_SUCCESS);
19472 }
19473 */
19474 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
19475                 (tng_trajectory_t tng_data,
19476                  const int64_t prev_frame)
19477 {
19478     tng_function_status stat;
19479     FILE *temp = tng_data->input_file;
19480
19481     TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
19482     TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
19483
19484     tng_data->input_file = tng_data->output_file;
19485
19486     stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
19487     if(stat != TNG_SUCCESS)
19488     {
19489         return(stat);
19490     }
19491
19492     tng_data->current_trajectory_frame_set_output_file_pos =
19493     tng_data->current_trajectory_frame_set_input_file_pos;
19494
19495     tng_data->input_file = temp;
19496
19497     return(TNG_SUCCESS);
19498 }