1 #include "SWFGlyphList.h"
2 #include <SWFShapeItem.h>
3 #include "gSWF.h"
4 #include <cstring>
5 
6 namespace SWF {
7 
GlyphList()8 	GlyphList::GlyphList() {
9 		nGlyphs = 0;
10 		glyphs = NULL;
11 		map = 0;
12 	}
13 
~GlyphList()14 	GlyphList::~GlyphList() {
15 		delete[] glyphs;
16 		delete[] map;
17 	}
18 
parse(Reader * r,int end,Context * ctx)19 	bool GlyphList::parse(Reader *r, int end, Context *ctx) {
20 		file_offset = r->getPosition();
21 
22 		int nOffsets;
23 		int s=0;
24 
25 		if (ctx->tagVersion>1) {
26 			nGlyphs = ctx->glyphCount;
27 			nOffsets = nGlyphs+1;
28 		} else {
29 			nGlyphs = (r->getWord()/2);
30 			nOffsets = nGlyphs;
31 			s=1;
32 		}
33 
34 		if (ctx->debugTrace) {
35 			fprintf(stderr, "GL nGlyphs: %i, glyphs %s, map %s\n", (int)nGlyphs, ctx->wideGlyphOffsets?"wide":"narrow", ctx->wideMap?"wide":"narrow");
36 		}
37 
38 		int offset[nGlyphs+1];
39 		memset(offset, 0, sizeof(int)*nGlyphs+1);
40 		if (ctx->wideGlyphOffsets) {
41 			for (int i=s; i<nOffsets; i++) {
42 				offset[i] = r->getInt();
43 			}
44 		} else {
45 			for (int i=s; i<nOffsets; i++) {
46 				offset[i] = r->getWord();
47 			}
48 		}
49 
50 		if (ctx->tagVersion<=1) {
51 			offset[0] = r->getPosition() - file_offset;
52 			offset[nOffsets] = end-file_offset;
53 		}
54 
55 		if (ctx->debugTrace) {
56 			fprintf(stderr, "Glyphs @%i offset[0]: %i\n", r->getPosition(), offset[0]);
57 		}
58 		glyphs = new GlyphShape[nGlyphs];
59 		for (int i=0; i<nGlyphs; i++) {
60 			if (ctx->debugTrace) {
61 				fprintf(stderr, "PARSE glyph #%i @%i should be %i-%i\n", i, r->getPosition(), file_offset + offset[i], file_offset + offset[i+1]);
62 			}
63 			if (r->getPosition() != file_offset + offset[i]) {
64 				fprintf(stderr,"WARNING: wrong offset at glyph %i, ofs %i but pos %i\n", i, offset[i], r->getPosition()-file_offset);
65 			}
66 			glyphs[i].parse(r, file_offset + offset[i+1], ctx);
67 			r->byteAlign();
68 		}
69 
70 		if (ctx->tagVersion>1) {
71 			if (ctx->debugTrace) {
72 				fprintf(stderr,"- parse GlyphMap" );
73 			}
74 			map = new int[nGlyphs];
75 			if (ctx->wideMap) {
76 				for (int i=0; i<nGlyphs; i++) {
77 					map[i] = r->getWord();
78 				}
79 			} else {
80 				for (int i=0; i<nGlyphs; i++) {
81 					map[i] = r->getByte();
82 				}
83 			}
84 		}
85 
86 		return r->getError() == Reader::ok;
87 	}
88 
dump(int n,Context * ctx)89 	void GlyphList::dump(int n, Context *ctx) {
90 		for (int i=0; i<n; i++) {
91 			printf("  ");
92 		}
93 		printf("GlyphList\n");
94 
95 		for (int i=0; i<nGlyphs; i++) {
96 			glyphs[i].dump(n+1, ctx);
97 		}
98 		printf("\n");
99 	}
100 
calcSize(Context * ctx,int start_at)101 	size_t GlyphList::calcSize(Context *ctx, int start_at) {
102 		int r=start_at;
103 
104 		if (ctx->tagVersion>1) {
105 			r += (ctx->wideGlyphOffsets ? 4 : 2) * (nGlyphs+1) * 8;
106 		} else {
107 			r += (nGlyphs+1) * 16;
108 		}
109 
110 		for (int i=0; i<nGlyphs; i++) {
111 			r += glyphs[i].getSize(ctx, r);
112 			if (r%8 != 0) {
113 				r += 8-(r%8);
114 			}
115 		}
116 
117 		if (ctx->tagVersion>1) {
118 			r += (ctx->wideMap ? 2 : 1) * nGlyphs * 8;
119 		}
120 
121 		r += Item::getHeaderSize(r-start_at);
122 		return r-start_at;
123 	}
124 
write(Writer * w,Context * ctx)125 	void GlyphList::write(Writer *w, Context *ctx) {
126 		Item::writeHeader(w, ctx, 0);
127 		int ofs = 0;
128 
129 		if (ctx->tagVersion>1) {
130 			ofs = ((ctx->wideGlyphOffsets ? 4 : 2) * (nGlyphs+1));
131 		} else {
132 			ofs = (nGlyphs+1)*2;
133 		}
134 
135 		ctx->fillBits = 1;
136 		ctx->lineBits = 1;
137 
138 		ctx->wideGlyphOffsets ? w->putInt(ofs) : w->putWord(ofs);
139 		for (int i=0; i<nGlyphs; i++) {
140 			int p = glyphs[i].getSize(ctx,ofs);
141 			if (p%8 != 0) {
142 				p += 8-(p%8);
143 			}
144 			ofs += (p)/8;
145 			ctx->wideGlyphOffsets ? w->putInt(ofs) : w->putWord(ofs);
146 		}
147 
148 		ofs = w->getPosition();
149 		for (int i=0; i<nGlyphs; i++) {
150 			glyphs[i].write(w, ctx);
151 			w->byteAlign();
152 		}
153 
154 		if (ctx->tagVersion>1) {
155 			for (int i=0; i<nGlyphs; i++) {
156 				ctx->wideMap ? w->putWord(map[i]) : w->putByte(map[i]);
157 			}
158 		}
159 	}
160 
writeXML(xmlNodePtr xml,Context * ctx)161 	void GlyphList::writeXML(xmlNodePtr xml, Context *ctx) {
162 		char tmp[32];
163 
164 		xmlNodePtr node = xml;
165 		for (int i=0; i<nGlyphs; i++) {
166 			xmlNodePtr child = xmlNewChild(node, NULL, (const xmlChar *)"Glyph", NULL);
167 			glyphs[i].writeXML(child, ctx);
168 			if (ctx->tagVersion>1 && map) {
169 				snprintf(tmp, 32, "%i", map[i]);
170 				xmlSetProp(child, (const xmlChar *)"map", (const xmlChar *)tmp);
171 			}
172 		}
173 	}
174 
parseXML(xmlNodePtr node,Context * ctx)175 	void GlyphList::parseXML(xmlNodePtr node, Context *ctx) {
176 		{
177 			nGlyphs = 0;
178 			xmlNodePtr child = node;
179 			while (child) {
180 				if (!strcmp((const char *)child->name, "Glyph")) {
181 					nGlyphs++;
182 				}
183 				child = child->next;
184 			}
185 			ctx->glyphCount = nGlyphs;
186 
187 			if (ctx->tagVersion>1) {
188 				map = new int[nGlyphs];
189 				memset(map, 0, sizeof(int)*nGlyphs);
190 			}
191 
192 			glyphs = new GlyphShape[nGlyphs];
193 			child = node;
194 			int i=0;
195 			while (child) {
196 				if (!strcmp((const char *)child->name, "Glyph")) {
197 					xmlNodePtr shape = child->children;
198 					while (shape) {
199 						if (!strcmp((const char *)shape->name, "GlyphShape")) {
200 							glyphs[i].parseXML(shape, ctx);
201 
202 							if (ctx->tagVersion>1) {
203 								xmlChar *tmp;
204 								tmp = xmlGetProp(child, (const xmlChar *)"map");
205 								if (tmp) {
206 									sscanf((char*)tmp, "%i", &map[i]);
207 									xmlFree( tmp );
208 									if (map[i] > 0xFF) {
209 										ctx->wideMap = true;
210 									}
211 								} else {
212 									map[i] = 0;
213 								}
214 							}
215 
216 							i++;
217 							shape = NULL;
218 						} else {
219 							shape = shape->next;
220 						}
221 					}
222 				}
223 				child = child->next;
224 			}
225 
226 			if (ctx->swfVersion >= 6) {
227 				ctx->wideMap = true;
228 			}
229 		}
230 	}
231 
allocate(int n)232 	void GlyphList::allocate(int n) {
233 		delete[] map;
234 		delete[] glyphs;
235 
236 		nGlyphs = n;
237 		glyphs = new GlyphShape[nGlyphs];
238 		map = new int[nGlyphs];
239 		memset(map, 0, sizeof(int)*nGlyphs);
240 	}
241 
getShapeN(int n)242 	GlyphShape *GlyphList::getShapeN(int n) {
243 		return &glyphs[n];
244 	}
245 
setMapN(int n,int m)246 	void GlyphList::setMapN(int n, int m) {
247 		map[n] = m;
248 	}
249 
250 }
251