5 * Created by Alyssa Milburn on Mon Jan 16 2006.
6 * Copyright (c) 2006 Alyssa Milburn. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
21 #include "exceptions.h"
22 #include "endianlove.h"
25 prayFile::prayFile(fs::path filepath
) {
27 file
.open(path
.native_directory_string().c_str(), std::ios::binary
);
29 throw creaturesException(std::string("couldn't open PRAY file \"") + path
.native_directory_string() + "\"");
33 if (strncmp(majic
, "PRAY", 4) != 0)
34 throw creaturesException(std::string("bad magic of PRAY file \"") + path
.native_directory_string() + "\"");
37 // TODO: catch exceptions, and free all blocks before passing it up the stack
38 prayBlock
*b
= new prayBlock(this);
41 file
.peek(); // make sure eof() gets set
45 prayFile::~prayFile() {
46 for (std::vector
<prayBlock
*>::iterator i
= blocks
.begin(); i
!= blocks
.end(); i
++) {
51 prayBlock::prayBlock(prayFile
*p
) {
52 std::istream
&file
= p
->getStream();
54 char stringid
[5]; stringid
[4] = 0;
55 file
.read(stringid
, 4);
58 char nameid
[129]; nameid
[128] = 0;
59 file
.read(nameid
, 128);
62 file
.read((char *)&compressedsize
, 4); compressedsize
= swapEndianLong(compressedsize
);
63 file
.read((char *)&size
, 4); size
= swapEndianLong(size
);
65 file
.read((char *)&flags
, 4); flags
= swapEndianLong(flags
);
66 compressed
= ((flags
& 1) == 1);
67 if (!compressed
&& size
!= compressedsize
)
68 throw creaturesException("Size doesn't match compressed size for uncompressed block.");
70 // Skip the data for this block.
71 offset
= file
.tellg();
72 file
.seekg(compressedsize
, std::ios::cur
);
80 prayBlock::~prayBlock() {
85 void prayBlock::load() {
86 std::istream
&file
= parent
->getStream();
91 throw creaturesException("Failed to seek to block offset.");
93 buffer
= new unsigned char[size
];
95 // TODO: check pray_uncompress_sanity_check
96 char *src
= new char[compressedsize
];
97 file
.read(src
, compressedsize
);
100 throw creaturesException("Failed to read all of compressed block.");
103 int r
= uncompress((Bytef
*)buffer
, (uLongf
*)&usize
, (Bytef
*)src
, compressedsize
);
105 delete[] buffer
; delete[] src
;
106 std::string o
= "Unknown error";
108 case Z_MEM_ERROR
: o
= "Out of memory"; break;
109 case Z_BUF_ERROR
: o
= "Out of buffer space"; break;
110 case Z_DATA_ERROR
: o
= "Corrupt data"; break;
112 o
= o
+ " while decompressing PRAY block \"" + name
+ "\"";
113 throw creaturesException(o
);
118 throw creaturesException("Decompressed data is not the correct size.");
121 file
.read((char *)buffer
, size
);
124 throw creaturesException("Failed to read all of uncompressed block.");
130 std::string
tagStringRead(unsigned char *&ptr
) {
131 unsigned int len
= *(unsigned int *)ptr
;
132 len
= swapEndianLong(len
);
135 unsigned char *data
= ptr
;
138 return std::string((char *)data
, len
);
141 void prayBlock::parseTags() {
142 if (tagsloaded
) return;
149 unsigned char *ptr
= buffer
;
151 unsigned int nointvalues
= swapEndianLong(*(unsigned int *)ptr
); ptr
+= 4;
153 for (unsigned int i
= 0; i
< nointvalues
; i
++) {
154 std::string n
= tagStringRead(ptr
);
155 unsigned int v
= swapEndianLong(*(unsigned int *)ptr
); ptr
+= 4;
157 if (integerValues
.find(n
) != integerValues
.end())
158 throw creaturesException(std::string("Duplicate tag \"") + n
+ "\"");
159 integerValues
[n
] = v
;
162 unsigned int nostrvalues
= swapEndianLong(*(unsigned int *)ptr
); ptr
+= 4;
164 for (unsigned int i
= 0; i
< nostrvalues
; i
++) {
165 std::string n
= tagStringRead(ptr
);
166 std::string v
= tagStringRead(ptr
);
167 if (stringValues
.find(n
) != stringValues
.end()) // TODO: check integers too?
168 throw creaturesException(std::string("Duplicate tag \"") + n
+ "\"");